use of org.alfresco.service.cmr.repository.AssociationRef in project alfresco-repository by Alfresco.
the class CopyServiceImpl method recursiveCopy.
/**
* Recursive copy algorithm
*
* @param dropName drop the name property when associations don't allow duplicately named children
*/
private NodeRef recursiveCopy(CopyDetails copyDetails, boolean copyChildren, boolean dropName, Map<NodeRef, NodeRef> copiesByOriginal, Set<NodeRef> copies, Map<QName, CopyBehaviourCallback> callbacks) {
NodeRef sourceNodeRef = copyDetails.getSourceNodeRef();
Set<QName> sourceNodeAspectQNames = copyDetails.getSourceNodeAspectQNames();
NodeRef targetParentNodeRef = copyDetails.getTargetParentNodeRef();
QName assocTypeQName = copyDetails.getAssocTypeQName();
QName assocQName = copyDetails.getAssocQName();
// Avoid duplicate and cyclic copies
if (copies.contains(sourceNodeRef)) {
throw new IllegalStateException("Nested copy prevention has failed: \n" + " " + copyDetails + "\n" + " Copies by original: " + copiesByOriginal);
} else if (copiesByOriginal.containsKey(sourceNodeRef)) {
throw new IllegalStateException("Multiple child assocs between same two nodes detected: \n" + " " + copyDetails + "\n" + " Copies by original: " + copiesByOriginal);
}
// Extract Type Definition
QName sourceNodeTypeQName = copyDetails.getSourceNodeTypeQName();
// Does this node get copied at all?
// The source node's type-bound behaviour has an effective veto.
CopyBehaviourCallback sourceTypeBehaviour = callbacks.get(sourceNodeTypeQName);
if (sourceTypeBehaviour == null) {
throw new IllegalStateException("Source node type has no callback: " + sourceNodeTypeQName);
}
if (!sourceTypeBehaviour.getMustCopy(sourceNodeTypeQName, copyDetails)) {
// Nothing to do
return null;
}
// Get the type properties to copy
Map<QName, Serializable> targetNodeProperties = buildCopyProperties(copyDetails, Collections.singleton(sourceNodeTypeQName), callbacks);
// Some aspects are going to be applied automatically. For efficiency, the initial node properties
// for these aspects should be provided.
Set<QName> defaultAspectQNames = getDefaultAspects(sourceNodeTypeQName);
Map<QName, Serializable> defaultAspectsProperties = buildCopyProperties(copyDetails, defaultAspectQNames, callbacks);
targetNodeProperties.putAll(defaultAspectsProperties);
// Drop the name property, if required. This prevents duplicate names and leaves it up to the client
// to assign a new name.
AssociationDefinition assocDef = dictionaryService.getAssociation(assocTypeQName);
if (!assocDef.isChild()) {
throw new AlfrescoRuntimeException("Association is not a child association: " + assocTypeQName);
} else {
ChildAssociationDefinition childAssocDef = (ChildAssociationDefinition) assocDef;
if (dropName && !childAssocDef.getDuplicateChildNamesAllowed()) {
// ALF-13949: A behaviour callback (e.g. WorkingCopyAspect) may already have generated a new name, so
// preserve the new name if it has changed
String newName = (String) targetNodeProperties.get(ContentModel.PROP_NAME);
if (newName != null && newName.equals(nodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME))) {
// duplicate children are not allowed.
targetNodeProperties.remove(ContentModel.PROP_NAME);
}
}
}
// Lastly, make sure the the Node UUID is set correctly; after all, the contract
// of the CopyDetails says that the targetNodeRef was already determined.
String targetNodeUuid = copyDetails.getTargetNodeRef().getId();
targetNodeProperties.put(ContentModel.PROP_NODE_UUID, targetNodeUuid);
// The initial node copy is good to go
ChildAssociationRef targetChildAssocRef = this.nodeService.createNode(targetParentNodeRef, assocTypeQName, assocQName, sourceNodeTypeQName, targetNodeProperties);
NodeRef copyTarget = targetChildAssocRef.getChildRef();
// Save the mapping for later
copiesByOriginal.put(sourceNodeRef, copyTarget);
copies.add(copyTarget);
// We now have a node, so fire the BeforeCopyPolicy
invokeBeforeCopy(sourceNodeRef, copyTarget);
// Work out which aspects still need copying. The source aspects less the default aspects
// will give this set.
Set<QName> remainingAspectQNames = new HashSet<QName>(sourceNodeAspectQNames);
remainingAspectQNames.removeAll(defaultAspectQNames);
// Prevent any rules being fired on the new destination node
this.ruleService.disableRules(copyTarget);
try {
// Apply the remaining aspects and properties
for (QName remainingAspectQName : remainingAspectQNames) {
copyProperties(copyDetails, copyTarget, remainingAspectQName, callbacks);
}
// Copy residual properties
copyResidualProperties(copyDetails, copyTarget);
// 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);
}
// We create the link if the source is a cm:object and the not sys:pendingDelete
QName sourceTypeQName = internalNodeService.getType(sourceNodeRef);
if (dictionaryService.isSubClass(sourceTypeQName, ContentModel.TYPE_CMOBJECT) && !sourceNodeAspectQNames.contains(ContentModel.ASPECT_PENDING_DELETE)) {
internalNodeService.createAssociation(copyTarget, sourceNodeRef, ContentModel.ASSOC_ORIGINAL);
} else {
// We are not creating the association, so remove the associated aspect
internalNodeService.removeAspect(copyTarget, ContentModel.ASPECT_COPIEDFROM);
}
// Copy permissions
copyPermissions(sourceNodeRef, copyTarget);
// We present the recursion option regardless of what the client chooses
copyChildren(copyDetails, copyTarget, // We know that the node has been created
true, copyChildren, copiesByOriginal, copies, callbacks);
} finally {
this.ruleService.enableRules(copyTarget);
}
return copyTarget;
}
use of org.alfresco.service.cmr.repository.AssociationRef in project alfresco-repository by Alfresco.
the class CMISConnector method getRelationships.
public List<ObjectData> getRelationships(NodeRef nodeRef, IncludeRelationships includeRelationships) /*, CmisVersion cmisVersion*/
{
List<ObjectData> result = new ArrayList<ObjectData>();
if (nodeRef.getStoreRef().getProtocol().equals(VersionBaseModel.STORE_PROTOCOL)) {
// relationships from and to versions are not preserved
return result;
}
// get relationships
List<AssociationRef> assocs = new ArrayList<AssociationRef>();
if (includeRelationships == IncludeRelationships.SOURCE || includeRelationships == IncludeRelationships.BOTH) {
assocs.addAll(nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL));
}
if (includeRelationships == IncludeRelationships.TARGET || includeRelationships == IncludeRelationships.BOTH) {
assocs.addAll(nodeService.getSourceAssocs(nodeRef, RegexQNamePattern.MATCH_ALL));
}
// filter relationships that not map the CMIS domain model
for (AssociationRef assocRef : assocs) {
TypeDefinitionWrapper assocTypeDef = getOpenCMISDictionaryService().findAssocType(assocRef.getTypeQName());
if (assocTypeDef == null || getType(assocRef.getSourceRef()) == null || getType(assocRef.getTargetRef()) == null) {
continue;
}
try {
result.add(createCMISObject(createNodeInfo(assocRef), null, false, IncludeRelationships.NONE, RENDITION_NONE, false, false));
} catch (AccessDeniedException e) {
// PUBLICAPI-110
// ok, just skip it
} catch (CmisObjectNotFoundException e) {
// ignore objects that have not been found (perhaps because their type is unknown to CMIS)
}// TODO: Somewhere this has not been wrapped correctly
catch (net.sf.acegisecurity.AccessDeniedException e) {
// skip
}
}
return result;
}
use of org.alfresco.service.cmr.repository.AssociationRef in project alfresco-repository by Alfresco.
the class CMISConnector method getObjectRelationships.
public ObjectList getObjectRelationships(NodeRef nodeRef, RelationshipDirection relationshipDirection, String typeId, String filter, Boolean includeAllowableActions, BigInteger maxItems, BigInteger skipCount) {
ObjectListImpl result = new ObjectListImpl();
result.setHasMoreItems(false);
result.setNumItems(BigInteger.ZERO);
result.setObjects(new ArrayList<ObjectData>());
if (nodeRef.getStoreRef().getProtocol().equals(VersionBaseModel.STORE_PROTOCOL)) {
// relationships from and to versions are not preserved
return result;
}
// get relationships
List<AssociationRef> assocs = new ArrayList<AssociationRef>();
if (relationshipDirection == RelationshipDirection.SOURCE || relationshipDirection == RelationshipDirection.EITHER) {
assocs.addAll(nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL));
}
if (relationshipDirection == RelationshipDirection.TARGET || relationshipDirection == RelationshipDirection.EITHER) {
assocs.addAll(nodeService.getSourceAssocs(nodeRef, RegexQNamePattern.MATCH_ALL));
}
int skip = (skipCount == null ? 0 : skipCount.intValue());
int max = (maxItems == null ? Integer.MAX_VALUE : maxItems.intValue());
int counter = 0;
boolean hasMore = false;
if (max > 0) {
// filter relationships that not map the CMIS domain model
for (AssociationRef assocRef : assocs) {
TypeDefinitionWrapper assocTypeDef = getOpenCMISDictionaryService().findAssocType(assocRef.getTypeQName());
if (assocTypeDef == null || getType(assocRef.getSourceRef()) == null || getType(assocRef.getTargetRef()) == null) {
continue;
}
if ((typeId != null) && !assocTypeDef.getTypeId().equals(typeId)) {
continue;
}
counter++;
if (skip > 0) {
skip--;
continue;
}
max--;
if (max > 0) {
try {
result.getObjects().add(createCMISObject(createNodeInfo(assocRef), filter, includeAllowableActions, IncludeRelationships.NONE, RENDITION_NONE, false, false));
} catch (CmisObjectNotFoundException e) {
// ignore objects that have not been found (perhaps because their type is unknown to CMIS)
}
} else {
hasMore = true;
}
}
}
result.setNumItems(BigInteger.valueOf(counter));
result.setHasMoreItems(hasMore);
return result;
}
use of org.alfresco.service.cmr.repository.AssociationRef in project alfresco-repository by Alfresco.
the class AbstractNodeDAOImpl method getTargetNodeAssocs.
@Override
public Collection<Pair<Long, AssociationRef>> getTargetNodeAssocs(Long sourceNodeId, QName typeQName) {
Long typeQNameId = null;
if (typeQName != null) {
Pair<Long, QName> typeQNamePair = qnameDAO.getQName(typeQName);
if (typeQNamePair == null) {
// No such QName
return Collections.emptyList();
}
typeQNameId = typeQNamePair.getFirst();
}
List<NodeAssocEntity> nodeAssocEntities = selectNodeAssocsBySource(sourceNodeId, typeQNameId);
List<Pair<Long, AssociationRef>> results = new ArrayList<Pair<Long, AssociationRef>>(nodeAssocEntities.size());
for (NodeAssocEntity nodeAssocEntity : nodeAssocEntities) {
Long assocId = nodeAssocEntity.getId();
AssociationRef assocRef = nodeAssocEntity.getAssociationRef(qnameDAO);
results.add(new Pair<Long, AssociationRef>(assocId, assocRef));
}
return results;
}
use of org.alfresco.service.cmr.repository.AssociationRef in project alfresco-repository by Alfresco.
the class ScriptNode method getSourceAssocs.
/**
* Return the source associations to this Node. As a Map of assoc name to a JavaScript array of Nodes.
* The Map returned implements the Scriptable interface to allow access to the assoc arrays via JavaScript
* associative array access. This means source associations to this node can be access thus:
* <code>node.sourceAssocs["translations"][0]</code>
*
* @return source associations as a Map of assoc name to a JavaScript array of Nodes.
*/
@SuppressWarnings("unchecked")
public Map<String, Object> getSourceAssocs() {
if (this.sourceAssocs == null) {
// this Map implements the Scriptable interface for native JS syntax property access
this.sourceAssocs = new ScriptableQNameMap<String, Object>(this);
// get the list of source nodes for each association type
List<AssociationRef> refs = this.nodeService.getSourceAssocs(this.nodeRef, RegexQNamePattern.MATCH_ALL);
for (AssociationRef ref : refs) {
String qname = ref.getTypeQName().toString();
List<ScriptNode> nodes = (List<ScriptNode>) this.sourceAssocs.get(qname);
if (nodes == null) {
// first access of the list for this qname
nodes = new ArrayList<ScriptNode>(4);
this.sourceAssocs.put(ref.getTypeQName().toString(), nodes);
}
nodes.add(newInstance(ref.getSourceRef(), this.services, this.scope));
}
// convert each Node list into a JavaScript array object
for (String qname : this.sourceAssocs.keySet()) {
List<ScriptNode> nodes = (List<ScriptNode>) this.sourceAssocs.get(qname);
Object[] objs = nodes.toArray(new Object[nodes.size()]);
this.sourceAssocs.put(qname, Context.getCurrentContext().newArray(this.scope, objs));
}
}
return this.sourceAssocs;
}
Aggregations