Transfer service : more work on just sending content that is required.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21160 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Mark Rogers
2010-07-14 13:10:05 +00:00
parent 240e0d9f05
commit 9dde9b2ab5
9 changed files with 136 additions and 36 deletions

View File

@@ -31,18 +31,18 @@ import java.util.TreeSet;
public class DeltaList
{
/**
* The set of requiredURLs
* The set of requiredParts
*/
private TreeSet<String> requiredURLs = new TreeSet<String>();
private TreeSet<String> requiredParts = new TreeSet<String>();
/**
* get the list of URLs reqired by the manifest.
* @return the list of required URLs
*/
public Set<String> getRequiredURLs()
public Set<String> getRequiredParts()
{
return requiredURLs;
return requiredParts;
}
}

View File

@@ -290,7 +290,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
Map<QName, Serializable> props = new HashMap<QName, Serializable>(node.getProperties());
// Split out the content properties and sanitise the others
Map<QName, Serializable> contentProps = processProperties(null, props, true);
Map<QName, Serializable> contentProps = processProperties(null, props, null);
// inject transferred property here
if(!contentProps.containsKey(TransferModel.PROP_REPOSITORY_ID))
@@ -390,6 +390,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// We need to process content properties separately.
// First, create a shallow copy of the supplied property map...
Map<QName, Serializable> props = new HashMap<QName, Serializable>(node.getProperties());
Map<QName, Serializable> existingProps = nodeService.getProperties(nodeToUpdate);
// inject transferred property here
if(!props.containsKey(TransferModel.PROP_REPOSITORY_ID))
@@ -399,14 +400,14 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
// Split out the content properties and sanitise the others
Map<QName, Serializable> contentProps = processProperties(nodeToUpdate, props, false);
Map<QName, Serializable> contentProps = processProperties(nodeToUpdate, props, existingProps);
// Update the non-content properties
nodeService.setProperties(nodeToUpdate, props);
// Deal with the content properties
writeContent(nodeToUpdate, contentProps);
// Blend the aspects together
Set<QName> suppliedAspects = new HashSet<QName>(node.getAspects());
Set<QName> existingAspects = nodeService.getAspects(nodeToUpdate);
@@ -448,17 +449,19 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
* @param nodeToUpdate
* The noderef of the existing node in the local repo that is to be updated with these properties. May be
* null, indicating that these properties are destined for a brand new local node.
* @param props
* @return A map containing the content properties from the supplied "props" map
* @param props the new properties
* @param the existing properties, null if this is a create
* @return A map containing the content properties which are going to be replaced from the supplied "props" map
*/
private Map<QName, Serializable> processProperties(NodeRef nodeToUpdate, Map<QName, Serializable> props,
boolean isNew)
Map<QName, Serializable> existingProps)
{
Map<QName, Serializable> contentProps = new HashMap<QName, Serializable>();
// ...and copy any supplied content properties into this new map...
for (Map.Entry<QName, Serializable> propEntry : props.entrySet())
{
Serializable value = propEntry.getValue();
QName key = propEntry.getKey();
if (log.isDebugEnabled())
{
if (value == null)
@@ -468,7 +471,42 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
if ((value != null) && ContentData.class.isAssignableFrom(value.getClass()))
{
contentProps.put(propEntry.getKey(), propEntry.getValue());
if(existingProps != null)
{
// This is an update and we have content data
File stagingDir = getStagingFolder();
ContentData contentData = (ContentData) propEntry.getValue();
String contentUrl = contentData.getContentUrl();
String fileName = TransferCommons.URLToPartName(contentUrl);
File stagedFile = new File(stagingDir, fileName);
if (stagedFile.exists())
{
if(log.isDebugEnabled())
{
log.debug("replace content for node:" + nodeToUpdate + ", " + key);
}
// Yes we are going to replace the content item
contentProps.put(propEntry.getKey(), propEntry.getValue());
}
else
{
// Staging file does not exist
if(props.containsKey(key))
{
if(log.isDebugEnabled())
{
log.debug("keep existing content for node:" + nodeToUpdate + ", " + key);
}
// keep the existing content value
props.put(propEntry.getKey(), existingProps.get(key));
}
}
}
else
{
// This is a create so all content items are new
contentProps.put(propEntry.getKey(), propEntry.getValue());
}
}
}
@@ -480,13 +518,10 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
props.remove(contentPropertyName);
}
if (!isNew)
if (existingProps != null)
{
// 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);
for (QName localProperty : getLocalProperties())
{
Serializable existingValue = existingProps.get(localProperty);
@@ -515,7 +550,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
{
ContentData contentData = (ContentData) contentEntry.getValue();
String contentUrl = contentData.getContentUrl();
String fileName = contentUrl.substring(contentUrl.lastIndexOf('/') + 1);
String fileName = TransferCommons.URLToPartName(contentUrl);
File stagedFile = new File(stagingDir, fileName);
if (!stagedFile.exists())
{

View File

@@ -22,6 +22,7 @@ package org.alfresco.repo.transfer;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -105,9 +106,9 @@ public class RepoRequsiteManifestProcessorImpl extends AbstractManifestProcessor
*/
NodeRef destinationNode = resolvedNodes.resolvedChild;
// Serializable yy = node.getProperties().get(ContentModel.PROP_MODIFIED);
Map<QName, Serializable> destProps = nodeService.getProperties(destinationNode);
// Serializable xx = destProps.get(ContentModel.PROP_MODIFIED);
for (Map.Entry<QName, Serializable> propEntry : node.getProperties().entrySet())
{
@@ -128,26 +129,33 @@ public class RepoRequsiteManifestProcessorImpl extends AbstractManifestProcessor
ContentData destContent = (ContentData)destProps.get(propEntry.getKey());
/**
* If the URLs are the same then the content is already on the server
* If the modification dates for the node are different
*/
if(TransferCommons.URLToPartName(destContent.getContentUrl()).equalsIgnoreCase(
TransferCommons.URLToPartName(srcContent.getContentUrl())))
Serializable srcModified = node.getProperties().get(ContentModel.PROP_MODIFIED);
Serializable destModified = destProps.get(ContentModel.PROP_MODIFIED);
log.debug ("srcModified :" + srcModified + "destModified :" + destModified);
if(srcModified != null &&
destModified != null &&
srcModified instanceof Date &&
destModified instanceof Date &&
((Date)srcModified).getTime() >= ((Date)destModified).getTime())
{
if(log.isDebugEnabled())
{
log.debug("the url is the same - no need to send it:" + destContent.getContentUrl());
log.debug("the modified date is the same - no need to send it:" + destContent.getContentUrl());
}
}
else
{
// We need to diff the property
out.missingContent(node.getNodeRef(), propEntry.getKey(), srcContent.getContentUrl());
out.missingContent(node.getNodeRef(), propEntry.getKey(), TransferCommons.URLToPartName(srcContent.getContentUrl()));
}
}
else
{
// We don't have the property on the destination node
out.missingContent(node.getNodeRef(), propEntry.getKey(), srcContent.getContentUrl());
out.missingContent(node.getNodeRef(), propEntry.getKey(), TransferCommons.URLToPartName(srcContent.getContentUrl()));
}
}
}
@@ -171,7 +179,7 @@ public class RepoRequsiteManifestProcessorImpl extends AbstractManifestProcessor
{
ContentData content = (ContentData)value;
//
out.missingContent(node.getNodeRef(), propEntry.getKey(), content.getContentUrl());
out.missingContent(node.getNodeRef(), propEntry.getKey(), TransferCommons.URLToPartName(content.getContentUrl()));
}
}
}

View File

@@ -699,7 +699,8 @@ public class TransferServiceImpl implements TransferService
*/
if(deltaList != null)
{
if(deltaList.getRequiredURLs().contains(d.getContentUrl()))
String partName = TransferCommons.URLToPartName(d.getContentUrl());
if(deltaList.getRequiredParts().contains(partName))
{
logger.debug("content is required :" + d.getContentUrl());
chunker.addContent(d);

View File

@@ -19,6 +19,7 @@
package org.alfresco.repo.transfer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -62,6 +63,8 @@ import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.BaseAlfrescoSpringTest;
import org.alfresco.util.GUID;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.ResourceUtils;
@@ -647,6 +650,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
endTransaction();
}
logger.debug("First transfer - create new node (no content yet)");
startNewTransaction();
try
{
@@ -676,10 +680,25 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
assertEquals("title is wrong", (String)nodeService.getProperty(destNodeRef, ContentModel.PROP_TITLE), CONTENT_TITLE);
assertEquals("type is wrong", nodeService.getType(contentNodeRef), nodeService.getType(destNodeRef));
// Check the modified time of the destination node is the same as the source node.
Date destModifiedDate = (Date)nodeService.getProperty(destNodeRef, ContentModel.PROP_MODIFIED);
Date srcModifiedDate = (Date)nodeService.getProperty(contentNodeRef, ContentModel.PROP_MODIFIED);
logger.debug("srcModifiedDate : " + srcModifiedDate + " destModifiedDate : " + destModifiedDate);
assertTrue("dest modified date is not correct", destModifiedDate.compareTo(srcModifiedDate)== 0);
Date destCreatedDate = (Date)nodeService.getProperty(destNodeRef, ContentModel.PROP_CREATED);
Date srcCreatedDate = (Date)nodeService.getProperty(contentNodeRef, ContentModel.PROP_CREATED);
logger.debug("srcCreatedDate : " + srcCreatedDate + " destCreatedDate : " + destCreatedDate);
assertTrue("dest created date is not correct", destCreatedDate.compareTo(srcCreatedDate)== 0);
// Check injected transferred aspect.
assertNotNull("transferredAspect", (String)nodeService.getProperty(destNodeRef, TransferModel.PROP_REPOSITORY_ID));
// Now set up the next test which is to
// Now set up the next test which is to change the title
nodeService.setProperty(contentNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE_UPDATED);
}
finally
@@ -687,11 +706,12 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
endTransaction();
}
logger.debug("Second transfer - update title property (no content yet)");
startNewTransaction();
try
{
/**
* Transfer our node again - so this is an update
* Transfer our node again - so this is an update of the title property
*/
{
TransferDefinition definition = new TransferDefinition();
@@ -715,6 +735,21 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
assertEquals("title is wrong", (String)nodeService.getProperty(destNodeRef, ContentModel.PROP_TITLE), CONTENT_TITLE_UPDATED);
assertEquals("type is wrong", nodeService.getType(contentNodeRef), nodeService.getType(destNodeRef));
// Check the modified time of the destination node is the same as the source node.
Date destModifiedDate = (Date)nodeService.getProperty(destNodeRef, ContentModel.PROP_MODIFIED);
Date srcModifiedDate = (Date)nodeService.getProperty(contentNodeRef, ContentModel.PROP_MODIFIED);
logger.debug("srcModifiedDate : " + srcModifiedDate + " destModifiedDate : " + destModifiedDate);
// BUGBUG - MER 14/07/2010 - can't set modified date
// assertTrue("after update, modified date is not correct", destModifiedDate.compareTo(srcModifiedDate) == 0);
Date destCreatedDate = (Date)nodeService.getProperty(destNodeRef, ContentModel.PROP_CREATED);
Date srcCreatedDate = (Date)nodeService.getProperty(contentNodeRef, ContentModel.PROP_CREATED);
logger.debug("srcCreatedDate : " + srcCreatedDate + " destCreatedDate : " + destCreatedDate);
assertTrue("after update, created date is not correct", destCreatedDate.compareTo(srcCreatedDate)== 0);
// Check injected transferred aspect.
assertNotNull("transferredAspect", (String)nodeService.getProperty(destNodeRef, TransferModel.PROP_REPOSITORY_ID));
@@ -724,6 +759,7 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
endTransaction();
}
logger.debug("Transfer again - this is an update");
startNewTransaction();
try
{
@@ -744,9 +780,10 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
}
/**
* Now transfer nothing - content items do not need to be transferred since its alrady on
* Now transfer nothing - content items do not need to be transferred since its already on
* the destination.
*/
logger.debug("Transfer again - with no new content");
startNewTransaction();
try
{
@@ -760,12 +797,29 @@ public class TransferServiceImplTest extends BaseAlfrescoSpringTest
{
endTransaction();
}
startNewTransaction();
try
{
// Now validate that the target node still exists and in particular that the old content is still there
assertFalse("unit test stuffed up - comparing with self", destNodeRef.equals(transferMe.getNodeRef()));
assertTrue("dest node ref does not exist", nodeService.exists(destNodeRef));
assertEquals("title is wrong", (String)nodeService.getProperty(destNodeRef, ContentModel.PROP_TITLE), CONTENT_TITLE_UPDATED);
assertEquals("type is wrong", nodeService.getType(contentNodeRef), nodeService.getType(destNodeRef));
// Check injected transferred aspect.
assertNotNull("transferredAspect", (String)nodeService.getProperty(destNodeRef, TransferModel.PROP_REPOSITORY_ID));
}
finally
{
endTransaction();
}
/**
* Negative test transfer nothing
*/
logger.debug("Transfer again - with no content - should throw exception");
try
{
TransferDefinition definition = new TransferDefinition();

View File

@@ -38,7 +38,7 @@ public class DeltaListRequsiteProcessor implements TransferRequsiteProcessor
public void missingContent(NodeRef node, QName qname, String name)
{
deltaList.getRequiredURLs().add(name);
deltaList.getRequiredParts().add(name);
}
public void startTransferRequsite()

View File

@@ -25,6 +25,8 @@ import org.alfresco.repo.transfer.TransferModel;
*/
public interface RequsiteModel extends TransferModel
{
static final String REQUSITE_MODEL_1_0_URI = "http://www.alfresco.org/model/requsite/1.0";
static final String LOCALNAME_TRANSFER_REQUSITE = "transferRequsite";
static final String LOCALNAME_ELEMENT_NODES = "nodes";
@@ -37,5 +39,5 @@ public interface RequsiteModel extends TransferModel
// Manifest file prefix
static final String REQUSITE_PREFIX = "xferreq";
static final String REQUSITE_PREFIX = "xferr";
}

View File

@@ -51,7 +51,7 @@ public class XMLTransferRequsiteReader extends DefaultHandler implements Content
*/
LinkedList<HashMap<String, String>> namespaces = new LinkedList<HashMap<String, String>>();
final String TRANSFER_URI = RequsiteModel.TRANSFER_MODEL_1_0_URI;
final String REQUSITE_URI = RequsiteModel.REQUSITE_MODEL_1_0_URI;
final String XMLNS_URI = "http://www.w3.org/XML/1998/namespace";
/*
@@ -191,7 +191,7 @@ public class XMLTransferRequsiteReader extends DefaultHandler implements Content
return;
}
if(elementQName.getNamespaceURI().equals(TRANSFER_URI));
if(elementQName.getNamespaceURI().equals(REQUSITE_URI));
{
// This is one of the transfer manifest elements
String elementName = elementQName.getLocalName();

View File

@@ -90,7 +90,7 @@ public class XMLTransferRequsiteWriter implements TransferRequsiteWriter
{
this.writer.startDocument();
this.writer.startPrefixMapping(PREFIX, TransferModel.TRANSFER_MODEL_1_0_URI);
this.writer.startPrefixMapping(PREFIX, RequsiteModel.TRANSFER_MODEL_1_0_URI);
this.writer.startPrefixMapping("cm", NamespaceService.CONTENT_MODEL_1_0_URI);
// Start Transfer Manifest // uri, name, prefix