Files
alfresco-community-repo/source/test-java/org/alfresco/repo/dictionary/CustomModelServiceImplTest.java
Jamal Kaabi-Mofrad 2d21700775 Merged DEV to HEAD
109455: Merged modules/custommodelmanagement/HEAD to DEV.
		93923: SHA-300: Added ALFRESCO_MODEL_ADMINISTRATORS group.
		95982: SHA-401: Implemented repo service for retrieving Custom Models. (WIP)
		95983: SHA-400: Added Private REST API to retrieve custom model(s)
			- Get All models: http://localhost:8080/alfresco/api/-default-/private/alfresco/versions/1/cmm
			- Get the model: http://localhost:8080/alfresco/api/-default-/private/alfresco/versions/1/cmm/<model-name>
		95984: SHA-401: Fixed the service to return null rather than throwing an exception, when the model does not exist.
		96053: SHA-400: Modified the custom model API response to return the "status" as "ACTIVE" or "DRAFT".
		96775: SHA-542: Added support to create a custom model. (WIP)
		96779: SHA-543: Added Private REST API to create custom model(s).
			- SHA-539: Cleaned up test data.
		96850: SHA-543: Added Author and Description properties to the custom model API.
		97410: SHA-407, SHA-555: Added tests for custom model backend service and the related REST API. Also, a minor modification as a result of added tests.
		97570: Modified the CMM REST API, per Kevin's request, to return empty arrays for model's types and aspects if they don't exist.
		97731: SHA-386: Added support to activate custom models. Also, a minor modification to the backend service and REST API, based on the Alfresco REST API guidelines.
		97775: SHA-386: Added tests for custom model activation (backend service). As well as, fixed the build failure by refactoring the public API tests.
		97992: SHA-573, SHA-393, SHA-494: Added support to deactivate custom model, create a new type and create a new property group (aspect).
		97994: Fixed the test as a result of renaming the service method.
		98123: SHA-393, SHA-494: Enabled the CMM REST API to create/update Types and/or Aspects via PUT. Also added validations for aspect/type's name.
		98259: SHA-453: Added backend and REST API support to delete a custom model.
		98690: SHA-393, SHA-494, SHA-453, SHA-575: Added tests for custom model backend service and the related REST API. Also, a minor modification as a result of added tests.
		99276: SHA-549: Added backend support to update a custom model. Also, refactored the service to externalise the error messages.
			- SHA-550: Added REST API support to update a custom model.
			- SHA-619: Made sure the backend service validates the model before creating a node. 
			- SHA-623: Added checks to not allow a user to create a custom model with the same name as the bootstrapped models.
		99287: SHA-619: Added InvalidCustomModelException for the CMM service to throw when the model validation fails.
		99514: SHA-506: added backend and API support to create custom Type/Aspect properties. Also refactored the API to overcome the Public API limitations.
		99522: SHA-506: Modified the Type/Aspect JSON payload to include a new read only property "prefixedName".
		99527: Fixed Bamboo build failure as the result of r99522 commit.
		99630: SHA-506: - Updated the API to exclude the inherited properties.
			- Added API tests for creating properties.
			- Modified the Custom Properties JSON response to include a new read only attribute "prefixedName".
                99662: SHA-351: Updated the API to support 'mandatory' and 'mandatoryEnforced' properties.
			- SHA-410: Updated the API to support 'defaultValue' property.
			- SHA-506: Modified the Custom Properties JSON response to include 'description' and 'multiValued' attributes.
		99669: SHA-506: Removed the unnecessary (at least in this sprint) methods from the backend service.
		99684: SHA-638: Added checks to not allow a user to create a custom model with already in-use namespace prefix.
		99959: SHA-679: Modified the custom model API to not import the already defined namespace.
		100211: SHA-607: Modified the custom model API to support delete model's type. Also, removed the unnecessary test as we depend on the dictionary service, so no need to test it in the custom model API.
		100281: Added Types and Aspects to the GET a single model API response, when it is requested with "?select=all" query string.
		100335: Added test for "?select=all" query string within the GET a single model API (see rev 100281).
		100366: SHA-612: Modified the custom model API to support delete model's aspect.
		100738: SHA-698: Added checks so the model Admin is not allowed to deactivate a custom model when its types/aspects are parent to other models' types/aspects (regardless of the model being active or not).
		100740: SHA-698: Fixed Bamboo build failures.
		101085: SHA-703: Added dependency validation before deleting custom type/aspect in the custom model API.
		101160: Modified the custom model API to return all properties (including the inherited properties) of the type/aspect, when requested by "?select=allProps".
		101636: SHA-697.
		101771: SHA-706: Made custom models hidden in the data dictionary.
		101863: SHA-701: Added checks to not allow creating duplicate properties within the same model. Also, removed unnecessary/duplicate constants from the custom model service class.
		101983: SHA-688: Fixed the error message by getting the root-cause-exception and returning its message. However, DictionaryException messages are not localised, so this will be fixed in the alfresco core.
		102223: Fix for SHA-726: Not able to edit prefix field of deactivated model when model type is referenced within same model - The API will update the parent prefixed name with the new prefix.
			- Also, added more validations to the CMM API, when setting a type/asptect's parent.
		102587: SHA-741, SHA-745, SHA-747: Added custom model Constraints support.
		102725: SHA-784: Fixed parent validation of the type/aspect.
		103030: SHA-741, SHA-745, SHA-747: Added tests for custom model Constraints.
			- Also fixed and refactored the API code as the result of tests.
		103753: SHA-846: Added inline constraints support. Also:
			- Modified the backend CMM service to throw CustomModelConstraintException when the root cause is DuplicateDefinitionException.
			- Removed the duplicate name check from the CMM API, as now it will depend on the exceptions thrown upon model compilation.
		103885: SHA-819, SHA-833: Added support to edit existing type/aspect.
		103973: SHA-819, SHA-833: Added API tests for types/aspects Edit. Also, refactored CMM API tests by moving the tests to their corresponding test class.
		104079: SHA-808: Fixed custom models bidirectional dependency.
		104158: Deleted the ExtendedRepoAdminService class as the required functionality has been added (see SHA-879) to the core alfresco code.
		104287: SHA-843: Modified the custom model API to support delete property. Also, minor refactoring of the API tests.
		104403: SHA-842: Modified the custom model API to support Edit property.
		104475: SHA-842: Added API tests for Edit property.
		104569: SHA-913 - Remove case sensitive option from the UI
			- SHA-914 - Update PO and tests that use the case sensitive option
			- Remove case sensitive option on LIST constraint throughout
			Also:
			- Update Aikau version to 1.0.18
		104690: Fixed Bamboo build failure caused by r104569.
		104849: SHA-808: Fixed custom models circular dependencies.
		105297: SHA-807: Added property default-value and constraint (REGEX, MINMAX and LENGTH) validators.
		105642: SHA-950: Wrapped backend CMM service method with a NEW transaction, in order to catch the thrown exception within DictionaryModelTypeTransactionListener. Also refactored the CMM backend service tests as the result of this change.
		106677: SHA-888, SHA-889, SHA-890: Added Backend and API support to export a custom model and its associated Share form.
		106722: SHA-888, SHA-889, SHA-890: Fixed a few minor issues raised during code review.
		107007: ACE-4019: Modified the CMM service to not start a new TX when creating a new model.
		107070: Temporarily enabled (hard coded) index and facetable attributes in the custom model properties.
		107296: GERMAN: Model Manager files localised as per EN-rev105921
		107297: FRENCH: Model Manager localised files based on EN-rev105921
		107315: SPANISH: Model Manager localised files based on EN-rev105921
		107317: JAPANESE: Model Manager localised files based on EN-rev105921
		107321: ITALIAN: Model Manager localised files based on EN-rev105921
		107322: DUTCH: Model Manager localised files based on EN-rev105921
		107335: SHA-889: Modified the CMM service to not throw an exception when exporting the model and its associated share extension module, where the Share extension module has not been created for the model yet.
		107456: SHA-893: Added API support to upload/import a custom model and its associated Share extension module.
		107560: SHA-893: Added model upload API tests as well as minor fixes.
		107647: SHA-893: Fixed minor issues raised during code review.
		107773: Docs review of message labels and errors.
		107866: SHA-1126: Added check for the maximum value of the MINMAX constraint to be a positive nonzero value.
		108117: SHA-832: Added validation for properties' default values to be checked against the property defined constraint.
		108256: SHA-1194: Modified CMM API to support indexing options.
		108510: SHA-1151: Externalised CMM rest API error messages.
			- SHA-1196: Changed the CMM Rest API input validator to use the same RegExs as the CMM Share.
		108518: SHA-1194: Changed CMM property facetable options to include "UNSET".
		108561: GERMAN: Model Manager files updated as per EN-rev107962
		108562: FRENCH: Model Manager files updated as per EN-rev107962
		108565: ITALIAN: Model Manager files updated as per EN-rev107962
		108566: SPANISH: Model Manager files updated as per EN-rev107962
		108567: JAPANESE: Model Manager files updated as per EN-rev107962
		108568: NORWEGIAN Bokmal: Model Manager files updated as per EN-rev107962
		108570: DUTCH: Model Manager files updated as per EN-rev107962
		108571: RUSSIAN: Model Manager files updated as per EN-rev107962
		108572: BRAZILIAN Portuguese: Model Manager files updated as per EN-rev107962
		108573: SIMPLIFIED CHINESE: Model Manager files updated as per EN-rev107962
		108604: Removed the unnecessary escaped quotation from the strings which don't have variables.
		108721: Api message changes from docs.
		108728: Changed "Property group" to "Aspect" in the CMM API error messages.
		108934: Added the missing escaped quotation into API messages.
		109037: Changes from docs for mandatory field character messages in the API.
		109204: ITALIAN: Updated bundle based on EN rev109039
		109205: GERMAN: Updated bundle based on EN rev109039
		109206: FRENCH: Updated bundle based on EN rev109039
		109223: GERMAN: Updated bundle based on EN rev109039 - fixed single quotes
		109226: FRENCH: Updated bundle based on EN rev109039 - fixed single quotes
		109228: ITALIAN: Updated bundle based on EN rev109039 - fixed single quotes
		109230: FRENCH: Updated bundle based on EN rev109039 - fixed single quotes again
		109235: JAPANESE: Updated bundle based on EN rev109039
		109293: SPANISH: Updated bundle based on EN rev109039
		109300: DUTCH: Updated bundle based on EN rev109039
		109412:	- Refactored the CMM JMX support to return CompositeData for performance reasons.
			- Reorganised a few of CMM classes/interfaces to make it easier for merging to alfresco core.
			- A minor fixes as a result of Find Bugs analysis.
			- Added the minimum and maximum repo versions for CMM module.
		109421: NORWEGIAN: Updated bundle based on EN rev109039
		109424: BRAZILIAN PORTUGUESE: Updated bundle based on EN rev109039
		109426: RUSSIAN: Updated bundle based on EN rev109039
		109427: CHINESE: Updated bundle based on EN rev10903
   109475: Added CMM Model into the core services (missed from previous commit).
   109480: SHA-723: Added custom models analytics in HeartBeat data.
   109481: SHA-528: Added GROUP_ALFRESCO_MODEL_ADMINISTRATORS_AUTHORITY patch.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@109490 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2015-08-04 01:56:12 +00:00

1055 lines
43 KiB
Java

/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.dictionary;
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.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.CustomModelDefinition;
import org.alfresco.service.cmr.dictionary.CustomModelService;
import org.alfresco.service.cmr.dictionary.ModelDefinition;
import org.alfresco.service.cmr.dictionary.NamespaceDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.dictionary.CustomModelException.ActiveModelConstraintException;
import org.alfresco.service.cmr.dictionary.CustomModelException.InvalidNamespaceException;
import org.alfresco.service.cmr.dictionary.CustomModelException.ModelDoesNotExistException;
import org.alfresco.service.cmr.dictionary.CustomModelException.NamespaceConstraintException;
import org.alfresco.service.cmr.download.DownloadStatus;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyMap;
import org.alfresco.util.test.junitrules.ApplicationContextInit;
import org.alfresco.util.test.junitrules.RunAsFullyAuthenticatedRule;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
/**
* Integration tests for {@link CustomModelServiceImpl}
*
* @author Jamal Kaabi-Mofrad
*/
public class CustomModelServiceImplTest
{
private static final long PAUSE_TIME = 1000;
@ClassRule
public static ApplicationContextInit APP_CONTEXT_INIT = new ApplicationContextInit();
@Rule
public RunAsFullyAuthenticatedRule runAsRule = new RunAsFullyAuthenticatedRule(AuthenticationUtil.getAdminUserName());
private static CustomModelService customModelService;
private static RetryingTransactionHelper transactionHelper;
private static PersonService personService;
private static AuthorityService authorityService;
private static CMMDownloadTestUtil cmmDownloadTestUtil;
private List<String> modelNames = new ArrayList<>();
@BeforeClass
public static void initStaticData() throws Exception
{
customModelService = APP_CONTEXT_INIT.getApplicationContext().getBean("customModelService", CustomModelService.class);
transactionHelper = APP_CONTEXT_INIT.getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
personService = APP_CONTEXT_INIT.getApplicationContext().getBean("personService", PersonService.class);
authorityService = APP_CONTEXT_INIT.getApplicationContext().getBean("authorityService", AuthorityService.class);
cmmDownloadTestUtil = new CMMDownloadTestUtil(APP_CONTEXT_INIT.getApplicationContext());
}
@AfterClass
public static void cleanUp()
{
cmmDownloadTestUtil.cleanup();
AuthenticationUtil.clearCurrentSecurityContext();
}
@After
public void tearDown() throws Exception
{
final List<String> activeModels = new ArrayList<>();
for (final String model : modelNames)
{
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Exception
{
try
{
customModelService.deleteCustomModel(model);
}
catch (ActiveModelConstraintException ex)
{
activeModels.add(model);
}
catch (Exception e)
{
// Ignore
}
return null;
}
});
}
for(final String am: activeModels)
{
// Try to deactivate and delete again
try
{
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Exception
{
customModelService.deactivateCustomModel(am);
return null;
}
});
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Exception
{
customModelService.deleteCustomModel(am);
return null;
}
});
}
catch (Exception ex)
{
// Ignore
}
}
modelNames.clear();
}
@Test
public void testCreateBasicInactiveModel() throws Exception
{
final String modelName1 = makeUniqueName("testCustomModel1");
final String desc = "This is test custom model desc";
Pair<String, String> namespacePair = getTestNamespacePrefixPair();
M2Model model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName1);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
model.setDescription(desc);
model.setAuthor("John Doe");
// Create the 1st model
CustomModelDefinition modelDefinition = createModel(model, false);
assertNotNull(modelDefinition);
assertEquals(modelName1, modelDefinition.getName().getLocalName());
assertTrue("There is no imported namespace." ,modelDefinition.getImportedNamespaces().isEmpty());
NamespaceDefinition namespaceDefinition = modelDefinition.getNamespaces().iterator().next();
assertNotNull(namespaceDefinition);
assertEquals(namespacePair.getFirst(), namespaceDefinition.getUri());
assertEquals(namespacePair.getSecond(), namespaceDefinition.getPrefix());
assertEquals(desc, modelDefinition.getDescription());
assertEquals("John Doe", modelDefinition.getAuthor());
final String modelName2 = makeUniqueName("testCustomModel2");
model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName2);
model.createNamespace(namespacePair.getFirst(), "newTestPrefix");
// Create the 2nd model - duplicate namespace URI
try
{
createModel(model, false);
fail("Shouldn't be able to create a model with an already in-use namespace uri.");
}
catch (NamespaceConstraintException ex)
{
// Expected
}
final String modelName3 = makeUniqueName("testCustomModel3");
model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName3);
model.createNamespace(getTestNamespacePrefixPair().getFirst(), namespacePair.getSecond());
// Create the 2nd model - duplicate namespace Prefix
try
{
createModel(model, false);
fail("Shouldn't be able to create a model with an already in-use namespace prefix.");
}
catch (NamespaceConstraintException ex)
{
// Expected
}
namespacePair = getTestNamespacePrefixPair();
model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName2);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
modelDefinition = createModel(model, false);
assertNotNull(modelDefinition);
assertEquals(modelName2, modelDefinition.getName().getLocalName());
namespaceDefinition = modelDefinition.getNamespaces().iterator().next();
assertNotNull(namespaceDefinition);
assertEquals(namespacePair.getFirst(), namespaceDefinition.getUri());
assertEquals(namespacePair.getSecond(), namespaceDefinition.getPrefix());
try
{
// Test duplicate model
createModel(model, false);
fail("Shouldn't be able to create a duplicate model.");
}
catch (Exception e)
{
// Expected
}
try
{
// Test creating a model with the same name as the bootstrapped model
model.setName("contentmodel");
createModel(model, false);
fail("Shouldn't be able to create a model with the same name as the bootstrapped model.");
}
catch (Exception e)
{
// Expected
}
// Test list all models
try
{
customModelService.getCustomModels(null);
fail("Should have thrown IllegalArgumentException as PagingRequest was null.");
}
catch (IllegalArgumentException e)
{
// Expected
}
final PagingRequest pagingRequest = new PagingRequest(0, Integer.MAX_VALUE);
PagingResults<CustomModelDefinition> result = transactionHelper.doInTransaction(new RetryingTransactionCallback<PagingResults<CustomModelDefinition>>()
{
public PagingResults<CustomModelDefinition> execute() throws Exception
{
return customModelService.getCustomModels(pagingRequest);
}
});
assertTrue(result.getTotalResultCount().getFirst() >= 2);
}
@Test
public void testListTypesAspects_Empty() throws Exception
{
final String modelName = makeUniqueName("testCustomModel");
Pair<String, String> namespacePair = getTestNamespacePrefixPair();
final M2Model model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
createModel(model, false);
// Retrieve the created model
CustomModelDefinition modelDefinition = getModel(modelName);
assertNotNull(modelDefinition);
assertEquals(modelName, modelDefinition.getName().getLocalName());
// List all of the model's types
Collection<TypeDefinition> types = modelDefinition.getTypeDefinitions();
assertEquals(0, types.size());
// List all of the model's aspects
Collection<AspectDefinition> aspects = modelDefinition.getAspectDefinitions();
assertEquals(0, aspects.size());
}
@Test
public void testModelAdmin() throws Exception
{
assertFalse(customModelService.isModelAdmin(null));
final String userName = "testUser" + System.currentTimeMillis();
final PropertyMap testUser = new PropertyMap();
testUser.put(ContentModel.PROP_USERNAME, userName);
testUser.put(ContentModel.PROP_FIRSTNAME, "John");
testUser.put(ContentModel.PROP_LASTNAME, "Doe");
testUser.put(ContentModel.PROP_PASSWORD, "password");
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Exception
{
personService.createPerson(testUser);
assertFalse(customModelService.isModelAdmin(userName));
// Add the user to the group
authorityService.addAuthority(CustomModelServiceImpl.GROUP_ALFRESCO_MODEL_ADMINISTRATORS_AUTHORITY, userName);
assertTrue(customModelService.isModelAdmin(userName));
return null;
}
});
}
@Test
public void testActivateModel() throws Exception
{
final String modelName = makeUniqueName("testCustomModel");
final String desc = "This is test custom model desc";
Pair<String, String> namespacePair = getTestNamespacePrefixPair();
M2Model model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
model.setDescription(desc);
model.setAuthor("John Doe");
// Create the model
CustomModelDefinition modelDefinition = createModel(model, false);
assertNotNull(modelDefinition);
assertEquals(modelName, modelDefinition.getName().getLocalName());
assertFalse(modelDefinition.isActive());
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Exception
{
// Activate the model
customModelService.activateCustomModel(modelName);
return null;
}
});
// Retrieve the model
modelDefinition = getModel(modelName);
assertNotNull(modelDefinition);
assertEquals(modelName, modelDefinition.getName().getLocalName());
assertTrue(modelDefinition.isActive());
// Try to activate the model again
try
{
customModelService.activateCustomModel(modelName);
fail("Shouldn't be able to activate an already activated model.");
}
catch (Exception ex)
{
// Expected
}
}
@Test
public void testisNamespaceUriExists()
{
final String modelName = makeUniqueName("testCustomModel");
Pair<String, String> namespacePair = getTestNamespacePrefixPair();
M2Model model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
model.setAuthor("John Doe");
assertNull(customModelService.getCustomModelByUri(namespacePair.getFirst()));
// Create the model
CustomModelDefinition modelDefinition = createModel(model, false);
assertNotNull(modelDefinition);
assertEquals(modelName, modelDefinition.getName().getLocalName());
assertTrue(customModelService.isNamespaceUriExists(namespacePair.getFirst()));
ModelDefinition modelDefinitionByUri = customModelService.getCustomModelByUri(namespacePair.getFirst());
assertNotNull(modelDefinitionByUri);
assertEquals(modelName, modelDefinitionByUri.getName().getLocalName());
}
@Test
public void testCreateModelWithTypesAndAspects() throws Exception
{
String modelName = makeUniqueName("testCustomModelFailed");
Pair<String, String> namespacePair = getTestNamespacePrefixPair();
M2Model model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
model.setAuthor("Average Joe");
// Type
String typeName = "testType";
M2Type m2Type = model.createType(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typeName);
m2Type.setTitle("Test type title");
m2Type.setParentName("cm:content");
// Aspect
String aspectName = "testMarkerAspect";
model.createAspect(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + aspectName);
try
{
createModel(model, false);
fail("Shouldn't be able to create a model without namespace imports, when type and/or aspect have parent name.");
}
catch (Exception ex)
{
// Expected
}
model.setName(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createImport("http://www.alfresco.org/model/content/1.0", "cm");
CustomModelDefinition modelDefinition = createModel(model, false);
assertNotNull(modelDefinition);
assertEquals(modelName, modelDefinition.getName().getLocalName());
assertEquals(1, modelDefinition.getTypeDefinitions().size());
assertEquals(typeName, modelDefinition.getTypeDefinitions().iterator().next().getName().getLocalName());
assertEquals("cm:content", modelDefinition.getTypeDefinitions().iterator().next().getParentName().toPrefixString());
assertEquals(1, modelDefinition.getAspectDefinitions().size());
assertEquals(aspectName, modelDefinition.getAspectDefinitions().iterator().next().getName().getLocalName());
// list all custom models's types and aspects
{
try
{
customModelService.getAllCustomTypes(null);
fail("Should have thrown IllegalArgumentException as PagingRequest was null.");
}
catch (IllegalArgumentException e)
{
// Expected
}
try
{
customModelService.getAllCustomAspects(null);
fail("Should have thrown IllegalArgumentException as PagingRequest was null.");
}
catch (IllegalArgumentException e)
{
// Expected
}
final PagingRequest pagingRequest = new PagingRequest(0, Integer.MAX_VALUE);
PagingResults<TypeDefinition> allTypes = transactionHelper.doInTransaction(new RetryingTransactionCallback<PagingResults<TypeDefinition>>()
{
public PagingResults<TypeDefinition> execute() throws Exception
{
return customModelService.getAllCustomTypes(pagingRequest);
}
});
assertTrue(allTypes.getTotalResultCount().getFirst() >= 1);
PagingResults<AspectDefinition> allAspects = transactionHelper.doInTransaction(new RetryingTransactionCallback<PagingResults<AspectDefinition>>()
{
public PagingResults<AspectDefinition> execute() throws Exception
{
return customModelService.getAllCustomAspects(pagingRequest);
}
});
assertTrue(allAspects.getTotalResultCount().getFirst() >= 1);
}
// Retrieve the aspect by the aspect QName
QName aspectQName = QName.createQName("{" + namespacePair.getFirst() + "}" + aspectName);
AspectDefinition aspectDefinition = customModelService.getCustomAspect(aspectQName);
assertNotNull(aspectDefinition);
assertEquals(1, getModel(modelName).getAspectDefinitions().size());
// Retrieve the type by the type QName
QName typeQName = QName.createQName("{" + namespacePair.getFirst()+ "}" + typeName);
TypeDefinition typeDefinition = customModelService.getCustomType(typeQName);
assertNotNull(typeDefinition);
assertEquals(1, getModel(modelName).getTypeDefinitions().size());
// Test update model by adding an aspect
String aspectName2 = "testMarkerAspect2";
model.createAspect(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + aspectName2);
updateModel(modelName, model, false);
// Retrieve the created aspect
aspectQName = QName.createQName("{" + namespacePair.getFirst() + "}" + aspectName2);
aspectDefinition = customModelService.getCustomAspect(aspectQName);
assertNotNull(aspectDefinition);
assertEquals(aspectQName, aspectDefinition.getName());
assertEquals(2, getModel(modelName).getAspectDefinitions().size());
// Test update model by adding a type
String typeName2 = "testType2";
model.createType(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typeName2);
updateModel(modelName, model, false);
// Retrieve the created type
typeQName = QName.createQName("{" + namespacePair.getFirst() + "}" + typeName2);
typeDefinition = customModelService.getCustomType(typeQName);
assertNotNull(typeDefinition);
assertEquals(typeQName, typeDefinition.getName());
assertEquals(2, getModel(modelName).getTypeDefinitions().size());
{
// Create an aspect with an identical name as an already defined
// type name within this model
model.createAspect(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typeName);
try
{
updateModel(modelName, model, false);
fail("Shouldn't be able to create a type and an aspect with the same name in a model.");
}
catch (Exception ex)
{
// Expected
}
}
}
@Test
public void testDeactivateModel() throws Exception
{
final String modelName = makeUniqueName("testDeactivateCustomModel");
final String desc = "This is test custom model desc";
Pair<String, String> namespacePair = getTestNamespacePrefixPair();
final M2Model model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
model.setDescription(desc);
model.setAuthor("John Doe");
// Create the model
CustomModelDefinition modelDefinition = createModel(model, true);
assertNotNull(modelDefinition);
assertEquals(modelName, modelDefinition.getName().getLocalName());
assertTrue(modelDefinition.isActive());
// Deactivate the model
customModelService.deactivateCustomModel(modelName);
// Retrieve the model
modelDefinition = transactionHelper.doInTransaction(new RetryingTransactionCallback<CustomModelDefinition>()
{
public CustomModelDefinition execute() throws Exception
{
return customModelService.getCustomModel(modelName);
}
});
assertNotNull(modelDefinition);
assertEquals(modelName, modelDefinition.getName().getLocalName());
assertFalse(modelDefinition.isActive());
// Try to deactivate the model again
try
{
customModelService.deactivateCustomModel(modelName);
fail("Shouldn't be able to deactivate an already deactivated model.");
}
catch (Exception ex)
{
// Expected
}
}
@Test
public void testDeleteModel() throws Exception
{
final String modelName = makeUniqueName("testDeleteCustomModel");
Pair<String, String> namespacePair = getTestNamespacePrefixPair();
final M2Model model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
model.setAuthor("John Doe");
// Create the model
CustomModelDefinition modelDefinition = createModel(model, false);
assertNotNull(modelDefinition);
assertEquals(modelName, modelDefinition.getName().getLocalName());
assertFalse(modelDefinition.isActive());
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Exception
{
// delete non-existing model
try
{
customModelService.deleteCustomModel(modelName + "someModel");
fail("Should have thrown ModelDoesNotExistException.");
}
catch (ModelDoesNotExistException ex)
{
// Expected
}
return null;
}
});
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Exception
{
// Activate the model
customModelService.activateCustomModel(modelName);
return null;
}
});
// delete an active model
try
{
customModelService.deleteCustomModel(modelName);
fail("Shouldn't be able to delete an active model.");
}
catch (ActiveModelConstraintException ex)
{
// Expected
}
// Deactivate the model
customModelService.deactivateCustomModel(modelName);
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Exception
{
customModelService.deleteCustomModel(modelName);
return null;
}
});
modelDefinition = getModel(modelName);
assertNull(modelDefinition);
}
@Test
public void testUpdateModel() throws Exception
{
final String modelName = makeUniqueName("testUpdateCustomModel");
final String desc = "This is test custom model desc";
Pair<String, String> namespacePair = getTestNamespacePrefixPair();
M2Model model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
model.setDescription(desc);
model.setAuthor("John Doe");
// Add aspect
String aspectName = "testMarkerAspect";
model.createAspect(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + aspectName);
// Create the model
CustomModelDefinition modelDefinition = createModel(model, false);
assertNotNull(modelDefinition);
assertEquals(modelName, modelDefinition.getName().getLocalName());
assertFalse(modelDefinition.isActive());
NamespaceDefinition namespaceDefinition = modelDefinition.getNamespaces().iterator().next();
assertEquals(namespacePair.getFirst(), namespaceDefinition.getUri());
assertEquals(namespacePair.getSecond(), namespaceDefinition.getPrefix());
assertEquals(desc, modelDefinition.getDescription());
assertEquals("John Doe", modelDefinition.getAuthor());
assertEquals(1, modelDefinition.getAspectDefinitions().size());
// Update the model by removing the namespace
model.removeNamespace(namespacePair.getFirst());
try
{
updateModel(modelName, model, false);
fail("Shouldn't be able to update a custom model with an empty namespace.");
}
catch (InvalidNamespaceException ex)
{
// Expected
}
// Update the model by removing the namespace prefix
model.createNamespace(namespacePair.getFirst(), null);
try
{
updateModel(modelName, model, false);
fail("Model validation should have failed, as the namespace prefix is null.");
}
catch (IllegalArgumentException ex)
{
// Expected
}
// Update the model by adding more namespace URIs
model.createNamespace("http://www.alfresco.org/model/contenttest/1.0", namespacePair.getSecond());
try
{
updateModel(modelName, model, false);
fail("Shouldn't be able to add more than one namespace URI into a custom model.");
}
catch (InvalidNamespaceException ex)
{
// Expected
}
// Update the namespace with a URI that has already been used
model.removeNamespace(namespacePair.getFirst());
model.removeNamespace("http://www.alfresco.org/model/contenttest/1.0");
model.createNamespace("http://www.alfresco.org/model/content/1.0", namespacePair.getSecond());
try
{
updateModel(modelName, model, false);
fail("Shouldn't be able to update a model with an already in-use namespace URI.");
}
catch (NamespaceConstraintException ex)
{
// Expected
}
// Update the namespace with a Prefix that has already been used
model.removeNamespace("http://www.alfresco.org/model/content/1.0");
model.createNamespace(namespacePair.getFirst(), "cm");
try
{
updateModel(modelName, model, false);
fail("Shouldn't be able to update a model with an already in-use namespace Prefix.");
}
catch (NamespaceConstraintException ex)
{
// Expected
}
// New namespace
Pair<String, String> newNamespacePair = getTestNamespacePrefixPair();
model = M2Model.createModel(newNamespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(newNamespacePair.getFirst(), newNamespacePair.getSecond());
model.setDescription(desc);
// Update non-existing model
try
{
updateModel(modelName + "non-existing model", model, false);
fail("Should have thrown ModelDoesNotExistException.");
}
catch (ModelDoesNotExistException ex)
{
// Expected
}
modelDefinition = updateModel(modelName, model, false);
namespaceDefinition = modelDefinition.getNamespaces().iterator().next();
assertEquals(newNamespacePair.getFirst(), namespaceDefinition.getUri());
assertEquals(newNamespacePair.getSecond(), namespaceDefinition.getPrefix());
assertEquals(desc, modelDefinition.getDescription());
assertNull(modelDefinition.getAuthor());
assertEquals(0, modelDefinition.getAspectDefinitions().size());
// Test that the cache is updated correctly. This means the cache should have removed the old namespace URI.
QName aspectQName = QName.createQName("{" + namespacePair.getFirst() + "}" + aspectName);
AspectDefinition aspectDefinition = customModelService.getCustomAspect(aspectQName);
assertNull(aspectDefinition);
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Exception
{
// Activate the model
customModelService.activateCustomModel(modelName);
return null;
}
});
// Retrieve the model
modelDefinition = getModel(modelName);
assertNotNull(modelDefinition);
assertTrue(modelDefinition.isActive());
// Try to update only the namespace URI of an active model
Pair<String, String> activeModelNamespacePair = getTestNamespacePrefixPair();
model = M2Model.createModel(newNamespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(activeModelNamespacePair.getFirst(), newNamespacePair.getSecond());
try
{
updateModel(modelName, model, true); // true => as we activated the model
fail("Shouldn't be able to update the namespace URI of an active model.");
}
catch (ActiveModelConstraintException ax)
{
// Expected
}
// Try to update only the namespace prefix of an active model
activeModelNamespacePair = getTestNamespacePrefixPair();
model = M2Model.createModel(activeModelNamespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(newNamespacePair.getFirst(), activeModelNamespacePair.getSecond());
try
{
updateModel(modelName, model, true); // true => as we activated the model
fail("Shouldn't be able to update the namespace prefix of an active model.");
}
catch (ActiveModelConstraintException ax)
{
// Expected
}
// Try to update both the namespace URI and prefix of an active model
activeModelNamespacePair = getTestNamespacePrefixPair();
model = M2Model.createModel(activeModelNamespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(activeModelNamespacePair.getFirst(), activeModelNamespacePair.getSecond());
try
{
updateModel(modelName, model, true); // true => as we activated the model
fail("Shouldn't be able to update the namespace URI and namespace prefix of an active model.");
}
catch (ActiveModelConstraintException ax)
{
// Expected
}
// Update active model's desc and author
modelDefinition = getModel(modelName);
namespaceDefinition = modelDefinition.getNamespaces().iterator().next();
model = M2Model.createModel(namespaceDefinition.getPrefix() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(namespaceDefinition.getUri(), namespaceDefinition.getPrefix());
model.setDescription(desc);
model.setAuthor("Admin Admin");
modelDefinition = updateModel(modelName, model, true);
assertEquals(modelName, modelDefinition.getName().getLocalName());
assertTrue(modelDefinition.isActive());
assertEquals(desc, modelDefinition.getDescription());
assertEquals("Admin Admin", modelDefinition.getAuthor());
}
@Test
public void testCreateDownload() throws Exception
{
final String modelName = makeUniqueName("testDownloadCustomModel");
final String modelExportFileName = modelName + ".xml";
final String shareExtExportFileName = "CMM_" + modelName + "_module.xml";
Pair<String, String> namespacePair = getTestNamespacePrefixPair();
M2Model model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
model.setAuthor("Admin");
model.createImport("http://www.alfresco.org/model/content/1.0", "cm");
// Add Type
String typeName = "testType";
M2Type m2Type = model.createType(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typeName);
m2Type.setTitle("Test type title");
m2Type.setParentName("cm:content");
// Create the model
CustomModelDefinition modelDefinition = createModel(model, false);
assertNotNull(modelDefinition);
assertEquals(modelName, modelDefinition.getName().getLocalName());
NodeRef downloadNode = createDownload(modelName, false);
assertNotNull(downloadNode);
DownloadStatus status = cmmDownloadTestUtil.getDownloadStatus(downloadNode);
while (status.getStatus() == DownloadStatus.Status.PENDING)
{
Thread.sleep(PAUSE_TIME);
status = cmmDownloadTestUtil.getDownloadStatus(downloadNode);
}
Set<String> entries = cmmDownloadTestUtil.getDownloadEntries(downloadNode);
assertEquals(1, entries.size());
String modelEntry = cmmDownloadTestUtil.getDownloadEntry(entries, modelExportFileName);
assertNotNull(modelEntry);
assertEquals(modelEntry, modelExportFileName);
// Create Share extension module
cmmDownloadTestUtil.createShareExtModule(modelName);
downloadNode = createDownload(modelName, true);
assertNotNull(downloadNode);
status = cmmDownloadTestUtil.getDownloadStatus(downloadNode);
while (status.getStatus() == DownloadStatus.Status.PENDING)
{
Thread.sleep(PAUSE_TIME);
status = cmmDownloadTestUtil.getDownloadStatus(downloadNode);
}
entries = cmmDownloadTestUtil.getDownloadEntries(downloadNode);
assertEquals(2, entries.size());
modelEntry = cmmDownloadTestUtil.getDownloadEntry(entries, modelExportFileName);
assertNotNull(modelEntry);
assertEquals(modelEntry, modelExportFileName);
String shareExtEntry = cmmDownloadTestUtil.getDownloadEntry(entries, shareExtExportFileName);
assertNotNull(shareExtEntry);
assertEquals(shareExtEntry, shareExtExportFileName);
// Create Share extension module - this will override the existing module
cmmDownloadTestUtil.createShareExtModule(modelName + System.currentTimeMillis());
// The module id dose not exist, so the CMM service logs the error
// (warning) and creates a zip containing only the model.
downloadNode = createDownload(modelName, true);
assertNotNull(downloadNode);
status = cmmDownloadTestUtil.getDownloadStatus(downloadNode);
while (status.getStatus() == DownloadStatus.Status.PENDING)
{
Thread.sleep(PAUSE_TIME);
status = cmmDownloadTestUtil.getDownloadStatus(downloadNode);
}
entries = cmmDownloadTestUtil.getDownloadEntries(downloadNode);
assertEquals(1, entries.size());
modelEntry = cmmDownloadTestUtil.getDownloadEntry(entries, modelExportFileName);
assertNotNull(modelEntry);
assertEquals(modelEntry, modelExportFileName);
}
@Test
public void testModelsInfo() throws Exception
{
CustomModelsInfo info = transactionHelper.doInTransaction(new RetryingTransactionCallback<CustomModelsInfo>()
{
public CustomModelsInfo execute() throws Exception
{
return customModelService.getCustomModelsInfo();
}
});
final String modelName = makeUniqueName("testCustomModelsInfo");
Pair<String, String> namespacePair = getTestNamespacePrefixPair();
M2Model model = M2Model.createModel(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + modelName);
model.createNamespace(namespacePair.getFirst(), namespacePair.getSecond());
model.setAuthor("Admin");
model.createImport("http://www.alfresco.org/model/content/1.0", "cm");
// Add Type
String typeName = "testType";
M2Type m2Type = model.createType(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + typeName);
m2Type.setTitle("Test type title");
m2Type.setParentName("cm:content");
// Add Aspect
String aspectName = "testMarkerAspect";
model.createAspect(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + aspectName);
// Create the model
createModel(model, true);
CustomModelsInfo newInfo = transactionHelper.doInTransaction(new RetryingTransactionCallback<CustomModelsInfo>()
{
public CustomModelsInfo execute() throws Exception
{
return customModelService.getCustomModelsInfo();
}
});
assertEquals(info.getNumberOfActiveModels() + 1, newInfo.getNumberOfActiveModels());
assertEquals(info.getNumberOfActiveTypes() + 1, newInfo.getNumberOfActiveTypes());
assertEquals(info.getNumberOfActiveAspects() + 1, newInfo.getNumberOfActiveAspects());
// Add another aspect
String aspectNameTwo = "testMarkerAspectTwo";
model.createAspect(namespacePair.getSecond() + QName.NAMESPACE_PREFIX + aspectNameTwo);
// Update the model
updateModel(modelName, model, true);
// Get the models' info
newInfo = transactionHelper.doInTransaction(new RetryingTransactionCallback<CustomModelsInfo>()
{
public CustomModelsInfo execute() throws Exception
{
return customModelService.getCustomModelsInfo();
}
});
assertEquals(info.getNumberOfActiveModels() + 1, newInfo.getNumberOfActiveModels());
assertEquals(info.getNumberOfActiveTypes() + 1, newInfo.getNumberOfActiveTypes());
// 2 => we added two aspects
assertEquals(info.getNumberOfActiveAspects() + 2, newInfo.getNumberOfActiveAspects());
}
private Pair<String, String> getTestNamespacePrefixPair()
{
long timeMillis = System.currentTimeMillis();
String uri = "http://www.alfresco.org/model/testcmmservicenamespace" + timeMillis + "/1.0";
String prefix = "testcmmservice" + timeMillis;
return new Pair<String, String>(uri, prefix);
}
private String makeUniqueName(String modelName)
{
String name = modelName + System.currentTimeMillis();
modelNames.add(name);
return name;
}
private CustomModelDefinition createModel(final M2Model m2Model, final boolean activate)
{
return transactionHelper.doInTransaction(new RetryingTransactionCallback<CustomModelDefinition>()
{
public CustomModelDefinition execute() throws Exception
{
return customModelService.createCustomModel(m2Model, activate);
}
});
}
private CustomModelDefinition updateModel(final String modelName, final M2Model m2Model, final boolean activate)
{
return transactionHelper.doInTransaction(new RetryingTransactionCallback<CustomModelDefinition>()
{
public CustomModelDefinition execute() throws Exception
{
return customModelService.updateCustomModel(modelName, m2Model, activate);
}
});
}
private CustomModelDefinition getModel(final String modelName)
{
return transactionHelper.doInTransaction(new RetryingTransactionCallback<CustomModelDefinition>()
{
public CustomModelDefinition execute() throws Exception
{
return customModelService.getCustomModel(modelName);
}
});
}
private NodeRef createDownload(final String modelName, final boolean withShareExtModule)
{
return transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Exception
{
NodeRef nodeRef = customModelService.createDownloadNode(modelName, withShareExtModule);
return nodeRef;
}
});
}
}