Allow management of Alfresco Aspects through CMIS REST and SOAP APIs

- In CMIS methods that allow setting of node properties, the <cmis:properties> element may carry an <alf:setAspects> extension that lists
  - aspectsToRemove    
  - aspectsToAdd
  - properties (properties to set belonging to aspects rather than the node type)
- In CMIS methods that allow retrieval of node properties, the <cmis:properties> carries an <alf:getAspects> extension that lists
  - appliedAspects
  - properties (properties belonging to aspects rather than the node type)
- Added extension types to Alfresco-Core.xsd and referenced in extended WSDL
- Plumbed in to Web Service and REST APIs

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@19037 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2010-03-03 18:03:58 +00:00
parent 9a966ac2b3
commit 673add1796
2 changed files with 225 additions and 15 deletions

View File

@@ -23,6 +23,7 @@ import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -151,7 +152,7 @@ public interface CMISServices
public AssociationRef[] getRelationships(NodeRef node, CMISTypeDefinition relDef, boolean includeSubTypes, CMISRelationshipDirectionEnum direction) throws CMISInvalidArgumentException; public AssociationRef[] getRelationships(NodeRef node, CMISTypeDefinition relDef, boolean includeSubTypes, CMISRelationshipDirectionEnum direction) throws CMISInvalidArgumentException;
/** /**
* Get a single property for a node. * Get a single property belonging to the node's type.
* *
* @param nodeRef * @param nodeRef
* the node * the node
@@ -163,6 +164,22 @@ public interface CMISServices
*/ */
public Serializable getProperty(NodeRef nodeRef, String propertyName) throws CMISInvalidArgumentException; public Serializable getProperty(NodeRef nodeRef, String propertyName) throws CMISInvalidArgumentException;
/**
* Get a single property, optionally constrained to a given node type or aspect
*
* @param nodeRef
* the node
* @param typeDef
* the node type or aspect or <code>null</code> if any property can be returned
* @param propertyName
* the property name
* @return value
* @throws CMISInvalidArgumentException
* if an argument is invalid
*/
public Serializable getProperty(NodeRef nodeRef, CMISTypeDefinition typeDef, String propertyName)
throws CMISInvalidArgumentException;
/** /**
* Get a single property for an association. * Get a single property for an association.
* *
@@ -175,7 +192,7 @@ public interface CMISServices
public Serializable getProperty(AssociationRef assocRef, String propertyName); public Serializable getProperty(AssociationRef assocRef, String propertyName);
/** /**
* Get all properties. * Get all properties of a node's type.
* *
* @param nodeRef * @param nodeRef
* the node ref * the node ref
@@ -186,7 +203,32 @@ public interface CMISServices
public Map<String, Serializable> getProperties(NodeRef nodeRef) throws CMISInvalidArgumentException; public Map<String, Serializable> getProperties(NodeRef nodeRef) throws CMISInvalidArgumentException;
/** /**
* Set a single property. * Get all of a node's values for the properties in the given type or aspect.
*
* @param nodeRef
* the node ref
* @param typeDef
* the type or aspect definition
* @return the properties
* @throws CMISInvalidArgumentException
* if an argument is invalid
*/
public Map<String, Serializable> getProperties(NodeRef nodeRef, CMISTypeDefinition typeDef)
throws CMISInvalidArgumentException;
/**
* Gets the aspects applied to a node.
*
* @param nodeRef
* the node ref
* @return the aspect definitions
* @throws CMISInvalidArgumentException
* if an argument is invalid
*/
public Set<CMISTypeDefinition> getAspects(NodeRef nodeRef);
/**
* Set a single property belonging to the node's type.
* *
* @param nodeRef * @param nodeRef
* the node ref * the node ref
@@ -196,9 +238,47 @@ public interface CMISServices
* the value * the value
* @throws CMISInvalidArgumentException * @throws CMISInvalidArgumentException
* if an argument is invalid * if an argument is invalid
* @throws CMISConstraintException
* if the property cannot be set
*/ */
public void setProperty(NodeRef nodeRef, String propertyName, Serializable value) throws CMISInvalidArgumentException; public void setProperty(NodeRef nodeRef, String propertyName, Serializable value)
throws CMISInvalidArgumentException, CMISConstraintException;
/**
* Set a single property, optionally constrained to a given node type or aspect
*
* @param nodeRef
* the node ref
* @param typeDef
* the node type or aspect or <code>null</code> if any valid property should be set (corresponding aspect
* added automatically).
* @param propertyName
* the property name
* @param value
* the value
* @throws CMISInvalidArgumentException
* if an argument is invalid
* @throws CMISConstraintException
* if the property cannot be set
*/
public void setProperty(NodeRef nodeRef, CMISTypeDefinition typeDef, String propertyName, Serializable value)
throws CMISInvalidArgumentException, CMISConstraintException;
/**
* Sets the aspects on a node (Alfresco extension).
*
* @param node
* the node
* @param aspectsToRemove
* the aspects to remove
* @param aspectsToAdd
* the aspects to add
* @throws CMISInvalidArgumentException
* if an argument is invalid
*/
public void setAspects(NodeRef node, Iterable<String> aspectsToRemove, Iterable<String> aspectsToAdd)
throws CMISInvalidArgumentException;
/** /**
* Applies a versioning state to a new node, potentially resulting in a new node. * Applies a versioning state to a new node, potentially resulting in a new node.
* *

View File

@@ -26,9 +26,11 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -36,6 +38,7 @@ import java.util.regex.Pattern;
import org.alfresco.cmis.CMISConstraintException; import org.alfresco.cmis.CMISConstraintException;
import org.alfresco.cmis.CMISContentAlreadyExistsException; import org.alfresco.cmis.CMISContentAlreadyExistsException;
import org.alfresco.cmis.CMISContentStreamAllowedEnum; import org.alfresco.cmis.CMISContentStreamAllowedEnum;
import org.alfresco.cmis.CMISDataTypeEnum;
import org.alfresco.cmis.CMISDictionaryModel; import org.alfresco.cmis.CMISDictionaryModel;
import org.alfresco.cmis.CMISDictionaryService; import org.alfresco.cmis.CMISDictionaryService;
import org.alfresco.cmis.CMISFilterNotValidException; import org.alfresco.cmis.CMISFilterNotValidException;
@@ -54,6 +57,7 @@ import org.alfresco.cmis.CMISServices;
import org.alfresco.cmis.CMISStreamNotSupportedException; import org.alfresco.cmis.CMISStreamNotSupportedException;
import org.alfresco.cmis.CMISTypeDefinition; import org.alfresco.cmis.CMISTypeDefinition;
import org.alfresco.cmis.CMISTypesFilterEnum; import org.alfresco.cmis.CMISTypesFilterEnum;
import org.alfresco.cmis.CMISUpdatabilityEnum;
import org.alfresco.cmis.CMISVersioningException; import org.alfresco.cmis.CMISVersioningException;
import org.alfresco.cmis.CMISVersioningStateEnum; import org.alfresco.cmis.CMISVersioningStateEnum;
import org.alfresco.cmis.dictionary.CMISFolderTypeDefinition; import org.alfresco.cmis.dictionary.CMISFolderTypeDefinition;
@@ -74,10 +78,12 @@ import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.coci.CheckOutCheckInServiceException; import org.alfresco.service.cmr.coci.CheckOutCheckInServiceException;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.InvalidAspectException;
import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
@@ -699,12 +705,24 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware,
*/ */
public Serializable getProperty(NodeRef nodeRef, String propertyName) throws CMISInvalidArgumentException public Serializable getProperty(NodeRef nodeRef, String propertyName) throws CMISInvalidArgumentException
{ {
CMISTypeDefinition typeDef = getTypeDefinition(nodeRef); return getProperty(nodeRef, getTypeDefinition(nodeRef), propertyName);
}
public Serializable getProperty(NodeRef nodeRef, CMISTypeDefinition typeDef, String propertyName)
throws CMISInvalidArgumentException
{
CMISPropertyDefinition propDef = cmisDictionaryService.findProperty(propertyName, typeDef); CMISPropertyDefinition propDef = cmisDictionaryService.findProperty(propertyName, typeDef);
if (propDef == null) if (propDef == null)
{ {
throw new CMISInvalidArgumentException("Property " + propertyName + " not found for type " if (typeDef == null)
+ typeDef.getTypeId() + " in CMIS Dictionary"); {
throw new CMISInvalidArgumentException("Property " + propertyName + " not found in CMIS Dictionary");
}
else
{
throw new CMISInvalidArgumentException("Property " + propertyName + " not found for type "
+ typeDef.getTypeId() + " in CMIS Dictionary");
}
} }
return propDef.getPropertyAccessor().getValue(nodeRef); return propDef.getPropertyAccessor().getValue(nodeRef);
} }
@@ -796,31 +814,143 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware,
*/ */
public Map<String, Serializable> getProperties(NodeRef nodeRef) throws CMISInvalidArgumentException public Map<String, Serializable> getProperties(NodeRef nodeRef) throws CMISInvalidArgumentException
{ {
CMISTypeDefinition typeDef = getTypeDefinition(nodeRef); return getProperties(nodeRef, getTypeDefinition(nodeRef));
}
/*
* (non-Javadoc)
* @see org.alfresco.cmis.CMISServices#getProperties(org.alfresco.service.cmr.repository.NodeRef,
* org.alfresco.cmis.CMISTypeDefinition)
*/
public Map<String, Serializable> getProperties(NodeRef nodeRef, CMISTypeDefinition typeDef)
throws CMISInvalidArgumentException
{
Map<String, CMISPropertyDefinition> propDefs = typeDef.getPropertyDefinitions(); Map<String, CMISPropertyDefinition> propDefs = typeDef.getPropertyDefinitions();
Map<String, Serializable> values = new HashMap<String, Serializable>(propDefs.size()); Map<String, Serializable> values = new HashMap<String, Serializable>(propDefs.size() * 2);
for (CMISPropertyDefinition propDef : propDefs.values()) for (CMISPropertyDefinition propDef : propDefs.values())
{ {
values.put(propDef.getPropertyId().getId(), propDef.getPropertyAccessor().getValue(nodeRef)); values.put(propDef.getPropertyId().getId(), propDef.getPropertyAccessor().getValue(nodeRef));
} }
return values; return values;
} }
/*
* (non-Javadoc)
* @see org.alfresco.cmis.CMISServices#getAspects(org.alfresco.service.cmr.repository.NodeRef)
*/
public Set<CMISTypeDefinition> getAspects(NodeRef nodeRef)
{
Set<QName> aspects = nodeService.getAspects(nodeRef);
Set<CMISTypeDefinition> result = new HashSet<CMISTypeDefinition>(aspects.size() * 2);
for (QName aspect : aspects)
{
CMISTypeDefinition typeDef = cmisDictionaryService.findTypeForClass(aspect, CMISScope.POLICY);
if (typeDef != null)
{
result.add(typeDef);
}
}
return result;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.alfresco.cmis.CMISServices#setProperty(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.io.Serializable) * @see org.alfresco.cmis.CMISServices#setProperty(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.io.Serializable)
*/ */
public void setProperty(NodeRef nodeRef, String propertyName, Serializable value) public void setProperty(NodeRef nodeRef, String propertyName, Serializable value)
throws CMISInvalidArgumentException throws CMISInvalidArgumentException, CMISConstraintException
{
setProperty(nodeRef, getTypeDefinition(nodeRef), propertyName, value);
}
/*
* (non-Javadoc)
* @see org.alfresco.cmis.CMISServices#setProperty(org.alfresco.service.cmr.repository.NodeRef,
* org.alfresco.cmis.CMISTypeDefinition, java.lang.String, java.io.Serializable)
*/
public void setProperty(NodeRef nodeRef, CMISTypeDefinition typeDef, String propertyName, Serializable value)
throws CMISInvalidArgumentException, CMISConstraintException
{ {
CMISTypeDefinition typeDef = getTypeDefinition(nodeRef);
CMISPropertyDefinition propDef = cmisDictionaryService.findProperty(propertyName, typeDef); CMISPropertyDefinition propDef = cmisDictionaryService.findProperty(propertyName, typeDef);
if (propDef == null) if (propDef == null)
{ {
throw new AlfrescoRuntimeException("Property " + propertyName + " not found for type " if (typeDef == null)
+ typeDef.getTypeId() + " in CMIS Dictionary"); {
throw new CMISInvalidArgumentException("Property " + propertyName + " not found in CMIS Dictionary");
}
else
{
throw new CMISInvalidArgumentException("Property " + propertyName + " not found for type "
+ typeDef.getTypeId() + " in CMIS Dictionary");
}
}
CMISUpdatabilityEnum updatability = propDef.getUpdatability();
if (updatability == CMISUpdatabilityEnum.READ_ONLY
|| updatability == CMISUpdatabilityEnum.READ_AND_WRITE_WHEN_CHECKED_OUT
&& !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY))
{
throw new CMISConstraintException("Unable to update read-only property" + propertyName);
}
if (propDef.isRequired() && value == null)
{
throw new CMISConstraintException("Property " + propertyName + " is required");
}
if (propDef.getDataType() == CMISDataTypeEnum.STRING && propDef.getMaximumLength() > 0 && value != null
&& value.toString().length() > propDef.getMaximumLength())
{
throw new CMISConstraintException("Value is too long for property " + propertyName);
}
QName property = propDef.getPropertyAccessor().getMappedProperty();
if (property == null)
{
throw new CMISConstraintException("Unable to set property " + propertyName);
}
nodeService.setProperty(nodeRef, property, value);
}
/*
* (non-Javadoc)
* @see org.alfresco.cmis.CMISServices#setAspects(org.alfresco.service.cmr.repository.NodeRef, java.lang.Iterable,
* java.lang.Iterable)
*/
public void setAspects(NodeRef node, Iterable<String> aspectsToRemove, Iterable<String> aspectsToAdd)
throws CMISInvalidArgumentException
{
for (String aspectType : aspectsToRemove)
{
try
{
nodeService.removeAspect(node, getTypeDefinition(aspectType).getTypeId().getQName());
}
catch (InvalidAspectException e)
{
throw new CMISInvalidArgumentException("Invalid aspect " + aspectType);
}
catch (InvalidNodeRefException e)
{
throw new CMISInvalidArgumentException("Invalid node " + node);
}
}
for (String aspectType : aspectsToAdd)
{
try
{
nodeService.addAspect(node, getTypeDefinition(aspectType).getTypeId().getQName(), Collections
.<QName, Serializable> emptyMap());
}
catch (InvalidAspectException e)
{
throw new CMISInvalidArgumentException("Invalid aspect " + aspectType);
}
catch (InvalidNodeRefException e)
{
throw new CMISInvalidArgumentException("Invalid node " + node);
}
} }
propDef.getPropertyAccessor().setValue(nodeRef, value);
} }
/* /*