diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml
index 837a533832..5bebbe3f9c 100644
--- a/config/alfresco/core-services-context.xml
+++ b/config/alfresco/core-services-context.xml
@@ -614,24 +614,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/config/alfresco/messages/repoadmin-interpreter-help.txt b/config/alfresco/messages/repoadmin-interpreter-help.txt
index 3c8a75bc49..c943b2e1d0 100755
--- a/config/alfresco/messages/repoadmin-interpreter-help.txt
+++ b/config/alfresco/messages/repoadmin-interpreter-help.txt
@@ -49,22 +49,30 @@ ok> show models
ok> deploy model
- Upload model to repository and into runtime data dictionary. This will also
- set the model as active.
+ Upload model to repository and load into runtime data dictionary. This will also
+ set the repository model as active.
+
+ If a model is already deployed then it will be updated and re-deployed.
e.g. deploy model alfresco/extension/exampleModel.xml
ok> undeploy model
- Permanently delete model from repository (all versions) and from runtime data dictionary.
+ Permanently delete model from repository (all versions) and unload from runtime data dictionary.
e.g. undeploy model exampleModel.xml
-ok> reload model
+ok> activate model
- Reload (or load for first time) from repository into runtime data dictionary.
+ Set repository model to active and load into runtime data dictionary.
- e.g. reload model exampleModel.xml
+ e.g. activate model exampleModel.xml
+
+ok> deactivate model
+
+ Set repository model to inactive and unload from runtime data dictionary.
+
+ e.g. deactivate model exampleModel.xml
##
## Message Admin Commands
diff --git a/config/alfresco/repo-admin-context.xml b/config/alfresco/repo-admin-context.xml
index 73b29d4755..c00c67880c 100755
--- a/config/alfresco/repo-admin-context.xml
+++ b/config/alfresco/repo-admin-context.xml
@@ -11,17 +11,9 @@
-
-
-
-
- ${spaces.store}
- ${spaces.archive.store}
-
-
@@ -63,38 +55,47 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${spaces.store}
+ ${spaces.archive.store}
+
+
+
+
diff --git a/source/java/org/alfresco/repo/admin/RepoAdminInterpreter.java b/source/java/org/alfresco/repo/admin/RepoAdminInterpreter.java
index bc37dc5d17..b41bd349cd 100755
--- a/source/java/org/alfresco/repo/admin/RepoAdminInterpreter.java
+++ b/source/java/org/alfresco/repo/admin/RepoAdminInterpreter.java
@@ -255,8 +255,8 @@ public class RepoAdminInterpreter extends BaseInterpreter
InputStream fileStream = file.getInputStream();
String modelFileName = file.getFilename();
- QName modelQName = repoAdminService.deployModel(fileStream, modelFileName);
- out.println("Model deployed: " + modelFileName + " [" + modelQName + "]");
+ repoAdminService.deployModel(fileStream, modelFileName);
+ out.println("Model deployed: " + modelFileName);
}
else if (command[1].equals("messages"))
@@ -272,7 +272,7 @@ public class RepoAdminInterpreter extends BaseInterpreter
}
}
- else if (command[0].equals("reload"))
+ else if (command[0].equals("activate"))
{
if (command.length != 3)
{
@@ -282,15 +282,38 @@ public class RepoAdminInterpreter extends BaseInterpreter
else if (command[1].equals("model"))
{
String modelFileName = command[2];
- QName modelQName = repoAdminService.reloadModel(modelFileName);
- out.println("Model (re-)loaded: " + modelFileName + " [" + modelQName + "]");
+ QName modelQName = repoAdminService.activateModel(modelFileName);
+ out.println("Model activated: " + modelFileName + " [" + modelQName + "]");
+ }
+ }
+
+ else if (command[0].equals("deactivate"))
+ {
+ if (command.length != 3)
+ {
+ return "Syntax Error.\n";
+ }
+
+ else if (command[1].equals("model"))
+ {
+ String modelFileName = command[2];
+ QName modelQName = repoAdminService.deactivateModel(modelFileName);
+ out.println("Model deactivated: " + modelFileName + " [" + modelQName + "]");
+ }
+ }
+
+ else if (command[0].equals("reload"))
+ {
+ if (command.length != 3)
+ {
+ return "Syntax Error.\n";
}
else if (command[1].equals("messages"))
{
String bundleBaseName = command[2];
repoAdminService.reloadMessageBundle(bundleBaseName);
- out.println("Message resource bundle (re-)loaded: " + bundleBaseName);
+ out.println("Message resource bundle reloaded: " + bundleBaseName);
}
else
diff --git a/source/java/org/alfresco/repo/admin/RepoAdminService.java b/source/java/org/alfresco/repo/admin/RepoAdminService.java
index 811f208515..1a524c00cd 100755
--- a/source/java/org/alfresco/repo/admin/RepoAdminService.java
+++ b/source/java/org/alfresco/repo/admin/RepoAdminService.java
@@ -27,6 +27,7 @@ package org.alfresco.repo.admin;
import java.io.InputStream;
import java.util.List;
+import org.alfresco.service.Auditable;
import org.alfresco.service.namespace.QName;
@@ -47,11 +48,13 @@ public interface RepoAdminService
public List getModels();
- public QName deployModel(InputStream modelStream, String modelFileName);
+ public void deployModel(InputStream modelStream, String modelFileName);
public QName undeployModel(String modelFileName);
- public QName reloadModel(String modelFileName);
+ public QName activateModel(String modelFileName);
+
+ public QName deactivateModel(String modelFileName);
/* Custom message/resource bundles managed in the repository */
diff --git a/source/java/org/alfresco/repo/admin/RepoAdminServiceImpl.java b/source/java/org/alfresco/repo/admin/RepoAdminServiceImpl.java
index 1f41027b8a..2399827d42 100755
--- a/source/java/org/alfresco/repo/admin/RepoAdminServiceImpl.java
+++ b/source/java/org/alfresco/repo/admin/RepoAdminServiceImpl.java
@@ -24,10 +24,7 @@
*/
package org.alfresco.repo.admin;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
@@ -43,12 +40,9 @@ import org.alfresco.repo.dictionary.DictionaryDAO;
import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.dictionary.RepositoryLocation;
import org.alfresco.repo.i18n.MessageService;
-import org.alfresco.repo.workflow.BPMEngineRegistry;
import org.alfresco.service.cmr.admin.RepoAdminService;
-import org.alfresco.service.cmr.dictionary.AspectDefinition;
-import org.alfresco.service.cmr.dictionary.ClassDefinition;
-import org.alfresco.service.cmr.dictionary.NamespaceDefinition;
-import org.alfresco.service.cmr.dictionary.TypeDefinition;
+import org.alfresco.service.cmr.dictionary.DictionaryException;
+import org.alfresco.service.cmr.dictionary.ModelDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
@@ -56,11 +50,7 @@ import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
-import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
-import org.alfresco.service.cmr.workflow.WorkflowDefinition;
-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.util.ParameterCheck;
@@ -88,13 +78,10 @@ public class RepoAdminServiceImpl implements RepoAdminService
private ContentService contentService;
private NamespaceService namespaceService;
private MessageService messageService;
- private WorkflowService workflowService;
private RepositoryLocation repoModelsLocation;
private RepositoryLocation repoMessagesLocation;
- private List storeUrls; // stores against which model changes (updates/deletes) should be validated
-
public final static String CRITERIA_ALL = "/*"; // immediate children only
public final static String defaultSubtypeOfDictionaryModel = "subtypeOf('cm:dictionaryModel')";
@@ -130,11 +117,7 @@ public class RepoAdminServiceImpl implements RepoAdminService
{
this.messageService = messageService;
}
-
- public void setWorkflowService(WorkflowService workflowService)
- {
- this.workflowService = workflowService;
- }
+
public void setRepositoryModelsLocation(RepositoryLocation repoModelsLocation)
@@ -147,11 +130,6 @@ public class RepoAdminServiceImpl implements RepoAdminService
this.repoMessagesLocation = repoMessagesLocation;
}
- public void setStoreUrls(List storeUrls)
- {
- this.storeUrls = storeUrls;
- }
-
/*
* (non-Javadoc)
@@ -162,53 +140,55 @@ public class RepoAdminServiceImpl implements RepoAdminService
StoreRef storeRef = repoModelsLocation.getStoreRef();
NodeRef rootNode = nodeService.getRootNode(storeRef);
- Collection models = dictionaryDAO.getModels();
-
- List dictionaryModels = new ArrayList();
- for (QName model : models)
- {
- dictionaryModels.add(model.toPrefixString());
- }
-
- List nodeRefs = searchService.selectNodes(rootNode, repoModelsLocation.getPath()+CRITERIA_ALL+"["+defaultSubtypeOfDictionaryModel+"]", null, namespaceService, false);
-
List modelsInRepo = new ArrayList();
- if (nodeRefs.size() > 0)
+ try
+ {
+ Collection models = dictionaryDAO.getModels();
+
+ List dictionaryModels = new ArrayList();
+ for (QName model : models)
+ {
+ dictionaryModels.add(model.toPrefixString());
+ }
+
+ List nodeRefs = searchService.selectNodes(rootNode, repoModelsLocation.getPath()+CRITERIA_ALL+"["+defaultSubtypeOfDictionaryModel+"]", null, namespaceService, false);
+
+ if (nodeRefs.size() > 0)
+ {
+ for (NodeRef nodeRef : nodeRefs)
+ {
+ String modelFileName = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
+ String repoVersion = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_VERSION_LABEL);
+
+ String modelName = null;
+
+
+ ContentReader cr = contentService.getReader(nodeRef, ContentModel.TYPE_CONTENT);
+ InputStream is = cr.getContentInputStream();
+
+ M2Model model = M2Model.createModel(is);
+ is.close();
+
+ modelName = model.getName();
+
+
+ // check against models loaded in dictionary and give warning if not found
+ if (dictionaryModels.contains(modelName))
+ {
+ // note: uses dictionary model cache, rather than getting content from repo and re-compiling
+ modelsInRepo.add(new RepoModelDefinition(modelFileName, repoVersion, dictionaryDAO.getModel(QName.createQName(modelName, namespaceService)), true));
+ }
+ else
+ {
+ modelsInRepo.add(new RepoModelDefinition(modelFileName, repoVersion, null, false));
+ }
+ }
+ }
+ }
+ catch (Throwable t)
{
- for (NodeRef nodeRef : nodeRefs)
- {
- String modelFileName = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
- String repoVersion = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_VERSION_LABEL);
-
- String modelName = null;
-
- try
- {
- ContentReader cr = contentService.getReader(nodeRef, ContentModel.TYPE_CONTENT);
- InputStream is = cr.getContentInputStream();
-
- M2Model model = M2Model.createModel(is);
- is.close();
-
- modelName = model.getName();
- }
- catch (Throwable t)
- {
- throw new AlfrescoRuntimeException("Failed to getModels " + t);
- }
-
- // check against models loaded in dictionary and give warning if not found
- if (dictionaryModels.contains(modelName))
- {
- // note: uses dictionary model cache, rather than getting content from repo and re-compiling
- modelsInRepo.add(new RepoModelDefinition(modelFileName, repoVersion, dictionaryDAO.getModel(QName.createQName(modelName, namespaceService)), true));
- }
- else
- {
- modelsInRepo.add(new RepoModelDefinition(modelFileName, repoVersion, null, false));
- }
- }
+ throw new AlfrescoRuntimeException("Failed to get models " + t);
}
return modelsInRepo;
@@ -218,28 +198,13 @@ public class RepoAdminServiceImpl implements RepoAdminService
* (non-Javadoc)
* @see org.alfresco.service.cmr.admin.RepoAdminService#deployModel(java.io.InputStream, java.lang.String)
*/
- public QName deployModel(InputStream modelStream, String modelFileName)
+ public void deployModel(InputStream modelStream, String modelFileName)
{
- // Check that all the passed values are not null
- ParameterCheck.mandatory("ModelStream", modelStream);
- ParameterCheck.mandatoryString("ModelFileName", modelFileName);
-
- QName modelQName = null;
-
try
- {
- // TODO workaround due to issue with model.toXML() - see below
- BufferedReader in = new BufferedReader(new InputStreamReader(modelStream));
- StringBuffer buffer = new StringBuffer();
- String line = null;
- while ((line = in.readLine()) != null) {
- buffer.append(line);
- }
-
- InputStream is = new ByteArrayInputStream(buffer.toString().getBytes());
-
- M2Model model = M2Model.createModel(is);
- is.close();
+ {
+ // Check that all the passed values are not null
+ ParameterCheck.mandatory("ModelStream", modelStream);
+ ParameterCheck.mandatoryString("ModelFileName", modelFileName);
Map contentProps = new HashMap();
contentProps.put(ContentModel.PROP_NAME, modelFileName);
@@ -259,106 +224,99 @@ public class RepoAdminServiceImpl implements RepoAdminService
throw new AlfrescoRuntimeException("Found multiple custom models location " + repoModelsLocation.getPath());
}
- NodeRef customModelsNodeRef = nodeRefs.get(0);
+ NodeRef customModelsSpaceNodeRef = nodeRefs.get(0);
- nodeRefs = searchService.selectNodes(customModelsNodeRef, "*[@cm:name='"+modelFileName+"' and "+defaultSubtypeOfDictionaryModel+"]", null, namespaceService, false);
+ nodeRefs = searchService.selectNodes(customModelsSpaceNodeRef, "*[@cm:name='"+modelFileName+"' and "+defaultSubtypeOfDictionaryModel+"]", null, namespaceService, false);
+ NodeRef modelNodeRef = null;
+
if (nodeRefs.size() == 1)
{
// re-deploy existing model to the repository
- NodeRef modelNodeRef = nodeRefs.get(0);
-
- ContentWriter writer = contentService.getWriter(modelNodeRef, ContentModel.PROP_CONTENT, true);
-
- writer.setMimetype(MimetypeMap.MIMETYPE_XML);
- writer.setEncoding("UTF-8");
-
- is = new ByteArrayInputStream(buffer.toString().getBytes());
- writer.putContent(is); // also invokes policies for DictionaryModelType - e.g. onContentUpdate
- is.close();
-
- /* TODO
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- model.toXML(out); // fails with NPE in JIBX - see also: http://issues.alfresco.com/browse/AR-1304
- writer.putContent(out.toString("UTF-8"));
- */
-
- // validate model against dictionary - could be new, unchanged or updated
- dictionaryDAO.validateModel(model);
-
- // parse and update model in the dictionary
- modelQName = dictionaryDAO.putModel(model);
-
- logger.info("Model re-deployed: " + modelQName);
+ modelNodeRef = nodeRefs.get(0);
}
else
{
// deploy new model to the repository
// note: dictionary model type has associated policies that will be invoked
- ChildAssociationRef association = nodeService.createNode(customModelsNodeRef,
+ ChildAssociationRef association = nodeService.createNode(customModelsSpaceNodeRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, modelFileName),
ContentModel.TYPE_DICTIONARY_MODEL,
contentProps); // also invokes policies for DictionaryModelType - e.g. onUpdateProperties
- NodeRef content = association.getChildRef();
+ modelNodeRef = association.getChildRef();
// add titled aspect (for Web Client display)
Map titledProps = new HashMap();
titledProps.put(ContentModel.PROP_TITLE, modelFileName);
titledProps.put(ContentModel.PROP_DESCRIPTION, modelFileName);
- nodeService.addAspect(content, ContentModel.ASPECT_TITLED, titledProps);
+ nodeService.addAspect(modelNodeRef, ContentModel.ASPECT_TITLED, titledProps);
// add versionable aspect (set auto-version)
Map versionProps = new HashMap();
versionProps.put(ContentModel.PROP_AUTO_VERSION, true);
- nodeService.addAspect(content, ContentModel.ASPECT_VERSIONABLE, versionProps);
-
- ContentWriter writer = contentService.getWriter(content, ContentModel.PROP_CONTENT, true);
-
- writer.setMimetype(MimetypeMap.MIMETYPE_XML);
- writer.setEncoding("UTF-8");
-
- is = new ByteArrayInputStream(buffer.toString().getBytes());
- writer.putContent(is); // also invokes policies for DictionaryModelType - e.g. onContentUpdate
- is.close();
-
- /* TODO
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- model.toXML(out); // fails with NPE in JIBX - see also: http://issues.alfresco.com/browse/AR-1304
- writer.putContent(out.toString("UTF-8"));
- */
-
- // validate model against dictionary - could be new, unchanged or updated
- dictionaryDAO.validateModel(model);
-
- // parse and add model to dictionary
- modelQName = dictionaryDAO.putModel(model);
-
- logger.info("Model deployed: " + modelQName);
+ nodeService.addAspect(modelNodeRef, ContentModel.ASPECT_VERSIONABLE, versionProps);
}
+
+ ContentWriter writer = contentService.getWriter(modelNodeRef, ContentModel.PROP_CONTENT, true);
+
+ writer.setMimetype(MimetypeMap.MIMETYPE_XML);
+ writer.setEncoding("UTF-8");
+
+ writer.putContent(modelStream); // also invokes policies for DictionaryModelType - e.g. onContentUpdate
+ modelStream.close();
+
+ // activate the model
+ nodeService.setProperty(modelNodeRef, ContentModel.PROP_MODEL_ACTIVE, new Boolean(true));
+
+ // note: model will be loaded as part of DictionaryModelType.beforeCommit()
}
catch (Throwable e)
{
- throw new AlfrescoRuntimeException("Model deployment failed", e);
- }
-
- return modelQName;
+ throw new AlfrescoRuntimeException("Model deployment failed ", e);
+ }
}
/*
* (non-Javadoc)
- * @see org.alfresco.service.cmr.admin.RepoAdminService#reloadModel(java.lang.String)
+ * @see org.alfresco.service.cmr.admin.RepoAdminService#activateModel(java.lang.String)
*/
- public QName reloadModel(String modelFileName)
+ public QName activateModel(String modelFileName)
{
+ try
+ {
+ return activateOrDeactivate(modelFileName, true);
+ }
+ catch (Throwable e)
+ {
+ throw new AlfrescoRuntimeException("Model activation failed ", e);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.service.cmr.admin.RepoAdminService#deactivateModel(java.lang.String)
+ */
+ public QName deactivateModel(String modelFileName)
+ {
+ try
+ {
+ return activateOrDeactivate(modelFileName, false);
+ }
+ catch (Throwable e)
+ {
+ throw new AlfrescoRuntimeException("Model deactivation failed ", e);
+ }
+ }
+
+ private QName activateOrDeactivate(String modelFileName, boolean activate)
+ {
// Check that all the passed values are not null
ParameterCheck.mandatoryString("modelFileName", modelFileName);
-
- QName modelQName = null;
-
+
StoreRef storeRef = repoModelsLocation.getStoreRef();
NodeRef rootNode = nodeService.getRootNode(storeRef);
@@ -376,32 +334,74 @@ public class RepoAdminServiceImpl implements RepoAdminService
NodeRef modelNodeRef = nodeRefs.get(0);
- try
- {
- ContentReader cr = contentService.getReader(modelNodeRef, ContentModel.TYPE_CONTENT);
- InputStream is = cr.getContentInputStream();
-
- // create model
- M2Model model = M2Model.createModel(is);
- is.close();
-
- if (model != null)
- {
- // validate model against dictionary - could be new, unchanged or updated
- dictionaryDAO.validateModel(model);
-
- // parse and update model in the dictionary
- modelQName = dictionaryDAO.putModel(model);
-
- logger.info("Model loaded: " + modelQName);
- }
- }
- catch (Throwable e)
+ boolean isActive = ((Boolean)nodeService.getProperty(modelNodeRef, ContentModel.PROP_MODEL_ACTIVE)).booleanValue();
+ QName modelQName = (QName)nodeService.getProperty(modelNodeRef, ContentModel.PROP_MODEL_NAME);
+
+ ModelDefinition modelDef = null;
+ if (modelQName != null)
{
- throw new AlfrescoRuntimeException("Model deployment failed", e);
+ try
+ {
+ modelDef = dictionaryDAO.getModel(modelQName);
+ }
+ catch (DictionaryException e)
+ {
+ logger.warn(e);
+ }
}
- return modelQName;
+ if (activate)
+ {
+ // activate
+ if (isActive)
+ {
+ if (modelDef != null)
+ {
+ // model is already activated
+ throw new AlfrescoRuntimeException("Model activation failed - model '" + modelQName + "' is already activated");
+ }
+ else
+ {
+ logger.warn("Model is set to active but not loaded in Dictionary - trying to load...");
+ }
+ }
+ else
+ {
+ if (modelDef != null)
+ {
+ logger.warn("Model is loaded in Dictionary but is not set to active - trying to activate...");
+ }
+ }
+ }
+ else
+ {
+ // deactivate
+ if (!isActive)
+ {
+ if (modelDef == null)
+ {
+ // model is already deactivated
+ throw new AlfrescoRuntimeException("Model deactivation failed - model '" + modelQName + "' is already deactivated");
+ }
+ else
+ {
+ logger.warn("Model is set to inactive but loaded in Dictionary - trying to unload...");
+ }
+ }
+ else
+ {
+ if (modelDef == null)
+ {
+ logger.warn("Model is not loaded in Dictionary but is set to active - trying to deactivate...");
+ }
+ }
+ }
+
+ // activate/deactivate the model
+ nodeService.setProperty(modelNodeRef, ContentModel.PROP_MODEL_ACTIVE, new Boolean(activate));
+
+ // note: model will be loaded/unloaded as part of DictionaryModelType.beforeCommit()
+ return modelQName;
}
/*
@@ -436,39 +436,39 @@ public class RepoAdminServiceImpl implements RepoAdminService
NodeRef modelNodeRef = nodeRefs.get(0);
- String modelName = null;
+ boolean isActive = ((Boolean)nodeService.getProperty(modelNodeRef, ContentModel.PROP_MODEL_ACTIVE)).booleanValue();
+ modelQName = (QName)nodeService.getProperty(modelNodeRef, ContentModel.PROP_MODEL_NAME);
- try
+ ModelDefinition modelDef = null;
+ if (modelQName != null)
{
- ContentReader cr = contentService.getReader(modelNodeRef, ContentModel.TYPE_CONTENT);
- InputStream is = cr.getContentInputStream();
-
- M2Model model = M2Model.createModel(is);
- is.close();
-
- modelName = model.getName();
+ try
+ {
+ modelDef = dictionaryDAO.getModel(modelQName);
+ }
+ catch (DictionaryException e)
+ {
+ logger.warn(e);
+ }
}
- catch (Throwable t)
- {
- throw new AlfrescoRuntimeException("Failed to get model " + t);
+
+ if (isActive)
+ {
+ if (modelDef == null)
+ {
+ logger.warn("Model is set to active but not loaded in Dictionary - trying to undeploy...");
+ }
}
-
+
// permanently remove model from repository
nodeService.addAspect(modelNodeRef, ContentModel.ASPECT_TEMPORARY, null);
nodeService.deleteNode(modelNodeRef);
- modelQName = QName.createQName(modelName, namespaceService);
-
- // simple check for usages
- validateModelDelete(modelQName);
-
- dictionaryDAO.removeModel(modelQName);
-
- logger.info("Model undeployed: " + modelQName);
+ // note: deleted model will be unloaded as part of DictionaryModelType.beforeCommit()
}
catch (Throwable e)
{
- throw new AlfrescoRuntimeException("Model undeployment failed", e);
+ throw new AlfrescoRuntimeException("Model undeployment failed ", e);
}
return modelQName;
@@ -769,75 +769,5 @@ public class RepoAdminServiceImpl implements RepoAdminService
{
throw new AlfrescoRuntimeException("Message resource re-load failed", e);
}
- }
-
- /**
- * validate against repository contents / workflows (e.g. when deleting an existing model)
- *
- * @param modelName
- */
- private void validateModelDelete(QName modelName)
- {
- // TODO add model locking during delete (would need to be tenant-aware & cluster-aware) to avoid potential
- // for concurrent addition of new content/workflow as model is being deleted
-
- for (WorkflowDefinition workflowDef : workflowService.getDefinitions())
- {
- String workflowDefName = workflowDef.getName();
- String workflowNamespaceURI = QName.createQName(BPMEngineRegistry.getLocalId(workflowDefName), namespaceService).getNamespaceURI();
- for (NamespaceDefinition namespace : dictionaryDAO.getNamespaces(modelName))
- {
- if (workflowNamespaceURI.equals(namespace.getUri()))
- {
- throw new AlfrescoRuntimeException("Failed to validate model delete - found workflow process definition " + workflowDefName + " using model namespace '" + namespace.getUri() + "'");
- }
- }
- }
-
- for (TypeDefinition type : dictionaryDAO.getTypes(modelName))
- {
- validateClass(type);
- }
-
- for (AspectDefinition aspect : dictionaryDAO.getAspects(modelName))
- {
- validateClass(aspect);
- }
- }
-
- private void validateClass(ClassDefinition classDef)
- {
- QName className = classDef.getName();
-
- String classType = "TYPE";
- if (classDef instanceof AspectDefinition)
- {
- classType = "ASPECT";
- }
-
- for (String storeUrl : this.storeUrls)
- {
- StoreRef store = new StoreRef(storeUrl);
-
- // search for TYPE or ASPECT - TODO - alternative would be to extract QName and search by namespace ...
- ResultSet rs = searchService.query(store, SearchService.LANGUAGE_LUCENE, classType+":\""+className+"\"");
- if (rs.length() > 0)
- {
- throw new AlfrescoRuntimeException("Failed to validate model delete - found " + rs.length() + " nodes in store " + store + " with " + classType + " '" + className + "'");
- }
- }
-
- // check against workflow usage
- for (WorkflowDefinition workflowDef : workflowService.getDefinitions())
- {
- for (WorkflowTaskDefinition workflowTaskDef : workflowService.getTaskDefinitions(workflowDef.getId()))
- {
- TypeDefinition workflowTypeDef = workflowTaskDef.metadata;
- if (workflowTypeDef.getName().toString().equals(className))
- {
- throw new AlfrescoRuntimeException("Failed to validate model delete - found task definition in workflow " + workflowDef.getName() + " with " + classType + " '" + className + "'");
- }
- }
- }
}
}
diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java b/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java
index 0a6876f99d..93ac146d74 100644
--- a/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java
+++ b/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java
@@ -26,24 +26,43 @@ package org.alfresco.repo.dictionary;
import java.io.Serializable;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.ContentServicePolicies;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
+import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionListener;
+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.DictionaryException;
import org.alfresco.service.cmr.dictionary.ModelDefinition;
+import org.alfresco.service.cmr.dictionary.NamespaceDefinition;
+import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.cmr.search.ResultSet;
+import org.alfresco.service.cmr.search.SearchService;
+import org.alfresco.service.cmr.workflow.WorkflowDefinition;
+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.util.GUID;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* Dictionary model type behaviour.
@@ -54,6 +73,9 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
NodeServicePolicies.OnUpdatePropertiesPolicy,
NodeServicePolicies.BeforeDeleteNodePolicy
{
+ // Logger
+ private static Log logger = LogFactory.getLog(DictionaryModelType.class);
+
/** Key to the pending models */
private static final String KEY_PENDING_MODELS = "dictionaryModelType.pendingModels";
@@ -72,9 +94,24 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
/** The policy component */
private PolicyComponent policyComponent;
+ /** The workflow service */
+ private WorkflowService workflowService;
+
+ /** The search service */
+ private SearchService searchService;
+
+ /** The namespace service */
+ private NamespaceService namespaceService;
+
+ /** The tenant service */
+ private TenantService tenantService;
+
/** Transaction listener */
private DictionaryModelTypeTransactionListener transactionListener;
+ private List storeUrls; // stores against which model deletes should be validated
+
+
/**
* Set the dictionary DAO
*
@@ -125,6 +162,53 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
this.policyComponent = policyComponent;
}
+ /**
+ * Set the workflow service
+ *
+ * @param workflowService the workflow service
+ */
+ public void setWorkflowService(WorkflowService workflowService)
+ {
+ this.workflowService = workflowService;
+ }
+
+ /**
+ * Set the search service
+ *
+ * @param searchService the search service
+ */
+ public void setSearchService(SearchService searchService)
+ {
+ this.searchService = searchService;
+ }
+
+ /**
+ * Set the namespace service
+ *
+ * @param namespaceService the namespace service
+ */
+ public void setNamespaceService(NamespaceService namespaceService)
+ {
+ this.namespaceService = namespaceService;
+ }
+
+ /**
+ * Set the tenant service
+ *
+ * @param tenantService the tenant service
+ */
+ public void setTenantService(TenantService tenantService)
+ {
+ this.tenantService = tenantService;
+ }
+
+
+ public void setStoreUrls(List storeUrls)
+ {
+ this.storeUrls = storeUrls;
+ }
+
+
/**
* The initialise method
*/
@@ -215,10 +299,11 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
QName modelName = (QName)this.nodeService.getProperty(nodeRef, ContentModel.PROP_MODEL_NAME);
if (modelName != null)
{
+ // Validate model delete against usages - content and/or workflows
+ validateModelDelete(modelName);
+
// Remove the model from the dictionary
dictionaryDAO.removeModel(modelName);
-
- // TODO how can we make this transactional ??
}
}
}
@@ -259,60 +344,73 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
if (pendingModels != null)
{
- for (NodeRef nodeRef : pendingModels)
+ for (final NodeRef nodeRef : pendingModels)
{
- // Find out whether the model is active (by default it is)
- boolean isActive = false;
- Boolean value = (Boolean)nodeService.getProperty(nodeRef, ContentModel.PROP_MODEL_ACTIVE);
- if (value != null)
- {
- isActive = value.booleanValue();
- }
+ String tenantDomain = tenantService.getDomain(nodeRef.getStoreRef().getIdentifier());
+ String tenantAdminUserName = tenantService.getDomainUser(TenantService.ADMIN_BASENAME, tenantDomain);
- // Ignore if the node is a working copy or if its inactive
- if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY) == false)
+ AuthenticationUtil.runAs(new RunAsWork