mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-02 17:35:18 +00:00
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3833 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
1507 lines
58 KiB
Java
1507 lines
58 KiB
Java
/*
|
|
* Copyright (C) 2006 Alfresco, Inc.
|
|
*
|
|
* Licensed under the Mozilla Public License version 1.1
|
|
* with a permitted attribution clause. You may obtain a
|
|
* copy of the License at
|
|
*
|
|
* http://www.alfresco.org/legal/license.txt
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
|
* either express or implied. See the License for the specific
|
|
* language governing permissions and limitations under the
|
|
* License.
|
|
*/
|
|
|
|
package org.alfresco.repo.avm;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.SortedMap;
|
|
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.repo.domain.PropertyValue;
|
|
import org.alfresco.repo.node.AbstractNodeServiceImpl;
|
|
import org.alfresco.service.cmr.avm.AVMException;
|
|
import org.alfresco.service.cmr.avm.AVMExistsException;
|
|
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
|
|
import org.alfresco.service.cmr.avm.AVMNotFoundException;
|
|
import org.alfresco.service.cmr.avm.AVMService;
|
|
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
|
|
import org.alfresco.service.cmr.avm.AVMWrongTypeException;
|
|
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
|
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
|
import org.alfresco.service.cmr.dictionary.InvalidAspectException;
|
|
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
|
|
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
|
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
|
import org.alfresco.service.cmr.repository.AssociationExistsException;
|
|
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.CyclicChildRelationshipException;
|
|
import org.alfresco.service.cmr.repository.InvalidChildAssociationRefException;
|
|
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
|
import org.alfresco.service.cmr.repository.InvalidStoreRefException;
|
|
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.StoreExistsException;
|
|
import org.alfresco.service.cmr.repository.StoreRef;
|
|
import org.alfresco.service.namespace.NamespaceService;
|
|
import org.alfresco.service.namespace.QName;
|
|
import org.alfresco.service.namespace.QNamePattern;
|
|
import org.apache.log4j.Logger;
|
|
|
|
/**
|
|
* NodeService implementing facade over AVMService.
|
|
* @author britt
|
|
*/
|
|
public class AVMNodeService extends AbstractNodeServiceImpl implements NodeService
|
|
{
|
|
private static Logger fgLogger = Logger.getLogger(AVMNodeService.class);
|
|
|
|
/**
|
|
* Reference to AVMService.
|
|
*/
|
|
private AVMService fAVMService;
|
|
|
|
/**
|
|
* Set the AVMService. For Spring.
|
|
* @param service The AVMService instance.
|
|
*/
|
|
public void setAvmService(AVMService service)
|
|
{
|
|
fAVMService = service;
|
|
}
|
|
|
|
/**
|
|
* Default constructor.
|
|
*/
|
|
public AVMNodeService()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Gets a list of all available node store references
|
|
*
|
|
* @return Returns a list of store references
|
|
*/
|
|
public List<StoreRef> getStores()
|
|
{
|
|
// For AVM stores we fake up StoreRefs.
|
|
List<AVMStoreDescriptor> stores = fAVMService.getAVMStores();
|
|
List<StoreRef> result = new ArrayList<StoreRef>();
|
|
for (AVMStoreDescriptor desc : stores)
|
|
{
|
|
String name = desc.getName();
|
|
result.add(new StoreRef(StoreRef.PROTOCOL_AVM, name));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Create a new AVM store.
|
|
* @param protocol the implementation protocol
|
|
* @param identifier the protocol-specific identifier
|
|
* @return Returns a reference to the store
|
|
* @throws StoreExistsException
|
|
*/
|
|
public StoreRef createStore(String protocol, String identifier) throws StoreExistsException
|
|
{
|
|
StoreRef result = new StoreRef(StoreRef.PROTOCOL_AVM, identifier);
|
|
invokeBeforeCreateStore(ContentModel.TYPE_STOREROOT, result);
|
|
try
|
|
{
|
|
fAVMService.createAVMStore(identifier);
|
|
NodeRef rootRef = getRootNode(result);
|
|
addAspect(rootRef, ContentModel.ASPECT_ROOT,
|
|
Collections.<QName, Serializable>emptyMap());
|
|
invokeOnCreateStore(rootRef);
|
|
return result;
|
|
}
|
|
catch (AVMExistsException e)
|
|
{
|
|
throw new StoreExistsException("AVMStore exists", result);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Does the indicated store exist?
|
|
* @param storeRef a reference to the store to look for
|
|
* @return Returns true if the store exists, otherwise false
|
|
*/
|
|
public boolean exists(StoreRef storeRef)
|
|
{
|
|
return fAVMService.getAVMStore(storeRef.getIdentifier()) != null;
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef a reference to the node to look for
|
|
* @return Returns true if the node exists, otherwise false
|
|
*/
|
|
public boolean exists(NodeRef nodeRef)
|
|
{
|
|
Object [] avmInfo = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = (Integer)avmInfo[0];
|
|
String avmPath = (String)avmInfo[1];
|
|
return fAVMService.lookup(version, avmPath) != null;
|
|
}
|
|
|
|
/**
|
|
* Gets the ID of the last transaction that caused the node to change. This includes
|
|
* deletions, so it is possible that the node being referenced no longer exists.
|
|
* If the node never existed, then null is returned.
|
|
*
|
|
* @param nodeRef a reference to a current or previously existing node
|
|
* @return Returns the status of the node, or null if the node never existed
|
|
*/
|
|
public NodeRef.Status getNodeStatus(NodeRef nodeRef)
|
|
{
|
|
// TODO Need to find out if this is important and if so
|
|
// need to capture Transaction IDs.
|
|
return new NodeRef.Status("Unknown", !exists(nodeRef));
|
|
}
|
|
|
|
/**
|
|
* @param storeRef a reference to an existing store
|
|
* @return Returns a reference to the root node of the store
|
|
* @throws InvalidStoreRefException if the store could not be found
|
|
*/
|
|
public NodeRef getRootNode(StoreRef storeRef) throws InvalidStoreRefException
|
|
{
|
|
String storeName = storeRef.getIdentifier();
|
|
if (fAVMService.getAVMStore(storeName) != null)
|
|
{
|
|
return AVMNodeConverter.ToNodeRef(-1, storeName + ":/");
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidStoreRefException("Not Found.", storeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @see #createNode(NodeRef, QName, QName, QName, Map)
|
|
*/
|
|
public ChildAssociationRef createNode(
|
|
NodeRef parentRef,
|
|
QName assocTypeQName,
|
|
QName assocQName,
|
|
QName nodeTypeQName)
|
|
throws InvalidNodeRefException, InvalidTypeException
|
|
{
|
|
return createNode(parentRef,
|
|
assocTypeQName,
|
|
assocQName,
|
|
nodeTypeQName,
|
|
new HashMap<QName, Serializable>());
|
|
}
|
|
|
|
/**
|
|
* Creates a new, non-abstract, real node as a primary child of the given parent node.
|
|
*
|
|
* @param parentRef the parent node
|
|
* @param assocTypeQName the type of the association to create. This is used
|
|
* for verification against the data dictionary.
|
|
* @param assocQName the qualified name of the association
|
|
* @param nodeTypeQName a reference to the node type
|
|
* @param properties optional map of properties to keyed by their qualified names
|
|
* @return Returns a reference to the newly created child association
|
|
* @throws InvalidNodeRefException if the parent reference is invalid
|
|
* @throws InvalidTypeException if the node type reference is not recognised
|
|
*
|
|
* @see org.alfresco.service.cmr.dictionary.DictionaryService
|
|
*/
|
|
public ChildAssociationRef createNode(
|
|
NodeRef parentRef,
|
|
QName assocTypeQName,
|
|
QName assocQName,
|
|
QName nodeTypeQName,
|
|
Map<QName, Serializable> properties)
|
|
throws InvalidNodeRefException, InvalidTypeException
|
|
{
|
|
// AVM stores only allow simple child associations.
|
|
if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
throw new InvalidTypeException(assocTypeQName);
|
|
}
|
|
String nodeName = assocQName.getLocalName();
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef);
|
|
int version = ((Integer)avmVersionPath[0]);
|
|
if (version >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", parentRef);
|
|
}
|
|
String avmPath = (String)avmVersionPath[1];
|
|
// Invoke policy behavior.
|
|
invokeBeforeUpdateNode(parentRef);
|
|
invokeBeforeCreateNode(parentRef, assocTypeQName, assocQName, nodeTypeQName);
|
|
// Look up the type definition in the dictionary.
|
|
TypeDefinition nodeTypeDef = dictionaryService.getType(nodeTypeQName);
|
|
// Do the creates for supported types, or error out.
|
|
try
|
|
{
|
|
if (nodeTypeQName.equals(ContentModel.TYPE_AVM_PLAIN_FOLDER) ||
|
|
nodeTypeQName.equals(ContentModel.TYPE_FOLDER))
|
|
{
|
|
fAVMService.createDirectory(avmPath, nodeName);
|
|
}
|
|
else if (nodeTypeQName.equals(ContentModel.TYPE_AVM_PLAIN_CONTENT)
|
|
||nodeTypeQName.equals(ContentModel.TYPE_CONTENT))
|
|
{
|
|
fAVMService.createFile(avmPath, nodeName);
|
|
}
|
|
else if (nodeTypeQName.equals(ContentModel.TYPE_AVM_LAYERED_CONTENT))
|
|
{
|
|
NodeRef indirection = (NodeRef)properties.get(ContentModel.PROP_AVM_FILE_INDIRECTION);
|
|
if (indirection == null)
|
|
{
|
|
throw new InvalidTypeException("No Indirection Property", nodeTypeQName);
|
|
}
|
|
Object [] indVersionPath = AVMNodeConverter.ToAVMVersionPath(indirection);
|
|
fAVMService.createLayeredFile((String)indVersionPath[1], avmPath, nodeName);
|
|
}
|
|
else if (nodeTypeQName.equals(ContentModel.TYPE_AVM_LAYERED_FOLDER))
|
|
{
|
|
NodeRef indirection = (NodeRef)properties.get(ContentModel.PROP_AVM_DIR_INDIRECTION);
|
|
if (indirection == null)
|
|
{
|
|
throw new InvalidTypeException("No Indirection Property.", nodeTypeQName);
|
|
}
|
|
Object [] indVersionPath = AVMNodeConverter.ToAVMVersionPath(indirection);
|
|
fAVMService.createLayeredDirectory((String)indVersionPath[1], avmPath, nodeName);
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidTypeException("Invalid node type for AVM.", nodeTypeQName);
|
|
}
|
|
addDefaultPropertyValues(nodeTypeDef, properties);
|
|
// TODO Add default aspects to the child..
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException("Not Found.", parentRef);
|
|
}
|
|
catch (AVMExistsException e)
|
|
{
|
|
throw new InvalidNodeRefException("Child " + nodeName + " exists", parentRef);
|
|
}
|
|
String newAVMPath = AVMNodeConverter.ExtendAVMPath(avmPath, nodeName);
|
|
NodeRef childRef = AVMNodeConverter.ToNodeRef(-1, newAVMPath);
|
|
addDefaultPropertyValues(nodeTypeDef, properties);
|
|
addDefaultAspects(nodeTypeDef, newAVMPath, properties);
|
|
Map<QName, PropertyValue> props = new HashMap<QName, PropertyValue>();
|
|
for (QName qname : properties.keySet())
|
|
{
|
|
if (isBuiltInProperty(qname))
|
|
{
|
|
continue;
|
|
}
|
|
props.put(qname, new PropertyValue(null, properties.get(qname)));
|
|
}
|
|
fAVMService.setNodeProperties(newAVMPath, props);
|
|
ChildAssociationRef ref =
|
|
new ChildAssociationRef(assocTypeQName,
|
|
parentRef,
|
|
assocQName,
|
|
childRef,
|
|
true,
|
|
-1);
|
|
invokeOnCreateNode(ref);
|
|
invokeOnUpdateNode(parentRef);
|
|
// TODO invokeOnUpdateProperties
|
|
|
|
return ref;
|
|
}
|
|
|
|
/**
|
|
* Moves the primary location of the given node.
|
|
* <p>
|
|
* This involves changing the node's primary parent and possibly the name of the
|
|
* association referencing it.
|
|
* <p>
|
|
* If the new parent is in a different store from the original, then the entire
|
|
* node hierarchy is moved to the new store. Inter-store associations are not
|
|
* affected.
|
|
*
|
|
* @param nodeToMoveRef the node to move
|
|
* @param newParentRef the new parent of the moved node
|
|
* @param assocTypeQName the type of the association to create. This is used
|
|
* for verification against the data dictionary.
|
|
* @param assocQName the qualified name of the new child association
|
|
* @return Returns a reference to the newly created child association
|
|
* @throws InvalidNodeRefException if either the parent node or move node reference is invalid
|
|
* @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add
|
|
*
|
|
* @see #getPrimaryParent(NodeRef)
|
|
*/
|
|
public ChildAssociationRef moveNode(
|
|
NodeRef nodeToMoveRef,
|
|
NodeRef newParentRef,
|
|
QName assocTypeQName,
|
|
QName assocQName)
|
|
throws InvalidNodeRefException
|
|
{
|
|
// AVM stores only allow simple child associations.
|
|
if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
throw new InvalidTypeException(assocTypeQName);
|
|
}
|
|
// Extract the parts from the source.
|
|
Object [] src = AVMNodeConverter.ToAVMVersionPath(nodeToMoveRef);
|
|
int srcVersion = (Integer)src[0];
|
|
if (srcVersion >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read Only Store.", nodeToMoveRef);
|
|
}
|
|
String srcPath = (String)src[0];
|
|
String [] splitSrc = null;
|
|
try
|
|
{
|
|
splitSrc = AVMNodeConverter.SplitBase(srcPath);
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
throw new InvalidNodeRefException("Invalid src path.", nodeToMoveRef);
|
|
}
|
|
String srcParent = splitSrc[0];
|
|
if (srcParent == null)
|
|
{
|
|
throw new InvalidNodeRefException("Cannot rename root node.", nodeToMoveRef);
|
|
}
|
|
String srcName = splitSrc[1];
|
|
// Extract and setup the parts of the destination.
|
|
Object[] dst = AVMNodeConverter.ToAVMVersionPath(newParentRef);
|
|
if ((Integer)dst[0] >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read Only Store.", newParentRef);
|
|
}
|
|
String dstParent = (String)dst[1];
|
|
String dstName = assocQName.getLocalName();
|
|
// TODO Invoke policy behavior. Not quite sure how to translate this.
|
|
// Actually perform the rename and return a pseudo
|
|
// ChildAssociationRef.
|
|
try
|
|
{
|
|
fAVMService.rename(srcParent, srcName, dstParent, dstName);
|
|
String dstPath = AVMNodeConverter.ExtendAVMPath(dstParent, dstName);
|
|
// TODO Invoke policy behaviors. Not sure how to translate that.
|
|
return new ChildAssociationRef(assocTypeQName,
|
|
newParentRef,
|
|
assocQName,
|
|
AVMNodeConverter.ToNodeRef(-1, dstPath),
|
|
true,
|
|
-1);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException("Non existent node.", nodeToMoveRef);
|
|
}
|
|
catch (AVMExistsException e)
|
|
{
|
|
throw new InvalidNodeRefException("Target already exists.", newParentRef);
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
throw new InvalidNodeRefException("Illegal move.", nodeToMoveRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the ordering index of the child association. This affects the ordering of
|
|
* of the return values of methods that return a set of children or child
|
|
* associations.
|
|
*
|
|
* @param childAssocRef the child association that must be moved in the order
|
|
* @param index an arbitrary index that will affect the return order
|
|
*
|
|
* @see #getChildAssocs(NodeRef)
|
|
* @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern)
|
|
* @see ChildAssociationRef#getNthSibling()
|
|
*/
|
|
public void setChildAssociationIndex(
|
|
ChildAssociationRef childAssocRef,
|
|
int index)
|
|
throws InvalidChildAssociationRefException
|
|
{
|
|
// TODO We'll keep this a no-op unless there's a
|
|
// compelling reason to implement this capability
|
|
// for the AVM repository.
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef
|
|
* @return Returns the type name
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see org.alfresco.service.cmr.dictionary.DictionaryService
|
|
*/
|
|
public QName getType(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
AVMNodeDescriptor desc = fAVMService.lookup((Integer)avmVersionPath[0],
|
|
(String)avmVersionPath[1]);
|
|
if (desc == null)
|
|
{
|
|
throw new InvalidNodeRefException("Not Found.", nodeRef);
|
|
}
|
|
if (desc.isPlainDirectory())
|
|
{
|
|
return ContentModel.TYPE_AVM_PLAIN_FOLDER;
|
|
}
|
|
else if (desc.isPlainFile())
|
|
{
|
|
return ContentModel.TYPE_AVM_PLAIN_CONTENT;
|
|
}
|
|
else if (desc.isLayeredDirectory())
|
|
{
|
|
return ContentModel.TYPE_AVM_LAYERED_FOLDER;
|
|
}
|
|
else
|
|
{
|
|
return ContentModel.TYPE_AVM_LAYERED_CONTENT;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Re-sets the type of the node. Can be called in order specialise a node to a sub-type.
|
|
*
|
|
* This should be used with caution since calling it changes the type of the node and thus
|
|
* implies a different set of aspects, properties and associations. It is the calling codes
|
|
* responsibility to ensure that the node is in a approriate state after changing the type.
|
|
*
|
|
* @param nodeRef the node reference
|
|
* @param typeQName the type QName
|
|
*
|
|
* @since 1.1
|
|
*/
|
|
public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException
|
|
{
|
|
throw new UnsupportedOperationException("AVM Types are immutable.");
|
|
}
|
|
|
|
/**
|
|
* Applies an aspect to the given node. After this method has been called,
|
|
* the node with have all the aspect-related properties present
|
|
*
|
|
* @param nodeRef
|
|
* @param aspectTypeQName the aspect to apply to the node
|
|
* @param aspectProperties a minimum of the mandatory properties required for
|
|
* the aspect
|
|
* @throws InvalidNodeRefException
|
|
* @throws InvalidAspectException if the class reference is not to a valid aspect
|
|
*
|
|
* @see org.alfresco.service.cmr.dictionary.DictionaryService#getAspect(QName)
|
|
* @see org.alfresco.service.cmr.dictionary.ClassDefinition#getProperties()
|
|
*/
|
|
public void addAspect(
|
|
NodeRef nodeRef,
|
|
QName aspectTypeQName,
|
|
Map<QName, Serializable> aspectProperties)
|
|
throws InvalidNodeRefException, InvalidAspectException
|
|
{
|
|
// Check that the aspect exists.
|
|
AspectDefinition aspectDef = this.dictionaryService.getAspect(aspectTypeQName);
|
|
if (aspectDef == null)
|
|
{
|
|
throw new InvalidAspectException("The aspect is invalid: " + aspectTypeQName,
|
|
aspectTypeQName);
|
|
}
|
|
// Invoke policy behaviors.
|
|
invokeBeforeUpdateNode(nodeRef);
|
|
invokeBeforeAddAspect(nodeRef, aspectTypeQName);
|
|
// Crack the nodeRef.
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = (Integer)avmVersionPath[0];
|
|
if (version >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read Only node.", nodeRef);
|
|
}
|
|
String avmPath = (String)avmVersionPath[1];
|
|
// Get the current node properties.
|
|
Map<QName, Serializable> properties = getProperties(nodeRef);
|
|
// Add the supplied properties.
|
|
if (aspectProperties != null)
|
|
{
|
|
properties.putAll(aspectProperties);
|
|
}
|
|
// Now set any unspecified default properties for the aspect.
|
|
addDefaultPropertyValues(aspectDef, properties);
|
|
// Now add any cascading aspects.
|
|
addDefaultAspects(aspectDef, avmPath, properties);
|
|
// Set the property values on the AVM Node.
|
|
setProperties(nodeRef, properties);
|
|
if (isBuiltinAspect(aspectTypeQName))
|
|
{
|
|
// No more work to do in this case.
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
fAVMService.addAspect(avmPath, aspectTypeQName);
|
|
// Invoke policy behaviors.
|
|
invokeOnUpdateNode(nodeRef);
|
|
invokeOnAddAspect(nodeRef, aspectTypeQName);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add any aspects that are mandatory for the ClassDefinition.
|
|
* @param classDef The ClassDefinition.
|
|
* @param path The path to the AVMNode.
|
|
* @param properties The in/out map of accumulated properties.
|
|
*/
|
|
private void addDefaultAspects(ClassDefinition classDef, String path,
|
|
Map<QName, Serializable> properties)
|
|
{
|
|
NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, path);
|
|
// Get mandatory aspects.
|
|
List<AspectDefinition> defaultAspectDefs = classDef.getDefaultAspects();
|
|
// add all the aspects (and there dependent aspects recursively).
|
|
for (AspectDefinition def : defaultAspectDefs)
|
|
{
|
|
invokeBeforeAddAspect(nodeRef, def.getName());
|
|
addAspect(nodeRef, def.getName(), Collections.<QName, Serializable>emptyMap());
|
|
addDefaultPropertyValues(def, properties);
|
|
invokeOnAddAspect(nodeRef, def.getName());
|
|
// recurse
|
|
addDefaultAspects(def, path, properties);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove an aspect and all related properties from a node
|
|
*
|
|
* @param nodeRef
|
|
* @param aspectTypeQName the type of aspect to remove
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
* @throws InvalidAspectException if the the aspect is unknown or if the
|
|
* aspect is mandatory for the <b>class</b> of the <b>node</b>
|
|
*/
|
|
public void removeAspect(NodeRef nodeRef, QName aspectTypeQName)
|
|
throws InvalidNodeRefException, InvalidAspectException
|
|
{
|
|
// Invoke policy behaviors.
|
|
invokeBeforeUpdateNode(nodeRef);
|
|
invokeBeforeRemoveAspect(nodeRef, aspectTypeQName);
|
|
AspectDefinition def = dictionaryService.getAspect(aspectTypeQName);
|
|
if (def == null)
|
|
{
|
|
throw new InvalidAspectException(aspectTypeQName);
|
|
}
|
|
if (isBuiltinAspect(aspectTypeQName))
|
|
{
|
|
// TODO shouldn't we be throwing some kind of exception here.
|
|
return;
|
|
}
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = (Integer)avmVersionPath[0];
|
|
if (version >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read Only Node.", nodeRef);
|
|
}
|
|
String path = (String)avmVersionPath[1];
|
|
try
|
|
{
|
|
if (fAVMService.hasAspect(-1, path, aspectTypeQName))
|
|
{
|
|
fAVMService.removeAspect(path, aspectTypeQName);
|
|
Map<QName, PropertyDefinition> propDefs = def.getProperties();
|
|
for (QName propertyName : propDefs.keySet())
|
|
{
|
|
fAVMService.deleteNodeProperty(path, propertyName);
|
|
}
|
|
}
|
|
// Invoke policy behaviors.
|
|
invokeOnUpdateNode(nodeRef);
|
|
invokeOnRemoveAspect(nodeRef, aspectTypeQName);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines if a given aspect is present on a node. Aspects may only be
|
|
* removed if they are <b>NOT</b> mandatory.
|
|
*
|
|
* @param nodeRef
|
|
* @param aspectTypeQName
|
|
* @return Returns true if the aspect has been applied to the given node,
|
|
* otherwise false
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
* @throws InvalidAspectException if the aspect reference is invalid
|
|
*/
|
|
public boolean hasAspect(NodeRef nodeRef, QName aspectTypeQName)
|
|
throws InvalidNodeRefException, InvalidAspectException
|
|
{
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = (Integer)avmVersionPath[0];
|
|
String path = (String)avmVersionPath[1];
|
|
if (isBuiltinAspect(aspectTypeQName))
|
|
{
|
|
return true;
|
|
}
|
|
try
|
|
{
|
|
return fAVMService.hasAspect(version, path, aspectTypeQName);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(nodeRef);
|
|
}
|
|
}
|
|
|
|
private static QName [] fgBuiltinAspects = new QName[] { ContentModel.ASPECT_AUDITABLE,
|
|
ContentModel.ASPECT_REFERENCEABLE };
|
|
|
|
private boolean isBuiltinAspect(QName aspectQName)
|
|
{
|
|
for (QName builtin : fgBuiltinAspects)
|
|
{
|
|
if (builtin.equals(aspectQName))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef
|
|
* @return Returns a set of all aspects applied to the node, including mandatory
|
|
* aspects
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public Set<QName> getAspects(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = (Integer)avmVersionPath[0];
|
|
String path = (String)avmVersionPath[1];
|
|
Set<QName> result = new HashSet<QName>();
|
|
// Add the builtin ones.
|
|
for (QName name : fgBuiltinAspects)
|
|
{
|
|
result.add(name);
|
|
}
|
|
try
|
|
{
|
|
List<QName> aspects = fAVMService.getAspects(version, path);
|
|
for (QName name : aspects)
|
|
{
|
|
result.add(name);
|
|
}
|
|
return result;
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes the given node.
|
|
* <p>
|
|
* All associations (both children and regular node associations)
|
|
* will be deleted, and where the given node is the primary parent,
|
|
* the children will also be cascade deleted.
|
|
*
|
|
* @param nodeRef reference to a node within a store
|
|
* @throws InvalidNodeRefException if the reference given is invalid
|
|
*/
|
|
public void deleteNode(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
// Invoke policy behaviors.
|
|
invokeBeforeDeleteNode(nodeRef);
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
if ((Integer)avmVersionPath[0] != -1)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", nodeRef);
|
|
}
|
|
String [] avmPathBase = AVMNodeConverter.SplitBase((String)avmVersionPath[1]);
|
|
if (avmPathBase[0] == null)
|
|
{
|
|
throw new InvalidNodeRefException("Cannot delete root node.", nodeRef);
|
|
}
|
|
try
|
|
{
|
|
fAVMService.removeNode(avmPathBase[0], avmPathBase[1]);
|
|
// Invoke policy behaviors.
|
|
// TODO invokeOnDeleteNode() Need to fake up ChildAssocRef.
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException("Not Found.", nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes a parent-child association between the given nodes. Both nodes must belong to the same store.
|
|
* <p>
|
|
*
|
|
* @param parentRef
|
|
* @param childRef
|
|
* @param assocTypeQName the qualified name of the association type as defined in the datadictionary
|
|
* @param qname the qualified name of the association
|
|
* @return Returns a reference to the newly created child association
|
|
* @throws InvalidNodeRefException if the parent or child nodes could not be found
|
|
* @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add
|
|
*/
|
|
public ChildAssociationRef addChild(
|
|
NodeRef parentRef,
|
|
NodeRef childRef,
|
|
QName assocTypeQName,
|
|
QName qname) throws InvalidNodeRefException
|
|
{
|
|
throw new UnsupportedOperationException("addChild: unsupported");
|
|
}
|
|
|
|
/**
|
|
* Severs all parent-child relationships between two nodes.
|
|
* <p>
|
|
* The child node will be cascade deleted if one of the associations was the
|
|
* primary association, i.e. the one with which the child node was created.
|
|
*
|
|
* @param parentRef the parent end of the association
|
|
* @param childRef the child end of the association
|
|
* @throws InvalidNodeRefException if the parent or child nodes could not be found
|
|
*/
|
|
public void removeChild(NodeRef parentRef, NodeRef childRef) throws InvalidNodeRefException
|
|
{
|
|
// Invoke policy behaviors.
|
|
// TODO Have to fake up ChildAssocRef.
|
|
Object [] parentVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef);
|
|
if ((Integer)parentVersionPath[0] >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", parentRef);
|
|
}
|
|
Object [] childVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef);
|
|
if ((Integer)childVersionPath[0] >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", childRef);
|
|
}
|
|
String parentPath = (String)parentVersionPath[1];
|
|
String childPath = (String)childVersionPath[1];
|
|
String [] childPathBase = AVMNodeConverter.SplitBase(childPath);
|
|
if (childPathBase[0] == null || !childPathBase[0].equals(parentPath))
|
|
{
|
|
throw new InvalidNodeRefException("Not a child.", childRef);
|
|
}
|
|
try
|
|
{
|
|
fAVMService.removeNode(childPathBase[0], childPathBase[1]);
|
|
// Invoke policy behaviors.
|
|
// TODO Need to fake up ChildAssocRef.
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException("Not found.", childRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef
|
|
* @return Returns all properties keyed by their qualified name
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public Map<QName, Serializable> getProperties(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
Map<QName, PropertyValue> props = null;
|
|
AVMNodeDescriptor desc = fAVMService.lookup((Integer)avmVersionPath[0],
|
|
(String)avmVersionPath[1]);
|
|
try
|
|
{
|
|
props = fAVMService.getNodeProperties((Integer)avmVersionPath[0],
|
|
(String)avmVersionPath[1]);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException("Not Found.", nodeRef);
|
|
}
|
|
Map<QName, Serializable> result = new HashMap<QName, Serializable>();
|
|
for (QName qName : props.keySet())
|
|
{
|
|
PropertyValue value = props.get(qName);
|
|
PropertyDefinition def = this.dictionaryService.getProperty(qName);
|
|
result.put(qName, value.getValue(def.getDataType().getName()));
|
|
}
|
|
// Now spoof properties that are built in.
|
|
result.put(ContentModel.PROP_CREATED, new Date(desc.getCreateDate()));
|
|
result.put(ContentModel.PROP_CREATOR, desc.getCreator());
|
|
result.put(ContentModel.PROP_MODIFIED, new Date(desc.getModDate()));
|
|
result.put(ContentModel.PROP_MODIFIER, desc.getLastModifier());
|
|
result.put(ContentModel.PROP_OWNER, desc.getOwner());
|
|
result.put(ContentModel.PROP_NAME, desc.getName());
|
|
result.put(ContentModel.PROP_NODE_UUID, "UNKNOWN");
|
|
result.put(ContentModel.PROP_NODE_DBID, new Long(desc.getId()));
|
|
result.put(ContentModel.PROP_STORE_PROTOCOL, "avm");
|
|
result.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier());
|
|
if (desc.isLayeredDirectory())
|
|
{
|
|
result.put(ContentModel.PROP_AVM_DIR_INDIRECTION,
|
|
AVMNodeConverter.ToNodeRef(-1, desc.getIndirection()));
|
|
}
|
|
if (desc.isLayeredFile())
|
|
{
|
|
result.put(ContentModel.PROP_AVM_FILE_INDIRECTION,
|
|
AVMNodeConverter.ToNodeRef(-1, desc.getIndirection()));
|
|
}
|
|
if (desc.isFile())
|
|
{
|
|
try
|
|
{
|
|
ContentData contentData = fAVMService.getContentDataForRead((Integer)avmVersionPath[0],
|
|
(String)avmVersionPath[1]);
|
|
result.put(ContentModel.PROP_CONTENT, contentData);
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
// TODO For now ignore.
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef
|
|
* @param qname the qualified name of the property
|
|
* @return Returns the value of the property, or null if not yet set
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException
|
|
{
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
if (isBuiltInProperty(qname))
|
|
{
|
|
return getBuiltInProperty(avmVersionPath, qname, nodeRef);
|
|
}
|
|
try
|
|
{
|
|
PropertyValue value = fAVMService.getNodeProperty((Integer)avmVersionPath[0],
|
|
(String)avmVersionPath[1],
|
|
qname);
|
|
if (value == null)
|
|
{
|
|
return null;
|
|
}
|
|
PropertyDefinition def = this.dictionaryService.getProperty(qname);
|
|
return value.getValue(def.getDataType().getName());
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException("Not Found.", nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A Helper to spoof built in properties.
|
|
* @param avmVersionPath The broken out version and path from a NodeRef.
|
|
* @param qName The name of the property to retrieve.
|
|
* @param nodeRef The original NodeRef (for error reporting).
|
|
* @return The property value.
|
|
*/
|
|
private Serializable getBuiltInProperty(Object [] avmVersionPath,
|
|
QName qName,
|
|
NodeRef nodeRef)
|
|
{
|
|
if (qName.equals(ContentModel.PROP_CONTENT))
|
|
{
|
|
try
|
|
{
|
|
ContentData contentData =
|
|
fAVMService.getContentDataForRead((Integer)avmVersionPath[0],
|
|
(String)avmVersionPath[1]);
|
|
return contentData;
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
// TODO This seems very wrong. Do something better
|
|
// sooner rather than later.
|
|
return null;
|
|
}
|
|
}
|
|
AVMNodeDescriptor desc = fAVMService.lookup((Integer)avmVersionPath[0],
|
|
(String)avmVersionPath[1]);
|
|
if (desc == null)
|
|
{
|
|
throw new InvalidNodeRefException("Not Found.", nodeRef);
|
|
}
|
|
if (qName.equals(ContentModel.PROP_CREATED))
|
|
{
|
|
return new Date(desc.getCreateDate());
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_CREATOR))
|
|
{
|
|
return desc.getCreator();
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_MODIFIED))
|
|
{
|
|
return new Date(desc.getModDate());
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_MODIFIER))
|
|
{
|
|
return desc.getLastModifier();
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_OWNER))
|
|
{
|
|
return desc.getOwner();
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_NAME))
|
|
{
|
|
return desc.getName();
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_NODE_UUID))
|
|
{
|
|
return "UNKNOWN";
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_NODE_DBID))
|
|
{
|
|
return new Long(desc.getId());
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_STORE_PROTOCOL))
|
|
{
|
|
return "avm";
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_STORE_IDENTIFIER))
|
|
{
|
|
return nodeRef.getStoreRef().getIdentifier();
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_AVM_DIR_INDIRECTION))
|
|
{
|
|
if (desc.isLayeredDirectory())
|
|
{
|
|
return AVMNodeConverter.ToNodeRef(-1, desc.getIndirection());
|
|
}
|
|
return null;
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_AVM_FILE_INDIRECTION))
|
|
{
|
|
if (desc.isLayeredFile())
|
|
{
|
|
return AVMNodeConverter.ToNodeRef(-1, desc.getIndirection());
|
|
}
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
fgLogger.error("Invalid Built In Property: " + qName);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the values of all properties to be an <code>Serializable</code> instances.
|
|
* The properties given must still fulfill the requirements of the class and
|
|
* aspects relevant to the node.
|
|
* <p>
|
|
* <b>NOTE:</b> Null values <u>are</u> allowed.
|
|
*
|
|
* @param nodeRef
|
|
* @param properties all the properties of the node keyed by their qualified names
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public void setProperties(NodeRef nodeRef, Map<QName, Serializable> properties) throws InvalidNodeRefException
|
|
{
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
if ((Integer)avmVersionPath[0] >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", nodeRef);
|
|
}
|
|
// TODO Not sure this try block is necessary.
|
|
try
|
|
{
|
|
// Invoke policy behaviors.
|
|
invokeBeforeUpdateNode(nodeRef);
|
|
fAVMService.deleteNodeProperties((String)avmVersionPath[1]);
|
|
Map<QName, PropertyValue> values = new HashMap<QName, PropertyValue>();
|
|
for (QName qName : properties.keySet())
|
|
{
|
|
// For AVM nodes is in place.
|
|
if (isBuiltInProperty(qName))
|
|
{
|
|
if (qName.equals(ContentModel.PROP_CONTENT))
|
|
{
|
|
AVMNodeDescriptor desc = fAVMService.lookup(-1, (String)avmVersionPath[1]);
|
|
if (desc == null)
|
|
{
|
|
throw new InvalidNodeRefException("Not Found.", nodeRef);
|
|
}
|
|
if (desc.isPlainFile())
|
|
{
|
|
fAVMService.setContentData((String)avmVersionPath[1],
|
|
(ContentData)properties.get(qName));
|
|
}
|
|
}
|
|
}
|
|
values.put(qName, new PropertyValue(null, properties.get(qName)));
|
|
}
|
|
fAVMService.setNodeProperties((String)avmVersionPath[1], values);
|
|
// Invoke policy behaviors.
|
|
invokeOnUpdateNode(nodeRef);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException("Not Found.", nodeRef);
|
|
}
|
|
}
|
|
|
|
static QName [] fgBuiltinProperties = new QName []
|
|
{
|
|
ContentModel.PROP_CREATED,
|
|
ContentModel.PROP_CREATOR,
|
|
ContentModel.PROP_MODIFIED,
|
|
ContentModel.PROP_MODIFIER,
|
|
ContentModel.PROP_OWNER,
|
|
ContentModel.PROP_CONTENT,
|
|
ContentModel.PROP_NAME,
|
|
ContentModel.PROP_NODE_UUID,
|
|
ContentModel.PROP_NODE_DBID,
|
|
ContentModel.PROP_STORE_PROTOCOL,
|
|
ContentModel.PROP_STORE_IDENTIFIER,
|
|
ContentModel.PROP_AVM_FILE_INDIRECTION,
|
|
ContentModel.PROP_AVM_DIR_INDIRECTION
|
|
};
|
|
|
|
/**
|
|
* Helper to distinguish built-in from generic properties.
|
|
* @param qName The name of the property to check.
|
|
* @return Whether <code>qName</code> is a built-in propety.
|
|
*/
|
|
private boolean isBuiltInProperty(QName qName)
|
|
{
|
|
for (QName name : fgBuiltinProperties)
|
|
{
|
|
if (name.equals(qName))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of a property to be any <code>Serializable</code> instance.
|
|
* To remove a property value, use {@link #getProperties(NodeRef)}, remove the
|
|
* value and call {@link #setProperties(NodeRef, Map)}.
|
|
* <p>
|
|
* <b>NOTE:</b> Null values <u>are</u> allowed.
|
|
*
|
|
* @param nodeRef
|
|
* @param qname the fully qualified name of the property
|
|
* @param propertyValue the value of the property - never null
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException
|
|
{
|
|
// Invoke policy behaviors.
|
|
invokeBeforeUpdateNode(nodeRef);
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
if ((Integer)avmVersionPath[0] >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", nodeRef);
|
|
}
|
|
// TODO Just until we can set built in properties on AVM Nodes.
|
|
if (isBuiltInProperty(qname))
|
|
{
|
|
if (qname.equals(ContentModel.PROP_CONTENT))
|
|
{
|
|
try
|
|
{
|
|
fAVMService.setContentData((String)avmVersionPath[1], (ContentData)value);
|
|
}
|
|
catch (ClassCastException e)
|
|
{
|
|
throw new AVMException("Invalid ContentData.");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
fAVMService.setNodeProperty((String)avmVersionPath[1], qname, new PropertyValue(null, value));
|
|
// Invoke policy behaviors.
|
|
invokeOnUpdateNode(nodeRef);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException("Not Found.", nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef the child node
|
|
* @return Returns a list of all parent-child associations that exist where the given
|
|
* node is the child
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see #getParentAssocs(NodeRef, QNamePattern, QNamePattern)
|
|
*/
|
|
public List<ChildAssociationRef> getParentAssocs(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
// TODO OK, for now we'll simply return the single parent that corresponds
|
|
// to the path stuffed in the NodeRef.
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
String path = (String)avmVersionPath[1];
|
|
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
|
|
String [] splitPath = AVMNodeConverter.SplitBase(path);
|
|
if (splitPath[0] == null)
|
|
{
|
|
return result;
|
|
}
|
|
result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
|
|
AVMNodeConverter.ToNodeRef((Integer)avmVersionPath[0],
|
|
splitPath[0]),
|
|
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
|
splitPath[1]),
|
|
nodeRef,
|
|
true,
|
|
-1));
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets all parent associations where the pattern of the association qualified
|
|
* name is a match
|
|
* <p>
|
|
* The resultant list is ordered by (a) explicit index and (b) association creation time.
|
|
*
|
|
* @param nodeRef the child node
|
|
* @param typeQNamePattern the pattern that the type qualified name of the association must match
|
|
* @param qnamePattern the pattern that the qnames of the assocs must match
|
|
* @return Returns a list of all parent-child associations that exist where the given
|
|
* node is the child
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see ChildAssociationRef#getNthSibling()
|
|
* @see #setChildAssociationIndex(ChildAssociationRef, int)
|
|
* @see QName
|
|
* @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL
|
|
*/
|
|
public List<ChildAssociationRef> getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern)
|
|
throws InvalidNodeRefException
|
|
{
|
|
if (!typeQNamePattern.isMatch(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
return new ArrayList<ChildAssociationRef>();
|
|
}
|
|
List<ChildAssociationRef> result = getParentAssocs(nodeRef);
|
|
if (result.size() == 0)
|
|
{
|
|
return result;
|
|
}
|
|
if (qnamePattern.isMatch(result.get(0).getQName()))
|
|
{
|
|
return result;
|
|
}
|
|
return new ArrayList<ChildAssociationRef>();
|
|
}
|
|
|
|
/**
|
|
* Get all child associations of the given node.
|
|
* <p>
|
|
* The resultant list is ordered by (a) explicit index and (b) association creation time.
|
|
*
|
|
* @param nodeRef the parent node - usually a <b>container</b>
|
|
* @return Returns a collection of <code>ChildAssocRef</code> instances. If the
|
|
* node is not a <b>container</b> then the result will be empty.
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern)
|
|
* @see #setChildAssociationIndex(ChildAssociationRef, int)
|
|
* @see ChildAssociationRef#getNthSibling()
|
|
*/
|
|
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = (Integer)avmVersionPath[0];
|
|
String path = (String)avmVersionPath[1];
|
|
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
|
|
SortedMap<String, AVMNodeDescriptor> children = null;
|
|
try
|
|
{
|
|
children =
|
|
fAVMService.getDirectoryListing(version,
|
|
path);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
return result;
|
|
}
|
|
for (String name : children.keySet())
|
|
{
|
|
result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
|
|
nodeRef,
|
|
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
|
name),
|
|
AVMNodeConverter.ToNodeRef(
|
|
version,
|
|
AVMNodeConverter.ExtendAVMPath(path, name)),
|
|
true,
|
|
-1));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets all child associations where the pattern of the association qualified
|
|
* name is a match.
|
|
*
|
|
* @param nodeRef the parent node - usually a <b>container</b>
|
|
* @param typeQNamePattern the pattern that the type qualified name of the association must match
|
|
* @param qnamePattern the pattern that the qnames of the assocs must match
|
|
* @return Returns a list of <code>ChildAssocRef</code> instances. If the
|
|
* node is not a <b>container</b> then the result will be empty.
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see QName
|
|
* @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL
|
|
*/
|
|
public List<ChildAssociationRef> getChildAssocs(
|
|
NodeRef nodeRef,
|
|
QNamePattern typeQNamePattern,
|
|
QNamePattern qnamePattern)
|
|
throws InvalidNodeRefException
|
|
{
|
|
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
|
|
if (!typeQNamePattern.isMatch(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
return result;
|
|
}
|
|
List<ChildAssociationRef> all = getChildAssocs(nodeRef);
|
|
for (ChildAssociationRef child : all)
|
|
{
|
|
if (!qnamePattern.isMatch(child.getQName()))
|
|
{
|
|
continue;
|
|
}
|
|
result.add(child);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get a child NodeRef by name.
|
|
* @param nodeRef The parent node.
|
|
* @param assocTypeQName The type of the Child Association.
|
|
* @param childName The name of the child to get.
|
|
*/
|
|
public NodeRef getChildByName(NodeRef nodeRef, QName assocTypeQName, String childName)
|
|
{
|
|
if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
return null;
|
|
}
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
try
|
|
{
|
|
AVMNodeDescriptor child = fAVMService.lookup((Integer)avmVersionPath[0],
|
|
(String)avmVersionPath[1]);
|
|
if (child == null)
|
|
{
|
|
return null;
|
|
}
|
|
return AVMNodeConverter.ToNodeRef((Integer)avmVersionPath[0],
|
|
child.getPath());
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetches the primary parent-child relationship.
|
|
* <p>
|
|
* For a root node, the parent node reference will be null.
|
|
*
|
|
* @param nodeRef
|
|
* @return Returns the primary parent-child association of the node
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public ChildAssociationRef getPrimaryParent(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
List<ChildAssociationRef> parents = getParentAssocs(nodeRef);
|
|
if (parents.size() == 0)
|
|
{
|
|
return new ChildAssociationRef(null, null, null, nodeRef);
|
|
}
|
|
return parents.get(0);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param sourceRef a reference to a <b>real</b> node
|
|
* @param targetRef a reference to a node
|
|
* @param assocTypeQName the qualified name of the association type
|
|
* @return Returns a reference to the new association
|
|
* @throws InvalidNodeRefException if either of the nodes could not be found
|
|
* @throws AssociationExistsException
|
|
*/
|
|
public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName)
|
|
throws InvalidNodeRefException, AssociationExistsException
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support arbitrary associations.");
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param sourceRef the associaton source node
|
|
* @param targetRef the association target node
|
|
* @param assocTypeQName the qualified name of the association type
|
|
* @throws InvalidNodeRefException if either of the nodes could not be found
|
|
*/
|
|
public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName)
|
|
throws InvalidNodeRefException
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support arbitrary associations.");
|
|
}
|
|
|
|
/**
|
|
* Fetches all associations <i>from</i> the given source where the associations'
|
|
* qualified names match the pattern provided.
|
|
*
|
|
* @param sourceRef the association source
|
|
* @param qnamePattern the association qname pattern to match against
|
|
* @return Returns a list of <code>NodeAssocRef</code> instances for which the
|
|
* given node is a source
|
|
* @throws InvalidNodeRefException if the source node could not be found
|
|
*
|
|
* @see QName
|
|
* @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL
|
|
*/
|
|
public List<AssociationRef> getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern)
|
|
throws InvalidNodeRefException
|
|
{
|
|
return new ArrayList<AssociationRef>();
|
|
}
|
|
|
|
/**
|
|
* Fetches all associations <i>to</i> the given target where the associations'
|
|
* qualified names match the pattern provided.
|
|
*
|
|
* @param targetRef the association target
|
|
* @param qnamePattern the association qname pattern to match against
|
|
* @return Returns a list of <code>NodeAssocRef</code> instances for which the
|
|
* given node is a target
|
|
* @throws InvalidNodeRefException
|
|
*
|
|
* @see QName
|
|
* @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL
|
|
*/
|
|
public List<AssociationRef> getSourceAssocs(NodeRef targetRef, QNamePattern qnamePattern)
|
|
throws InvalidNodeRefException
|
|
{
|
|
return new ArrayList<AssociationRef>();
|
|
}
|
|
|
|
/**
|
|
* The root node has an entry in the path(s) returned. For this reason, there
|
|
* will always be <b>at least one</b> path element in the returned path(s).
|
|
* The first element will have a null parent reference and qname.
|
|
*
|
|
* @param nodeRef
|
|
* @return Returns the path to the node along the primary node path
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see #getPaths(NodeRef, boolean)
|
|
*/
|
|
public Path getPath(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
// TODO Review later. This may be wrong.
|
|
Path path = new Path();
|
|
Object [] avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = (Integer)avmVersionPath[0];
|
|
String currPath = (String)avmVersionPath[1];
|
|
while (!currPath.endsWith("/"))
|
|
{
|
|
String [] splitPath = AVMNodeConverter.SplitBase(currPath);
|
|
String parentPath = splitPath[0];
|
|
String name = splitPath[1];
|
|
ChildAssociationRef caRef =
|
|
new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
|
|
AVMNodeConverter.ToNodeRef(version, parentPath),
|
|
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
|
name),
|
|
AVMNodeConverter.ToNodeRef(version, currPath),
|
|
true,
|
|
-1);
|
|
path.prepend(new Path.ChildAssocElement(caRef));
|
|
currPath = parentPath;
|
|
}
|
|
ChildAssociationRef caRef = new ChildAssociationRef(null, null, null,
|
|
AVMNodeConverter.ToNodeRef(version,
|
|
currPath));
|
|
path.prepend(new Path.ChildAssocElement(caRef));
|
|
return path;
|
|
}
|
|
|
|
/**
|
|
* The root node has an entry in the path(s) returned. For this reason, there
|
|
* will always be <b>at least one</b> path element in the returned path(s).
|
|
* The first element will have a null parent reference and qname.
|
|
*
|
|
* @param nodeRef
|
|
* @param primaryOnly true if only the primary path must be retrieved. If true, the
|
|
* result will have exactly one entry.
|
|
* @return Returns a List of all possible paths to the given node
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public List<Path> getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException
|
|
{
|
|
List<Path> result = new ArrayList<Path>();
|
|
result.add(getPath(nodeRef));
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get the node where archived items will have gone when deleted from the given store.
|
|
*
|
|
* @param storeRef the store that items were deleted from
|
|
* @return Returns the archive node parent
|
|
*/
|
|
public NodeRef getStoreArchiveNode(StoreRef storeRef)
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support this operation.");
|
|
}
|
|
|
|
/**
|
|
* Restore an individual node (along with its sub-tree nodes) to the target location.
|
|
* The archived node must have the {@link org.alfresco.model.ContentModel#ASPECT_ARCHIVED archived aspect}
|
|
* set against it.
|
|
*
|
|
* @param archivedNodeRef the archived node
|
|
* @param destinationParentNodeRef the parent to move the node into
|
|
* or <tt>null</tt> to use the original
|
|
* @param assocTypeQName the primary association type name to use in the new location
|
|
* or <tt>null</tt> to use the original
|
|
* @param assocQName the primary association name to use in the new location
|
|
* or <tt>null</tt> to use the original
|
|
* @return Returns the reference to the newly created node
|
|
*/
|
|
public NodeRef restoreNode(
|
|
NodeRef archivedNodeRef,
|
|
NodeRef destinationParentNodeRef,
|
|
QName assocTypeQName,
|
|
QName assocQName)
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support this operation.");
|
|
}
|
|
}
|