<artifactId>org.collectionspace.services.intake.client</artifactId>\r
<version>${project.version}</version>\r
</dependency>\r
+ <dependency>\r
+ <groupId>org.collectionspace.services</groupId>\r
+ <artifactId>org.collectionspace.services.dimension.jaxb</artifactId>\r
+ <version>${project.version}</version>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.collectionspace.services</groupId>\r
+ <artifactId>org.collectionspace.services.dimension.client</artifactId>\r
+ <version>${project.version}</version>\r
+ </dependency>\r
<dependency>\r
<groupId>org.collectionspace.services</groupId>\r
<artifactId>org.collectionspace.services.relation.client</artifactId>\r
*/
package org.collectionspace.services.IntegrationTests.test;
+import java.io.StringWriter;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
import org.testng.Assert;
import org.testng.annotations.Test;
import org.jboss.resteasy.client.ClientResponse;
import org.collectionspace.services.client.CollectionObjectClient;
+import org.collectionspace.services.client.DimensionClient;
+import org.collectionspace.services.client.DimensionFactory;
import org.collectionspace.services.client.PayloadOutputPart;
import org.collectionspace.services.client.PoxPayloadIn;
import org.collectionspace.services.client.PoxPayloadOut;
import org.collectionspace.services.intake.IntakesCommon;
import org.collectionspace.services.client.RelationClient;
+import org.collectionspace.services.client.workflow.WorkflowClient;
+import org.collectionspace.services.dimension.DimensionsCommon;
import org.collectionspace.services.relation.RelationsCommon;
import org.collectionspace.services.relation.RelationsCommonList;
import org.collectionspace.services.relation.RelationshipType;
private CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
private RelationClient relationClient = new RelationClient();
private IntakeClient intakeClient = new IntakeClient();
+ private DimensionClient dimensionClient = new DimensionClient();
private static final int OBJECTS_TO_INTAKE = 1;
+
+ /**
+ * Object as xml string.
+ *
+ * @param o the o
+ * @param clazz the clazz
+ * @return the string
+ */
+ static protected String objectAsXmlString(Object o, Class<?> clazz) {
+ StringWriter sw = new StringWriter();
+ try {
+ JAXBContext jc = JAXBContext.newInstance(clazz);
+ Marshaller m = jc.createMarshaller();
+ m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
+ Boolean.TRUE);
+ m.marshal(o, sw);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return sw.toString();
+ }
+
+ private PoxPayloadOut createDimensionInstance(String commonPartName, String dimensionType, String dimensionValue, String entryDate) {
+ DimensionsCommon dimensionsCommon = new DimensionsCommon();
+ dimensionsCommon.setDimension(dimensionType);
+ dimensionsCommon.setValue(new BigDecimal(dimensionValue));
+ dimensionsCommon.setValueDate(entryDate);
+ PoxPayloadOut multipart = DimensionFactory.createDimensionInstance(
+ commonPartName, dimensionsCommon);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("to be created, dimension common");
+ logger.debug(objectAsXmlString(dimensionsCommon,
+ DimensionsCommon.class));
+ }
+
+ return multipart;
+ }
+
+ protected PoxPayloadOut createDimensionInstance(String identifier) {
+ DimensionClient client = new DimensionClient();
+ return createDimensionInstance(client.getCommonPartName(), identifier);
+ }
+
+ /**
+ * Creates the dimension instance.
+ *
+ * @param identifier the identifier
+ * @return the multipart output
+ */
+ protected PoxPayloadOut createDimensionInstance(String commonPartName, String identifier) {
+ final String DIMENSION_VALUE = "78.306";
+
+ return createDimensionInstance(commonPartName,
+ "dimensionType-" + identifier,
+ DIMENSION_VALUE,
+ "entryDate-" + identifier);
+ }
+
+ @Test void deleteCollectionObjectRelationshipToLockedDimension() {
+ //
+ // First create a CollectionObject
+ //
+ CollectionobjectsCommon co = new CollectionobjectsCommon();
+ fillCollectionObject(co, createIdentifier());
+
+ // Next, create a part object
+ PoxPayloadOut multipart = new PoxPayloadOut(CollectionObjectClient.SERVICE_PAYLOAD_NAME);
+ PayloadOutputPart commonPart = multipart.addPart(co, MediaType.APPLICATION_XML_TYPE);
+ commonPart.setLabel(collectionObjectClient.getCommonPartName());
+
+ // Make the create call and check the response
+ ClientResponse<Response> response = collectionObjectClient.create(multipart);
+ String collectionObjectCsid = null;
+ try {
+ Assert.assertEquals(response.getStatus(), Response.Status.CREATED
+ .getStatusCode());
+ collectionObjectCsid = extractId(response);
+ } finally {
+ response.releaseConnection();
+ }
+
+ //Next, create a Dimension record to relate the collection object to
+ multipart = this.createDimensionInstance(createIdentifier());
+ // Make the call to create and check the response
+ response = dimensionClient.create(multipart);
+ String dimensionCsid = null;
+ try {
+ Assert.assertEquals(response.getStatus(), Response.Status.CREATED.getStatusCode());
+ dimensionCsid = extractId(response);
+ } finally {
+ response.releaseConnection();
+ }
+
+ // Relate the two entities, by creating a new relation object
+ RelationsCommon relation = new RelationsCommon();
+ fillRelation(relation, collectionObjectCsid, CollectionobjectsCommon.class.getSimpleName(),
+ dimensionCsid, DimensionsCommon.class.getSimpleName(),
+ "collectionobject-dimension");
+ // Create the part and fill it with the relation object
+ multipart = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
+ commonPart = multipart.addPart(relation, MediaType.APPLICATION_XML_TYPE);
+ commonPart.setLabel(relationClient.getCommonPartName());
+
+ // Create the relationship
+ response = relationClient.create(multipart);
+ @SuppressWarnings("unused")
+ String relationCsid = null;
+ try {
+ Assert.assertEquals(response.getStatus(), Response.Status.CREATED.getStatusCode());
+ relationCsid = extractId(response);
+ } finally {
+ response.releaseConnection();
+ }
+
+ // Now lock the dimension record.
+
+ @SuppressWarnings("unused")
+ ClientResponse<String> workflowResponse = dimensionClient.updateWorkflowWithTransition(dimensionCsid, WorkflowClient.WORKFLOWTRANSITION_LOCK);
+ System.out.println("Locked dimension record with CSID=" + dimensionCsid);
+
+ // Finally, try to delete the relationship
+
+ // Try to delete the relationship -should fail because we don't allow delete if one of the sides is locked.
+ response = relationClient.delete(relationCsid);
+ try {
+ Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
+ } finally {
+ response.releaseConnection();
+ }
+
+ // Also, try to soft-delete. This should also fail.
+ workflowResponse = dimensionClient.updateWorkflowWithTransition(dimensionCsid, WorkflowClient.WORKFLOWTRANSITION_DELETE);
+ System.out.println("Locked dimension record with CSID=" + dimensionCsid);
+ }
+
+
+ @Test void releteCollectionObjectToLockedDimension() {
+ //
+ // First create a CollectionObject
+ //
+ CollectionobjectsCommon co = new CollectionobjectsCommon();
+ fillCollectionObject(co, createIdentifier());
+
+ // Next, create a part object
+ PoxPayloadOut multipart = new PoxPayloadOut(CollectionObjectClient.SERVICE_PAYLOAD_NAME);
+ PayloadOutputPart commonPart = multipart.addPart(co, MediaType.APPLICATION_XML_TYPE);
+ commonPart.setLabel(collectionObjectClient.getCommonPartName());
+
+ // Make the create call and check the response
+ ClientResponse<Response> response = collectionObjectClient.create(multipart);
+ String collectionObjectCsid = null;
+ try {
+ Assert.assertEquals(response.getStatus(), Response.Status.CREATED
+ .getStatusCode());
+ collectionObjectCsid = extractId(response);
+ } finally {
+ response.releaseConnection();
+ }
+
+ //Next, create a Dimension record to relate the collection object to
+ multipart = this.createDimensionInstance(createIdentifier());
+ // Make the call to create and check the response
+ response = dimensionClient.create(multipart);
+ String dimensionCsid = null;
+ try {
+ Assert.assertEquals(response.getStatus(), Response.Status.CREATED.getStatusCode());
+ dimensionCsid = extractId(response);
+ } finally {
+ response.releaseConnection();
+ }
+
+ @SuppressWarnings("unused")
+ ClientResponse<String> workflowResponse = dimensionClient.updateWorkflowWithTransition(dimensionCsid, WorkflowClient.WORKFLOWTRANSITION_LOCK);
+ System.out.println("Locked dimension record with CSID=" + dimensionCsid);
+
+ // Lastly, relate the two entities, by creating a new relation object
+ RelationsCommon relation = new RelationsCommon();
+ fillRelation(relation, collectionObjectCsid, CollectionobjectsCommon.class.getSimpleName(),
+ dimensionCsid, DimensionsCommon.class.getSimpleName(),
+ "collectionobject-dimension");
+ // Create the part and fill it with the relation object
+ multipart = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
+ commonPart = multipart.addPart(relation, MediaType.APPLICATION_XML_TYPE);
+ commonPart.setLabel(relationClient.getCommonPartName());
+
+ // Make the call to crate
+ ClientResponse<Response> relationresponse = relationClient.create(multipart);
+ @SuppressWarnings("unused")
+ String relationCsid = null;
+ try {
+ Assert.assertEquals(relationresponse.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
+ relationCsid = extractId(response);
+ } finally {
+ relationresponse.releaseConnection();
+ }
+
+ }
+
@Test
public void relateCollectionObjectToIntake() {
//
import org.collectionspace.services.common.ResourceMap;
import org.collectionspace.services.common.ServiceMain;
import org.collectionspace.services.common.ServiceMessages;
-import org.collectionspace.services.common.XmlTools;
import org.collectionspace.services.common.api.RefName;
import org.collectionspace.services.common.api.Tools;
import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
import org.collectionspace.services.common.authorityref.AuthorityRefList;
import org.collectionspace.services.common.context.JaxRsContext;
import org.collectionspace.services.common.context.MultipartServiceContext;
-import org.collectionspace.services.common.context.MultipartServiceContextImpl;
import org.collectionspace.services.common.context.RemoteServiceContext;
import org.collectionspace.services.common.context.ServiceBindingUtils;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.DocumentNotFoundException;
import org.collectionspace.services.common.document.DocumentWrapper;
import org.collectionspace.services.common.query.QueryManager;
-import org.collectionspace.services.common.repository.RepositoryClient;
import org.collectionspace.services.common.vocabulary.RefNameServiceUtils;
import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler;
import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler;
import org.collectionspace.services.jaxb.AbstractCommonList;
import org.collectionspace.services.lifecycle.TransitionDef;
import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
-import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
-import org.collectionspace.services.relation.RelationResource;
-import org.collectionspace.services.relation.RelationsCommonList;
-import org.collectionspace.services.relation.RelationshipType;
import org.collectionspace.services.workflow.WorkflowCommon;
import org.jboss.resteasy.util.HttpResponseCodes;
import org.nuxeo.ecm.core.api.DocumentModel;
try {
ensureCSID(csid, ServiceMessages.DELETE_FAILED, "Authority.csid");
ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
- getRepositoryClient(ctx).delete(ctx, csid);
+ DocumentHandler handler = createDocumentHandler(ctx);
+ getRepositoryClient(ctx).delete(ctx, csid, handler);
return Response.status(HttpResponseCodes.SC_OK).build();
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid);
return result.getBytes();
}
+ //FIXME: This method is almost identical to the method org.collectionspace.services.common.updateWorkflowWithTransition() so
+ // they should be consolidated -be DRY (don't repeat yourself).
@PUT
@Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
public byte[] updateItemWorkflowWithTransition(
@PathParam("itemcsid") String itemcsid,
@PathParam("transition") String transition) {
PoxPayloadOut result = null;
+
try {
+ //
+ // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(),
WorkflowClient.SERVICE_COMMONPART_NAME);
+ MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
+ // Create a service context and document handler for the parent resource.
ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
- String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
+ DocumentHandler parentDocHandler = this.createDocumentHandler(parentCtx);
+ ctx.setProperty(WorkflowClient.PARENT_DOCHANDLER, parentDocHandler); //added as a context param for the workflow document handler -it will call the parent's dochandler "prepareForWorkflowTranstion" method
+ // When looking for the document, we need to use the parent's workspace name -not the "workflow" workspace name
+ String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
+ ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
+
+ // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
TransitionDef transitionDef = getTransitionDef(parentCtx, transition);
- MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
+
WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
- ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
getRepositoryClient(ctx).update(ctx, itemcsid, handler);
result = ctx.getOutput();
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
}
+
return result.getBytes();
}
// try {
// Note that we have to create the service context for the Items, not the main service
ServiceContext ctx = createServiceContext(getItemServiceName());
- getRepositoryClient(ctx).delete(ctx, itemcsid);
+ DocumentHandler handler = createDocumentHandler(ctx);
+ getRepositoryClient(ctx).delete(ctx, itemcsid, handler);
return Response.status(HttpResponseCodes.SC_OK).build();
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemcsid + " parentcsid:" + parentcsid);
}
}
- protected void updateItemLifeCycleState(String testName, String parentCsid, String itemCsid, String workflowTransition, String lifeCycleState) throws Exception {
+ @SuppressWarnings("unchecked")
+ protected void updateItemLifeCycleState(String testName, String parentCsid, String itemCsid, String workflowTransition, String lifeCycleState) throws Exception {
//
// Read the existing object
//
//
public static final String WORKFLOW_QUERY_NONDELETED = "wf_deleted";
public static final String WORKFLOWSTATE_QUERY = "wf_deleted";
+ public static final String PARENT_DOCHANDLER = "wf_dochandler";
@Override
/*\r
* JAX-RS Annotated methods\r
*/\r
+ \r
+ /*\r
+ * We should change this method. The RepositoryClient (from call to getRepositoryClient) should support a call getWorkflowTransition() instead.\r
+ */ \r
@GET\r
@Path("{csid}" + WorkflowClient.SERVICE_PATH)\r
public byte[] getWorkflow(\r
return result;\r
}\r
\r
+ /*\r
+ * We should change this code. The RepositoryClient (from call to getRepositoryClient) should support a call doWorkflowTransition() instead.\r
+ */\r
+ //FIXME: This method is almost identical to the method org.collectionspace.services.common.vocabulary.updateWorkflowWithTransition() so\r
+ // they should be consolidated -be DRY (don't repeat yourself).\r
+\r
@PUT\r
@Path("{csid}" + WorkflowClient.SERVICE_PATH + "/" + "{transition}")\r
public byte[] updateWorkflowWithTransition(@PathParam("csid") String csid,\r
@PathParam("transition") String transition) {\r
PoxPayloadOut result = null;\r
+ \r
+ \r
try {\r
+ //\r
+ // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context\r
PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(), \r
WorkflowClient.SERVICE_COMMONPART_NAME);\r
+ MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);\r
\r
+ // Create a service context and document handler for the parent resource.\r
ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext();\r
+ DocumentHandler parentDocHandler = this.createDocumentHandler(parentCtx); \r
+ ctx.setProperty(WorkflowClient.PARENT_DOCHANDLER, parentDocHandler); //added as a context param for the workflow document handler -it will call the parent's dochandler "prepareForWorkflowTranstion" method\r
+\r
+ // When looking for the document, we need to use the parent's workspace name -not the "workflow" workspace name\r
String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();\r
- \r
+ ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace\r
+ \r
+ // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler\r
TransitionDef transitionDef = getTransitionDef(parentCtx, transition);\r
- MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);\r
ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);\r
+\r
WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);\r
- ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace\r
getRepositoryClient(ctx).update(ctx, csid, handler);\r
result = ctx.getOutput();\r
} catch (Exception e) {\r
* which handles setup of ServiceContext, and does Exception handling. */\r
protected Response delete(String csid, ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx)\r
throws Exception {\r
- getRepositoryClient(ctx).delete(ctx, csid);\r
+ DocumentHandler handler = createDocumentHandler(ctx);\r
+ getRepositoryClient(ctx).delete(ctx, csid, handler);\r
return Response.status(HttpResponseCodes.SC_OK).build();\r
}\r
\r
break;
case DELETE:
+ validate(action);
prepareDelete();
break;
import java.util.Map;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.lifecycle.Lifecycle;
+import org.collectionspace.services.lifecycle.TransitionDef;
+import org.nuxeo.ecm.core.api.DocumentModel;
/**
*
public interface DocumentHandler<T, TL, WT, WTL> {
public enum Action {
- CREATE, GET, GET_ALL, UPDATE, DELETE
+ CREATE, GET, GET_ALL, UPDATE, DELETE, WORKFLOW
}
public Lifecycle getLifecycle();
*/
public void prepare(Action action) throws Exception;
+ /**
+ * updateWorkflowTransition - prepare for a workflow transition
+ */
+ public void handleWorkflowTransition(DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef) throws Exception;
+
/**
* prepareCreate processes documents before creating document in repository
import org.collectionspace.services.common.document.DocumentException;
import org.collectionspace.services.common.document.DocumentHandler;
import org.collectionspace.services.common.document.DocumentNotFoundException;
+import org.collectionspace.services.lifecycle.TransitionDef;
/**
*
* @throws DocumentNotFoundException if entity not found
* @throws DocumentException
*/
- void update(ServiceContext ctx, String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException;
+ void update(ServiceContext ctx, String id, DocumentHandler handler)
+ throws BadRequestException, DocumentNotFoundException, DocumentException;
+
+ /*
+ * Updates the workflow state of a document
+ */
+ void doWorkflowTransition(ServiceContext ctx, String id, DocumentHandler handler, TransitionDef transitionDef)
+ throws BadRequestException, DocumentNotFoundException, DocumentException;
}
import org.collectionspace.services.common.document.DocumentWrapper;\r
import org.collectionspace.services.jaxb.AbstractCommonList;\r
import org.collectionspace.services.lifecycle.Lifecycle;\r
+import org.collectionspace.services.lifecycle.TransitionDef;\r
+import org.nuxeo.ecm.core.api.DocumentModel;\r
\r
public abstract class JpaDocumentHandler<T, TL, WT, WLT>\r
extends AbstractDocumentHandlerImpl<T, TL, WT, WLT>{\r
public Lifecycle getLifecycle() {\r
return getLifecycle(null); // NOTE: As of 3/2012, none of the JPA-based services support a life cycle type.\r
}\r
+ \r
+ @Override\r
+ public void handleWorkflowTransition(\r
+ DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef)\r
+ throws Exception {\r
+ // Do nothing. JPA document handlers do not support workflow transitions yet.\r
+ }\r
+ \r
}\r
import org.collectionspace.services.common.context.ServiceContextProperties;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.query.QueryContext;
+import org.collectionspace.services.lifecycle.TransitionDef;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
throws DocumentNotFoundException, DocumentException {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public void doWorkflowTransition(ServiceContext ctx, String id,
+ DocumentHandler handler, TransitionDef transitionDef)
+ throws BadRequestException, DocumentNotFoundException,
+ DocumentException {
+ // Do nothing. JPA services do not support workflow.
+ }
}
*/
package org.collectionspace.services.common.workflow.service.nuxeo;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.core.MediaType;
-import org.collectionspace.services.client.PayloadInputPart;
-import org.collectionspace.services.client.PoxPayloadIn;
-import org.collectionspace.services.client.PoxPayloadOut;
import org.collectionspace.services.client.workflow.WorkflowClient;
import org.collectionspace.services.common.context.MultipartServiceContext;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.DocumentWrapper;
-import org.collectionspace.services.common.document.DocumentHandler.Action;
import org.collectionspace.services.common.workflow.jaxb.WorkflowJAXBSchema;
import org.collectionspace.services.config.service.ObjectPartType;
import org.collectionspace.services.lifecycle.TransitionDef;
import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
+import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
import org.collectionspace.services.workflow.WorkflowCommon;
import org.nuxeo.ecm.core.api.ClientException;
import org.nuxeo.ecm.core.api.DocumentModel;
*
* org.nuxeo.ecm.core.LifecycleCoreExtensions--lifecycle (as opposed to --types)
*/
- private static final String TRANSITION_DELETE = "delete";
- private static final String TRANSITION_APPROVE = "approve";
- private static final String TRANSITION_UNDELETE = "undelete";
private static final String TRANSITION_UNKNOWN = "unknown";
+
+ @Override
+ public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
+ //
+ // First, call the parent document handler to give it a chance to handle the workflow transition -otherwise, call
+ // the super/parent handleUpdate() method.
+ //
+ ServiceContext ctx = this.getServiceContext();
+ DocumentModelHandler docHandler = (DocumentModelHandler)ctx.getProperty(WorkflowClient.PARENT_DOCHANDLER);
+ TransitionDef transitionDef = (TransitionDef)ctx.getProperty(WorkflowClient.TRANSITION_ID);
+ docHandler.handleWorkflowTransition(wrapDoc, transitionDef);
+ //
+ // If no exception occurred, then call the super's method
+ //
+ super.handleUpdate(wrapDoc);
+ }
+
/*
* Handle read (GET)
*/
import org.collectionspace.services.authorization.AccountPermission;
import org.collectionspace.services.jaxb.AbstractCommonList;
+import org.collectionspace.services.lifecycle.TransitionDef;
import org.collectionspace.services.client.PayloadInputPart;
import org.collectionspace.services.client.PayloadOutputPart;
import org.collectionspace.services.client.PoxPayloadIn;
}
}
+ @Override
+ public void handleWorkflowTransition(DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef)
+ throws Exception {
+ // Do nothing by default, but children can override if they want. The really workflow transition happens in the WorkflowDocumemtModelHandler class
+ }
+
/* (non-Javadoc)
* @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#completeUpdate(org.collectionspace.services.common.document.DocumentWrapper)
*/
import org.collectionspace.services.common.query.QueryContext;
import org.collectionspace.services.common.repository.RepositoryClient;
import org.collectionspace.services.common.profile.Profiler;
+import org.collectionspace.services.lifecycle.TransitionDef;
import org.collectionspace.services.nuxeo.util.NuxeoUtils;
import org.collectionspace.services.common.document.BadRequestException;
* @throws DocumentException
*/
@Override
- public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException,
+ public void delete(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException,
DocumentException {
-
+ if (ctx == null) {
+ throw new IllegalArgumentException(
+ "delete(ctx, ix, handler): ctx is missing");
+ }
+ if (handler == null) {
+ throw new IllegalArgumentException(
+ "delete(ctx, ix, handler): handler is missing");
+ }
if (logger.isDebugEnabled()) {
logger.debug("Deleting document with CSID=" + id);
}
RepositoryInstance repoSession = null;
try {
+ handler.prepare(Action.DELETE);
repoSession = getRepositorySession();
- DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
+ DocumentWrapper<DocumentModel> wrapDoc = null;
try {
+ DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
+ wrapDoc = new DocumentWrapperImpl<DocumentModel>(repoSession.getDocument(docRef));
+ ((DocumentModelHandler) handler).setRepositorySession(repoSession);
+ handler.handle(Action.DELETE, wrapDoc);
repoSession.removeDocument(docRef);
} catch (ClientException ce) {
String msg = logException(ce, "Could not find document to delete with CSID=" + id);
throw new DocumentNotFoundException(msg, ce);
}
repoSession.save();
+ handler.complete(Action.DELETE, wrapDoc);
} catch (DocumentException de) {
throw de;
} catch (Exception e) {
* @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
*/
@Override
- public void delete(ServiceContext ctx, String id, DocumentHandler handler)
+ @Deprecated
+ public void delete(@SuppressWarnings("rawtypes") ServiceContext ctx, String id)
throws DocumentNotFoundException, DocumentException {
throw new UnsupportedOperationException();
+ // Use the other delete instead
}
@Override
}
}
+ @Override
+ public void doWorkflowTransition(ServiceContext ctx, String id,
+ DocumentHandler handler, TransitionDef transitionDef)
+ throws BadRequestException, DocumentNotFoundException,
+ DocumentException {
+ // This is a placeholder for when we change the StorageClient interface to treat workflow transitions as 1st class operations like 'get', 'create', 'update, 'delete', etc
+ }
+
}
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
+
+ // Bail out if the validation action is for delete.
+ if (action.equals(Action.DELETE)) {
+ return;
+ }
+
try {
MultipartServiceContext mctx = (MultipartServiceContext) ctx;
ConceptsCommon concept = (ConceptsCommon) mctx.getInputPart(mctx.getCommonPartLabel(),
ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
// Note that we have to create the service context for the Contact service, not the main service.
ctx = createServiceContext(getContactServiceName());
- getRepositoryClient(ctx).delete(ctx, csid);
+ DocumentHandler handler = createDocumentHandler(ctx);
+ getRepositoryClient(ctx).delete(ctx, csid, handler);
return Response.status(HttpResponseCodes.SC_OK).build();
} catch (Exception e) {
throw bigReThrow(e, "DELETE failed, the requested Contact CSID:" + csid
<ServiceName>dimension</ServiceName>
<NuxeoDocTypeName>Dimension</NuxeoDocTypeName>
<CommonSchemaName>dimensions_common</CommonSchemaName>
- <Lifecycle>cs_default</Lifecycle>
+ <Lifecycle>cs_locking</Lifecycle>
</properties>
<build>
<artifactId>org.collectionspace.services.common</artifactId>\r
<version>${project.version}</version>\r
</dependency>\r
- \r
+ <!-- \r
<dependency>\r
<groupId>org.collectionspace.services</groupId>\r
<artifactId>org.collectionspace.services.IntegrationTests</artifactId>\r
<version>${project.version}</version>\r
</dependency>\r
+ -->\r
\r
<!-- External dependencies -->\r
<dependency>\r
package org.collectionspace.services.client.test;\r
\r
+/*\r
+ * XMLReplay test classes shoud ***NOT*** be part of the IntegrationTests module. Move them out into the org.collectionspace.services.client (src/main.test) module ASAP!\r
+ */\r
+\r
+/*\r
import org.collectionspace.services.IntegrationTests.xmlreplay.ServiceResult;\r
import org.collectionspace.services.IntegrationTests.xmlreplay.XmlReplay;\r
import org.collectionspace.services.IntegrationTests.xmlreplay.XmlReplayTest;\r
import org.testng.annotations.Test;\r
\r
import java.util.List;\r
+*/\r
\r
/**\r
* User: laramie\r
* $LastChangedRevision: $\r
* $LastChangedDate: $\r
*/\r
-public class DimensionXmlReplayTest extends XmlReplayTest { \r
+public class DimensionXmlReplayTest /*extends XmlReplayTest*/ { \r
\r
+ /*\r
//@Test\r
public void runMaster() throws Exception {\r
XmlReplay replay = createXmlReplayUsingIntegrationTestsModule("../../");\r
ServiceResult res = replay.runTest("dimensionTestGroup", "dimension1");\r
logTest(res, "runOneTest");\r
}\r
+ */\r
\r
}\r
public String getQProperty(String prop) {
return DimensionConstants.NUXEO_SCHEMA_NAME + ":" + prop;
}
+
}
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
+
+ // Bail out if the validation action is for delete.
+ if (action.equals(Action.DELETE)) {
+ return;
+ }
+
try {
MultipartServiceContext mctx = (MultipartServiceContext) ctx;
LocationsCommon location = (LocationsCommon) mctx.getInputPart(mctx.getCommonPartLabel(),
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
+
+ // Bail out if the validation action is for delete.
+ if (action.equals(Action.DELETE)) {
+ return;
+ }
+
try {
MultipartServiceContext mctx = (MultipartServiceContext) ctx;
OrgauthoritiesCommon organizationAuth =
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
+
+ // Bail out if the validation action is for delete.
+ if (action.equals(Action.DELETE)) {
+ return;
+ }
+
try {
MultipartServiceContext mctx = (MultipartServiceContext) ctx;
OrganizationsCommon org = (OrganizationsCommon) mctx.getInputPart(mctx.getCommonPartLabel(),
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
+
+ // Bail out if the validation action is for delete.
+ if (action.equals(Action.DELETE)) {
+ return;
+ }
+
try {
MultipartServiceContext mctx = (MultipartServiceContext) ctx;
PersonauthoritiesCommon personAuth =
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
+
+ // Bail out if the validation action is for delete.
+ if (action.equals(Action.DELETE)) {
+ return;
+ }
+
try {
MultipartServiceContext mctx = (MultipartServiceContext) ctx;
PersonsCommon person = (PersonsCommon) mctx.getInputPart(mctx.getCommonPartLabel(),
if(logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
+
+ // Bail out if the validation action is for delete.
+ if (action.equals(Action.DELETE)) {
+ return;
+ }
+
try {
MultipartServiceContext mctx = (MultipartServiceContext) ctx;
PlacesCommon place = (PlacesCommon) mctx.getInputPart(mctx.getCommonPartLabel(),
import java.util.HashMap;
import java.util.Iterator;
+import java.net.HttpURLConnection;
import org.collectionspace.services.client.PoxPayloadIn;
import org.collectionspace.services.client.PoxPayloadOut;
import org.collectionspace.services.common.ResourceBase;
+import org.collectionspace.services.common.ServiceException;
import org.collectionspace.services.common.ServiceMain;
import org.collectionspace.services.common.api.RefName;
import org.collectionspace.services.common.api.Tools;
import org.collectionspace.services.common.relation.RelationJAXBSchema;
import org.collectionspace.services.common.relation.nuxeo.RelationConstants;
import org.collectionspace.services.common.context.ServiceContext;
+import org.collectionspace.services.lifecycle.TransitionDef;
import org.collectionspace.services.nuxeo.util.NuxeoUtils;
import org.collectionspace.services.relation.RelationsCommon;
import org.collectionspace.services.relation.RelationsCommonList;
import org.collectionspace.services.client.TaxonomyAuthorityClient;
import org.collectionspace.services.client.PlaceAuthorityClient;
import org.collectionspace.services.client.ConceptAuthorityClient;
+import org.collectionspace.services.client.workflow.WorkflowClient;
import org.collectionspace.services.config.service.ServiceBindingType;
import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
import org.nuxeo.ecm.core.api.ClientException;
-import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.model.PropertyException;
* for ACTION.GET_ALL
*/
private RelationsCommonList relationList;
+
+ private static final String ERROR_TERMS_IN_WORKFLOWSTATE = "Cannot modify a relationship if either end is in the workflow state: ";
+
+
+ private boolean subjectOrObjectInWorkflowState(DocumentWrapper<DocumentModel> wrapDoc, String workflowState) throws ServiceException {
+ boolean result = false;
+ DocumentModel relationDocModel = wrapDoc.getWrappedObject();
+ String errMsg = ERROR_TERMS_IN_WORKFLOWSTATE + workflowState;
+
+ RepositoryInstance repoSession = this.getRepositorySession();
+ try {
+ DocumentModel subjectDocModel = getSubjectOrObjectDocModel(repoSession, relationDocModel, SUBJ_DOC_MODEL);
+ DocumentModel objectDocModel = getSubjectOrObjectDocModel(repoSession, relationDocModel, OBJ_DOC_MODEL);
+ if (subjectDocModel.getCurrentLifeCycleState().equalsIgnoreCase(workflowState) ||
+ objectDocModel.getCurrentLifeCycleState().equalsIgnoreCase(workflowState)) {
+ result = true;
+ }
+ } catch (Exception e) {
+ if (logger.isInfoEnabled() == true) {
+ logger.info(errMsg, e);
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ /*
+ * Until we rework the RepositoryClient to handle the workflow transition (just like it does for 'create', 'get', 'update', and 'delete', this method will only check to see if the transition is allowed. Until then,
+ * the WorkflowDocumentModelHandler class does the actual workflow transition.
+ *
+ * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#handleWorkflowTransition(org.collectionspace.services.common.document.DocumentWrapper, org.collectionspace.services.lifecycle.TransitionDef)
+ */
+ public void handleWorkflowTransition(DocumentWrapper<DocumentModel> wrapDoc, TransitionDef transitionDef)
+ throws Exception {
+ String workflowState = transitionDef.getDestinationState();
+ if (subjectOrObjectInWorkflowState(wrapDoc, workflowState) == true) {
+ throw new ServiceException(HttpURLConnection.HTTP_FORBIDDEN,
+ "Cannot change a relationship if either end of it is in the workflow state: " + workflowState);
+ }
+ }
@Override
public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
// And take care of ensuring all the values for the relation info are correct
populateSubjectAndObjectValues(wrapDoc);
+
+ // both subject and object cannot be locked
+ String workflowState = WorkflowClient.WORKFLOWSTATE_LOCKED;
+ if (subjectOrObjectInWorkflowState(wrapDoc, workflowState) == true) {
+ throw new ServiceException(HttpURLConnection.HTTP_FORBIDDEN,
+ "Cannot create a relationship if either end is in the workflow state: " + workflowState);
+ }
}
@Override
populateSubjectAndObjectValues(wrapDoc);
}
+ @Override
+ public void handleDelete(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
+ String workflowState = WorkflowClient.WORKFLOWSTATE_LOCKED;
+ // both subject and object cannot be locked
+ if (subjectOrObjectInWorkflowState(wrapDoc, workflowState) == false) {
+ super.handleDelete(wrapDoc);
+ } else {
+ throw new ServiceException(HttpURLConnection.HTTP_FORBIDDEN,
+ "Cannot delete a relationship if either end is in the workflow state: " + workflowState);
+ }
+ }
+
private void populateSubjectAndObjectValues(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
// Obtain document models for the subject and object of the relation, so that
// we ensure we have value docType, URI info. If the docModels support refNames,
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
+
+ // Bail out if the validation action is for delete.
+ if (action.equals(Action.DELETE)) {
+ return;
+ }
+
try {
MultipartServiceContext mctx = (MultipartServiceContext) ctx;
TaxonCommon taxon = (TaxonCommon) mctx.getInputPart(mctx.getCommonPartLabel(),
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
+
+ // Bail out if the validation action is for delete.
+ if (action.equals(Action.DELETE)) {
+ return;
+ }
+
try {
MultipartServiceContext mctx = (MultipartServiceContext) ctx;
VocabularyitemsCommon vocabItem = (VocabularyitemsCommon) mctx.getInputPart(mctx.getCommonPartLabel(),
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
+
+ // Bail out if the validation action is for delete.
+ if (action.equals(Action.DELETE)) {
+ return;
+ }
+
try {
MultipartServiceContext mctx = (MultipartServiceContext) ctx;
VocabulariesCommon vocab = (VocabulariesCommon) mctx.getInputPart(mctx.getCommonPartLabel(),