2006-05-10 18:01:58 +00:00

1239 lines
50 KiB
Java

/*
* Copyright (C) 2005 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.jcr.item;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.jcr.AccessDeniedException;
import javax.jcr.InvalidItemStateException;
import javax.jcr.Item;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.ItemVisitor;
import javax.jcr.MergeException;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.jcr.lock.Lock;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
import javax.jcr.version.VersionHistory;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.jcr.api.JCRNodeRef;
import org.alfresco.jcr.dictionary.ClassMap;
import org.alfresco.jcr.dictionary.NodeDefinitionImpl;
import org.alfresco.jcr.dictionary.NodeTypeImpl;
import org.alfresco.jcr.item.property.PropertyResolver;
import org.alfresco.jcr.session.SessionImpl;
import org.alfresco.jcr.util.JCRProxyFactory;
import org.alfresco.jcr.version.VersionHistoryImpl;
import org.alfresco.jcr.version.VersionImpl;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.lock.LockType;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.Path.Element;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.ParameterCheck;
/**
* Alfresco Implementation of a JCR Node
*
* @author David Caruana
*/
public class NodeImpl extends ItemImpl implements Node
{
/** Node Reference to wrap */
private NodeRef nodeRef;
/** Proxy */
private Node proxy = null;
/**
* Construct
*
* @param context session context
* @param nodeRef node reference to wrap
*/
public NodeImpl(SessionImpl context, NodeRef nodeRef)
{
super(context);
this.nodeRef = nodeRef;
}
/**
* Get Node Proxy
*
* @param nodeImpl
* @return
*/
@Override
public Node getProxy()
{
if (proxy == null)
{
proxy = (Node)JCRProxyFactory.create(this, Node.class, session);
}
return proxy;
}
/* (non-Javadoc)
* @see javax.jcr.Node#addNode(java.lang.String)
*/
public Node addNode(String relPath) throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException, RepositoryException
{
return addNode(relPath, null);
}
/* (non-Javadoc)
* @see javax.jcr.Node#addNode(java.lang.String, java.lang.String)
*/
public Node addNode(String relPath, String primaryNodeTypeName) throws ItemExistsException, PathNotFoundException, NoSuchNodeTypeException, LockException, VersionException, ConstraintViolationException, RepositoryException
{
ParameterCheck.mandatoryString("relPath", relPath);
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
DictionaryService dictionaryService = session.getRepositoryImpl().getServiceRegistry().getDictionaryService();
// Determine parent node reference and new node name
Path path = new JCRPath(session.getNamespaceResolver(), relPath).getPath();
QName nodeName = null;
NodeRef parentRef = null;
if (path.size() == 1)
{
parentRef = nodeRef;
nodeName = ((JCRPath.SimpleElement)path.get(0)).getQName();
}
else
{
Path parentPath = path.subPath(path.size() -2);
parentRef = ItemResolver.getNodeRef(session, nodeRef, parentPath.toPrefixString(session.getNamespaceResolver()));
if (parentRef == null)
{
throw new PathNotFoundException("Path '" + relPath + "' does not exist from node " + nodeRef);
}
nodeName = ((JCRPath.SimpleElement)path.get(path.size() -1)).getQName();
}
// Check for invalid node name
// TODO: Replace with proper name validation
if (nodeName.getLocalName().indexOf('[') != -1 || nodeName.getLocalName().indexOf(']') != -1)
{
throw new RepositoryException("Node name '" + nodeName + "' is invalid");
}
// Determine child association to add node under
ChildAssociationDefinition childAssocDef = null;
QName nodeType = null;
if (primaryNodeTypeName == null || primaryNodeTypeName.length() == 0)
{
childAssocDef = getDefaultChildAssocDefForParent(nodeService, dictionaryService, parentRef);
nodeType = childAssocDef.getTargetClass().getName();
}
else
{
nodeType = QName.createQName(primaryNodeTypeName, session.getNamespaceResolver());
childAssocDef = getNodeTypeChildAssocDefForParent(nodeService, dictionaryService, parentRef, nodeType);
}
// Create node
// Note: Integrity exception will be thrown when the node is saved
ChildAssociationRef childRef = nodeService.createNode(parentRef, childAssocDef.getName(), nodeName, nodeType);
NodeImpl nodeImpl = new NodeImpl(session, childRef.getChildRef());
return nodeImpl.getProxy();
}
/**
* Get the default child association definition for the specified node
*
* @param nodeService node service
* @param dictionaryService dictionary service
* @param nodeRef node reference
* @return child association definition
*/
private ChildAssociationDefinition getDefaultChildAssocDefForParent(NodeService nodeService, DictionaryService dictionaryService, NodeRef nodeRef)
{
QName type = nodeService.getType(nodeRef);
Set<QName> aspects = nodeService.getAspects(nodeRef);
ClassDefinition classDef = dictionaryService.getAnonymousType(type, aspects);
Map<QName, ChildAssociationDefinition> childAssocs = classDef.getChildAssociations();
if (childAssocs.size() != 1)
{
throw new AlfrescoRuntimeException("Cannot determine node type for child within parent " + nodeRef);
}
ChildAssociationDefinition childAssocDef = childAssocs.values().iterator().next();
return childAssocDef;
}
/**
* Get the child association definition whose target matches the specified node type for the specified node
*
* @param nodeService node service
* @param dictionaryService dictionary service
* @param nodeRef node reference
* @param nodeType node type to find child association definition for
* @return child association definition
*/
private ChildAssociationDefinition getNodeTypeChildAssocDefForParent(NodeService nodeService, DictionaryService dictionaryService, NodeRef nodeRef, QName nodeType)
{
ChildAssociationDefinition nodeTypeChildAssocDef = null;
QName type = nodeService.getType(nodeRef);
Set<QName> aspects = nodeService.getAspects(nodeRef);
ClassDefinition classDef = dictionaryService.getAnonymousType(type, aspects);
Map<QName, ChildAssociationDefinition> childAssocs = classDef.getChildAssociations();
for (ChildAssociationDefinition childAssocDef : childAssocs.values())
{
QName targetClass = childAssocDef.getTargetClass().getName();
if (dictionaryService.isSubClass(nodeType, targetClass))
{
if (nodeTypeChildAssocDef != null)
{
throw new AlfrescoRuntimeException("Cannot determine child association for node type '" + nodeType + " within parent " + nodeRef);
}
nodeTypeChildAssocDef = childAssocDef;
}
}
if (nodeTypeChildAssocDef == null)
{
throw new AlfrescoRuntimeException("Cannot determine child association for node type '" + nodeType + " within parent " + nodeRef);
}
return nodeTypeChildAssocDef;
}
/* (non-Javadoc)
* @see javax.jcr.Item#remove()
*/
public void remove() throws VersionException, LockException, ConstraintViolationException, RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
// Note: remove the primary child association, therefore forcing a delete of the node (including any secondary child
// associations)
ChildAssociationRef assocRef = nodeService.getPrimaryParent(nodeRef);
NodeRef parentRef = assocRef.getParentRef();
if (parentRef == null)
{
throw new ConstraintViolationException("Cannot remove the root node");
}
nodeService.removeChild(parentRef, nodeRef);
}
/* (non-Javadoc)
* @see javax.jcr.Node#orderBefore(java.lang.String, java.lang.String)
*/
public void orderBefore(String srcChildRelPath, String destChildRelPath) throws UnsupportedRepositoryOperationException, VersionException, ConstraintViolationException, ItemNotFoundException, LockException, RepositoryException
{
throw new UnsupportedRepositoryOperationException();
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Value)
*/
public Property setProperty(String name, Value value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(value, -1);
return (value == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Value, int)
*/
public Property setProperty(String name, Value value, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(value, type);
return (value == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Value[])
*/
public Property setProperty(String name, Value[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(values, -1);
return (values == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Value[], int)
*/
public Property setProperty(String name, Value[] values, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(values, type);
return (values == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, java.lang.String[])
*/
public Property setProperty(String name, String[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(values, -1);
return (values == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, java.lang.String[], int)
*/
public Property setProperty(String name, String[] values, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(values, type);
return (values == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, java.lang.String)
*/
public Property setProperty(String name, String value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(value, -1);
return (value == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, java.lang.String, int)
*/
public Property setProperty(String name, String value, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(value, type);
return (value == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, java.io.InputStream)
*/
public Property setProperty(String name, InputStream value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(value, -1);
return (value == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, boolean)
*/
public Property setProperty(String name, boolean value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(value, -1);
return property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, double)
*/
public Property setProperty(String name, double value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(value, -1);
return property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, long)
*/
public Property setProperty(String name, long value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue(value, -1);
return property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, java.util.Calendar)
*/
public Property setProperty(String name, Calendar value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue((value == null) ? null : value.getTime(), -1);
return (value == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Node)
*/
public Property setProperty(String name, Node value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException
{
QName propertyName = QName.createQName(name, session.getNamespaceResolver());
PropertyImpl property = new PropertyImpl(this, propertyName);
property.setPropertyValue((value == null) ? null : JCRNodeRef.getNodeRef(value), -1);
return (value == null ) ? null : property;
}
/* (non-Javadoc)
* @see javax.jcr.Node#getNode(java.lang.String)
*/
public Node getNode(String relPath) throws PathNotFoundException, RepositoryException
{
NodeImpl nodeImpl = ItemResolver.findNode(session, nodeRef, relPath);
return nodeImpl.getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Node#getNodes()
*/
public NodeIterator getNodes() throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(nodeRef);
NodeIterator iterator = new ChildAssocNodeIteratorImpl(session, childAssocs);
return iterator;
}
/* (non-Javadoc)
* @see javax.jcr.Node#getNodes(java.lang.String)
*/
public NodeIterator getNodes(String namePattern) throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
JCRPatternMatch match = new JCRPatternMatch(namePattern, session.getNamespaceResolver());
List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(nodeRef, RegexQNamePattern.MATCH_ALL, match);
NodeIterator iterator = new ChildAssocNodeIteratorImpl(session, childAssocs);
return iterator;
}
/* (non-Javadoc)
* @see javax.jcr.Node#getProperty(java.lang.String)
*/
public Property getProperty(String relPath) throws PathNotFoundException, RepositoryException
{
JCRPath jcrPath = new JCRPath(session.getNamespaceResolver(), relPath);
Path path = jcrPath.getPath();
if (path.size() == 1)
{
QName propertyName = ((JCRPath.SimpleElement)path.get(0)).getQName();
return PropertyResolver.createProperty(this, propertyName).getProxy();
}
ItemImpl itemImpl = ItemResolver.findItem(session, nodeRef, relPath);
if (itemImpl == null || !(itemImpl instanceof PropertyImpl))
{
throw new PathNotFoundException("Property path " + relPath + " not found from node " + nodeRef);
}
return ((PropertyImpl)itemImpl).getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Node#getProperties()
*/
public PropertyIterator getProperties() throws RepositoryException
{
List<PropertyImpl> properties = PropertyResolver.createProperties(this, null);
PropertyIterator iterator = new PropertyListIterator(properties);
return iterator;
}
/* (non-Javadoc)
* @see javax.jcr.Node#getProperties(java.lang.String)
*/
public PropertyIterator getProperties(String namePattern) throws RepositoryException
{
JCRPatternMatch match = new JCRPatternMatch(namePattern, session.getNamespaceResolver());
List<PropertyImpl> properties = PropertyResolver.createProperties(this, match);
PropertyIterator iterator = new PropertyListIterator(properties);
return iterator;
}
/* (non-Javadoc)
* @see javax.jcr.Node#getPrimaryItem()
*/
public Item getPrimaryItem() throws ItemNotFoundException, RepositoryException
{
// Note: Alfresco does not support the notion of primary item
throw new ItemNotFoundException();
}
/* (non-Javadoc)
* @see javax.jcr.Node#getUUID()
*/
public String getUUID() throws UnsupportedRepositoryOperationException, RepositoryException
{
return nodeRef.getId();
}
/* (non-Javadoc)
* @see javax.jcr.Node#getIndex()
*/
public int getIndex() throws RepositoryException
{
int index = 1;
String name = getName();
if (name != null)
{
// TODO: Look at more efficient approach
SearchService searchService = session.getRepositoryImpl().getServiceRegistry().getSearchService();
List<NodeRef> siblings = searchService.selectNodes(nodeRef, "../" + name, null, session.getNamespaceResolver(), false);
for (NodeRef sibling : siblings)
{
if (sibling.equals(nodeRef))
{
break;
}
index++;
}
}
return index;
}
/* (non-Javadoc)
* @see javax.jcr.Node#getReferences()
*/
public PropertyIterator getReferences() throws RepositoryException
{
// Note: Lookup for references not supported for now
return new PropertyListIterator(new ArrayList<PropertyImpl>());
}
/* (non-Javadoc)
* @see javax.jcr.Node#hasNode(java.lang.String)
*/
public boolean hasNode(String relPath) throws RepositoryException
{
return ItemResolver.nodeExists(session, nodeRef, relPath);
}
/* (non-Javadoc)
* @see javax.jcr.Node#hasProperty(java.lang.String)
*/
public boolean hasProperty(String relPath) throws RepositoryException
{
JCRPath jcrPath = new JCRPath(session.getNamespaceResolver(), relPath);
Path path = jcrPath.getPath();
if (path.size() == 1)
{
QName propertyName = ((JCRPath.SimpleElement)path.get(0)).getQName();
return PropertyResolver.hasProperty(this, propertyName);
}
return ItemResolver.itemExists(session, nodeRef, relPath);
}
/* (non-Javadoc)
* @see javax.jcr.Node#hasNodes()
*/
public boolean hasNodes() throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(nodeRef);
return childAssocs.size() > 0;
}
/* (non-Javadoc)
* @see javax.jcr.Node#hasProperties()
*/
public boolean hasProperties() throws RepositoryException
{
// Note: nt:base has a mandatory primaryType property for which we don't have security access control
return true;
}
/* (non-Javadoc)
* @see javax.jcr.Node#getPrimaryNodeType()
*/
public NodeType getPrimaryNodeType() throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
QName type = nodeService.getType(nodeRef);
return session.getTypeManager().getNodeTypeImpl(type);
}
/* (non-Javadoc)
* @see javax.jcr.Node#getMixinNodeTypes()
*/
public NodeType[] getMixinNodeTypes() throws RepositoryException
{
// Add aspects defined by node
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
Set<QName> aspects = nodeService.getAspects(nodeRef);
NodeType[] nodeTypes = new NodeType[aspects.size() + 1];
int i = 0;
for (QName aspect : aspects)
{
nodeTypes[i++] = session.getTypeManager().getNodeTypeImpl(aspect);
QName mixin = ClassMap.convertClassToType(aspect);
if (mixin != null)
{
nodeTypes[i++] = session.getTypeManager().getNodeTypeImpl(mixin);
}
}
return nodeTypes;
}
/* (non-Javadoc)
* @see javax.jcr.Node#isNodeType(java.lang.String)
*/
public boolean isNodeType(String nodeTypeName) throws RepositoryException
{
QName nodeType = QName.createQName(nodeTypeName, session.getNamespaceResolver());
// is it one of standard types
if (nodeType.equals(NodeTypeImpl.MIX_REFERENCEABLE) || nodeType.equals(NodeTypeImpl.NT_BASE))
{
return true;
}
// map JCR mixins to Alfresco mixins
QName nodeClass = ClassMap.convertTypeToClass(nodeType);
if (nodeClass == null)
{
nodeClass = nodeType;
}
// determine via class hierarchy
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
DictionaryService dictionaryService = session.getRepositoryImpl().getServiceRegistry().getDictionaryService();
// first, check the type
QName type = nodeService.getType(nodeRef);
if (dictionaryService.isSubClass(nodeClass, type))
{
return true;
}
// second, check the aspects
Set<QName> aspects = nodeService.getAspects(nodeRef);
for (QName aspect : aspects)
{
if (dictionaryService.isSubClass(nodeClass, aspect))
{
return true;
}
}
// no, its definitely not of the specified type
return false;
}
/* (non-Javadoc)
* @see javax.jcr.Node#addMixin(java.lang.String)
*/
public void addMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException
{
// map JCR mixins to Alfresco mixins
QName mixin = QName.createQName(mixinName, session.getNamespaceResolver());
QName aspect = ClassMap.convertTypeToClass(mixin);
if (aspect == null)
{
aspect = mixin;
}
// retrieve aspect definition
DictionaryService dictionaryService = session.getRepositoryImpl().getServiceRegistry().getDictionaryService();
AspectDefinition aspectDef = dictionaryService.getAspect(aspect);
if (aspectDef == null)
{
throw new NoSuchNodeTypeException("Unknown mixin name '" + mixinName + "'");
}
// apply aspect
ClassMap.AddMixin addMixin = ClassMap.getAddMixin(aspect);
Map<QName, Serializable> initialProperties = addMixin.preAddMixin(session, nodeRef);
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
nodeService.addAspect(nodeRef, aspect, initialProperties);
addMixin.postAddMixin(session, nodeRef);
}
/* (non-Javadoc)
* @see javax.jcr.Node#removeMixin(java.lang.String)
*/
public void removeMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException
{
// map JCR mixins to Alfresco mixins
QName mixin = QName.createQName(mixinName, session.getNamespaceResolver());
QName aspect = ClassMap.convertTypeToClass(mixin);
if (aspect == null)
{
aspect = mixin;
}
// retrieve aspect definition
DictionaryService dictionaryService = session.getRepositoryImpl().getServiceRegistry().getDictionaryService();
AspectDefinition aspectDef = dictionaryService.getAspect(aspect);
if (aspectDef == null)
{
throw new NoSuchNodeTypeException("Unknown mixin name '" + mixinName + "'");
}
// check the node actually has the mixin
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
Set<QName> nodeAspects = nodeService.getAspects(nodeRef);
if (!nodeAspects.contains(aspect))
{
throw new NoSuchNodeTypeException("Node " + nodeRef.getId() + " does not have the mixin " + mixin);
}
// remove aspect
ClassMap.RemoveMixin removeMixin = ClassMap.getRemoveMixin(aspect);
removeMixin.preRemoveMixin(session, nodeRef);
nodeService.removeAspect(nodeRef, aspect);
removeMixin.postRemoveMixin(session, nodeRef);
}
/* (non-Javadoc)
* @see javax.jcr.Node#canAddMixin(java.lang.String)
*/
public boolean canAddMixin(String mixinName) throws NoSuchNodeTypeException, RepositoryException
{
// map JCR mixins to Alfresco mixins
QName mixin = QName.createQName(mixinName, session.getNamespaceResolver());
QName aspect = ClassMap.convertTypeToClass(mixin);
if (aspect == null)
{
aspect = mixin;
}
// retrieve aspect definition
DictionaryService dictionaryService = session.getRepositoryImpl().getServiceRegistry().getDictionaryService();
AspectDefinition aspectDef = dictionaryService.getAspect(aspect);
if (aspectDef == null)
{
throw new NoSuchNodeTypeException("Unknown mixin name '" + mixinName + "'");
}
// TODO: check for write permission
// check for locked node
LockService lockService = session.getRepositoryImpl().getServiceRegistry().getLockService();
LockStatus lockStatus = lockService.getLockStatus(nodeRef);
if (lockStatus == LockStatus.LOCKED)
{
return false;
}
// mixin addition is allowed
return true;
}
/* (non-Javadoc)
* @see javax.jcr.Node#getDefinition()
*/
public NodeDefinition getDefinition() throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
DictionaryService dictionaryService = session.getRepositoryImpl().getServiceRegistry().getDictionaryService();
ChildAssociationRef childAssocRef = nodeService.getPrimaryParent(this.nodeRef);
ChildAssociationDefinition childAssocDef = (ChildAssociationDefinition)dictionaryService.getAssociation(childAssocRef.getTypeQName());
NodeDefinition nodeDef = new NodeDefinitionImpl(session.getTypeManager(), childAssocDef);
return nodeDef;
}
/* (non-Javadoc)
* @see javax.jcr.Node#checkin()
*/
public Version checkin() throws VersionException, UnsupportedRepositoryOperationException, InvalidItemStateException, LockException, RepositoryException
{
// check this node is versionable
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE))
{
throw new UnsupportedRepositoryOperationException("Node " + nodeRef + " is not versionable");
}
Version version = null;
if (!isCheckedOut())
{
// return current version
version = getBaseVersion();
}
else
{
// create a new version snapshot
VersionService versionService = session.getRepositoryImpl().getServiceRegistry().getVersionService();
org.alfresco.service.cmr.version.Version versionNode = versionService.createVersion(nodeRef, null);
org.alfresco.service.cmr.version.VersionHistory versionHistory = versionService.getVersionHistory(nodeRef);
version = new VersionImpl(new VersionHistoryImpl(session, versionHistory), versionNode).getProxy();
// set to 'read only'
LockService lockService = session.getRepositoryImpl().getServiceRegistry().getLockService();
lockService.lock(nodeRef, LockType.READ_ONLY_LOCK);
}
return version;
}
/* (non-Javadoc)
* @see javax.jcr.Node#checkout()
*/
public void checkout() throws UnsupportedRepositoryOperationException, LockException, RepositoryException
{
// check this node is versionable
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE))
{
throw new UnsupportedRepositoryOperationException("Node " + nodeRef + " is not versionable");
}
// remove 'read only' lock
if (!isCheckedOut())
{
LockService lockService = session.getRepositoryImpl().getServiceRegistry().getLockService();
lockService.unlock(nodeRef);
}
}
/* (non-Javadoc)
* @see javax.jcr.Node#doneMerge(javax.jcr.version.Version)
*/
public void doneMerge(Version version) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException
{
throw new UnsupportedRepositoryOperationException();
}
/* (non-Javadoc)
* @see javax.jcr.Node#cancelMerge(javax.jcr.version.Version)
*/
public void cancelMerge(Version version) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException
{
throw new UnsupportedRepositoryOperationException();
}
/* (non-Javadoc)
* @see javax.jcr.Node#update(java.lang.String)
*/
public void update(String srcWorkspaceName) throws NoSuchWorkspaceException, AccessDeniedException, LockException, InvalidItemStateException, RepositoryException
{
throw new UnsupportedRepositoryOperationException();
}
/* (non-Javadoc)
* @see javax.jcr.Node#merge(java.lang.String, boolean)
*/
public NodeIterator merge(String srcWorkspace, boolean bestEffort) throws NoSuchWorkspaceException, AccessDeniedException, MergeException, LockException, InvalidItemStateException, RepositoryException
{
throw new UnsupportedRepositoryOperationException();
}
/* (non-Javadoc)
* @see javax.jcr.Node#getCorrespondingNodePath(java.lang.String)
*/
public String getCorrespondingNodePath(String workspaceName) throws ItemNotFoundException, NoSuchWorkspaceException, AccessDeniedException, RepositoryException
{
throw new UnsupportedRepositoryOperationException();
}
/* (non-Javadoc)
* @see javax.jcr.Node#isCheckedOut()
*/
public boolean isCheckedOut() throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE))
{
// it's not versionable, therefore it's checked-out and writable
// TODO: Do not yet take into consideration versionable ancestor
return true;
}
// it's versionable, use the lock to determine if it's checked-out
LockService lockService = session.getRepositoryImpl().getServiceRegistry().getLockService();
LockType lockType = lockService.getLockType(nodeRef);
if (lockType == null)
{
// it's not locked at all
return true;
}
// it's only checked-in when a read-only locked
return (lockType.equals(LockType.READ_ONLY_LOCK)) ? false : true;
}
/* (non-Javadoc)
* @see javax.jcr.Node#restore(java.lang.String, boolean)
*/
public void restore(String versionName, boolean removeExisting) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException
{
// check this node is versionable
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE))
{
throw new UnsupportedRepositoryOperationException("Node " + nodeRef + " is not versionable");
}
// retrieve version for label
VersionService versionService = session.getRepositoryImpl().getServiceRegistry().getVersionService();
org.alfresco.service.cmr.version.VersionHistory versionHistory = versionService.getVersionHistory(nodeRef);
org.alfresco.service.cmr.version.Version version = versionHistory.getVersion(versionName);
if (version == null)
{
throw new VersionException("Version name " + versionName + " does not exist in the version history of node " + nodeRef);
}
// unlock if necessary
LockService lockService = session.getRepositoryImpl().getServiceRegistry().getLockService();
LockType lockType = lockService.getLockType(nodeRef);
if (lockType != null)
{
lockService.unlock(nodeRef);
}
// revert to version
versionService.revert(nodeRef, version);
lockService.lock(nodeRef, LockType.READ_ONLY_LOCK);
}
/* (non-Javadoc)
* @see javax.jcr.Node#restore(javax.jcr.version.Version, boolean)
*/
public void restore(Version version, boolean removeExisting) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, RepositoryException
{
restore(version.getName(), removeExisting);
}
/* (non-Javadoc)
* @see javax.jcr.Node#restore(javax.jcr.version.Version, java.lang.String, boolean)
*/
public void restore(Version version, String relPath, boolean removeExisting) throws PathNotFoundException, ItemExistsException, VersionException, ConstraintViolationException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException
{
throw new UnsupportedRepositoryOperationException();
}
/* (non-Javadoc)
* @see javax.jcr.Node#restoreByLabel(java.lang.String, boolean)
*/
public void restoreByLabel(String versionLabel, boolean removeExisting) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException
{
throw new UnsupportedRepositoryOperationException();
}
/* (non-Javadoc)
* @see javax.jcr.Node#getVersionHistory()
*/
public VersionHistory getVersionHistory() throws UnsupportedRepositoryOperationException, RepositoryException
{
// check this node is versionable
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE))
{
throw new UnsupportedRepositoryOperationException("Node " + nodeRef + " is not versionable");
}
// construct version history
VersionService versionService = session.getRepositoryImpl().getServiceRegistry().getVersionService();
org.alfresco.service.cmr.version.VersionHistory versionHistory = versionService.getVersionHistory(nodeRef);
return new VersionHistoryImpl(session, versionHistory).getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Node#getBaseVersion()
*/
public Version getBaseVersion() throws UnsupportedRepositoryOperationException, RepositoryException
{
// check this node is versionable
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE))
{
throw new UnsupportedRepositoryOperationException("Node " + nodeRef + " is not versionable");
}
// construct version
VersionService versionService = session.getRepositoryImpl().getServiceRegistry().getVersionService();
org.alfresco.service.cmr.version.VersionHistory versionHistory = versionService.getVersionHistory(nodeRef);
org.alfresco.service.cmr.version.Version version = versionService.getCurrentVersion(nodeRef);
return new VersionImpl(new VersionHistoryImpl(session, versionHistory), version).getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Node#lock(boolean, boolean)
*/
public Lock lock(boolean isDeep, boolean isSessionScoped) throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException
{
// note: alfresco does not yet support session scoped locks
if (isSessionScoped)
{
throw new UnsupportedRepositoryOperationException("Session scope locking is not supported.");
}
// check this node is lockable
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE))
{
throw new LockException("Node " + nodeRef + " does is not lockable.");
}
// lock the node
LockService lockService = session.getRepositoryImpl().getServiceRegistry().getLockService();
lockService.lock(nodeRef, LockType.WRITE_LOCK, 0, isDeep);
// return lock
return new LockImpl(this).getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Node#getLock()
*/
public Lock getLock() throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, RepositoryException
{
// check this node is lockable
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE))
{
throw new LockException("Node " + nodeRef + " does is not lockable.");
}
// return lock
return new LockImpl(this).getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Node#unlock()
*/
public void unlock() throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException
{
// check this node is lockable
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE))
{
throw new LockException("Node " + nodeRef + " does is not lockable.");
}
// unlock
LockService lockService = session.getRepositoryImpl().getServiceRegistry().getLockService();
lockService.unlock(nodeRef, true);
}
/* (non-Javadoc)
* @see javax.jcr.Node#holdsLock()
*/
public boolean holdsLock() throws RepositoryException
{
// note: for now, alfresco doesn't distinguish between lock holder and locked
return isLocked();
}
/* (non-Javadoc)
* @see javax.jcr.Node#isLocked()
*/
public boolean isLocked() throws RepositoryException
{
LockService lockService = session.getRepositoryImpl().getServiceRegistry().getLockService();
LockStatus lockStatus = lockService.getLockStatus(getNodeRef());
return lockStatus.equals(LockStatus.LOCK_OWNER) || lockStatus.equals(LockStatus.LOCKED);
}
/* (non-Javadoc)
* @see javax.jcr.Item#getName()
*/
public String getName() throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
ChildAssociationRef parentAssoc = nodeService.getPrimaryParent(nodeRef);
QName childName = parentAssoc.getQName();
return (childName == null) ? "" : childName.toPrefixString(session.getNamespaceResolver());
}
/* (non-Javadoc)
* @see javax.jcr.Item#isNode()
*/
public boolean isNode()
{
return true;
}
/* (non-Javadoc)
* @see javax.jcr.Item#getParent()
*/
public Node getParent() throws ItemNotFoundException, AccessDeniedException, RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
ChildAssociationRef parentAssoc = nodeService.getPrimaryParent(nodeRef);
if (parentAssoc == null || parentAssoc.getParentRef() == null)
{
// TODO: Distinguish between ItemNotFound and AccessDenied
throw new ItemNotFoundException("Parent of node " + nodeRef + " does not exist.");
}
NodeImpl nodeImpl = new NodeImpl(session, parentAssoc.getParentRef());
return nodeImpl.getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Item#getPath()
*/
public String getPath() throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
SearchService searchService = session.getRepositoryImpl().getServiceRegistry().getSearchService();
Path path = nodeService.getPath(nodeRef);
// Add indexes for same name siblings
// TODO: Look at more efficient approach
for (int i = path.size() - 1; i >= 0; i--)
{
Path.Element pathElement = path.get(i);
if (i > 0 && pathElement instanceof Path.ChildAssocElement)
{
int index = 1;
String searchPath = path.subPath(i).toPrefixString(session.getNamespaceResolver());
List<NodeRef> siblings = searchService.selectNodes(nodeRef, searchPath, null, session.getNamespaceResolver(), false);
if (siblings.size() > 1)
{
ChildAssociationRef childAssoc = ((Path.ChildAssocElement)pathElement).getRef();
NodeRef childRef = childAssoc.getChildRef();
for (NodeRef sibling : siblings)
{
if (sibling.equals(childRef))
{
childAssoc.setNthSibling(index);
break;
}
index++;
}
}
}
}
return path.toPrefixString(session.getNamespaceResolver());
}
/* (non-Javadoc)
* @see javax.jcr.Item#getDepth()
*/
public int getDepth() throws RepositoryException
{
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
Path path = nodeService.getPath(nodeRef);
// Note: Root is at depth 0
return path.size() -1;
}
/* (non-Javadoc)
* @see javax.jcr.Item#getAncestor(int)
*/
public Item getAncestor(int depth) throws ItemNotFoundException, AccessDeniedException, RepositoryException
{
// Retrieve primary parent path for node
NodeService nodeService = session.getRepositoryImpl().getServiceRegistry().getNodeService();
Path path = nodeService.getPath(nodeRef);
if (depth < 0 || depth > (path.size() - 1))
{
throw new ItemNotFoundException("Ancestor at depth " + depth + " not found for node " + nodeRef);
}
// Extract path element at requested depth
Element element = path.get(depth);
if (!(element instanceof Path.ChildAssocElement))
{
throw new RepositoryException("Path element at depth " + depth + " is not a node");
}
Path.ChildAssocElement childAssocElement = (Path.ChildAssocElement)element;
// Create node
NodeRef ancestorNodeRef = childAssocElement.getRef().getChildRef();
NodeImpl nodeImpl = new NodeImpl(session, ancestorNodeRef);
return nodeImpl.getProxy();
}
/* (non-Javadoc)
* @see javax.jcr.Item#isSame(javax.jcr.Item)
*/
public boolean isSame(Item otherItem) throws RepositoryException
{
return getProxy().equals(otherItem);
}
/* (non-Javadoc)
* @see javax.jcr.Item#accept(javax.jcr.ItemVisitor)
*/
public void accept(ItemVisitor visitor) throws RepositoryException
{
visitor.visit(getProxy());
}
/**
* Gets the Alfresco Node Reference
*
* @return the node reference
*/
public NodeRef getNodeRef()
{
return nodeRef;
}
@Override
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (!(obj instanceof NodeImpl))
{
return false;
}
NodeImpl other = (NodeImpl)obj;
return this.nodeRef.equals(other.nodeRef);
}
@Override
public int hashCode()
{
return nodeRef.hashCode();
}
}