Britt Park edd333a029 Deployment stuff.
Filesystem deployment can now run a given java class, or external
program on commit.
Changed signatures of DeploymentService methods
to take a NameMatcher to act as an exclusion
filter for deployment. This works for filesystem deployment
but isn't in place for alfresco->alfresco deployment.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6214 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2007-07-11 21:03:48 +00:00

889 lines
35 KiB
Java

/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.deploy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import org.alfresco.deployment.DeploymentReceiverService;
import org.alfresco.deployment.DeploymentReceiverTransport;
import org.alfresco.deployment.FileDescriptor;
import org.alfresco.deployment.FileType;
import org.alfresco.deployment.impl.client.DeploymentReceiverServiceClient;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.avm.util.SimplePath;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.remote.AVMRemoteImpl;
import org.alfresco.repo.remote.ClientTicketHolder;
import org.alfresco.repo.remote.ClientTicketHolderThread;
import org.alfresco.service.cmr.avm.AVMException;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMNotFoundException;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.avm.AVMWrongTypeException;
import org.alfresco.service.cmr.avm.deploy.DeploymentCallback;
import org.alfresco.service.cmr.avm.deploy.DeploymentEvent;
import org.alfresco.service.cmr.avm.deploy.DeploymentReport;
import org.alfresco.service.cmr.avm.deploy.DeploymentService;
import org.alfresco.service.cmr.avmsync.AVMDifference;
import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.cmr.remote.AVMRemote;
import org.alfresco.service.cmr.remote.AVMRemoteTransport;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.NameMatcher;
import org.alfresco.util.Pair;
import org.springframework.remoting.rmi.RmiProxyFactoryBean;
/**
* Implementation of DeploymentService.
* @author britt
*/
public class DeploymentServiceImpl implements DeploymentService
{
/**
* The local AVMService Instance.
*/
private AVMService fAVMService;
/**
* The Ticket holder.
*/
private ClientTicketHolder fTicketHolder;
/**
* Default constructor.
*/
public DeploymentServiceImpl()
{
fTicketHolder = new ClientTicketHolderThread();
}
/**
* Setter.
* @param service The instance to set.
*/
public void setAvmService(AVMService service)
{
fAVMService = service;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.avm.deploy.DeploymentService#deployDifference(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean)
*/
public DeploymentReport deployDifference(int version, String srcPath, String hostName, int port, String userName, String password, String dstPath, NameMatcher matcher, boolean createDst, boolean dontDelete, boolean dontDo, DeploymentCallback callback)
{
try
{
DeploymentReport report = new DeploymentReport();
AVMRemote remote = getRemote(hostName, port, userName, password);
if (callback != null)
{
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.START,
new Pair<Integer, String>(version, srcPath),
dstPath);
callback.eventOccurred(event);
}
if (version < 0)
{
String storeName = srcPath.substring(0, srcPath.indexOf(":"));
version = fAVMService.createSnapshot(storeName, null, null).get(storeName);
}
// Get the root of the deployment from this server.
AVMNodeDescriptor srcRoot = fAVMService.lookup(version, srcPath);
if (srcRoot == null)
{
throw new AVMNotFoundException("Directory Not Found: " + srcPath);
}
if (!srcRoot.isDirectory())
{
throw new AVMWrongTypeException("Not a directory: " + srcPath);
}
// Create a snapshot on the destination store.
String [] storePath = dstPath.split(":");
int snapshot = -1;
AVMNodeDescriptor dstParent = null;
if (!dontDo)
{
String[] parentBase = AVMNodeConverter.SplitBase(dstPath);
dstParent = remote.lookup(-1, parentBase[0]);
if (dstParent == null)
{
if (createDst)
{
createDestination(remote, parentBase[0]);
dstParent = remote.lookup(-1, parentBase[0]);
}
else
{
throw new AVMNotFoundException("Node Not Found: " + parentBase[0]);
}
}
snapshot = remote.createSnapshot(storePath[0], "PreDeploy", "Pre Deployment Snapshot").get(storePath[0]);
}
// Get the root of the deployment on the destination server.
AVMNodeDescriptor dstRoot = remote.lookup(-1, dstPath);
if (dstRoot == null)
{
// If it doesn't exist, do a copyDirectory to create it.
DeploymentEvent event =
new DeploymentEvent(DeploymentEvent.Type.COPIED,
new Pair<Integer, String>(version, srcPath),
dstPath);
report.add(event);
if (callback != null)
{
callback.eventOccurred(event);
}
if (dontDo)
{
return report;
}
copyDirectory(version, srcRoot, dstParent, remote);
remote.createSnapshot(storePath[0], "Deployment", "Post Deployment Snapshot.");
if (callback != null)
{
event = new DeploymentEvent(DeploymentEvent.Type.END,
new Pair<Integer, String>(version, srcPath),
dstPath);
callback.eventOccurred(event);
}
return report;
}
if (!dstRoot.isDirectory())
{
throw new AVMWrongTypeException("Not a Directory: " + dstPath);
}
// The corresponding directory exists so recursively deploy.
try
{
deployDirectoryPush(version, srcRoot, dstRoot, remote, dontDelete, dontDo, report, callback);
remote.createSnapshot(storePath[0], "Deployment", "Post Deployment Snapshot.");
if (callback != null)
{
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.END,
new Pair<Integer, String>(version, srcPath),
dstPath);
callback.eventOccurred(event);
}
return report;
}
catch (AVMException e)
{
try
{
if (snapshot != -1)
{
AVMSyncService syncService = getSyncService(hostName, port);
List<AVMDifference> diffs = syncService.compare(snapshot, dstPath, -1, dstPath, null);
syncService.update(diffs, null, false, false, true, true, "Aborted Deployment", "Aborted Deployment");
}
}
catch (Exception ee)
{
throw new AVMException("Failed to rollback to version " + snapshot + " on " + hostName, ee);
}
throw new AVMException("Deployment to " + hostName + "failed.", e);
}
}
finally
{
fTicketHolder.setTicket(null);
}
}
/**
* Deploy all the children of corresponding directories.
* @param src The source directory.
* @param dst The destination directory.
* @param remote The AVMRemote instance.
* @param dontDelete Flag for not deleting.
* @param dontDo Flag for dry run.
*/
private void deployDirectoryPush(int version,
AVMNodeDescriptor src, AVMNodeDescriptor dst,
AVMRemote remote, boolean dontDelete, boolean dontDo,
DeploymentReport report,
DeploymentCallback callback)
{
if (src.getGuid().equals(dst.getGuid()))
{
return;
}
if (!dontDo && !dontDelete)
{
copyMetadata(version, src, dst, remote);
}
// Get the listing for the source.
SortedMap<String, AVMNodeDescriptor> srcList = fAVMService.getDirectoryListing(src);
// Get the listing for the destination.
SortedMap<String, AVMNodeDescriptor> dstList = remote.getDirectoryListing(dst);
for (Map.Entry<String, AVMNodeDescriptor> entry : srcList.entrySet())
{
String name = entry.getKey();
AVMNodeDescriptor srcNode = entry.getValue();
AVMNodeDescriptor dstNode = dstList.get(name);
deploySinglePush(version, srcNode, dst, dstNode, remote, dontDelete, dontDo, report, callback);
}
// Delete nodes that are missing in the source.
if (dontDelete)
{
return;
}
for (String name : dstList.keySet())
{
if (!srcList.containsKey(name))
{
Pair<Integer, String> source =
new Pair<Integer, String>(version, AVMNodeConverter.ExtendAVMPath(src.getPath(), name));
String destination = AVMNodeConverter.ExtendAVMPath(dst.getPath(), name);
DeploymentEvent event =
new DeploymentEvent(DeploymentEvent.Type.DELETED,
source,
destination);
report.add(event);
if (callback != null)
{
callback.eventOccurred(event);
}
if (dontDo)
{
continue;
}
remote.removeNode(dst.getPath(), name);
}
}
}
/**
* Push out a single node.
* @param src The source node.
* @param dstParent The destination parent.
* @param dst The destination node. May be null.
* @param remote The AVMRemote instance.
* @param dontDelete Flag for whether deletions should happen.
* @param dontDo Dry run flag.
*/
private void deploySinglePush(int version,
AVMNodeDescriptor src, AVMNodeDescriptor dstParent,
AVMNodeDescriptor dst, AVMRemote remote,
boolean dontDelete, boolean dontDo,
DeploymentReport report,
DeploymentCallback callback)
{
// Destination does not exist.
if (dst == null)
{
if (src.isDirectory())
{
// Recursively copy a source directory.
Pair<Integer, String> source =
new Pair<Integer, String>(version, src.getPath());
String destination = AVMNodeConverter.ExtendAVMPath(dstParent.getPath(), src.getName());
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.COPIED,
source,
destination);
report.add(event);
if (callback != null)
{
callback.eventOccurred(event);
}
if (dontDo)
{
return;
}
copyDirectory(version, src, dstParent, remote);
return;
}
Pair<Integer, String> source =
new Pair<Integer, String>(version, src.getPath());
String destination = AVMNodeConverter.ExtendAVMPath(dstParent.getPath(), src.getName());
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.COPIED,
source,
destination);
report.add(event);
if (callback != null)
{
callback.eventOccurred(event);
}
if (dontDo)
{
return;
}
// Copy a source file.
OutputStream out = remote.createFile(dstParent.getPath(), src.getName());
InputStream in = fAVMService.getFileInputStream(src);
copyStream(in, out);
copyMetadata(version, src, remote.lookup(-1, dstParent.getPath() + '/' + src.getName()), remote);
return;
}
// Destination exists.
if (src.isDirectory())
{
// If the destination is also a directory, recursively deploy.
if (dst.isDirectory())
{
deployDirectoryPush(version, src, dst, remote, dontDelete, dontDo, report, callback);
return;
}
Pair<Integer, String> source =
new Pair<Integer, String>(version, src.getPath());
String destination = dst.getPath();
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.COPIED,
source, destination);
report.add(event);
if (callback != null)
{
callback.eventOccurred(event);
}
if (dontDo)
{
return;
}
remote.removeNode(dstParent.getPath(), src.getName());
copyDirectory(version, src, dstParent, remote);
return;
}
// Source is a file.
if (dst.isFile())
{
// Destination is also a file. Overwrite if the GUIDS are different.
if (src.getGuid().equals(dst.getGuid()))
{
return;
}
Pair<Integer, String> source =
new Pair<Integer, String>(version, src.getPath());
String destination = dst.getPath();
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.UPDATED,
source,
destination);
report.add(event);
if (callback != null)
{
callback.eventOccurred(event);
}
if (dontDo)
{
return;
}
InputStream in = fAVMService.getFileInputStream(src);
OutputStream out = remote.getFileOutputStream(dst.getPath());
copyStream(in, out);
copyMetadata(version, src, dst, remote);
return;
}
Pair<Integer, String> source =
new Pair<Integer, String>(version, src.getPath());
String destination = AVMNodeConverter.ExtendAVMPath(dstParent.getPath(), src.getName());
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.UPDATED,
source,
destination);
report.add(event);
if (callback != null)
{
callback.eventOccurred(event);
}
if (dontDo)
{
return;
}
// Destination is a directory and the source is a file.
// Delete the destination directory and copy the file over.
remote.removeNode(dstParent.getPath(), dst.getName());
InputStream in = fAVMService.getFileInputStream(src);
OutputStream out = remote.createFile(dstParent.getPath(), src.getName());
copyStream(in, out);
copyMetadata(version, src, remote.lookup(-1, dstParent.getPath() + '/' + dst.getName()), remote);
}
/**
* Recursively copy a directory.
* @param src
* @param parent
* @param remote
*/
private void copyDirectory(int version, AVMNodeDescriptor src, AVMNodeDescriptor parent,
AVMRemote remote)
{
// Create the destination directory.
remote.createDirectory(parent.getPath(), src.getName());
AVMNodeDescriptor newParent = remote.lookup(-1, parent.getPath() + '/' + src.getName());
copyMetadata(version, src, newParent, remote);
SortedMap<String, AVMNodeDescriptor> list =
fAVMService.getDirectoryListing(src);
// For each child in the source directory.
for (AVMNodeDescriptor child : list.values())
{
// If it's a file, copy it over and move on.
if (child.isFile())
{
InputStream in = fAVMService.getFileInputStream(child);
OutputStream out = remote.createFile(newParent.getPath(), child.getName());
copyStream(in, out);
copyMetadata(version, child, remote.lookup(-1, newParent.getPath() + '/' + child.getName()), remote);
continue;
}
// Otherwise copy the child directory recursively.
copyDirectory(version, child, newParent, remote);
}
}
/**
* Utility for copying from one stream to another.
* @param in The input stream.
* @param out The output stream.
*/
private void copyStream(InputStream in, OutputStream out)
{
byte[] buff = new byte[8192];
int read = 0;
try
{
while ((read = in.read(buff)) != -1)
{
out.write(buff, 0, read);
}
in.close();
out.close();
}
catch (IOException e)
{
throw new AVMException("I/O Exception", e);
}
}
private void copyMetadata(int version, AVMNodeDescriptor src, AVMNodeDescriptor dst, AVMRemote remote)
{
Map<QName, PropertyValue> props = fAVMService.getNodeProperties(version, src.getPath());
remote.setNodeProperties(dst.getPath(), props);
Set<QName> aspects = fAVMService.getAspects(version, src.getPath());
for (QName aspect : aspects)
{
if (remote.hasAspect(-1, dst.getPath(), aspect))
{
continue;
}
remote.addAspect(dst.getPath(), aspect);
}
remote.setGuid(dst.getPath(), src.getGuid());
if (src.isFile())
{
ContentData contData = fAVMService.getContentDataForRead(version, src.getPath());
remote.setEncoding(dst.getPath(), contData.getEncoding());
remote.setMimeType(dst.getPath(), contData.getMimetype());
}
}
/**
* Utility to get an AVMRemote from a remote Alfresco Server.
* @param hostName
* @param port
* @param userName
* @param password
* @return
*/
private AVMRemote getRemote(String hostName, int port, String userName, String password)
{
try
{
RmiProxyFactoryBean authFactory = new RmiProxyFactoryBean();
authFactory.setRefreshStubOnConnectFailure(true);
authFactory.setServiceInterface(AuthenticationService.class);
authFactory.setServiceUrl("rmi://" + hostName + ":" + port + "/authentication");
authFactory.afterPropertiesSet();
AuthenticationService authService = (AuthenticationService)authFactory.getObject();
authService.authenticate(userName, password.toCharArray());
String ticket = authService.getCurrentTicket();
fTicketHolder.setTicket(ticket);
RmiProxyFactoryBean remoteFactory = new RmiProxyFactoryBean();
remoteFactory.setRefreshStubOnConnectFailure(true);
remoteFactory.setServiceInterface(AVMRemoteTransport.class);
remoteFactory.setServiceUrl("rmi://" + hostName + ":" + port + "/avm");
remoteFactory.afterPropertiesSet();
AVMRemoteTransport transport = (AVMRemoteTransport)remoteFactory.getObject();
AVMRemoteImpl remote = new AVMRemoteImpl();
remote.setAvmRemoteTransport(transport);
remote.setClientTicketHolder(fTicketHolder);
return remote;
}
catch (Exception e)
{
throw new AVMException("Could not Initialize Remote Connection to " + hostName, e);
}
}
private DeploymentReceiverService getReceiver(String hostName, int port)
{
try
{
RmiProxyFactoryBean factory = new RmiProxyFactoryBean();
factory.setRefreshStubOnConnectFailure(true);
factory.setServiceInterface(DeploymentReceiverTransport.class);
factory.setServiceUrl("rmi://" + hostName + ":" + port + "/deployment");
factory.afterPropertiesSet();
DeploymentReceiverTransport transport = (DeploymentReceiverTransport)factory.getObject();
DeploymentReceiverServiceClient service = new DeploymentReceiverServiceClient();
service.setDeploymentReceiverTransport(transport);
return service;
}
catch (Exception e)
{
throw new AVMException("Could not connect to " + hostName + " at " + port, e);
}
}
/**
* Utility to get the sync service for rolling back after a failed deployment.
* @param hostName The target machine.
* @param port The port.
* @return An AVMSyncService instance.
*/
private AVMSyncService getSyncService(String hostName, int port)
{
try
{
RmiProxyFactoryBean syncFactory = new RmiProxyFactoryBean();
syncFactory.setRefreshStubOnConnectFailure(true);
syncFactory.setServiceInterface(AVMSyncService.class);
syncFactory.setServiceUrl("rmi://" + hostName + ":" + port + "/avmsync");
syncFactory.afterPropertiesSet();
AVMSyncService syncService = (AVMSyncService)syncFactory.getObject();
return syncService;
}
catch (Exception e)
{
throw new AVMException("Could not roll back failed deployment to " + hostName, e);
}
}
/**
* Helper function to create a non existent destination.
* @param remote The AVMRemote instance.
* @param dstPath The destination path to create.
*/
private void createDestination(AVMRemote remote, String dstPath)
{
String[] storePath = dstPath.split(":");
String storeName = storePath[0];
String path = storePath[1];
AVMStoreDescriptor storeDesc = remote.getStore(storeName);
if (storeDesc == null)
{
remote.createStore(storeName);
}
SimplePath simpPath = new SimplePath(path);
if (simpPath.size() == 0)
{
return;
}
String prevPath = storeName + ":/";
for (int i = 0; i < simpPath.size(); i++)
{
String currPath = AVMNodeConverter.ExtendAVMPath(prevPath, simpPath.get(i));
AVMNodeDescriptor desc = remote.lookup(-1, currPath);
if (desc == null)
{
remote.createDirectory(prevPath, simpPath.get(i));
}
prevPath = currPath;
}
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.avm.deploy.DeploymentService#deployDifferenceFS(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean)
*/
public DeploymentReport deployDifferenceFS(int version, String srcPath, String hostName, int port, String userName, String password, String target, NameMatcher matcher, boolean createDst, boolean dontDelete, boolean dontDo, DeploymentCallback callback)
{
DeploymentReport report = new DeploymentReport();
DeploymentReceiverService service = getReceiver(hostName, port);
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.START,
new Pair<Integer, String>(version, srcPath),
target);
if (callback != null)
{
callback.eventOccurred(event);
}
report.add(event);
String storeName = srcPath.substring(0, srcPath.indexOf(':'));
System.out.println(storeName);
if (version < 0)
{
version = fAVMService.createSnapshot(storeName, null, null).get(storeName);
}
String ticket = service.begin(target, userName, password);
deployDirectoryPush(service, ticket, report, callback, version, srcPath, "/", matcher);
service.commit(ticket);
event = new DeploymentEvent(DeploymentEvent.Type.END,
new Pair<Integer, String>(version, srcPath),
target);
if (callback != null)
{
callback.eventOccurred(event);
}
report.add(event);
return report;
}
private void deployDirectoryPush(DeploymentReceiverService service, String ticket,
DeploymentReport report, DeploymentCallback callback,
int version,
String srcPath, String dstPath, NameMatcher matcher)
{
Map<String, AVMNodeDescriptor> srcListing = fAVMService.getDirectoryListing(version, srcPath);
List<FileDescriptor> dstListing = service.getListing(ticket, dstPath);
Iterator<AVMNodeDescriptor> srcIter = srcListing.values().iterator();
Iterator<FileDescriptor> dstIter = dstListing.iterator();
AVMNodeDescriptor src = null;
FileDescriptor dst = null;
while (srcIter.hasNext() || dstIter.hasNext())
{
if (src == null)
{
if (srcIter.hasNext())
{
src = srcIter.next();
}
}
if (dst == null)
{
if (dstIter.hasNext())
{
dst = dstIter.next();
}
}
// This means no entry on src so delete.
if (src == null)
{
String newDstPath = extendPath(dstPath, dst.getName());
if (!excluded(matcher, null, newDstPath))
{
service.delete(ticket, newDstPath);
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.DELETED,
new Pair<Integer, String>(version, extendPath(srcPath, dst.getName())),
newDstPath);
if (callback != null)
{
callback.eventOccurred(event);
}
report.add(event);
}
dst = null;
continue;
}
// Nothing on the destination so copy over.
if (dst == null)
{
if (!excluded(matcher, src.getPath(), null))
{
copy(service, ticket, report, callback, version, src, dstPath, matcher);
}
src = null;
continue;
}
int diff = src.getName().compareTo(dst.getName());
if (diff < 0)
{
if (!excluded(matcher, src.getPath(), null))
{
copy(service, ticket, report, callback, version, src, dstPath, matcher);
}
src = null;
continue;
}
if (diff == 0)
{
if (src.getGuid().equals(dst.getGUID()))
{
src = null;
dst = null;
continue;
}
if (src.isFile())
{
String extendedPath = extendPath(dstPath, dst.getName());
if (!excluded(matcher, src.getPath(), extendedPath))
{
copyFile(service, ticket, report, callback, version, src,
extendedPath);
}
src = null;
dst = null;
continue;
}
// Source is a directory.
if (dst.getType() == FileType.DIR)
{
if (!dstPath.equals("/"))
{
service.setGuid(ticket, dstPath, src.getGuid());
}
String extendedPath = extendPath(dstPath, dst.getName());
if (!excluded(matcher, src.getPath(), extendedPath))
{
deployDirectoryPush(service, ticket, report, callback, version, src.getPath(), extendPath(dstPath, dst.getName()), matcher);
}
src = null;
dst = null;
continue;
}
if (!excluded(matcher, src.getPath(), null))
{
copy(service, ticket, report, callback, version, src, dstPath, matcher);
}
src = null;
dst = null;
continue;
}
// diff > 0
// Destination is missing in source, delete it.
String newDstPath = extendPath(dstPath, dst.getName());
service.delete(ticket, newDstPath);
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.DELETED,
new Pair<Integer, String>(version, extendPath(srcPath, dst.getName())),
newDstPath);
if (callback != null)
{
callback.eventOccurred(event);
}
report.add(event);
dst = null;
}
}
/**
* Copy or overwrite a single file.
* @param service
* @param ticket
* @param report
* @param callback
* @param version
* @param src
* @param dstPath
*/
private void copyFile(DeploymentReceiverService service, String ticket,
DeploymentReport report, DeploymentCallback callback, int version,
AVMNodeDescriptor src, String dstPath)
{
InputStream in = fAVMService.getFileInputStream(src);
OutputStream out = service.send(ticket, dstPath, src.getGuid());
try
{
copyStream(in, out);
service.finishSend(ticket, out);
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.COPIED,
new Pair<Integer, String>(version, src.getPath()),
dstPath);
if (callback != null)
{
callback.eventOccurred(event);
}
report.add(event);
}
catch (Exception e)
{
service.abort(ticket);
throw new AVMException("Failed to copy " + src + ". Deployment aborted.", e);
}
}
/**
* Copy a file or directory to an empty destination.
* @param service
* @param ticket
* @param report
* @param callback
* @param version
* @param src
* @param parentPath
*/
private void copy(DeploymentReceiverService service, String ticket,
DeploymentReport report, DeploymentCallback callback,
int version, AVMNodeDescriptor src, String parentPath, NameMatcher matcher)
{
String dstPath = extendPath(parentPath, src.getName());
if (src.isFile())
{
copyFile(service, ticket, report, callback, version, src, dstPath);
return;
}
// src is a directory.
service.mkdir(ticket, dstPath, src.getGuid());
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.COPIED,
new Pair<Integer, String>(version, src.getPath()),
dstPath);
if (callback != null)
{
callback.eventOccurred(event);
}
report.add(event);
Map<String, AVMNodeDescriptor> listing = fAVMService.getDirectoryListing(src);
for (AVMNodeDescriptor child : listing.values())
{
if (!excluded(matcher, child.getPath(), null))
{
copy(service, ticket, report, callback, version, child, dstPath, matcher);
}
}
}
/**
* Extend a path.
* @param path
* @param name
* @return
*/
private String extendPath(String path, String name)
{
if (path.endsWith("/"))
{
return path + name;
}
return path + '/' + name;
}
/**
* Returns true if either srcPath or dstPath are matched by matcher.
* @param matcher
* @param srcPath
* @param dstPath
* @return
*/
private boolean excluded(NameMatcher matcher, String srcPath, String dstPath)
{
return matcher != null && ((srcPath != null && matcher.matches(srcPath)) || (dstPath != null && matcher.matches(dstPath)));
}
}