From 56d4c7c51a0fb6cd843ee415f92b25774c43cea6 Mon Sep 17 00:00:00 2001 From: Dave Ward Date: Mon, 22 Mar 2010 12:08:30 +0000 Subject: [PATCH] ALF-2086: CMIS Web Service policy and aspect unit tests - Added Alfresco-specific unit tests, actually run by the build - Fixed exception handling in getProperty - Fix null value handling in createProperty git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@19451 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../repo/cmis/ws/DMNavigationServicePort.java | 53 ++++--- .../repo/cmis/ws/DMRepositoryServicePort.java | 10 +- .../repo/cmis/ws/test/AspectTest.java | 139 ++++++++++++++++++ .../repo/cmis/ws/test/BaseCMISTest.java | 135 +++++++++++++++++ .../repo/cmis/ws/test/PolicyTest.java | 97 ++++++++++++ .../repo/cmis/ws/utils/PropertyUtil.java | 10 +- 6 files changed, 420 insertions(+), 24 deletions(-) create mode 100644 source/java/org/alfresco/repo/cmis/ws/test/AspectTest.java create mode 100644 source/java/org/alfresco/repo/cmis/ws/test/BaseCMISTest.java create mode 100644 source/java/org/alfresco/repo/cmis/ws/test/PolicyTest.java diff --git a/source/java/org/alfresco/repo/cmis/ws/DMNavigationServicePort.java b/source/java/org/alfresco/repo/cmis/ws/DMNavigationServicePort.java index 2790923212..725887d47d 100644 --- a/source/java/org/alfresco/repo/cmis/ws/DMNavigationServicePort.java +++ b/source/java/org/alfresco/repo/cmis/ws/DMNavigationServicePort.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Stack; import org.alfresco.cmis.CMISDictionaryModel; +import org.alfresco.cmis.CMISInvalidArgumentException; import org.alfresco.cmis.CMISServiceException; import org.alfresco.cmis.CMISTypesFilterEnum; import org.alfresco.cmis.PropertyFilter; @@ -223,38 +224,38 @@ public class DMNavigationServicePort extends DMAbstractServicePort implements Na * @throws CmisException (with following {@link EnumServiceException} : INVALID_ARGUMENT, OBJECT_NOT_FOUND, NOT_SUPPORTED, PERMISSION_DENIED, RUNTIME, CONSTRAINT, * FILTER_NOT_VALID) */ - public List getObjectParents(String repositoryId, String objectId, String filter, Boolean includeAllowableActions, - EnumIncludeRelationships includeRelationships, String renditionFilter, Boolean includeRelativePathSegment, CmisExtensionType extension) throws CmisException + public List getObjectParents(String repositoryId, String objectId, String filter, + Boolean includeAllowableActions, EnumIncludeRelationships includeRelationships, String renditionFilter, + Boolean includeRelativePathSegment, CmisExtensionType extension) throws CmisException { checkRepositoryId(repositoryId); PropertyFilter propertyFilter = createPropertyFilter(filter); - NodeRef childNode; try { - childNode = (NodeRef) cmisService.getReadableObject(objectId, NodeRef.class); + NodeRef childNode = (NodeRef) cmisService.getReadableObject(objectId, NodeRef.class); + List parents = receiveObjectParents(childNode); + + List result = new ArrayList(); + String relativePathSegment = propertiesUtil.getProperty(childNode, CMISDictionaryModel.PROP_NAME, ""); + for (NodeRef objectNodeRef : parents) + { + CmisObjectType cmisObject = createCmisObject(objectNodeRef, propertyFilter, includeRelationships, + includeAllowableActions, renditionFilter); + CmisObjectParentsType cmisObjectParentsType = new CmisObjectParentsType(); + cmisObjectParentsType.setObject(cmisObject); + if (includeRelativePathSegment != null && includeRelativePathSegment) + { + cmisObjectParentsType.setRelativePathSegment(relativePathSegment); + } + result.add(cmisObjectParentsType); + } + return result; } catch (CMISServiceException e) { throw ExceptionUtil.createCmisException(e); } - List parents = receiveObjectParents(childNode); - - List result = new ArrayList(); - String relativePathSegment = propertiesUtil.getProperty(childNode, CMISDictionaryModel.PROP_NAME, ""); - for (NodeRef objectNodeRef : parents) - { - CmisObjectType cmisObject = createCmisObject(objectNodeRef, propertyFilter, includeRelationships, - includeAllowableActions, renditionFilter); - CmisObjectParentsType cmisObjectParentsType = new CmisObjectParentsType(); - cmisObjectParentsType.setObject(cmisObject); - if (includeRelativePathSegment != null && includeRelativePathSegment) - { - cmisObjectParentsType.setRelativePathSegment(relativePathSegment); - } - result.add(cmisObjectParentsType); - } - return result; } private CmisObjectInFolderContainerType getDescendantsTree(String repositoryId, String folderId, BigInteger depth, String filter, Boolean includeAllowableActions, @@ -316,7 +317,15 @@ public class DMNavigationServicePort extends DMAbstractServicePort implements Na objectInFolderType.setObject(cmisObject); if (includePathSegments != null && includePathSegments) { - String path = propertiesUtil.getProperty(nodeRef, CMISDictionaryModel.PROP_NAME, ""); + String path; + try + { + path = propertiesUtil.getProperty(nodeRef, CMISDictionaryModel.PROP_NAME, ""); + } + catch (CMISInvalidArgumentException e) + { + throw ExceptionUtil.createCmisException(e); + } objectInFolderType.setPathSegment(path); } CmisObjectInFolderContainerType result = new CmisObjectInFolderContainerType(); diff --git a/source/java/org/alfresco/repo/cmis/ws/DMRepositoryServicePort.java b/source/java/org/alfresco/repo/cmis/ws/DMRepositoryServicePort.java index 0a3273515a..2050fa1e6e 100644 --- a/source/java/org/alfresco/repo/cmis/ws/DMRepositoryServicePort.java +++ b/source/java/org/alfresco/repo/cmis/ws/DMRepositoryServicePort.java @@ -38,6 +38,7 @@ import org.alfresco.cmis.CMISChoice; import org.alfresco.cmis.CMISContentStreamAllowedEnum; import org.alfresco.cmis.CMISDataTypeEnum; import org.alfresco.cmis.CMISDictionaryModel; +import org.alfresco.cmis.CMISInvalidArgumentException; import org.alfresco.cmis.CMISJoinEnum; import org.alfresco.cmis.CMISPermissionDefinition; import org.alfresco.cmis.CMISPermissionMapping; @@ -457,7 +458,14 @@ public class DMRepositoryServicePort extends DMAbstractServicePort implements Re repositoryInfoType.setVendorName("Alfresco"); repositoryInfoType.setProductName("Alfresco Repository (" + serverDescriptor.getEdition() + ")"); repositoryInfoType.setProductVersion(serverDescriptor.getVersion()); - repositoryInfoType.setRootFolderId(propertiesUtil.getProperty(cmisService.getDefaultRootNodeRef(), CMISDictionaryModel.PROP_OBJECT_ID, (String) null)); + try + { + repositoryInfoType.setRootFolderId(propertiesUtil.getProperty(cmisService.getDefaultRootNodeRef(), CMISDictionaryModel.PROP_OBJECT_ID, (String) null)); + } + catch (CMISInvalidArgumentException e) + { + throw ExceptionUtil.createCmisException(e); + } repositoryInfoType.setLatestChangeLogToken(cmisChangeLogService.getLastChangeLogToken()); // TODO: cmisVersionSupported is different in stubs and specification repositoryInfoType.setCmisVersionSupported("1.0"); diff --git a/source/java/org/alfresco/repo/cmis/ws/test/AspectTest.java b/source/java/org/alfresco/repo/cmis/ws/test/AspectTest.java new file mode 100644 index 0000000000..dad9686133 --- /dev/null +++ b/source/java/org/alfresco/repo/cmis/ws/test/AspectTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.cmis.ws.test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.xml.ws.Holder; + +import org.alfresco.repo.cmis.ws.Aspects; +import org.alfresco.repo.cmis.ws.CmisExtensionType; +import org.alfresco.repo.cmis.ws.CmisPropertiesType; +import org.alfresco.repo.cmis.ws.CmisProperty; +import org.alfresco.repo.cmis.ws.CmisPropertyString; +import org.alfresco.repo.cmis.ws.SetAspects; +import org.junit.Assert; + +/** + * Tests Alfresco CMIS WebService API extensions for Aspects. + * + * @author dward + */ +public class AspectTest extends BaseCMISTest +{ + public void testAspectSet() throws Exception + { + // create document for checkout + Holder objectId = new Holder(); + objectServicePort.createDocument(repositoryId, createObjectProperties(getName(), "cmis:document"), + testFolderId, null, null, null, null, null, new Holder(), objectId); + Assert.assertNotNull(objectId.value); + + // checkout + versioningServicePort.checkOut(repositoryId, objectId, new Holder(), new Holder()); + Assert.assertNotNull(objectId.value); + + // Apply some aspects to the working copy + { + CmisPropertiesType properties = new CmisPropertiesType(); + SetAspects extension = new SetAspects(); + properties.getAny().add(extension); + extension.getAspectsToAdd().addAll(Arrays.asList(new String[] + { + "P:cm:syndication", "P:cm:summarizable" + })); + CmisPropertiesType extensionProperties = new CmisPropertiesType(); + extension.setProperties(extensionProperties); + setStringProperty(extensionProperties, "cm:summary", "Aspect Test (summary)"); + // Add a property without explicitly adding its aspect. Should be automatically added. + setStringProperty(extensionProperties, "cm:author", "David Ward"); + objectServicePort.updateProperties(repositoryId, objectId, null, properties, null); + CmisPropertiesType updated = objectServicePort.getProperties(repositoryId, objectId.value, null, null); + Set appliedAspects = new HashSet(5); + Map aspectProperties = new HashMap(11); + extractAspectsAndProperties(updated, appliedAspects, aspectProperties); + assertContains(appliedAspects, "P:cm:syndication", "P:cm:summarizable", "P:cm:author"); + assertEquals("Aspect Test (summary)", aspectProperties.get("cm:summary")); + assertEquals("David Ward", aspectProperties.get("cm:author")); + } + + // check in with updated aspects + { + CmisPropertiesType properties = new CmisPropertiesType(); + SetAspects extension = new SetAspects(); + properties.getAny().add(extension); + extension.getAspectsToAdd().add("P:cm:countable"); + extension.getAspectsToRemove().add("P:cm:author"); + CmisPropertiesType extensionProperties = new CmisPropertiesType(); + extension.setProperties(extensionProperties); + setStringProperty(extensionProperties, "cm:summary", "Aspect Test (new summary)"); + versioningServicePort.checkIn(repositoryId, objectId, null, properties, null, null, null, null, null, + new Holder()); + CmisPropertiesType checkedIn = objectServicePort.getProperties(repositoryId, objectId.value, null, null); + Set appliedAspects = new HashSet(5); + Map aspectProperties = new HashMap(11); + extractAspectsAndProperties(checkedIn, appliedAspects, aspectProperties); + assertContains(appliedAspects, "P:cm:syndication", "P:cm:summarizable", "P:cm:countable"); + assertDoesNotContain(appliedAspects, "P:cm:author"); + assertEquals("Aspect Test (new summary)", aspectProperties.get("cm:summary")); + assertNull(aspectProperties.get("cm:author")); + } + } + + /** + * @param properties + * @param appliedAspects + * @param aspectProperties + */ + private void extractAspectsAndProperties(CmisPropertiesType properties, Set appliedAspects, + Map aspectProperties) + { + Aspects extension = null; + for (Object object : properties.getAny()) + { + if (object instanceof Aspects) + { + extension = (Aspects) object; + break; + } + } + if (extension == null) + { + fail("alf:aspects element not included"); + } + appliedAspects.addAll(extension.getAppliedAspects()); + CmisPropertiesType extensionProperties = extension.getProperties(); + if (extensionProperties == null) + { + return; + } + for (CmisProperty property : extensionProperties.getProperty()) + { + if (property instanceof CmisPropertyString) + { + aspectProperties.put(property.getPropertyDefinitionId(), ((CmisPropertyString) property).getValue() + .get(0)); + } + } + } +} diff --git a/source/java/org/alfresco/repo/cmis/ws/test/BaseCMISTest.java b/source/java/org/alfresco/repo/cmis/ws/test/BaseCMISTest.java new file mode 100644 index 0000000000..b1750bc8ef --- /dev/null +++ b/source/java/org/alfresco/repo/cmis/ws/test/BaseCMISTest.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.cmis.ws.test; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.xml.ws.Holder; + +import junit.framework.TestCase; + +import org.alfresco.cmis.CMISDictionaryModel; +import org.alfresco.repo.cmis.ws.CmisException; +import org.alfresco.repo.cmis.ws.CmisExtensionType; +import org.alfresco.repo.cmis.ws.CmisPropertiesType; +import org.alfresco.repo.cmis.ws.CmisPropertyId; +import org.alfresco.repo.cmis.ws.CmisPropertyString; +import org.alfresco.repo.cmis.ws.ObjectServicePort; +import org.alfresco.repo.cmis.ws.PolicyServicePort; +import org.alfresco.repo.cmis.ws.RepositoryServicePort; +import org.alfresco.repo.cmis.ws.VersioningServicePort; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.util.ApplicationContextHelper; +import org.junit.Assert; +import org.springframework.context.ApplicationContext; + +/** + * Base class for tests to Alfresco CMIS WebService API extensions. + * + * @author dward + */ +public abstract class BaseCMISTest extends TestCase +{ + protected RepositoryServicePort repositoryServicePort; + protected ObjectServicePort objectServicePort; + protected VersioningServicePort versioningServicePort; + protected PolicyServicePort policyServicePort; + protected String defaultRunAs = "admin"; + protected String repositoryId; + protected String testFolderId; + + public BaseCMISTest() + { + ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(new String[] + { + ApplicationContextHelper.CONFIG_LOCATIONS[0], "classpath:alfresco/web-services-application-context.xml" + }); + repositoryServicePort = (RepositoryServicePort) ctx.getBean("dmRepositoryService"); + objectServicePort = (ObjectServicePort) ctx.getBean("dmObjectService"); + versioningServicePort = (VersioningServicePort) ctx.getBean("dmVersioningService"); + policyServicePort = (PolicyServicePort) ctx.getBean("dmPolicyService"); + try + { + repositoryId = repositoryServicePort.getRepositories(null).get(0).getRepositoryId(); + } + catch (CmisException e) + { + throw new RuntimeException(e); + } + } + + public void setDefaultRunAs(String defaultRunAs) + { + this.defaultRunAs = defaultRunAs; + } + + @Override + protected void setUp() throws Exception + { + AuthenticationUtil.setFullyAuthenticatedUser(defaultRunAs); + String rootFolderId = repositoryServicePort.getRepositoryInfo(repositoryId, null).getRootFolderId(); + Holder objectId = new Holder(); + String folderName = getClass().getSimpleName() + System.currentTimeMillis() + " - " + getName(); + objectServicePort.createFolder(repositoryId, createObjectProperties(folderName, "cmis:folder"), rootFolderId, + null, null, null, new Holder(), objectId); + testFolderId = objectId.value; + } + + @Override + protected void tearDown() throws Exception + { + AuthenticationUtil.clearCurrentSecurityContext(); + } + + protected CmisPropertiesType createObjectProperties(String name, String type) + { + CmisPropertiesType properties = new CmisPropertiesType(); + CmisPropertyString stringProperty = new CmisPropertyString(); + stringProperty.setPropertyDefinitionId(CMISDictionaryModel.PROP_NAME); + stringProperty.getValue().add(name); + properties.getProperty().add(stringProperty); + CmisPropertyId idProperty = new CmisPropertyId(); + idProperty.setPropertyDefinitionId(CMISDictionaryModel.PROP_OBJECT_TYPE_ID); + idProperty.getValue().add(type); + properties.getProperty().add(idProperty); + return properties; + } + + protected void setStringProperty(CmisPropertiesType properties, String id, String value) + { + CmisPropertyString stringProperty = new CmisPropertyString(); + properties.getProperty().add(stringProperty); + stringProperty.setPropertyDefinitionId(id); + stringProperty.getValue().add(value); + } + + protected void assertContains(Set actual, String... expected) + { + Assert.assertTrue(actual.containsAll(Arrays.asList(expected))); + } + + protected void assertDoesNotContain(Set actual, String... unexpected) + { + Set copy = new HashSet(actual); + copy.retainAll(Arrays.asList(unexpected)); + Assert.assertTrue(copy.isEmpty()); + } +} diff --git a/source/java/org/alfresco/repo/cmis/ws/test/PolicyTest.java b/source/java/org/alfresco/repo/cmis/ws/test/PolicyTest.java new file mode 100644 index 0000000000..8f10e1d96c --- /dev/null +++ b/source/java/org/alfresco/repo/cmis/ws/test/PolicyTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.cmis.ws.test; + +import java.util.List; + +import javax.xml.ws.Holder; + +import org.alfresco.repo.cmis.ws.CmisException; +import org.alfresco.repo.cmis.ws.CmisExtensionType; +import org.alfresco.repo.cmis.ws.CmisObjectType; +import org.alfresco.repo.cmis.ws.CmisTypeDefinitionListType; +import org.alfresco.repo.cmis.ws.CmisTypeDefinitionType; +import org.alfresco.repo.cmis.ws.EnumServiceException; +import org.junit.Assert; + +/** + * Tests Alfresco CMIS Policy Web Service implementation. + * + * @author dward + */ +public class PolicyTest extends BaseCMISTest +{ + public void testPolicies() throws Exception + { + // Try creating an object with the cmis:policy base type (expect a constraint exception) + Holder objectId = new Holder(); + try + { + objectServicePort.createPolicy(repositoryId, createObjectProperties(getName(), "cmis:policy"), + testFolderId, null, null, null, new Holder(), objectId); + fail("Expected CmisException"); + } + catch (CmisException e) + { + Assert.assertEquals(EnumServiceException.CONSTRAINT, e.getFaultInfo().getType()); + } + + // Try creating an object of any of the cmis:policy subtypes + CmisTypeDefinitionListType typeDefs = repositoryServicePort.getTypeChildren(repositoryId, "cmis:policy", true, + null, null, null); + List entries = typeDefs.getTypes(); + assertNotSame(0, entries.size()); + for (CmisTypeDefinitionType type : entries) + { + try + { + objectServicePort.createPolicy(repositoryId, createObjectProperties(getName(), type.getId()), + testFolderId, null, null, null, new Holder(), objectId); + fail("Expected CmisException"); + } + catch (CmisException e) + { + Assert.assertEquals(EnumServiceException.CONSTRAINT, e.getFaultInfo().getType()); + } + } + + // Create a document to attempt to apply policies to + objectServicePort.createDocument(repositoryId, createObjectProperties(getName(), "cmis:document"), + testFolderId, null, null, null, null, null, new Holder(), objectId); + Assert.assertNotNull(objectId.value); + + // retrieve list of policies applied to document (this should be empty) + List policies = policyServicePort.getAppliedPolicies(repositoryId, objectId.value, null, null); + assertNotNull(policies); + assertEquals(0, policies.size()); + + // Try applying a policy (expect a constraint exception) + try + { + policyServicePort + .applyPolicy(repositoryId, "doesnotexist", objectId.value, new Holder()); + fail("Expected CmisException"); + } + catch (CmisException e) + { + Assert.assertEquals(EnumServiceException.CONSTRAINT, e.getFaultInfo().getType()); + } + + } +} diff --git a/source/java/org/alfresco/repo/cmis/ws/utils/PropertyUtil.java b/source/java/org/alfresco/repo/cmis/ws/utils/PropertyUtil.java index 750496f2d6..6681fb45a6 100644 --- a/source/java/org/alfresco/repo/cmis/ws/utils/PropertyUtil.java +++ b/source/java/org/alfresco/repo/cmis/ws/utils/PropertyUtil.java @@ -123,17 +123,20 @@ public class PropertyUtil * @param defaultValue - some value of the appropriate for conversion type. Also null may be accepted by this parameter * @return value instance of the appropriate type if specified object has such property and defaultValue if requested property value or objectNodeRef or * propertyName are null or if some exception occurred during property receiving + * @throws CMISInvalidArgumentException */ public ResultType getProperty(NodeRef objectNodeRef, String propertyName, ResultType defaultValue) + throws CMISInvalidArgumentException { if ((null == objectNodeRef) || (null == propertyName)) { return defaultValue; } + Serializable value = cmisService.getProperty(objectNodeRef, propertyName); try { - return convertPropertyValue(cmisService.getProperty(objectNodeRef, propertyName), defaultValue); + return convertPropertyValue(value, defaultValue); } catch (Exception exception) { @@ -511,6 +514,11 @@ public class PropertyUtil @SuppressWarnings("unchecked") public CmisProperty createProperty(String pdid, CMISDataTypeEnum dataType, Serializable value) { + if (value == null) + { + return null; + } + switch (dataType) { case BOOLEAN: