/* * #%L * Alfresco Repository * %% * Copyright (C) 2005 - 2016 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of * the paid license agreement will prevail. Otherwise, the software is * provided under the following open source license terms: * * 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 . * #L% */ package org.alfresco.opencmis; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.File; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import org.alfresco.model.ContentModel; import org.alfresco.opencmis.dictionary.CMISDictionaryService; import org.alfresco.opencmis.dictionary.PropertyDefinitionWrapper; import org.alfresco.opencmis.dictionary.TypeDefinitionWrapper; import org.alfresco.opencmis.search.CMISQueryOptions; import org.alfresco.opencmis.search.CMISQueryOptions.CMISQueryMode; import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator; import org.alfresco.repo.action.executer.AddFeaturesActionExecuter; import org.alfresco.repo.audit.AuditComponent; import org.alfresco.repo.audit.AuditComponentImpl; import org.alfresco.repo.audit.AuditServiceImpl; import org.alfresco.repo.audit.UserAuditFilter; import org.alfresco.repo.audit.model.AuditModelRegistryImpl; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.dictionary.DictionaryDAO; import org.alfresco.repo.dictionary.M2Model; import org.alfresco.repo.domain.audit.AuditDAO; import org.alfresco.repo.domain.node.ContentDataWithId; import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.model.Repository; import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationContext; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.tenant.TenantAdminService; import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantUtil; import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.version.VersionableAspectTest; import org.alfresco.repo.workflow.WorkflowDeployer; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.action.ActionCondition; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.lock.LockType; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.rule.Rule; import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.rule.RuleType; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.tagging.TaggingService; import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.VersionService; import org.alfresco.service.cmr.version.VersionType; import org.alfresco.service.cmr.workflow.WorkflowAdminService; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.Pair; import org.alfresco.util.testing.category.LuceneTests; import org.alfresco.util.testing.category.RedundantTests; import org.apache.chemistry.opencmis.commons.PropertyIds; import org.apache.chemistry.opencmis.commons.data.Ace; import org.apache.chemistry.opencmis.commons.data.AllowableActions; import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement; import org.apache.chemistry.opencmis.commons.data.ContentStream; import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData; import org.apache.chemistry.opencmis.commons.data.ObjectData; import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData; import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList; import org.apache.chemistry.opencmis.commons.data.ObjectList; import org.apache.chemistry.opencmis.commons.data.ObjectParentData; import org.apache.chemistry.opencmis.commons.data.Properties; import org.apache.chemistry.opencmis.commons.data.PropertyData; import org.apache.chemistry.opencmis.commons.data.RepositoryInfo; import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition; import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition; import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer; import org.apache.chemistry.opencmis.commons.enums.AclPropagation; import org.apache.chemistry.opencmis.commons.enums.Action; import org.apache.chemistry.opencmis.commons.enums.ChangeType; import org.apache.chemistry.opencmis.commons.enums.CmisVersion; import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships; import org.apache.chemistry.opencmis.commons.enums.UnfileObject; import org.apache.chemistry.opencmis.commons.enums.VersioningState; import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException; import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException; import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException; import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException; import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.CmisExtensionElementImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.ExtensionDataImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDecimalDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerDefinitionImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerImpl; import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringImpl; import org.apache.chemistry.opencmis.commons.impl.server.AbstractServiceFactory; import org.apache.chemistry.opencmis.commons.server.CallContext; import org.apache.chemistry.opencmis.commons.server.CmisService; import org.apache.chemistry.opencmis.commons.server.ObjectInfo; import org.apache.chemistry.opencmis.commons.spi.Holder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.springframework.context.ApplicationContext; import org.springframework.extensions.webscripts.GUID; /** * OpenCMIS tests. * * @author steveglover * */ @Category(LuceneTests.class) public class CMISTest { private static Log logger = LogFactory.getLog(CMISTest.class); private static final QName TEST_START_TASK = QName.createQName("http://www.alfresco.org/model/workflow/test/1.0", "startTaskVarScriptAssign"); private static final QName TEST_WORKFLOW_TASK = QName.createQName("http://www.alfresco.org/model/workflow/test/1.0", "assignVarTask"); private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(new String[]{ApplicationContextHelper.CONFIG_LOCATIONS[0],"classpath:test-cmisinteger_modell-context.xml"}); private FileFolderService fileFolderService; private TransactionService transactionService; private NodeService nodeService; private ContentService contentService; private Repository repositoryHelper; private VersionService versionService; private LockService lockService; private TaggingService taggingService; private NamespaceService namespaceService; private AuthorityService authorityService; private AuditModelRegistryImpl auditSubsystem; private PermissionService permissionService; private DictionaryDAO dictionaryDAO; private CMISDictionaryService cmisDictionaryService; private AuditDAO auditDAO; private ActionService actionService; private RuleService ruleService; private NodeArchiveService nodeArchiveService; private DictionaryService dictionaryService; private WorkflowService workflowService; private WorkflowAdminService workflowAdminService; private AuthenticationContext authenticationContext; private TenantAdminService tenantAdminService; private TenantService tenantService; private SearchService searchService; private java.util.Properties globalProperties; private AuditComponentImpl auditComponent; private AlfrescoCmisServiceFactory factory; private CMISConnector cmisConnector; private NodeDAO nodeDAO; /** * Test class to provide the service factory * * @author Derek Hulley * @since 4.0 */ public static class TestCmisServiceFactory extends AbstractServiceFactory { private static AlfrescoCmisServiceFactory serviceFactory = (AlfrescoCmisServiceFactory) ctx.getBean("CMISServiceFactory"); @Override public void init(Map parameters) { serviceFactory.init(parameters); } @Override public void destroy() { } @Override public CmisService getService(CallContext context) { return serviceFactory.getService(context); } } /** * Test class to provide the service factory * * @author Derek Hulley * @since 4.0 */ public static class TestCmisServiceFactory11 extends AbstractServiceFactory { private static AlfrescoCmisServiceFactory serviceFactory = (AlfrescoCmisServiceFactory) ctx.getBean("CMISServiceFactory1.1"); @Override public void init(Map parameters) { serviceFactory.init(parameters); } @Override public void destroy() { } @Override public CmisService getService(CallContext context) { return serviceFactory.getService(context); } } public static class SimpleCallContext implements CallContext { private final Map contextMap = new HashMap(); private CmisVersion cmisVersion; public SimpleCallContext(String user, String password, CmisVersion cmisVersion) { contextMap.put(USERNAME, user); contextMap.put(PASSWORD, password); this.cmisVersion = cmisVersion; } public String getBinding() { return BINDING_LOCAL; } public Object get(String key) { return contextMap.get(key); } public String getRepositoryId() { return (String) get(REPOSITORY_ID); } public String getUsername() { return (String) get(USERNAME); } public String getPassword() { return (String) get(PASSWORD); } public String getLocale() { return null; } public BigInteger getOffset() { return (BigInteger) get(OFFSET); } public BigInteger getLength() { return (BigInteger) get(LENGTH); } public boolean isObjectInfoRequired() { return false; } public File getTempDirectory() { return null; } public int getMemoryThreshold() { return 0; } public long getMaxContentSize() { return Long.MAX_VALUE; } @Override public boolean encryptTempFiles() { return false; } @Override public CmisVersion getCmisVersion() { return cmisVersion; } } @Before public void before() { this.actionService = (ActionService)ctx.getBean("actionService"); this.ruleService = (RuleService)ctx.getBean("ruleService"); this.fileFolderService = (FileFolderService)ctx.getBean("FileFolderService"); this.transactionService = (TransactionService)ctx.getBean("transactionService"); this.nodeService = (NodeService)ctx.getBean("NodeService"); this.contentService = (ContentService)ctx.getBean("ContentService"); this.versionService = (VersionService) ctx.getBean("versionService"); this.lockService = (LockService) ctx.getBean("lockService"); this.taggingService = (TaggingService) ctx.getBean("TaggingService"); this.namespaceService = (NamespaceService) ctx.getBean("namespaceService"); this.repositoryHelper = (Repository)ctx.getBean("repositoryHelper"); this.factory = (AlfrescoCmisServiceFactory)ctx.getBean("CMISServiceFactory"); this.versionService = (VersionService) ctx.getBean("versionService"); this.cmisConnector = (CMISConnector) ctx.getBean("CMISConnector"); this.nodeDAO = (NodeDAO) ctx.getBean("nodeDAO"); this.authorityService = (AuthorityService)ctx.getBean("AuthorityService"); this.auditSubsystem = (AuditModelRegistryImpl) ctx.getBean("Audit"); this.permissionService = (PermissionService) ctx.getBean("permissionService"); this.dictionaryDAO = (DictionaryDAO)ctx.getBean("dictionaryDAO"); this.cmisDictionaryService = (CMISDictionaryService)ctx.getBean("OpenCMISDictionaryService1.1"); this.auditDAO = (AuditDAO) ctx.getBean("auditDAO"); this.nodeArchiveService = (NodeArchiveService) ctx.getBean("nodeArchiveService"); this.dictionaryService = (DictionaryService) ctx.getBean("dictionaryService"); this.workflowService = (WorkflowService) ctx.getBean("WorkflowService"); this.workflowAdminService = (WorkflowAdminService) ctx.getBean("workflowAdminService"); this.authenticationContext = (AuthenticationContext) ctx.getBean("authenticationContext"); this.tenantAdminService = (TenantAdminService) ctx.getBean("tenantAdminService"); this.tenantService = (TenantService) ctx.getBean("tenantService"); this.searchService = (SearchService) ctx.getBean("SearchService"); this.auditComponent = (AuditComponentImpl) ctx.getBean("auditComponent"); this.globalProperties = (java.util.Properties) ctx.getBean("global-properties"); this.globalProperties.setProperty(VersionableAspectTest.AUTO_VERSION_PROPS_KEY, "true"); } @After public void after() { this.globalProperties.setProperty(VersionableAspectTest.AUTO_VERSION_PROPS_KEY, "false"); } /** * MNT-10868 CMIS: Incorrect value of Latest Major version on Versions and Properties tabs. */ @Test public void testIsLatestMajorVersionMNT10868() { CallContext context = new SimpleCallContext("admin", "admin", CmisVersion.CMIS_1_0); String repositoryId = null; AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); CmisService cmisService = factory.getService(context); try { // get repository id List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); repositoryId = repo.getId(); final String folderName = "testfolder" + GUID.generate(); final String docName = "testdoc.txt" + GUID.generate(); final FileInfo fileInfo = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public FileInfo execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); FileInfo fileInfo = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); nodeService.setProperty(fileInfo.getNodeRef(), ContentModel.PROP_NAME, docName); nodeService.addAspect(fileInfo.getNodeRef(), ContentModel.ASPECT_VERSIONABLE, null); return fileInfo; } }); ObjectData objectData = cmisService.getObjectByPath(repositoryId, "/" + folderName + "/" + docName, null, true, IncludeRelationships.NONE, null, false, true, null); PropertyData pd = getPropIsLatestMajorVersion(objectData); if (pd != null) { assertTrue("The CMISDictionaryModel.PROP_IS_LATEST_MAJOR_VERSION should be true as major version was created", (Boolean) pd.getValues().get(0)); } nodeService.setProperty(fileInfo.getNodeRef(), ContentModel.PROP_TITLE, docName); // Create minor version transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { public Object execute() throws Throwable { // get an updating writer ContentWriter writer = contentService.getWriter(fileInfo.getNodeRef(), ContentModel.PROP_CONTENT, true); writer.setMimetype("text/plain"); writer.putContent("New Version"); return null; } }); objectData = cmisService.getObjectByPath(repositoryId, "/" + folderName + "/" + docName, null, true, IncludeRelationships.NONE, null, false, true, null); pd = getPropIsLatestMajorVersion(objectData); if (pd != null) { assertFalse("The CMISDictionaryModel.PROP_IS_LATEST_MAJOR_VERSION should be false as minor version was created", (Boolean) pd.getValues().get(0)); } } finally { cmisService.close(); } } private PropertyData getPropIsLatestMajorVersion(ObjectData objectData) { List> properties = objectData.getProperties().getPropertyList(); boolean found = false; PropertyData propIsLatestMajorVersion = null; for (PropertyData property : properties) { if (property.getId().equals(PropertyIds.IS_LATEST_MAJOR_VERSION)) { found = true; propIsLatestMajorVersion = property; break; } } //properties..contains(PropertyIds.IS_LATEST_MAJOR_VERSION); assertTrue("The PropertyIds.IS_LATEST_MAJOR_VERSION property was not found", found); if (found) { return propIsLatestMajorVersion; } return null; } /** * Test for MNT-9203. */ @Test public void testCheckIn() { String repositoryId = null; ObjectData objectData = null; Holder objectId = null; CallContext context = new SimpleCallContext("admin", "admin", CmisVersion.CMIS_1_0); final String folderName = "testfolder." + GUID.generate(); final String docName = "testdoc.txt." + GUID.generate(); final String customModel = "cmistest.model"; final QName testCustomTypeQName = QName.createQName(customModel, "sop"); final QName authorisedByQname = QName.createQName(customModel, "authorisedBy"); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { final FileInfo fileInfo = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public FileInfo execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); FileInfo fileInfo = fileFolderService.create(folderInfo.getNodeRef(), docName, testCustomTypeQName); Map customProperties = new HashMap(); customProperties.put(authorisedByQname, "customPropertyString"); customProperties.put(ContentModel.PROP_NAME, docName); nodeService.setProperties(fileInfo.getNodeRef(), customProperties); return fileInfo; } }); CmisService service = factory.getService(context); try { List repositories = service.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); repositoryId = repo.getId(); objectData = service.getObjectByPath(repositoryId, "/" + folderName + "/" + docName, null, true, IncludeRelationships.NONE, null, false, true, null); // checkout objectId = new Holder(objectData.getId()); service.checkOut(repositoryId, objectId, null, new Holder(true)); } finally { service.close(); } try { service = factory.getService(context); PropertyStringImpl prop = new PropertyStringImpl(); prop.setId("abc:" + authorisedByQname.toPrefixString()); prop.setValue(null); Collection> propsList = new ArrayList>(); propsList.add(prop); Properties properties = new PropertiesImpl(propsList); // checkIn on pwc service.checkIn(repositoryId, objectId, false, properties, null, null, null, null, null, null); } finally { service.close(); } // check that value is null assertTrue(nodeService.getProperty(fileInfo.getNodeRef(), authorisedByQname) == null); } finally { AuthenticationUtil.popAuthentication(); } } /** * Test for MNT-10537. */ @Test public void testModelAvailability() throws Exception { final WorkflowDeployer testWorkflowDeployer = new WorkflowDeployer(); // setup dependencies testWorkflowDeployer.setTransactionService(transactionService); testWorkflowDeployer.setWorkflowService(workflowService); testWorkflowDeployer.setWorkflowAdminService(workflowAdminService); testWorkflowDeployer.setAuthenticationContext(authenticationContext); testWorkflowDeployer.setDictionaryDAO(dictionaryDAO); testWorkflowDeployer.setTenantAdminService(tenantAdminService); testWorkflowDeployer.setTenantService(tenantService); testWorkflowDeployer.setNodeService(nodeService); testWorkflowDeployer.setNamespaceService(namespaceService); testWorkflowDeployer.setSearchService(searchService); // populate workflow parameters java.util.Properties props = new java.util.Properties(); props.setProperty(WorkflowDeployer.ENGINE_ID, "activiti"); props.setProperty(WorkflowDeployer.LOCATION, "activiti/testCustomActiviti.bpmn20.xml"); props.setProperty(WorkflowDeployer.MIMETYPE, "text/xml"); props.setProperty(WorkflowDeployer.REDEPLOY, Boolean.FALSE.toString()); List definitions = new ArrayList(1); definitions.add(props); testWorkflowDeployer.setWorkflowDefinitions(definitions); List models = new ArrayList(1); models.add("activiti/testWorkflowModel.xml"); testWorkflowDeployer.setModels(models); // deploy test workflow RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper(); txnHelper.setForceWritable(true); txnHelper.doInTransaction(new RetryingTransactionCallback() { @Override public Object execute() throws Throwable { return AuthenticationUtil.runAs(new RunAsWork() { public Object doWork() { testWorkflowDeployer.init(); return null; } }, AuthenticationUtil.getSystemUserName()); } }, false, true); org.alfresco.service.cmr.dictionary.TypeDefinition startTaskTypeDefinition = this.dictionaryService.getType(TEST_START_TASK); org.alfresco.service.cmr.dictionary.TypeDefinition workflowTaskTypeDefinition = this.dictionaryService.getType(TEST_WORKFLOW_TASK); // check that workflow types were correctly bootstrapped assertNotNull(startTaskTypeDefinition); assertNotNull(workflowTaskTypeDefinition); // caches are refreshed asynchronously Thread.sleep(5000); // check that loaded model is available via CMIS API CallContext context = new SimpleCallContext("admin", "admin", CmisVersion.CMIS_1_1); CmisService service = factory.getService(context); try { List repositories = service.getRepositoryInfos(null); assertTrue(repositories.size() > 0); List container = service.getTypeDescendants(repositories.get(0).getId(), null, new BigInteger("-1"), true, null); assertTrue("Workflow model haven't been loaded", container.toString().contains("testwf:startTaskVarScriptAssign")); } finally { service.close(); } } private FileInfo createContent(final String folderName, final String docName, final boolean isRule) { return createContent(null, folderName, docName, isRule); } private FileInfo createContent(final FileInfo parentFolder, final String folderName, final String docName, final boolean isRule) { final FileInfo folderInfo = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public FileInfo execute() throws Throwable { NodeRef nodeRef; if (parentFolder != null) { nodeRef = parentFolder.getNodeRef(); } else { nodeRef = repositoryHelper.getCompanyHome(); } FileInfo folderInfo = fileFolderService.create(nodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); assertNotNull(folderInfo); FileInfo fileInfo; if (docName != null) { fileInfo = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); nodeService.setProperty(fileInfo.getNodeRef(), ContentModel.PROP_NAME, docName); assertNotNull(fileInfo); } if (isRule) { Rule rule = addRule(true, folderName); assertNotNull(rule); // Attach the rule to the node ruleService.saveRule(folderInfo.getNodeRef(), rule); assertTrue(ruleService.getRules(folderInfo.getNodeRef()).size() > 0); } return folderInfo; } }); return folderInfo; } private Rule addRule(boolean isAppliedToChildren, String title) { // Rule properties Map conditionProps = new HashMap(); conditionProps.put(ComparePropertyValueEvaluator.PARAM_VALUE, ".txt"); Map actionProps = new HashMap(); actionProps.put(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); List ruleTypes = new ArrayList(1); ruleTypes.add(RuleType.INBOUND); // Create the action org.alfresco.service.cmr.action.Action action = actionService.createAction(title); action.setParameterValues(conditionProps); ActionCondition actionCondition = actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); actionCondition.setParameterValues(conditionProps); action.addActionCondition(actionCondition); // Create the rule Rule rule = new Rule(); rule.setRuleTypes(ruleTypes); rule.setTitle(title); rule.setDescription("description"); rule.applyToChildren(isAppliedToChildren); rule.setAction(action); return rule; } private T withCmisService(CmisServiceCallback callback) { return withCmisService(callback, CmisVersion.CMIS_1_0); } private T withCmisService(CmisServiceCallback callback, CmisVersion cmisVersion) { CmisService cmisService = null; try { CallContext context = new SimpleCallContext("admin", "admin", cmisVersion); cmisService = factory.getService(context); T ret = callback.execute(cmisService); return ret; } finally { if(cmisService != null) { cmisService.close(); } } } private static interface CmisServiceCallback { T execute(CmisService cmisService); } /** * ALF-18006 Test content mimetype auto-detection into CmisStreamInterceptor when "Content-Type" is not defined. */ @Test public void testContentMimeTypeDetection() { ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); FileFolderService ffs = serviceRegistry.getFileFolderService(); AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); final String isoEncoding = "ISO-8859-1"; final String utfEncoding = "UTF-8"; // get repository id List repositories = withCmisService(new CmisServiceCallback>() { @Override public List execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); return repositories; } }); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); final String repositoryId = repo.getId(); // create simple text plain content final PropertiesImpl properties = new PropertiesImpl(); String objectTypeId = "cmis:document"; properties.addProperty(new PropertyIdImpl(PropertyIds.OBJECT_TYPE_ID, objectTypeId)); String fileName = "textFile" + GUID.generate(); properties.addProperty(new PropertyStringImpl(PropertyIds.NAME, fileName)); final ContentStreamImpl contentStream = new ContentStreamImpl(fileName, MimetypeMap.MIMETYPE_TEXT_PLAIN, "Simple text plain document"); String objectId = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { String objectId = cmisService.create(repositoryId, properties, repositoryHelper.getCompanyHome().getId(), contentStream, VersioningState.MAJOR, null, null); return objectId; } }); final Holder objectIdHolder = new Holder(objectId); final String path = "/" + fileName; // create content stream with undefined mimetype and file name { final ContentStreamImpl contentStreamHTML = new ContentStreamImpl(null, null, " Hello

Test html

"); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { cmisService.setContentStream(repositoryId, objectIdHolder, true, null, contentStreamHTML, null); return null; } }); // check mimetype ObjectData objectData = withCmisService(new CmisServiceCallback() { @Override public ObjectData execute(CmisService cmisService) { return cmisService.getObjectByPath(repositoryId, path, null, false, IncludeRelationships.NONE, null, false, false, null); } }); final String objectId1 = objectData.getId(); String contentType = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { String contentType = cmisService.getObjectInfo(repositoryId, objectId1).getContentType(); return contentType; } }); assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_HTML, contentType); // check that the encoding is detected correctly checkEncoding(ffs, authenticationComponent, objectData, utfEncoding); } // create content stream with mimetype and encoding as UTF-8 { String mimeType = MimetypeMap.MIMETYPE_TEXT_PLAIN + "; charset="+isoEncoding; // NOTE that we intentionally specify the wrong charset here. // Alfresco will detect the encoding (as UTF-8 - given by the ContentStreamImpl constructor) final ContentStreamImpl contentStreamHTML = new ContentStreamImpl(null, mimeType, " Hello

Test html

"); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { Holder latestObjectIdHolder = getHolderOfObjectOfLatestVersion(cmisService, repositoryId, objectIdHolder); cmisService.setContentStream(repositoryId, latestObjectIdHolder, true, null, contentStreamHTML, null); return null; } }); // check mimetype final ObjectData objectData = withCmisService(new CmisServiceCallback() { @Override public ObjectData execute(CmisService cmisService) { ObjectData objectData = cmisService.getObjectByPath(repositoryId, path, null, false, IncludeRelationships.NONE, null, false, false, null); return objectData; } }); String contentType = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { String contentType = cmisService.getObjectInfo(repositoryId, objectData.getId()).getContentType(); return contentType; } }); assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_TEXT_PLAIN, contentType); // check that the encoding is detected correctly checkEncoding(ffs, authenticationComponent, objectData, utfEncoding); } // create content stream with mimetype and encoding as ISO-8859-1 { String mimeType = MimetypeMap.MIMETYPE_TEXT_PLAIN + "; charset=" + utfEncoding; // NOTE that we intentionally specify the wrong charset here. // Alfresco will detect the encoding (as ISO-8859-1 - given by the ContentStreamImpl with streams) String content = "aegif Mind Share Leader Generating New Paradigms by aegif corporation

Test html

"; byte[] buf = null; try { buf = content.getBytes(isoEncoding); // set the encoding here for the content stream } catch (UnsupportedEncodingException e) { e.printStackTrace(); } ByteArrayInputStream input = new ByteArrayInputStream(buf); final ContentStream contentStreamHTML = new ContentStreamImpl(null, BigInteger.valueOf(buf.length), mimeType, input); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { Holder latestObjectIdHolder = getHolderOfObjectOfLatestVersion(cmisService, repositoryId, objectIdHolder); cmisService.setContentStream(repositoryId, latestObjectIdHolder, true, null, contentStreamHTML, null); return null; } }); // check mimetype final ObjectData objectData = withCmisService(new CmisServiceCallback() { @Override public ObjectData execute(CmisService cmisService) { ObjectData objectData = cmisService.getObjectByPath(repositoryId, path, null, false, IncludeRelationships.NONE, null, false, false, null); return objectData; } }); String contentType = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { String contentType = cmisService.getObjectInfo(repositoryId, objectData.getId()).getContentType(); return contentType; } }); assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_TEXT_PLAIN, contentType); // check that the encoding is detected correctly checkEncoding(ffs, authenticationComponent, objectData, isoEncoding); } // checkout/checkin object with mimetype and encoding { ObjectData objectDa = withCmisService(new CmisServiceCallback() { @Override public ObjectData execute(CmisService cmisService) { return cmisService.getObjectByPath(repositoryId, path, null, false, IncludeRelationships.NONE, null, false, false, null); } }); objectIdHolder.setValue(objectDa.getId()); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { cmisService.checkOut(repositoryId, objectIdHolder, null, new Holder()); return null; } }); String mimeType = MimetypeMap.MIMETYPE_HTML + "; charset=UTF-8"; final ContentStreamImpl contentStreamHTML = new ContentStreamImpl(null, mimeType, " Hello

Test html

"); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { cmisService.checkIn(repositoryId, objectIdHolder, false, null, contentStreamHTML, "checkin", null, null, null, null); return null; } }); // check mimetype final ObjectData objectData = withCmisService(new CmisServiceCallback() { @Override public ObjectData execute(CmisService cmisService) { ObjectData objectData = cmisService.getObjectByPath(repositoryId, path, null, false, IncludeRelationships.NONE, null, false, false, null); return objectData; } }); String contentType = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { String contentType = cmisService.getObjectInfo(repositoryId, objectData.getId()).getContentType(); return contentType; } }); assertEquals("Mimetype is not defined correctly.", MimetypeMap.MIMETYPE_HTML, contentType); checkEncoding(ffs, authenticationComponent, objectData, utfEncoding); } } protected void checkEncoding(FileFolderService ffs, AuthenticationComponent authenticationComponent, final ObjectData objectData, String expectedEncoding) { // Authenticate as system to check the properties in alfresco authenticationComponent.setSystemUserAsCurrentUser(); try { NodeRef doc1NodeRef = cmisIdToNodeRef(objectData.getId()); doc1NodeRef.getId(); FileInfo fileInfo = ffs.getFileInfo(doc1NodeRef); Map properties2 = fileInfo.getProperties(); ContentDataWithId contentData = (ContentDataWithId) properties2 .get(QName.createQName("{http://www.alfresco.org/model/content/1.0}content")); String encoding = contentData.getEncoding(); assertEquals(expectedEncoding, encoding); } finally { authenticationComponent.clearCurrentSecurityContext(); } } /** * Turns a CMIS id into a node ref * @param nodeId * @return */ private NodeRef cmisIdToNodeRef(String nodeId) { int idx = nodeId.indexOf(";"); if(idx != -1) { nodeId = nodeId.substring(0, idx); } NodeRef nodeRef = new NodeRef(nodeId); return nodeRef; } private Holder getHolderOfObjectOfLatestVersion(CmisService cmisService, String repositoryId, Holder currentHolder) { ObjectData oData = cmisService.getObjectOfLatestVersion(repositoryId, currentHolder.getValue(), null, Boolean.FALSE, null, null, null, null, null, null, null); return new Holder(oData.getId()); } /** * ALF-20389 Test Alfresco cmis stream interceptor that checks content stream for mimetype. Only ContentStreamImpl extensions should take palace. */ @Test public void testGetRepositoryInfos() { boolean cmisEx = false; List infoDataList = null; try { infoDataList = withCmisService(new CmisServiceCallback>() { @Override public List execute(CmisService cmisService) { ExtensionDataImpl result = new ExtensionDataImpl(); List extensions = new ArrayList(); result.setExtensions(extensions); return cmisService.getRepositoryInfos(result); } }); } catch (CmisRuntimeException e) { cmisEx = true; } assertNotNull(cmisEx ? "CmisRuntimeException was thrown. Please, take a look on ALF-20389" : "No CMIS repository information was retrieved", infoDataList); } private static class TestContext { private String repositoryId = null; @SuppressWarnings("unused") private ObjectData objectData = null; private Holder objectId = null; public TestContext() { super(); } public String getRepositoryId() { return repositoryId; } public void setRepositoryId(String repositoryId) { this.repositoryId = repositoryId; } public void setObjectData(ObjectData objectData) { this.objectData = objectData; } public Holder getObjectId() { return objectId; } public void setObjectId(Holder objectId) { this.objectId = objectId; } } /** * Test for ALF-16310. * * Check that, for AtomPub binding, cancel checkout on the originating checked out document i.e. not the working * copy throws an exception and does not delete the document. */ @SuppressWarnings("unchecked") @Test public void testCancelCheckout() { final TestContext testContext = new TestContext(); final String folderName = "testfolder." + GUID.generate(); final String docName = "testdoc.txt." + GUID.generate(); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { final FileInfo folderInfo = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public FileInfo execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); FileInfo fileInfo = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); nodeService.setProperty(fileInfo.getNodeRef(), ContentModel.PROP_NAME, docName); return folderInfo; } }); final ObjectData objectData = withCmisService(new CmisServiceCallback() { @Override public ObjectData execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); testContext.setRepositoryId(repositoryId); ObjectData objectData = cmisService.getObjectByPath(repositoryId, "/" + folderName + "/" + docName, null, true, IncludeRelationships.NONE, null, false, true, null); testContext.setObjectData(objectData); // checkout Holder objectId = new Holder(objectData.getId()); testContext.setObjectId(objectId); cmisService.checkOut(repositoryId, objectId, null, new Holder(true)); return objectData; } }); // AtomPub cancel checkout withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { try { // check allowable actions ObjectData originalDoc = cmisService.getObject(testContext.getRepositoryId(), objectData.getId(), null, true, IncludeRelationships.NONE, null, false, true, null); AllowableActions allowableActions = originalDoc.getAllowableActions(); assertNotNull(allowableActions); assertFalse(allowableActions.getAllowableActions().contains(Action.CAN_DELETE_OBJECT)); // try to cancel the checkout cmisService.deleteObjectOrCancelCheckOut(testContext.getRepositoryId(), objectData.getId(), Boolean.TRUE, null); fail(); } catch(CmisConstraintException e) { // expected } return null; } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { // cancel checkout on pwc cmisService.deleteObjectOrCancelCheckOut(testContext.getRepositoryId(), testContext.getObjectId().getValue(), Boolean.TRUE, null); return null; } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { // get original document ObjectData originalDoc = cmisService.getObject(testContext.getRepositoryId(), objectData.getId(), null, true, IncludeRelationships.NONE, null, false, true, null); Map> properties = originalDoc.getProperties().getProperties(); PropertyData isVersionSeriesCheckedOutProp = (PropertyData)properties.get(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT); assertNotNull(isVersionSeriesCheckedOutProp); Boolean isVersionSeriesCheckedOut = isVersionSeriesCheckedOutProp.getFirstValue(); assertNotNull(isVersionSeriesCheckedOut); assertEquals(Boolean.FALSE, isVersionSeriesCheckedOut); return null; } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { // delete original document cmisService.deleteObject(testContext.getRepositoryId(), objectData.getId(), true, null); return null; } }); List children = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() { @Override public List execute() throws Throwable { List children = fileFolderService.list(folderInfo.getNodeRef()); return children; } }); assertEquals(0, children.size()); } finally { AuthenticationUtil.popAuthentication(); } } /** * Test for MNT-13366. */ @Test public void testDeleteTree() { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); FileInfo parentFolder = null; FileInfo childFolder1 = null; try { // Create a parent folder: parentFolder: String parentFolderName = "parentFolder" + GUID.generate(); parentFolder = createContent(parentFolderName, null, false); final NodeRef parentFolderNodeRef = parentFolder.getNodeRef(); final String parentFolderID = parentFolderNodeRef.getId(); // Create a child folder: parentFolder -> childFolder1: String childFolder1Name = "childFolder1" + GUID.generate(); childFolder1 = createContent(parentFolder, childFolder1Name, null, false); final NodeRef childFolder1NodeRef = childFolder1.getNodeRef(); // Create a child folder for previous child folder, which will contain a file: // parentFolder -> childFolder1 -> childFolder2 -> testdoc.txt String childFolder2Name = "childFolder2" + GUID.generate(); String docName = "testdoc.txt" + GUID.generate(); final NodeRef childFolder2NodeRef = createContent(childFolder1, childFolder2Name, docName, false).getNodeRef(); // Store a reference to the file "testdoc.txt" contained by childFolder2: List childFolder2FileList = fileFolderService.list(childFolder2NodeRef); final NodeRef childFolder2FileNodeRef = childFolder2FileList.get(0).getNodeRef(); List repositories = withCmisService(new CmisServiceCallback>() { @Override public List execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); return repositories; } }); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); final String repositoryId = repo.getId(); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { // CMIS delete tree: FailedToDeleteData failedItems = cmisService.deleteTree(repositoryId, parentFolderID, Boolean.TRUE, UnfileObject.DELETE, Boolean.TRUE, null); assertEquals(failedItems.getIds().size(), 0); // Reference to the archive root node (the trash-can): NodeRef archiveRootNode = nodeArchiveService.getStoreArchiveNode(repositoryHelper.getCompanyHome().getStoreRef()); // Get the archived ("canned") version of folders and file and check that hirarchy is correct: // ArchiveRoot -> archivedParentFolder -> archivedChildFolder1 -> archivedChildFolder2 -> archivedChildFolder2File. // Check parentFolder: NodeRef archivedParentFolderNodeRef = nodeArchiveService.getArchivedNode(parentFolderNodeRef); assertTrue(nodeService.getPrimaryParent(archivedParentFolderNodeRef).getParentRef().equals(archiveRootNode)); // Check childFolder1: NodeRef archivedChildFolder1NodeRef = nodeArchiveService.getArchivedNode(childFolder1NodeRef); assertTrue(nodeService.getPrimaryParent(archivedChildFolder1NodeRef).getParentRef().equals(archivedParentFolderNodeRef)); assertFalse(nodeService.getPrimaryParent(archivedChildFolder1NodeRef).getParentRef().equals(archiveRootNode)); // Check childFolder2: NodeRef archivedChildFolder2NodeRef = nodeArchiveService.getArchivedNode(childFolder2NodeRef); assertTrue(nodeService.getPrimaryParent(archivedChildFolder2NodeRef).getParentRef().equals(archivedChildFolder1NodeRef)); assertFalse(nodeService.getPrimaryParent(archivedChildFolder2NodeRef).getParentRef().equals(archiveRootNode)); // Check childFolder2's file ("testdoc.txt"): NodeRef archivedChildFolder2FileNodeRef = nodeArchiveService.getArchivedNode(childFolder2FileNodeRef); assertTrue(nodeService.getPrimaryParent(archivedChildFolder2FileNodeRef).getParentRef().equals(archivedChildFolder2NodeRef)); assertFalse(nodeService.getPrimaryParent(archivedChildFolder2FileNodeRef).getParentRef().equals(archiveRootNode)); return null; }; }); } finally { if (parentFolder != null && fileFolderService.exists(parentFolder.getNodeRef())) { fileFolderService.delete(parentFolder.getNodeRef()); } AuthenticationUtil.popAuthentication(); } } /** * Test for ALF-18151. */ @Test public void testDeleteFolder() { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); final Map testFolderMap = new HashMap(4); try { // create folder with file String folderName = "testfolder" + GUID.generate(); String docName = "testdoc.txt" + GUID.generate(); FileInfo folder = createContent(folderName, docName, false); testFolderMap.put(folder, Boolean.FALSE); // create empty folder String folderNameEmpty = "testfolder_empty1" + GUID.generate(); FileInfo folderEmpty = createContent(folderNameEmpty, null, false); testFolderMap.put(folderEmpty, Boolean.TRUE); // create folder with file String folderNameRule = "testfolde_rule" + GUID.generate(); String docNameRule = "testdoc_rule.txt" + GUID.generate(); FileInfo folderWithRule = createContent(folderNameRule, docNameRule, true); testFolderMap.put(folderWithRule, Boolean.FALSE); // create empty folder String folderNameEmptyRule = "testfolde_empty_rule1" + GUID.generate(); FileInfo folderEmptyWithRule = createContent(folderNameEmptyRule, null, true); testFolderMap.put(folderEmptyWithRule, Boolean.TRUE); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); for (Map.Entry entry : testFolderMap.entrySet()) { ObjectData objectData = cmisService.getObjectByPath(repositoryId, "/" + entry.getKey().getName(), null, true, IncludeRelationships.NONE, null, false, true, null); Holder objectId = new Holder(objectData.getId()); try { // delete folder cmisService.deleteObjectOrCancelCheckOut(repositoryId, objectId.getValue(), Boolean.TRUE, null); } catch (CmisConstraintException ex) { assertTrue(!entry.getValue()); continue; } assertTrue(entry.getValue()); } return null; } }); } finally { for (Map.Entry entry : testFolderMap.entrySet()) { if (fileFolderService.exists(entry.getKey().getNodeRef())) { fileFolderService.delete(entry.getKey().getNodeRef()); } } AuthenticationUtil.popAuthentication(); } } /** * Test *
    *
  • MNT-8825: READ_ONLYLOCK prevent getAllVersions via new CMIS enpoint.
  • *
  • ACE-762: BM-0012: NodeLockedException not handled by CMIS
  • *
*/ @Test public void testOperationsOnReadOnlyLockedNode() { final String folderName = "testfolder." + GUID.generate(); final String docName = "testdoc.txt." + GUID.generate(); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); try { final FileInfo fileInfo = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public FileInfo execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); FileInfo fileInfo = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); nodeService.setProperty(fileInfo.getNodeRef(), ContentModel.PROP_NAME, docName); versionService.createVersion(fileInfo.getNodeRef(), new HashMap()); lockService.lock(fileInfo.getNodeRef(), LockType.READ_ONLY_LOCK, 0, true); return fileInfo; } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); ObjectData objectData = cmisService.getObjectByPath(repositoryId, "/" + folderName + "/" + docName, null, true, IncludeRelationships.NONE, null, false, true, null); // Expect no failure cmisService.getAllVersions(repositoryId, objectData.getId(), fileInfo.getNodeRef().getId(), null, true, null); return null; } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); ObjectData objectData = cmisService.getObjectByPath( repositoryId, "/" + folderName + "/" + docName, null, true, IncludeRelationships.NONE, null, false, true, null); String objectId = objectData.getId(); // Expect failure as the node is locked try { cmisService.deleteObject(repositoryId, objectId, true, null); fail("Locked node should not be deletable."); } catch (CmisUpdateConflictException e) { // Expected } return null; } }); } finally { AuthenticationUtil.popAuthentication(); } } /** * ALF-18455 */ @Test public void testOrderByCreationAndModificationDate() { final List nodes = new ArrayList(10); final List expectedChildrenByCreationDate = new ArrayList(10); final List expectedChildrenByModificationDate = new ArrayList(10); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public Void execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); String folderName = GUID.generate(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); assertNotNull(folderInfo); nodes.add(folderInfo); for(int i = 0; i < 5; i++) { String docName = GUID.generate(); FileInfo fileInfo = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); assertNotNull(fileInfo); nodeService.setProperty(fileInfo.getNodeRef(), ContentModel.PROP_NAME, docName); expectedChildrenByCreationDate.add(0, fileInfo); nodes.add(fileInfo); // make sure there is some difference in creation times Thread.sleep(400); } // make modifications for(int i = 5; i > 0; i--) { FileInfo fileInfo = nodes.get(i); assertNotNull(fileInfo); nodeService.setProperty(fileInfo.getNodeRef(), ContentModel.PROP_DESCRIPTION, GUID.generate()); // "refresh" fileInfo fileInfo = fileFolderService.getFileInfo(fileInfo.getNodeRef()); assertNotNull(fileInfo); expectedChildrenByModificationDate.add(0, fileInfo); // make sure there is some difference in modification times Thread.sleep(400); } return null; } }); } finally { AuthenticationUtil.popAuthentication(); } withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { // get repository id List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); String folderId = nodes.get(0).getNodeRef().getId(); String orderBy = PropertyIds.CREATION_DATE + " DESC"; ObjectInFolderList children = cmisService.getChildren(repositoryId, folderId, null, orderBy, false, IncludeRelationships.NONE, null, false, BigInteger.valueOf(Integer.MAX_VALUE), BigInteger.valueOf(0), null); int i = 0; for(ObjectInFolderData child : children.getObjects()) { Map> properties = child.getObject().getProperties().getProperties(); PropertyData pObjectId = properties.get(PropertyIds.VERSION_SERIES_ID); String actualObjectId = (String)pObjectId.getFirstValue(); PropertyData pCreationDate = properties.get(PropertyIds.CREATION_DATE); GregorianCalendar actualCreationDate = (GregorianCalendar)pCreationDate.getFirstValue(); FileInfo expectedChild = expectedChildrenByCreationDate.get(i++); assertEquals(expectedChild.getNodeRef().toString(), actualObjectId); assertEquals(expectedChild.getCreatedDate().getTime(), actualCreationDate.getTimeInMillis()); } orderBy = PropertyIds.LAST_MODIFICATION_DATE + " DESC"; children = cmisService.getChildren(repositoryId, folderId, null, orderBy, false, IncludeRelationships.NONE, null, false, BigInteger.valueOf(Integer.MAX_VALUE), BigInteger.valueOf(0), null); i = 0; for(ObjectInFolderData child : children.getObjects()) { Map> properties = child.getObject().getProperties().getProperties(); PropertyData pObjectId = properties.get(PropertyIds.VERSION_SERIES_ID); String actualObjectId = (String)pObjectId.getFirstValue(); PropertyData pModificationDate = properties.get(PropertyIds.LAST_MODIFICATION_DATE); GregorianCalendar actualModificationDate = (GregorianCalendar)pModificationDate.getFirstValue(); FileInfo expectedChild = expectedChildrenByModificationDate.get(i++); assertEquals(expectedChild.getNodeRef().toString(), actualObjectId); assertEquals(expectedChild.getModifiedDate().getTime(), actualModificationDate.getTimeInMillis()); } return null; } }); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testSecondaryTypes() { final String aspectName = "P:cm:indexControl"; // get repository id final String repositoryId = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); final String repositoryId = repo.getId(); return repositoryId; } }, CmisVersion.CMIS_1_1); final String objectId = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { final PropertiesImpl properties = new PropertiesImpl(); String objectTypeId = "cmis:document"; properties.addProperty(new PropertyIdImpl(PropertyIds.OBJECT_TYPE_ID, objectTypeId)); String fileName = "textFile" + GUID.generate(); properties.addProperty(new PropertyStringImpl(PropertyIds.NAME, fileName)); final ContentStreamImpl contentStream = new ContentStreamImpl(fileName, MimetypeMap.MIMETYPE_TEXT_PLAIN, "Simple text plain document"); String objectId = cmisService.create(repositoryId, properties, repositoryHelper.getCompanyHome().getId(), contentStream, VersioningState.MAJOR, null, null); return objectId; } }, CmisVersion.CMIS_1_1); final Holder objectIdHolder = new Holder(objectId); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { final PropertiesImpl properties = new PropertiesImpl(); properties.addProperty(new PropertyStringImpl(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, Arrays.asList(aspectName))); cmisService.updateProperties(repositoryId, objectIdHolder, null, properties, null); return null; } }, CmisVersion.CMIS_1_1); final Properties currentProperties = withCmisService(new CmisServiceCallback() { @Override public Properties execute(CmisService cmisService) { Properties properties = cmisService.getProperties(repositoryId, objectIdHolder.getValue(), null, null); return properties; } }, CmisVersion.CMIS_1_1); List secondaryTypeIds = (List) currentProperties.getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues(); assertTrue(secondaryTypeIds.contains(aspectName)); // We don't actually want to add these! (REPO-2926) final Set sysAspectsToAdd = new HashSet<>(Arrays.asList( "P:sys:undeletable", "P:sys:hidden")); // Pre-condition of further test is that these aspects are not present assertEquals(0, secondaryTypeIds.stream().filter(sysAspectsToAdd::contains).count()); // We also want to check that existing sys aspects aren't accidentally removed assertTrue(secondaryTypeIds.contains("P:sys:localized")); // Check we can remove an aspect - through its absence secondaryTypeIds.remove(aspectName); // Check that attempts to update/add sys:* aspects are ignored secondaryTypeIds.addAll(sysAspectsToAdd); final PropertiesImpl newProperties = new PropertiesImpl(); newProperties.addProperty(new PropertyStringImpl(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, secondaryTypeIds)); final String updatedName = "My_new_name_"+UUID.randomUUID().toString(); newProperties.replaceProperty(new PropertyStringImpl(PropertyIds.NAME, updatedName)); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { Holder latestObjectIdHolder = getHolderOfObjectOfLatestVersion(cmisService, repositoryId, objectIdHolder); // This will result in aspectName being removed // but that shouldn't mean that, for example, a cmis:name prop update gets ignored (MNT-18340) cmisService.updateProperties(repositoryId, latestObjectIdHolder, null, newProperties, null); return null; } }, CmisVersion.CMIS_1_1); Properties currentProperties1 = withCmisService(new CmisServiceCallback() { @Override public Properties execute(CmisService cmisService) { Holder latestObjectIdHolder = getHolderOfObjectOfLatestVersion(cmisService, repositoryId, objectIdHolder); Properties properties = cmisService.getProperties(repositoryId, latestObjectIdHolder.getValue(), null, null); return properties; } }, CmisVersion.CMIS_1_1); secondaryTypeIds = (List) currentProperties1.getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues(); assertFalse(secondaryTypeIds.contains(aspectName)); assertEquals(updatedName, currentProperties1.getProperties().get(PropertyIds.NAME).getFirstValue()); // sys aspects must not be added through CMIS (REPO-2926) assertEquals(0, secondaryTypeIds.stream().filter(sysAspectsToAdd::contains).count()); // Check pre-existing sys aspects aren't accidentally removed assertTrue(secondaryTypeIds.contains("P:sys:localized")); } /** * Test for MNT-9089 */ @Test public void testIntegerBoudaries() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { final FileInfo fileInfo = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public FileInfo execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); QName testIntTypeQName = QName.createQName("http://testCMISIntegersModel/1.0/", "testintegerstype"); String folderName = GUID.generate(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); assertNotNull(folderInfo); String docName = GUID.generate(); FileInfo fileInfo = fileFolderService.create(folderInfo.getNodeRef(), docName, testIntTypeQName); assertNotNull(fileInfo); nodeService.setProperty(fileInfo.getNodeRef(), ContentModel.PROP_NAME, docName); return fileInfo; } }); // get repository id withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); String objectIdStr = fileInfo.getNodeRef().toString(); TypeDefinition typeDef = cmisService.getTypeDefinition(repositoryId, "D:tcim:testintegerstype", null); PropertyIntegerDefinitionImpl intNoBoundsTypeDef = (PropertyIntegerDefinitionImpl)typeDef.getPropertyDefinitions().get("tcim:int"); PropertyIntegerDefinitionImpl longNoBoundsTypeDef = (PropertyIntegerDefinitionImpl)typeDef.getPropertyDefinitions().get("tcim:long"); PropertyIntegerDefinitionImpl intWithBoundsTypeDef = (PropertyIntegerDefinitionImpl)typeDef.getPropertyDefinitions().get("tcim:intwithbounds"); PropertyIntegerDefinitionImpl longWithBoundsTypeDef = (PropertyIntegerDefinitionImpl)typeDef.getPropertyDefinitions().get("tcim:longwithbounds"); BigInteger minInteger = BigInteger.valueOf(Integer.MIN_VALUE); BigInteger maxInteger = BigInteger.valueOf(Integer.MAX_VALUE); BigInteger minLong = BigInteger.valueOf(Long.MIN_VALUE); BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); // test for default boundaries assertTrue(intNoBoundsTypeDef.getMinValue().equals(minInteger)); assertTrue(intNoBoundsTypeDef.getMaxValue().equals(maxInteger)); assertTrue(longNoBoundsTypeDef.getMinValue().equals(minLong)); assertTrue(longNoBoundsTypeDef.getMaxValue().equals(maxLong)); // test for pre-defined boundaries assertTrue(intWithBoundsTypeDef.getMinValue().equals(BigInteger.valueOf(-10L))); assertTrue(intWithBoundsTypeDef.getMaxValue().equals(BigInteger.valueOf(10L))); assertTrue(longWithBoundsTypeDef.getMinValue().equals(BigInteger.valueOf(-10L))); assertTrue(longWithBoundsTypeDef.getMaxValue().equals(BigInteger.valueOf(10L))); try // try to overfloat long without boundaries { BigInteger aValue = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.valueOf(1L)); setProperiesToObject(cmisService, repositoryId, objectIdStr, "tcim:long", aValue); fail(); } catch(Exception e) { assertTrue(e instanceof CmisConstraintException); } try // try to overfloat int without boundaries { BigInteger aValue = BigInteger.valueOf(Integer.MAX_VALUE).add(BigInteger.valueOf(1L)); setProperiesToObject(cmisService, repositoryId, objectIdStr, "tcim:int", aValue); fail(); } catch(Exception e) { assertTrue(e instanceof CmisConstraintException); } try // try to overfloat int with boundaries { BigInteger aValue = BigInteger.valueOf( 11l ); setProperiesToObject(cmisService, repositoryId, objectIdStr, "tcim:intwithbounds", aValue); fail(); } catch(Exception e) { assertTrue(e instanceof CmisConstraintException); } try // try to overfloat long with boundaries { BigInteger aValue = BigInteger.valueOf( 11l ); setProperiesToObject(cmisService, repositoryId, objectIdStr, "tcim:longwithbounds", aValue); fail(); } catch(Exception e) { assertTrue(e instanceof CmisConstraintException); } return null; } }, CmisVersion.CMIS_1_0); } catch(Exception e) { fail(e.getMessage()); } finally { AuthenticationUtil.popAuthentication(); } } private void setProperiesToObject(CmisService cmisService, String repositoryId, String objectIdStr, String propertyStr, BigInteger bigIntValue) throws CmisConstraintException{ Properties properties = cmisService.getProperties(repositoryId, objectIdStr, null, null); PropertyIntegerImpl pd = (PropertyIntegerImpl)properties.getProperties().get(propertyStr); pd.setValue(bigIntValue); Collection> propsList = new ArrayList>(); propsList.add(pd); Properties newProps = new PropertiesImpl(propsList); cmisService.updateProperties(repositoryId, new Holder(objectIdStr), null, newProps, null); } @Test public void testMNT9090() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { final FileInfo fileInfo = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public FileInfo execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); String folderName = GUID.generate(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); assertNotNull(folderInfo); String docName = GUID.generate(); FileInfo fileInfo = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); assertNotNull(fileInfo); nodeService.setProperty(fileInfo.getNodeRef(), ContentModel.PROP_NAME, docName); QName ASPECT_AUDIO = QName.createQName(NamespaceService.AUDIO_MODEL_1_0_URI, "audio"); Map aspectProperties = new HashMap(); nodeService.addAspect(fileInfo.getNodeRef(), ASPECT_AUDIO, aspectProperties); return fileInfo; } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { // get repository id List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); String objectIdStr = fileInfo.getNodeRef().toString(); Holder objectId = new Holder(objectIdStr); // try to overflow the value Object value = BigInteger.valueOf(Integer.MAX_VALUE + 1l); Properties properties = new PropertiesImpl(); List extensions = new ArrayList(); CmisExtensionElement valueElem = new CmisExtensionElementImpl(CMISConnector.ALFRESCO_EXTENSION_NAMESPACE, "value", null, value.toString()); List valueElems = new ArrayList(); valueElems.add(valueElem); List children = new ArrayList(); Map attributes = new HashMap(); attributes.put("propertyDefinitionId", "audio:trackNumber"); children.add(new CmisExtensionElementImpl(CMISConnector.ALFRESCO_EXTENSION_NAMESPACE, "propertyInteger", attributes, valueElems)); List propertyValuesExtension = new ArrayList(); propertyValuesExtension.add(new CmisExtensionElementImpl(CMISConnector.ALFRESCO_EXTENSION_NAMESPACE, CMISConnector.PROPERTIES, null, children)); CmisExtensionElement setAspectsExtension = new CmisExtensionElementImpl(CMISConnector.ALFRESCO_EXTENSION_NAMESPACE, CMISConnector.SET_ASPECTS, null, propertyValuesExtension); extensions.add(setAspectsExtension); properties.setExtensions(extensions); // should throw a CMISConstraintException cmisService.updateProperties(repositoryId, objectId, null, properties, null); fail(); return null; } }, CmisVersion.CMIS_1_0); } catch(CmisConstraintException e) { assertTrue(e.getMessage().startsWith("Value is out of range for property")); // ok } finally { AuthenticationUtil.popAuthentication(); } } /** * MNT-20139 * CmisConnector returns wrong values for changeLogToken and hasMoreItems */ @Test public void testGetContentChanges() { setupAudit(); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { // create folders with files createContent("testfolder" + GUID.generate(), "testdoc.txt" + GUID.generate(), false); createContent("testfolder" + GUID.generate(), "testdoc.txt" + GUID.generate(), false); createContent("testfolder" + GUID.generate(), "testdoc.txt" + GUID.generate(), false); Holder changeLogToken = new Holder(); /* * GetContentChanges with maxitems = 2 and null changeLogToken * Check that changeLogToken should be the latest from the retrieved entries */ ObjectList ol = this.cmisConnector.getContentChanges(changeLogToken, new BigInteger("2")); assertEquals(2, ol.getObjects().size()); assertEquals("ChangeLogToken should be latest from retrieved entries.", "2", changeLogToken.getValue()); assertTrue(ol.hasMoreItems()); /* * GetContentChanges with maxitems = 2 and changeLogToken = 0 * Check that changeLogToken should be the latest from the retrieved entries */ changeLogToken.setValue(Integer.toString(0)); ol = this.cmisConnector.getContentChanges(changeLogToken, new BigInteger("2")); assertEquals(2, ol.getObjects().size()); assertEquals("ChangeLogToken should be latest from retrieved entries.", "2", changeLogToken.getValue()); assertTrue(ol.hasMoreItems()); /* * GetContentChanges with changeLogToken = maxChangeLogToken - 2 * Check that changeLogToken is not null when the latest entries (fromToken) are retrieved */ Long latestToken = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { public Long execute() throws Exception { return Long.parseLong(cmisConnector.getRepositoryInfo(CmisVersion.CMIS_1_1).getLatestChangeLogToken()); } }, true, false); Long fromToken = latestToken - 2; changeLogToken.setValue(fromToken.toString()); ol = this.cmisConnector.getContentChanges(changeLogToken, new BigInteger("20")); assertEquals(3, ol.getObjects().size()); assertNotNull(changeLogToken.getValue()); assertEquals("ChangeLogToken should be the latest from all entries.", latestToken.toString(), changeLogToken.getValue()); assertFalse(ol.hasMoreItems()); } finally { auditSubsystem.destroy(); AuthenticationUtil.popAuthentication(); }; } /** * MNT-10223 * Check the IsLatestMajorVersion for a doc with minor version. */ @SuppressWarnings("unused") @Test public void testIsLatestMajorVersion() { final TestContext testContext = new TestContext(); // create simple text plain content final PropertiesImpl properties = new PropertiesImpl(); String objectTypeId = "cmis:document"; properties.addProperty(new PropertyIdImpl(PropertyIds.OBJECT_TYPE_ID, objectTypeId)); String fileName = "textFile" + GUID.generate(); properties.addProperty(new PropertyStringImpl(PropertyIds.NAME, fileName)); final ContentStreamImpl contentStream = new ContentStreamImpl(fileName, MimetypeMap.MIMETYPE_TEXT_PLAIN, "Simple text plain document"); withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); String objectId = cmisService.create(repositoryId, properties, repositoryHelper.getCompanyHome().getId(), contentStream, VersioningState.MINOR, null, null); ObjectData cmidDoc = cmisService.getObject(repositoryId, objectId, null, true, IncludeRelationships.NONE, null, false, false, null); List> properties = cmidDoc.getProperties().getPropertyList(); boolean found = false; PropertyData propIsLatestMajorVersion = null; for (PropertyData property : properties) { if (property.getId().equals(PropertyIds.IS_LATEST_MAJOR_VERSION)) { found = true; propIsLatestMajorVersion = property; break; } } //properties..contains(CMISDictionaryModel.PROP_IS_LATEST_MAJOR_VERSION); assertTrue("The CMISDictionaryModel.PROP_IS_LATEST_MAJOR_VERSION property was not found", found); if (found) { assertFalse("The CMISDictionaryModel.PROP_IS_LATEST_MAJOR_VERSION should be false as minor version was created", (Boolean) propIsLatestMajorVersion.getValues().get(0)); } return objectId; } }); } /** * ACE-33 * * Cmis Item support */ @Test public void testItems() { withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); TypeDefinition def = cmisService.getTypeDefinition(repositoryId, "cmis:item", null); assertNotNull("the cmis:item type is not defined", def); @SuppressWarnings("unused") TypeDefinition p = cmisService.getTypeDefinition(repositoryId, "I:cm:person", null); assertNotNull("the I:cm:person type is not defined", def); ObjectList result = cmisService.query(repositoryId, "select * from cm:person", Boolean.FALSE, Boolean.TRUE, IncludeRelationships.NONE, "", BigInteger.TEN, BigInteger.ZERO, null); assertTrue("", result.getNumItems().intValue() > 0); return ""; }; }, CmisVersion.CMIS_1_1); } /** * MNT-11339 related test : * Unable to create relationship between cmis:document and cmis:item */ @Test public void testItemRelations() { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); final String TEST_NAME = "testItemRelations-"; final String FOLDER_NAME = TEST_NAME + "FOLDER" + GUID.generate(); final String DOCUMENT_NAME = TEST_NAME + "DOCUMENT" + GUID.generate(); final String CLIENT_NAME = "Some Test Client " + GUID.generate(); try { transactionService.getRetryingTransactionHelper().doInTransaction( new RetryingTransactionCallback() { @Override public Void execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); /* Create folder within companyHome */ FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, FOLDER_NAME, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, FOLDER_NAME); assertNotNull(folderInfo); // and document FileInfo document = fileFolderService.create(folderInfo.getNodeRef(), DOCUMENT_NAME, ContentModel.TYPE_CONTENT); assertNotNull(document); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOCUMENT_NAME); return null; } }); withCmisService(new CmisServiceCallback() { @SuppressWarnings("unchecked") @Override public String execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); // ensure there are custom type, aspect and association defined TypeDefinition tpdfn = cmisService.getTypeDefinition(repositoryId, "I:sctst:client", null); assertNotNull("the I:sctst:client type is not defined", tpdfn); TypeDefinition aspectDfn = cmisService.getTypeDefinition(repositoryId, "P:sctst:clientRelated", null); assertNotNull("the P:sctst:clientRelated aspect is not defined", aspectDfn); TypeDefinition relDfn = cmisService.getTypeDefinition(repositoryId, "R:sctst:relatedClients", null); assertNotNull("the R:sctst:relatedClients association is not defined", relDfn); // create cmis:item within test folder PropertiesImpl properties = new PropertiesImpl(); properties.addProperty(new PropertyIdImpl(PropertyIds.OBJECT_TYPE_ID, tpdfn.getId())); properties.addProperty(new PropertyStringImpl(PropertyIds.NAME, CLIENT_NAME)); properties.addProperty(new PropertyStringImpl("sctst:clientId", "id" + GUID.generate())); properties.addProperty(new PropertyStringImpl("sctst:clientName", CLIENT_NAME)); ObjectData folderData = cmisService.getObjectByPath(repositoryId, "/" + FOLDER_NAME, null, null, null, null, null, null, null); cmisService.createItem(repositoryId, properties, folderData.getId(), null, null, null, null); ObjectData contentData = cmisService.getObjectByPath(repositoryId, "/" + FOLDER_NAME + "/" + DOCUMENT_NAME, null, null, null, null, null, null, null); // add test aspect sctst:clientRelated to document Properties props = cmisService.getProperties(repositoryId, contentData.getId(), null, null); PropertyData propAspects = props.getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS); @SuppressWarnings("rawtypes") List aspects = propAspects.getValues(); aspects.add("P:sctst:clientRelated"); properties = new PropertiesImpl(); properties.addProperty(new PropertyStringImpl(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, aspects)); cmisService.updateProperties(repositoryId, new Holder(contentData.getId()), null, properties, null); // ensure document has sctst:clientRelated aspect applied aspects = cmisService.getProperties(repositoryId, contentData.getId(), null, null).getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues(); assertTrue("P:sctst:clientRelated excpected", aspects.contains("P:sctst:clientRelated")); ObjectData itemData = cmisService.getObjectByPath(repositoryId, "/" + FOLDER_NAME + "/" + CLIENT_NAME, null, null, null, null, null, null, null); // create relationship between cmis:document and cmis:item properties = new PropertiesImpl(); properties.addProperty(new PropertyIdImpl(PropertyIds.OBJECT_TYPE_ID, "R:sctst:relatedClients")); properties.addProperty(new PropertyIdImpl(PropertyIds.SOURCE_ID, contentData.getId())); properties.addProperty(new PropertyIdImpl(PropertyIds.TARGET_ID, itemData.getId())); cmisService.createRelationship(repositoryId, properties, null, null, null, null); return ""; }; }, CmisVersion.CMIS_1_1); } finally { AuthenticationUtil.popAuthentication(); } } @Test public void testMNT10529() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { final Pair folderAndDocument = transactionService.getRetryingTransactionHelper().doInTransaction( new RetryingTransactionCallback>() { @Override public Pair execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); String folderName = GUID.generate(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); assertNotNull(folderInfo); String docName = GUID.generate(); FileInfo document = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); assertNotNull(document); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, docName); return new Pair(folderInfo, document); } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertNotNull(repositories); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.iterator().next(); String repositoryId = repo.getId(); String objectIdStr = folderAndDocument.getFirst().getNodeRef().toString(); ObjectInFolderList children = cmisService.getChildren(repositoryId, objectIdStr, null, "cmis:name ASC", false, IncludeRelationships.NONE, null, false, null, null, null); assertChildren(folderAndDocument, children); children = cmisService.getChildren(repositoryId, objectIdStr, null, "cmis:name ASC, cmis:creationDate ASC", false, IncludeRelationships.NONE, null, false, null, null, null); assertChildren(folderAndDocument, children); children = cmisService.getChildren(repositoryId, objectIdStr, null, " cmis:name ASC", false, IncludeRelationships.NONE, null, false, null, null, null); assertChildren(folderAndDocument, children); children = cmisService.getChildren(repositoryId, objectIdStr, null, " cmis:name ASC, cmis:creationDate ASC ", false, IncludeRelationships.NONE, null, false, null, null, null); assertChildren(folderAndDocument, children); return null; } private void assertChildren(final Pair folderAndDocument, ObjectInFolderList children) { assertNotNull(children); assertTrue(1 == children.getNumItems().longValue()); PropertyData nameData = children.getObjects().iterator().next().getObject().getProperties().getProperties().get("cmis:name"); assertNotNull(nameData); Object name = nameData.getValues().iterator().next(); assertEquals(folderAndDocument.getSecond().getName(), name); } }, CmisVersion.CMIS_1_0); } catch (CmisConstraintException e) { fail(e.toString()); } finally { AuthenticationUtil.popAuthentication(); } } @Category(RedundantTests.class) @Test public void mnt10548test() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); final Pair folderAndDocument = transactionService.getRetryingTransactionHelper().doInTransaction( new RetryingTransactionCallback>() { private final static String TEST_NAME = "mnt10548test-"; @Override public Pair execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); /* Create folder within companyHome */ String folderName = TEST_NAME + GUID.generate(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); assertNotNull(folderInfo); /* Create content */ String docName = TEST_NAME + GUID.generate(); FileInfo document = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); assertNotNull(document); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, docName); /* Add some tags */ NodeRef nodeRef = document.getNodeRef(); taggingService.addTag(nodeRef, "tag1"); taggingService.addTag(nodeRef, "tag2"); taggingService.addTag(nodeRef, "tag3"); return new Pair(folderInfo, document); } }); ObjectData objData = withCmisService( new CmisServiceCallback() { private static final String FILE_FOLDER_SEPARATOR = "/"; @Override public ObjectData execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); String path = FILE_FOLDER_SEPARATOR + folderAndDocument.getFirst().getName() + FILE_FOLDER_SEPARATOR + folderAndDocument.getSecond().getName(); /* get CMIS object of document */ ObjectData objData = cmisService.getObjectByPath(repositoryId, path, null, false, null, null, false, false, null); return objData; } }, CmisVersion.CMIS_1_1); Map> cmisProps = objData.getProperties().getProperties(); String taggable = ContentModel.ASPECT_TAGGABLE.getPrefixedQName(namespaceService).toPrefixString(); PropertyData propData = cmisProps.get(taggable); assertNotNull(propData); List props = propData.getValues(); assertTrue(props.size() == 3); /* MNT-10548 fix : CMIS should return List of String, not List of NodeRef */ for(Object o : props) { assertTrue(o.getClass() + " found but String expected", o instanceof String); } } /** * MNT-8804 related test : * Check CMISConnector.query for search nodes in environment with corrupted indexes */ @Test public void testQueryNodesWithCorruptedIndexes() { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); final String TEST_NAME = "mnt8804test-"; final String docName = TEST_NAME + GUID.generate(); /* Create node */ final FileInfo document = transactionService.getRetryingTransactionHelper().doInTransaction( new RetryingTransactionCallback() { @Override public FileInfo execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); /* Create folder within companyHome */ String folderName = TEST_NAME + GUID.generate(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); assertNotNull(folderInfo); /* Create document to query */ FileInfo document = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); assertNotNull(document); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, docName); return document; } }); final Pair nodePair = nodeDAO.getNodePair(document.getNodeRef()); /* delete node's metadata directly */ transactionService.getRetryingTransactionHelper().doInTransaction( new RetryingTransactionCallback() { @Override public Void execute() throws Throwable { Pair childAssocPair = nodeDAO.getPrimaryParentAssoc(nodePair.getFirst()); nodeDAO.deleteChildAssoc(childAssocPair.getFirst()); nodeDAO.deleteNode(nodePair.getFirst()); return null; } }); /* ensure the node does not exist */ assertTrue(!nodeService.exists(nodePair.getSecond())); String queryString = "SELECT * FROM cmis:document WHERE cmis:name='" + docName + "'"; ObjectList resultList = cmisConnector.query(queryString, Boolean.FALSE, IncludeRelationships.NONE, "cmis:none", BigInteger.ONE, BigInteger.ZERO); assertEquals(resultList.getNumItems(), BigInteger.ZERO); // prepare cmis query CMISQueryOptions options = new CMISQueryOptions(queryString, cmisConnector.getRootStoreRef()); CmisVersion cmisVersion = cmisConnector.getRequestCmisVersion(); options.setCmisVersion(cmisVersion); options.setQueryMode(CMISQueryMode.CMS_WITH_ALFRESCO_EXTENSIONS); options.setSkipCount(0); options.setMaxItems(100); /* make query bypassing CMISConnector */ org.alfresco.opencmis.search.CMISResultSet rs = cmisConnector.getOpenCMISQueryService().query(options); assertEquals(rs.getNumberFound(), 0); } /** * CMIS 1.0 aspect properties should provide the following CMIS attributes: * propertyDefinitionId, displayName, localName, queryName */ @Test public void testMNT10021() throws Exception { final String folderName = "testfolder." + GUID.generate(); final String docName = "testdoc.txt." + GUID.generate(); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public Void execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); assertNotNull(folderInfo); FileInfo document = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); assertNotNull(document); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, docName); // lock adds aspects to the document with properties: lockIsDeep, lockOwner, lockType, expiryDate, lockLifetime lockService.lock(document.getNodeRef(), LockType.READ_ONLY_LOCK, 0, true); return null; } }); final ObjectData objectData = withCmisService(new CmisServiceCallback() { @Override public ObjectData execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); ObjectData objectData = cmisService.getObjectByPath(repositoryId, "/" + folderName + "/" + docName, null, true, IncludeRelationships.NONE, null, false, true, null); return objectData; } }, CmisVersion.CMIS_1_0); List propertyExtensionList = objectData.getProperties().getExtensions(); assertEquals("propertyExtensionList should be singletonList", propertyExtensionList.size(), 1); List extensions = propertyExtensionList.iterator().next().getChildren(); for (CmisExtensionElement extension : extensions) { if ("properties".equals(extension.getName())) { // check properties extension List propExtensions = extension.getChildren(); assertTrue("cmisObject should contain aspect properties", propExtensions.size() > 0); for (CmisExtensionElement prop : propExtensions) { Map cmisAspectProperty = prop.getAttributes(); Set cmisAspectPropertyNames = cmisAspectProperty.keySet(); assertTrue("propertyDefinitionId attribute should be present", cmisAspectPropertyNames.contains("propertyDefinitionId")); assertTrue("queryName attribute should be present", cmisAspectPropertyNames.contains("queryName")); // optional values that are present for test document assertTrue("displayName attribute should be present for property of test node", cmisAspectPropertyNames.contains("displayName")); assertTrue("localName attribute should be present for property of test node", cmisAspectPropertyNames.contains("localName")); assertEquals(cmisAspectPropertyNames.size(), 4); // check values for (String aspectPropertyName : cmisAspectPropertyNames) { String value = cmisAspectProperty.get(aspectPropertyName); assertTrue("value for " + aspectPropertyName + " should be present", value != null && value.length() > 0); } } } } } catch (CmisConstraintException e) { fail(e.toString()); } finally { AuthenticationUtil.popAuthentication(); } } @Test public void dictionaryTest() { TenantUtil.runAsUserTenant(new TenantRunAsWork() { @Override public Void doWork() throws Exception { M2Model customModel = M2Model.createModel( Thread.currentThread().getContextClassLoader(). getResourceAsStream("dictionary/dictionarydaotest_model1.xml")); dictionaryDAO.putModel(customModel); assertNotNull(cmisDictionaryService.findType("P:cm:dublincore")); TypeDefinitionWrapper td = cmisDictionaryService.findType("D:daotest1:type1"); assertNotNull(td); return null; } }, "user1", "tenant1"); TenantUtil.runAsUserTenant(new TenantRunAsWork() { @Override public Void doWork() throws Exception { assertNotNull(cmisDictionaryService.findType("P:cm:dublincore")); TypeDefinitionWrapper td = cmisDictionaryService.findType("D:daotest1:type1"); assertNull(td); return null; } }, "user2", "tenant2"); } /** * MNT-13529: Just-installed Alfresco does not return a CMIS latestChangeLogToken * * @throws Exception */ @Test public void testMNT13529() throws Exception { setupAudit(); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { // Delete the entries, it simulates just installed Alfresco for reproduce the issue final Long appId = auditSubsystem.getAuditApplicationByName("CMISChangeLog").getApplicationId(); RetryingTransactionCallback deletedCallback = new RetryingTransactionCallback() { public Void execute() throws Throwable { auditDAO.deleteAuditEntries(appId, null, null); return null; } }; transactionService.getRetryingTransactionHelper().doInTransaction(deletedCallback); // Retrieve initial latestChangeLogToken final String initialChangeLogToken = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertNotNull(repositories); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.iterator().next(); return repo.getLatestChangeLogToken(); } }, CmisVersion.CMIS_1_1); assertNotNull(initialChangeLogToken); assertEquals("0", initialChangeLogToken); } finally { auditSubsystem.destroy(); AuthenticationUtil.popAuthentication(); } } /** * MNT-11726: Test that {@link CMISChangeEvent} contains objectId of node in short form (without StoreRef). */ @Test public void testCMISChangeLogObjectIds() throws Exception { // setUp audit subsystem setupAudit(); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { final String changeToken = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertNotNull(repositories); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.iterator().next(); return repo.getLatestChangeLogToken(); } }, CmisVersion.CMIS_1_1); transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public Void execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); // perform CREATED, UPDATED, SECURITY, DELETED CMIS change type actions String folder = GUID.generate(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folder, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folder); assertNotNull(folderInfo); String content = GUID.generate(); FileInfo document = fileFolderService.create(folderInfo.getNodeRef(), content, ContentModel.TYPE_CONTENT); assertNotNull(document); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, content); permissionService.setPermission(document.getNodeRef(), "SomeAuthority", PermissionService.EXECUTE_CONTENT, true); fileFolderService.delete(document.getNodeRef()); fileFolderService.delete(folderInfo.getNodeRef()); return null; } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertNotNull(repositories); assertTrue(repositories.size() > 0); String repositoryId = repositories.iterator().next().getId(); ObjectList changes = cmisService.getContentChanges(repositoryId, new Holder(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(1000), null); for (ObjectData od : changes.getObjects()) { ChangeType changeType = od.getChangeEventInfo().getChangeType(); Object objectId = od.getProperties().getProperties().get("cmis:objectId").getValues().get(0); assertFalse("CMISChangeEvent " + changeType + " should store short form of objectId " + objectId, objectId.toString().contains(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE.toString())); } int expectAtLeast = changes.getObjects().size(); // We should also be able to query without passing in any limit changes = cmisService.getContentChanges(repositoryId, new Holder(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, null, null); assertTrue("Expected to still get changes", changes.getObjects().size() >= expectAtLeast); // and zero changes = cmisService.getContentChanges(repositoryId, new Holder(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(0), null); assertTrue("Expected to still get changes", changes.getObjects().size() >= expectAtLeast); // and one changes = cmisService.getContentChanges(repositoryId, new Holder(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(1), null); assertEquals("Expected to still get changes", changes.getObjects().size(), 1); // Integery.MAX_VALUE must be handled // This will limit the number to a sane value changes = cmisService.getContentChanges(repositoryId, new Holder(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(Integer.MAX_VALUE), null); assertTrue("Expected to still get changes", changes.getObjects().size() >= expectAtLeast); // but not negative try { changes = cmisService.getContentChanges(repositoryId, new Holder(changeToken), Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE, BigInteger.valueOf(-1), null); fail("Negative maxItems is expected to fail"); } catch (CmisInvalidArgumentException e) { // Expected } return null; } }, CmisVersion.CMIS_1_1); } finally { auditSubsystem.destroy(); AuthenticationUtil.popAuthentication(); } } private void setupAudit() { UserAuditFilter userAuditFilter = new UserAuditFilter(); userAuditFilter.setUserFilterPattern("System;.*"); userAuditFilter.afterPropertiesSet(); AuditComponent auditComponent = (AuditComponent) ctx.getBean("auditComponent"); auditComponent.setUserAuditFilter(userAuditFilter); AuditServiceImpl auditServiceImpl = (AuditServiceImpl) ctx.getBean("auditService"); auditServiceImpl.setAuditComponent(auditComponent); RetryingTransactionCallback initAudit = new RetryingTransactionCallback() { public Void execute() throws Exception { auditSubsystem.stop(); auditSubsystem.setProperty("audit.enabled", "true"); auditSubsystem.setProperty("audit.cmischangelog.enabled", "true"); auditSubsystem.start(); return null; } }; transactionService.getRetryingTransactionHelper().doInTransaction(initAudit, false, true); } /** * MNT-11727: move and rename operations should be shown as an UPDATE in the CMIS change log */ @Test public void testMoveRenameWithCMISshouldBeAuditedAsUPDATE() throws Exception { // setUp audit subsystem setupAudit(); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { assertTrue("Audit is not enabled", auditSubsystem.isAuditEnabled()); assertNotNull("CMIS audit is not enabled", auditSubsystem.getAuditApplicationByName("CMISChangeLog")); NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); String folder = GUID.generate(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folder, ContentModel.TYPE_FOLDER); final String actualToken = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { public String execute() throws Exception { return cmisConnector.getRepositoryInfo(CmisVersion.CMIS_1_1).getLatestChangeLogToken(); } }, true, false); String content = GUID.generate(); FileInfo document = fileFolderService.create(folderInfo.getNodeRef(), content, ContentModel.TYPE_CONTENT); assertNotNull(document); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, content); Holder changeLogToken = new Holder(); changeLogToken.setValue(actualToken); ObjectList changeLog = CMISTest.this.cmisConnector.getContentChanges(changeLogToken, new BigInteger("10")); List events = changeLog.getObjects(); int count = events.size(); // it should be 3 entries: 1 for previous folder create, 1 new CREATE (for document create) // and 1 NEW UPDATE assertEquals(3, count); assertEquals(events.get(0).getProperties().getPropertyList().get(0).getValues().get(0), folderInfo.getNodeRef().getId()); assertEquals(events.get(0).getChangeEventInfo().getChangeType(), ChangeType.CREATED); assertTrue(((String) events.get(1).getProperties().getPropertyList().get(0).getValues().get(0)).contains(document.getNodeRef().getId())); assertEquals(events.get(1).getChangeEventInfo().getChangeType(), ChangeType.CREATED); assertTrue(((String) events.get(2).getProperties().getPropertyList().get(0).getValues().get(0)).contains(document.getNodeRef().getId())); assertEquals(events.get(2).getChangeEventInfo().getChangeType(), ChangeType.UPDATED); // test rename final String actualToken2 = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { public String execute() throws Exception { return cmisConnector.getRepositoryInfo(CmisVersion.CMIS_1_1).getLatestChangeLogToken(); } }, true, false); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, content + "-updated"); changeLogToken = new Holder(); changeLogToken.setValue(actualToken2); changeLog = CMISTest.this.cmisConnector.getContentChanges(changeLogToken, new BigInteger("10")); events = changeLog.getObjects(); count = events.size(); assertEquals(2, count); assertEquals("Rename operation should be shown as an UPDATE in the CMIS change log", events.get(1).getChangeEventInfo().getChangeType(), ChangeType.UPDATED); // test move String targetFolder = GUID.generate(); FileInfo targetFolderInfo = fileFolderService.create(companyHomeNodeRef, targetFolder, ContentModel.TYPE_FOLDER); final String actualToken3 = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { public String execute() throws Exception { return cmisConnector.getRepositoryInfo(CmisVersion.CMIS_1_1).getLatestChangeLogToken(); } }, true, false); nodeService.moveNode(document.getNodeRef(), targetFolderInfo.getNodeRef(), ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS); changeLogToken = new Holder(); changeLogToken.setValue(actualToken3); changeLog = CMISTest.this.cmisConnector.getContentChanges(changeLogToken, new BigInteger("10")); events = changeLog.getObjects(); count = events.size(); assertEquals(2, count); assertEquals("Move operation should be shown as an UPDATE in the CMIS change log", events.get(1).getChangeEventInfo().getChangeType(), ChangeType.UPDATED); } finally { auditSubsystem.destroy(); AuthenticationUtil.popAuthentication(); } } /** * MNT-11304: Test that Alfresco has no default boundaries for decimals * @throws Exception */ @Test public void testDecimalDefaultBoundaries() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); TypeDefinition decimalTypeDef = cmisService.getTypeDefinition(repositoryId, "D:tcdm:testdecimalstype", null); PropertyDecimalDefinitionImpl floatNoBoundsTypeDef = (PropertyDecimalDefinitionImpl)decimalTypeDef.getPropertyDefinitions().get("tcdm:float"); PropertyDecimalDefinitionImpl doubleNoBoundsTypeDef = (PropertyDecimalDefinitionImpl)decimalTypeDef.getPropertyDefinitions().get("tcdm:double"); PropertyDecimalDefinitionImpl floatWithBoundsTypeDef = (PropertyDecimalDefinitionImpl)decimalTypeDef.getPropertyDefinitions().get("tcdm:floatwithbounds"); PropertyDecimalDefinitionImpl doubleWithBoundsTypeDef = (PropertyDecimalDefinitionImpl)decimalTypeDef.getPropertyDefinitions().get("tcdm:doublewithbounds"); // test that there is not default boundaries for decimals assertNull(floatNoBoundsTypeDef.getMinValue()); assertNull(floatNoBoundsTypeDef.getMaxValue()); assertNull(doubleNoBoundsTypeDef.getMinValue()); assertNull(doubleNoBoundsTypeDef.getMaxValue()); // test for pre-defined boundaries assertTrue(floatWithBoundsTypeDef.getMinValue().equals(BigDecimal.valueOf(-10f))); assertTrue(floatWithBoundsTypeDef.getMaxValue().equals(BigDecimal.valueOf(10f))); assertTrue(doubleWithBoundsTypeDef.getMinValue().equals(BigDecimal.valueOf(-10d))); assertTrue(doubleWithBoundsTypeDef.getMaxValue().equals(BigDecimal.valueOf(10d))); return null; } }, CmisVersion.CMIS_1_1); } finally { AuthenticationUtil.popAuthentication(); } } /** * MNT-11876 : Test that Alfresco CMIS 1.1 Implementation is returning aspect and aspect properties as extension data * @throws Exception */ @Test public void testExtensionDataIsReturnedViaCmis1_1() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); final String FOLDER = "testExtensionDataIsReturnedViaCmis1_1-" + GUID.generate(); final String CONTENT = FOLDER + "-file"; try { transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public Void execute() throws Throwable { // create folder FileInfo folderInfo = fileFolderService.create(repositoryHelper.getCompanyHome(), FOLDER, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, FOLDER); assertNotNull(folderInfo); // create document FileInfo document = fileFolderService.create(folderInfo.getNodeRef(), CONTENT, ContentModel.TYPE_CONTENT); assertNotNull(document); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, CONTENT); // apply aspect with properties Map props = new HashMap(); props.put(ContentModel.PROP_LATITUDE, Double.valueOf(1.0d)); props.put(ContentModel.PROP_LONGITUDE, Double.valueOf(1.0d)); nodeService.addAspect(document.getNodeRef(), ContentModel.ASPECT_GEOGRAPHIC, props); return null; } }); final ObjectData objectData = withCmisService(new CmisServiceCallback() { @Override public ObjectData execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); // get object data ObjectData objectData = cmisService.getObjectByPath(repositoryId, "/" + FOLDER + "/" + CONTENT, null, true, IncludeRelationships.NONE, null, false, true, null); return objectData; } }, CmisVersion.CMIS_1_1); // get extension data from object properties List extensions = objectData.getProperties().getExtensions().iterator().next().getChildren(); Set appliedAspects = new HashSet(); Set aspectProperties = new HashSet(); for (CmisExtensionElement extension : extensions) { if (CMISConnector.PROPERTIES.equals(extension.getName())) { // check properties extension List propExtensions = extension.getChildren(); assertTrue("cmisObject should contain aspect properties", propExtensions.size() > 0); for (CmisExtensionElement prop : propExtensions) { Map cmisAspectProperty = prop.getAttributes(); Set cmisAspectPropertyNames = cmisAspectProperty.keySet(); assertTrue("propertyDefinitionId attribute should be present", cmisAspectPropertyNames.contains("propertyDefinitionId")); aspectProperties.add(cmisAspectProperty.get("propertyDefinitionId")); } } else if (CMISConnector.APPLIED_ASPECTS.equals(extension.getName())) { appliedAspects.add(extension.getValue()); } } // extension data should contain applied aspects and aspect properties assertTrue("Extensions should contain " + ContentModel.ASPECT_GEOGRAPHIC, appliedAspects.contains("P:cm:geographic")); assertTrue("Extensions should contain " + ContentModel.PROP_LATITUDE, aspectProperties.contains("cm:latitude")); assertTrue("Extensions should contain " + ContentModel.PROP_LONGITUDE, aspectProperties.contains("cm:longitude")); } finally { AuthenticationUtil.popAuthentication(); } } /** * MNT-10165: Check that all concomitant basic CMIS permissions are deleted * when permission is deleted vai CMIS 1.1 API. For Atom binding it applies * new set of permissions instead of deleting the old ones. */ @Test public void testRemoveACL() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); final String groupName = "group" + GUID.generate(); final String testGroup = PermissionService.GROUP_PREFIX + groupName; try { // preconditions: create test document if (!authorityService.authorityExists(testGroup)) { authorityService.createAuthority(AuthorityType.GROUP, groupName); } final FileInfo document = transactionService.getRetryingTransactionHelper().doInTransaction( new RetryingTransactionCallback() { @Override public FileInfo execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); String folderName = GUID.generate(); FileInfo folderInfo = fileFolderService.create(companyHomeNodeRef, folderName, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, folderName); assertNotNull(folderInfo); String docName = GUID.generate(); FileInfo document = fileFolderService.create(folderInfo.getNodeRef(), docName, ContentModel.TYPE_CONTENT); assertNotNull(document); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, docName); return document; } }); Set permissions = permissionService.getAllSetPermissions(document.getNodeRef()); assertEquals(permissions.size(), 1); AccessPermission current = permissions.iterator().next(); assertEquals(current.getAuthority(), "GROUP_EVERYONE"); assertEquals(current.getPermission(), "Consumer"); // add group1 with Coordinator permissions permissionService.setPermission(document.getNodeRef(), testGroup, PermissionService.COORDINATOR, true); permissions = permissionService.getAllSetPermissions(document.getNodeRef()); Map docPermissions = new HashMap(); for (AccessPermission permission : permissions) { docPermissions.put(permission.getAuthority(), permission.getPermission()); } assertTrue(docPermissions.keySet().contains(testGroup)); assertEquals(docPermissions.get(testGroup), PermissionService.COORDINATOR); // update permissions for group1 via CMIS 1.1 API withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertNotNull(repositories); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.iterator().next(); String repositoryId = repo.getId(); String docIdStr = document.getNodeRef().toString(); // when removing Coordinator ACE there are only inherited permissions // so empty list of direct permissions is sent to be set AccessControlListImpl acesToPut = new AccessControlListImpl(); List acesList = Collections.emptyList(); acesToPut.setAces(acesList); cmisService.applyAcl(repositoryId, docIdStr, acesToPut, AclPropagation.REPOSITORYDETERMINED); return null; } }, CmisVersion.CMIS_1_1); // check that permissions are the same as they were before Coordinator was added permissions = permissionService.getAllSetPermissions(document.getNodeRef()); docPermissions = new HashMap(); for (AccessPermission permission : permissions) { docPermissions.put(permission.getAuthority(), permission.getPermission()); } assertFalse(docPermissions.keySet().contains(testGroup)); assertEquals(permissions.size(), 1); current = permissions.iterator().next(); assertEquals(current.getAuthority(), "GROUP_EVERYONE"); assertEquals(current.getPermission(), "Consumer"); } catch (CmisConstraintException e) { fail(e.toString()); } finally { if (authorityService.authorityExists(testGroup)) { authorityService.deleteAuthority(testGroup); } AuthenticationUtil.popAuthentication(); } } /** * ACE-2904 */ @Test public void testACE2904() { // Basic CMIS Types // Additional types from Content Model final String[] types = { "cmis:document", "cmis:relationship", "cmis:folder", "cmis:policy", "cmis:item", "R:cm:replaces", "P:cm:author", "I:cm:cmobject" }; final String[] displayNames = { "Document", "Relationship", "Folder", "Policy", "Item Type", "Replaces", "Author", "Object" }; final String[] descriptions = { "Document Type", "Relationship Type", "Folder Type", "Policy Type", "CMIS Item", "Replaces", "Author", "I:cm:cmobject" }; CmisServiceCallback callback = new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); String repositoryId = repo.getId(); for (int i = 0; i < types.length; i++) { TypeDefinition def = cmisService.getTypeDefinition(repositoryId, types[i], null); assertNotNull("The " + types[i] + " type is not defined", def); assertNotNull("The display name is incorrect. Please, refer to ACE-2904.", def.getDisplayName()); assertEquals("The display name is incorrect. Please, refer to ACE-2904.", def.getDisplayName(), displayNames[i]); assertEquals("The description is incorrect. Please, refer to ACE-2904.", def.getDescription(), descriptions[i]); for (PropertyDefinition property : def.getPropertyDefinitions().values()) { assertNotNull("Property definition dispaly name is incorrect. Please, refer to ACE-2904.", property.getDisplayName()); assertNotNull("Property definition description is incorrect. Please, refer to ACE-2904.", property.getDescription()); } } return ""; }; }; // Lets test types for cmis 1.1 and cmis 1.0 withCmisService(callback, CmisVersion.CMIS_1_1); withCmisService(callback, CmisVersion.CMIS_1_0); } /** * ACE-3322 */ @Test public void testACE3322() { final String[] types = { "cmis:document", "cmis:relationship", "cmis:folder", "cmis:item" }; CmisServiceCallback callback = new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { for (int i = 0; i < types.length; i++) { List baseTypes = cmisDictionaryService.getBaseTypes(); assertNotNull(baseTypes); checkDefs(baseTypes); List children = cmisDictionaryService.getChildren(types[i]); assertNotNull(children); // Check that children were updated checkDefs(children); } return ""; }; private void checkDefs(List defs) { for (TypeDefinitionWrapper def : defs) { assertNotNull("Type definition was not updated. Please refer to ACE-3322", def.getTypeDefinition(false).getDisplayName()); assertNotNull("Type definition was not updated. Please refer to ACE-3322", def.getTypeDefinition(false).getDescription()); // Check that property's display name and description were updated for (PropertyDefinitionWrapper property : def.getProperties()) { assertNotNull("Display name is null", property.getPropertyDefinition().getDisplayName()); assertNotNull("Description is null", property.getPropertyDefinition().getDescription()); } } } }; withCmisService(callback, CmisVersion.CMIS_1_1); } /** * Test auto version behavior for setContentStream, deleteContentStream and appendContentStream according to ALF-21852. */ @Test public void testSetDeleteAppendContentStreamVersioning() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); final String DOC1 = "documentProperties1-" + GUID.generate(); try { final FileInfo doc = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public FileInfo execute() throws Throwable { FileInfo document; // create document document = fileFolderService.create(repositoryHelper.getCompanyHome(), DOC1, ContentModel.TYPE_CONTENT); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOC1); Map props = new HashMap(); props.put(ContentModel.PROP_TITLE, "Initial Title"); props.put(ContentModel.PROP_DESCRIPTION, "Initial Description"); nodeService.addAspect(document.getNodeRef(), ContentModel.ASPECT_TITLED, props); // apply versionable aspect with properties props = new HashMap(); // ContentModel.PROP_INITIAL_VERSION always true props.put(ContentModel.PROP_INITIAL_VERSION, true); props.put(ContentModel.PROP_AUTO_VERSION, true); props.put(ContentModel.PROP_AUTO_VERSION_PROPS, true); versionService.ensureVersioningEnabled(document.getNodeRef(), props); return document; } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { final String documentNodeRefId = doc.getNodeRef().toString(); final String repositoryId = cmisService.getRepositoryInfos(null).get(0).getId(); ObjectInfo objInfoInitialVersion = cmisService.getObjectInfo(repositoryId, documentNodeRefId); assertTrue("We had just created the document - it should be version 1.0", objInfoInitialVersion.getId().endsWith("1.0")); ContentStreamImpl contentStream = new ContentStreamImpl(null, MimetypeMap.MIMETYPE_TEXT_PLAIN, "Content " + GUID.generate()); Holder objectIdHolder = new Holder<>(documentNodeRefId); // Test setContentStream cmisService.setContentStream(repositoryId, objectIdHolder, true, null, contentStream, null); assertTrue("The \"output\" parameter should returns the newly created version id: 1.1", objectIdHolder.getValue().endsWith("1.1")); // we can use this new version id to get information about the cmis object ObjectInfo objInfoAfterSetContentStream = cmisService.getObjectInfo(repositoryId, objectIdHolder.getValue()); assertTrue("The object info should reflect the version requested: 1.1", objInfoAfterSetContentStream.getId().endsWith("1.1")); // Test deleteContentStream cmisService.deleteContentStream(repositoryId, objectIdHolder, null, null); assertTrue("The \"output\" parameter should returns the newly created version id: 1.2", objectIdHolder.getValue().endsWith("1.2")); // we can use this new version id to get information about the cmis object objInfoAfterSetContentStream = cmisService.getObjectInfo(repositoryId, objectIdHolder.getValue()); assertTrue("The object info should reflect the version requested: 1.2", objInfoAfterSetContentStream.getId().endsWith("1.2")); // Test appendContentStream cmisService.appendContentStream(repositoryId, objectIdHolder, null, contentStream, true, null); assertTrue("The \"output\" parameter should returns the newly created version id: 1.3", objectIdHolder.getValue().endsWith("1.3")); // we can use this new version id to get information about the cmis object objInfoAfterSetContentStream = cmisService.getObjectInfo(repositoryId, objectIdHolder.getValue()); assertTrue("The object info should reflect the version requested: 1.3", objInfoAfterSetContentStream.getId().endsWith("1.3")); return null; } }, CmisVersion.CMIS_1_1); } finally { AuthenticationUtil.popAuthentication(); } } /** * Test to ensure auto version behavior for update properties, set and delete content using both Alfresco and CMIS perspectives. * Testing different combinations of cm:initialVersion, cm:autoVersion and cm:autoVersionOnUpdateProps properties *
* OnUpdateProperties MINOR version should be created if cm:initialVersion and cm:autoVersionOnUpdateProps are both TRUE *
* OnContentUpdate MINOR version should be created if cm:initialVersion and cm:autoVersion are both TRUE * * @throws Exception */ @Test public void testUpdatePropertiesSetDeleteContentVersioning() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); final String FOLDER = "testUpdatePropertiesSetDeleteContentVersioning-" + GUID.generate(); final String DOC1 = "documentProperties1-" + GUID.generate(); final String DOC2 = "documentProperties2-" + GUID.generate(); final String DOC3 = "documentProperties3-" + GUID.generate(); final String DOC4 = "documentProperties4-" + GUID.generate(); try { final List docs = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() { @Override public List execute() throws Throwable { // create folder FileInfo folderInfo = fileFolderService.create(repositoryHelper.getCompanyHome(), FOLDER, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, FOLDER); assertNotNull(folderInfo); FileInfo document; List docs = new ArrayList(); // create documents document = fileFolderService.create(folderInfo.getNodeRef(), DOC1, ContentModel.TYPE_CONTENT); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOC1); docs.add(document); document = fileFolderService.create(folderInfo.getNodeRef(), DOC2, ContentModel.TYPE_CONTENT); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOC2); docs.add(document); document = fileFolderService.create(folderInfo.getNodeRef(), DOC3, ContentModel.TYPE_CONTENT); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOC3); docs.add(document); document = fileFolderService.create(folderInfo.getNodeRef(), DOC4, ContentModel.TYPE_CONTENT); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOC4); docs.add(document); Map props = new HashMap(); props.put(ContentModel.PROP_TITLE, "Initial Title"); props.put(ContentModel.PROP_DESCRIPTION, "Initial Description"); for (FileInfo fileInfo : docs) { nodeService.addAspect(fileInfo.getNodeRef(), ContentModel.ASPECT_TITLED, props); } // apply versionable aspect with properties props = new HashMap(); // ContentModel.PROP_INITIAL_VERSION always true props.put(ContentModel.PROP_INITIAL_VERSION, true); props.put(ContentModel.PROP_AUTO_VERSION, false); props.put(ContentModel.PROP_AUTO_VERSION_PROPS, false); versionService.ensureVersioningEnabled(docs.get(0).getNodeRef(), props); props.put(ContentModel.PROP_AUTO_VERSION, false); props.put(ContentModel.PROP_AUTO_VERSION_PROPS, true); versionService.ensureVersioningEnabled(docs.get(1).getNodeRef(), props); props.put(ContentModel.PROP_AUTO_VERSION, true); props.put(ContentModel.PROP_AUTO_VERSION_PROPS, false); versionService.ensureVersioningEnabled(docs.get(2).getNodeRef(), props); props.put(ContentModel.PROP_AUTO_VERSION, true); props.put(ContentModel.PROP_AUTO_VERSION_PROPS, true); versionService.ensureVersioningEnabled(docs.get(3).getNodeRef(), props); return docs; } }); assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); assertVersions(docs.get(1).getNodeRef(), "1.0", VersionType.MAJOR); assertVersions(docs.get(2).getNodeRef(), "1.0", VersionType.MAJOR); assertVersions(docs.get(3).getNodeRef(), "1.0", VersionType.MAJOR); // update node properties using Alfresco transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() { @Override public List execute() throws Throwable { for (FileInfo fileInfo : docs) { Map props = nodeService.getProperties(fileInfo.getNodeRef()); props.put(ContentModel.PROP_DESCRIPTION, "description-" + GUID.generate()); props.put(ContentModel.PROP_TITLE, "title-" + GUID.generate()); nodeService.setProperties(fileInfo.getNodeRef(), props); } return null; } }); assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); assertVersions(docs.get(1).getNodeRef(), "1.1", VersionType.MINOR); assertVersions(docs.get(2).getNodeRef(), "1.0", VersionType.MAJOR); assertVersions(docs.get(3).getNodeRef(), "1.1", VersionType.MINOR); // update properties using CMIS perspective final String repositoryId = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { String repositoryId = cmisService.getRepositoryInfos(null).get(0).getId(); for (FileInfo fileInfo : docs) { PropertiesImpl properties = new PropertiesImpl(); properties.addProperty(new PropertyStringImpl(PropertyIds.DESCRIPTION, "description-" + GUID.generate())); cmisService.updateProperties(repositoryId, new Holder(fileInfo.getNodeRef().toString()), null, properties, null); } //This extra check was added due to MNT-16641. { PropertiesImpl properties = new PropertiesImpl(); properties.addProperty(new PropertyStringImpl(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, "P:cm:lockable")); Set existingAspects = nodeService.getAspects(docs.get(0).getNodeRef()); cmisService.updateProperties(repositoryId,new Holder(docs.get(0).getNodeRef().toString()), null, properties, null); Set updatedAspects = nodeService.getAspects(docs.get(0).getNodeRef()); updatedAspects.removeAll(existingAspects); assertEquals(ContentModel.ASPECT_LOCKABLE, updatedAspects.iterator().next()); } return repositoryId; } }, CmisVersion.CMIS_1_1); assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); assertVersions(docs.get(1).getNodeRef(), "1.2", VersionType.MINOR); assertVersions(docs.get(2).getNodeRef(), "1.0", VersionType.MAJOR); assertVersions(docs.get(3).getNodeRef(), "1.2", VersionType.MINOR); // CMIS setContentStream withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { for (FileInfo fileInfo : docs) { ContentStreamImpl contentStream = new ContentStreamImpl(null, MimetypeMap.MIMETYPE_TEXT_PLAIN, "Content " + GUID.generate()); cmisService.setContentStream(repositoryId, new Holder(fileInfo.getNodeRef().toString()), true, null, contentStream, null); } return null; } }, CmisVersion.CMIS_1_1); assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); assertVersions(docs.get(1).getNodeRef(), "1.2", VersionType.MINOR); assertVersions(docs.get(2).getNodeRef(), "1.1", VersionType.MINOR); assertVersions(docs.get(3).getNodeRef(), "1.3", VersionType.MINOR); // update content using Alfresco transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() { @Override public List execute() throws Throwable { for (FileInfo fileInfo : docs) { ContentWriter writer = contentService.getWriter(fileInfo.getNodeRef(), ContentModel.PROP_CONTENT, true); writer.putContent("Content " + GUID.generate()); } return null; } }); assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); assertVersions(docs.get(1).getNodeRef(), "1.2", VersionType.MINOR); assertVersions(docs.get(2).getNodeRef(), "1.2", VersionType.MINOR); assertVersions(docs.get(3).getNodeRef(), "1.4", VersionType.MINOR); // CMIS deleteContentStream withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { for (FileInfo fileInfo : docs) { cmisService.deleteContentStream(repositoryId, new Holder(fileInfo.getNodeRef().toString()), null, null); } return null; } }, CmisVersion.CMIS_1_1); assertVersions(docs.get(0).getNodeRef(), "1.0", VersionType.MAJOR); assertVersions(docs.get(1).getNodeRef(), "1.2", VersionType.MINOR); assertVersions(docs.get(2).getNodeRef(), "1.3", VersionType.MINOR); assertVersions(docs.get(3).getNodeRef(), "1.5", VersionType.MINOR); } finally { AuthenticationUtil.popAuthentication(); } } private void assertVersions(final NodeRef nodeRef, final String expectedVersionLabel, final VersionType expectedVersionType) { transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() { @Override public List execute() throws Throwable { assertTrue("Node should be versionable", nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)); Version version = versionService.getCurrentVersion(nodeRef); assertNotNull(version); assertEquals(expectedVersionLabel, version.getVersionLabel()); assertEquals(expectedVersionType, version.getVersionType()); return null; } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { String repositoryId = cmisService.getRepositoryInfos(null).get(0).getId(); ObjectData data = cmisService.getObjectOfLatestVersion(repositoryId, nodeRef.toString(), null, Boolean.FALSE, null, null, null, null, null, null, null); assertNotNull(data); PropertyData prop = data.getProperties().getProperties().get(PropertyIds.VERSION_LABEL); Object versionLabelCmisValue = prop.getValues().get(0); assertEquals(expectedVersionLabel, versionLabelCmisValue); return null; } }, CmisVersion.CMIS_1_1); } /** * Test to ensure that set of aspect returned by cmisService#getAllVersions for latest version is the same * as for the object returned by cmisService#getObjectByPath. * * See MNT-9557 */ @Test public void testLastVersionOfVersionSeries() { CallContext context = new SimpleCallContext("admin", "admin", CmisVersion.CMIS_1_0); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); final String FOLDER = "testUpdatePropertiesSetDeleteContentVersioning-" + GUID.generate(), DOC = "documentProperties-" + GUID.generate(); try { final NodeRef nodeRef = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public NodeRef execute() throws Throwable { // create folder FileInfo folderInfo = fileFolderService.create(repositoryHelper.getCompanyHome(), FOLDER, ContentModel.TYPE_FOLDER); nodeService.setProperty(folderInfo.getNodeRef(), ContentModel.PROP_NAME, FOLDER); assertNotNull(folderInfo); // create documents FileInfo document = fileFolderService.create(folderInfo.getNodeRef(), DOC, ContentModel.TYPE_CONTENT); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_NAME, DOC); nodeService.setProperty(document.getNodeRef(), ContentModel.PROP_DESCRIPTION, "Initial doc"); return document.getNodeRef(); } }); transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public Void execute() throws Throwable { // make sure that there is no version history yet assertNull(versionService.getVersionHistory(nodeRef)); // create a version // turn off auto-versioning Map props = new HashMap(); props.put(ContentModel.PROP_INITIAL_VERSION, false); props.put(ContentModel.PROP_AUTO_VERSION, false); props.put(ContentModel.PROP_AUTO_VERSION_PROPS, false); versionService.ensureVersioningEnabled(nodeRef, props); return null; } }); transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public Void execute() throws Throwable { assertNotNull(versionService.getVersionHistory(nodeRef)); // create another one version versionService.createVersion(nodeRef, null); return null; } }); final String NEW_DOC_NAME = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public String execute() throws Throwable { // add aspect to the node String newDocName = DOC + GUID.generate(); nodeService.addAspect(nodeRef, ContentModel.ASPECT_AUTHOR, null); nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, newDocName); return newDocName; } }); CmisService cmisService = factory.getService(context); String repositoryId = cmisService.getRepositoryInfos(null).get(0).getId(); List versions = cmisService.getAllVersions(repositoryId, nodeRef.toString(), null, null, null, null); assertNotNull(versions); // get the latest version ObjectData latestVersion = versions.get(0); // get the object ObjectData object = // cmisService.getObjectOfLatestVersion(repositoryId, nodeRef.toString(), null, false, null, null, null, null, false, false, null); cmisService.getObjectByPath(repositoryId, "/" + FOLDER + "/" + NEW_DOC_NAME, null, null, null, null, false, false, null); assertNotNull(latestVersion); assertNotNull(object); Object objectDescriptionString = object.getProperties().getProperties().get("cmis:name").getValues().get(0); Object latestVersionDescriptionString = latestVersion.getProperties().getProperties().get("cmis:name").getValues().get(0); // ensure that node and latest version both have same description assertEquals(objectDescriptionString, latestVersionDescriptionString); Set documentAspects = new HashSet(); for (CmisExtensionElement cmisEE : object.getProperties().getExtensions().get(0).getChildren()) { documentAspects.add(cmisEE.getValue()); } Set latestVersionAspects = new HashSet(); for (CmisExtensionElement cmisEE : latestVersion.getProperties().getExtensions().get(0).getChildren()) { latestVersionAspects.add(cmisEE.getValue()); } // ensure that node and latest version both have the same set of aspects assertEquals(latestVersionAspects, documentAspects); } finally { AuthenticationUtil.popAuthentication(); } } /** * Test to ensure that versioning properties have default values defined in Alfresco content model. * Testing cm:initialVersion, cm:autoVersion and cm:autoVersionOnUpdateProps properties * * @throws Exception */ @Test public void testVersioningPropertiesHaveDefaultValue() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { // Create document via CMIS final NodeRef documentNodeRef = withCmisService(new CmisServiceCallback() { @Override public NodeRef execute(CmisService cmisService) { String repositoryId = cmisService.getRepositoryInfos(null).get(0).getId(); String rootNodeId = cmisService.getObjectByPath(repositoryId, "/", null, true, IncludeRelationships.NONE, null, false, true, null).getId(); Collection> propsList = new ArrayList>(); propsList.add(new PropertyStringImpl(PropertyIds.NAME, "Folder-" + GUID.generate())); propsList.add(new PropertyIdImpl(PropertyIds.OBJECT_TYPE_ID, "cmis:folder")); String folderId = cmisService.createFolder(repositoryId, new PropertiesImpl(propsList), rootNodeId, null, null, null, null); propsList = new ArrayList>(); propsList.add(new PropertyStringImpl(PropertyIds.NAME, "File-" + GUID.generate())); propsList.add(new PropertyIdImpl(PropertyIds.OBJECT_TYPE_ID, "cmis:document")); String nodeId = cmisService.createDocument(repositoryId, new PropertiesImpl(propsList), folderId, null, null, null, null, null, null); return new NodeRef(nodeId.substring(0, nodeId.indexOf(';'))); } }, CmisVersion.CMIS_1_1); // check versioning properties transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() { @Override public List execute() throws Throwable { assertTrue(nodeService.exists(documentNodeRef)); assertTrue(nodeService.hasAspect(documentNodeRef, ContentModel.ASPECT_VERSIONABLE)); AspectDefinition ad = dictionaryService.getAspect(ContentModel.ASPECT_VERSIONABLE); Map properties = ad.getProperties(); for (QName qName : new QName[] {ContentModel.PROP_INITIAL_VERSION, ContentModel.PROP_AUTO_VERSION, ContentModel.PROP_AUTO_VERSION_PROPS}) { Serializable property = nodeService.getProperty(documentNodeRef, qName); assertNotNull(property); org.alfresco.service.cmr.dictionary.PropertyDefinition pd = properties.get(qName); assertNotNull(pd.getDefaultValue()); assertEquals(property, Boolean.parseBoolean(pd.getDefaultValue())); } return null; } }); } finally { AuthenticationUtil.popAuthentication(); } } @Test public void testCreateDocWithVersioningStateNone() throws Exception { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { // get repository id final String repositoryId = withCmisService(new CmisServiceCallback() { @Override public String execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertTrue(repositories.size() > 0); RepositoryInfo repo = repositories.get(0); final String repositoryId = repo.getId(); return repositoryId; } }, CmisVersion.CMIS_1_1); final NodeRef documentNodeRef = withCmisService(new CmisServiceCallback() { @Override public NodeRef execute(CmisService cmisService) { final PropertiesImpl properties = new PropertiesImpl(); String objectTypeId = "cmis:document"; properties.addProperty(new PropertyIdImpl(PropertyIds.OBJECT_TYPE_ID, objectTypeId)); String fileName = "textFile" + GUID.generate(); properties.addProperty(new PropertyStringImpl(PropertyIds.NAME, fileName)); final ContentStreamImpl contentStream = new ContentStreamImpl(fileName, MimetypeMap.MIMETYPE_TEXT_PLAIN, "Simple text plain document"); String nodeId = cmisService.create(repositoryId, properties, repositoryHelper.getCompanyHome().getId(), contentStream, VersioningState.NONE, null, null); return new NodeRef(nodeId.substring(0, nodeId.indexOf(';'))); } }, CmisVersion.CMIS_1_1); // check versioning properties transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback>() { @Override public List execute() throws Throwable { assertTrue(nodeService.exists(documentNodeRef)); assertFalse(nodeService.hasAspect(documentNodeRef, ContentModel.ASPECT_VERSIONABLE)); return null; } }); } finally { AuthenticationUtil.popAuthentication(); } } /** * MNT-14951: Test that the list of parents can be retrieved for a folder. */ @Test public void testCMISGetObjectParents() throws Exception { // setUp audit subsystem setupAudit(); AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { final NodeRef folderWithTwoParents = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public NodeRef execute() throws Throwable { NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); String folder1 = GUID.generate(); FileInfo folderInfo1 = fileFolderService.create(companyHomeNodeRef, folder1, ContentModel.TYPE_FOLDER); assertNotNull(folderInfo1); String folder2 = GUID.generate(); FileInfo folderInfo2 = fileFolderService.create(companyHomeNodeRef, folder2, ContentModel.TYPE_FOLDER); assertNotNull(folderInfo2); // Create folder11 as a subfolder of folder1 String folder11 = GUID.generate(); FileInfo folderInfo11 = fileFolderService.create(folderInfo1.getNodeRef(), folder11, ContentModel.TYPE_FOLDER); assertNotNull(folderInfo11); // Add folder2 as second parent for folder11 nodeService.addChild(folderInfo2.getNodeRef(), folderInfo11.getNodeRef(), ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS); return folderInfo11.getNodeRef(); } }); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { List repositories = cmisService.getRepositoryInfos(null); assertNotNull(repositories); assertTrue(repositories.size() > 0); String repositoryId = repositories.iterator().next().getId(); List parents = cmisService.getObjectParents(repositoryId, folderWithTwoParents.getId(), null, Boolean.FALSE, IncludeRelationships.NONE, "cmis:none", Boolean.FALSE, null); // Check if the second parent was also returned. assertEquals(2, parents.size()); return null; } }, CmisVersion.CMIS_1_1); } finally { auditSubsystem.destroy(); AuthenticationUtil.popAuthentication(); } } /* * REPO-3627 / MNT-19630: CMIS: Unable to call getAllVersions() if node is checked out and if binding type is WSDL * * For WS binding the getAllVersions call is made with null objectId */ @Test public void getAllVersionsWithNullObjectId() { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); // Create folder with file String folderName = "testfolder" + GUID.generate(); String docName = "testdoc.txt" + GUID.generate(); NodeRef folderRef = createContent(folderName, docName, false).getNodeRef(); List folderFileList = fileFolderService.list(folderRef); final NodeRef fileRef = folderFileList.get(0).getNodeRef(); // Create new version for file transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @Override public Void execute() throws Throwable { // create a new version versionService.createVersion(fileRef, null); return null; } }); // Checkout document and get all versions List versions = withCmisService(new CmisServiceCallback>() { @Override public List execute(CmisService cmisService) { String repositoryId = cmisService.getRepositoryInfos(null).get(0).getId(); ObjectData objectData = cmisService.getObjectByPath(repositoryId, "/" + folderName + "/" + docName, null, true, IncludeRelationships.NONE, null, false, true, null); // Checkout Holder objectId = new Holder(objectData.getId()); cmisService.checkOut(repositoryId, objectId, null, new Holder(true)); // Call get all versions with null objectId List versions = cmisService.getAllVersions(repositoryId, null, fileRef.toString(), null, null, null); return versions; } }); // Check that the correct versions are retrieved assertEquals(2, versions.size()); assertEquals(versions.get(0).getProperties().getProperties().get("cmis:versionLabel").getFirstValue(), "pwc"); assertEquals(versions.get(1).getProperties().getProperties().get("cmis:versionLabel").getFirstValue(), "0.1"); } }