/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.system.server.profileservice.repository;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SyncFailedException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.zip.ZipInputStream;
import org.jboss.profileservice.spi.DeploymentContentFlags;
import org.jboss.profileservice.spi.DeploymentOption;
import org.jboss.profileservice.spi.ModificationInfo;
import org.jboss.profileservice.spi.ProfileDeployment;
import org.jboss.profileservice.spi.ProfileKey;
import org.jboss.virtual.VFS;
import org.jboss.virtual.VirtualFile;
/**
* A basic deployment repository.
*
* @author <a href="mailto:emuckenh@redhat.com">Emanuel Muckenhuber</a>
* @version $Revision: 89042 $
*/
public class BasicDeploymentRepository extends AbstractDeploymentRepository
{
/** Should an attempt to overwrite existing content fail in {@link #addDeploymentContent(String, ZipInputStream)}*/
private boolean failIfAlreadyExists = false;
/** A optional upload uri. */
private URI uploadUri;
/** A lock for the hot deployment/{@link #getModifiedDeployments()} */
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
public BasicDeploymentRepository(ProfileKey key, URI[] uris)
{
super(key, uris);
}
public boolean isFailIfAlreadyExists()
{
return failIfAlreadyExists;
}
public void setFailIfAlreadyExists(boolean failIfAlreadyExists)
{
this.failIfAlreadyExists = failIfAlreadyExists;
}
public URI getUploadUri()
{
if(uploadUri != null)
return uploadUri;
if(getRepositoryURIs() != null && getRepositoryURIs().length > 0)
return getRepositoryURIs()[0];
throw new IllegalArgumentException("No upload uri available.");
}
public void setUploadUri(URI uploadUri)
{
if(uploadUri == null)
{
this.uploadUri = null;
return;
}
// Validate
if(getRepositoryURIs() != null && getRepositoryURIs().length > 0)
{
if(Arrays.asList(getRepositoryURIs()).contains(uploadUri))
{
this.uploadUri = uploadUri;
return;
}
}
throw new IllegalArgumentException("Upload uri is not managed by this repository: "+ uploadUri);
}
public void load() throws Exception
{
for(URI uri : getRepositoryURIs())
{
VirtualFile root = getCachedVirtualFile(uri);
loadApplications(root);
}
updateLastModfied();
}
@Override
public void addDeployment(String vfsPath, ProfileDeployment d) throws Exception
{
// Suspend hot deployment checking
if( log.isTraceEnabled() )
log.trace("Aquiring content write lock");
lockWrite();
try
{
internalAddDeployment(vfsPath, d);
}
finally
{
// Allow hot deployment checking
unlockWrite();
if(log.isTraceEnabled())
log.trace("Released content write lock");
}
}
public Collection<ModificationInfo> getModifiedDeployments() throws Exception
{
return Collections.emptySet();
}
public String addDeploymentContent(String vfsPath, InputStream contentIS) throws IOException
{
return addDeploymentContent(vfsPath, contentIS, new DeploymentOption[0]);
}
public String addDeploymentContent(String vfsPath, InputStream contentIS, DeploymentOption... options)
throws IOException
{
boolean trace = log.isTraceEnabled();
// Suspend hot deployment checking
if( trace )
log.trace("Aquiring content write lock");
lockWrite();
String repositoryName = null;
try
{
// Write the content out
File contentRoot = new File(getUploadUri());
if(contentRoot == null)
throw new FileNotFoundException("Failed to obtain content dir for phase: "+vfsPath);
if(contentRoot.isDirectory() == false)
throw new FileNotFoundException("The content root is not a directory." + contentRoot.getAbsolutePath());
// The content file
File contentFile = new File(contentRoot, vfsPath);
// Check if it already exists
boolean exists = contentFile.exists();
if(exists && isFailIfAlreadyExists())
throw new SyncFailedException("Deployment content already exists: "+ contentFile.getAbsolutePath());
// Copy streams
FileOutputStream fos = new FileOutputStream(contentFile);
try
{
byte[] tmp = new byte[4096];
int read;
while((read = contentIS.read(tmp)) > 0)
{
if (trace)
log.trace("write, " + read);
fos.write(tmp, 0, read);
}
fos.flush();
// Get the vfs uri and add the VFS uri to the cached VFS uris
VirtualFile contentVF = VFS.getRoot(contentFile.toURI());
try
{
// Add the new virtual file to the cache
repositoryName = addVirtualFileCache(contentVF);
// Cleanup
if(exists)
cleanUpRoot(contentVF);
}
catch(URISyntaxException e)
{
throw new RuntimeException(e); // This should not happen anyway
}
}
finally
{
try
{
fos.close();
}
catch (IOException ignored)
{
}
}
// Lock the content
setDeploymentContentFlags(repositoryName, DeploymentContentFlags.LOCKED);
}
finally
{
// Allow hot deployment checking
unlockWrite();
if(trace)
log.trace("Released content write lock");
}
return repositoryName;
}
public ProfileDeployment removeDeployment(String vfsPath) throws Exception
{
return removeDeployment(vfsPath, true);
}
/**
* Internal add the deployment, without locking the repository.
*
* @param vfsPath - the name of the deployment
* @param deployment - the deployment
* @throws Exception
*/
protected void internalAddDeployment(String vfsPath, ProfileDeployment deployment) throws Exception
{
super.addDeployment(vfsPath, deployment);
}
/**
* Remove deployment.
*
* @param vfsPath the vfs path
* @param deleteFile do we delete the file
* @return found profile deployment
* @throws Exception for any error
*/
protected ProfileDeployment removeDeployment(String vfsPath, boolean deleteFile) throws Exception
{
// Suspend hot deployment checking
if( log.isTraceEnabled() )
log.trace("Aquiring content write lock");
lockWrite();
try
{
// Remove the deployment from the filesystem
ProfileDeployment deployment = getDeployment(vfsPath);
VirtualFile root = deployment.getRoot();
if(deleteFile && root != null)
{
// Delete the file
if(root.delete() == false)
throw new IOException("Failed to delete: " + root);
cleanUpRoot(root);
}
// Cleanup
return super.removeDeployment(deployment.getName());
}
finally
{
unlockWrite();
if (log.isTraceEnabled())
log.trace("Released content write lock");
}
}
/**
* A way for the hot-deployment repository to cleanup
* the root (modification checker).
*
* @param vf the deployment root
*/
protected void cleanUpRoot(VirtualFile vf)
{
//
}
public void remove() throws Exception
{
// FIXME remove
}
/**
* Lock for read
*/
protected void lockRead()
{
lock.readLock().lock();
}
/**
* Unlock for read
*/
protected void unlockRead()
{
lock.readLock().unlock();
}
/**
* Lock for write
*/
protected void lockWrite()
{
lock.writeLock().lock();
}
/**
* Unlock for write
*/
protected void unlockWrite()
{
lock.writeLock().unlock();
}
}