Merged DEV to HEAD

- ALF-8806 RINF 41: Lucene Removal: Fix CopyService
     - ALF-9028: RINF 41: Fix Aspect cm:copiedFrom
   - ALF-9029 RINF 49: Lucene Removal: CheckOutCheckInService API
     - ALF-9032: RINF 49: fixes to cm:workingcopy aspect

   28996: Dev branch for De-Lucene work pending patches
   29004: Evaluator runs in read-only txn
   29006: Additional PermissionCheckedCollection.create method
          - Use an existing collection's permission check data (cut-off, etc) to wrap a new collection
   29007:
          CopyService and CheckOutCheckInService refactors to remove Lucene
          
          CopyService:
          
          Removed cm:source property from cm:copiedfrom aspect and replaced with a cm:original association.
          Added CQ-based APIs to query for copies
          Added APIs to support bi-directional walking of copy association
          Fixed sundry uses of cm:copiedfrom esp. all uses related to cm:workingcopy
          
          CheckOutCheckInService:
          
          Check-out now creates a source aspect cm:checkedOut with 1:1 relationship to cm:workingcopy via cm:workingcopylink
          Removed explicit use of cm:workingcopy aspect and replaced it with calls to COCI API
          
   29083: Audit tests fail when indexing is turned off.
          Also removed a getReader() call during rule evaluation, leading to a 'sub-action' read being recorded.
   29113: NodeDAO.getNodesWithAspects supports paging
   29135: Removed unused patch queries
   29139: Basic patch (still terminates with error) to upgrade cm:copiedfrom and cm:workingcopy
   29157: Tested patch for cm:copiedfrom and cm:workingcopy aspects


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@29159 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2011-07-19 03:22:11 +00:00
parent 8a561b38ca
commit 6ec3f44c29
58 changed files with 2277 additions and 1845 deletions

View File

@@ -32,7 +32,6 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQuery;
import org.alfresco.query.CannedQueryFactory;
import org.alfresco.query.CannedQueryPageDetails;
import org.alfresco.query.CannedQueryParameters;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
@@ -43,6 +42,7 @@ import org.alfresco.repo.copy.CopyBehaviourCallback.ChildAssocCopyAction;
import org.alfresco.repo.copy.CopyBehaviourCallback.ChildAssocRecurseAction;
import org.alfresco.repo.copy.CopyBehaviourCallback.CopyAssociationDetails;
import org.alfresco.repo.copy.CopyBehaviourCallback.CopyChildAssociationDetails;
import org.alfresco.repo.copy.query.AbstractCopyCannedQueryFactory;
import org.alfresco.repo.policy.ClassPolicyDelegate;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
@@ -61,8 +61,6 @@ import org.alfresco.service.cmr.repository.CopyServiceException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
@@ -90,7 +88,6 @@ public class CopyServiceImpl implements CopyService
/* Query names */
private static final String QUERY_FACTORY_GET_COPIES = "getCopiesCannedQueryFactory";
private static final String QUERY_FACTORY_GET_COPIED = "getCopiesCannedQueryFactory";
/* I18N labels */
private static final String COPY_OF_LABEL = "copy_service.copy_of_label";
@@ -100,7 +97,6 @@ public class CopyServiceImpl implements CopyService
private NodeService internalNodeService;
private NamedObjectRegistry<CannedQueryFactory<CopyInfo>> cannedQueryRegistry;
private DictionaryService dictionaryService;
private SearchService searchService;
private PolicyComponent policyComponent;
private RuleService ruleService;
private PermissionService permissionService;
@@ -148,14 +144,6 @@ public class CopyServiceImpl implements CopyService
this.policyComponent = policyComponent;
}
/**
* @param searchService the search service
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @param ruleService the rule service
*/
@@ -192,15 +180,15 @@ public class CopyServiceImpl implements CopyService
// Register policy behaviours
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "getCopyCallback"),
CopyServicePolicies.OnCopyNodePolicy.QNAME,
ContentModel.ASPECT_COPIEDFROM,
new JavaBehaviour(this, "getCallbackForCopiedFromAspect"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "getCopyCallback"),
CopyServicePolicies.OnCopyNodePolicy.QNAME,
ContentModel.TYPE_FOLDER,
new JavaBehaviour(this, "getCallbackForFolderType"));
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "getCopyCallback"),
CopyServicePolicies.OnCopyNodePolicy.QNAME,
ContentModel.ASPECT_OWNABLE,
new JavaBehaviour(this, "getCallbackForOwnableAspect"));
}
@@ -376,34 +364,40 @@ public class CopyServiceImpl implements CopyService
invokeCopyComplete(sourceNodeRef, targetNodeRef, false, copiedNodeRefs);
}
@Override
public NodeRef getOriginal(NodeRef nodeRef)
{
List<AssociationRef> assocs = internalNodeService.getTargetAssocs(nodeRef, ContentModel.ASSOC_ORIGINAL);
if (assocs.size() > 1)
{
logger.warn("Multiple cm:orignal associations from node: " + nodeRef);
}
if (assocs.size() == 0)
{
return null;
}
else
{
return assocs.get(0).getTargetRef();
}
}
@Override
public List<NodeRef> getCopies(NodeRef nodeRef)
{
List<NodeRef> copies = new ArrayList<NodeRef>();
// Do a search to find the origional document
ResultSet resultSet = null;
try
PagingRequest pagingRequest = new PagingRequest(1000);
PagingResults<CopyInfo> page = getCopies(nodeRef, pagingRequest);
if (page.hasMoreItems())
{
resultSet = this.searchService.query(
nodeRef.getStoreRef(),
SearchService.LANGUAGE_LUCENE,
"+@\\{http\\://www.alfresco.org/model/content/1.0\\}" + ContentModel.PROP_COPY_REFERENCE.getLocalName() + ":\"" + nodeRef.toString() + "\"");
for (NodeRef copy : resultSet.getNodeRefs())
{
copies.add(copy);
}
logger.warn("Trimmed page size for deprecated getCopies() call.");
}
finally
List<CopyInfo> pageResults = page.getPage();
List<NodeRef> results = new ArrayList<NodeRef>(pageResults.size());
for (CopyInfo copyInfo : pageResults)
{
if (resultSet != null)
{
resultSet.close();
}
results.add(copyInfo.getNodeRef());
}
return copies;
return results;
}
@Override
@@ -411,9 +405,9 @@ public class CopyServiceImpl implements CopyService
{
CannedQueryFactory<CopyInfo> queryFactory = cannedQueryRegistry.getNamedObject(QUERY_FACTORY_GET_COPIES);
CannedQueryParameters params = new CannedQueryParameters(
originalNodeRef,
new CannedQueryPageDetails(pagingRequest),
null);
new AbstractCopyCannedQueryFactory.CopyCannedQueryDetail(originalNodeRef),
null,
pagingRequest);
CannedQuery<CopyInfo> query = queryFactory.getCannedQuery(params);
return query.execute();
}
@@ -421,14 +415,14 @@ public class CopyServiceImpl implements CopyService
@Override
public PagingResults<CopyInfo> getCopies(
NodeRef originalNodeRef,
NodeRef copyParentNodeRef, Set<QName> copyNodeAspectsToIgnore,
NodeRef copyParentNodeRef,
PagingRequest pagingRequest)
{
CannedQueryFactory<CopyInfo> queryFactory = cannedQueryRegistry.getNamedObject(QUERY_FACTORY_GET_COPIES);
CannedQueryParameters params = new CannedQueryParameters(
originalNodeRef,
new CannedQueryPageDetails(pagingRequest),
null);
new AbstractCopyCannedQueryFactory.CopyCannedQueryDetail(originalNodeRef, copyParentNodeRef),
null,
pagingRequest);
CannedQuery<CopyInfo> query = queryFactory.getCannedQuery(params);
return query.execute();
}
@@ -593,10 +587,16 @@ public class CopyServiceImpl implements CopyService
// Copy residual properties
copyResidualProperties(copyDetails, copyTarget);
// Apply the copy aspect to the new node
Map<QName, Serializable> copyProperties = new HashMap<QName, Serializable>();
copyProperties.put(ContentModel.PROP_COPY_REFERENCE, sourceNodeRef);
internalNodeService.addAspect(copyTarget, ContentModel.ASPECT_COPIEDFROM, copyProperties);
// Link the new node to the original, but ensure that we only keep track of the last copy
List<AssociationRef> originalAssocs = internalNodeService.getTargetAssocs(copyTarget, ContentModel.ASSOC_ORIGINAL);
for (AssociationRef originalAssoc : originalAssocs)
{
internalNodeService.removeAssociation(
originalAssoc.getSourceRef(),
originalAssoc.getTargetRef(),
ContentModel.ASSOC_ORIGINAL);
}
internalNodeService.createAssociation(copyTarget, sourceNodeRef, ContentModel.ASSOC_ORIGINAL);
// Copy permissions
copyPermissions(sourceNodeRef, copyTarget);
@@ -1389,5 +1389,5 @@ public class CopyServiceImpl implements CopyService
public CopyBehaviourCallback getCallbackForOwnableAspect(QName classRef, CopyDetails copyDetails)
{
return DoNothingCopyBehaviourCallback.getInstance();
}
}
}

View File

@@ -43,6 +43,7 @@ import org.alfresco.repo.dictionary.M2ChildAssociation;
import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.dictionary.M2Property;
import org.alfresco.repo.dictionary.M2Type;
import org.alfresco.repo.node.integrity.IntegrityChecker;
import org.alfresco.repo.rule.RuleModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -77,6 +78,7 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyMap;
import org.springframework.context.ApplicationContext;
import org.springframework.extensions.surf.util.I18NUtil;
@@ -477,14 +479,14 @@ public class CopyServiceImplTest extends TestCase
/**
* Test copy new node within store
*/
public void DISABLED_testCopyToNewNode()
public void testCopyToNewNode()
{
PagingRequest pageRequest = new PagingRequest(10);
PagingResults<CopyInfo> copies = null;
// Check that the node has no copies
copies = copyService.getCopies(sourceNodeRef, pageRequest);
assertEquals("Incorrect number of copies", 1, copies.getPage().size());
assertEquals("Incorrect number of copies", 0, copies.getPage().size());
// Copy to new node without copying children
NodeRef copy = copyService.copy(
@@ -535,7 +537,87 @@ public class CopyServiceImplTest extends TestCase
//System.out.println(
// NodeStoreInspector.dumpNodeStore(nodeService, storeRef));
}
}
public void testCopiedFromAspect()
{
IntegrityChecker integrityChecker = (IntegrityChecker) ctx.getBean("integrityChecker");
// Create the node used for copying
ChildAssociationRef childAssocRef = nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{test}test"),
TEST_TYPE_QNAME,
createTypePropertyBag());
NodeRef nodeRef = childAssocRef.getChildRef();
PagingRequest pageRequest = new PagingRequest(10);
pageRequest.setRequestTotalCountMax(200);
PagingResults<CopyInfo> copies = null;
NodeRef firstCopy = null;
for (int i = 1; i <= 100; i++)
{
NodeRef copyNodeRef = copyService.copy(
nodeRef,
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{test}copyAssoc"));
if (firstCopy == null)
{
firstCopy = copyNodeRef;
}
copies = copyService.getCopies(nodeRef, pageRequest);
assertEquals("Total count not correct", new Pair<Integer, Integer>(i, i), copies.getTotalResultCount());
assertEquals("Incorrect number of copies", (i > 10 ? 10 : i), copies.getPage().size());
// Since the results are paged, make sure that we have the correct results while we only have a page
boolean found = (i > 10) ? true : false;
for (CopyInfo copy : copies.getPage())
{
if (found) // Might not be checking if we are over a page
{
break;
}
if (copy.getNodeRef().equals(copyNodeRef))
{
found = true;
}
}
assertTrue("Did not find the copy in the list of copies.", found);
// Run integrity checks to ensure that commit has a chance
integrityChecker.checkIntegrity();
// Now query for copies in current parent location
copies = copyService.getCopies(nodeRef, rootNodeRef, pageRequest);
assertEquals("Total count not correct", new Pair<Integer, Integer>(i, i), copies.getTotalResultCount());
assertEquals("Incorrect number of copies", (i > 10 ? 10 : i), copies.getPage().size());
// Check that the original node can be retrieved
NodeRef originalCheck = copyService.getOriginal(copyNodeRef);
assertEquals("Original is not as expected. ", nodeRef, originalCheck);
// Check that the parent node can be included
copies = copyService.getCopies(nodeRef, rootNodeRef, pageRequest);
assertEquals("Total count not correct", new Pair<Integer, Integer>(i, i), copies.getTotalResultCount());
assertEquals("Incorrect number of copies", (i > 10 ? 10 : i), copies.getPage().size());
// And query against some other parent node
copies = copyService.getCopies(nodeRef, sourceNodeRef, pageRequest); // Some arbitrary parent
assertEquals("Expected to find no copies", 0, copies.getPage().size());
}
// Should be able to delete the original
nodeService.deleteNode(nodeRef);
// Run integrity checks to ensure that commit has a chance
integrityChecker.checkIntegrity();
// Should be no original
NodeRef originalCheck = copyService.getOriginal(firstCopy);
assertNull("Original should not be present. ", originalCheck);
}
public void testCopyNodeWithRules()
{
@@ -1069,9 +1151,10 @@ public class CopyServiceImplTest extends TestCase
// Check that the copy aspect has been applied to the copy
boolean hasCopyAspect = nodeService.hasAspect(destinationNodeRef, ContentModel.ASPECT_COPIEDFROM);
assertTrue("Missing aspect: " + ContentModel.ASPECT_COPIEDFROM, hasCopyAspect);
NodeRef copyNodeRef = (NodeRef)nodeService.getProperty(destinationNodeRef, ContentModel.PROP_COPY_REFERENCE);
assertNotNull(copyNodeRef);
assertEquals(sourceNodeRef, copyNodeRef);
List<AssociationRef> assocs = nodeService.getTargetAssocs(destinationNodeRef, ContentModel.ASSOC_ORIGINAL);
assertEquals("Expectd exactly one reference back to original", 1, assocs.size());
NodeRef checkSourceNodeRef = assocs.get(0).getTargetRef();
assertEquals("Copy refers to incorrect original source", sourceNodeRef, checkSourceNodeRef);
}
else
{

View File

@@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
@@ -14,392 +14,396 @@
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.copy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.CrossRepositoryCopyService;
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.namespace.QName;
import org.alfresco.util.Pair;
/**
* Cross Repository Copying.
*
* @author britt
*/
public class CrossRepositoryCopyServiceImpl implements CrossRepositoryCopyService
{
/**
* The NodeService reference.
*/
private NodeService fNodeService;
/**
* The FileFolderService reference.
*/
private FileFolderService fFileFolderService;
/**
* The regular CopyService reference.
*/
private CopyService fCopyService;
/**
* The AVMService.
*/
private AVMService fAVMService;
/**
* The ContentService.
*/
private ContentService fContentService;
/**
* The DictionaryService.
*/
private DictionaryService fDictionaryService;
/**
* A default constructor.
*/
public CrossRepositoryCopyServiceImpl()
{
}
// Setters for Spring.
public void setAvmService(AVMService service)
{
fAVMService = service;
}
public void setContentService(ContentService service)
{
fContentService = service;
}
public void setCopyService(CopyService service)
{
fCopyService = service;
}
public void setDictionaryService(DictionaryService service)
{
fDictionaryService = service;
}
public void setFileFolderService(FileFolderService service)
{
fFileFolderService = service;
}
public void setNodeService(NodeService service)
{
fNodeService = service;
}
/**
* This copies recursively src, which may be a container or a content type to dst, which must be a container. Copied
* nodes will have the copied from aspect applied to them.
*
* @param src
* The node to copy.
* @param dst
* The container to copy it into.
* @param name
* The name to give the copy.
*/
public void copy(NodeRef src, NodeRef dst, String name)
{
StoreRef srcStoreRef = src.getStoreRef();
StoreRef dstStoreRef = dst.getStoreRef();
if (srcStoreRef.getProtocol().equals(StoreRef.PROTOCOL_AVM))
{
if (dstStoreRef.getProtocol().equals(StoreRef.PROTOCOL_AVM))
{
copyAVMToAVM(src, dst, name);
}
else if (dstStoreRef.getProtocol().equals(StoreRef.PROTOCOL_WORKSPACE))
{
copyAVMToRepo(src, dst, name);
}
}
else if (srcStoreRef.getProtocol().equals(StoreRef.PROTOCOL_WORKSPACE))
{
if (dstStoreRef.getProtocol().equals(StoreRef.PROTOCOL_AVM))
{
copyRepoToAVM(src, dst, name);
}
else if (dstStoreRef.getProtocol().equals(StoreRef.PROTOCOL_WORKSPACE))
{
copyRepoToRepo(src, dst, name);
}
}
}
/**
* Handle copying from AVM to AVM
*
* @param src
* Source node.
* @param dst
* Destination directory node.
* @param name
* Name to give copy.
*/
private void copyAVMToAVM(NodeRef src, NodeRef dst, String name)
{
Pair<Integer, String> srcStorePath = AVMNodeConverter.ToAVMVersionPath(src);
Pair<Integer, String> dstStorePath = AVMNodeConverter.ToAVMVersionPath(dst);
fAVMService.copy(srcStorePath.getFirst(), srcStorePath.getSecond(), dstStorePath.getSecond(), name);
}
/**
* Handle copying from AVM to Repo.
*
* @param src
* Source node.
* @param dst
* Destination Container.
* @param name
* The name to give the copy.
*/
private void copyAVMToRepo(NodeRef src, NodeRef dst, String name)
{
Pair<Integer, String> versionPath = AVMNodeConverter.ToAVMVersionPath(src);
AVMNodeDescriptor desc = fAVMService.lookup(versionPath.getFirst(), versionPath.getSecond());
NodeRef existing = fFileFolderService.searchSimple(dst, name);
if (desc.isFile())
{
if (existing != null && !fNodeService.getType(existing).equals(ContentModel.TYPE_CONTENT))
{
fFileFolderService.delete(existing);
existing = null;
}
NodeRef childRef = null;
if (existing == null)
{
childRef = fFileFolderService.create(dst, name, ContentModel.TYPE_CONTENT).getNodeRef();
}
else
{
childRef = existing;
}
InputStream in = fAVMService.getFileInputStream(desc);
ContentData cd = fAVMService.getContentDataForRead(versionPath.getFirst(), desc.getPath());
ContentWriter writer = fContentService.getWriter(childRef, ContentModel.PROP_CONTENT, true);
writer.setEncoding(cd.getEncoding());
writer.setMimetype(cd.getMimetype());
OutputStream out = writer.getContentOutputStream();
copyData(in, out);
copyPropsAndAspectsAVMToRepo(src, childRef);
}
else
{
if (existing != null && !fNodeService.getType(existing).equals(ContentModel.TYPE_FOLDER))
{
fFileFolderService.delete(existing);
existing = null;
}
NodeRef childRef = null;
if (existing == null)
{
childRef = fFileFolderService.create(dst, name, ContentModel.TYPE_FOLDER).getNodeRef();
}
else
{
childRef = existing;
}
copyPropsAndAspectsAVMToRepo(src, childRef);
Map<String, AVMNodeDescriptor> listing = fAVMService.getDirectoryListing(desc);
for (Map.Entry<String, AVMNodeDescriptor> entry : listing.entrySet())
{
NodeRef srcChild = AVMNodeConverter.ToNodeRef(versionPath.getFirst(), entry.getValue().getPath());
copyAVMToRepo(srcChild, childRef, entry.getKey());
}
}
}
/**
* Helper that copies aspects and properties.
*
* @param src
* The source AVM node.
* @param dst
* The destination Repo node.
*/
private void copyPropsAndAspectsAVMToRepo(NodeRef src, NodeRef dst)
{
Map<QName, Serializable> props = fNodeService.getProperties(src);
fNodeService.setProperties(dst, props);
Set<QName> aspects = fNodeService.getAspects(src);
Map<QName, Serializable> empty = new HashMap<QName, Serializable>();
for (QName aspect : aspects)
{
fNodeService.addAspect(dst, aspect, empty);
}
if (!fNodeService.hasAspect(dst, ContentModel.ASPECT_COPIEDFROM))
{
empty.put(ContentModel.PROP_COPY_REFERENCE, src);
fNodeService.addAspect(dst, ContentModel.ASPECT_COPIEDFROM, empty);
}
else
{
fNodeService.setProperty(dst, ContentModel.PROP_COPY_REFERENCE, src);
}
}
/**
* Handle copying from Repo to AVM.
*
* @param src
* The source node.
* @param dst
* The destingation directory.
* @param name
* The name to give the copy.
*/
private void copyRepoToAVM(NodeRef src, NodeRef dst, String name)
{
QName srcType = fNodeService.getType(src);
Pair<Integer, String> versionPath = AVMNodeConverter.ToAVMVersionPath(dst);
String childPath = AVMNodeConverter.ExtendAVMPath(versionPath.getSecond(), name);
NodeRef childNodeRef = AVMNodeConverter.ToNodeRef(-1, childPath);
if (fDictionaryService.isSubClass(srcType, ContentModel.TYPE_CONTENT))
{
ContentReader reader = fContentService.getReader(src, ContentModel.PROP_CONTENT);
InputStream in = reader.getContentInputStream();
AVMNodeDescriptor desc = fAVMService.lookup(-1, childPath);
if (desc != null && !desc.isFile())
{
fAVMService.removeNode(childPath);
desc = null;
}
if (desc == null)
{
try
{
fAVMService.createFile(versionPath.getSecond(), name).close();
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("I/O Error.", e);
}
}
ContentWriter writer = fAVMService.getContentWriter(childPath, true);
writer.setEncoding(reader.getEncoding());
writer.setMimetype(reader.getMimetype());
OutputStream out = writer.getContentOutputStream();
copyData(in, out);
copyPropsAndAspectsRepoToAVM(src, childNodeRef, childPath);
return;
}
if (fDictionaryService.isSubClass(srcType, ContentModel.TYPE_FOLDER))
{
AVMNodeDescriptor desc = fAVMService.lookup(-1, childPath);
if (desc != null && !desc.isDirectory())
{
fAVMService.removeNode(childPath);
desc = null;
}
if (desc == null)
{
fAVMService.createDirectory(versionPath.getSecond(), name);
}
copyPropsAndAspectsRepoToAVM(src, childNodeRef, childPath);
List<FileInfo> listing = fFileFolderService.list(src);
for (FileInfo info : listing)
{
copyRepoToAVM(info.getNodeRef(), childNodeRef, info.getName());
}
return;
}
}
/**
* Helper to copy properties and aspects.
*
* @param src
* The source node.
* @param dst
* The destination node.
* @param dstPath
* The destination AVM path.
*/
private void copyPropsAndAspectsRepoToAVM(NodeRef src, NodeRef dst, String dstPath)
{
Map<QName, Serializable> props = fNodeService.getProperties(src);
fNodeService.setProperties(dst, props);
Set<QName> aspects = fNodeService.getAspects(src);
for (QName aspect : aspects)
{
fAVMService.addAspect(dstPath, aspect);
}
if (!fAVMService.hasAspect(-1, dstPath, ContentModel.ASPECT_COPIEDFROM))
{
fAVMService.addAspect(dstPath, ContentModel.ASPECT_COPIEDFROM);
}
fNodeService.setProperty(dst, ContentModel.PROP_COPY_REFERENCE, src);
}
/**
* Handle copying from Repo to Repo.
*
* @param src
* The source node.
* @param dst
* The destination container.
* @param name
* The name to give the copy.
*/
private void copyRepoToRepo(NodeRef src, NodeRef dst, String name)
{
ChildAssociationRef assocRef = fNodeService.getPrimaryParent(src);
fCopyService.copyAndRename(src, dst, ContentModel.ASSOC_CONTAINS, assocRef.getQName(), true);
}
private void copyData(InputStream in, OutputStream out)
{
try
{
byte[] buff = new byte[8192];
int read = 0;
while ((read = in.read(buff)) != -1)
{
out.write(buff, 0, read);
}
in.close();
out.close();
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("I/O Error.", e);
}
}
}
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.copy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.CrossRepositoryCopyService;
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.namespace.QName;
import org.alfresco.util.Pair;
/**
* Cross Repository Copying.
*
* @author britt
*/
public class CrossRepositoryCopyServiceImpl implements CrossRepositoryCopyService
{
/**
* The NodeService reference.
*/
private NodeService fNodeService;
/**
* The FileFolderService reference.
*/
private FileFolderService fFileFolderService;
/**
* The regular CopyService reference.
*/
private CopyService fCopyService;
/**
* The AVMService.
*/
private AVMService fAVMService;
/**
* The ContentService.
*/
private ContentService fContentService;
/**
* The DictionaryService.
*/
private DictionaryService fDictionaryService;
/**
* A default constructor.
*/
public CrossRepositoryCopyServiceImpl()
{
}
// Setters for Spring.
public void setAvmService(AVMService service)
{
fAVMService = service;
}
public void setContentService(ContentService service)
{
fContentService = service;
}
public void setCopyService(CopyService service)
{
fCopyService = service;
}
public void setDictionaryService(DictionaryService service)
{
fDictionaryService = service;
}
public void setFileFolderService(FileFolderService service)
{
fFileFolderService = service;
}
public void setNodeService(NodeService service)
{
fNodeService = service;
}
/**
* This copies recursively src, which may be a container or a content type to dst, which must be a container. Copied
* nodes will have the copied from aspect applied to them.
*
* @param src
* The node to copy.
* @param dst
* The container to copy it into.
* @param name
* The name to give the copy.
*/
public void copy(NodeRef src, NodeRef dst, String name)
{
StoreRef srcStoreRef = src.getStoreRef();
StoreRef dstStoreRef = dst.getStoreRef();
if (srcStoreRef.getProtocol().equals(StoreRef.PROTOCOL_AVM))
{
if (dstStoreRef.getProtocol().equals(StoreRef.PROTOCOL_AVM))
{
copyAVMToAVM(src, dst, name);
}
else if (dstStoreRef.getProtocol().equals(StoreRef.PROTOCOL_WORKSPACE))
{
copyAVMToRepo(src, dst, name);
}
}
else if (srcStoreRef.getProtocol().equals(StoreRef.PROTOCOL_WORKSPACE))
{
if (dstStoreRef.getProtocol().equals(StoreRef.PROTOCOL_AVM))
{
copyRepoToAVM(src, dst, name);
}
else if (dstStoreRef.getProtocol().equals(StoreRef.PROTOCOL_WORKSPACE))
{
copyRepoToRepo(src, dst, name);
}
}
}
/**
* Handle copying from AVM to AVM
*
* @param src
* Source node.
* @param dst
* Destination directory node.
* @param name
* Name to give copy.
*/
private void copyAVMToAVM(NodeRef src, NodeRef dst, String name)
{
Pair<Integer, String> srcStorePath = AVMNodeConverter.ToAVMVersionPath(src);
Pair<Integer, String> dstStorePath = AVMNodeConverter.ToAVMVersionPath(dst);
fAVMService.copy(srcStorePath.getFirst(), srcStorePath.getSecond(), dstStorePath.getSecond(), name);
}
/**
* Handle copying from AVM to Repo.
*
* @param src
* Source node.
* @param dst
* Destination Container.
* @param name
* The name to give the copy.
*/
private void copyAVMToRepo(NodeRef src, NodeRef dst, String name)
{
Pair<Integer, String> versionPath = AVMNodeConverter.ToAVMVersionPath(src);
AVMNodeDescriptor desc = fAVMService.lookup(versionPath.getFirst(), versionPath.getSecond());
NodeRef existing = fFileFolderService.searchSimple(dst, name);
if (desc.isFile())
{
if (existing != null && !fNodeService.getType(existing).equals(ContentModel.TYPE_CONTENT))
{
fFileFolderService.delete(existing);
existing = null;
}
NodeRef childRef = null;
if (existing == null)
{
childRef = fFileFolderService.create(dst, name, ContentModel.TYPE_CONTENT).getNodeRef();
}
else
{
childRef = existing;
}
InputStream in = fAVMService.getFileInputStream(desc);
ContentData cd = fAVMService.getContentDataForRead(versionPath.getFirst(), desc.getPath());
ContentWriter writer = fContentService.getWriter(childRef, ContentModel.PROP_CONTENT, true);
writer.setEncoding(cd.getEncoding());
writer.setMimetype(cd.getMimetype());
OutputStream out = writer.getContentOutputStream();
copyData(in, out);
copyPropsAndAspectsAVMToRepo(src, childRef);
}
else
{
if (existing != null && !fNodeService.getType(existing).equals(ContentModel.TYPE_FOLDER))
{
fFileFolderService.delete(existing);
existing = null;
}
NodeRef childRef = null;
if (existing == null)
{
childRef = fFileFolderService.create(dst, name, ContentModel.TYPE_FOLDER).getNodeRef();
}
else
{
childRef = existing;
}
copyPropsAndAspectsAVMToRepo(src, childRef);
Map<String, AVMNodeDescriptor> listing = fAVMService.getDirectoryListing(desc);
for (Map.Entry<String, AVMNodeDescriptor> entry : listing.entrySet())
{
NodeRef srcChild = AVMNodeConverter.ToNodeRef(versionPath.getFirst(), entry.getValue().getPath());
copyAVMToRepo(srcChild, childRef, entry.getKey());
}
}
}
/**
* Helper that copies aspects and properties.
*
* @param src
* The source AVM node.
* @param dst
* The destination Repo node.
*/
private void copyPropsAndAspectsAVMToRepo(NodeRef src, NodeRef dst)
{
Map<QName, Serializable> props = fNodeService.getProperties(src);
fNodeService.setProperties(dst, props);
Set<QName> aspects = fNodeService.getAspects(src);
Map<QName, Serializable> empty = new HashMap<QName, Serializable>();
for (QName aspect : aspects)
{
fNodeService.addAspect(dst, aspect, empty);
}
// 4.0: Derek Hulley: The cm:copiedFrom aspect is not that important and
// AVM doesn't support associations
// if (!fNodeService.hasAspect(dst, ContentModel.ASPECT_COPIEDFROM))
// {
// empty.put(ContentModel.PROP_COPY_REFERENCE, src);
// fNodeService.addAspect(dst, ContentModel.ASPECT_COPIEDFROM, empty);
// }
// else
// {
// fNodeService.setProperty(dst, ContentModel.PROP_COPY_REFERENCE, src);
// }
}
/**
* Handle copying from Repo to AVM.
*
* @param src
* The source node.
* @param dst
* The destingation directory.
* @param name
* The name to give the copy.
*/
private void copyRepoToAVM(NodeRef src, NodeRef dst, String name)
{
QName srcType = fNodeService.getType(src);
Pair<Integer, String> versionPath = AVMNodeConverter.ToAVMVersionPath(dst);
String childPath = AVMNodeConverter.ExtendAVMPath(versionPath.getSecond(), name);
NodeRef childNodeRef = AVMNodeConverter.ToNodeRef(-1, childPath);
if (fDictionaryService.isSubClass(srcType, ContentModel.TYPE_CONTENT))
{
ContentReader reader = fContentService.getReader(src, ContentModel.PROP_CONTENT);
InputStream in = reader.getContentInputStream();
AVMNodeDescriptor desc = fAVMService.lookup(-1, childPath);
if (desc != null && !desc.isFile())
{
fAVMService.removeNode(childPath);
desc = null;
}
if (desc == null)
{
try
{
fAVMService.createFile(versionPath.getSecond(), name).close();
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("I/O Error.", e);
}
}
ContentWriter writer = fAVMService.getContentWriter(childPath, true);
writer.setEncoding(reader.getEncoding());
writer.setMimetype(reader.getMimetype());
OutputStream out = writer.getContentOutputStream();
copyData(in, out);
copyPropsAndAspectsRepoToAVM(src, childNodeRef, childPath);
return;
}
if (fDictionaryService.isSubClass(srcType, ContentModel.TYPE_FOLDER))
{
AVMNodeDescriptor desc = fAVMService.lookup(-1, childPath);
if (desc != null && !desc.isDirectory())
{
fAVMService.removeNode(childPath);
desc = null;
}
if (desc == null)
{
fAVMService.createDirectory(versionPath.getSecond(), name);
}
copyPropsAndAspectsRepoToAVM(src, childNodeRef, childPath);
List<FileInfo> listing = fFileFolderService.list(src);
for (FileInfo info : listing)
{
copyRepoToAVM(info.getNodeRef(), childNodeRef, info.getName());
}
return;
}
}
/**
* Helper to copy properties and aspects.
*
* @param src
* The source node.
* @param dst
* The destination node.
* @param dstPath
* The destination AVM path.
*/
private void copyPropsAndAspectsRepoToAVM(NodeRef src, NodeRef dst, String dstPath)
{
Map<QName, Serializable> props = fNodeService.getProperties(src);
fNodeService.setProperties(dst, props);
Set<QName> aspects = fNodeService.getAspects(src);
for (QName aspect : aspects)
{
fAVMService.addAspect(dstPath, aspect);
}
// 4.0: Derek Hulley: The cm:copiedFrom aspect is not that important and
// AVM doesn't support associations
// if (!fAVMService.hasAspect(-1, dstPath, ContentModel.ASPECT_COPIEDFROM))
// {
// fAVMService.addAspect(dstPath, ContentModel.ASPECT_COPIEDFROM);
// }
// fNodeService.setProperty(dst, ContentModel.PROP_COPY_REFERENCE, src);
}
/**
* Handle copying from Repo to Repo.
*
* @param src
* The source node.
* @param dst
* The destination container.
* @param name
* The name to give the copy.
*/
private void copyRepoToRepo(NodeRef src, NodeRef dst, String name)
{
ChildAssociationRef assocRef = fNodeService.getPrimaryParent(src);
fCopyService.copyAndRename(src, dst, ContentModel.ASSOC_CONTAINS, assocRef.getQName(), true);
}
private void copyData(InputStream in, OutputStream out)
{
try
{
byte[] buff = new byte[8192];
int read = 0;
while ((read = in.read(buff)) != -1)
{
out.write(buff, 0, read);
}
in.close();
out.close();
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("I/O Error.", e);
}
}
}

View File

@@ -19,9 +19,13 @@
package org.alfresco.repo.copy.query;
import org.alfresco.query.AbstractCannedQueryFactory;
import org.alfresco.query.CannedQueryParameters;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.qname.QNameDAO;
import org.alfresco.repo.domain.query.CannedQueryDAO;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityBean;
import org.alfresco.service.cmr.repository.CopyService.CopyInfo;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Support for Canned Queries for copy
@@ -34,6 +38,7 @@ public abstract class AbstractCopyCannedQueryFactory<R> extends AbstractCannedQu
protected NodeDAO nodeDAO;
protected QNameDAO qnameDAO;
protected CannedQueryDAO cannedQueryDAO;
protected MethodSecurityBean<CopyInfo> methodSecurity;
public void setNodeDAO(NodeDAO nodeDAO)
{
@@ -47,4 +52,56 @@ public abstract class AbstractCopyCannedQueryFactory<R> extends AbstractCannedQu
{
this.cannedQueryDAO = cannedQueryDAO;
}
public void setMethodSecurity(MethodSecurityBean<CopyInfo> methodSecurity)
{
this.methodSecurity = methodSecurity;
}
/**
* Parameter bean to use for copy queries
*
* @author Derek Hulley
* @since 4.0
*/
public static class CopyCannedQueryDetail
{
/*package*/ final NodeRef originalNodeRef;
/*package*/ final NodeRef copyParentNodeRef;
/**
* @param originalNodeRef the original node
*/
public CopyCannedQueryDetail(NodeRef originalNodeRef)
{
this(originalNodeRef, null);
}
/**
* @param originalNodeRef the original node
* @param copyParentNodeRef the copied node's primary parent (optional)
* @param copyNodeAspectsToIgnore aspects on the copied node that effectively hide it
* (<tt>null</tt> or empty allowed)
*/
public CopyCannedQueryDetail(NodeRef originalNodeRef, NodeRef copyParentNodeRef)
{
super();
if (originalNodeRef == null)
{
throw new IllegalArgumentException("Must supply an originalNodeRef");
}
this.originalNodeRef = originalNodeRef;
this.copyParentNodeRef = copyParentNodeRef;
}
}
protected CopyCannedQueryDetail getDetail(CannedQueryParameters parameters)
{
try
{
return (CopyCannedQueryDetail) parameters.getParameterBean();
}
catch (ClassCastException e)
{
throw new IllegalArgumentException("Expected " + CopyCannedQueryDetail.class);
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.copy.query;
import org.alfresco.repo.domain.node.NodeEntity;
/**
* Bean class to data about copied nodes
*
* @author Derek Hulley
* @since 4.0
*/
public class CopyEntity
{
private NodeEntity copy;
private String copyName;
public NodeEntity getCopy()
{
return copy;
}
public void setCopy(NodeEntity copy)
{
this.copy = copy;
}
public String getCopyName()
{
return copyName;
}
public void setCopyName(String copyName)
{
this.copyName = copyName;
}
}

View File

@@ -29,7 +29,8 @@ import java.util.List;
public class CopyParametersEntity
{
private Long originalNodeId;
private Long copiedFromAssocTypeId;
private Long originalAssocTypeId;
private Long namePropId;
private Long copyParentNodeId;
private List<Long> copyAspectIdsToIgnore;
@@ -41,13 +42,21 @@ public class CopyParametersEntity
{
this.originalNodeId = originalNodeId;
}
public Long getCopiedFromAssocTypeId()
public Long getOriginalAssocTypeId()
{
return copiedFromAssocTypeId;
return originalAssocTypeId;
}
public void setCopiedFromAssocTypeId(Long copiedFromAssocTypeId)
public void setOriginalAssocTypeId(Long originalAssocTypeId)
{
this.copiedFromAssocTypeId = copiedFromAssocTypeId;
this.originalAssocTypeId = originalAssocTypeId;
}
public Long getNamePropId()
{
return namePropId;
}
public void setNamePropId(Long namePropId)
{
this.namePropId = namePropId;
}
public Long getCopyParentNodeId()
{
@@ -65,4 +74,8 @@ public class CopyParametersEntity
{
this.copyAspectIdsToIgnore = copyAspectIdsToIgnore;
}
public boolean getTrue()
{
return true;
}
}

View File

@@ -18,10 +18,20 @@
*/
package org.alfresco.repo.copy.query;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQuery;
import org.alfresco.query.CannedQueryParameters;
import org.alfresco.repo.security.permissions.impl.acegi.AbstractCannedQueryPermissions;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityBean;
import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.CopyService.CopyInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
/**
* Factory producing queries for the {@link CopyService}
@@ -34,6 +44,75 @@ public class GetCopiesCannedQueryFactory extends AbstractCopyCannedQueryFactory<
@Override
public CannedQuery<CopyInfo> getCannedQuery(CannedQueryParameters parameters)
{
throw new UnsupportedOperationException();
return new GetCopiesCannedQuery(parameters, methodSecurity);
}
/**
* Query to find nodes copied <i>from</i> a given node, optionally filtering out
* based on specific values.
*
* @author Derek Hulley
* @since 4.0
*/
private class GetCopiesCannedQuery extends AbstractCannedQueryPermissions<CopyInfo>
{
private GetCopiesCannedQuery(CannedQueryParameters parameters, MethodSecurityBean<CopyInfo> methodSecurity)
{
super(parameters, methodSecurity);
}
@Override
protected List<CopyInfo> queryAndFilter(CannedQueryParameters parameters)
{
CopyCannedQueryDetail detail = GetCopiesCannedQueryFactory.this.getDetail(parameters);
// Build parameters
CopyParametersEntity queryParameters = new CopyParametersEntity();
// Original node
Pair<Long, NodeRef> originalNodePair = nodeDAO.getNodePair(detail.originalNodeRef);
if (originalNodePair == null)
{
return Collections.emptyList(); // Shortcut
}
queryParameters.setOriginalNodeId(originalNodePair.getFirst());
// cm:original association type ID
Pair<Long, QName> assocTypeQNamePair = qnameDAO.getQName(ContentModel.ASSOC_ORIGINAL);
if (assocTypeQNamePair == null)
{
return Collections.emptyList(); // Shortcut
}
queryParameters.setOriginalAssocTypeId(assocTypeQNamePair.getFirst());
// cm:name property ID
Pair<Long, QName> propQNamePair = qnameDAO.getQName(ContentModel.PROP_NAME);
if (propQNamePair == null)
{
return Collections.emptyList(); // Shortcut
}
queryParameters.setNamePropId(propQNamePair.getFirst());
// Copied parent node
if (detail.copyParentNodeRef != null)
{
Pair<Long, NodeRef> copyParentNodePair = nodeDAO.getNodePair(detail.copyParentNodeRef);
if (copyParentNodePair == null)
{
return Collections.emptyList(); // Shortcut
}
queryParameters.setCopyParentNodeId(copyParentNodePair.getFirst());
}
// Now query
int resultsRequired = parameters.getResultsRequired();
List<CopyEntity> copies = cannedQueryDAO.executeQuery(
"alfresco.query.copy", "select_GetCopies",
queryParameters,
0, resultsRequired);
// Convert them
List<CopyInfo> results = new ArrayList<CopyService.CopyInfo>(copies.size());
for (CopyEntity copy : copies)
{
CopyInfo result = new CopyInfo(copy.getCopy().getNodeRef(), copy.getCopyName());
results.add(result);
}
// Done
return results;
}
}
}