2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.common.workflow.service.nuxeo;
26 import java.util.Collection;
27 import java.util.HashMap;
30 import javax.ws.rs.core.MediaType;
32 import org.collectionspace.services.client.workflow.WorkflowClient;
33 import org.collectionspace.services.common.context.MultipartServiceContext;
34 import org.collectionspace.services.common.context.ServiceContext;
35 import org.collectionspace.services.common.document.DocumentWrapper;
36 import org.collectionspace.services.common.workflow.jaxb.WorkflowJAXBSchema;
37 import org.collectionspace.services.config.service.ObjectPartType;
38 import org.collectionspace.services.lifecycle.TransitionDef;
39 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler;
40 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
41 import org.collectionspace.services.workflow.WorkflowCommon;
42 import org.nuxeo.ecm.core.api.ClientException;
43 import org.nuxeo.ecm.core.api.DocumentModel;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 public class WorkflowDocumentModelHandler
48 extends NuxeoDocumentModelHandler<WorkflowCommon> {
51 private static final Logger logger = LoggerFactory.getLogger(WorkflowDocumentModelHandler.class);
53 * Workflow transitions
55 * See the "Nuxeo core default life cycle definition", an XML configuration
56 * for Nuxeo's "lifecycle" extension point that specifies valid workflow
57 * states and the operations that transition documents to those states, via:
59 * org.nuxeo.ecm.core.LifecycleCoreExtensions--lifecycle (as opposed to --types)
61 private static final String TRANSITION_UNKNOWN = "unknown";
65 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
67 // First, call the parent document handler to give it a chance to handle the workflow transition -otherwise, call
68 // the super/parent handleUpdate() method.
70 ServiceContext ctx = this.getServiceContext();
71 DocumentModelHandler targetDocHandler = (DocumentModelHandler)ctx.getProperty(WorkflowClient.TARGET_DOCHANDLER);
73 // We need to make sure the repo session is available to the handler and its service context
74 targetDocHandler.setRepositorySession(this.getRepositorySession()); // Make sure the target doc handler has a repository session to work with
75 targetDocHandler.getServiceContext().setCurrentRepositorySession(this.getRepositorySession());
77 TransitionDef transitionDef = (TransitionDef)ctx.getProperty(WorkflowClient.TRANSITION_ID);
78 targetDocHandler.handleWorkflowTransition(ctx, wrapDoc, transitionDef); // Call the target resouce's handler first
80 // If no exception occurred, then call the super's method
82 super.handleUpdate(wrapDoc);
86 protected void handleRefNameChanges(ServiceContext ctx, DocumentModel docModel) throws ClientException {
88 // We are intentionally overriding this method to do nothing since the Workflow resource is a meta-resource without a refname
96 protected Map<String, Object> extractPart(DocumentModel docModel,
98 ObjectPartType partMeta,
99 Map<String, Object> addToMap)
101 Map<String, Object> result = null;
103 MediaType mt = MediaType.valueOf(partMeta.getContent().getContentType()); //FIXME: REM - This is no longer needed. Everything is POX
104 if (mt.equals(MediaType.APPLICATION_XML_TYPE)) {
105 Map<String, Object> unQObjectProperties =
106 (addToMap != null) ? addToMap : (new HashMap<String, Object>());
107 unQObjectProperties.put(WorkflowJAXBSchema.WORKFLOW_LIFECYCLEPOLICY, docModel.getLifeCyclePolicy());
108 unQObjectProperties.put(WorkflowJAXBSchema.WORKFLOW_CURRENTLIFECYCLESTATE, docModel.getCurrentLifeCycleState());
109 result = unQObjectProperties;
110 } //TODO: handle other media types
116 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc)
118 DocumentModel docModel = wrapDoc.getWrappedObject();
119 String[] schemas = {WorkflowClient.SERVICE_COMMONPART_NAME};
120 Map<String, ObjectPartType> partsMetaMap = getServiceContext().getPartsMetadata();
121 for (String schema : schemas) {
122 ObjectPartType partMeta = partsMetaMap.get(schema);
123 if (partMeta == null) {
124 continue; // unknown part, ignore
126 Map<String, Object> unQObjectProperties = extractPart(docModel, schema, partMeta);
127 addOutputPart(unQObjectProperties, schema, partMeta);
132 * Maps the transition name to handle existing states like "replicated" and "deleted". This allows us to do things like replicate "deleted"
133 * records, delete "replicated" records, etc. For example, this code maps the transition name "delete" to "delete_replicated" on records in the "replicated" state.
134 * As another example, it would map "undelete" to "undelete_replicated" for replicated records and just "undelete" for records in any other state.
136 * Essentially, this mapping allows REST API clients to use the "delete", "undelete", "replicate", "unreplicate", etc transitions on records no matter what
137 * their current state. Without this mapping, REST API clients would need to calculate this on their own and use the longer forms like:
138 * "delete_replicated", "undelete_replicated", "lock_deleted", "unlock_deleted", etc.
140 public static String getQualifiedTransitionName(DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef) {
141 String result = null;
143 String currentTransitionName = result = transitionDef.getName(); // begin with result set to the current name
144 DocumentModel docModel = wrapDoc.getWrappedObject();
145 Collection<String> allowedTransitionList = docModel.getAllowedStateTransitions();
146 for (String allowedTransitionName:allowedTransitionList) {
147 if (allowedTransitionName.startsWith(currentTransitionName)) {
148 result = allowedTransitionName;
149 break; // we found a mapping
157 * Handle Update (PUT)
161 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
162 String transitionToFollow = null;
164 DocumentModel docModel = wrapDoc.getWrappedObject();
165 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
168 TransitionDef transitionDef = (TransitionDef)this.getServiceContext().getProperty(WorkflowClient.TRANSITION_ID);
169 transitionToFollow = getQualifiedTransitionName(wrapDoc, transitionDef);
170 docModel.followTransition(transitionToFollow);
171 } catch (Exception e) {
172 String msg = "Unable to follow workflow transition to state = "
173 + transitionToFollow;
174 logger.error(msg, e);
175 ClientException ce = new ClientException("Unable to follow workflow transition: " + transitionToFollow);