mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V3.2 to HEAD
18023: RM: groundwork for custom metadata delete 18071: MT - fix ETHREEOH-3730 (reject invitation shows "Invitation not found" instead of Yes / No options) 18078: MT - fix ETHREEOH-3892 (it is not possible to create or manage any Tenants once the DOD5015 RM AMP is installed) 18903: RM Caveats - fix ALF-1894 (improvement for ESC - remove hardcoded "rmc" model/namespace) 19046: Improve dictionary debug logging (ALF-587) 19096: Merging PATCHES/V3.2.r to V3.2 19075: Merging DEV/BELARUS/V3.2-2010_02_24 to PATCHES/V3.2.r 18881: ALF-587: MT Upgrades to 3.2r fail unable to find Alfresco content types 19085: ALF-587 - test/build fix (follow on for r18881->r19075) 19145: Dynamic Models - follow-on for ALF-587 (& ALFCOM-2977) + additional unit tests 19176: Remove Java 6'ism 19198: Build/test fix (follow-on to r19145 - do not validate model delete of version nodes) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@19260 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -64,6 +64,7 @@
|
||||
<property name="namespaceService" ref="namespaceService"/>
|
||||
<property name="tenantService" ref="tenantService"/>
|
||||
<property name="tenantAdminService" ref="tenantAdminService"/>
|
||||
<property name="transactionService" ref="TransactionService"/>
|
||||
|
||||
<property name="storeUrls">
|
||||
<list>
|
||||
|
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.admin;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.service.cmr.admin.RepoAdminService;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* @see RepoAdminServiceImpl
|
||||
*
|
||||
* @author janv
|
||||
*/
|
||||
public class RepoAdminServiceImplTest extends TestCase
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(RepoAdminServiceImplTest.class);
|
||||
|
||||
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
private RepoAdminService repoAdminService;
|
||||
private DictionaryService dictionaryService;
|
||||
private TransactionService transactionService;
|
||||
|
||||
final String modelPrefix = "model-";
|
||||
final static String MKR = "{MKR}";
|
||||
|
||||
public static final String MODEL_MKR_XML =
|
||||
"<model name='test"+MKR+":testModel"+MKR+"' xmlns='http://www.alfresco.org/model/dictionary/1.0'>" +
|
||||
|
||||
" <description>Test model "+MKR+"</description>" +
|
||||
" <author>Alfresco</author>" +
|
||||
" <published>2005-05-30</published>" +
|
||||
" <version>1.0</version>" +
|
||||
|
||||
" <imports>" +
|
||||
" <import uri='http://www.alfresco.org/model/dictionary/1.0' prefix='d'/>" +
|
||||
" <import uri='http://www.alfresco.org/model/content/1.0' prefix='cm'/>" +
|
||||
" </imports>" +
|
||||
|
||||
" <namespaces>" +
|
||||
" <namespace uri='http://www.alfresco.org/test/testmodel"+MKR+"/1.0' prefix='test"+MKR+"'/>" +
|
||||
" </namespaces>" +
|
||||
|
||||
" <types>" +
|
||||
|
||||
" <type name='test"+MKR+":base'>" +
|
||||
" <title>Base</title>" +
|
||||
" <description>The Base Type</description>" +
|
||||
" <parent>cm:content</parent>" +
|
||||
" <properties>" +
|
||||
" <property name='test"+MKR+":prop1'>" +
|
||||
" <type>d:text</type>" +
|
||||
" </property>" +
|
||||
" </properties>" +
|
||||
" </type>" +
|
||||
|
||||
" </types>" +
|
||||
|
||||
"</model>";
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
repoAdminService = (RepoAdminService) ctx.getBean("RepoAdminService");
|
||||
dictionaryService = (DictionaryService) ctx.getBean("DictionaryService");
|
||||
transactionService = (TransactionService) ctx.getBean("TransactionService");
|
||||
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testSetup() throws Exception
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
|
||||
//
|
||||
// Test custom model management
|
||||
//
|
||||
|
||||
public void testSimpleDynamicModel() throws Exception
|
||||
{
|
||||
final int X = 0;
|
||||
final String modelFileName = modelPrefix+X+".xml";
|
||||
final QName typeName = QName.createQName("{http://www.alfresco.org/test/testmodel"+X+"/1.0}base");
|
||||
final QName modelName = QName.createQName("{http://www.alfresco.org/test/testmodel"+X+"/1.0}testModel"+X);
|
||||
|
||||
try
|
||||
{
|
||||
if (isModelDeployed(modelFileName))
|
||||
{
|
||||
// undeploy model
|
||||
repoAdminService.undeployModel(modelFileName);
|
||||
}
|
||||
|
||||
assertFalse(isModelDeployed(modelFileName));
|
||||
|
||||
assertNull(dictionaryService.getClass(typeName));
|
||||
|
||||
final int defaultModelCnt = dictionaryService.getAllModels().size();
|
||||
|
||||
// deploy custom model
|
||||
String model = MODEL_MKR_XML.replace(MKR, X+"");
|
||||
InputStream modelStream = new ByteArrayInputStream(model.getBytes("UTF-8"));
|
||||
|
||||
repoAdminService.deployModel(modelStream, modelFileName);
|
||||
|
||||
assertTrue(isModelDeployed(modelFileName));
|
||||
assertEquals(defaultModelCnt+1, dictionaryService.getAllModels().size());
|
||||
|
||||
ClassDefinition myType = dictionaryService.getClass(typeName);
|
||||
assertNotNull(myType);
|
||||
assertEquals(modelName, myType.getModel().getName());
|
||||
|
||||
// can re-deploy a deployed model (note: re-deploying the same model is a valid incremental update)
|
||||
modelStream = new ByteArrayInputStream(model.getBytes("UTF-8"));
|
||||
repoAdminService.deployModel(modelStream, modelFileName);
|
||||
|
||||
// deactivate model
|
||||
repoAdminService.deactivateModel(modelFileName);
|
||||
|
||||
assertTrue(isModelDeployed(modelFileName)); // still deployed, although not active
|
||||
assertEquals(defaultModelCnt, dictionaryService.getAllModels().size());
|
||||
assertNull(dictionaryService.getClass(typeName));
|
||||
|
||||
// try to deactivate an already deactivated model
|
||||
try
|
||||
{
|
||||
repoAdminService.deactivateModel(modelFileName);
|
||||
fail();
|
||||
}
|
||||
catch (AlfrescoRuntimeException are)
|
||||
{
|
||||
// expected
|
||||
assertTrue(are.getMessage().contains("Model deactivation failed"));
|
||||
}
|
||||
|
||||
// re-activate model
|
||||
repoAdminService.activateModel(modelFileName);
|
||||
|
||||
assertTrue(isModelDeployed(modelFileName));
|
||||
assertEquals(defaultModelCnt+1, dictionaryService.getAllModels().size());
|
||||
|
||||
myType = dictionaryService.getClass(typeName);
|
||||
assertNotNull(myType);
|
||||
assertEquals(modelName, myType.getModel().getName());
|
||||
|
||||
// try to activate an already activated model
|
||||
try
|
||||
{
|
||||
repoAdminService.activateModel(modelFileName);
|
||||
fail();
|
||||
}
|
||||
catch (AlfrescoRuntimeException are)
|
||||
{
|
||||
// expected
|
||||
assertTrue(are.getMessage().contains("Model activation failed"));
|
||||
}
|
||||
|
||||
// undeploy model
|
||||
repoAdminService.undeployModel(modelFileName);
|
||||
|
||||
assertFalse(isModelDeployed(modelFileName));
|
||||
assertEquals(defaultModelCnt, dictionaryService.getAllModels().size());
|
||||
assertNull(dictionaryService.getClass(typeName));
|
||||
|
||||
// try to undeploy an already undeployed (or non-existant) model
|
||||
try
|
||||
{
|
||||
repoAdminService.undeployModel(modelFileName);
|
||||
fail();
|
||||
}
|
||||
catch (AlfrescoRuntimeException are)
|
||||
{
|
||||
// expected
|
||||
assertTrue(are.getMessage().contains("Model undeployment failed"));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (isModelDeployed(modelFileName))
|
||||
{
|
||||
// undeploy model
|
||||
repoAdminService.undeployModel(modelFileName);
|
||||
}
|
||||
|
||||
assertNull(dictionaryService.getClass(typeName));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isModelDeployed(String modelFileName)
|
||||
{
|
||||
for (RepoModelDefinition modelDef : repoAdminService.getModels())
|
||||
{
|
||||
if (modelDef.getRepoName().equals(modelFileName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void undeployModels(int modelCnt)
|
||||
{
|
||||
for (int i = 1; i <= modelCnt; i++)
|
||||
{
|
||||
if (isModelDeployed(modelPrefix+i))
|
||||
{
|
||||
repoAdminService.undeployModel(modelPrefix+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deployModels(int modelCnt) throws UnsupportedEncodingException
|
||||
{
|
||||
for (int i = 1; i <= modelCnt; i++)
|
||||
{
|
||||
if (! isModelDeployed(modelPrefix+i))
|
||||
{
|
||||
String model = MODEL_MKR_XML.replace(MKR, i+"");
|
||||
InputStream modelStream = new ByteArrayInputStream(model.getBytes("UTF-8"));
|
||||
repoAdminService.deployModel(modelStream, modelPrefix+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testConcurrentDynamicModelCreate() throws Exception
|
||||
{
|
||||
final int n = 5;
|
||||
|
||||
undeployModels(n);
|
||||
|
||||
int deployedModelCount = repoAdminService.getModels().size();
|
||||
logger.info("Existing deployed custom model count: "+deployedModelCount);
|
||||
|
||||
int dictModelCount = getModelCount();
|
||||
logger.info("Existing dictionary model count: "+dictModelCount);
|
||||
|
||||
// concurrently deploy N models
|
||||
runConcurrentOps(n, 1);
|
||||
|
||||
assertEquals(deployedModelCount+n, repoAdminService.getModels().size());
|
||||
|
||||
for (int i = 1; i <= n; i++)
|
||||
{
|
||||
assertTrue(isModelDeployed(modelPrefix+i));
|
||||
}
|
||||
|
||||
assertEquals(dictModelCount+n, getModelCount());
|
||||
|
||||
undeployModels(n);
|
||||
}
|
||||
|
||||
public void testConcurrentDynamicModelDelete() throws Exception
|
||||
{
|
||||
final int n = 5;
|
||||
|
||||
undeployModels(n);
|
||||
|
||||
int deployedModelCount = repoAdminService.getModels().size();
|
||||
logger.info("Existing deployed custom model count: "+deployedModelCount);
|
||||
|
||||
int dictModelCount = getModelCount();
|
||||
logger.info("Existing dictionary model count: "+dictModelCount);
|
||||
|
||||
deployModels(n);
|
||||
|
||||
assertEquals(deployedModelCount+n, repoAdminService.getModels().size());
|
||||
|
||||
for (int i = 1; i <= n; i++)
|
||||
{
|
||||
assertTrue(isModelDeployed(modelPrefix+i));
|
||||
}
|
||||
|
||||
assertEquals(dictModelCount+n, getModelCount());
|
||||
|
||||
// concurrently undeploy N models
|
||||
runConcurrentOps(n, 2);
|
||||
|
||||
assertEquals(deployedModelCount, repoAdminService.getModels().size());
|
||||
|
||||
for (int i = 1; i <= n; i++)
|
||||
{
|
||||
assertFalse(isModelDeployed(modelPrefix+i));
|
||||
}
|
||||
|
||||
assertEquals(dictModelCount, getModelCount());
|
||||
}
|
||||
|
||||
private int getModelCount()
|
||||
{
|
||||
return dictionaryService.getAllModels().size();
|
||||
}
|
||||
|
||||
private void runConcurrentOps(int threadCnt, int opType) throws InterruptedException
|
||||
{
|
||||
Thread[] threads = new Thread[threadCnt];
|
||||
Tester[] testers = new Tester[threadCnt];
|
||||
|
||||
for (int i = 0; i < threadCnt; i++)
|
||||
{
|
||||
Tester tester = new Tester(i+1, opType);
|
||||
testers[i] = tester;
|
||||
|
||||
threads[i] = new Thread(tester);
|
||||
threads[i].start();
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCnt; i++)
|
||||
{
|
||||
threads[i].join();
|
||||
|
||||
if (testers[i].getErrorStackTrace() != null)
|
||||
{
|
||||
fail(testers[i].getErrorStackTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Tester implements Runnable
|
||||
{
|
||||
private int i;
|
||||
private int opType;
|
||||
private String errorStackTrace = null;
|
||||
|
||||
public Tester(int i, int opType)
|
||||
{
|
||||
this.i = i;
|
||||
this.opType = opType;
|
||||
}
|
||||
|
||||
public String getErrorStackTrace()
|
||||
{
|
||||
return errorStackTrace;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
if (opType == 1)
|
||||
{
|
||||
// Deploy model
|
||||
String model = MODEL_MKR_XML.replace(MKR, i+"");
|
||||
InputStream modelStream = new ByteArrayInputStream(model.getBytes("UTF-8"));
|
||||
repoAdminService.deployModel(modelStream, modelPrefix+i);
|
||||
|
||||
logger.info("["+i+"] Deploying test model: "+modelPrefix+i+" ["+AlfrescoTransactionSupport.getTransactionId()+"]");
|
||||
}
|
||||
else if (opType == 2)
|
||||
{
|
||||
// Undeploy model
|
||||
repoAdminService.undeployModel(modelPrefix+i);
|
||||
|
||||
logger.info("["+i+"] Undeployed test model: "+modelPrefix+i+" ["+AlfrescoTransactionSupport.getTransactionId()+"]");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
t.printStackTrace(new PrintWriter(sw));
|
||||
errorStackTrace = sw.toString();
|
||||
|
||||
logger.error("["+i+"] Failed to deploy test model: "+t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TODO - Test custom message management
|
||||
//
|
||||
}
|
@@ -20,11 +20,13 @@ package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -32,7 +34,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
/**
|
||||
* Bootstrap Dictionary DAO with pre-defined models & message resources (from classpath)
|
||||
*
|
||||
* @author David Caruana
|
||||
* @author David Caruana, janv
|
||||
*
|
||||
*/
|
||||
public class DictionaryBootstrap implements DictionaryListener
|
||||
@@ -50,7 +52,7 @@ public class DictionaryBootstrap implements DictionaryListener
|
||||
private TenantService tenantService;
|
||||
|
||||
// Logger
|
||||
private static Log logger = LogFactory.getLog(DictionaryDAO.class);
|
||||
private static Log logger = LogFactory.getLog(DictionaryBootstrap.class);
|
||||
|
||||
|
||||
/**
|
||||
@@ -110,7 +112,6 @@ public class DictionaryBootstrap implements DictionaryListener
|
||||
*/
|
||||
public void register()
|
||||
{
|
||||
dictionaryDAO.destroy(); // deployer - force reload on next get
|
||||
dictionaryDAO.register(this);
|
||||
}
|
||||
|
||||
@@ -120,6 +121,11 @@ public class DictionaryBootstrap implements DictionaryListener
|
||||
*/
|
||||
public void onDictionaryInit()
|
||||
{
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
Collection<QName> modelsBefore = dictionaryDAO.getModels(); // note: on first bootstrap will init empty dictionary
|
||||
int modelsBeforeCnt = (modelsBefore != null ? modelsBefore.size() : 0);
|
||||
|
||||
if ((tenantService == null) || (! tenantService.isTenantUser()))
|
||||
{
|
||||
// register models
|
||||
@@ -132,12 +138,13 @@ public class DictionaryBootstrap implements DictionaryListener
|
||||
}
|
||||
try
|
||||
{
|
||||
M2Model model = M2Model.createModel(modelStream);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Loading model from " + bootstrapModel);
|
||||
logger.debug("Loading model: "+model.getName()+" (from "+bootstrapModel+")");
|
||||
}
|
||||
|
||||
M2Model model = M2Model.createModel(modelStream);
|
||||
dictionaryDAO.putModel(model);
|
||||
}
|
||||
catch(DictionaryException e)
|
||||
@@ -145,6 +152,14 @@ public class DictionaryBootstrap implements DictionaryListener
|
||||
throw new DictionaryException("Could not import bootstrap model " + bootstrapModel, e);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<QName> modelsAfter = dictionaryDAO.getModels();
|
||||
int modelsAfterCnt = (modelsAfter != null ? modelsAfter.size() : 0);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Model count: before="+modelsBeforeCnt+", load="+models.size()+", after="+modelsAfterCnt+" in "+(System.currentTimeMillis()-startTime)+" msecs");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -46,7 +46,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
{
|
||||
private DictionaryDAO dictionaryDAO;
|
||||
|
||||
|
||||
// TODO: Check passed arguments are valid
|
||||
|
||||
/**
|
||||
@@ -59,7 +58,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
this.dictionaryDAO = dictionaryDAO;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getAllModels()
|
||||
*/
|
||||
@@ -68,7 +66,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return dictionaryDAO.getModels();
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getModel(org.alfresco.repo.ref.QName)
|
||||
*/
|
||||
@@ -90,7 +87,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return propertyTypes;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getPropertyTypes(org.alfresco.repo.ref.QName)
|
||||
*/
|
||||
@@ -105,7 +101,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return qnames;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getAllTypes()
|
||||
*/
|
||||
@@ -128,7 +123,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return dictionaryDAO.getSubTypes(superType, follow);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getTypes(org.alfresco.repo.ref.QName)
|
||||
*/
|
||||
@@ -143,7 +137,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return qnames;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getAllAspects()
|
||||
*/
|
||||
@@ -170,7 +163,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return associations;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.dictionary.DictionaryService#getSubAspects(org.alfresco.service.namespace.QName, boolean)
|
||||
*/
|
||||
@@ -208,7 +200,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return qnames;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#isSubClass(org.alfresco.repo.ref.QName, org.alfresco.repo.ref.QName)
|
||||
*/
|
||||
@@ -248,7 +239,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return subClassOf;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getPropertyType(org.alfresco.repo.ref.QName)
|
||||
*/
|
||||
@@ -257,7 +247,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return dictionaryDAO.getDataType(name);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.dictionary.DictionaryService#getDataType(java.lang.Class)
|
||||
*/
|
||||
@@ -266,7 +255,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return dictionaryDAO.getDataType(javaClass);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getType(org.alfresco.repo.ref.QName)
|
||||
*/
|
||||
@@ -275,7 +263,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return dictionaryDAO.getType(name);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getAspect(org.alfresco.repo.ref.QName)
|
||||
*/
|
||||
@@ -284,7 +271,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return dictionaryDAO.getAspect(name);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getClass(org.alfresco.repo.ref.QName)
|
||||
*/
|
||||
@@ -331,7 +317,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.dictionary.DictionaryService#getProperty(org.alfresco.repo.ref.QName)
|
||||
*/
|
||||
@@ -348,7 +333,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return dictionaryDAO.getAssociation(associationName);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.dictionary.DictionaryService#getAllProperties(org.alfresco.service.namespace.QName)
|
||||
@@ -363,7 +347,6 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return aspects;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.dictionary.DictionaryService#getAllProperties(org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName)
|
||||
@@ -380,7 +363,9 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.dictionary.DictionaryService#getProperties(org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
public Collection<QName> getProperties(QName model)
|
||||
{
|
||||
Collection<PropertyDefinition> propDefs = dictionaryDAO.getProperties(model);
|
||||
@@ -392,11 +377,30 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
|
||||
return props;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.dictionary.DictionaryService#getConstraint(org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
public ConstraintDefinition getConstraint(QName constraintQName)
|
||||
{
|
||||
return dictionaryDAO.getConstraint(constraintQName);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.dictionary.DictionaryService#getConstraints(org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
public Collection<ConstraintDefinition> getConstraints(QName model)
|
||||
{
|
||||
return dictionaryDAO.getConstraints(model);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.dictionary.DictionaryService#getConstraints(org.alfresco.service.namespace.QName, boolean)
|
||||
*/
|
||||
public Collection<ConstraintDefinition> getConstraints(QName model, boolean referenceableDefsOnly)
|
||||
{
|
||||
return dictionaryDAO.getConstraints(model, referenceableDefsOnly);
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
dictionaryDAO.init();
|
||||
|
@@ -19,6 +19,7 @@
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
@@ -138,26 +139,26 @@ public interface DictionaryDAO extends ModelQuery
|
||||
public Collection<NamespaceDefinition> getNamespaces(QName modelName);
|
||||
|
||||
/**
|
||||
* @param model the model to retrieve constraints for
|
||||
* @param model the model to retrieve constraint defs (including property constaint refs)
|
||||
* @return the constraints of the model
|
||||
*/
|
||||
public Collection<ConstraintDefinition> getConstraints(QName model);
|
||||
|
||||
/**
|
||||
* validate against dictionary
|
||||
*
|
||||
* if new model
|
||||
* then nothing to validate
|
||||
*
|
||||
* else if an existing model
|
||||
* then could be updated (or unchanged) so validate to currently only allow incremental updates
|
||||
* - addition of new types, aspects (except default aspects), properties, associations
|
||||
* - no deletion of types, aspects or properties or associations
|
||||
* - no addition, update or deletion of default/mandatory aspects
|
||||
*
|
||||
* @param newOrUpdatedModel
|
||||
* @param model the model to retrieve constraint defs (optionally only referenceable constraints)
|
||||
* @return the constraints of the model
|
||||
*/
|
||||
public void validateModel(M2Model newOrUpdatedModel);
|
||||
public Collection<ConstraintDefinition> getConstraints(QName model, boolean referenceableDefsOnly);
|
||||
|
||||
/**
|
||||
* Return diffs between input model and model in the Dictionary.
|
||||
*
|
||||
* If the input model does not exist in the Dictionary then no diffs will be returned.
|
||||
*
|
||||
* @param model
|
||||
* @return model diffs (if any)
|
||||
*/
|
||||
public List<M2ModelDiff> diffModel(M2Model model);
|
||||
|
||||
/**
|
||||
*
|
||||
|
@@ -46,7 +46,6 @@ import org.alfresco.service.cmr.dictionary.NamespaceDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -54,7 +53,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
/**
|
||||
* Default implementation of the Dictionary.
|
||||
*
|
||||
* @author David Caruana
|
||||
* @author David Caruana, janv
|
||||
*
|
||||
*/
|
||||
public class DictionaryDAOImpl implements DictionaryDAO
|
||||
@@ -299,12 +298,12 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
// Publish new Model Definition
|
||||
getCompiledModels(tenantDomain).put(modelName, compiledModel);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.debug("Registered model " + modelName.toPrefixString(namespaceDAO));
|
||||
logger.trace("Registered model: " + modelName.toPrefixString(namespaceDAO));
|
||||
for (M2Namespace namespace : model.getNamespaces())
|
||||
{
|
||||
logger.debug("Registered namespace '" + namespace.getUri() + "' (prefix '" + namespace.getPrefix() + "')");
|
||||
logger.trace("Registered namespace: '" + namespace.getUri() + "' (prefix '" + namespace.getPrefix() + "')");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -941,10 +940,37 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
* @see org.alfresco.repo.dictionary.DictionaryDAO#getConstraints(org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
public Collection<ConstraintDefinition> getConstraints(QName modelName)
|
||||
{
|
||||
return getConstraints(modelName, false);
|
||||
}
|
||||
|
||||
public Collection<ConstraintDefinition> getConstraints(QName modelName, boolean referenceableDefsOnly)
|
||||
{
|
||||
CompiledModel model = getCompiledModel(modelName);
|
||||
if (referenceableDefsOnly)
|
||||
{
|
||||
return getReferenceableConstraintDefs(model);
|
||||
}
|
||||
else
|
||||
{
|
||||
return model.getConstraints();
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<ConstraintDefinition> getReferenceableConstraintDefs(CompiledModel model)
|
||||
{
|
||||
Collection<ConstraintDefinition> conDefs = model.getConstraints();
|
||||
Collection<PropertyDefinition> propDefs = model.getProperties();
|
||||
for (PropertyDefinition propDef : propDefs)
|
||||
{
|
||||
for (ConstraintDefinition conDef : propDef.getConstraints())
|
||||
{
|
||||
conDefs.remove(conDef);
|
||||
}
|
||||
}
|
||||
|
||||
return conDefs;
|
||||
}
|
||||
|
||||
// re-entrant (eg. via reset)
|
||||
private DictionaryRegistry getDictionaryRegistry(String tenantDomain)
|
||||
@@ -974,9 +1000,9 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.debug("getDictionaryRegistry: not in cache (or threadlocal) - re-init ["+Thread.currentThread().getId()+", "+AlfrescoTransactionSupport.getTransactionId()+"]"+(tenantDomain.equals(TenantService.DEFAULT_DOMAIN) ? "" : " (Tenant: "+tenantDomain+")"));
|
||||
logger.trace("getDictionaryRegistry: not in cache (or threadlocal) - re-init ["+Thread.currentThread().getId()+", "+AlfrescoTransactionSupport.getTransactionId()+"]"+(tenantDomain.equals(TenantService.DEFAULT_DOMAIN) ? "" : " (Tenant: "+tenantDomain+")"));
|
||||
}
|
||||
|
||||
// reset caches - may have been invalidated (e.g. in a cluster)
|
||||
@@ -1088,13 +1114,12 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
/**
|
||||
* Return diffs between input model and model in the Dictionary.
|
||||
*
|
||||
* If the input model does not exist in the Dictionary or is equivalent to the one in the Dictionary
|
||||
* then no diffs will be returned.
|
||||
* If the input model does not exist in the Dictionary then no diffs will be returned.
|
||||
*
|
||||
* @param model
|
||||
* @return model diffs (if any)
|
||||
*/
|
||||
private List<M2ModelDiff> diffModel(M2Model model)
|
||||
public List<M2ModelDiff> diffModel(M2Model model)
|
||||
{
|
||||
// Compile model definition
|
||||
CompiledModel compiledModel = model.compile(this, namespaceDAO);
|
||||
@@ -1140,6 +1165,7 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
{
|
||||
Collection<TypeDefinition> previousTypes = previousVersion.getTypes();
|
||||
Collection<AspectDefinition> previousAspects = previousVersion.getAspects();
|
||||
Collection<ConstraintDefinition> previousConDefs = getReferenceableConstraintDefs(previousVersion);
|
||||
|
||||
if (model == null)
|
||||
{
|
||||
@@ -1152,12 +1178,17 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
{
|
||||
M2ModelDiffs.add(new M2ModelDiff(previousAspect.getName(), M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_DELETED));
|
||||
}
|
||||
for (ConstraintDefinition previousConDef : previousConDefs)
|
||||
{
|
||||
M2ModelDiffs.add(new M2ModelDiff(previousConDef.getName(), M2ModelDiff.TYPE_CONSTRAINT, M2ModelDiff.DIFF_DELETED));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// update model
|
||||
Collection<TypeDefinition> types = model.getTypes();
|
||||
Collection<AspectDefinition> aspects = model.getAspects();
|
||||
Collection<ConstraintDefinition> conDefs = getReferenceableConstraintDefs(model);
|
||||
|
||||
if (previousTypes.size() != 0)
|
||||
{
|
||||
@@ -1182,6 +1213,18 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
M2ModelDiffs.add(new M2ModelDiff(aspect.getName(), M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_CREATED));
|
||||
}
|
||||
}
|
||||
|
||||
if (previousConDefs.size() != 0)
|
||||
{
|
||||
M2ModelDiffs.addAll(M2ConstraintDefinition.diffConstraintLists(new ArrayList<ConstraintDefinition>(previousConDefs), new ArrayList<ConstraintDefinition>(conDefs)));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ConstraintDefinition conDef : conDefs)
|
||||
{
|
||||
M2ModelDiffs.add(new M2ModelDiff(conDef.getName(), M2ModelDiff.TYPE_CONSTRAINT, M2ModelDiff.DIFF_CREATED));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1211,41 +1254,6 @@ public class DictionaryDAOImpl implements DictionaryDAO
|
||||
return M2ModelDiffs;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate against dictionary
|
||||
*
|
||||
* if new model
|
||||
* then nothing to validate
|
||||
*
|
||||
* else if an existing model
|
||||
* then could be updated (or unchanged) so validate to currently only allow incremental updates
|
||||
* - addition of new types, aspects (except default aspects), properties, associations
|
||||
* - no deletion of types, aspects or properties or associations
|
||||
* - no addition, update or deletion of default/mandatory aspects
|
||||
*
|
||||
* @param newOrUpdatedModel
|
||||
*/
|
||||
public void validateModel(M2Model newOrUpdatedModel)
|
||||
{
|
||||
// Check that all the passed values are not null
|
||||
ParameterCheck.mandatory("newOrUpdatedModel", newOrUpdatedModel);
|
||||
|
||||
List<M2ModelDiff> modelDiffs = diffModel(newOrUpdatedModel);
|
||||
|
||||
for (M2ModelDiff modelDiff : modelDiffs)
|
||||
{
|
||||
if (modelDiff.getDiffType().equals(M2ModelDiff.DIFF_DELETED))
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to validate model update - found deleted " + modelDiff.getElementType() + " '" + modelDiff.getElementName() + "'");
|
||||
}
|
||||
|
||||
if (modelDiff.getDiffType().equals(M2ModelDiff.DIFF_UPDATED))
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to validate model update - found non-incrementally updated " + modelDiff.getElementType() + " '" + modelDiff.getElementName() + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ class DictionaryRegistry
|
||||
{
|
||||
private Map<String, List<CompiledModel>> uriToModels = new HashMap<String, List<CompiledModel>>(0);
|
||||
|
@@ -19,11 +19,12 @@
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
@@ -38,12 +39,16 @@ import org.alfresco.repo.tenant.TenantAdminService;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.transaction.TransactionListenerAdapter;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.repo.version.Version2Model;
|
||||
import org.alfresco.repo.workflow.BPMEngineRegistry;
|
||||
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.NamespaceDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
@@ -58,6 +63,7 @@ import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -119,6 +125,8 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
/** The tenant deployer service */
|
||||
private TenantAdminService tenantAdminService;
|
||||
|
||||
private TransactionService transactionService;
|
||||
|
||||
/** Transaction listener */
|
||||
private DictionaryModelTypeTransactionListener transactionListener;
|
||||
|
||||
@@ -205,6 +213,14 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
this.tenantAdminService = tenantAdminService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction service
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
public void setStoreUrls(List<String> storeUrls)
|
||||
{
|
||||
this.storeUrls = storeUrls;
|
||||
@@ -263,19 +279,25 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
*/
|
||||
public void onContentUpdate(NodeRef nodeRef, boolean newContent)
|
||||
{
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("onContentUpdate: nodeRef="+nodeRef+ " ["+AlfrescoTransactionSupport.getTransactionId()+"]");
|
||||
}
|
||||
|
||||
queueModel(nodeRef);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void queueModel(NodeRef nodeRef)
|
||||
{
|
||||
Set<NodeRef> pendingModelUpdates = (Set<NodeRef>)AlfrescoTransactionSupport.getResource(KEY_PENDING_MODELS);
|
||||
if (pendingModelUpdates == null)
|
||||
Set<NodeRef> pendingModels = (Set<NodeRef>)AlfrescoTransactionSupport.getResource(KEY_PENDING_MODELS);
|
||||
if (pendingModels == null)
|
||||
{
|
||||
pendingModelUpdates = new HashSet<NodeRef>();
|
||||
AlfrescoTransactionSupport.bindResource(KEY_PENDING_MODELS, pendingModelUpdates);
|
||||
//pendingModels = Collections.newSetFromMap(new ConcurrentHashMap()); // Java 6
|
||||
pendingModels = new CopyOnWriteArraySet<NodeRef>();
|
||||
AlfrescoTransactionSupport.bindResource(KEY_PENDING_MODELS, pendingModels);
|
||||
}
|
||||
pendingModelUpdates.add(tenantService.getName(nodeRef));
|
||||
pendingModels.add(tenantService.getName(nodeRef));
|
||||
|
||||
AlfrescoTransactionSupport.bindListener(this.transactionListener);
|
||||
}
|
||||
@@ -292,6 +314,11 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
Map<QName, Serializable> before,
|
||||
Map<QName, Serializable> after)
|
||||
{
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("onUpdateProperties: nodeRef="+nodeRef+ " ["+AlfrescoTransactionSupport.getTransactionId()+"]");
|
||||
}
|
||||
|
||||
Boolean beforeValue = (Boolean)before.get(ContentModel.PROP_MODEL_ACTIVE);
|
||||
Boolean afterValue = (Boolean)after.get(ContentModel.PROP_MODEL_ACTIVE);
|
||||
|
||||
@@ -312,6 +339,11 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
|
||||
public void onRemoveAspect(NodeRef nodeRef, QName aspect)
|
||||
{
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("onRemoveAspect: nodeRef="+nodeRef+ " ["+AlfrescoTransactionSupport.getTransactionId()+"]");
|
||||
}
|
||||
|
||||
// undo/cancel checkout removes the "workingcopy" aspect prior to deleting the node - hence need to track here
|
||||
if (aspect.equals(ContentModel.ASPECT_WORKING_COPY))
|
||||
{
|
||||
@@ -342,24 +374,28 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
archived = true;
|
||||
}
|
||||
|
||||
// Ignore if the node is a working copy or archived
|
||||
if (! (workingCopy || archived))
|
||||
boolean isVersionNode = nodeRef.getStoreRef().getIdentifier().equals(Version2Model.STORE_ID);
|
||||
|
||||
// Ignore if the node is a working copy, archived or version node
|
||||
if (! (workingCopy || archived || isVersionNode))
|
||||
{
|
||||
QName modelName = (QName)this.nodeService.getProperty(nodeRef, ContentModel.PROP_MODEL_NAME);
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("beforeDeleteNode: nodeRef="+nodeRef+" validate model delete (modelName="+modelName+")");
|
||||
}
|
||||
|
||||
if (modelName != null)
|
||||
{
|
||||
// Validate model delete against usages - content and/or workflows
|
||||
validateModelDelete(modelName);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("beforeDeleteNode: modelName="+modelName+" ("+nodeRef+")");
|
||||
}
|
||||
|
||||
Set<NodeRef> pendingModelDeletes = (Set<NodeRef>)AlfrescoTransactionSupport.getResource(KEY_PENDING_DELETE_MODELS);
|
||||
if (pendingModelDeletes == null)
|
||||
{
|
||||
pendingModelDeletes = new HashSet<NodeRef>();
|
||||
//pendingModelDeletes = Collections.newSetFromMap(new ConcurrentHashMap()); // Java 6
|
||||
pendingModelDeletes = new CopyOnWriteArraySet<NodeRef>();
|
||||
AlfrescoTransactionSupport.bindResource(KEY_PENDING_DELETE_MODELS, pendingModelDeletes);
|
||||
}
|
||||
pendingModelDeletes.add(tenantService.getName(nodeRef));
|
||||
@@ -367,13 +403,26 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
AlfrescoTransactionSupport.bindListener(this.transactionListener);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("beforeDeleteNode: nodeRef="+nodeRef+ " ignored ("+(workingCopy ? " workingCopy " : "")+(archived ? " archived " : "")+(isVersionNode ? " isVersionNode " : "")+") ["+AlfrescoTransactionSupport.getTransactionId()+"]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
//@SuppressWarnings("unchecked")
|
||||
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isNodeArchived)
|
||||
{
|
||||
/*
|
||||
NodeRef nodeRef = childAssocRef.getChildRef();
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("onDeleteNode: nodeRef="+nodeRef+ " ["+AlfrescoTransactionSupport.getTransactionId()+"]");
|
||||
}
|
||||
|
||||
Set<NodeRef> pendingDeleteModels = (Set<NodeRef>)AlfrescoTransactionSupport.getResource(KEY_PENDING_DELETE_MODELS);
|
||||
|
||||
if (pendingDeleteModels != null)
|
||||
@@ -393,13 +442,25 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
return null;
|
||||
}
|
||||
}, tenantSystemUserName);
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("onDeleteNode: Dictionary destroyed ["+AlfrescoTransactionSupport.getTransactionId()+"]");
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
NodeRef nodeRef = childAssocRef.getChildRef();
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("onCreateNode: nodeRef="+nodeRef+ " ["+AlfrescoTransactionSupport.getTransactionId()+"]");
|
||||
}
|
||||
|
||||
if (nodeService.getType(nodeRef).equals(ContentModel.TYPE_DICTIONARY_MODEL))
|
||||
{
|
||||
Boolean value = (Boolean)nodeService.getProperty(nodeRef, ContentModel.PROP_MODEL_ACTIVE);
|
||||
@@ -429,6 +490,81 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void afterCommit()
|
||||
{
|
||||
Set<NodeRef> pendingModels = (Set<NodeRef>)AlfrescoTransactionSupport.getResource(KEY_PENDING_MODELS);
|
||||
Set<NodeRef> pendingDeleteModels = (Set<NodeRef>)AlfrescoTransactionSupport.getResource(KEY_PENDING_DELETE_MODELS);
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("afterCommit: pendingModelsCnt="+(pendingModels != null ? pendingModels.size() : "0")+
|
||||
", pendingDeleteModelsCnt="+(pendingDeleteModels != null ? pendingDeleteModels.size() : "0"));
|
||||
}
|
||||
|
||||
Set<String> systemTenants = new HashSet<String>(10);
|
||||
|
||||
if (pendingModels != null)
|
||||
{
|
||||
// unbind the resource from the transaction
|
||||
AlfrescoTransactionSupport.unbindResource(KEY_PENDING_MODELS);
|
||||
|
||||
for (NodeRef nodeRef : pendingModels)
|
||||
{
|
||||
String tenantDomain = tenantService.getDomain(nodeRef.getStoreRef().getIdentifier());
|
||||
String tenantSystemUserName = tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain);
|
||||
systemTenants.add(tenantSystemUserName);
|
||||
}
|
||||
}
|
||||
|
||||
if (pendingDeleteModels != null)
|
||||
{
|
||||
// unbind the resource from the transaction
|
||||
AlfrescoTransactionSupport.unbindResource(KEY_PENDING_DELETE_MODELS);
|
||||
|
||||
for (NodeRef nodeRef : pendingDeleteModels)
|
||||
{
|
||||
String tenantDomain = tenantService.getDomain(nodeRef.getStoreRef().getIdentifier());
|
||||
String tenantSystemUserName = tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain);
|
||||
systemTenants.add(tenantSystemUserName);
|
||||
}
|
||||
}
|
||||
|
||||
if (systemTenants.size() > 0)
|
||||
{
|
||||
for (final String tenantSystemUserName : systemTenants)
|
||||
{
|
||||
RetryingTransactionCallback<Void> work = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||
{
|
||||
public Object doWork()
|
||||
{
|
||||
// invalidate - to force lazy re-init
|
||||
// note: since afterCommit - need to either clear shared cache or destroy in separate txn
|
||||
dictionaryDAO.destroy();
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("afterCommit: Dictionary destroyed ["+AlfrescoTransactionSupport.getTransactionId()+"]");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}, tenantSystemUserName);
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(work, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#beforeCommit(boolean)
|
||||
*/
|
||||
@@ -440,14 +576,11 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
|
||||
if (pendingModels != null)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.debug("beforeCommit: pendingModelsCnt="+pendingModels.size());
|
||||
logger.trace("beforeCommit: pendingModelsCnt="+pendingModels.size());
|
||||
}
|
||||
|
||||
// unbind the resource from the transaction
|
||||
AlfrescoTransactionSupport.unbindResource(KEY_PENDING_MODELS);
|
||||
|
||||
for (NodeRef pendingNodeRef : pendingModels)
|
||||
{
|
||||
String tenantDomain = tenantService.getDomain(pendingNodeRef.getStoreRef().getIdentifier());
|
||||
@@ -459,6 +592,12 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
{
|
||||
public Object doWork()
|
||||
{
|
||||
// Ignore if the node no longer exists
|
||||
if (! nodeService.exists(nodeRef))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find out whether the model is active
|
||||
boolean isActive = false;
|
||||
Boolean value = (Boolean)nodeService.getProperty(nodeRef, ContentModel.PROP_MODEL_ACTIVE);
|
||||
@@ -482,7 +621,8 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
M2Model m2Model = M2Model.createModel(contentReader.getContentInputStream());
|
||||
|
||||
// Try and compile the model
|
||||
ModelDefinition modelDefinition = m2Model.compile(dictionaryDAO, namespaceDAO).getModelDefinition();
|
||||
CompiledModel compiledModel= m2Model.compile(dictionaryDAO, namespaceDAO);
|
||||
ModelDefinition modelDefinition = compiledModel.getModelDefinition();
|
||||
|
||||
// Update the meta data for the model
|
||||
Map<QName, Serializable> props = nodeService.getProperties(nodeRef);
|
||||
@@ -493,32 +633,16 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
props.put(ContentModel.PROP_MODEL_VERSION, modelDefinition.getVersion());
|
||||
nodeService.setProperties(nodeRef, props);
|
||||
|
||||
ArrayList<NodeRef> modelNodeRefs = getModelNodes(nodeRef.getStoreRef(), modelDefinition.getName());
|
||||
for (NodeRef existingNodeRef : modelNodeRefs)
|
||||
{
|
||||
if (! existingNodeRef.equals(nodeRef))
|
||||
{
|
||||
// check if existing model node is active
|
||||
Boolean existingValue = (Boolean)nodeService.getProperty(existingNodeRef, ContentModel.PROP_MODEL_ACTIVE);
|
||||
if ((existingValue != null) && (existingValue.booleanValue() == true))
|
||||
{
|
||||
String name = (String)nodeService.getProperty(existingNodeRef, ContentModel.PROP_NAME);
|
||||
|
||||
// for MT import, model may have been activated by DictionaryRepositoryBootstrap
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Re-activating '"+modelDefinition.getName()+"' - existing active model: " + name);
|
||||
}
|
||||
//throw new AlfrescoRuntimeException("Cannot activate '"+modelDefinition.getName()+"' - existing active model: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate model against dictionary - could be new, unchanged or updated
|
||||
dictionaryDAO.validateModel(m2Model);
|
||||
validateModel(modelDefinition.getName(), m2Model, compiledModel);
|
||||
|
||||
// invalidate - to force lazy re-init
|
||||
dictionaryDAO.destroy();
|
||||
//dictionaryDAO.destroy();
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("beforeCommit: activating nodeRef="+nodeRef+" ("+modelDefinition.getName()+")");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -530,7 +654,12 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
validateModelDelete(modelName);
|
||||
|
||||
// invalidate - to force lazy re-init
|
||||
dictionaryDAO.destroy();
|
||||
//dictionaryDAO.destroy();
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("beforeCommit: deactivating nodeRef="+nodeRef+" ("+modelName+")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,7 +709,10 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
}
|
||||
catch (DictionaryException e)
|
||||
{
|
||||
logger.warn("Model ' + modelName + ' does not exist ... skip delete validation : " + e);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Dictionary model '" + modelName + "' does not exist ... skip delete validation : " + e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -687,29 +819,162 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<NodeRef> getModelNodes(StoreRef storeRef, QName modelName)
|
||||
/**
|
||||
* validate against dictionary
|
||||
*
|
||||
* if new model
|
||||
* then nothing to validate
|
||||
*
|
||||
* else if an existing model
|
||||
* then could be updated (or unchanged) so validate to currently only allow incremental updates
|
||||
* - addition of new types, aspects (except default aspects), properties, associations
|
||||
* - no deletion of types, aspects or properties or associations
|
||||
* - no addition, update or deletion of default/mandatory aspects
|
||||
*
|
||||
* @paramn modelName
|
||||
* @param newOrUpdatedModel
|
||||
*/
|
||||
private void validateModel(QName modelName, M2Model model, CompiledModel compiledModel)
|
||||
{
|
||||
ArrayList<NodeRef> nodeRefs = new ArrayList<NodeRef>();
|
||||
List<M2ModelDiff> modelDiffs = dictionaryDAO.diffModel(model);
|
||||
|
||||
ResultSet rs = searchService.query(storeRef, SearchService.LANGUAGE_LUCENE, "TYPE:\""+ContentModel.TYPE_DICTIONARY_MODEL+"\"");
|
||||
for (M2ModelDiff modelDiff : modelDiffs)
|
||||
{
|
||||
if (modelDiff.getDiffType().equals(M2ModelDiff.DIFF_DELETED))
|
||||
{
|
||||
// TODO - check tenants if model is shared / inherited
|
||||
if (modelDiff.getElementType().equals(M2ModelDiff.TYPE_PROPERTY))
|
||||
{
|
||||
validatePropertyDelete(modelName, modelDiff.getElementName(), false);
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (modelDiff.getElementType().equals(M2ModelDiff.TYPE_CONSTRAINT))
|
||||
{
|
||||
validateConstraintDelete(compiledModel, modelDiff.getElementName(), false);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to validate model update - found deleted " + modelDiff.getElementType() + " '" + modelDiff.getElementName() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
if (modelDiff.getDiffType().equals(M2ModelDiff.DIFF_UPDATED))
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to validate model update - found non-incrementally updated " + modelDiff.getElementType() + " '" + modelDiff.getElementName() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO validate that any deleted constraints are not being referenced - else currently will become anon - or push down into model compilation (check backwards compatibility ...)
|
||||
}
|
||||
|
||||
private void validatePropertyDelete(QName modelName, QName propertyName, boolean sharedModel)
|
||||
{
|
||||
String tenantDomain = TenantService.DEFAULT_DOMAIN;
|
||||
if (sharedModel)
|
||||
{
|
||||
tenantDomain = " for tenant [" + tenantService.getCurrentUserDomain() + "]";
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
|
||||
// check for property usages
|
||||
for (PropertyDefinition prop : dictionaryDAO.getProperties(modelName, null))
|
||||
{
|
||||
// TODO ... match property
|
||||
if (prop.getName().equals(propertyName))
|
||||
{
|
||||
// found
|
||||
found = true;
|
||||
validateIndexedProperty(tenantDomain, prop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! found)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to validate property delete" + tenantDomain + " - property definition '" + propertyName + "' not defined in model '" + modelName + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateIndexedProperty(String tenantDomain, PropertyDefinition propDef)
|
||||
{
|
||||
QName propName = propDef.getName();
|
||||
|
||||
if (! propDef.isIndexed())
|
||||
{
|
||||
// TODO ... implement DB-level referential integrity
|
||||
throw new AlfrescoRuntimeException("Failed to validate property delete" + tenantDomain + " - cannot delete unindexed property definition '" + propName);
|
||||
}
|
||||
|
||||
for (String storeUrl : this.storeUrls)
|
||||
{
|
||||
StoreRef store = new StoreRef(storeUrl);
|
||||
|
||||
// search for indexed PROPERTY
|
||||
String escapePropName = propName.toPrefixString().replace(":", "\\:");
|
||||
ResultSet rs = searchService.query(store, SearchService.LANGUAGE_LUCENE, "@"+escapePropName+":*");
|
||||
try
|
||||
{
|
||||
if (rs.length() > 0)
|
||||
{
|
||||
for (NodeRef modelNodeRef : rs.getNodeRefs())
|
||||
{
|
||||
QName name = (QName)nodeService.getProperty(modelNodeRef, ContentModel.PROP_MODEL_NAME);
|
||||
if ((name != null) && (name.equals(modelName)))
|
||||
{
|
||||
nodeRefs.add(modelNodeRef);
|
||||
}
|
||||
}
|
||||
throw new AlfrescoRuntimeException("Failed to validate property delete" + tenantDomain + " - found " + rs.length() + " nodes in store " + store + " with PROPERTY '" + propName + "'" );
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
rs.close();
|
||||
}
|
||||
return nodeRefs;
|
||||
}
|
||||
}
|
||||
|
||||
// validate delete of a referencable constraint def
|
||||
private void validateConstraintDelete(CompiledModel compiledModel, QName constraintName, boolean sharedModel)
|
||||
{
|
||||
String tenantDomain = TenantService.DEFAULT_DOMAIN;
|
||||
if (sharedModel)
|
||||
{
|
||||
tenantDomain = " for tenant [" + tenantService.getCurrentUserDomain() + "]";
|
||||
}
|
||||
|
||||
Set<QName> referencedBy = new HashSet<QName>(0);
|
||||
|
||||
// check for references to constraint definition
|
||||
// note: could be anon prop constraint (if no referenceable constraint)
|
||||
Collection<QName> allModels = dictionaryDAO.getModels();
|
||||
for (QName model : allModels)
|
||||
{
|
||||
Collection<PropertyDefinition> propDefs = null;
|
||||
if (compiledModel.getModelDefinition().getName().equals(model))
|
||||
{
|
||||
// TODO deal with multiple pending model updates
|
||||
propDefs = compiledModel.getProperties();
|
||||
}
|
||||
else
|
||||
{
|
||||
propDefs = dictionaryDAO.getProperties(model);
|
||||
}
|
||||
|
||||
for (PropertyDefinition propDef : propDefs)
|
||||
{
|
||||
for (ConstraintDefinition conDef : propDef.getConstraints())
|
||||
{
|
||||
if (constraintName.equals(conDef.getRef()))
|
||||
{
|
||||
referencedBy.add(conDef.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (referencedBy.size() == 1)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to validate constraint delete" + tenantDomain + " - constraint definition '" + constraintName + "' is being referenced by '" + referencedBy.toArray()[0] + "' property constraint");
|
||||
}
|
||||
else if (referencedBy.size() > 1)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to validate constraint delete" + tenantDomain + " - constraint definition '" + constraintName + "' is being referenced by " + referencedBy.size() + " property constraints");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -19,21 +19,23 @@
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.i18n.MessageService;
|
||||
import org.alfresco.repo.tenant.TenantAdminService;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
||||
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
||||
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.search.SearchService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseAlfrescoSpringTest;
|
||||
@@ -42,14 +44,17 @@ import org.alfresco.util.PropertyMap;
|
||||
/**
|
||||
* Dictionary model type unit test
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
* @author Roy Wetherall, janv
|
||||
*/
|
||||
public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
{
|
||||
/** QName of the test model */
|
||||
private static final QName TEST_MODEL_ONE = QName.createQName("{http://www.alfresco.org/test/testmodel1/1.0}testModelOne");
|
||||
/** QNames of the test models */
|
||||
|
||||
private static final QName TEST_MODEL_ONE = QName.createQName("{http://www.alfresco.org/test/testmodel1/1.0}testModelOne");
|
||||
private static final QName TEST_MODEL_TWO = QName.createQName("{http://www.alfresco.org/test/testmodel2/1.0}testModelTwo");
|
||||
|
||||
/** Test model XMLs */
|
||||
|
||||
/** Test model XML */
|
||||
public static final String MODEL_ONE_XML =
|
||||
"<model name='test1:testModelOne' xmlns='http://www.alfresco.org/model/dictionary/1.0'>" +
|
||||
|
||||
@@ -60,6 +65,7 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
|
||||
" <imports>" +
|
||||
" <import uri='http://www.alfresco.org/model/dictionary/1.0' prefix='d'/>" +
|
||||
" <import uri='http://www.alfresco.org/model/content/1.0' prefix='cm'/>" +
|
||||
" </imports>" +
|
||||
|
||||
" <namespaces>" +
|
||||
@@ -71,6 +77,7 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
" <type name='test1:base'>" +
|
||||
" <title>Base</title>" +
|
||||
" <description>The Base Type</description>" +
|
||||
" <parent>cm:content</parent>" +
|
||||
" <properties>" +
|
||||
" <property name='test1:prop1'>" +
|
||||
" <type>d:text</type>" +
|
||||
@@ -92,6 +99,7 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
|
||||
" <imports>" +
|
||||
" <import uri='http://www.alfresco.org/model/dictionary/1.0' prefix='d'/>" +
|
||||
" <import uri='http://www.alfresco.org/model/content/1.0' prefix='cm'/>" +
|
||||
" </imports>" +
|
||||
|
||||
" <namespaces>" +
|
||||
@@ -103,11 +111,168 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
" <type name='test1:base'>" +
|
||||
" <title>Base</title>" +
|
||||
" <description>The Base Type</description>" +
|
||||
" <parent>cm:content</parent>" +
|
||||
" <properties>" +
|
||||
" <property name='test1:prop1'>" +
|
||||
" <type>d:text</type>" +
|
||||
" </property>" +
|
||||
" <property name='test1:prop2'>" +
|
||||
" <type>d:boolean</type>" +
|
||||
" </property>" +
|
||||
" </properties>" +
|
||||
" </type>" +
|
||||
|
||||
" </types>" +
|
||||
|
||||
"</model>";
|
||||
|
||||
public static final String MODEL_ONE_MODIFIED2_XML =
|
||||
"<model name='test1:testModelOne' xmlns='http://www.alfresco.org/model/dictionary/1.0'>" +
|
||||
|
||||
" <description>Test model one (updated 2)</description>" +
|
||||
" <author>Alfresco</author>" +
|
||||
" <published>2005-05-30</published>" +
|
||||
" <version>1.2</version>" +
|
||||
|
||||
" <imports>" +
|
||||
" <import uri='http://www.alfresco.org/model/dictionary/1.0' prefix='d'/>" +
|
||||
" <import uri='http://www.alfresco.org/model/content/1.0' prefix='cm'/>" +
|
||||
" </imports>" +
|
||||
|
||||
" <namespaces>" +
|
||||
" <namespace uri='http://www.alfresco.org/test/testmodel1/1.0' prefix='test1'/>" +
|
||||
" </namespaces>" +
|
||||
|
||||
" <types>" +
|
||||
|
||||
" <type name='test1:base'>" +
|
||||
" <title>Base</title>" +
|
||||
" <description>The Base Type</description>" +
|
||||
" <parent>cm:content</parent>" +
|
||||
" <properties>" +
|
||||
" <property name='test1:prop1'>" +
|
||||
" <type>d:text</type>" +
|
||||
" </property>" +
|
||||
" <property name='test1:prop99'>" +
|
||||
" <type>d:text</type>" +
|
||||
" </property>" +
|
||||
" </properties>" +
|
||||
" </type>" +
|
||||
|
||||
" </types>" +
|
||||
|
||||
"</model>";
|
||||
|
||||
public static final String MODEL_TWO_XML =
|
||||
"<model name='test2:testModelTwo' xmlns='http://www.alfresco.org/model/dictionary/1.0'>" +
|
||||
|
||||
" <description>Test model two</description>" +
|
||||
" <author>Alfresco</author>" +
|
||||
" <published>2010-01-13</published>" +
|
||||
" <version>1.0</version>" +
|
||||
|
||||
" <imports>" +
|
||||
" <import uri='http://www.alfresco.org/model/dictionary/1.0' prefix='d'/>" +
|
||||
" <import uri='http://www.alfresco.org/model/content/1.0' prefix='cm'/>" +
|
||||
" </imports>" +
|
||||
|
||||
" <namespaces>" +
|
||||
" <namespace uri='http://www.alfresco.org/test/testmodel2/1.0' prefix='test2'/>" +
|
||||
" </namespaces>" +
|
||||
|
||||
" <constraints>" +
|
||||
" <constraint name='test2:con1' type='LIST'>" +
|
||||
" <parameter name='allowedValues'>" +
|
||||
" <list>" +
|
||||
" <value>alfresco</value>" +
|
||||
" <value>file</value>" +
|
||||
" </list>" +
|
||||
" </parameter>" +
|
||||
" </constraint>" +
|
||||
" </constraints>" +
|
||||
|
||||
" <types>" +
|
||||
|
||||
" <type name='test2:base'>" +
|
||||
" <title>Base</title>" +
|
||||
" <description>The Base Type</description>" +
|
||||
" <parent>cm:content</parent>" +
|
||||
" <properties>" +
|
||||
" <property name='test2:prop2'>" +
|
||||
" <type>d:text</type>" +
|
||||
" <constraints>" +
|
||||
" <constraint ref='test2:con1'/>" +
|
||||
" </constraints>" +
|
||||
" </property>" +
|
||||
" </properties>" +
|
||||
" </type>" +
|
||||
|
||||
" </types>" +
|
||||
|
||||
"</model>";
|
||||
|
||||
public static final String MODEL_TWO_INVALID_XML =
|
||||
"<model name='test2:testModelTwo' xmlns='http://www.alfresco.org/model/dictionary/1.0'>" +
|
||||
|
||||
" <description>Test model two</description>" +
|
||||
" <author>Alfresco</author>" +
|
||||
" <published>2010-01-14</published>" +
|
||||
" <version>1.1</version>" +
|
||||
|
||||
" <imports>" +
|
||||
" <import uri='http://www.alfresco.org/model/dictionary/1.0' prefix='d'/>" +
|
||||
" <import uri='http://www.alfresco.org/model/content/1.0' prefix='cm'/>" +
|
||||
" </imports>" +
|
||||
|
||||
" <namespaces>" +
|
||||
" <namespace uri='http://www.alfresco.org/test/testmodel2/1.0' prefix='test2'/>" +
|
||||
" </namespaces>" +
|
||||
|
||||
" <types>" +
|
||||
|
||||
" <type name='test2:base'>" +
|
||||
" <title>Base</title>" +
|
||||
" <description>The Base Type</description>" +
|
||||
" <parent>cm:content</parent>" +
|
||||
" <properties>" +
|
||||
" <property name='test2:prop2'>" +
|
||||
" <type>d:text</type>" +
|
||||
" <constraints>" +
|
||||
" <constraint ref='test2:con1'/>" +
|
||||
" </constraints>" +
|
||||
" </property>" +
|
||||
" </properties>" +
|
||||
" </type>" +
|
||||
|
||||
" </types>" +
|
||||
|
||||
"</model>";
|
||||
|
||||
public static final String MODEL_TWO_MODIFIED_XML =
|
||||
"<model name='test2:testModelTwo' xmlns='http://www.alfresco.org/model/dictionary/1.0'>" +
|
||||
|
||||
" <description>Test model two - modified</description>" +
|
||||
" <author>Alfresco - modified</author>" +
|
||||
" <published>2010-01-14</published>" +
|
||||
" <version>1.1</version>" +
|
||||
|
||||
" <imports>" +
|
||||
" <import uri='http://www.alfresco.org/model/dictionary/1.0' prefix='d'/>" +
|
||||
" <import uri='http://www.alfresco.org/model/content/1.0' prefix='cm'/>" +
|
||||
" </imports>" +
|
||||
|
||||
" <namespaces>" +
|
||||
" <namespace uri='http://www.alfresco.org/test/testmodel2/1.0' prefix='test2'/>" +
|
||||
" </namespaces>" +
|
||||
|
||||
" <types>" +
|
||||
|
||||
" <type name='test2:base'>" +
|
||||
" <title>Base</title>" +
|
||||
" <description>The Base Type</description>" +
|
||||
" <parent>cm:content</parent>" +
|
||||
" <properties>" +
|
||||
" <property name='test2:prop2'>" +
|
||||
" <type>d:text</type>" +
|
||||
" </property>" +
|
||||
" </properties>" +
|
||||
@@ -142,6 +307,11 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
TenantAdminService tenantAdminService = (TenantAdminService)this.applicationContext.getBean("tenantAdminService");
|
||||
MessageService messageService = (MessageService)this.applicationContext.getBean("messageService");
|
||||
|
||||
List<String> storeUrlsToValidate = new ArrayList<String>(1);
|
||||
storeUrlsToValidate.add(this.storeRef.toString());
|
||||
DictionaryModelType dictionaryModelType = (DictionaryModelType)this.applicationContext.getBean("dictionaryModelType");
|
||||
dictionaryModelType.setStoreUrls(storeUrlsToValidate);
|
||||
|
||||
DictionaryRepositoryBootstrap bootstrap = new DictionaryRepositoryBootstrap();
|
||||
bootstrap.setContentService(this.contentService);
|
||||
bootstrap.setDictionaryDAO(this.dictionaryDAO);
|
||||
@@ -189,6 +359,7 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
// Create a model node
|
||||
PropertyMap properties = new PropertyMap(1);
|
||||
properties.put(ContentModel.PROP_MODEL_ACTIVE, true);
|
||||
|
||||
final NodeRef modelNode = this.nodeService.createNode(
|
||||
this.rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
@@ -211,6 +382,10 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
{
|
||||
public NodeRef execute() throws Exception
|
||||
{
|
||||
// Check that the namespace is in the namespace service
|
||||
String uri = namespaceService.getNamespaceURI("test1");
|
||||
assertNotNull(uri);
|
||||
|
||||
// Check that the meta data has been extracted from the model
|
||||
assertEquals(QName.createQName("{http://www.alfresco.org/test/testmodel1/1.0}testModelOne"),
|
||||
DictionaryModelTypeTest.this.nodeService.getProperty(modelNode, ContentModel.PROP_MODEL_NAME));
|
||||
@@ -244,7 +419,7 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
// Check that the policy has not been fired since we have updated a working copy
|
||||
assertEquals("1.0", DictionaryModelTypeTest.this.nodeService.getProperty(workingCopy, ContentModel.PROP_MODEL_VERSION));
|
||||
|
||||
// Now check the model changed back in
|
||||
// Check-in the model change
|
||||
DictionaryModelTypeTest.this.cociService.checkin(workingCopy, null);
|
||||
return null;
|
||||
}
|
||||
@@ -260,6 +435,24 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
}
|
||||
});
|
||||
|
||||
// create node using new type
|
||||
final NodeRef node1 = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Exception
|
||||
{
|
||||
NodeRef node = nodeService.createNode(
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName("http://www.alfresco.org/model/system/1.0", "node1"),
|
||||
QName.createQName("http://www.alfresco.org/test/testmodel1/1.0", "base"),
|
||||
null).getChildRef();
|
||||
assertNotNull(node);
|
||||
return node;
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
@@ -269,6 +462,293 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
}
|
||||
});
|
||||
|
||||
fail("Unexpected - should not be able to delete model");
|
||||
}
|
||||
catch (AlfrescoRuntimeException are)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
|
||||
// delete node
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
nodeService.deleteNode(node1);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
DictionaryModelTypeTest.this.nodeService.deleteNode(modelNode);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testUpdateDictionaryModelPropertyDelete()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Check that the model has not yet been loaded into the dictionary
|
||||
this.dictionaryService.getModel(TEST_MODEL_ONE);
|
||||
fail("This model has not yet been loaded into the dictionary service");
|
||||
}
|
||||
catch (DictionaryException exception)
|
||||
{
|
||||
// We expect this exception
|
||||
}
|
||||
|
||||
// Check that the namespace is not yet in the namespace service
|
||||
String uri = this.namespaceService.getNamespaceURI("test1");
|
||||
assertNull(uri);
|
||||
|
||||
// Create a model node
|
||||
PropertyMap properties = new PropertyMap(1);
|
||||
properties.put(ContentModel.PROP_MODEL_ACTIVE, true);
|
||||
final NodeRef modelNode = this.nodeService.createNode(
|
||||
this.rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "dictionaryModels"),
|
||||
ContentModel.TYPE_DICTIONARY_MODEL,
|
||||
properties).getChildRef();
|
||||
assertNotNull(modelNode);
|
||||
|
||||
// Add the model content to the model node
|
||||
ContentWriter contentWriter = this.contentService.getWriter(modelNode, ContentModel.PROP_CONTENT, true);
|
||||
contentWriter.setEncoding("UTF-8");
|
||||
contentWriter.setMimetype(MimetypeMap.MIMETYPE_XML);
|
||||
contentWriter.putContent(MODEL_ONE_MODIFIED_XML);
|
||||
|
||||
// End the transaction to force update
|
||||
setComplete();
|
||||
endTransaction();
|
||||
|
||||
// create node using new type
|
||||
final NodeRef node1 = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Exception
|
||||
{
|
||||
// Check that the namespace is in the namespace service
|
||||
String uri = namespaceService.getNamespaceURI("test1");
|
||||
assertNotNull(uri);
|
||||
|
||||
// Create a model node
|
||||
PropertyMap properties = new PropertyMap(1);
|
||||
properties.put(QName.createQName("http://www.alfresco.org/test/testmodel1/1.0", "prop2"), "false"); // boolean
|
||||
|
||||
NodeRef node = nodeService.createNode(
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "node1"),
|
||||
QName.createQName("http://www.alfresco.org/test/testmodel1/1.0", "base"),
|
||||
properties).getChildRef();
|
||||
assertNotNull(node);
|
||||
return node;
|
||||
}
|
||||
});
|
||||
|
||||
final NodeRef workingCopy = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Exception
|
||||
{
|
||||
// Update model
|
||||
NodeRef workingCopy = DictionaryModelTypeTest.this.cociService.checkout(modelNode);
|
||||
ContentWriter contentWriter2 = DictionaryModelTypeTest.this.contentService.getWriter(workingCopy, ContentModel.PROP_CONTENT, true);
|
||||
contentWriter2.putContent(MODEL_ONE_MODIFIED2_XML);
|
||||
|
||||
return workingCopy;
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
// Check that the policy has not been fired since we have updated a working copy
|
||||
assertEquals("1.1", DictionaryModelTypeTest.this.nodeService.getProperty(workingCopy, ContentModel.PROP_MODEL_VERSION));
|
||||
|
||||
// Check-in the model change
|
||||
DictionaryModelTypeTest.this.cociService.checkin(workingCopy, null);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
fail("Unexpected - should not be able to update model");
|
||||
}
|
||||
catch (AlfrescoRuntimeException are)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
|
||||
// delete node
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
nodeService.deleteNode(node1);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
// Check that the policy has not been fired since we have updated a working copy
|
||||
assertEquals("1.1", DictionaryModelTypeTest.this.nodeService.getProperty(workingCopy, ContentModel.PROP_MODEL_VERSION));
|
||||
|
||||
// Check-in the model change
|
||||
DictionaryModelTypeTest.this.cociService.checkin(workingCopy, null);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
// Now check that the model has been updated
|
||||
assertEquals("1.2", DictionaryModelTypeTest.this.nodeService.getProperty(modelNode, ContentModel.PROP_MODEL_VERSION));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
DictionaryModelTypeTest.this.nodeService.deleteNode(modelNode);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testUpdateDictionaryModelConstraintDelete()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Check that the model has not yet been loaded into the dictionary
|
||||
this.dictionaryService.getModel(TEST_MODEL_TWO);
|
||||
fail("This model has not yet been loaded into the dictionary service");
|
||||
}
|
||||
catch (DictionaryException exception)
|
||||
{
|
||||
// We expect this exception
|
||||
}
|
||||
|
||||
// Check that the namespace is not yet in the namespace service
|
||||
String uri = this.namespaceService.getNamespaceURI("test2");
|
||||
assertNull(uri);
|
||||
|
||||
// Create a model node
|
||||
PropertyMap properties = new PropertyMap(1);
|
||||
properties.put(ContentModel.PROP_MODEL_ACTIVE, true);
|
||||
final NodeRef modelNode = this.nodeService.createNode(
|
||||
this.rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "dictionaryModels"),
|
||||
ContentModel.TYPE_DICTIONARY_MODEL,
|
||||
properties).getChildRef();
|
||||
assertNotNull(modelNode);
|
||||
|
||||
// Add the model content to the model node
|
||||
ContentWriter contentWriter = this.contentService.getWriter(modelNode, ContentModel.PROP_CONTENT, true);
|
||||
contentWriter.setEncoding("UTF-8");
|
||||
contentWriter.setMimetype(MimetypeMap.MIMETYPE_XML);
|
||||
contentWriter.putContent(MODEL_TWO_XML);
|
||||
|
||||
// End the transaction to force update
|
||||
setComplete();
|
||||
endTransaction();
|
||||
|
||||
final NodeRef workingCopy = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Exception
|
||||
{
|
||||
// Check that the namespace is in the namespace service
|
||||
String uri = namespaceService.getNamespaceURI("test2");
|
||||
assertNotNull(uri);
|
||||
|
||||
Collection<ConstraintDefinition> constraints = dictionaryService.getConstraints(TEST_MODEL_TWO, true);
|
||||
assertEquals(1, constraints.size());
|
||||
assertEquals("test2:con1", constraints.iterator().next().getName().getPrefixString());
|
||||
|
||||
// Update model
|
||||
NodeRef workingCopy = DictionaryModelTypeTest.this.cociService.checkout(modelNode);
|
||||
ContentWriter contentWriter2 = DictionaryModelTypeTest.this.contentService.getWriter(workingCopy, ContentModel.PROP_CONTENT, true);
|
||||
contentWriter2.putContent(MODEL_TWO_INVALID_XML);
|
||||
|
||||
return workingCopy;
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
// Check that the policy has not been fired since we have updated a working copy
|
||||
assertEquals("1.0", DictionaryModelTypeTest.this.nodeService.getProperty(workingCopy, ContentModel.PROP_MODEL_VERSION));
|
||||
|
||||
// Check-in the model change
|
||||
DictionaryModelTypeTest.this.cociService.checkin(workingCopy, null);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
fail("Unexpected - should not be able to update model");
|
||||
}
|
||||
catch (AlfrescoRuntimeException are)
|
||||
{
|
||||
assertTrue(are.getMessage().contains("Failed to validate constraint delete"));
|
||||
}
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
// Check that the policy has not been fired since the previous update was invalid
|
||||
assertEquals("1.0", DictionaryModelTypeTest.this.nodeService.getProperty(modelNode, ContentModel.PROP_MODEL_VERSION));
|
||||
|
||||
// Update model
|
||||
ContentWriter contentWriter2 = DictionaryModelTypeTest.this.contentService.getWriter(workingCopy, ContentModel.PROP_CONTENT, true);
|
||||
contentWriter2.putContent(MODEL_TWO_MODIFIED_XML);
|
||||
|
||||
// Check-in the model change
|
||||
DictionaryModelTypeTest.this.cociService.checkin(workingCopy, null);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
// Now check that the model has been updated
|
||||
|
||||
Collection<ConstraintDefinition> constraints = dictionaryService.getConstraints(TEST_MODEL_TWO, true);
|
||||
assertEquals(0, constraints.size());
|
||||
|
||||
assertEquals("1.1", DictionaryModelTypeTest.this.nodeService.getProperty(modelNode, ContentModel.PROP_MODEL_VERSION));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
DictionaryModelTypeTest.this.nodeService.deleteNode(modelNode);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testIsActiveFlagAndDelete()
|
||||
@@ -371,8 +851,16 @@ public class DictionaryModelTypeTest extends BaseAlfrescoSpringTest
|
||||
// The model should now be loaded
|
||||
assertNotNull(DictionaryModelTypeTest.this.dictionaryService.getModel(TEST_MODEL_ONE));
|
||||
|
||||
// Delete the model
|
||||
DictionaryModelTypeTest.this.nodeService.deleteNode(modelNode);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
// The model should not be loaded
|
||||
try
|
||||
{
|
||||
|
@@ -19,6 +19,7 @@
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -31,6 +32,8 @@ import org.alfresco.repo.i18n.MessageDeployer;
|
||||
import org.alfresco.repo.i18n.MessageService;
|
||||
import org.alfresco.repo.tenant.TenantAdminService;
|
||||
import org.alfresco.repo.tenant.TenantDeployer;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
@@ -42,10 +45,11 @@ import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
||||
import org.springframework.extensions.surf.util.Pair;
|
||||
|
||||
/**
|
||||
* Bootstrap the dictionary from specified locations within the repository
|
||||
@@ -55,8 +59,7 @@ import org.springframework.context.ApplicationEvent;
|
||||
public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean implements TenantDeployer, DictionaryListener, MessageDeployer
|
||||
{
|
||||
// Logging support
|
||||
private static Log logger = LogFactory
|
||||
.getLog("org.alfresco.repo.dictionary.DictionaryRepositoryBootstrap");
|
||||
private static Log logger = LogFactory.getLog(DictionaryRepositoryBootstrap.class);
|
||||
|
||||
/** Locations in the repository from which models should be loaded */
|
||||
private List<RepositoryLocation> repositoryModelsLocations = new ArrayList<RepositoryLocation>();
|
||||
@@ -206,9 +209,16 @@ public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean impleme
|
||||
*/
|
||||
public void onDictionaryInit()
|
||||
{
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
Collection<QName> modelsBefore = dictionaryDAO.getModels();
|
||||
int modelsBeforeCnt = (modelsBefore != null ? modelsBefore.size() : 0);
|
||||
|
||||
List<String> loadedModels = new ArrayList<String>();
|
||||
|
||||
if (this.repositoryModelsLocations != null)
|
||||
{
|
||||
Map<String, M2Model> modelMap = new HashMap<String, M2Model>();
|
||||
Map<String, Pair<RepositoryLocation, M2Model>> modelMap = new HashMap<String, Pair<RepositoryLocation, M2Model>>();
|
||||
|
||||
// Register the models found in the repository
|
||||
|
||||
@@ -249,7 +259,7 @@ public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean impleme
|
||||
|
||||
for (M2Namespace namespace : model.getNamespaces())
|
||||
{
|
||||
modelMap.put(namespace.getUri(), model);
|
||||
modelMap.put(namespace.getUri(), new Pair<RepositoryLocation, M2Model>(repositoryLocation, model));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,10 +274,29 @@ public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean impleme
|
||||
}
|
||||
|
||||
// Load the models ensuring that they are loaded in the correct order
|
||||
List<String> loadedModels = new ArrayList<String>();
|
||||
for (Map.Entry<String, M2Model> entry : modelMap.entrySet())
|
||||
for (Map.Entry<String, Pair<RepositoryLocation, M2Model>> entry : modelMap.entrySet())
|
||||
{
|
||||
loadModel(modelMap, loadedModels, entry.getValue());
|
||||
RepositoryLocation importedLocation = entry.getValue().getFirst();
|
||||
M2Model importedModel = entry.getValue().getSecond();
|
||||
|
||||
loadModel(modelMap, loadedModels, importedModel, importedLocation);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<QName> modelsAfter = dictionaryDAO.getModels();
|
||||
int modelsAfterCnt = (modelsAfter != null ? modelsAfter.size() : 0);
|
||||
|
||||
if (modelsAfterCnt != (modelsBeforeCnt + loadedModels.size()))
|
||||
{
|
||||
String tenantDomain = tenantAdminService.getCurrentUserDomain();
|
||||
logger.warn("Model count: before="+modelsBeforeCnt+", load="+loadedModels.size()+", after="+modelsAfterCnt+" ["+AlfrescoTransactionSupport.getTransactionId()+"] in "+(System.currentTimeMillis()-startTime)+" msecs "+(tenantDomain.equals(TenantService.DEFAULT_DOMAIN) ? "" : " (Tenant: "+tenantDomain+")"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
String tenantDomain = tenantAdminService.getCurrentUserDomain();
|
||||
logger.debug("Model count: before="+modelsBeforeCnt+", load="+loadedModels.size()+", after="+modelsAfterCnt+" ["+AlfrescoTransactionSupport.getTransactionId()+"] in "+(System.currentTimeMillis()-startTime)+" msecs "+(tenantDomain.equals(TenantService.DEFAULT_DOMAIN) ? "" : " (Tenant: "+tenantDomain+")"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -371,18 +400,21 @@ public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean impleme
|
||||
* @param loadedModels the list of models already loaded
|
||||
* @param model the model to try and load
|
||||
*/
|
||||
private void loadModel(Map<String, M2Model> modelMap, List<String> loadedModels, M2Model model)
|
||||
private void loadModel(Map<String, Pair<RepositoryLocation, M2Model>> modelMap, List<String> loadedModels, M2Model model, RepositoryLocation modelLocation)
|
||||
{
|
||||
String modelName = model.getName();
|
||||
if (loadedModels.contains(modelName) == false)
|
||||
{
|
||||
for (M2Namespace importNamespace : model.getImports())
|
||||
{
|
||||
M2Model importedModel = modelMap.get(importNamespace.getUri());
|
||||
if (importedModel != null)
|
||||
Pair<RepositoryLocation, M2Model> entry = modelMap.get(importNamespace.getUri());
|
||||
if (entry != null)
|
||||
{
|
||||
RepositoryLocation importedLocation = entry.getFirst();
|
||||
M2Model importedModel = entry.getSecond();
|
||||
|
||||
// Ensure that the imported model is loaded first
|
||||
loadModel(modelMap, loadedModels, importedModel);
|
||||
loadModel(modelMap, loadedModels, importedModel, importedLocation);
|
||||
}
|
||||
// else we can assume that the imported model is already loaded, if this not the case then
|
||||
// an error will be raised during compilation
|
||||
@@ -390,6 +422,11 @@ public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean impleme
|
||||
|
||||
try
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Loading model: " + modelName + " (from ["+ modelLocation.getStoreRef() + "]"+ modelLocation.getPath() + ")");
|
||||
}
|
||||
|
||||
dictionaryDAO.putModel(model);
|
||||
loadedModels.add(modelName);
|
||||
}
|
||||
@@ -446,7 +483,8 @@ public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean impleme
|
||||
*/
|
||||
public void register()
|
||||
{
|
||||
dictionaryDAO.destroy(); // deployer - force reload on next get
|
||||
// deployer - force reload on next get (eg. bootstrap "rmc:rmcustom")
|
||||
dictionaryDAO.destroy();
|
||||
|
||||
// register with Dictionary Service to allow (re-)init
|
||||
dictionaryDAO.register(this);
|
||||
|
@@ -997,17 +997,22 @@ public class DiffModelTest extends TestCase
|
||||
System.out.println(M2ModelDiff.toString());
|
||||
}
|
||||
|
||||
assertEquals(8, modelDiffs.size());
|
||||
assertEquals(16, modelDiffs.size());
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_CREATED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UPDATED));
|
||||
assertEquals(2, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(0, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UPDATED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_DELETED));
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_CREATED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UPDATED));
|
||||
assertEquals(2, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(0, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UPDATED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_DELETED));
|
||||
|
||||
assertEquals(0, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_CREATED));
|
||||
assertEquals(6, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UPDATED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_DELETED));
|
||||
}
|
||||
|
||||
public void testIncUpdatePropertiesAdded()
|
||||
@@ -1029,10 +1034,12 @@ public class DiffModelTest extends TestCase
|
||||
System.out.println(modelDiff.toString());
|
||||
}
|
||||
|
||||
assertEquals(2, modelDiffs.size());
|
||||
assertEquals(8, modelDiffs.size());
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UPDATED_INC));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UPDATED_INC));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(4, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(2, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_CREATED));
|
||||
}
|
||||
|
||||
public void testIncUpdateTypesAndAspectsAdded()
|
||||
@@ -1054,13 +1061,15 @@ public class DiffModelTest extends TestCase
|
||||
System.out.println(modelDiff.toString());
|
||||
}
|
||||
|
||||
assertEquals(4, modelDiffs.size());
|
||||
assertEquals(8, modelDiffs.size());
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_CREATED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_CREATED));
|
||||
|
||||
assertEquals(4, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UNCHANGED));
|
||||
}
|
||||
|
||||
public void testIncUpdateAssociationsAdded()
|
||||
@@ -1082,14 +1091,16 @@ public class DiffModelTest extends TestCase
|
||||
System.out.println(modelDiff.toString());
|
||||
}
|
||||
|
||||
assertEquals(4, modelDiffs.size());
|
||||
assertEquals(12, modelDiffs.size());
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UPDATED_INC));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UPDATED_INC));
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
|
||||
assertEquals(2, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
|
||||
assertEquals(6, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UNCHANGED));
|
||||
|
||||
assertEquals(2, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASSOCIATION, M2ModelDiff.DIFF_CREATED));
|
||||
}
|
||||
|
||||
public void testIncUpdateTitleDescription()
|
||||
@@ -1111,10 +1122,11 @@ public class DiffModelTest extends TestCase
|
||||
System.out.println(modelDiff.toString());
|
||||
}
|
||||
|
||||
assertEquals(2, modelDiffs.size());
|
||||
assertEquals(4, modelDiffs.size());
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UPDATED_INC));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UPDATED_INC));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(2, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UPDATED_INC));
|
||||
}
|
||||
|
||||
public void testNonIncUpdatePropertiesRemoved()
|
||||
@@ -1136,10 +1148,12 @@ public class DiffModelTest extends TestCase
|
||||
System.out.println(modelDiff.toString());
|
||||
}
|
||||
|
||||
assertEquals(2, modelDiffs.size());
|
||||
assertEquals(8, modelDiffs.size());
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UPDATED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UPDATED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(4, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(2, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_DELETED));
|
||||
}
|
||||
|
||||
public void testNonIncUpdateTypesAndAspectsRemoved()
|
||||
@@ -1161,13 +1175,15 @@ public class DiffModelTest extends TestCase
|
||||
System.out.println(modelDiff.toString());
|
||||
}
|
||||
|
||||
assertEquals(4, modelDiffs.size());
|
||||
assertEquals(8, modelDiffs.size());
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_DELETED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_DELETED));
|
||||
|
||||
assertEquals(4, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UNCHANGED));
|
||||
}
|
||||
|
||||
public void testNonIncUpdateDefaultAspectAdded()
|
||||
@@ -1189,10 +1205,11 @@ public class DiffModelTest extends TestCase
|
||||
System.out.println(modelDiff.toString());
|
||||
}
|
||||
|
||||
assertEquals(2, modelDiffs.size());
|
||||
assertEquals(4, modelDiffs.size());
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UPDATED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(2, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UNCHANGED));
|
||||
}
|
||||
|
||||
public void testNonIncUpdateAssociationsRemoved()
|
||||
@@ -1214,13 +1231,16 @@ public class DiffModelTest extends TestCase
|
||||
System.out.println(modelDiff.toString());
|
||||
}
|
||||
|
||||
assertEquals(4, modelDiffs.size());
|
||||
assertEquals(12, modelDiffs.size());
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UPDATED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UPDATED));
|
||||
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_TYPE, M2ModelDiff.DIFF_UNCHANGED));
|
||||
assertEquals(1, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
|
||||
assertEquals(2, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASPECT, M2ModelDiff.DIFF_UNCHANGED));
|
||||
|
||||
assertEquals(6, countDiffs(modelDiffs, M2ModelDiff.TYPE_PROPERTY, M2ModelDiff.DIFF_UNCHANGED));
|
||||
|
||||
assertEquals(2, countDiffs(modelDiffs, M2ModelDiff.TYPE_ASSOCIATION, M2ModelDiff.DIFF_DELETED));
|
||||
}
|
||||
|
||||
private int countDiffs(List<M2ModelDiff> M2ModelDiffs, String elementType, String diffType)
|
||||
|
@@ -570,38 +570,12 @@ import org.alfresco.util.EqualsHelper;
|
||||
// check all properties (including inherited properties)
|
||||
Collection<M2ModelDiff> propertyDiffs = M2PropertyDefinition.diffPropertyLists(getProperties().values(), classDef.getProperties().values());
|
||||
|
||||
for (M2ModelDiff propertyDiff : propertyDiffs)
|
||||
{
|
||||
// note: incremental property updates not supported yet, added for completeness
|
||||
if (propertyDiff.getDiffType().equals(M2ModelDiff.DIFF_CREATED) || propertyDiff.getDiffType().equals(M2ModelDiff.DIFF_UPDATED_INC))
|
||||
{
|
||||
isUpdatedIncrementally = true;
|
||||
}
|
||||
|
||||
if (propertyDiff.getDiffType().equals(M2ModelDiff.DIFF_UPDATED) || propertyDiff.getDiffType().equals(M2ModelDiff.DIFF_DELETED))
|
||||
{
|
||||
isUpdated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
modelDiffs.addAll(propertyDiffs);
|
||||
|
||||
// check all associations (including inherited associations, child associations and inherited child associations)
|
||||
Collection<M2ModelDiff> assocDiffs = M2AssociationDefinition.diffAssocLists(getAssociations().values(), classDef.getAssociations().values());
|
||||
|
||||
for (M2ModelDiff assocDiff : assocDiffs)
|
||||
{
|
||||
// note: incremental association updates not supported yet, added for completeness
|
||||
if (assocDiff.getDiffType().equals(M2ModelDiff.DIFF_CREATED) || assocDiff.getDiffType().equals(M2ModelDiff.DIFF_UPDATED_INC))
|
||||
{
|
||||
isUpdatedIncrementally = true;
|
||||
}
|
||||
|
||||
if (assocDiff.getDiffType().equals(M2ModelDiff.DIFF_UPDATED) || assocDiff.getDiffType().equals(M2ModelDiff.DIFF_DELETED))
|
||||
{
|
||||
isUpdated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
modelDiffs.addAll(assocDiffs);
|
||||
|
||||
// check default/mandatory aspects (including inherited default aspects)
|
||||
Collection<M2ModelDiff> defaultAspectsDiffs = M2ClassDefinition.diffClassLists(new ArrayList<ClassDefinition>(getDefaultAspects()), new ArrayList<ClassDefinition>(classDef.getDefaultAspects()), M2ModelDiff.TYPE_DEFAULT_ASPECT);
|
||||
@@ -676,13 +650,6 @@ import org.alfresco.util.EqualsHelper;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (M2ModelDiff modelDiff : modelDiffs)
|
||||
{
|
||||
if (! modelDiff.getDiffType().equals(M2ModelDiff.DIFF_UNCHANGED))
|
||||
{
|
||||
throw new DictionaryException("Unexpected: diff found although '" + name + "' not marked as updated");
|
||||
}
|
||||
}
|
||||
modelDiffs.add(new M2ModelDiff(name, modelDiffType, M2ModelDiff.DIFF_UNCHANGED));
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.alfresco.repo.dictionary;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
|
||||
@@ -31,6 +33,7 @@ import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
import org.alfresco.service.cmr.dictionary.ModelDefinition;
|
||||
import org.alfresco.service.namespace.NamespacePrefixResolver;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.InvalidPropertyException;
|
||||
@@ -39,7 +42,7 @@ import org.springframework.beans.PropertyAccessException;
|
||||
/**
|
||||
* Compiled Property Constraint
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @author Derek Hulley. janv
|
||||
*/
|
||||
/* package */class M2ConstraintDefinition implements ConstraintDefinition
|
||||
{
|
||||
@@ -320,6 +323,17 @@ import org.springframework.beans.PropertyAccessException;
|
||||
return constraint;
|
||||
}
|
||||
|
||||
public QName getRef()
|
||||
{
|
||||
QName refQName = null;
|
||||
String ref = m2Constraint.getRef();
|
||||
if (ref != null)
|
||||
{
|
||||
refQName = QName.createQName(ref, prefixResolver);
|
||||
}
|
||||
return refQName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Well-known constraint types
|
||||
*/
|
||||
@@ -371,4 +385,100 @@ import org.springframework.beans.PropertyAccessException;
|
||||
*/
|
||||
protected abstract Constraint newInstance();
|
||||
}
|
||||
|
||||
/* package */ M2ModelDiff diffConstraint(ConstraintDefinition conDef)
|
||||
{
|
||||
M2ModelDiff modelDiff = null;
|
||||
boolean isUpdated = false;
|
||||
boolean isUpdatedIncrementally = false;
|
||||
|
||||
if (this == conDef)
|
||||
{
|
||||
modelDiff = new M2ModelDiff(name, M2ModelDiff.TYPE_CONSTRAINT, M2ModelDiff.DIFF_UNCHANGED);
|
||||
return modelDiff;
|
||||
}
|
||||
|
||||
// check name - cannot be null
|
||||
if (! name.equals(conDef.getName()))
|
||||
{
|
||||
isUpdated = true;
|
||||
}
|
||||
|
||||
// check title
|
||||
if (! EqualsHelper.nullSafeEquals(getTitle(), conDef.getTitle(), false))
|
||||
{
|
||||
isUpdatedIncrementally = true;
|
||||
}
|
||||
|
||||
// check description
|
||||
if (! EqualsHelper.nullSafeEquals(getDescription(), conDef.getDescription(), false))
|
||||
{
|
||||
isUpdatedIncrementally = true;
|
||||
}
|
||||
|
||||
// check type string
|
||||
if (! EqualsHelper.nullSafeEquals(getConstraint().getType(), conDef.getConstraint().getType()))
|
||||
{
|
||||
isUpdated = true;
|
||||
}
|
||||
|
||||
if (isUpdated)
|
||||
{
|
||||
modelDiff = new M2ModelDiff(name, M2ModelDiff.TYPE_CONSTRAINT, M2ModelDiff.DIFF_UPDATED);
|
||||
}
|
||||
else if (isUpdatedIncrementally)
|
||||
{
|
||||
modelDiff = new M2ModelDiff(name, M2ModelDiff.TYPE_CONSTRAINT, M2ModelDiff.DIFF_UPDATED_INC);
|
||||
}
|
||||
else
|
||||
{
|
||||
modelDiff = new M2ModelDiff(name, M2ModelDiff.TYPE_CONSTRAINT, M2ModelDiff.DIFF_UNCHANGED);
|
||||
}
|
||||
|
||||
return modelDiff;
|
||||
}
|
||||
|
||||
/*package*/ static Collection<M2ModelDiff> diffConstraintLists(Collection<ConstraintDefinition> previousConstraints, Collection<ConstraintDefinition> newConstraints)
|
||||
{
|
||||
List<M2ModelDiff> modelDiffs = new ArrayList<M2ModelDiff>();
|
||||
|
||||
for (ConstraintDefinition previousConstraint : previousConstraints)
|
||||
{
|
||||
boolean found = false;
|
||||
for (ConstraintDefinition newConstraint : newConstraints)
|
||||
{
|
||||
if (newConstraint.getName().equals(previousConstraint.getName()))
|
||||
{
|
||||
modelDiffs.add(((M2ConstraintDefinition)previousConstraint).diffConstraint(previousConstraint));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! found)
|
||||
{
|
||||
modelDiffs.add(new M2ModelDiff(previousConstraint.getName(), M2ModelDiff.TYPE_CONSTRAINT, M2ModelDiff.DIFF_DELETED));
|
||||
}
|
||||
}
|
||||
|
||||
for (ConstraintDefinition newConstraint : newConstraints)
|
||||
{
|
||||
boolean found = false;
|
||||
for (ConstraintDefinition previousConstraint : previousConstraints)
|
||||
{
|
||||
if (newConstraint.getName().equals(previousConstraint.getName()))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! found)
|
||||
{
|
||||
modelDiffs.add(new M2ModelDiff(newConstraint.getName(), M2ModelDiff.TYPE_CONSTRAINT, M2ModelDiff.DIFF_CREATED));
|
||||
}
|
||||
}
|
||||
|
||||
return modelDiffs;
|
||||
}
|
||||
}
|
||||
|
@@ -41,6 +41,7 @@ public class M2ModelDiff
|
||||
public static final String TYPE_DEFAULT_ASPECT = "DEFAULT_ASPECT";
|
||||
public static final String TYPE_PROPERTY = "PROPERTY";
|
||||
public static final String TYPE_ASSOCIATION = "ASSOCIATION";
|
||||
public static final String TYPE_CONSTRAINT = "TYPE_CONSTRAINT";
|
||||
|
||||
private QName elementName;
|
||||
private String elementType;
|
||||
@@ -57,7 +58,9 @@ public class M2ModelDiff
|
||||
(!elementType.equals(TYPE_ASPECT)) &&
|
||||
(!elementType.equals(TYPE_DEFAULT_ASPECT)) &&
|
||||
(!elementType.equals(TYPE_PROPERTY)) &&
|
||||
(!elementType.equals(TYPE_ASSOCIATION)))
|
||||
(!elementType.equals(TYPE_ASSOCIATION)) &&
|
||||
(!elementType.equals(TYPE_CONSTRAINT))
|
||||
)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Unknown element type = " + elementType);
|
||||
}
|
||||
|
@@ -94,9 +94,9 @@ public class NamespaceDAOImpl implements NamespaceDAO
|
||||
|
||||
removeNamespaceRegistry(tenantDomain);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.debug("Namespaces destroyed");
|
||||
logger.trace("Namespaces destroyed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,18 +111,18 @@ public class NamespaceDAOImpl implements NamespaceDAO
|
||||
throw new AlfrescoRuntimeException("Dictionary should be registered in order to perform reset");
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.debug("Resetting namespaces ...");
|
||||
logger.trace("Resetting namespaces ...");
|
||||
}
|
||||
|
||||
dictionaryDAO.init();
|
||||
|
||||
NamespaceRegistry namespaceRegistry = getNamespaceRegistry(tenantDomain);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.debug("... resetting namespaces completed");
|
||||
logger.trace("... resetting namespaces completed");
|
||||
}
|
||||
|
||||
return namespaceRegistry;
|
||||
@@ -176,9 +176,9 @@ public class NamespaceDAOImpl implements NamespaceDAO
|
||||
getNamespaceRegistry(tenantDomain).setUrisCache(new ArrayList<String>());
|
||||
getNamespaceRegistry(tenantDomain).setPrefixesCache(new HashMap<String, String>());
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.debug("Empty namespaces initialised");
|
||||
logger.trace("Empty namespaces initialised");
|
||||
}
|
||||
|
||||
return getNamespaceRegistryLocal(tenantDomain);
|
||||
|
@@ -211,7 +211,7 @@ public abstract class BaseVersionStoreTest extends BaseSpringTest
|
||||
bootstrap.setModels(bootstrapModels);
|
||||
bootstrap.setDictionaryDAO(dictionaryDAO);
|
||||
|
||||
bootstrap.register();
|
||||
bootstrap.bootstrap();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -51,4 +51,11 @@ public interface ConstraintDefinition
|
||||
* @return Returns the constraint implementation
|
||||
*/
|
||||
public Constraint getConstraint();
|
||||
|
||||
/**
|
||||
* @return Returns the referenced constraint definition, if any (null for explicit or inline constraint def)
|
||||
*
|
||||
* @since 3.2R
|
||||
*/
|
||||
public QName getRef();
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@
|
||||
package org.alfresco.service.cmr.dictionary;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.NotAuditable;
|
||||
@@ -257,6 +256,17 @@ public interface DictionaryService
|
||||
@NotAuditable
|
||||
Collection<QName> getAllAssociations();
|
||||
|
||||
/**
|
||||
* Gets the definition of the constraint
|
||||
*
|
||||
* @param constraintName the constraint name
|
||||
* @return the constraint definition (or null, if it doesn't exist)
|
||||
*
|
||||
* @since 3.2.1
|
||||
*/
|
||||
@NotAuditable
|
||||
public ConstraintDefinition getConstraint(QName constraintQName);
|
||||
|
||||
/**
|
||||
* Get constraints for the specified model
|
||||
*
|
||||
@@ -265,6 +275,19 @@ public interface DictionaryService
|
||||
*/
|
||||
public Collection<ConstraintDefinition> getConstraints(QName model);
|
||||
|
||||
/**
|
||||
* Get constraints for the specified model
|
||||
|
||||
* Optionally return referenceable (ie. non-property specific) constraints only
|
||||
*
|
||||
* @param model
|
||||
* @param referenceableDefsOnly
|
||||
* @return
|
||||
*
|
||||
* @since 3.2R
|
||||
*/
|
||||
Collection<ConstraintDefinition> getConstraints(QName model, boolean referenceableDefsOnly);
|
||||
|
||||
// TODO: Behaviour definitions
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user