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.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.Serializable; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import java.util.Map; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator; import org.alfresco.repo.action.executer.AddFeaturesActionExecuter; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.model.Repository; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.action.ActionCondition; import org.alfresco.service.cmr.action.ActionService; 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.NodeRef; import org.alfresco.service.cmr.repository.NodeService; 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.version.VersionService; 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.apache.chemistry.opencmis.commons.PropertyIds; import org.apache.chemistry.opencmis.commons.data.AllowableActions; import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement; 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.Properties; import org.apache.chemistry.opencmis.commons.data.PropertyData; import org.apache.chemistry.opencmis.commons.data.RepositoryInfo; import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition; import org.apache.chemistry.opencmis.commons.enums.Action; import org.apache.chemistry.opencmis.commons.enums.CmisVersion; import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships; import org.apache.chemistry.opencmis.commons.enums.VersioningState; import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException; 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.PropertiesImpl; 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.spi.Holder; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.extensions.webscripts.GUID; /** * OpenCMIS tests. * * @author steveglover * */ public class CMISTest { 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 Repository repositoryHelper; private VersionService versionService; private LockService lockService; private AlfrescoCmisServiceFactory factory; private ActionService actionService; private RuleService ruleService; private CMISConnector cmisConnector; /** * 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); } } private 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; } /* (non-Javadoc) * @see org.apache.chemistry.opencmis.commons.server.CallContext#encryptTempFiles() */ @Override public boolean encryptTempFiles() { // TODO Auto-generated method stub return false; } /* (non-Javadoc) * @see org.apache.chemistry.opencmis.commons.server.CallContext#getCmisVersion() */ @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.versionService = (VersionService) ctx.getBean("versionService"); this.lockService = (LockService) ctx.getBean("lockService"); this.repositoryHelper = (Repository)ctx.getBean("repositoryHelper"); this.factory = (AlfrescoCmisServiceFactory)ctx.getBean("CMISServiceFactory"); this.cmisConnector = (CMISConnector) ctx.getBean("CMISConnector"); } private FileInfo createContent(final String folderName, final String docName, final boolean isRule) { 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); 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() { // 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); } // create content stream with mimetype and encoding { String mimeType = MimetypeMap.MIMETYPE_TEXT_PLAIN + "; charset=UTF-8"; final ContentStreamImpl contentStreamHTML = new ContentStreamImpl(null, mimeType, " Hello

Test html

"); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { cmisService.setContentStream(repositoryId, objectIdHolder, 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); } // checkout/checkin object with mimetype and encoding { objectIdHolder.setValue(objectId); 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); } } private static class TestContext { private String repositoryId = null; 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 ObjectData getObjectData() { return objectData; } 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 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. */ @Test public void testGetAllVersionsOnReadOnlyLockedNode() { 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); try { cmisService.getAllVersions(repositoryId, objectData.getId(), fileInfo.getNodeRef().getId(), null, true, null); } catch (Throwable e) { e.printStackTrace(); fail(); } 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 = currentProperties.getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues(); secondaryTypeIds.remove(aspectName); final PropertiesImpl newProperties = new PropertiesImpl(); newProperties.addProperty(new PropertyStringImpl(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, secondaryTypeIds)); withCmisService(new CmisServiceCallback() { @Override public Void execute(CmisService cmisService) { cmisService.updateProperties(repositoryId, objectIdHolder, null, newProperties, null); return null; } }, CmisVersion.CMIS_1_1); Properties currentProperties1 = withCmisService(new CmisServiceCallback() { @Override public Properties execute(CmisService cmisService) { Properties properties = cmisService.getProperties(repositoryId, objectIdHolder.getValue(), null, null); return properties; } }, CmisVersion.CMIS_1_1); secondaryTypeIds = currentProperties1.getProperties().get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues(); } /** * 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(); } } public void testGetContentChanges() { // create folder with file String folderName = "testfolder" + GUID.generate(); String docName = "testdoc.txt" + GUID.generate(); createContent(folderName, docName, false); folderName = "testfolder" + GUID.generate(); docName = "testdoc.txt" + GUID.generate(); createContent(folderName, docName, false); Holder changeLogToken = new Holder(); ObjectList ol = this.cmisConnector.getContentChanges(changeLogToken, new BigInteger("2")); assertEquals(2, ol.getNumItems()); assertEquals("3", changeLogToken.getValue()); } }