Merge DM-DM_deployment to HEAD

18665 : Switch over to using new surf <formdata multipart-processing="false" /> configuration option.
   - now the PostContentCommandProcessor and PostSnapshotCommandProcessor handle their own MimePart processing.
  18683 : SAIL-288 Implementation of TransferService client side cancelAsync.
  18716 : Adding TransferEventBegin missed from asyncCancel work.
  18734 : Transfer format : implementation of null properties and Serialized base64 Java objects for type d:any
  18749 : SAIL-290: Added features that provide asynchronous commit on the receiver end and the ability to query commit status, as well as code that writes a progress report on the server side (currently only plain text) and the functionality to allow a transfer to be cancelled
  18750 : New files that should have been checked in with previous commit but weren't...
  18770 : Various transfer service work.
   - correction to transfer report name.
   - use surf Base64 Encoder
   - implementation of async commit to the TransferServiceImpl
   - implementation of the statusCommand through the HttpClientTransmitter.
  18773 : transferId was null.
  18780 : Changed the server-side commit to occur asynchronously.
	Added two test actions to transfer a single node or a tree of nodes.
	Tweaked TransferDefinition to provide varargs version of setNodes.
  18793 : SAIL-290:    Added a couple of test actions.
    	Added varargs versions of transfer and transferAsync on TransferService.
  18794 : SAIL-290: Added "targetExists" operation to the TransferService interface.
  18804 : SAIL-36: Fixed an issue where transfer could fail if numerous nodes with the same cm:name value are transferred.
  18805 : SAIL-36: Added model file that should have been with last commit.
  18808 Continuing work on transfer report.
  18825 TransferServiceImplTest green line.
  18836 : Added a little more output to the server-side transfer report. 
  18848 : More work on transfer report.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18865 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Mark Rogers
2010-02-25 23:02:27 +00:00
parent 29bfaff367
commit 14a4f808b8
49 changed files with 4884 additions and 1536 deletions

View File

@@ -8,6 +8,7 @@ transfer_service.comms.unsupported_protocol=Unsupported protocol: {0}
transfer_service.comms.unsuccessful_response=Received unsuccessful response code from target server: {0}, {1}
transfer_service.comms.http_request_failed=Failed to execute HTTP request {0} to target: {1} status: {2}
transfer_service.no_nodes=No nodes to transfer
transfer_service.cancelled=Transfer cancelled
transfer_service.receiver.failed_to_create_staging_folder=Unable to create staging directory for transfer {0}
transfer_service.receiver.lock_folder_not_found=Unable to locate specified lock folder: {0}
@@ -20,3 +21,5 @@ transfer_service.receiver.error_staging_snapshot=
transfer_service.receiver.error_staging_content=
transfer_service.receiver.no_snapshot_received=
transfer_service.receiver.error_committing_transfer=
transfer_service.receiver.transfer_not_found=Failed to find any record of requested transfer: {0}
transfer_service.receiver.transfer_cancelled=Transfer has been cancelled: {0}

View File

@@ -6,13 +6,15 @@
<version>1.0</version>
<imports>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<import uri="http://www.alfresco.org/model/dictionary/1.0"
prefix="d" />
<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys" />
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm" />
</imports>
<namespaces>
<namespace uri="http://www.alfresco.org/model/transfer/1.0" prefix="trx"/>
<namespace uri="http://www.alfresco.org/model/transfer/1.0"
prefix="trx" />
</namespaces>
<constraints>
@@ -96,15 +98,59 @@
<type name="trx:transferLock">
<title>Transfer Lock</title>
<description>Node type used to represent the transfer lock node</description>
<description>Node type used to represent the transfer lock node
</description>
<parent>cm:content</parent>
<mandatory-aspects>
<aspect>trx:transferRelated</aspect>
</mandatory-aspects>
</type>
<type name="trx:tempTransferStore">
<title>Temp Transfer Store</title>
<description>Node type used for storage of temporarily orphaned incoming nodes</description>
<parent>cm:content</parent>
<associations>
<child-association name="trx:orphan">
<source>
<mandatory>false</mandatory>
<many>true</many>
</source>
<target>
<class>sys:base</class>
<mandatory>false</mandatory>
<many>true</many>
</target>
</child-association>
</associations>
</type>
<type name="trx:transferRecord">
<title>Transfer Record</title>
<description>Node type used to record transfer information
</description>
<parent>cm:content</parent>
<properties>
<property name="trx:transferId">
<title>Locked Transfer Identifier</title>
<property name="trx:progressPosition">
<title>Current Progress</title>
<type>d:int</type>
<mandatory enforced="false">true</mandatory>
</property>
<property name="trx:progressEndpoint">
<title>Progress Endpoint</title>
<type>d:int</type>
<mandatory enforced="false">true</mandatory>
</property>
<property name="trx:transferStatus">
<title>Transfer Status</title>
<type>d:text</type>
<mandatory enforced="false">true</mandatory>
</property>
<property name="trx:transferError">
<title>Transfer Error Object</title>
<type>d:any</type>
<mandatory>false</mandatory>
</property>
</properties>
</type>
@@ -129,6 +175,18 @@
</property>
</properties>
</aspect>
<aspect name="trx:transferRelated">
<title>Nodes with this aspect are related to a particular transfer.
</title>
<properties>
<property name="trx:transferId">
<title>Transfer Identifier</title>
<type>d:text</type>
<mandatory enforced="false">true</mandatory>
</property>
</properties>
</aspect>
</aspects>
</model>

View File

@@ -2,7 +2,8 @@
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<!-- Transfer Service Configuration -->
<bean id="transferService" class="org.alfresco.repo.transfer.TransferServiceImpl" init-method="init">
<bean id="transferService" class="org.alfresco.repo.transfer.TransferServiceImpl"
init-method="init">
<property name="actionService">
<ref bean="ActionService" />
</property>
@@ -24,12 +25,16 @@
<property name="transmitter" ref="transferTransmitter" />
<property name="transferManifestNodeFactory" ref="transferManifestNodeFactory" />
<property name="transferReporter" ref="transferReporter" />
<!-- How long to wait while polling for commit status, in mS -->
<property name="commitPollDelay">
<value>2000</value>
</property>
</bean>
<bean id="transferTransmitter" class="org.alfresco.repo.transfer.HttpClientTransmitterImpl" init-method="init" >
<bean id="transferTransmitter" class="org.alfresco.repo.transfer.HttpClientTransmitterImpl"
init-method="init">
<property name="contentService" ref="ContentService" />
</bean>
@@ -43,25 +48,57 @@
</bean>
<bean id="transferReceiver" class="org.alfresco.repo.transfer.RepoTransferReceiverImpl" init-method="init">
<bean id="transferReceiver" class="org.alfresco.repo.transfer.RepoTransferReceiverImpl"
init-method="init">
<property name="nodeService" ref="NodeService" />
<property name="searchService" ref="SearchService" />
<property name="transactionService" ref="TransactionService" />
<property name="transferLockFolderPath"><value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}</value></property>
<property name="transferTempFolderPath"><value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}/${spaces.transfer_temp.childname}</value></property>
<property name="inboundTransferRecordsPath"><value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}/${spaces.inbound_transfer_records.childname}</value></property>
<property name="rootStagingDirectory"><value>${transferservice.receiver.stagingDir}</value></property>
<property name="actionService" ref="ActionService" />
<property name="transferLockFolderPath">
<value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}</value>
</property>
<property name="transferTempFolderPath">
<value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}/${spaces.transfer_temp.childname}</value>
</property>
<property name="inboundTransferRecordsPath">
<value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}/${spaces.inbound_transfer_records.childname}</value>
</property>
<property name="rootStagingDirectory">
<value>${transferservice.receiver.stagingDir}</value>
</property>
<property name="manifestProcessorFactory" ref="transferManifestProcessorFactory" />
<property name="behaviourFilter" ref="policyBehaviourFilter" />
<property name="progressMonitor" ref="transferProgressMonitor" />
</bean>
<bean id="transferManifestProcessorFactory" class="org.alfresco.repo.transfer.DefaultManifestProcessorFactoryImpl">
<bean id="transferProgressMonitor"
class="org.alfresco.repo.transfer.LoggingTransferProgressMonitorImpl">
<property name="delegate">
<bean class="org.alfresco.repo.transfer.RepoTransferProgressMonitorImpl">
<property name="nodeService" ref="NodeService" />
<property name="contentService" ref="ContentService" />
<property name="transactionService" ref="TransactionService" />
</bean>
</property>
</bean>
<bean id="commit-transfer" class="org.alfresco.repo.transfer.TransferCommitActionExecuter" parent="action-executer">
<property name="receiver" ref="TransferReceiver" />
<property name="publicAction">
<value>false</value>
</property>
</bean>
<bean id="transferManifestProcessorFactory"
class="org.alfresco.repo.transfer.DefaultManifestProcessorFactoryImpl">
<property name="nodeService" ref="NodeService" />
<property name="contentService" ref="ContentService" />
<property name="nodeResolverFactory" ref="transferNodeResolverFactory" />
</bean>
<bean id="transferNodeResolverFactory" class="org.alfresco.repo.transfer.DefaultCorrespondingNodeResolverFactory">
<bean id="transferNodeResolverFactory"
class="org.alfresco.repo.transfer.DefaultCorrespondingNodeResolverFactory">
<property name="nodeService" ref="NodeService" />
</bean>
@@ -73,9 +110,11 @@
</list>
</property>
</bean>
<bean id="TransferService_security" class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" />
<bean id="TransferService_security"
class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" />
<bean id="TransferService_transaction" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<bean id="TransferService_transaction"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
@@ -104,8 +143,42 @@
</property>
</bean>
<!-- Action for transfer async -->
<bean id="transfer-async" class="org.alfresco.repo.transfer.TransferAsyncAction" parent="action-executer">
<bean id="TransferReceiver_security"
class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" />
<bean id="TransferReceiver_transaction"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="*">${server.transaction.mode.default}</prop>
</props>
</property>
</bean>
<!-- Transfer service bean -->
<bean id="TransferReceiver" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.alfresco.service.cmr.transfer.TransferReceiver</value>
</property>
<property name="target">
<ref bean="transferReceiver" />
</property>
<property name="interceptorNames">
<list>
<idref local="TransferReceiver_transaction" />
<idref bean="AuditMethodInterceptor" />
<idref bean="exceptionTranslator" />
<idref local="TransferReceiver_security" />
</list>
</property>
</bean>
<bean id="transfer-async" class="org.alfresco.repo.transfer.TransferAsyncAction"
parent="action-executer">
<!-- Run transferAsyncAction on the deployment queue -->
<property name="queueName">
@@ -119,6 +192,33 @@
</property>
</bean>
<bean id="transfer-this-node" class="org.alfresco.repo.transfer.TransferOneNodeActionExecuter"
parent="action-executer">
<property name="transferService">
<ref bean="TransferService" />
</property>
</bean>
<bean id="create-transfer-target" class="org.alfresco.repo.transfer.CreateTransferTargetActionExecuter"
parent="action-executer">
<property name="transferService">
<ref bean="TransferService" />
</property>
</bean>
<bean id="transfer-this-tree" class="org.alfresco.repo.transfer.TransferTreeActionExecuter"
parent="action-executer">
<property name="transferService">
<ref bean="TransferService" />
</property>
<property name="serviceRegistry" ref="ServiceRegistry" />
</bean>
<bean id="transfer-tree-with-cancel" class="org.alfresco.repo.transfer.TransferTreeWithCancelActionExecuter"
parent="action-executer">
<property name="transferService">
<ref bean="TransferService" />
</property>
<property name="serviceRegistry" ref="ServiceRegistry" />
</bean>
</beans>

View File

@@ -0,0 +1,193 @@
package org.alfresco.repo.transfer;
import java.io.File;
import javax.transaction.UserTransaction;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode;
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
import org.alfresco.repo.transfer.manifest.TransferManifestNode;
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferReceiver;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* This abstract class handles the progress monitoring functionality as well as providing
* some utility methods for sub-classes.
* @author Brian
*
*/
public abstract class AbstractManifestProcessorBase implements TransferManifestProcessor
{
private static final Log log = LogFactory.getLog(AbstractManifestProcessorBase.class);
private static final String MSG_ERROR_WHILE_COMMITTING_TRANSFER = "transfer_service.receiver.error_committing_transfer";
private TransferReceiver receiver;
private String transferId;
private int targetEndProgress;
private int currProgress;
public AbstractManifestProcessorBase(TransferReceiver receiver, String transferId)
{
this.receiver = receiver;
this.transferId = transferId;
}
public final void endTransferManifest()
{
receiver.getProgressMonitor().updateProgress(transferId, this.targetEndProgress);
try
{
endManifest();
}
catch(Exception ex)
{
handleException(null, ex);
}
}
protected abstract void endManifest();
public final void processTransferManifestNode(TransferManifestNormalNode node)
{
incrementNodeCounter();
try
{
processNode(node);
}
catch (Exception ex)
{
handleException(node, ex);
}
}
protected abstract void processNode(TransferManifestNormalNode node) throws TransferProcessingException;
public final void processTransferManifestNode(TransferManifestDeletedNode node)
{
incrementNodeCounter();
try
{
processNode(node);
}
catch (Exception ex)
{
handleException(node, ex);
}
}
protected abstract void processNode(TransferManifestDeletedNode node) throws TransferProcessingException;
public final void processTransferManifiestHeader(TransferManifestHeader header)
{
TransferProgressMonitor progressMonitor = receiver.getProgressMonitor();
TransferProgress progress = progressMonitor.getProgress(transferId);
int newEndPos = progress.getEndPosition() + header.getNodeCount();
progressMonitor.updateProgress(transferId, progress.getCurrentPosition(), newEndPos);
targetEndProgress = newEndPos;
currProgress = progress.getCurrentPosition();
try
{
processHeader(header);
}
catch (Exception ex)
{
handleException(null, ex);
}
}
protected abstract void processHeader(TransferManifestHeader header);
public final void startTransferManifest()
{
try
{
startManifest();
}
catch (Exception ex)
{
handleException(null, ex);
}
}
protected abstract void startManifest();
private void incrementNodeCounter()
{
currProgress++;
if (currProgress % 20 == 0)
{
receiver.getProgressMonitor().updateProgress(transferId, currProgress);
}
}
/**
* Given the node ref, this method constructs the appropriate ChildAssociationRef that would place this node in the
* transfer's temporary folder. Useful when handling orphans.
*
* @param nodeRef
* @return
*/
protected ChildAssociationRef getTemporaryLocation(NodeRef nodeRef)
{
NodeRef parentNodeRef = receiver.getTempFolder(transferId);
QName parentAssocType = TransferModel.ASSOC_TRANSFER_ORPHAN;
QName parentAssocName = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, nodeRef.getId());
return new ChildAssociationRef(parentAssocType, parentNodeRef, parentAssocName, nodeRef, true, -1);
}
protected File getStagingFolder()
{
return receiver.getStagingFolder(transferId);
}
private void handleException(TransferManifestNode node, Exception ex)
{
try
{
UserTransaction tx = RetryingTransactionHelper.getActiveUserTransaction();
if (tx != null)
{
tx.setRollbackOnly();
log.debug("Successfully marked transaction for rollback.");
}
}
catch (Exception e)
{
//Nothing really to be done here
log.warn("Failed to mark transaction as rollback-only in response to an error", e);
}
TransferProgressMonitor monitor = receiver.getProgressMonitor();
String message = (node != null) ? "Error while processing incoming node " + node.getNodeRef() :
"Error processing commit";
monitor.log(transferId, message, ex);
//Any non-fatal transfer exception is logged and then skipped - the transfer continues
//(albeit with a guaranteed rollback at the end).
//A fatal transfer exception is rethrown and causes the transfer to end immediately.
//Any non-transfer exception is assumed to be fatal, so is wrapped in a fatal exception
//and thrown.
if (TransferFatalException.class.isAssignableFrom(ex.getClass()))
{
throw (TransferFatalException)ex;
}
else if (!TransferException.class.isAssignableFrom(ex.getClass()))
{
throw new TransferFatalException(MSG_ERROR_WHILE_COMMITTING_TRANSFER, ex);
}
}
protected void logProgress(String message)
{
receiver.getProgressMonitor().log(transferId, message);
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2009-2010 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 received 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.transfer;
import java.util.List;
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.transfer.TransferService;
/**
* @author brian
*
*/
public class CreateTransferTargetActionExecuter extends ActionExecuterAbstractBase
{
public static final String NAME = "create-transfer-target";
private TransferService transferService;
/**
* @param transferService the transferService to set
*/
public void setTransferService(TransferService transferService)
{
this.transferService = transferService;
}
/* (non-Javadoc)
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
TransferTestUtil.getTestTarget(transferService);
}
@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{
}
}

View File

@@ -59,7 +59,7 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
primaryProcessor.setNodeService(nodeService);
processors.add(primaryProcessor);
RepoSecondaryManifestProcessorImpl secondaryProcessor = new RepoSecondaryManifestProcessorImpl(transferId);
RepoSecondaryManifestProcessorImpl secondaryProcessor = new RepoSecondaryManifestProcessorImpl(receiver, transferId);
secondaryProcessor.setNodeResolver(nodeResolver);
secondaryProcessor.setNodeService(nodeService);
processors.add(secondaryProcessor);

View File

@@ -34,6 +34,7 @@ import java.util.TreeMap;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferTarget;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
@@ -555,6 +556,59 @@ public class HttpClientTransmitterImpl implements TransferTransmitter
}
}
/**
*
*/
public TransferProgress getStatus(Transfer transfer) throws TransferException
{
TransferTarget target = transfer.getTransferTarget();
HttpMethod statusRequest = new PostMethod();
try
{
HostConfiguration hostConfig = getHostConfig(target);
HttpState httpState = getHttpState(target);
statusRequest.setPath(target.getEndpointPath() + "/status");
//Put the transferId on the query string
statusRequest.setQueryString(
new NameValuePair[] {new NameValuePair("transferId", transfer.getTransferId())});
try
{
int responseStatus = httpClient.executeMethod(hostConfig, statusRequest, httpState);
checkResponseStatus("status", responseStatus, statusRequest);
//If we get here then we've received a 200 response
String statusPayload = statusRequest.getResponseBodyAsString();
JSONObject statusObj = new JSONObject(statusPayload);
//We're expecting the transfer progress encoded in a JSON object...
int currentPosition = statusObj.getInt("currentPosition");
int endPosition = statusObj.getInt("endPosition");
String statusStr= statusObj.getString("status");
//We're expecting the transfer progress encoded in a JSON object...
TransferProgress p = new TransferProgress();
p.setStatus(TransferProgress.Status.valueOf(statusStr));
p.setCurrentPosition(currentPosition);
p.setEndPosition(endPosition);
return p;
}
catch (RuntimeException e)
{
throw e;
}
catch (Exception e)
{
String error = "Failed to execute HTTP request to target";
log.debug(error, e);
throw new TransferException(MSG_HTTP_REQUEST_FAILED, new Object[]{"status", target.toString(), e.toString()}, e);
}
}
finally
{
statusRequest.releaseConnection();
}
}
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
@@ -566,4 +620,6 @@ public class HttpClientTransmitterImpl implements TransferTransmitter
}
} // end of class

View File

@@ -0,0 +1,153 @@
/*
* Copyright (C) 2009-2010 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 received 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.transfer;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferProgress.Status;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author brian
*
*/
public class LoggingTransferProgressMonitorImpl implements TransferProgressMonitor
{
private static final Log log = LogFactory.getLog(LoggingTransferProgressMonitorImpl.class);
private TransferProgressMonitor delegate;
/**
* @param delegate the delegate to set
*/
public void setDelegate(TransferProgressMonitor delegate)
{
this.delegate = delegate;
}
/**
* @param transferId
* @return
* @throws TransferException
* @see org.alfresco.repo.transfer.TransferProgressMonitor#getProgress(java.lang.String)
*/
public TransferProgress getProgress(String transferId) throws TransferException
{
return delegate.getProgress(transferId);
}
/**
* @param transferId
* @param obj
* @param ex
* @throws TransferException
* @see org.alfresco.repo.transfer.TransferProgressMonitor#log(java.lang.String, java.lang.Object, java.lang.Throwable)
*/
public void log(String transferId, Object obj, Throwable ex) throws TransferException
{
localLog(transferId, obj, ex);
delegate.log(transferId, obj, ex);
}
/**
* @param transferId
* @param obj
* @throws TransferException
* @see org.alfresco.repo.transfer.TransferProgressMonitor#log(java.lang.String, java.lang.Object)
*/
public void log(String transferId, Object obj) throws TransferException
{
localLog(transferId, obj, null);
delegate.log(transferId, obj);
}
/**
* @param transferId
* @param currPos
* @param endPos
* @throws TransferException
* @see org.alfresco.repo.transfer.TransferProgressMonitor#updateProgress(java.lang.String, int, int)
*/
public void updateProgress(String transferId, int currPos, int endPos) throws TransferException
{
if (loggingEnabled())
{
localLog(transferId, "Progress update: " + currPos + " out of " + endPos, null);
}
delegate.updateProgress(transferId, currPos, endPos);
}
/**
* @param transferId
* @param currPos
* @throws TransferException
* @see org.alfresco.repo.transfer.TransferProgressMonitor#updateProgress(java.lang.String, int)
*/
public void updateProgress(String transferId, int currPos) throws TransferException
{
if (loggingEnabled())
{
localLog(transferId, "Progress update: current position = " + currPos, null);
}
delegate.updateProgress(transferId, currPos);
}
/**
* @param transferId
* @param status
* @throws TransferException
* @see org.alfresco.repo.transfer.TransferProgressMonitor#updateStatus(java.lang.String, org.alfresco.service.cmr.transfer.TransferProgress.Status)
*/
public void updateStatus(String transferId, Status status) throws TransferException
{
if (loggingEnabled())
{
localLog(transferId, "Status update: " + status, null);
}
delegate.updateStatus(transferId, status);
}
private boolean loggingEnabled()
{
return log.isInfoEnabled();
}
private void localLog(String transferId, Object obj, Throwable ex)
{
if (loggingEnabled())
{
String message = "Transfer Log (" + transferId +"): " + obj.toString();
if (ex == null)
{
log.info(message);
}
else
{
log.info(message, ex);
}
}
}
}

View File

@@ -38,6 +38,7 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.transfer.NodeCrawler;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.BaseAlfrescoSpringTest;
@@ -171,7 +172,7 @@ public class NodeCrawlerTest extends BaseAlfrescoSpringTest
nodeService.addChild(node8, node15, ContentModel.ASSOC_THUMBNAILS, QName.createQName(
NamespaceService.APP_MODEL_1_0_URI, "temp"));
StandardNodeCrawlerImpl crawler = new StandardNodeCrawlerImpl(serviceRegistry);
NodeCrawler crawler = new StandardNodeCrawlerImpl(serviceRegistry);
crawler.setNodeFinders(new ChildAssociatedNodeFinder(ContentModel.ASSOC_CONTAINS));
Set<NodeRef> crawledNodes = crawler.crawl(node8);

View File

@@ -40,7 +40,6 @@ import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode;
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
import org.alfresco.repo.transfer.manifest.TransferManifestNode;
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
@@ -49,7 +48,6 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.transfer.TransferReceiver;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -58,7 +56,7 @@ import org.apache.commons.logging.LogFactory;
* @author brian
*
*/
public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcessor
public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorBase
{
private static final Log log = LogFactory.getLog(RepoPrimaryManifestProcessorImpl.class);
@@ -78,8 +76,6 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
DEFAULT_LOCAL_PROPERTIES.add(ContentModel.PROP_NODE_UUID);
}
private TransferReceiver receiver;
private String transferId;
private NodeService nodeService;
private ContentService contentService;
private CorrespondingNodeResolver nodeResolver;
@@ -91,8 +87,7 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
*/
public RepoPrimaryManifestProcessorImpl(TransferReceiver receiver, String transferId)
{
this.receiver = receiver;
this.transferId = transferId;
super(receiver, transferId);
}
/*
@@ -100,7 +95,7 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
*
* @seeorg.alfresco.repo.transfer.manifest.TransferManifestProcessor# endTransferManifest()
*/
public void endTransferManifest()
protected void endManifest()
{
if (!orphans.isEmpty())
{
@@ -111,7 +106,7 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
/**
*
*/
public void processTransferManifestNode(TransferManifestDeletedNode node)
protected void processNode(TransferManifestDeletedNode node)
{
// This is a deleted node. First we need to check whether it has already been deleted in this repo
// too by looking in the local archive store. If we find it then we need not do anything.
@@ -119,10 +114,11 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
// store in which its old parent lives.
// If we can find a corresponding node then we'll delete it.
// If we can't find a corresponding node then we'll do nothing.
logProgress("Processing incoming deleted node: " + node.getNodeRef());
if (!nodeService.exists(node.getNodeRef()))
{
// It's not in our archive store. Check to see if we can find it in its original store...
// It's not in our archive store. Check to see if we can find it in
// its original store...
ChildAssociationRef origPrimaryParent = node.getPrimaryParentAssoc();
NodeRef origNodeRef = new NodeRef(origPrimaryParent.getParentRef().getStoreRef(), node.getNodeRef().getId());
@@ -135,46 +131,51 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
// Yes, it does. Delete it.
if (log.isDebugEnabled())
{
log.debug("Incoming deleted noderef " + node.getNodeRef() +
" has been resolved to existing local noderef " + resolvedNodes.resolvedChild +
" - deleting");
log.debug("Incoming deleted noderef " + node.getNodeRef()
+ " has been resolved to existing local noderef " + resolvedNodes.resolvedChild
+ " - deleting");
}
logProgress("Deleting local node: " + resolvedNodes.resolvedChild);
nodeService.deleteNode(resolvedNodes.resolvedChild);
}
else
{
logProgress("Unable to find corresponding node for incoming deleted node: " + node.getNodeRef());
if (log.isDebugEnabled())
{
log.debug("Incoming deleted noderef has no corresponding local noderef: " + node.getNodeRef() +
" - ignoring");
log.debug("Incoming deleted noderef has no corresponding local noderef: " + node.getNodeRef()
+ " - ignoring");
}
}
}
else
{
logProgress("Incoming deleted node is already in the local archive store - ignoring: " + node.getNodeRef());
}
}
/*
* (non-Javadoc)
*
* @see
* org.alfresco.repo.transfer.manifest.TransferManifestProcessor#processTransferManifestNode(org.alfresco.repo.transfer
* .manifest.TransferManifestNode)
* @seeorg.alfresco.repo.transfer.manifest.TransferManifestProcessor#
* processTransferManifestNode(org.alfresco.repo.transfer .manifest.TransferManifestNode)
*/
public void processTransferManifestNode(TransferManifestNormalNode node)
{
try
protected void processNode(TransferManifestNormalNode node)
{
if (log.isDebugEnabled())
{
log.debug("Processing node with incoming noderef of " + node.getNodeRef());
}
ChildAssociationRef primaryParentAssoc = getPrimaryParent(node);
logProgress("Processing incoming node: " + node.getNodeRef() + " -- Source path = " + node.getParentPath() + "/" + node.getPrimaryParentAssoc().getQName());
ChildAssociationRef primaryParentAssoc = node.getPrimaryParentAssoc();
if (primaryParentAssoc == null)
{
error(node, MSG_NO_PRIMARY_PARENT_SUPPLIED);
}
CorrespondingNodeResolver.ResolvedParentChildPair resolvedNodes = nodeResolver.resolveCorrespondingNode(
node.getNodeRef(), primaryParentAssoc, node.getParentPath());
CorrespondingNodeResolver.ResolvedParentChildPair resolvedNodes = nodeResolver.resolveCorrespondingNode(node
.getNodeRef(), primaryParentAssoc, node.getParentPath());
// Does a corresponding node exist in this repo?
if (resolvedNodes.resolvedChild != null)
@@ -182,25 +183,30 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
// Yes, it does. Update it.
if (log.isDebugEnabled())
{
log.debug("Incoming noderef " + node.getNodeRef() +
" has been resolved to existing local noderef " + resolvedNodes.resolvedChild);
log.debug("Incoming noderef " + node.getNodeRef() + " has been resolved to existing local noderef "
+ resolvedNodes.resolvedChild);
}
update(node, resolvedNodes, primaryParentAssoc);
}
else
{
// No, there is no corresponding node. Worth just quickly checking the archive store...
// No, there is no corresponding node. Worth just quickly checking
// the archive store...
NodeRef archiveNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, node.getNodeRef().getId());
if (nodeService.exists(archiveNodeRef))
{
// We have found a node in the archive store that has the same UUID as the one that we've
// been sent. We'll restore that archived node to a temporary location and then try
// We have found a node in the archive store that has the same
// UUID as the one that we've
// been sent. We'll restore that archived node to a temporary
// location and then try
// processing this node again
if (log.isInfoEnabled())
{
log.info("Located an archived node with UUID matching transferred node: " + archiveNodeRef);
log.info("Attempting to restore " + archiveNodeRef);
}
logProgress("Restoring node from archive: " + archiveNodeRef);
ChildAssociationRef tempLocation = getTemporaryLocation(node.getNodeRef());
NodeRef restoredNodeRef = nodeService.restoreNode(archiveNodeRef, tempLocation.getParentRef(),
tempLocation.getTypeQName(), tempLocation.getQName());
@@ -218,29 +224,6 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
}
create(node, resolvedNodes, primaryParentAssoc);
}
}
catch (TransferProcessingException ex)
{
log.error("transfer processing exception" + ex.toString(), ex);
//TODO MER BUGBUG - What to do here? probably can't just swallow it
// does this mean that the manifest is stuffed?
}
}
/**
* Given the node ref, this method constructs the appropriate ChildAssociationRef that would place this node in the
* transfer's temporary folder. Useful when handling orphans.
*
* @param nodeRef
* @return
*/
private ChildAssociationRef getTemporaryLocation(NodeRef nodeRef)
{
NodeRef parentNodeRef = receiver.getTempFolder(transferId);
QName parentAssocType = ContentModel.ASSOC_CONTAINS;
QName parentAssocName = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, nodeRef.getId());
return new ChildAssociationRef(parentAssocType, parentNodeRef, parentAssocName, nodeRef, true, -1);
}
/**
@@ -253,6 +236,8 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
ChildAssociationRef primaryParentAssoc)
{
log.info("Creating new node with noderef " + node.getNodeRef());
logProgress("Creating new node to correspond to incoming node: " + node.getNodeRef());
QName parentAssocType = primaryParentAssoc.getTypeQName();
QName parentAssocName = primaryParentAssoc.getQName();
NodeRef parentNodeRef = resolvedNodes.resolvedParent;
@@ -260,20 +245,23 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
{
if (log.isDebugEnabled())
{
log.debug("Unable to resolve parent for inbound noderef " + node.getNodeRef() +
".\n Supplied parent noderef is " + primaryParentAssoc.getParentRef() +
".\n Supplied parent path is " + node.getParentPath().toString());
log.debug("Unable to resolve parent for inbound noderef " + node.getNodeRef()
+ ".\n Supplied parent noderef is " + primaryParentAssoc.getParentRef()
+ ".\n Supplied parent path is " + node.getParentPath().toString());
}
// We can't find the node's parent.
// We'll store the node in a temporary location and record it for later processing
// We'll store the node in a temporary location and record it for
// later processing
ChildAssociationRef tempLocation = getTemporaryLocation(node.getNodeRef());
parentNodeRef = tempLocation.getParentRef();
parentAssocType = tempLocation.getTypeQName();
parentAssocName = tempLocation.getQName();
log.info("Recording orphaned transfer node: " + node.getNodeRef());
logProgress("Unable to resolve parent for new incoming node. Storing it in temp folder: " + node.getNodeRef());
storeOrphanNode(primaryParentAssoc);
}
// We now know that this is a new node, and we have found the appropriate parent node in the
// We now know that this is a new node, and we have found the
// appropriate parent node in the
// local repository.
log.info("Resolved parent node to " + parentNodeRef);
@@ -285,8 +273,8 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
Map<QName, Serializable> contentProps = processProperties(null, props, true);
// Create the corresponding node...
ChildAssociationRef newNode = nodeService.createNode(parentNodeRef, parentAssocType, parentAssocName,
node.getType(), props);
ChildAssociationRef newNode = nodeService.createNode(parentNodeRef, parentAssocType, parentAssocName, node
.getType(), props);
if (log.isDebugEnabled())
{
@@ -296,7 +284,8 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
// Deal with the content properties
writeContent(newNode.getChildRef(), contentProps);
// Apply any aspects that are needed but haven't automatically been applied
// Apply any aspects that are needed but haven't automatically been
// applied
Set<QName> aspects = new HashSet<QName>(node.getAspects());
aspects.removeAll(nodeService.getAspects(newNode.getChildRef()));
for (QName aspect : aspects)
@@ -304,17 +293,20 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
nodeService.addAspect(newNode.getChildRef(), aspect, null);
}
// Is the node that we've just added the parent of any orphans that we've found earlier?
// Is the node that we've just added the parent of any orphans that
// we've found earlier?
List<ChildAssociationRef> orphansToClaim = orphans.get(newNode.getChildRef());
if (orphansToClaim != null)
{
// Yes, it is...
for (ChildAssociationRef orphan : orphansToClaim)
{
nodeService.moveNode(orphan.getChildRef(), orphan.getParentRef(), orphan.getTypeQName(),
orphan.getQName());
logProgress("Re-parenting previously orphaned node (" + orphan.getChildRef() + ") with found parent " + orphan.getParentRef());
nodeService.moveNode(orphan.getChildRef(), orphan.getParentRef(), orphan.getTypeQName(), orphan
.getQName());
}
// We can now remove the record of these orphans, as their parent has been found
// We can now remove the record of these orphans, as their parent
// has been found
orphans.remove(newNode.getChildRef());
}
}
@@ -330,28 +322,32 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
{
NodeRef nodeToUpdate = resolvedNodes.resolvedChild;
logProgress("Updating local node: " + node.getNodeRef());
QName parentAssocType = primaryParentAssoc.getTypeQName();
QName parentAssocName = primaryParentAssoc.getQName();
NodeRef parentNodeRef = resolvedNodes.resolvedParent;
if (parentNodeRef == null)
{
// We can't find the node's parent.
// We'll store the node in a temporary location and record it for later processing
// We'll store the node in a temporary location and record it for
// later processing
ChildAssociationRef tempLocation = getTemporaryLocation(node.getNodeRef());
parentNodeRef = tempLocation.getParentRef();
parentAssocType = tempLocation.getTypeQName();
parentAssocName = tempLocation.getQName();
storeOrphanNode(primaryParentAssoc);
}
// First of all, do we need to move the node? If any aspect of the primary parent association has changed
// First of all, do we need to move the node? If any aspect of the
// primary parent association has changed
// then the answer is "yes"
ChildAssociationRef currentParent = nodeService.getPrimaryParent(nodeToUpdate);
if (!currentParent.getParentRef().equals(parentNodeRef) ||
!currentParent.getTypeQName().equals(parentAssocType) ||
!currentParent.getQName().equals(parentAssocName))
if (!currentParent.getParentRef().equals(parentNodeRef)
|| !currentParent.getTypeQName().equals(parentAssocType)
|| !currentParent.getQName().equals(parentAssocName))
{
// Yes, we need to move the node
nodeService.moveNode(nodeToUpdate, parentNodeRef, parentAssocType, parentAssocName);
logProgress("Moved node " + nodeToUpdate + " to be under parent node " + parentNodeRef);
}
log.info("Resolved parent node to " + parentNodeRef);
@@ -415,13 +411,22 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
// ...and copy any supplied content properties into this new map...
for (Map.Entry<QName, Serializable> propEntry : props.entrySet())
{
if (ContentData.class.isAssignableFrom(propEntry.getValue().getClass()))
Serializable value = propEntry.getValue();
if (log.isDebugEnabled())
{
if (value == null)
{
log.debug("Received a null value for property " + propEntry.getKey());
}
}
if ((value != null) && ContentData.class.isAssignableFrom(value.getClass()))
{
contentProps.put(propEntry.getKey(), propEntry.getValue());
}
}
// Now we can remove the content properties from amongst the other kinds of properties
// Now we can remove the content properties from amongst the other kinds
// of properties
// (no removeAll on a Map...)
for (QName contentPropertyName : contentProps.keySet())
{
@@ -430,7 +435,8 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
if (!isNew)
{
// Finally, overlay the repo-specific properties from the existing node (if there is one)
// Finally, overlay the repo-specific properties from the existing
// node (if there is one)
Map<QName, Serializable> existingProps = (nodeToUpdate == null) ? new HashMap<QName, Serializable>()
: nodeService.getProperties(nodeToUpdate);
@@ -457,7 +463,7 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
*/
private void writeContent(NodeRef nodeToUpdate, Map<QName, Serializable> contentProps)
{
File stagingDir = receiver.getStagingFolder(transferId);
File stagingDir = getStagingFolder();
for (Map.Entry<QName, Serializable> contentEntry : contentProps.entrySet())
{
ContentData contentData = (ContentData) contentEntry.getValue();
@@ -476,12 +482,11 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
}
}
protected boolean updateNeeded(TransferManifestNode node, NodeRef nodeToUpdate)
protected boolean updateNeeded(TransferManifestNormalNode node, NodeRef nodeToUpdate)
{
return true;
// TODO MER - Temp commenting out.
// //Assumption: if the modified and modifier properties haven't changed, and the cm:content property
// //(if it exists) hasn't changed size then we can assume that properties don't need to be updated...
boolean updateNeeded = true;
// Assumption: if the modified and modifier properties haven't changed, and the cm:content property
// (if it exists) hasn't changed size then we can assume that properties don't need to be updated...
// Map<QName, Serializable> suppliedProps = node.getProperties();
// Date suppliedModifiedDate = (Date) suppliedProps.get(ContentModel.PROP_MODIFIED);
// String suppliedModifier = (String) suppliedProps.get(ContentModel.PROP_MODIFIER);
@@ -492,16 +497,15 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
// String existingModifier = (String) existingProps.get(ContentModel.PROP_MODIFIER);
// ContentData existingContent = (ContentData) existingProps.get(ContentModel.PROP_CONTENT);
//
// boolean updateNeeded = false;
// updateNeeded = false;
// updateNeeded |= ((suppliedModifiedDate != null && !suppliedModifiedDate.equals(existingModifiedDate)) ||
// (existingModifiedDate != null && !existingModifiedDate.equals(suppliedModifiedDate)));
// updateNeeded |= ((suppliedContent != null && existingContent == null) ||
// (suppliedContent == null && existingContent != null) ||
// (suppliedContent != null && existingContent != null && suppliedContent.getSize() !=
// existingContent.getSize()));
// updateNeeded |= ((suppliedContent != null && existingContent == null)
// || (suppliedContent == null && existingContent != null) || (suppliedContent != null
// && existingContent != null && suppliedContent.getSize() != existingContent.getSize()));
// updateNeeded |= ((suppliedModifier != null && !suppliedModifier.equals(existingModifier)) ||
// (existingModifier != null && !existingModifier.equals(suppliedModifier)));
// return updateNeeded;
return updateNeeded;
}
/**
@@ -547,29 +551,7 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
throw ex;
}
/**
* @param node
* @return
*/
private ChildAssociationRef getPrimaryParent(TransferManifestNormalNode node)
{
List<ChildAssociationRef> parents = node.getParentAssocs();
for (ChildAssociationRef parent : parents)
{
if (parent.isPrimary())
return parent;
}
return null;
}
/*
* (non-Javadoc)
*
* @see
* org.alfresco.repo.transfer.manifest.TransferManifestProcessor#processTransferManifiestHeader(org.alfresco.repo
* .transfer.manifest.TransferManifestHeader)
*/
public void processTransferManifiestHeader(TransferManifestHeader header)
protected void processHeader(TransferManifestHeader header)
{
}
@@ -578,7 +560,7 @@ public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcess
*
* @seeorg.alfresco.repo.transfer.manifest.TransferManifestProcessor# startTransferManifest()
*/
public void startTransferManifest()
protected void startManifest()
{
}

View File

@@ -34,57 +34,42 @@ import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode;
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
import org.alfresco.repo.transfer.manifest.TransferManifestNodeHelper;
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.transfer.TransferReceiver;
import org.alfresco.service.namespace.RegexQNamePattern;
/**
* @author brian
*
*/
public class RepoSecondaryManifestProcessorImpl implements TransferManifestProcessor
public class RepoSecondaryManifestProcessorImpl extends AbstractManifestProcessorBase
{
private NodeService nodeService;
private CorrespondingNodeResolver nodeResolver;
private String transferId;
/**
* @param receiver
* @param transferId
*/
public RepoSecondaryManifestProcessorImpl(String transferId)
public RepoSecondaryManifestProcessorImpl(TransferReceiver receiver, String transferId)
{
this.transferId = transferId;
super(receiver, transferId);
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.transfer.manifest.TransferManifestProcessor#endTransferManifest()
*/
public void endTransferManifest()
protected void endManifest()
{
// TODO Auto-generated method stub
//NOOP
}
/**
*
*/
public void processTransferManifestNode(TransferManifestDeletedNode node)
protected void processNode(TransferManifestDeletedNode node)
{
//NOOP
}
/*
* (non-Javadoc)
*
* @see
* org.alfresco.repo.transfer.manifest.TransferManifestProcessor#processTransferManifestNode(org.alfresco.repo.transfer
* .manifest.TransferManifestNode)
*/
public void processTransferManifestNode(TransferManifestNormalNode node)
protected void processNode(TransferManifestNormalNode node)
{
NodeRef correspondingNodeRef = nodeResolver.resolveCorrespondingNode(node.getNodeRef(),
TransferManifestNodeHelper.getPrimaryParentAssoc(node), node.getParentPath()).resolvedChild;
@@ -245,17 +230,9 @@ public class RepoSecondaryManifestProcessorImpl implements TransferManifestProce
}
/*
* (non-Javadoc)
*
* @see
* org.alfresco.repo.transfer.manifest.TransferManifestProcessor#processTransferManifiestHeader(org.alfresco.repo
* .transfer.manifest.TransferManifestHeader)
*/
public void processTransferManifiestHeader(TransferManifestHeader header)
protected void processHeader(TransferManifestHeader header)
{
// TODO Auto-generated method stub
//NOOP
}
/*
@@ -263,10 +240,9 @@ public class RepoSecondaryManifestProcessorImpl implements TransferManifestProce
*
* @see org.alfresco.repo.transfer.manifest.TransferManifestProcessor#startTransferManifest()
*/
public void startTransferManifest()
protected void startManifest()
{
// TODO Auto-generated method stub
//NOOP
}
/**
@@ -286,7 +262,4 @@ public class RepoSecondaryManifestProcessorImpl implements TransferManifestProce
{
this.nodeResolver = nodeResolver;
}
}

View File

@@ -0,0 +1,285 @@
/*
* Copyright (C) 2009-2010 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 received 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.transfer;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferProgress.Status;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author brian
*
*/
public class RepoTransferProgressMonitorImpl implements TransferProgressMonitor
{
private static final Log log = LogFactory.getLog(RepoTransferProgressMonitorImpl.class);
private static final String MSG_TRANSFER_NOT_FOUND = "transfer_service.receiver.transfer_not_found";
private static final String MSG_TRANSFER_CANCELLED = "transfer_service.receiver.transfer_cancelled";
private NodeService nodeService;
private ContentService contentService;
private TransactionService transactionService;
private Map<String, WritableByteChannel> transferLogWriters = new TreeMap<String, WritableByteChannel>();
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.transfer.TransferProgressMonitor#getProgress(java.lang.String)
*/
public TransferProgress getProgress(final String transferId)
{
return transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<TransferProgress>()
{
public TransferProgress execute() throws Throwable
{
NodeRef nodeRef = getTransferRecord(transferId);
TransferProgress progress = new TransferProgress();
progress.setStatus(TransferProgress.Status.valueOf((String) nodeService.getProperty(nodeRef,
TransferModel.PROP_TRANSFER_STATUS)));
progress.setCurrentPosition((Integer) nodeService.getProperty(nodeRef,
TransferModel.PROP_PROGRESS_POSITION));
progress.setEndPosition((Integer) nodeService.getProperty(nodeRef,
TransferModel.PROP_PROGRESS_ENDPOINT));
progress.setError((Throwable) nodeService.getProperty(nodeRef,
TransferModel.PROP_TRANSFER_ERROR));
return progress;
}
}, false, true);
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.transfer.TransferProgressMonitor#log(java.lang.String, java.lang.Object)
*/
public void log(final String transferId, final Object obj)
{
log(transferId, obj, null);
}
public void log(final String transferId, final Object obj, final Throwable ex)
{
transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<Object>()
{
public NodeRef execute() throws Throwable
{
if (ex != null)
{
NodeRef nodeRef = getTransferRecord(transferId);
// Write the exception onto the transfer record
nodeService.setProperty(nodeRef, TransferModel.PROP_TRANSFER_ERROR, ex);
}
WritableByteChannel writer = getLogWriter(transferId);
Date now = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String text = format.format(now) + " - " + obj.toString() + "\n";
if (ex != null)
{
text += ex.getMessage() + "\n";
StringWriter stringWriter = new StringWriter(1024);
PrintWriter errorWriter = new PrintWriter(stringWriter);
ex.printStackTrace(errorWriter);
text += stringWriter.toString();
}
try
{
ByteBuffer.wrap(text.getBytes("UTF-8"));
writer.write(ByteBuffer.wrap(text.getBytes("UTF-8")));
}
catch (Exception ex)
{
if (log.isWarnEnabled())
{
log.warn("Unable to record transfer log information:\n " + text, ex);
}
}
return null;
}
}, false, true);
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.transfer.TransferProgressMonitor#updateProgress(java.lang.String, int)
*/
public void updateProgress(final String transferId, final int currPos)
{
transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<Object>()
{
public NodeRef execute() throws Throwable
{
NodeRef nodeRef = getTransferRecord(transferId);
testCancelled(nodeRef);
nodeService.setProperty(nodeRef, TransferModel.PROP_PROGRESS_POSITION, new Integer(currPos));
return null;
}
}, false, true);
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.transfer.TransferProgressMonitor#updateProgress(java.lang.String, int, int)
*/
public void updateProgress(final String transferId, final int currPos, final int endPos)
{
transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<Object>()
{
public NodeRef execute() throws Throwable
{
NodeRef nodeRef = getTransferRecord(transferId);
testCancelled(nodeRef);
nodeService.setProperty(nodeRef, TransferModel.PROP_PROGRESS_POSITION, new Integer(currPos));
nodeService.setProperty(nodeRef, TransferModel.PROP_PROGRESS_ENDPOINT, new Integer(endPos));
return null;
}
}, false, true);
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.transfer.TransferProgressMonitor#updateStatus(java.lang.String,
* org.alfresco.service.cmr.transfer.TransferProgress.Status)
*/
public void updateStatus(final String transferId, final Status status)
{
transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<Object>()
{
public NodeRef execute() throws Throwable
{
NodeRef nodeRef = getTransferRecord(transferId);
testCancelled(nodeRef);
String currentStatusString = (String)nodeService.getProperty(nodeRef, TransferModel.PROP_TRANSFER_STATUS);
Status currentStatus = Status.valueOf(currentStatusString);
//If the transfer has already reached a terminal state then we don't allow any further change
if (!TransferProgress.getTerminalStatuses().contains(currentStatus))
{
log(transferId, "Status update: " + status);
nodeService.setProperty(nodeRef, TransferModel.PROP_TRANSFER_STATUS, status.toString());
//If the transfer has now reached a terminal state then the make sure that the log channel is
//closed for it (if one was open).
if (TransferProgress.getTerminalStatuses().contains(status))
{
WritableByteChannel logChannel = transferLogWriters.remove(transferId);
if (logChannel != null)
{
logChannel.close();
}
}
}
return null;
}
}, false, true);
}
private void testCancelled(NodeRef transferRecord) throws TransferFatalException
{
Status currentStatus = Status.valueOf((String)nodeService.getProperty(transferRecord, TransferModel.PROP_TRANSFER_STATUS));
if (Status.CANCELLED.equals(currentStatus))
{
throw new TransferFatalException(MSG_TRANSFER_CANCELLED, new Object[] { transferRecord.toString() });
}
}
private NodeRef getTransferRecord(String transferId) throws TransferException
{
NodeRef nodeRef = new NodeRef(transferId);
if (!nodeService.exists(nodeRef) || !nodeService.getType(nodeRef).equals(TransferModel.TYPE_TRANSFER_RECORD))
{
throw new TransferException(MSG_TRANSFER_NOT_FOUND, new Object[] { transferId });
}
return nodeRef;
}
private WritableByteChannel getLogWriter(String transferId)
{
WritableByteChannel channel = this.transferLogWriters.get(transferId);
if (channel == null)
{
NodeRef node = new NodeRef(transferId);
ContentWriter writer = contentService.getWriter(node, ContentModel.PROP_CONTENT, true);
writer.setMimetype("text/plain");
channel = writer.getWritableChannel();
transferLogWriters.put(transferId, channel);
}
return channel;
}
/**
* @param nodeService
* the nodeService to set
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param contentService
* the contentService to set
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* @param transactionService
* the transactionService to set
*/
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
}

View File

@@ -41,9 +41,15 @@ import javax.xml.parsers.SAXParserFactory;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
import org.alfresco.repo.transfer.manifest.XMLTransferManifestReader;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -52,7 +58,9 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferReceiver;
import org.alfresco.service.cmr.transfer.TransferProgress.Status;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
@@ -68,6 +76,46 @@ import org.springframework.util.FileCopyUtils;
*/
public class RepoTransferReceiverImpl implements TransferReceiver
{
/**
* This embedded class is used to push requests for asynchronous commits onto a different thread
*
* @author Brian
*
*/
public class AsyncCommitCommand implements Runnable
{
private String transferId;
private String runAsUser;
public AsyncCommitCommand(String transferId)
{
this.transferId = transferId;
this.runAsUser = AuthenticationUtil.getFullyAuthenticatedUser();
}
public void run()
{
RunAsWork<Object> actionRunAs = new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
return transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionCallback<Object>()
{
public Object execute()
{
commit(transferId);
return null;
}
}, false, true);
}
};
AuthenticationUtil.runAs(actionRunAs, runAsUser);
}
}
private final static Log log = LogFactory.getLog(RepoTransferReceiverImpl.class);
private static final String MSG_FAILED_TO_CREATE_STAGING_FOLDER = "transfer_service.receiver.failed_to_create_staging_folder";
@@ -95,7 +143,8 @@ public class RepoTransferReceiverImpl implements TransferReceiver
private String transferTempFolderPath;
private ManifestProcessorFactory manifestProcessorFactory;
private BehaviourFilter behaviourFilter;
private TransferProgressMonitor progressMonitor;
private ActionService actionService;
private NodeRef transferLockFolder;
private NodeRef transferTempFolder;
@@ -151,13 +200,15 @@ public class RepoTransferReceiverImpl implements TransferReceiver
if (transferLockFolder == null)
{
ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
SearchService.LANGUAGE_LUCENE, "PATH:\"" + transferLockFolderPath + "\"");
SearchService.LANGUAGE_XPATH, transferLockFolderPath);
if (rs.length() > 0)
{
transferLockFolder = rs.getNodeRef(0);
} else
}
else
{
throw new TransferException(MSG_TRANSFER_LOCK_FOLDER_NOT_FOUND, new Object[] {transferLockFolderPath});
throw new TransferException(MSG_TRANSFER_LOCK_FOLDER_NOT_FOUND,
new Object[] { transferLockFolderPath });
}
}
}
@@ -177,13 +228,15 @@ public class RepoTransferReceiverImpl implements TransferReceiver
if (transferTempFolder == null)
{
ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
SearchService.LANGUAGE_LUCENE, "PATH:\"" + transferTempFolderPath + "\"");
SearchService.LANGUAGE_XPATH, transferTempFolderPath);
if (rs.length() > 0)
{
transferTempFolder = rs.getNodeRef(0);
} else
}
else
{
throw new TransferException(MSG_TRANSFER_TEMP_FOLDER_NOT_FOUND, new Object[] {transferId, transferTempFolderPath});
throw new TransferException(MSG_TRANSFER_TEMP_FOLDER_NOT_FOUND, new Object[] { transferId,
transferTempFolderPath });
}
}
}
@@ -203,8 +256,9 @@ public class RepoTransferReceiverImpl implements TransferReceiver
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
props.put(ContentModel.PROP_NAME, tempTransferFolderName);
tempFolderNode = nodeService.createNode(transferTempFolder, ContentModel.ASSOC_CONTAINS, folderName,
ContentModel.TYPE_FOLDER, props).getChildRef();
} else
TransferModel.TYPE_TEMP_TRANSFER_STORE, props).getChildRef();
}
else
{
// Yes, we do have a temp folder for this transfer already. Return it.
tempFolderNode = tempChildren.get(0).getChildRef();
@@ -220,26 +274,38 @@ public class RepoTransferReceiverImpl implements TransferReceiver
*/
public String start()
{
log.debug("start");
final NodeRef relatedTransferRecord = createTransferRecord();
final NodeRef lockFolder = getLockFolder();
NodeRef relatedTransferRecord = null;
RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
try
{
txHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
relatedTransferRecord = txHelper.doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
final NodeRef relatedTransferRecord = createTransferRecord();
getTempFolder(relatedTransferRecord.toString());
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
props.put(ContentModel.PROP_NAME, LOCK_FILE_NAME);
props.put(TransferModel.PROP_TRANSFER_ID, relatedTransferRecord.toString());
log.error("Creating transfer lock associated with this transfer record: " + relatedTransferRecord);
if (log.isInfoEnabled())
{
log.info("Creating transfer lock associated with this transfer record: "
+ relatedTransferRecord);
}
ChildAssociationRef assoc = nodeService.createNode(lockFolder, ContentModel.ASSOC_CONTAINS,
LOCK_QNAME, TransferModel.TYPE_TRANSFER_LOCK, props);
log.error("Transfer lock created as node " + assoc.getChildRef());
return assoc.getChildRef();
if (log.isInfoEnabled())
{
log.info("Transfer lock created as node " + assoc.getChildRef());
}
return relatedTransferRecord;
}
}, false, true);
}
@@ -268,28 +334,33 @@ public class RepoTransferReceiverImpl implements TransferReceiver
{
log.debug("Trying to find transfer records folder: " + inboundTransferRecordsPath);
ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
SearchService.LANGUAGE_LUCENE, "PATH:\"" + inboundTransferRecordsPath + "\"");
SearchService.LANGUAGE_XPATH, inboundTransferRecordsPath);
if (rs.length() > 0)
{
inboundTransferRecordsFolder = rs.getNodeRef(0);
log.debug("Found inbound transfer records folder: " + inboundTransferRecordsFolder);
} else
}
else
{
throw new TransferException(MSG_INBOUND_TRANSFER_FOLDER_NOT_FOUND, new Object[] {inboundTransferRecordsPath});
throw new TransferException(MSG_INBOUND_TRANSFER_FOLDER_NOT_FOUND,
new Object[] { inboundTransferRecordsPath });
}
}
}
}
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssSSSZ");
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSSZ");
String timeNow = format.format(new Date());
QName recordName = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, timeNow);
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
props.put(ContentModel.PROP_NAME, timeNow);
props.put(TransferModel.PROP_PROGRESS_POSITION, 0);
props.put(TransferModel.PROP_PROGRESS_ENDPOINT, 1);
props.put(TransferModel.PROP_TRANSFER_STATUS, TransferProgress.Status.PRE_COMMIT.toString());
log.debug("Creating transfer record with name: " + timeNow);
ChildAssociationRef assoc = nodeService.createNode(inboundTransferRecordsFolder, ContentModel.ASSOC_CONTAINS,
recordName, ContentModel.TYPE_CONTENT, props);
recordName, TransferModel.TYPE_TRANSFER_RECORD, props);
log.debug("<-createTransferRecord: " + assoc.getChildRef());
return assoc.getChildRef();
}
@@ -301,7 +372,10 @@ public class RepoTransferReceiverImpl implements TransferReceiver
*/
public void end(final String transferId)
{
log.debug("end transferId:" + transferId);
if (log.isDebugEnabled())
{
log.debug("Request to end transfer " + transferId);
}
if (transferId == null)
{
throw new IllegalArgumentException("transferId = " + transferId);
@@ -326,7 +400,7 @@ public class RepoTransferReceiverImpl implements TransferReceiver
// Delete the lock node.
log.debug("delete lock node :" + lockId);
nodeService.deleteNode(lockId);
log.debug("lock deleted :" + lockId);
}
return null;
}
@@ -347,11 +421,15 @@ public class RepoTransferReceiverImpl implements TransferReceiver
}
}
public void abort(String transferId) throws TransferException
public void cancel(String transferId) throws TransferException
{
TransferProgress progress = getProgressMonitor().getProgress(transferId);
getProgressMonitor().updateStatus(transferId, TransferProgress.Status.CANCELLED);
if (progress.getStatus().equals(TransferProgress.Status.PRE_COMMIT))
{
//TODO Think about the relationship between abort and end.
end(transferId);
}
}
public void prepare(String transferId) throws TransferException
{
@@ -362,13 +440,17 @@ public class RepoTransferReceiverImpl implements TransferReceiver
*/
private void deleteFile(File file)
{
if (!file.isDirectory()) file.delete();
if (file.isDirectory())
{
File[] fileList = file.listFiles();
if (fileList != null) {
for (File currentFile : fileList) {
if (fileList != null)
{
for (File currentFile : fileList)
{
deleteFile(currentFile);
}
}
}
file.delete();
}
@@ -432,9 +514,13 @@ public class RepoTransferReceiverImpl implements TransferReceiver
*/
public void saveSnapshot(String transferId, InputStream openStream) throws TransferException
{
log.debug("save snapshot transferId=" + transferId);
// Check that this transfer owns the lock and give it a nudge to stop it expiring
nudgeLock(transferId);
if (log.isDebugEnabled())
{
log.debug("Saving snapshot for transferId =" + transferId);
}
File snapshotFile = new File(getStagingFolder(transferId), SNAPSHOT_FILE_NAME);
try
{
@@ -442,7 +528,10 @@ public class RepoTransferReceiverImpl implements TransferReceiver
{
FileCopyUtils.copy(openStream, new FileOutputStream(snapshotFile));
}
log.debug("saved snapshot for transferId=" + transferId);
if (log.isDebugEnabled())
{
log.debug("Saved snapshot for transferId =" + transferId);
}
}
catch (Exception ex)
{
@@ -474,13 +563,40 @@ public class RepoTransferReceiverImpl implements TransferReceiver
}
}
public void commit(String transferId) throws TransferException
public void commitAsync(String transferId)
{
log.debug("commit transferId=" + transferId);
nudgeLock(transferId);
progressMonitor.updateStatus(transferId, Status.COMMIT_REQUESTED);
Action commitAction = actionService.createAction(TransferCommitActionExecuter.NAME);
commitAction.setParameterValue(TransferCommitActionExecuter.PARAM_TRANSFER_ID, transferId);
commitAction.setExecuteAsynchronously(true);
actionService.executeAction(commitAction, new NodeRef(transferId));
if (log.isDebugEnabled())
{
log.debug("Registered transfer commit for asynchronous execution: " + transferId);
}
}
public void commit(final String transferId) throws TransferException
{
if (log.isDebugEnabled())
{
log.debug("Committing transferId=" + transferId);
}
try
{
nudgeLock(transferId);
List<TransferManifestProcessor> commitProcessors = manifestProcessorFactory.getCommitProcessors(this, transferId);
progressMonitor.updateStatus(transferId, Status.COMMITTING);
RetryingTransactionHelper.RetryingTransactionCallback<Object> commitWork = new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
AlfrescoTransactionSupport.bindListener(new TransferCommitTransactionListener(transferId,
RepoTransferReceiverImpl.this));
List<TransferManifestProcessor> commitProcessors = manifestProcessorFactory.getCommitProcessors(
RepoTransferReceiverImpl.this, transferId);
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser parser = saxParserFactory.newSAXParser();
@@ -488,7 +604,10 @@ public class RepoTransferReceiverImpl implements TransferReceiver
if (snapshotFile.exists())
{
log.debug("processing manifest file:" + snapshotFile.getAbsolutePath());
if (log.isDebugEnabled())
{
log.debug("Processing manifest file:" + snapshotFile.getAbsolutePath());
}
// We parse the file as many times as we have processors
for (TransferManifestProcessor processor : commitProcessors)
{
@@ -508,27 +627,47 @@ public class RepoTransferReceiverImpl implements TransferReceiver
}
else
{
log.debug("no snapshot received");
throw new TransferException(MSG_NO_SNAPSHOT_RECEIVED);
progressMonitor.log(transferId, "Unable to start commit. No snapshot file received",
new TransferException(MSG_NO_SNAPSHOT_RECEIVED));
}
return null;
}
};
transactionService.getRetryingTransactionHelper().doInTransaction(commitWork, false, true);
Throwable error = progressMonitor.getProgress(transferId).getError();
if (error != null)
{
if (TransferException.class.isAssignableFrom(error.getClass()))
{
throw (TransferException) error;
}
else
{
throw new TransferException(MSG_ERROR_WHILE_COMMITTING_TRANSFER, error);
}
}
/**
* Successfully transfred
* Successfully committed
*/
log.debug("commit success transferId=" + transferId);
}
catch (TransferException ex)
if (log.isDebugEnabled())
{
log.debug("unable to commit", ex);
throw ex;
log.debug("Commit success transferId=" + transferId);
}
}
catch (Exception ex)
{
log.debug("unable to commit", ex);
if (TransferException.class.isAssignableFrom(ex.getClass()))
{
throw (TransferException) ex;
}
else
{
throw new TransferException(MSG_ERROR_WHILE_COMMITTING_TRANSFER, ex);
}
}
finally
{
/**
@@ -547,6 +686,11 @@ public class RepoTransferReceiverImpl implements TransferReceiver
}
}
public TransferProgress getStatus(String transferId) throws TransferException
{
return getProgressMonitor().getProgress(transferId);
}
private File getSnapshotFile(String transferId)
{
return new File(getStagingFolder(transferId), SNAPSHOT_FILE_NAME);
@@ -580,7 +724,8 @@ public class RepoTransferReceiverImpl implements TransferReceiver
}
/**
* @param transferTempFolderPath the transferTempFolderPath to set
* @param transferTempFolderPath
* the transferTempFolderPath to set
*/
public void setTransferTempFolderPath(String transferTempFolderPath)
{
@@ -615,7 +760,8 @@ public class RepoTransferReceiverImpl implements TransferReceiver
}
/**
* @param manifestProcessorFactory the manifestProcessorFactory to set
* @param manifestProcessorFactory
* the manifestProcessorFactory to set
*/
public void setManifestProcessorFactory(ManifestProcessorFactory manifestProcessorFactory)
{
@@ -623,11 +769,34 @@ public class RepoTransferReceiverImpl implements TransferReceiver
}
/**
* @param behaviourFilter the behaviourFilter to set
* @param behaviourFilter
* the behaviourFilter to set
*/
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
{
this.behaviourFilter = behaviourFilter;
}
/**
* @return the progressMonitor
*/
public TransferProgressMonitor getProgressMonitor()
{
return progressMonitor;
}
/**
* @param progressMonitor
* the progressMonitor to set
*/
public void setProgressMonitor(TransferProgressMonitor progressMonitor)
{
this.progressMonitor = progressMonitor;
}
public void setActionService(ActionService actionService)
{
this.actionService = actionService;
}
}

View File

@@ -38,31 +38,42 @@ import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode;
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
import org.alfresco.repo.transfer.manifest.TransferManifestNode;
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
import org.alfresco.repo.transfer.manifest.XMLTransferManifestWriter;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.BaseAlfrescoSpringTest;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tools.ant.filters.StringInputStream;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionDefinition;
/**
* Unit test for RepoTransferReceiverImpl
*
* @author Brian Remmington
*/
@SuppressWarnings("deprecation")
// It's a test
public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
{
private static int fileCount = 0;
@@ -72,22 +83,42 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
private String dummyContent;
private byte[] dummyContentBytes;
@Override
public void runBare() throws Throwable
{
preventTransaction();
super.runBare();
}
/**
* Called during the transaction setup
*/
@SuppressWarnings("deprecation")
protected void onSetUpInTransaction() throws Exception
protected void onSetUp() throws Exception
{
super.onSetUp();
System.out.println("java.io.tmpdir == " + System.getProperty("java.io.tmpdir"));
super.onSetUpInTransaction();
// Get the required services
this.nodeService = (NodeService) this.applicationContext.getBean("nodeService");
this.contentService = (ContentService) this.applicationContext.getBean("contentService");
this.authenticationService = (MutableAuthenticationService) this.applicationContext
.getBean("authenticationService");
this.actionService = (ActionService) this.applicationContext.getBean("actionService");
this.transactionService = (TransactionService) this.applicationContext.getBean("transactionComponent");
this.authenticationComponent = (AuthenticationComponent) this.applicationContext
.getBean("authenticationComponent");
this.receiver = (RepoTransferReceiverImpl) this.getApplicationContext().getBean("transferReceiver");
this.dummyContent = "This is some dummy content.";
this.dummyContentBytes = dummyContent.getBytes("UTF-8");
setTransactionDefinition(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW));
authenticationComponent.setSystemUserAsCurrentUser();
}
public void testStartAndEnd() throws Exception
{
log.info("testStartAndEnd");
startNewTransaction();
try
{
String transferId = receiver.start();
System.out.println("TransferId == " + transferId);
@@ -99,7 +130,8 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
{
receiver.start();
fail("Successfully started twice!");
} catch (TransferException ex)
}
catch (TransferException ex)
{
// Expected
}
@@ -107,7 +139,8 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
{
receiver.end(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, GUID.generate()).toString());
fail("Successfully ended with transfer id that doesn't own lock.");
} catch (TransferException ex)
}
catch (TransferException ex)
{
// Expected
}
@@ -116,8 +149,17 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
receiver.end(receiver.start());
}
finally
{
endTransaction();
}
}
public void testSaveContent() throws Exception
{
log.info("testSaveContent");
startNewTransaction();
try
{
String transferId = receiver.start();
try
@@ -127,13 +169,23 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
File contentFile = new File(receiver.getStagingFolder(transferId), contentId);
assertTrue(contentFile.exists());
assertEquals(dummyContentBytes.length, contentFile.length());
} finally
}
finally
{
receiver.end(transferId);
}
}
finally
{
endTransaction();
}
}
public void testSaveSnapshot() throws Exception
{
log.info("testSaveSnapshot");
startNewTransaction();
try
{
String transferId = receiver.start();
File snapshotFile = null;
@@ -150,20 +202,34 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
snapshotFile = new File(stagingFolder, "snapshot.xml");
assertTrue(snapshotFile.exists());
assertEquals(snapshot.getBytes("UTF-8").length, snapshotFile.length());
} finally
}
finally
{
receiver.end(transferId);
if (snapshotFile != null) {
if (snapshotFile != null)
{
assertFalse(snapshotFile.exists());
}
}
}
finally
{
endTransaction();
}
}
public void testBasicCommit() throws Exception {
public void testBasicCommit() throws Exception
{
log.info("testBasicCommit");
startNewTransaction();
TransferManifestNode node = null;
try
{
String transferId = receiver.start();
try
{
TransferManifestNode node = createContentNode(transferId);
node = createContentNode(transferId);
List<TransferManifestNode> nodes = new ArrayList<TransferManifestNode>();
nodes.add(node);
String snapshot = createSnapshot(nodes);
@@ -172,44 +238,75 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes));
receiver.commit(transferId);
assertTrue(nodeService.exists(node.getNodeRef()));
nodeService.deleteNode(node.getNodeRef());
} catch (Exception ex)
}
catch (Exception ex)
{
receiver.end(transferId);
throw ex;
}
}
finally
{
endTransaction();
}
public void testMoreComplexCommit() throws Exception {
String transferId = receiver.start();
startNewTransaction();
try
{
assertTrue(nodeService.exists(node.getNodeRef()));
nodeService.deleteNode(node.getNodeRef());
}
finally
{
endTransaction();
}
}
public void testMoreComplexCommit() throws Exception
{
log.info("testMoreComplexCommit");
List<TransferManifestNode> nodes = new ArrayList<TransferManifestNode>();
TransferManifestNormalNode node1 = createContentNode(transferId);
TransferManifestNormalNode node1 = null;
TransferManifestNormalNode node2 = null;
TransferManifestNode node3 = null;
TransferManifestNode node4 = null;
TransferManifestNode node5 = null;
TransferManifestNode node6 = null;
TransferManifestNode node7 = null;
TransferManifestNode node8 = null;
TransferManifestNode node9 = null;
TransferManifestNode node10 = null;
TransferManifestNormalNode node11 = null;
TransferManifestNode node12 = null;
String transferId = null;
startNewTransaction();
try
{
transferId = receiver.start();
node1 = createContentNode(transferId);
nodes.add(node1);
TransferManifestNormalNode node2 = createContentNode(transferId);
node2 = createContentNode(transferId);
nodes.add(node2);
TransferManifestNode node3 = createContentNode(transferId);
node3 = createContentNode(transferId);
nodes.add(node3);
TransferManifestNode node4 = createContentNode(transferId);
node4 = createContentNode(transferId);
nodes.add(node4);
TransferManifestNode node5 = createContentNode(transferId);
node5 = createContentNode(transferId);
nodes.add(node5);
TransferManifestNode node6 = createContentNode(transferId);
node6 = createContentNode(transferId);
nodes.add(node6);
TransferManifestNode node7 = createContentNode(transferId);
node7 = createContentNode(transferId);
nodes.add(node7);
TransferManifestNode node8 = createFolderNode(transferId);
node8 = createFolderNode(transferId);
nodes.add(node8);
TransferManifestNode node9 = createFolderNode(transferId);
node9 = createFolderNode(transferId);
nodes.add(node9);
TransferManifestNode node10 = createFolderNode(transferId);
node10 = createFolderNode(transferId);
nodes.add(node10);
TransferManifestNormalNode node11 = createFolderNode(transferId);
node11 = createFolderNode(transferId);
nodes.add(node11);
TransferManifestNode node12 = createFolderNode(transferId);
node12 = createFolderNode(transferId);
nodes.add(node12);
associatePeers(node1, node2);
@@ -219,28 +316,44 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
for (TransferManifestNode node : nodes) {
for (TransferManifestNode node : nodes)
{
receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes));
}
receiver.commit(transferId);
assertTrue(nodeService.getAspects(node1.getNodeRef()).contains(ContentModel.ASPECT_ATTACHABLE));
assertFalse(nodeService.getSourceAssocs(node2.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS).isEmpty());
for (TransferManifestNode node : nodes) {
assertTrue(nodeService.exists(node.getNodeRef()));
}
} catch (Exception ex)
finally
{
receiver.end(transferId);
throw ex;
endTransaction();
}
}
public void testNodeDeleteAndRestore() throws Exception {
String transferId = receiver.start();
startNewTransaction();
try
{
assertTrue(nodeService.getAspects(node1.getNodeRef()).contains(ContentModel.ASPECT_ATTACHABLE));
assertFalse(nodeService.getSourceAssocs(node2.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS).isEmpty());
for (TransferManifestNode node : nodes)
{
assertTrue(nodeService.exists(node.getNodeRef()));
}
}
finally
{
endTransaction();
}
}
public void testNodeDeleteAndRestore() throws Exception
{
log.info("testNodeDeleteAndRestore");
this.setDefaultRollback(false);
startNewTransaction();
String transferId = receiver.start();
List<TransferManifestNode> nodes = new ArrayList<TransferManifestNode>();
TransferManifestNormalNode node1 = createContentNode(transferId);
nodes.add(node1);
@@ -270,39 +383,77 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
associatePeers(node1, node2);
moveNode(node2, node11);
TransferManifestDeletedNode deletedNode8 = createDeletedNode(node8);
TransferManifestDeletedNode deletedNode2 = createDeletedNode(node2);
TransferManifestDeletedNode deletedNode11 = createDeletedNode(node11);
endTransaction();
startNewTransaction();
try
{
String snapshot = createSnapshot(nodes);
log.debug(snapshot);
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
for (TransferManifestNode node : nodes) {
for (TransferManifestNode node : nodes)
{
receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes));
}
receiver.commit(transferId);
assertTrue(nodeService.getAspects(node1.getNodeRef()).contains(ContentModel.ASPECT_ATTACHABLE));
assertFalse(nodeService.getSourceAssocs(node2.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS).isEmpty());
for (TransferManifestNode node : nodes) {
for (TransferManifestNode node : nodes)
{
assertTrue(nodeService.exists(node.getNodeRef()));
}
}
finally
{
endTransaction();
}
startNewTransaction();
try
{
// Now delete nodes 8, 2, and 11 (2 and 11 are parent/child)
TransferManifestDeletedNode deletedNode8 = createDeletedNode(node8);
TransferManifestDeletedNode deletedNode2 = createDeletedNode(node2);
TransferManifestDeletedNode deletedNode11 = createDeletedNode(node11);
transferId = receiver.start();
snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] {deletedNode8, deletedNode2, deletedNode11}));
String snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] { deletedNode8, deletedNode2,
deletedNode11 }));
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
receiver.commit(transferId);
}
finally
{
endTransaction();
}
startNewTransaction();
try
{
assertTrue(nodeService.exists(deletedNode8.getNodeRef()));
assertTrue(nodeService.hasAspect(deletedNode8.getNodeRef(), ContentModel.ASPECT_ARCHIVED));
assertTrue(nodeService.exists(deletedNode2.getNodeRef()));
assertTrue(nodeService.hasAspect(deletedNode2.getNodeRef(), ContentModel.ASPECT_ARCHIVED));
assertTrue(nodeService.exists(deletedNode11.getNodeRef()));
assertTrue(nodeService.hasAspect(deletedNode11.getNodeRef(), ContentModel.ASPECT_ARCHIVED));
TransferProgress progress = receiver.getProgressMonitor().getProgress(transferId);
assertEquals(TransferProgress.Status.COMPLETE, progress.getStatus());
log.debug("Progress indication: " + progress.getCurrentPosition() + "/" + progress.getEndPosition());
}
finally
{
endTransaction();
}
String errorMsgId = null;
startNewTransaction();
try
{
// try to restore node 2. Expect an "orphan" failure, since its parent (node11) is deleted
transferId = receiver.start();
snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] {node2}));
String snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] { node2 }));
log.debug(snapshot);
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
receiver.saveContent(transferId, node2.getUuid(), new ByteArrayInputStream(dummyContentBytes));
@@ -313,15 +464,125 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
}
catch (TransferException ex)
{
assertTrue(ex.getMsgId(), ex.getMsgId().contains("orphan"));
// Expected
errorMsgId = ex.getMsgId();
}
} catch (Exception ex)
}
catch (Exception ex)
{
receiver.end(transferId);
throw ex;
}
finally
{
endTransaction();
}
startNewTransaction();
try
{
TransferProgress progress = receiver.getProgressMonitor().getProgress(transferId);
assertEquals(TransferProgress.Status.ERROR, progress.getStatus());
log.debug("Progress indication: " + progress.getCurrentPosition() + "/" + progress.getEndPosition());
assertNotNull("Progress error", progress.getError());
assertTrue(progress.getError() instanceof Exception);
assertTrue(errorMsgId, errorMsgId.contains("orphan"));
}
finally
{
endTransaction();
}
}
public void testAsyncCommit() throws Exception
{
log.info("testAsyncCommit");
this.setDefaultRollback(false);
startNewTransaction();
final String transferId = receiver.start();
endTransaction();
startNewTransaction();
final List<TransferManifestNode> nodes = new ArrayList<TransferManifestNode>();
final TransferManifestNormalNode node1 = createContentNode(transferId);
nodes.add(node1);
final TransferManifestNormalNode node2 = createContentNode(transferId);
nodes.add(node2);
TransferManifestNode node3 = createContentNode(transferId);
nodes.add(node3);
TransferManifestNode node4 = createContentNode(transferId);
nodes.add(node4);
TransferManifestNode node5 = createContentNode(transferId);
nodes.add(node5);
TransferManifestNode node6 = createContentNode(transferId);
nodes.add(node6);
TransferManifestNode node7 = createContentNode(transferId);
nodes.add(node7);
TransferManifestNode node8 = createFolderNode(transferId);
nodes.add(node8);
TransferManifestNode node9 = createFolderNode(transferId);
nodes.add(node9);
TransferManifestNode node10 = createFolderNode(transferId);
nodes.add(node10);
TransferManifestNormalNode node11 = createFolderNode(transferId);
nodes.add(node11);
TransferManifestNode node12 = createFolderNode(transferId);
nodes.add(node12);
associatePeers(node1, node2);
moveNode(node2, node11);
endTransaction();
String snapshot = createSnapshot(nodes);
startNewTransaction();
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
endTransaction();
for (TransferManifestNode node : nodes)
{
startNewTransaction();
receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes));
endTransaction();
}
startNewTransaction();
receiver.commitAsync(transferId);
endTransaction();
log.debug("Posted request for commit");
TransferProgressMonitor progressMonitor = receiver.getProgressMonitor();
TransferProgress progress = null;
while (progress == null || !TransferProgress.getTerminalStatuses().contains(progress.getStatus()))
{
Thread.sleep(500);
startNewTransaction();
progress = progressMonitor.getProgress(transferId);
endTransaction();
log.debug("Progress indication: " + progress.getStatus() + ": " + progress.getCurrentPosition() + "/"
+ progress.getEndPosition());
}
assertEquals(TransferProgress.Status.COMPLETE, progress.getStatus());
startNewTransaction();
try
{
assertTrue(nodeService.getAspects(node1.getNodeRef()).contains(ContentModel.ASPECT_ATTACHABLE));
assertFalse(nodeService.getSourceAssocs(node2.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS).isEmpty());
for (TransferManifestNode node : nodes)
{
assertTrue(nodeService.exists(node.getNodeRef()));
}
}
finally
{
endTransaction();
}
}
/**
@@ -347,12 +608,16 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
List<ChildAssociationRef> currentParents = childNode.getParentAssocs();
List<ChildAssociationRef> newParents = new ArrayList<ChildAssociationRef>();
for (ChildAssociationRef parent : currentParents) {
if (!parent.isPrimary()) {
for (ChildAssociationRef parent : currentParents)
{
if (!parent.isPrimary())
{
newParents.add(parent);
} else {
ChildAssociationRef newPrimaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
newParent.getNodeRef(), parent.getQName(), parent.getChildRef(), true, -1);
}
else
{
ChildAssociationRef newPrimaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, newParent
.getNodeRef(), parent.getQName(), parent.getChildRef(), true, -1);
newParents.add(newPrimaryAssoc);
childNode.setPrimaryParentAssoc(newPrimaryAssoc);
Path newParentPath = new Path();
@@ -364,39 +629,47 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
childNode.setParentAssocs(newParents);
}
private void associatePeers(TransferManifestNormalNode source, TransferManifestNormalNode target) {
private void associatePeers(TransferManifestNormalNode source, TransferManifestNormalNode target)
{
List<AssociationRef> currentReferencedPeers = source.getTargetAssocs();
if (currentReferencedPeers == null) {
if (currentReferencedPeers == null)
{
currentReferencedPeers = new ArrayList<AssociationRef>();
source.setTargetAssocs(currentReferencedPeers);
}
List<AssociationRef> currentRefereePeers = target.getSourceAssocs();
if (currentRefereePeers == null) {
if (currentRefereePeers == null)
{
currentRefereePeers = new ArrayList<AssociationRef>();
target.setSourceAssocs(currentRefereePeers);
}
Set<QName> aspects = source.getAspects();
if (aspects == null ) {
if (aspects == null)
{
aspects = new HashSet<QName>();
source.setAspects(aspects);
}
aspects.add(ContentModel.ASPECT_ATTACHABLE);
AssociationRef newAssoc = new AssociationRef(source.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS, target.getNodeRef());
AssociationRef newAssoc = new AssociationRef(source.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS, target
.getNodeRef());
currentRefereePeers.add(newAssoc);
currentReferencedPeers.add(newAssoc);
}
private String createSnapshot(List<TransferManifestNode> nodes) throws Exception {
private String createSnapshot(List<TransferManifestNode> nodes) throws Exception
{
XMLTransferManifestWriter manifestWriter = new XMLTransferManifestWriter();
StringWriter output = new StringWriter();
manifestWriter.startTransferManifest(output);
TransferManifestHeader header = new TransferManifestHeader();
header.setCreatedDate(new Date());
header.setNodeCount(nodes.size());
manifestWriter.writeTransferManifestHeader(header);
for (TransferManifestNode node : nodes) {
for (TransferManifestNode node : nodes)
{
manifestWriter.writeTransferManifestNode(node);
}
manifestWriter.endTransferManifest();
@@ -420,11 +693,11 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
node.setType(ContentModel.TYPE_CONTENT);
NodeRef parentFolder = receiver.getTempFolder(transferId);
String nodeName = transferId + ".testnode" + getNameSuffix();
String nodeName = uuid + ".testnode" + getNameSuffix();
List<ChildAssociationRef> parents = new ArrayList<ChildAssociationRef>();
ChildAssociationRef primaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, parentFolder, QName.createQName(
NamespaceService.CONTENT_MODEL_1_0_URI, nodeName), node.getNodeRef(), true, -1);
ChildAssociationRef primaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, parentFolder, QName
.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, nodeName), node.getNodeRef(), true, -1);
parents.add(primaryAssoc);
node.setParentAssocs(parents);
node.setParentPath(nodeService.getPath(parentFolder));
@@ -451,11 +724,11 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
node.setType(ContentModel.TYPE_FOLDER);
NodeRef parentFolder = receiver.getTempFolder(transferId);
String nodeName = transferId + ".folder" + getNameSuffix();
String nodeName = uuid + ".folder" + getNameSuffix();
List<ChildAssociationRef> parents = new ArrayList<ChildAssociationRef>();
ChildAssociationRef primaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, parentFolder, QName.createQName(
NamespaceService.CONTENT_MODEL_1_0_URI, nodeName), node.getNodeRef(), true, -1);
ChildAssociationRef primaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, parentFolder, QName
.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, nodeName), node.getNodeRef(), true, -1);
parents.add(primaryAssoc);
node.setParentAssocs(parents);
node.setParentPath(nodeService.getPath(parentFolder));
@@ -469,7 +742,8 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
return node;
}
private String getNameSuffix() {
private String getNameSuffix()
{
return "" + fileCount++;
}
}

View File

@@ -35,6 +35,7 @@ import java.util.Set;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.transfer.NodeCrawler;
import org.alfresco.service.cmr.transfer.NodeFilter;
import org.alfresco.service.cmr.transfer.NodeFinder;
import org.alfresco.service.cmr.transfer.TransferService;
@@ -50,7 +51,7 @@ import org.alfresco.service.cmr.transfer.TransferService;
* @author brian
*
*/
public class StandardNodeCrawlerImpl
public class StandardNodeCrawlerImpl implements NodeCrawler
{
private ServiceRegistry serviceRegistry;
private List<NodeFinder> nodeFinders = new ArrayList<NodeFinder>();
@@ -82,11 +83,17 @@ public class StandardNodeCrawlerImpl
this.serviceRegistry = serviceRegistry;
}
/* (non-Javadoc)
* @see org.alfresco.repo.transfer.NodeCrawler#crawl(org.alfresco.service.cmr.repository.NodeRef)
*/
public Set<NodeRef> crawl(NodeRef... nodes)
{
return crawl(new HashSet<NodeRef>(Arrays.asList(nodes)));
}
/* (non-Javadoc)
* @see org.alfresco.repo.transfer.NodeCrawler#crawl(java.util.Set)
*/
public synchronized Set<NodeRef> crawl(Set<NodeRef> startingNodes)
{
init();
@@ -166,11 +173,17 @@ public class StandardNodeCrawlerImpl
return include;
}
/* (non-Javadoc)
* @see org.alfresco.repo.transfer.NodeCrawler#setNodeFinders(org.alfresco.service.cmr.transfer.NodeFinder)
*/
public synchronized void setNodeFinders(NodeFinder... finders)
{
nodeFinders = Arrays.asList(finders);
}
/* (non-Javadoc)
* @see org.alfresco.repo.transfer.NodeCrawler#setNodeFilters(org.alfresco.service.cmr.transfer.NodeFilter)
*/
public synchronized void setNodeFilters(NodeFilter... filters)
{
nodeFilters = Arrays.asList(filters);

View File

@@ -5,6 +5,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import org.alfresco.service.cmr.transfer.TransferCallback;
import org.alfresco.service.cmr.transfer.TransferEvent;
import org.alfresco.service.cmr.transfer.TransferEventBegin;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -16,13 +17,23 @@ public class TestTransferCallback implements TransferCallback
private static final long serialVersionUID = 1L;
private static Log logger = LogFactory.getLog(TestTransferCallback.class);
Queue<TransferEvent> events = new ConcurrentLinkedQueue<TransferEvent>();
String transferId = null;
public void processEvent(TransferEvent event)
{
logger.debug(event.toString());
events.add(event);
if(event instanceof TransferEventBegin)
{
TransferEventBegin beginEvent = (TransferEventBegin)event;
transferId = beginEvent.getTransferId();
}
}
Queue<TransferEvent> events = new ConcurrentLinkedQueue<TransferEvent>();
/**
* Get the thread safe queue of events

View File

@@ -25,8 +25,8 @@
package org.alfresco.repo.transfer;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.service.cmr.action.Action;
@@ -39,11 +39,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Deploys a website to a remote server.
*
* TODO refactor and add to WCM services (when we support WCM deployment config)
*
* @author gavinc
* @author markr
*/
public class TransferAsyncAction extends ActionExecuterAbstractBase
{
@@ -58,15 +55,15 @@ public class TransferAsyncAction extends ActionExecuterAbstractBase
super.name = "transfer-async";
}
@SuppressWarnings("unchecked")
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
System.out.println("In TransferAsyncAction");
logger.debug("In TransferAsyncAction");
String targetName = (String) action.getParameterValue("targetName");
TransferDefinition definition = (TransferDefinition) action.getParameterValue("definition");
Set<TransferCallback> callback = (Set<TransferCallback>) action.getParameterValue("callbacks");
Collection<TransferCallback> callback = (Collection<TransferCallback>) action.getParameterValue("callbacks");
transferService.transfer(targetName, definition, callback);
}

View File

@@ -0,0 +1,46 @@
package org.alfresco.repo.transfer;
import java.util.List;
import org.alfresco.repo.action.ParameterDefinitionImpl;
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.transfer.TransferReceiver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class TransferCommitActionExecuter extends ActionExecuterAbstractBase
{
private Log log = LogFactory.getLog(TransferCommitActionExecuter.class);
public static final String NAME = "commit-transfer";
public static final String PARAM_TRANSFER_ID = "transfer-id";
private TransferReceiver receiver;
public void setReceiver(TransferReceiver receiver)
{
this.receiver = receiver;
}
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
String transferId = (String)action.getParameterValue(PARAM_TRANSFER_ID);
if (log.isDebugEnabled())
{
log.debug("Transfer id = " + transferId);
}
receiver.commit(transferId);
}
@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{
paramList.add(new ParameterDefinitionImpl(PARAM_TRANSFER_ID, DataTypeDefinition.TEXT, true,
getParamDisplayLabel(PARAM_TRANSFER_ID)));
}
}

View File

@@ -0,0 +1,35 @@
package org.alfresco.repo.transfer;
import org.alfresco.repo.transaction.TransactionListenerAdapter;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferReceiver;
public class TransferCommitTransactionListener extends TransactionListenerAdapter
{
private TransferReceiver receiver;
private String transferId;
public TransferCommitTransactionListener(String transferId, TransferReceiver receiver)
{
super();
this.receiver = receiver;
this.transferId = transferId;
}
@Override
public void afterCommit()
{
updateTransferStatus(TransferProgress.Status.COMPLETE);
}
@Override
public void afterRollback()
{
updateTransferStatus(TransferProgress.Status.ERROR);
}
private void updateTransferStatus(TransferProgress.Status status)
{
receiver.getProgressMonitor().updateStatus(transferId, status);
}
}

View File

@@ -24,7 +24,6 @@
*/
package org.alfresco.repo.transfer;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
@@ -32,6 +31,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.transfer.TransferCallback;
import org.alfresco.service.cmr.transfer.TransferEvent;
import org.alfresco.service.cmr.transfer.TransferEventBegin;
import org.alfresco.service.cmr.transfer.TransferEventCommittingStatus;
import org.alfresco.service.cmr.transfer.TransferEventEndState;
import org.alfresco.service.cmr.transfer.TransferEventEnterState;
@@ -77,6 +77,17 @@ public class TransferEventProcessor
}
public void begin(String transferId)
{
setState(TransferEvent.TransferState.START);
TransferEventBegin event = new TransferEventBegin();
event.setTransferState(TransferEvent.TransferState.START);
event.setMessage("begin transferId:" + transferId);
queue.add(event);
event.setTransferId(transferId);
notifyObservers();
}
public void start()
{
setState(TransferEvent.TransferState.START);
@@ -93,6 +104,7 @@ public class TransferEventProcessor
TransferEventSuccess event = new TransferEventSuccess();
event.setTransferState(TransferEvent.TransferState.SUCCESS);
event.setLast(true);
event.setMessage("success lastEvent:true");
queue.add(event);
notifyObservers();
}
@@ -107,6 +119,7 @@ public class TransferEventProcessor
TransferEventError event = new TransferEventError();
event.setTransferState(TransferEvent.TransferState.ERROR);
event.setLast(true);
event.setMessage("error lastEvent:true, " + exception.getMessage());
event.setException(exception);
queue.add(event);
notifyObservers();
@@ -157,6 +170,12 @@ public class TransferEventProcessor
notifyObservers();
}
public void commit()
{
setState(TransferEvent.TransferState.COMMITTING);
notifyObservers();
}
/**
*
* @param range

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2009-2010 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 received 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.transfer;
import org.alfresco.service.cmr.transfer.TransferException;
/**
* @author brian
*
*/
public class TransferFatalException extends TransferException
{
private static final long serialVersionUID = 1022985703059592513L;
/**
* @param msgId
* @param msgParams
* @param cause
*/
public TransferFatalException(String msgId, Object[] msgParams, Throwable cause)
{
super(msgId, msgParams, cause);
}
/**
* @param msgId
* @param msgParams
*/
public TransferFatalException(String msgId, Object[] msgParams)
{
super(msgId, msgParams);
}
/**
* @param msgId
* @param cause
*/
public TransferFatalException(String msgId, Throwable cause)
{
super(msgId, cause);
}
/**
* @param msgId
*/
public TransferFatalException(String msgId)
{
super(msgId);
}
}

View File

@@ -30,6 +30,7 @@ import org.alfresco.service.namespace.QName;
* Transfer Model Constants
*
* @author Mark Rogers
* @author Brian Remmington
*/
public interface TransferModel
{
@@ -62,9 +63,25 @@ public interface TransferModel
static final QName TYPE_TRANSFER_LOCK = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferLock");
static final QName PROP_TRANSFER_ID = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferId");
/*
* Type : Transfer Record
*/
static final QName TYPE_TRANSFER_RECORD = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferRecord");
static final QName PROP_PROGRESS_POSITION = QName.createQName(TRANSFER_MODEL_1_0_URI, "progressPosition");
static final QName PROP_PROGRESS_ENDPOINT = QName.createQName(TRANSFER_MODEL_1_0_URI, "progressEndpoint");
static final QName PROP_TRANSFER_STATUS = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferStatus");
static final QName PROP_TRANSFER_ERROR = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferError");
/*
* Type : Transfer report
*/
static final QName TYPE_TRANSFER_REPORT = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferReport");
/*
* Type : Temp Transfer Storage
*/
static final QName TYPE_TEMP_TRANSFER_STORE = QName.createQName(TRANSFER_MODEL_1_0_URI, "tempTransferStore");
static final QName ASSOC_TRANSFER_ORPHAN = QName.createQName(TRANSFER_MODEL_1_0_URI, "orphan");
}

View File

@@ -25,27 +25,23 @@
package org.alfresco.repo.transfer;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.alfresco.repo.action.ParameterDefinitionImpl;
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.transfer.TransferDefinition;
import org.alfresco.service.cmr.transfer.TransferService;
import org.alfresco.service.cmr.transfer.TransferTarget;
/**
* @author brian
*
*/
public class TransferActionExecuter extends ActionExecuterAbstractBase
public class TransferOneNodeActionExecuter extends ActionExecuterAbstractBase
{
public static final String NAME = "transfer-node";
public static final String PARAM_TRANSFER_TARGET = "target-name";
public static final String NAME = "transfer-this-node";
private TransferService transferService;
/**
@@ -62,20 +58,14 @@ public class TransferActionExecuter extends ActionExecuterAbstractBase
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
TransferTarget target = TransferTestUtil.getTestTarget(transferService);
TransferDefinition td = new TransferDefinition();
Set<NodeRef> nodes = new HashSet<NodeRef>();
nodes.add(actionedUponNodeRef);
td.setNodes(nodes);
transferService.transfer("transferMe", td);
td.setNodes(actionedUponNodeRef);
transferService.transfer(target.getName(), td);
}
/* (non-Javadoc)
* @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List)
*/
@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{
//paramList.add(new ParameterDefinitionImpl(PARAM_TRANSFER_TARGET, DataTypeDefinition.TEXT, true, "Transfer Target Name"));
}
}

View File

@@ -33,7 +33,10 @@ import org.alfresco.service.cmr.transfer.TransferException;
*/
public class TransferProcessingException extends TransferException
{
private boolean fatal = false;
/**
*
*/
private static final long serialVersionUID = 2547803698674661069L;
/**
* @param msgId
@@ -70,21 +73,4 @@ public class TransferProcessingException extends TransferException
{
super(msgId);
}
/**
* @return the fatal
*/
public boolean isFatal()
{
return fatal;
}
/**
* @param fatal the fatal to set
*/
public void setFatal(boolean fatal)
{
this.fatal = fatal;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2009-2010 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 received 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.transfer;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
/**
* @author brian
*
*/
public interface TransferProgressMonitor
{
void log(String transferId, Object obj) throws TransferException;
void log(String transferId, Object obj, Throwable ex) throws TransferException;
void updateProgress(String transferId, int currPos) throws TransferException;
void updateProgress(String transferId, int currPos, int endPos) throws TransferException;
void updateStatus(String transferId, TransferProgress.Status status) throws TransferException;
TransferProgress getProgress(String transferId) throws TransferException;
}

View File

@@ -30,6 +30,10 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -80,6 +84,7 @@ import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.transfer.TransferCallback;
import org.alfresco.service.cmr.transfer.TransferDefinition;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferService;
import org.alfresco.service.cmr.transfer.TransferTarget;
import org.alfresco.service.namespace.NamespaceService;
@@ -99,8 +104,14 @@ public class TransferServiceImpl implements TransferService
private static final String MSG_NO_GROUP = "transfer_service.unable_to_find_transfer_group";
private static final String MSG_NO_TARGET = "transfer_service.unable_to_find_transfer_target";
private static final String MSG_TARGET_EXISTS = "transfer_service.target_exists";
private static final String MSG_CANCELLED = "transfer_service.cancelled";
private static final String MSG_NO_NODES = "transfer_service.no_nodes";
/**
* The synchronised list of transfers in progress.
*/
private Map<String, TransferStatus> transferMonitoring = Collections.synchronizedMap(new HashMap<String,TransferStatus>());
private static Log logger = LogFactory.getLog(TransferServiceImpl.class);
public void init()
@@ -125,6 +136,11 @@ public class TransferServiceImpl implements TransferService
private TransferManifestNodeFactory transferManifestNodeFactory;
private TransferReporter transferReporter;
/**
* How long to delay while polling for commit status.
*/
private long commitPollDelay = 2000;
/**
* create transfer target
*/
@@ -269,6 +285,11 @@ public class TransferServiceImpl implements TransferService
nodeService.setProperty(nodeRef, TransferModel.PROP_ENABLED, new Boolean(enable));
}
public boolean targetExists(String name)
{
return (lookupTransferTarget(name) != null);
}
/**
*
*/
@@ -321,7 +342,7 @@ public class TransferServiceImpl implements TransferService
}
/**
*
* Transfer sync without callbacks.
*/
public NodeRef transfer(String targetName, TransferDefinition definition)
{
@@ -335,8 +356,22 @@ public class TransferServiceImpl implements TransferService
* @param targetName
* @param definition
* @param callbacks
*
*/
public void transferAsync(String targetName, TransferDefinition definition, Set<TransferCallback> callbacks)
public void transferAsync(String targetName, TransferDefinition definition, TransferCallback... callbacks)
{
transferAsync(targetName, definition, Arrays.asList(callbacks));
}
/**
* Transfer async.
*
* @param targetName
* @param definition
* @param callbacks
*
*/
public void transferAsync(String targetName, TransferDefinition definition, Collection<TransferCallback> callbacks)
{
/**
* Event processor for this transfer instance
@@ -399,7 +434,20 @@ public class TransferServiceImpl implements TransferService
* @param definition
* @param callbacks
*/
public NodeRef transfer(String targetName, TransferDefinition definition, Set<TransferCallback> callbacks)
public NodeRef transfer(String targetName, TransferDefinition definition, TransferCallback... callbacks)
{
return transfer(targetName, definition, Arrays.asList(callbacks));
}
/**
* Transfer Synchronous
*
* @param targetName
* @param definition
* @param callbacks
*/
public NodeRef transfer(String targetName, TransferDefinition definition, Collection<TransferCallback> callbacks)
{
/**
* Event processor for this transfer instance
@@ -425,15 +473,13 @@ public class TransferServiceImpl implements TransferService
*/
private NodeRef transferImpl(String targetName, final TransferDefinition definition, final TransferEventProcessor eventProcessor)
{
NodeRef reportNode = null;
if(logger.isDebugEnabled())
{
logger.debug("transfer started to :" + targetName);
}
/**
* Wire in the transferReport
* Wire in the transferReport - so any callbacks are stored in transferReport
*/
final List<TransferEvent> transferReport = new LinkedList<TransferEvent>();
TransferCallback reportCallback = new TransferCallback()
@@ -468,8 +514,6 @@ public class TransferServiceImpl implements TransferService
String prefix = "TRX-SNAP";
String suffix = ".xml";
long numberOfNodes = 0;
logger.debug("create snapshot");
// where to put snapshot ?
@@ -481,13 +525,13 @@ public class TransferServiceImpl implements TransferService
TransferManifestWriter formatter = new XMLTransferManifestWriter();
TransferManifestHeader header = new TransferManifestHeader();
header.setCreatedDate(new Date());
header.setNodeCount(nodes.size());
formatter.startTransferManifest(snapshotWriter);
formatter.writeTransferManifestHeader(header);
for(NodeRef nodeRef : nodes)
{
TransferManifestNode node = transferManifestNodeFactory.createTransferManifestNode(nodeRef);
formatter.writeTransferManifestNode(node);
numberOfNodes++;
}
formatter.endTransferManifest();
snapshotWriter.close();
@@ -500,8 +544,10 @@ public class TransferServiceImpl implements TransferService
{
outputFile(snapshotFile);
}
catch (Exception error)
catch (IOException error)
{
// This is debug code - so an exception thrown while debugging
logger.debug("error while outputting snapshotFile");
error.printStackTrace();
}
}
@@ -509,15 +555,22 @@ public class TransferServiceImpl implements TransferService
/**
* Begin
*/
logger.debug("transfer begin");
eventProcessor.start();
final Transfer transfer = transmitter.begin(target);
if(transfer != null)
{
logger.debug("transfer begin");
String transferId = transfer.getTransferId();
TransferStatus status = new TransferStatus(transferId);
transferMonitoring.put(transferId, status);
logger.debug("transfer begun transferId:" + transferId);
boolean prepared = false;
try
{
eventProcessor.begin(transferId);
checkCancel(transferId);
/**
* send Manifest
*/
@@ -528,16 +581,19 @@ public class TransferServiceImpl implements TransferService
/**
* Parse the manifest file and transfer chunks over
*
* ManifestFile -> Manifest Processor -> Chunker -> Transmitter
*
* Step 1: Create a chunker and wire it up to the transmitter
*/
// create a chunker and wire it up to the transmitter
final ContentChunker chunker = new ContentChunkerImpl();
final Long fRange = Long.valueOf(numberOfNodes);
final Long fRange = Long.valueOf(nodes.size());
chunker.setHandler(
new ContentChunkProcessor(){
private long counter = 0;
public void processChunk(Set<ContentData> data)
{
checkCancel(transfer.getTransferId());
logger.debug("send chunk to transmitter");
for(ContentData file : data)
{
@@ -549,8 +605,9 @@ public class TransferServiceImpl implements TransferService
}
);
// create a manifest processor and wire it up to the chunker
/**
* Step 2 : create a manifest processor and wire it up to the chunker
*/
TransferManifestProcessor processor = new TransferManifestProcessor()
{
public void processTransferManifestNode(TransferManifestNormalNode node)
@@ -558,6 +615,7 @@ public class TransferServiceImpl implements TransferService
Set<ContentData> data = TransferManifestNodeHelper.getContentData(node);
for(ContentData d : data)
{
checkCancel(transfer.getTransferId());
logger.debug("add content to chunker");
chunker.addContent(d);
}
@@ -571,68 +629,103 @@ public class TransferServiceImpl implements TransferService
}
};
// wire up the manifest parser to a manifest processor
/**
* Step 3: wire up the manifest reader to a manifest processor
*/
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser parser;
parser = saxParserFactory.newSAXParser();
XMLTransferManifestReader reader = new XMLTransferManifestReader(processor);
// start the magic
/**
* Step 4: start the magic Give the manifest file to the manifest reader
*/
parser.parse(snapshotFile, reader);
chunker.flush();
/**
* Content all sent over
*/
logger.debug("content sending finished");
checkCancel(transfer.getTransferId());
/**
* prepare
*/
eventProcessor.prepare();
transmitter.prepare(transfer);
logger.debug("prepared");
logger.debug("prepared transferId:" + transferId);
checkCancel(transfer.getTransferId());
/**
* committing
*/
eventProcessor.committing(100, 0);
eventProcessor.commit();
transmitter.commit(transfer);
logger.debug("committing transferId:" + transferId);
checkCancel(transfer.getTransferId());
/**
* need to poll for status
* need to poll for committed status
*/
// transmitter.getCommitStatus(transfer);
TransferProgress progress = null;
eventProcessor.committing(100, 50);
eventProcessor.committing(100, 100);
int position = -1;
for(int retries = 0; retries < 3; retries++)
{
checkCancel(transfer.getTransferId());
try
{
progress = transmitter.getStatus(transfer);
if(progress.getCurrentPosition() != position)
{
position = progress.getCurrentPosition();
eventProcessor.committing(progress.getEndPosition(), position);
}
if(progress.isFinished())
{
logger.debug("isFinished=true");
break;
}
retries = 0;
}
catch (TransferException te)
{
logger.debug("error while committing - retrying", te);
}
/**
* Now sleep for a while.
*/
Thread.sleep(commitPollDelay);
}
logger.debug("Finished transferId:" + transferId);
checkCancel(transfer.getTransferId());
/**
* committed
*/
//eventProcessor.serverMessage("Committed");
eventProcessor.success();
checkCancel(transfer.getTransferId());
prepared = true;
logger.debug("committed");
logger.debug("committed - write transfer report transferId:" + transferId);
// Write the Successful transfer report if we get here
// in its own transaction so it cannot be rolled back
final TransferTarget fTarget = target;
reportNode = transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
logger.debug("transfer report starting");
NodeRef reportNode = transferReporter.createTransferReport(transfer, fTarget, definition, transferReport);
logger.debug("transfer report done");
/**
* Write the Successful transfer report if we get here
*/
NodeRef reportNode = persistTransferReport(transfer, target, definition, transferReport, snapshotFile);
logger.debug("success - at end of method transferId:" + transferId);
return reportNode;
}
});
}
finally
{
logger.debug("remove monitoring for transferId:" + transferId);
transferMonitoring.remove(transferId);
logger.debug("removed monitoring for transferId:" + transferId);
if(!prepared)
{
logger.debug("abort incomplete transfer");
@@ -640,33 +733,42 @@ public class TransferServiceImpl implements TransferService
}
}
}
//TODO Do we ever get here ?
logger.debug("returning null - unable lock target");
return null;
}
catch (TransferException t)
{
logger.debug("TransferException - unable to transfer", t);
eventProcessor.error(t);
/**
* Write the transfer report. This is an error report so needs to be out
*/
if(target != null && reportNode!= null)
if(target != null )
{
// reportNode = transferReporter.createTransferReport(target, definition, transferReport);
persistTransferReport(t, target, definition, transferReport, snapshotFile);
}
throw t;
}
catch (Exception t)
{
// Wrap any other exception as a transfer exception
logger.debug("unable to transfer", t);
logger.debug("Exception - unable to transfer", t);
eventProcessor.error(t);
/**
* Write the transfer report. This is an error report so needs to be out
*/
if(target != null && reportNode!= null)
if(target != null )
{
// reportNode = transferReporter.createTransferReport(target, definition, transferReport);
persistTransferReport(t, target, definition, transferReport, snapshotFile);
}
/**
* Wrap the exception as a transfer exception
*/
throw new TransferException("unable to transfer:" + t.toString(), t);
}
finally
@@ -678,10 +780,39 @@ public class TransferServiceImpl implements TransferService
{
snapshotFile.delete();
}
logger.debug("snapshot file deleted");
}
} // end of transferImpl
/**
* CancelAsync
*/
public void cancelAsync(String transferHandle)
{
TransferStatus status = transferMonitoring.get(transferHandle);
if(status != null)
{
logger.debug("canceling transfer :" + transferHandle);
status.cancelMe = true;
}
}
return reportNode;
} // end of transferImpl
/**
* Check whether the specified transfer should be cancelled.
* @param transferHandle
* @throws TransferException - the transfer has been cancelled.
*/
private void checkCancel(String transferHandle) throws TransferException
{
TransferStatus status = transferMonitoring.get(transferHandle);
if(status != null)
{
if(status.cancelMe)
{
throw new TransferException(MSG_CANCELLED);
}
}
}
public void setNodeService(NodeService nodeService)
{
@@ -836,7 +967,7 @@ public class TransferServiceImpl implements TransferService
* Utility to dump the contents of a file to the console
* @param file
*/
private static void outputFile(File file) throws Exception
private static void outputFile(File file) throws IOException
{
BufferedReader reader = new BufferedReader(new FileReader(file));
String s = reader.readLine();
@@ -847,6 +978,48 @@ public class TransferServiceImpl implements TransferService
}
}
/**
* Success transfer report
*/
private NodeRef persistTransferReport(final Transfer transfer, final TransferTarget target, final TransferDefinition definition, final List<TransferEvent> events, final File snapshotFile)
{
/**
* persist the transfer report in its own transaction so it cannot be rolled back
*/
NodeRef reportNode = transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
logger.debug("transfer report starting");
NodeRef reportNode = transferReporter.createTransferReport(transfer, target, definition, events, snapshotFile);
logger.debug("transfer report done");
return reportNode;
}
}, false, true);
return reportNode;
}
/**
* Error Transfer report
*/
private NodeRef persistTransferReport(final Exception t, final TransferTarget target, final TransferDefinition definition, final List<TransferEvent> events, final File snapshotFile)
{
// in its own transaction so it cannot be rolled back
NodeRef reportNode = transactionService.getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
logger.debug("transfer report starting");
NodeRef reportNode = transferReporter.createTransferReport(t, target, definition, events, snapshotFile);
logger.debug("transfer report done");
return reportNode;
}
}, false, true);
return reportNode;
}
public void setTransferManifestNodeFactory(TransferManifestNodeFactory transferManifestNodeFactory)
{
this.transferManifestNodeFactory = transferManifestNodeFactory;
@@ -886,4 +1059,24 @@ public class TransferServiceImpl implements TransferService
{
return transferReporter;
}
public void setCommitPollDelay(long commitPollDelay)
{
this.commitPollDelay = commitPollDelay;
}
public long getCommitPollDelay()
{
return commitPollDelay;
}
private class TransferStatus
{
TransferStatus(String transferId)
{
this.transferId = transferId;
}
String transferId;
boolean cancelMe = false;
}
}

View File

@@ -0,0 +1,29 @@
package org.alfresco.repo.transfer;
import org.alfresco.service.cmr.transfer.TransferService;
import org.alfresco.service.cmr.transfer.TransferTarget;
public class TransferTestUtil
{
private final static String TEST_TARGET_NAME = "TestTarget";
private TransferTestUtil()
{
// Static methods only
}
public static TransferTarget getTestTarget(TransferService transferService)
{
TransferTarget target;
if (!transferService.targetExists(TEST_TARGET_NAME))
{
target = transferService.createTransferTarget(TEST_TARGET_NAME, "Test Target", "Test Target", "http",
"localhost", 8090, "/alfresco/service/api/transfer", "admin", "admin".toCharArray());
}
else
{
target = transferService.getTransferTarget(TEST_TARGET_NAME);
}
return target;
}
}

View File

@@ -31,6 +31,7 @@ import java.util.Set;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferTarget;
/**
@@ -93,6 +94,11 @@ public interface TransferTransmitter
*/
void abort(Transfer transfer) throws TransferException;
/**
* Get the status of an in process transfer
*/
TransferProgress getStatus(Transfer transfer) throws TransferException;
/**
* Get Async Messages for a transfer.
* Server Side Messages.

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2009-2010 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 received 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.transfer;
import java.util.List;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.transfer.NodeCrawler;
import org.alfresco.service.cmr.transfer.TransferDefinition;
import org.alfresco.service.cmr.transfer.TransferService;
import org.alfresco.service.cmr.transfer.TransferTarget;
/**
* @author brian
*
*/
public class TransferTreeActionExecuter extends ActionExecuterAbstractBase
{
public static final String NAME = "transfer-this-tree";
private TransferService transferService;
private ServiceRegistry serviceRegistry;
/**
* @param transferService the transferService to set
*/
public void setTransferService(TransferService transferService)
{
this.transferService = transferService;
}
public void setServiceRegistry(ServiceRegistry serviceRegistry)
{
this.serviceRegistry = serviceRegistry;
}
/* (non-Javadoc)
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
TransferTarget target = TransferTestUtil.getTestTarget(transferService);
NodeCrawler crawler = new StandardNodeCrawlerImpl(serviceRegistry);
crawler.setNodeFinders(new ChildAssociatedNodeFinder(ContentModel.ASSOC_CONTAINS));
Set<NodeRef> nodes = crawler.crawl(actionedUponNodeRef);
TransferDefinition td = new TransferDefinition();
td.setNodes(nodes);
transferService.transfer(target.getName(), td);
}
@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2009-2010 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 received 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.transfer;
import java.util.List;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.transfer.NodeCrawler;
import org.alfresco.service.cmr.transfer.TransferCallback;
import org.alfresco.service.cmr.transfer.TransferDefinition;
import org.alfresco.service.cmr.transfer.TransferEvent;
import org.alfresco.service.cmr.transfer.TransferEventBegin;
import org.alfresco.service.cmr.transfer.TransferEventCommittingStatus;
import org.alfresco.service.cmr.transfer.TransferService;
import org.alfresco.service.cmr.transfer.TransferTarget;
/**
* @author brian
*
*/
public class TransferTreeWithCancelActionExecuter extends ActionExecuterAbstractBase
{
public static final String NAME = "transfer-tree-with-cancel";
private TransferService transferService;
private ServiceRegistry serviceRegistry;
/**
* @param transferService the transferService to set
*/
public void setTransferService(TransferService transferService)
{
this.transferService = transferService;
}
public void setServiceRegistry(ServiceRegistry serviceRegistry)
{
this.serviceRegistry = serviceRegistry;
}
/* (non-Javadoc)
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
*/
@SuppressWarnings("serial")
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
TransferTarget target = serviceRegistry.getTransactionService().getRetryingTransactionHelper().doInTransaction(
new RetryingTransactionHelper.RetryingTransactionCallback<TransferTarget>()
{
public TransferTarget execute() throws Throwable
{
return TransferTestUtil.getTestTarget(transferService);
}
}, false, true);
NodeCrawler crawler = new StandardNodeCrawlerImpl(serviceRegistry);
crawler.setNodeFinders(new ChildAssociatedNodeFinder(ContentModel.ASSOC_CONTAINS));
Set<NodeRef> nodes = crawler.crawl(actionedUponNodeRef);
TransferDefinition td = new TransferDefinition();
td.setNodes(nodes);
transferService.transferAsync(target.getName(), td, new TransferCallback(){
private String transferId;
public void processEvent(TransferEvent event)
{
if (event instanceof TransferEventBegin)
{
transferId = ((TransferEventBegin)event).getTransferId();
}
else if (event instanceof TransferEventCommittingStatus)
{
transferService.cancelAsync(transferId);
}
}
});
}
@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{
}
}

View File

@@ -33,11 +33,14 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferReceiver;
import org.alfresco.service.cmr.transfer.TransferTarget;
import org.alfresco.service.transaction.TransactionService;
/**
* This class delegates transfer service to the transfer receiver without
@@ -53,14 +56,20 @@ public class UnitTestInProcessTransmitterImpl implements TransferTransmitter
private TransferReceiver receiver;
private ContentService contentService;
private TransactionService transactionService;
public UnitTestInProcessTransmitterImpl(TransferReceiver receiver, ContentService contentService)
public UnitTestInProcessTransmitterImpl(TransferReceiver receiver, ContentService contentService, TransactionService transactionService)
{
this.receiver = receiver;
this.contentService = contentService;
this.transactionService = transactionService;
}
public Transfer begin(TransferTarget target) throws TransferException
public Transfer begin(final TransferTarget target) throws TransferException
{
return transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Transfer>()
{
public Transfer execute() throws Throwable
{
Transfer transfer = new Transfer();
String transferId = receiver.start();
@@ -68,17 +77,33 @@ public class UnitTestInProcessTransmitterImpl implements TransferTransmitter
transfer.setTransferTarget(target);
return transfer;
}
public void abort(Transfer transfer) throws TransferException
{
String transferId = transfer.getTransferId();
receiver.abort(transferId);
}, false, true);
}
public void commit(Transfer transfer) throws TransferException
public void abort(final Transfer transfer) throws TransferException
{
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Transfer>()
{
public Transfer execute() throws Throwable
{
String transferId = transfer.getTransferId();
receiver.cancel(transferId);
return null;
}
}, false, true);
}
public void commit(final Transfer transfer) throws TransferException
{
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Transfer>()
{
public Transfer execute() throws Throwable
{
String transferId = transfer.getTransferId();
receiver.commit(transferId);
return null;
}
}, false, true);
}
public Set<TransferMessage> getMessages(Transfer transfer)
@@ -128,6 +153,12 @@ public class UnitTestInProcessTransmitterImpl implements TransferTransmitter
}
public TransferProgress getStatus(Transfer transfer) throws TransferException
{
String transferId = transfer.getTransferId();
return receiver.getStatus(transferId);
}
public void setReceiver(TransferReceiver receiver)
{
this.receiver = receiver;
@@ -147,4 +178,6 @@ public class UnitTestInProcessTransmitterImpl implements TransferTransmitter
{
return contentService;
}
}

View File

@@ -25,7 +25,6 @@
package org.alfresco.repo.transfer.manifest;
import org.alfresco.repo.transfer.TransferModel;
import org.alfresco.service.namespace.QName;
/**
* The transfer model - extended for XML Manifest Model
@@ -35,6 +34,7 @@ public interface ManifestModel extends TransferModel
static final String LOCALNAME_TRANSFER_MAINIFEST = "transferManifest";
static final String LOCALNAME_TRANSFER_HEADER = "transferManifestHeader";
static final String LOCALNAME_HEADER_CREATED_DATE = "createdDate";
static final String LOCALNAME_HEADER_NODE_COUNT = "nodeCount";
static final String LOCALNAME_ELEMENT_NODES = "nodes";
static final String LOCALNAME_ELEMENT_NODE = "node";
static final String LOCALNAME_ELEMENT_DELETED_NODE = "deletedNode";
@@ -52,7 +52,9 @@ public interface ManifestModel extends TransferModel
static final String LOCALNAME_ELEMENT_PRIMARY_PARENT = "primaryParent";
static final String LOCALNAME_ELEMENT_PRIMARY_PATH = "primaryPath";
static final String LOCALNAME_ELEMENT_VALUES = "values";
static final String LOCALNAME_ELEMENT_VALUE = "value";
static final String LOCALNAME_ELEMENT_VALUE_STRING = "value";
static final String LOCALNAME_ELEMENT_VALUE_NULL = "nullValue";
static final String LOCALNAME_ELEMENT_VALUE_SERIALIZED = "serializedValue";
static final String LOCALNAME_ELEMENT_MLVALUE = "mlvalue";
static final String LOCALNAME_ELEMENT_CONTENT_HEADER = "content";

View File

@@ -35,6 +35,7 @@ import java.util.Date;
public class TransferManifestHeader
{
private Date createdDate;
private int nodeCount;
public void setCreatedDate(Date createDate)
{
@@ -46,4 +47,20 @@ public class TransferManifestHeader
return createdDate;
}
/**
* @return the nodeCount
*/
public int getNodeCount()
{
return nodeCount;
}
/**
* @param nodeCount the nodeCount to set
*/
public void setNodeCount(int nodeCount)
{
this.nodeCount = nodeCount;
}
}

View File

@@ -57,6 +57,11 @@ import junit.framework.TestCase;
public class TransferManifestTest extends TestCase
{
/**
* This unit test creates and reads a manifest.
*
* @throws Exception
*/
public void testCreateAndReadSnapshot() throws Exception
{
/**
@@ -78,7 +83,8 @@ public class TransferManifestTest extends TestCase
// node to transmit
TransferManifestNormalNode node = new TransferManifestNormalNode();
node.setNodeRef(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "123"));
NodeRef nodeRefA = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "123");
node.setNodeRef(nodeRefA);
node.setParentPath(new Path());
Set<QName> aspects = new HashSet<QName>();
aspects.add(QName.createQName("{gsxhjsx}", "cm:wobble"));
@@ -86,17 +92,70 @@ public class TransferManifestTest extends TestCase
node.setAspects(aspects);
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
/**
* String type
*/
properties.put(QName.createQName("{gsxhjsx}", "cm:name"), "brian.jpg");
/**
* Date type
*/
properties.put(QName.createQName("{gsxhjsx}", "cm:created"), new java.util.Date());
/**
* Boolean type
*/
properties.put(QName.createQName("{gsxhjsx}", "trx:enabled"), Boolean.FALSE);
/**
* MLText value
*/
MLText mltext = new MLText();
mltext.addValue(Locale.FRENCH, "Bonjour");
mltext.addValue(Locale.ENGLISH, "Hello");
mltext.addValue(Locale.ITALY, "Buongiorno");
properties.put(QName.createQName("{gsxhjsx}", "cm:title"), mltext);
String password = "helloWorld";
/**
* Put a char array type
*/
properties.put(QName.createQName("{gsxhjsx}", "trx:password"), password.toCharArray());
/**
* Put an ArrayList type
*/
ArrayList a1 = new ArrayList();
a1.add("Rhubarb");
a1.add("Custard");
properties.put(QName.createQName("{gsxhjsx}", "trx:arrayList"), a1);
/**
* Put a HashMap type
*/
HashMap m1 = new HashMap();
m1.put("Rhubarb", "Rhubarb");
m1.put("Custard", "Custard");
properties.put(QName.createQName("{gsxhjsx}", "trx:hashMap"), m1);
/**
* Put a null value
*/
properties.put(QName.createQName("{gsxhjsx}", "cm:nullTest"), null);
/**
* Put a node ref property
*/
properties.put(QName.createQName("{gsxhjsx}", "trx:nodeRef"), new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "P1"));
/**
* Put an obscure "unknown type".
*/
// TestPrivateBean obscure = new TestPrivateBean();
// obscure.a = "hello";
// obscure.b = "world";
// properties.put(QName.createQName("{gsxhjsx}", "cm:obscure"), obscure);
List<ChildAssociationRef> parents = new ArrayList<ChildAssociationRef>();
ChildAssociationRef primaryParent = new ChildAssociationRef(QName.createQName("{gsxhjsx}", "cm:contains"),
@@ -201,14 +260,68 @@ public class TransferManifestTest extends TestCase
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser parser = saxParserFactory.newSAXParser();
TransferManifestProcessor tp = new TestTransferManifestProcessor();
TestTransferManifestProcessor tp = new TestTransferManifestProcessor();
XMLTransferManifestReader xmlReader = new XMLTransferManifestReader(tp);
parser.parse(snapshotFile, xmlReader );
/**
* Now validate the parsed data.
*/
Map<NodeRef, TransferManifestNode> nodes = tp.getNodes();
TransferManifestNormalNode rxNodeA = (TransferManifestNormalNode)nodes.get(nodeRefA);
assertNotNull("rxNodeA is null", rxNodeA);
Map<QName, Serializable> rxNodeAProps = rxNodeA.getProperties();
System.out.println(rxNodeAProps.get(QName.createQName("{gsxhjsx}", "trx:password")));
for(Map.Entry value : rxNodeAProps.entrySet())
{
System.out.println("key = " + value.getKey() + " value =" + value.getValue());
if(value.getValue() != null)
{
if(value.getValue().getClass().isArray())
{
System.out.println("arrayValue="+ value.getValue().toString());
char[] chars = (char[])value.getValue();
System.out.println(chars);
}
}
}
tp.getHeader();
snapshotFile.delete();
}
public class TestPrivateBean implements Serializable
{
public TestPrivateBean()
{
}
public void setA(String a)
{
this.a = a;
}
public String getA()
{
return a;
}
/**
*
*/
private static final long serialVersionUID = 1053132227110567282L;
private String a;
private String b;
}
}

View File

@@ -24,6 +24,10 @@
*/
package org.alfresco.repo.transfer.manifest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -33,21 +37,18 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.alfresco.repo.transfer.PathHelper;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.namespace.NamespaceException;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ISO9075;
import org.springframework.extensions.surf.util.Base64;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.extensions.surf.util.ISO8601DateFormat;
import org.xml.sax.Attributes;
@@ -56,8 +57,6 @@ import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.io.Serializable;
/**
* SAX XML Content Handler to read a transfer manifest XML Stream and
* delegate processing to the specified TransferManifestProcessor
@@ -150,22 +149,19 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
{
// Good we got this
}
if(elementName.equals(ManifestModel.LOCALNAME_TRANSFER_HEADER))
else if(elementName.equals(ManifestModel.LOCALNAME_TRANSFER_HEADER))
{
TransferManifestHeader header = new TransferManifestHeader();
props.put("header", header);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_DELETED_NODE))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_DELETED_NODE))
{
TransferManifestDeletedNode node = new TransferManifestDeletedNode();
NodeRef nodeRef = new NodeRef(atts.getValue("", "nodeRef"));
node.setNodeRef(nodeRef);
props.put("node", node);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_NODE))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_NODE))
{
TransferManifestNormalNode node = new TransferManifestNormalNode();
NodeRef nodeRef = new NodeRef(atts.getValue("", "nodeRef"));
@@ -174,50 +170,47 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
node.setType(type);
props.put("node", node);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECTS))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECTS))
{
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
node.setAspects(new HashSet<QName>());
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECT))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECT))
{
buffer = new StringBuffer();
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTIES))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTIES))
{
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
HashMap<QName, Serializable>properties = new HashMap<QName, Serializable>();
node.setProperties(properties);
props.put("properties", properties);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTY))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTY))
{
QName name = QName.createQName(atts.getValue("", "name"));
props.put("name", name);
props.remove("values");
props.remove("mltext");
}
if(elementName.equals(ManifestModel.LOCALNAME_HEADER_CREATED_DATE))
else if(elementName.equals(ManifestModel.LOCALNAME_HEADER_CREATED_DATE))
{
buffer = new StringBuffer();
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOCS))
else if(elementName.equals(ManifestModel.LOCALNAME_HEADER_NODE_COUNT))
{
buffer = new StringBuffer();
}
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOCS))
{
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOCS))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOCS))
{
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
node.setChildAssocs(new ArrayList<ChildAssociationRef>());
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOC))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOC))
{
buffer = new StringBuffer();
NodeRef to = new NodeRef(atts.getValue("", "to"));
@@ -228,7 +221,7 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
props.put("type", type);
props.put("isPrimary", isPrimary);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC))
{
buffer = new StringBuffer();
NodeRef from = new NodeRef(atts.getValue("", "from"));
@@ -239,14 +232,14 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
props.put("isPrimary", isPrimary);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_TARGET_ASSOCS))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_TARGET_ASSOCS))
{
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
List<AssociationRef> assocs = new ArrayList<AssociationRef>();
node.setTargetAssocs(assocs);
props.put("assocs", assocs);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_SOURCE_ASSOCS))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_SOURCE_ASSOCS))
{
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
List<AssociationRef> assocs = new ArrayList<AssociationRef>();
@@ -254,7 +247,7 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
props.put("assocs", assocs);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASSOC))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASSOC))
{
NodeRef source = new NodeRef(atts.getValue("", "source"));
NodeRef target = new NodeRef(atts.getValue("", "target"));
@@ -264,20 +257,27 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
props.put("type", type);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PARENT))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PARENT))
{
buffer = new StringBuffer();
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUES))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUES))
{
Collection<Serializable> values = new ArrayList<Serializable>();
props.put("values", values);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUE))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUE_STRING))
{
buffer = new StringBuffer();
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_MLVALUE))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUE_NULL))
{
}
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUE_SERIALIZED))
{
buffer = new StringBuffer();
}
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_MLVALUE))
{
MLText mltext = (MLText)props.get("mlvalues");
if(mltext == null)
@@ -290,7 +290,7 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
props.put("locale", locale);
buffer = new StringBuffer();
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER))
{
String contentURL = (String)atts.getValue("", "contentURL");
String mimetype = (String)atts.getValue("", "mimetype");
@@ -302,9 +302,7 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
ContentData contentHeader = new ContentData(contentURL, mimetype, size.longValue(), encoding, locale);
props.put("contentHeader", contentHeader);
}
}
} // if transfer URI
} // startElement
/**
@@ -330,68 +328,64 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
if(elementName.equals(ManifestModel.LOCALNAME_TRANSFER_MAINIFEST))
{
}
if(elementName.equals(ManifestModel.LOCALNAME_TRANSFER_HEADER))
else if(elementName.equals(ManifestModel.LOCALNAME_TRANSFER_HEADER))
{
TransferManifestHeader header = (TransferManifestHeader)props.get("header");
// User to process the header
processor.processTransferManifiestHeader(header);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_NODE))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_NODE))
{
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
processor.processTransferManifestNode(node);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_DELETED_NODE))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_DELETED_NODE))
{
TransferManifestDeletedNode node = (TransferManifestDeletedNode)props.get("node");
processor.processTransferManifestNode(node);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECTS))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECTS))
{
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECT))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECT))
{
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
node.getAspects().add(QName.createQName(buffer.toString()));
buffer = null;
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTIES))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTIES))
{
// nothing to do
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTY))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTY))
{
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
QName name = (QName)props.get("name");
Serializable value = (Serializable)props.get("value");
node.getProperties().put(name, value);
}
if(elementName.equals(ManifestModel.LOCALNAME_HEADER_CREATED_DATE))
else if(elementName.equals(ManifestModel.LOCALNAME_HEADER_CREATED_DATE))
{
TransferManifestHeader header = (TransferManifestHeader)props.get("header");
header.setCreatedDate(ISO8601DateFormat.parse(buffer.toString()));
buffer = null;
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOCS))
else if(elementName.equals(ManifestModel.LOCALNAME_HEADER_NODE_COUNT))
{
TransferManifestHeader header = (TransferManifestHeader)props.get("header");
header.setNodeCount(Integer.parseInt(buffer.toString()));
buffer = null;
}
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOCS))
{
// No-op
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOCS))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOCS))
{
// No-op
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOC))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOC))
{
String value = buffer.toString();
QName name = QName.createQName(value);
@@ -404,7 +398,7 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
node.getChildAssocs().add(childAssociationRef);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC))
{
String value = buffer.toString();
QName name = QName.createQName(value);
@@ -431,17 +425,17 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
node.setPrimaryParentAssoc(childAssociationRef);
}
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_TARGET_ASSOCS))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_TARGET_ASSOCS))
{
//TransferManifestNode node = (TransferManifestNode)props.get("node");
//node.getTargetAssocs().add((AssociationRef)props.get("assoc"));
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_SOURCE_ASSOCS))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_SOURCE_ASSOCS))
{
//TransferManifestNode node = (TransferManifestNode)props.get("node");
//node.getSourceAssocs().add((AssociationRef)props.get("assoc"));
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASSOC))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASSOC))
{
NodeRef source = (NodeRef)props.get("source");
NodeRef target = (NodeRef)props.get("target");
@@ -451,18 +445,18 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
assocs.add(assoc);
props.put("assoc", new AssociationRef(source, type, target));
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PATH))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PATH))
{
TransferManifestNode node = (TransferManifestNode)props.get("node");
String value = buffer.toString();
Path path = PathHelper.stringToPath(value);
node.setParentPath(path);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUES))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUES))
{
props.put("value", props.get("values"));
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUE))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUE_STRING))
{
Collection<Serializable> values = (Collection<Serializable>)props.get("values");
String value = buffer.toString();
@@ -476,7 +470,54 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
props.put("value", value);
}
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_MLVALUE))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUE_NULL))
{
Collection<Serializable> values = (Collection<Serializable>)props.get("values");
if(values != null)
{
values.add(null);
}
else
{
props.put("value", null);
}
}
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUE_SERIALIZED))
{
Collection<Serializable> values = (Collection<Serializable>)props.get("values");
String strValue = buffer.toString();
Object value = null;
// TODO assumes "base64/ObjectOutputStream" - should check
try
{
byte[] data = Base64.decode(strValue.getBytes("UTF-8"));
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
value = ois.readObject();
}
catch (IOException error)
{
//TODO Error handler - should this fail the transfer ?
error.printStackTrace();
}
catch (ClassNotFoundException error)
{
//TODO Error handler - should this fail the transfer ?
error.printStackTrace();
}
if(values != null)
{
values.add((Serializable)value);
}
else
{
props.put("value", value);
}
}
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_MLVALUE))
{
MLText mltext = (MLText)props.get("mlvalues");
Locale locale = (Locale)props.get("locale");
@@ -485,13 +526,13 @@ public class XMLTransferManifestReader extends DefaultHandler implements Content
props.put("value", mltext);
}
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER))
else if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER))
{
TransferManifestNode node = (TransferManifestNode)props.get("node");
ContentData data = (ContentData)props.get("contentHeader");
props.put("value", data);
}
}
} // if transfer URI
} // end element

View File

@@ -24,6 +24,9 @@
*/
package org.alfresco.repo.transfer.manifest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.Writer;
import java.util.Collection;
@@ -39,17 +42,21 @@ import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.repository.datatype.TypeConversionException;
import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.extensions.surf.util.Base64;
import org.springframework.extensions.surf.util.ISO8601DateFormat;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
//import com.sun.org.apache.xml.internal.security.utils.Base64;
/**
* XMLTransferManifestWriter
*
@@ -116,6 +123,12 @@ public class XMLTransferManifestWriter implements TransferManifestWriter
writeDate(header.getCreatedDate());
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_HEADER_CREATED_DATE, PREFIX + ":" + ManifestModel.LOCALNAME_HEADER_CREATED_DATE);
// Node count
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_HEADER_NODE_COUNT, PREFIX + ":" + ManifestModel.LOCALNAME_HEADER_NODE_COUNT, EMPTY_ATTRIBUTES);
char[] nodeCountChars = Integer.toString(header.getNodeCount()).toCharArray();
writer.characters(nodeCountChars, 0, nodeCountChars.length);
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_HEADER_NODE_COUNT, PREFIX + ":" + ManifestModel.LOCALNAME_HEADER_NODE_COUNT);
// End Header
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_TRANSFER_HEADER, PREFIX + ":" + ManifestModel.LOCALNAME_TRANSFER_HEADER);
}
@@ -217,12 +230,10 @@ public class XMLTransferManifestWriter implements TransferManifestWriter
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PROPERTY, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PROPERTY, attributes);
}
// TODO - Char [] does not seem to be processed correctly
if(value.getClass().isArray())
if(value == null)
{
writeValue(value.toString());
writeNullValue();
}
// Collection
else if(value instanceof ContentData)
{
ContentData data = (ContentData)value;
@@ -235,7 +246,6 @@ public class XMLTransferManifestWriter implements TransferManifestWriter
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER, dataAttributes);
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER);
}
// Collection
else if(value instanceof Collection)
{
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUES, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUES, EMPTY_ATTRIBUTES);
@@ -264,11 +274,59 @@ public class XMLTransferManifestWriter implements TransferManifestWriter
private void writeValue(Serializable value) throws SAXException
{
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUE, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUE, EMPTY_ATTRIBUTES);
try
{
String strValue = (String)DefaultTypeConverter.INSTANCE.convert(String.class, value);
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUE_STRING, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUE_STRING, EMPTY_ATTRIBUTES);
writer.characters(strValue.toCharArray(), 0, strValue.length());
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUE, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUE);
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUE_STRING, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUE_STRING);
}
catch (TypeConversionException e)
{
/**
* Can't convert this to a string for transmission
*
* Need to serialize the Java Object
*/
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos;
oos = new ObjectOutputStream(bos);
oos.writeObject(value);
oos.close();
byte[] ba = bos.toByteArray();
String s = new String(Base64.encodeBytes(ba));
AttributesImpl attributes = new AttributesImpl();
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "className", "className", "String", value.getClass().getName());
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "encoding", "encoding", "String", "base64/ObjectOutputStream");
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUE_SERIALIZED, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUE_SERIALIZED, attributes);
writer.startCDATA();
writer.characters(s.toCharArray(), 0, s.length());
writer.endCDATA();
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUE_SERIALIZED, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUE_SERIALIZED);
}
catch (IOException err)
{
throw new TransferException("Unable to write property value", err);
}
}
}
private void writeNullValue() throws SAXException
{
AttributesImpl attributes = new AttributesImpl();
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUE_NULL, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUE_NULL, attributes);
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUE_NULL, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUE_NULL);
}
private void writeMLValue(Locale locale, Serializable value) throws SAXException

View File

@@ -1,33 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.alfresco.org/model/transferReport/1.0" xmlns:report="http://www.alfresco.org/model/transferReport/1.0" elementFormDefault="qualified">
<schema
targetNamespace="http://www.alfresco.org/model/transferReport/1.0"
xmlns:report="http://www.alfresco.org/model/transferReport/1.0"
xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<!-- XML Schema for the client side transferReport -->
<complexType name="transferReport">
<xs:annotation>
<xs:documentation>
This is the transfer report root tag
</xs:documentation>
</xs:annotation>
<annotation>
<documentation>
This is an alfresco client side transfer report
</documentation>
</annotation>
<sequence>
<element name="target" type="report:target" maxOccurs="1" minOccurs="1"></element>
<element name="definition" type="report:definition" maxOccurs="1" minOccurs="1"></element>
<element name="target" type="report:target" maxOccurs="1"
minOccurs="1">
</element>
<element name="definition" type="report:definition"
maxOccurs="1" minOccurs="1">
</element>
<element name="exception" type="report:exception" maxOccurs="1"
minOccurs="0">
</element>
<element name="events" type="report:events"></element>
</sequence>
</complexType>
<complexType name="target">
<xs:annotation>
<xs:documentation>
<annotation>
<documentation>
The destination of the transfer
</xs:documentation>
</xs:annotation>
</documentation>
</annotation>
<attribute name="name" type="string"></attribute>
<attribute name="endpointPort" type="int"></attribute>
<attribute name="endpointHost" type="string"></attribute>
</complexType>
<complexType name="definition">
</complexType>
<complexType name="definition"></complexType>
<complexType name="events">
<sequence maxOccurs="unbounded" minOccurs="0">
@@ -36,9 +48,11 @@
</complexType>
<complexType name="event">
<attribute name="date" type="dateTime"></attribute>
<!-- message is content -->
</complexType>
<complexType name="exception">
</complexType>
<element name="report" type="string"></element>
</schema>

View File

@@ -35,8 +35,12 @@ public interface TransferReportModel extends TransferModel
static final String LOCALNAME_TRANSFER_REPORT = "transferReport";
static final String LOCALNAME_TRANSFER_TARGET = "target";
static final String LOCALNAME_TRANSFER_DEFINITION = "definition";
static final String LOCALNAME_EXCEPTION = "exception";
static final String LOCALNAME_TRANSFER_EVENTS = "events";
static final String LOCALNAME_TRANSFER_EVENT = "event";
static final String LOCALNAME_TRANSFER_NODE = "node";
static final String LOCALNAME_TRANSFER_PRIMARY_PATH = "primaryPath";
static final String LOCALNAME_TRANSFER_PRIMARY_PARENT = "primaryParent";
static final String REPORT_PREFIX = "report";
static final String TRANSFER_REPORT_MODEL_1_0_URI = "http://www.alfresco.org/model/transferReport/1.0";

View File

@@ -24,6 +24,7 @@
*/
package org.alfresco.repo.transfer.report;
import java.io.File;
import java.util.List;
import org.alfresco.repo.transfer.Transfer;
@@ -35,15 +36,35 @@ import org.alfresco.service.cmr.transfer.TransferTarget;
public interface TransferReporter
{
/**
* Create a transfer report
* Create a transfer report of success
* @param target the target of the transfer
* @param definition the definition of the transfer
* @param events the transfer events generated by the transfer.
* @param snapshotFile
*
* @return the node ref of the transfer report
*/
NodeRef createTransferReport(Transfer transfer,
public NodeRef createTransferReport(Transfer transfer,
TransferTarget target,
TransferDefinition definition,
List<TransferEvent> events);
List<TransferEvent> events,
File snapshotFile
);
/**
* Create a transfer report of failure
* @param e
* @param target
* @param definition
* @param events
* @param snapshotFile
* @return the node ref of the transfer report
*/
public NodeRef createTransferReport(Exception e,
TransferTarget target,
TransferDefinition definition,
List<TransferEvent> events,
File snapshotFile
);
}

View File

@@ -25,19 +25,34 @@
package org.alfresco.repo.transfer.report;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.transfer.Transfer;
import org.alfresco.repo.transfer.TransferModel;
import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode;
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
import org.alfresco.repo.transfer.manifest.TransferManifestNodeHelper;
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
import org.alfresco.repo.transfer.manifest.XMLTransferManifestReader;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -48,6 +63,7 @@ import org.alfresco.service.cmr.transfer.TransferTarget;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.dom4j.io.XMLWriter;
import org.springframework.extensions.surf.util.ISO8601DateFormat;
import org.springframework.extensions.surf.util.PropertyCheck;
import org.xml.sax.SAXException;
@@ -65,20 +81,27 @@ public class TransferReporterImpl implements TransferReporter
PropertyCheck.mandatory(this, "contentService", contentService);
}
/**
* Create a new transfer report
* Write exception transfer report
*
* @return NodeRef the node ref of the new transfer report
*/
public NodeRef createTransferReport(Transfer transfer,
public NodeRef createTransferReport(Exception e,
TransferTarget target,
TransferDefinition definition,
List<TransferEvent> events)
List<TransferEvent> events,
File snapshotFile)
{
Map<QName, Serializable> properties = new HashMap<QName, Serializable> ();
String transferId = transfer.getTransferId();
String title = "transfer report: success :" + transferId;
String name = transferId;
String description = "successful transfer report";
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssSSSZ");
String timeNow = format.format(new Date());
String title = "Transfer report, error, " + timeNow;
String description = "Transfer error report";
String name = "Transfer error report, " + timeNow;
properties.put(ContentModel.PROP_NAME, name);
properties.put(ContentModel.PROP_TITLE, title);
@@ -87,7 +110,7 @@ public class TransferReporterImpl implements TransferReporter
ContentWriter writer = contentService.getWriter(ref.getChildRef(), ContentModel.PROP_CONTENT, true);
writer.setLocale(Locale.getDefault());
writer.setMimetype(MimetypeMap.MIMETYPE_XML);
writer.setEncoding("UTF-8");
writer.setEncoding(DEFAULT_ENCODING);
//
XMLTransferReportWriter reportWriter = new XMLTransferReportWriter();
@@ -96,13 +119,15 @@ public class TransferReporterImpl implements TransferReporter
try
{
reportWriter.startTransferReport("UTF-8", bufferedWriter);
reportWriter.startTransferReport(DEFAULT_ENCODING, bufferedWriter);
// Header
reportWriter.writeTarget(target);
reportWriter.writeDefinition(definition);
reportWriter.writeException(e);
// Detail
reportWriter.writeTransferEvents(events);
@@ -128,6 +153,139 @@ public class TransferReporterImpl implements TransferReporter
}
}
/**
* Create a new transfer report of success
*
* @return NodeRef the node ref of the new transfer report
*/
public NodeRef createTransferReport(Transfer transfer,
TransferTarget target,
TransferDefinition definition,
List<TransferEvent> events,
File snapshotFile)
{
Map<QName, Serializable> properties = new HashMap<QName, Serializable> ();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssSSSZ");
String timeNow = format.format(new Date());
String title = "Transfer report, " + timeNow + "success";
String description = "Transfer report success targetName : " + target.getName();
String name = "Transfer report, " + timeNow;
properties.put(ContentModel.PROP_NAME, name);
properties.put(ContentModel.PROP_TITLE, title);
properties.put(ContentModel.PROP_DESCRIPTION, description);
ChildAssociationRef ref = nodeService.createNode(target.getNodeRef(), ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name), TransferModel.TYPE_TRANSFER_REPORT, properties);
ContentWriter writer = contentService.getWriter(ref.getChildRef(), ContentModel.PROP_CONTENT, true);
writer.setLocale(Locale.getDefault());
writer.setMimetype(MimetypeMap.MIMETYPE_XML);
writer.setEncoding(DEFAULT_ENCODING);
//
final XMLTransferReportWriter reportWriter = new XMLTransferReportWriter();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(writer.getContentOutputStream()));
try
{
reportWriter.startTransferReport(DEFAULT_ENCODING, bufferedWriter);
// Header
reportWriter.writeTarget(target);
reportWriter.writeDefinition(definition);
/**
* Write the node summary details to the transfer report
*/
TransferManifestProcessor processor = new TransferManifestProcessor()
{
public void processTransferManifestNode(TransferManifestNormalNode node)
{
try
{
reportWriter.writeNodeSummary(node);
}
catch (SAXException error)
{
error.printStackTrace();
}
}
public void processTransferManifestNode(TransferManifestDeletedNode node)
{
try
{
reportWriter.writeNodeSummary(node);
}
catch (SAXException error)
{
error.printStackTrace();
}
}
public void processTransferManifiestHeader(TransferManifestHeader header){/* NO-OP */ }
public void startTransferManifest(){ /* NO-OP */ }
public void endTransferManifest(){ /* NO-OP */ }
};
/**
* Step 3: wire up the manifest reader to a manifest processor
*/
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser parser;
parser = saxParserFactory.newSAXParser();
XMLTransferManifestReader reader = new XMLTransferManifestReader(processor);
/**
* Step 4: start the magic Give the manifest file to the manifest reader
*/
try
{
parser.parse(snapshotFile, reader);
}
catch (IOException error)
{
//TODO temp code
error.printStackTrace();
return null;
}
// Detail Events
reportWriter.writeTransferEvents(events);
reportWriter.endTransferReport();
return ref.getChildRef();
}
catch (SAXException se)
{
//TODO Temp code
return null;
}
catch (ParserConfigurationException error)
{
// TODO temp code
error.printStackTrace();
return null;
}
finally
{
try
{
bufferedWriter.close();
}
catch (IOException error)
{
error.printStackTrace();
}
}
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
@@ -148,4 +306,5 @@ public class TransferReporterImpl implements TransferReporter
return contentService;
}
}

View File

@@ -7,9 +7,13 @@ import java.util.List;
import org.alfresco.repo.transfer.TransferModel;
import org.alfresco.repo.transfer.manifest.ManifestModel;
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
import org.alfresco.repo.transfer.manifest.TransferManifestNode;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.transfer.TransferDefinition;
import org.alfresco.service.cmr.transfer.TransferEvent;
import org.alfresco.service.cmr.transfer.TransferTarget;
import org.alfresco.service.namespace.QName;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.extensions.surf.util.ISO8601DateFormat;
@@ -44,7 +48,7 @@ public class XMLTransferReportWriter
this.writer.startPrefixMapping(PREFIX, TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI);
// Start Transfer Manifest // uri, name, prefix
this.writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_REPORT, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_REPORT, EMPTY_ATTRIBUTES);
this.writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_REPORT, TransferReportModel.LOCALNAME_TRANSFER_REPORT, EMPTY_ATTRIBUTES);
}
/**
@@ -53,7 +57,7 @@ public class XMLTransferReportWriter
public void endTransferReport() throws SAXException
{
// End Transfer Manifest
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_REPORT, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_REPORT);
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_REPORT, TransferReportModel.LOCALNAME_TRANSFER_REPORT);
writer.endPrefixMapping(PREFIX);
writer.endDocument();
}
@@ -83,6 +87,18 @@ public class XMLTransferReportWriter
}
/**
* Write the definition to the report
*/
public void writeException(Exception e) throws SAXException
{
AttributesImpl attributes = new AttributesImpl();
attributes.addAttribute(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, "type", "type", "String", e.getClass().getName());
attributes.addAttribute(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, "message", "message", "String", e.getMessage());
writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_EXCEPTION, PREFIX + ":" + TransferReportModel.LOCALNAME_EXCEPTION, attributes);
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_EXCEPTION, PREFIX + ":" + TransferReportModel.LOCALNAME_EXCEPTION);
}
/**
* Write the transfer manifest header
*/
@@ -99,6 +115,57 @@ public class XMLTransferReportWriter
}
/**
* Write the transfer manifest header
*/
public void writeNodeSummary(TransferManifestNode node) throws SAXException
{
AttributesImpl attributes = new AttributesImpl();
attributes.addAttribute("uri", "nodeRef", "nodeRef", "String", node.getNodeRef().toString());
writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_NODE, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_NODE, attributes);
if(node.getPrimaryParentAssoc() != null)
{
writePrimaryParent(node.getPrimaryParentAssoc(), node.getParentPath());
}
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_NODE, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_NODE);
}
private void writePrimaryParent(ChildAssociationRef parentAssoc, Path parentPath) throws SAXException
{
writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_PRIMARY_PARENT, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_PRIMARY_PARENT, EMPTY_ATTRIBUTES);
writeParentAssoc(parentAssoc);
writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_PRIMARY_PATH, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_PRIMARY_PATH, EMPTY_ATTRIBUTES);
if(parentPath != null)
{
String path = parentPath.toString();
writer.characters(path.toCharArray(), 0, path.length());
}
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_PRIMARY_PATH, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PATH);
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_PRIMARY_PARENT, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PARENT);
}
private void writeParentAssoc(ChildAssociationRef assoc) throws SAXException
{
if(assoc != null)
{
AttributesImpl attributes = new AttributesImpl();
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "from", "from", "String", assoc.getParentRef().toString());
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "type", "type", "String", formatQName(assoc.getTypeQName()));
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "type", "isPrimary", "Boolean", assoc.isPrimary()?"true":"false");
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC, attributes);
String name= formatQName(assoc.getQName());
writer.characters(name.toCharArray(), 0, name.length());
assoc.isPrimary();
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC);
}
}
/**
* Write the transfer manifest header
*/
@@ -116,4 +183,10 @@ public class XMLTransferReportWriter
}
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_EVENT, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_EVENT);
}
private String formatQName(QName qname)
{
return qname.toString();
}
}

View File

@@ -0,0 +1,18 @@
package org.alfresco.service.cmr.transfer;
import java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef;
public interface NodeCrawler
{
public abstract Set<NodeRef> crawl(NodeRef... nodes);
public abstract Set<NodeRef> crawl(Set<NodeRef> startingNodes);
public abstract void setNodeFinders(NodeFinder... finders);
public abstract void setNodeFilters(NodeFilter... filters);
}

View File

@@ -25,6 +25,9 @@
package org.alfresco.service.cmr.transfer;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -49,9 +52,14 @@ public class TransferDefinition implements Serializable
* Set which nodes to transfer
* @param nodes
*/
public void setNodes(Set<NodeRef> nodes)
public void setNodes(Collection<NodeRef> nodes)
{
this.nodes = nodes;
this.nodes = new HashSet<NodeRef>(nodes);
}
public void setNodes(NodeRef...nodes)
{
this.setNodes(new HashSet<NodeRef>(Arrays.asList(nodes)));
}
/**

View File

@@ -0,0 +1,50 @@
/*
* 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.service.cmr.transfer;
import org.alfresco.repo.transfer.TransferEventImpl;
/**
* TransferEventBegin is produced when a transfer has started.
*/
public class TransferEventBegin extends TransferEventImpl
{
private String transferId;
public String toString()
{
return "TransferEventBegin: " + transferId;
}
public void setTransferId(String transferId)
{
this.transferId = transferId;
}
public String getTransferId()
{
return transferId;
}
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2009-2010 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 received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.service.cmr.transfer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* @author brian
*
*/
public class TransferProgress
{
public enum Status
{
PRE_COMMIT, COMMIT_REQUESTED, COMMITTING, COMPLETE, ERROR, CANCELLED
};
private static Set<Status> terminalStatuses = Collections.unmodifiableSet(new HashSet<Status>(Arrays.asList(
Status.COMPLETE, Status.ERROR, Status.CANCELLED)));
private Status status;
private int currentPosition;
private int endPosition;
private Throwable error;
/**
*
* @return The statuses that mark the end of the transfer. Once a transfer reaches one of these statuses
* it can never move into a different status.
*/
public static Set<Status> getTerminalStatuses()
{
return terminalStatuses;
}
/**
*
* @return true if the current status is one of the terminal statuses.
*/
public boolean isFinished()
{
return terminalStatuses.contains(status);
}
/**
* @return the status
*/
public Status getStatus()
{
return status;
}
/**
* @param status
* the status to set
*/
public void setStatus(Status status)
{
this.status = status;
}
/**
* @return the currentPosition
*/
public int getCurrentPosition()
{
return currentPosition;
}
/**
* @param currentPosition
* the currentPosition to set
*/
public void setCurrentPosition(int currentPosition)
{
this.currentPosition = currentPosition;
}
/**
* @return the endPosition
*/
public int getEndPosition()
{
return endPosition;
}
/**
* @param endPosition
* the endPosition to set
*/
public void setEndPosition(int endPosition)
{
this.endPosition = endPosition;
}
/**
* @return the error
*/
public Throwable getError()
{
return error;
}
/**
* @param error
* the error to set
*/
public void setError(Throwable error)
{
this.error = error;
}
}

View File

@@ -28,6 +28,7 @@ package org.alfresco.service.cmr.transfer;
import java.io.File;
import java.io.InputStream;
import org.alfresco.repo.transfer.TransferProgressMonitor;
import org.alfresco.service.cmr.repository.NodeRef;
/**
@@ -96,7 +97,14 @@ public interface TransferReceiver
* @param transferId
* @throws TransferException
*/
void abort(String transferId) throws TransferException;
void cancel(String transferId) throws TransferException;
/**
* Commit asynchronously
* @param transferId
* @throws TransferException
*/
void commitAsync(String transferId) throws TransferException;
/**
* Commit
@@ -104,4 +112,8 @@ public interface TransferReceiver
* @throws TransferException
*/
void commit(String transferId) throws TransferException;
TransferProgress getStatus(String transferId) throws TransferException;
TransferProgressMonitor getProgressMonitor();
}

View File

@@ -25,6 +25,7 @@
package org.alfresco.service.cmr.transfer;
import java.util.Collection;
import java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -63,24 +64,55 @@ public interface TransferService
* @throws TransferException
* @return the node reference of the transfer report
*/
public NodeRef transfer(String targetName, TransferDefinition definition, Set<TransferCallback> callback) throws TransferException;
public NodeRef transfer(String targetName, TransferDefinition definition, Collection<TransferCallback> callback) throws TransferException;
/**
* Transfer nodes sync, with callback. This synchronous version of the transfer method waits for the transfer to complete
* before returning to the caller. Callbacks are called in the current thread context, so will be associated with the current
* transaction and user.
*
* @param targetName the name of the target to transfer to
* @param definition - the definition of the transfer. Specifies which nodes to transfer.
* The following properties must be set, nodes
* @param callbacks - a list of callback handlers that will be called as transfer proceeds. May be null.
* @throws TransferException
* @return the node reference of the transfer report
*/
public NodeRef transfer(String targetName, TransferDefinition definition, TransferCallback... callbacks) throws TransferException;
/**
* Transfer nodes async with callback. The asynchronous version of the transfer method starts a transfer and returns as
* soon as possible.
* The transfer callbacks will be called by a different thread to that used to call the transferAsync method so transaction
* context will be different to the calling context.
*
* Please also be aware that the asychronous transfer does not have access to uncommitted
* The transfer callbacks will be called by a different thread to that used to call the transferAsync method so transaction
* context will be different to the calling context. The asychronous transfer does not have access to uncommitted
* data in the calling transaction.
*
* @param targetName the name of the target to transfer to
* @param definition - the definition of the transfer. Specifies which nodes to transfer.
* The following properties must be set, nodes
* @param callback - a set of callback handlers that will be called as transfer proceeds. May be null.
* @param callback - a collection of callback handlers that will be called as transfer proceeds. May be null.
*
* @throws TransferException
*/
public void transferAsync(String targetName, TransferDefinition definition, Set<TransferCallback> callback) throws TransferException;
public void transferAsync(String targetName, TransferDefinition definition, Collection<TransferCallback> callback) throws TransferException;
/**
* Transfer nodes async with callback. The asynchronous version of the transfer method starts a transfer and returns as
* soon as possible.
*
* The transfer callbacks will be called by a different thread to that used to call the transferAsync method so transaction
* context will be different to the calling context. The asychronous transfer does not have access to uncommitted
* data in the calling transaction.
*
* @param targetName the name of the target to transfer to
* @param definition - the definition of the transfer. Specifies which nodes to transfer.
* The following properties must be set, nodes
* @param callbacks - a collection of callback handlers that will be called as transfer proceeds. May be null.
*
* @throws TransferException
*/
public void transferAsync(String targetName, TransferDefinition definition, TransferCallback... callbacks) throws TransferException;
/**
* Verify a target is available and that the configured credentials correctly identify an admin user.
@@ -119,6 +151,13 @@ public interface TransferService
*/
public TransferTarget getTransferTarget(String name) throws TransferException;
/**
* Test to see if the target with the specified name exists
* @param name
* @return true if the specified target exists, and false otherwise
*/
public boolean targetExists(String name);
/**
* Delete a transfer target. After calling this method the transfer target will no longer exist.
* @throws TransferException - target does not exist
@@ -153,4 +192,23 @@ public interface TransferService
*/
public void enableTransferTarget(String name, boolean enable) throws TransferException;
/**
* Asynchronously cancel an in-progress transfer
*
* This method tells an in-process transfer to give up, rollback and stop as soon as possible.
*
* Depending upon the state of the in-progress transfer, the transfer may still complete,
* despite calling this method, however in most cases the transfer will not complete.
*
* Calling this method for a transfer that does not exist, possibly because it has already finished, has no
* effect and will not throw an exception.
*
* The transfer handle is returned by a TransferEventBegin event callback.
*
* @param transferId the unique identifier for the instance of the transfer to cancel.
*
* @see TransferEventBegin;
*/
public void cancelAsync(String transferId);
}

View File

@@ -63,6 +63,8 @@ public abstract class BaseAlfrescoSpringTest extends BaseSpringTest
protected ActionService actionService;
protected TransactionService transactionService;
protected AuthenticationComponent authenticationComponent;
/**
* On setup in transaction override
*/
@@ -79,7 +81,7 @@ public abstract class BaseAlfrescoSpringTest extends BaseSpringTest
this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent");
// Authenticate as the system user
AuthenticationComponent authenticationComponent = (AuthenticationComponent) this.applicationContext
authenticationComponent = (AuthenticationComponent) this.applicationContext
.getBean("authenticationComponent");
authenticationComponent.setSystemUserAsCurrentUser();