}
boolean isActiveDocument = false;
try {
- if (!docModel.getCurrentLifeCycleState().equals(WorkflowClient.WORKFLOWSTATE_DELETED)) {
+ if (!docModel.getCurrentLifeCycleState().contains(WorkflowClient.WORKFLOWSTATE_DELETED)) {
isActiveDocument = true;
}
} catch (ClientException ce) {
List<String> workflowStatesToFilter = new ArrayList<String>();
workflowStatesToFilter.add(WorkflowClient.WORKFLOWSTATE_DELETED);
workflowStatesToFilter.add(WorkflowClient.WORKFLOWSTATE_LOCKED);
+ workflowStatesToFilter.add(WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED);
LifeCycleFilter workflowStateFilter = new LifeCycleFilter(null, workflowStatesToFilter);
// Perform the filtered query
*/
private boolean isDocumentSoftDeletedEvent(EventContext eventContext) {
boolean isSoftDeletedEvent = false;
+
if (eventContext instanceof DocumentEventContext) {
if (eventContext.getProperties().containsKey(WorkflowClient.WORKFLOWTRANSITION_TO)
- && eventContext.getProperties().get(WorkflowClient.WORKFLOWTRANSITION_TO).equals(WorkflowClient.WORKFLOWSTATE_DELETED)) {
+ &&
+ (eventContext.getProperties().get(WorkflowClient.WORKFLOWTRANSITION_TO).equals(WorkflowClient.WORKFLOWSTATE_DELETED)
+ ||
+ eventContext.getProperties().get(WorkflowClient.WORKFLOWTRANSITION_TO).equals(WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED))) {
isSoftDeletedEvent = true;
}
}
+
return isSoftDeletedEvent;
}
-
}
public String lookupItemCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext, String itemspecifier, String parentcsid, String method, String op)
throws Exception {
String itemcsid;
+
Specifier itemSpec = Specifier.getSpecifier(itemspecifier, method, op);
if (itemSpec.form == SpecifierForm.CSID) {
itemcsid = itemSpec.value;
}
itemcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, itemWhereClause); //FIXME: REM - Should we be looking for the 'wf_deleted' query param and filtering on it?
}
+
return itemcsid;
}
WorkflowClient.SERVICE_COMMONPART_NAME);
MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
- ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession()); // If a repo session is already open, we need to use it and not create a new one
+ ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());// If a repo session is already open, we need to use it and not create a new one
}
//
// Create a service context and document handler for the target resource -not the workflow resource itself.
//
- ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName());
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName(), existingContext.getUriInfo());
AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
ctx.setProperty(WorkflowClient.TARGET_DOCHANDLER, targetDocHandler); //added as a context param for the workflow document handler -it will call the parent's dochandler "prepareForWorkflowTranstion" method
/**
* Delete authorityItem.
*
- * @param parentcsid the parentcsid
- * @param itemcsid the itemcsid
+ * @param parentIdentifier the parentcsid
+ * @param itemIdentifier the itemcsid
*
* @return the response
*/
@DELETE
@Path("{csid}/items/{itemcsid}")
public Response deleteAuthorityItem(
- @PathParam("csid") String parentcsid,
- @PathParam("itemcsid") String itemcsid) {
+ @PathParam("csid") String parentIdentifier,
+ @PathParam("itemcsid") String itemIdentifier) {
Response result = null;
- //try{
+
+ ensureCSID(parentIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
+ ensureCSID(itemIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
if (logger.isDebugEnabled()) {
- logger.debug("deleteAuthorityItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
+ logger.debug("deleteAuthorityItem with parentcsid=" + parentIdentifier + " and itemcsid=" + itemIdentifier);
}
try {
- deleteAuthorityItem(null, parentcsid, itemcsid);
+ deleteAuthorityItem(null, parentIdentifier, itemIdentifier);
result = Response.status(HttpResponseCodes.SC_OK).build();
} catch (Exception e) {
- throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemcsid + " parentcsid:" + parentcsid);
+ throw bigReThrow(e, ServiceMessages.DELETE_FAILED + " itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier);
}
- //Laramie, removing this catch, since it will surely fail below, since itemcsid or parentcsid will be null.
+
return result;
}
- // }catch (Throwable t){
+
+ /**
+ *
+ * @param existingCtx
+ * @param parentIdentifier
+ * @param itemIdentifier
+ * @throws Exception
+ */
public void deleteAuthorityItem(ServiceContext existingCtx,
- String parentcsid,
- String itemcsid) throws Exception {
+ String parentIdentifier,
+ String itemIdentifier) throws Exception {
Response result = null;
- // System.out.println("ERROR in setting up DELETE: "+t);
- ensureCSID(parentcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
- ensureCSID(itemcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
- // }
- ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName());
+
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName());
+ String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
+ String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
+
if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Use existing repo session if one exists
ctx.setProperties(existingCtx.getProperties());
}
- DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
- getRepositoryClient(ctx).delete(ctx, itemcsid, handler);
- }
+
+ DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
+ getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
+ }
@GET
@Path("{csid}/items/{itemcsid}/" + hierarchy)
@Produces("application/xml")
- public String getHierarchy(@PathParam("csid") String csid,
- @PathParam("itemcsid") String itemcsid,
- @Context UriInfo ui) throws Exception {
+ public String getHierarchy(
+ @PathParam("csid") String parentIdentifier,
+ @PathParam("itemcsid") String itemIdentifier,
+ @Context UriInfo uriInfo) throws Exception {
+ String result = null;
+
try {
+ //
// All items in dive can look at their child uri's to get uri. So we calculate the very first one. We could also do a GET and look at the common part uri field, but why...?
- String calledUri = ui.getPath();
+ //
+ String calledUri = uriInfo.getPath();
String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
- ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), ui);
- ctx.setUriInfo(ui);
- String direction = ui.getQueryParameters().getFirst(Hierarchy.directionQP);
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
+
+ String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
+ String itemcsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
+
+ String direction = uriInfo.getQueryParameters().getFirst(Hierarchy.directionQP);
if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
- return Hierarchy.surface(ctx, itemcsid, uri);
+ result = Hierarchy.surface(ctx, itemcsid, uri);
} else {
- return Hierarchy.dive(ctx, itemcsid, uri);
- }
+ result = Hierarchy.dive(ctx, itemcsid, uri);
+ }
} catch (Exception e) {
- throw bigReThrow(e, "Error showing hierarchy", itemcsid);
+ throw bigReThrow(e, "Error showing hierarchy for authority item: ", itemIdentifier);
}
+
+ return result;
}
+ /**
+ *
+ * @param tenantId
+ * @return
+ */
protected String getItemDocType(String tenantId) {
return getDocType(tenantId, getItemServiceName());
}
package org.collectionspace.services.common.vocabulary;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import javax.ws.rs.core.Response;
import org.collectionspace.services.client.AuthorityClient;
import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityIdentifierUtils;
import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
import org.collectionspace.services.nuxeo.util.NuxeoUtils;
+import org.dom4j.DocumentException;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
return result;
}
+ /*
+ * The domain name part of refnames on SAS may not match that of local refnames, so we need to update all the payload's
+ * refnames with the correct domain name
+ */
+ static public PoxPayloadIn filterRefnameDomains(ServiceContext ctx,
+ PoxPayloadIn payload) throws DocumentException {
+ PoxPayloadIn result = null;
+
+
+ String payloadStr = payload.getXmlPayload();
+ Pattern p = Pattern.compile("(urn:cspace:)(([a-z]{1,}\\.?)*)"); // matches the domain name part of a RefName. For example, matches "core.collectionspace.org" of RefName urn:cspace:core.collectionspace.org:personauthorities:name(person):item:name(BigBird1461101206103)'Big Bird'
+ Matcher m = p.matcher(payloadStr);
+
+ StringBuffer filteredPayloadStr = new StringBuffer();
+ while (m.find() == true) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Replacing: " + m.group(2));
+ }
+ m.appendReplacement(filteredPayloadStr, m.group(1) + ctx.getTenantName());
+ }
+ m.appendTail(filteredPayloadStr);
+ result = new PoxPayloadIn(filteredPayloadStr.toString());
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(String.format("", filteredPayloadStr));
+ }
+
+ return result;
+ }
+
/**
* Mark the authority item as deprecated.
*
//
PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(sasAuthorityItemSpecifier,
ctx.getServiceName(), getEntityResponseType());
+ sasPayloadIn = AuthorityServiceUtils.filterRefnameDomains(ctx, sasPayloadIn); // We need to filter domain name part of any and all refnames in the payload
//
// Using the payload from the remote server, create a local copy of the item
//
import org.slf4j.LoggerFactory;
import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
import java.util.Collection;
//
DocumentModel docModel = wrapDoc.getWrappedObject();
if (transitionDef.getName().equalsIgnoreCase(WorkflowClient.WORKFLOWTRANSITION_DELETE)) {
- if (hasReferencingObjects(this.getServiceContext(), docModel) == true) {
+ if (hasReferencingObjects(this.getServiceContext(), docModel, false) == true) {
throw new DocumentReferenceException(String.format("Cannot delete authority item '%s' because it still has records in the system that are referencing it. See the service layer log file for details.",
docModel.getName()));
}
// If the shared authority item is newer, update our local copy
//
if (sasRev > localItemRev || localIsProposed) {
+ sasPayloadIn = AuthorityServiceUtils.filterRefnameDomains(ctx, sasPayloadIn); // We need to filter the domain name part of any and all refnames in the payload
AuthorityResource authorityResource = (AuthorityResource) ctx.getResource(getAuthorityServicePath());
PoxPayloadOut payloadOut = authorityResource.updateAuthorityItem(ctx,
ctx.getResourceMap(),
ServiceContext ctx = getServiceContext();
DocumentModel docModel = wrapDoc.getWrappedObject();
- if (hasReferencingObjects(ctx, docModel) == true) {
+ long refsToObjects = hasReferencingObjects(ctx, docModel, false);
+ long refsToSoftDeletedObjects = hasReferencingObjects(ctx, docModel, true);
+
+ if (refsToObjects > refsToSoftDeletedObjects) {
throw new DocumentReferenceException(String.format("Cannot delete authority item '%s' because it still has records in the system that are referencing it. See the service layer log file for details.",
docModel.getName()));
}
* @return
* @throws Exception
*/
- private boolean hasReferencingObjects(ServiceContext ctx, DocumentModel docModel) throws Exception {
- boolean result = false;
+ private long hasReferencingObjects(ServiceContext ctx, DocumentModel docModel, boolean onlyRefsToDeletedObjects) throws Exception {
+ long result = 0;
String inAuthorityCsid = (String) docModel.getProperty(authorityItemCommonSchemaName, AuthorityItemJAXBSchema.IN_AUTHORITY);
AuthorityResource authorityResource = (AuthorityResource)ctx.getResource(getAuthorityServicePath());
String itemCsid = docModel.getName();
UriTemplateRegistry uriTemplateRegistry = ServiceMain.getInstance().getUriTemplateRegistry();
+ ctx.getUriInfo().getQueryParameters().add(WorkflowClient.WORKFLOW_QUERY_ONLY_DELETED, Boolean.toString(onlyRefsToDeletedObjects)); // Add the wf_deleted query param to the resource call
AuthorityRefDocList refObjs = authorityResource.getReferencingObjects(ctx, inAuthorityCsid, itemCsid,
uriTemplateRegistry, ctx.getUriInfo());
-
- if (refObjs.getTotalItems() > 0) {
- result = true;
+
+ result = refObjs.getTotalItems();
+ if (result > 0) {
logger.error(String.format("Cannot delete authority item '%s' because it still has %d records in the system that are referencing it.",
itemCsid, refObjs.getTotalItems()));
if (logger.isWarnEnabled() == true) {
private boolean isRecordDeleted(NuxeoBasedResource resource, String collectionObjectCsid)
throws URISyntaxException, DocumentException {
boolean isDeleted = false;
+
byte[] workflowResponse = resource.getWorkflow(createUriInfo(), collectionObjectCsid);
if (workflowResponse != null) {
PoxPayloadOut payloadOut = new PoxPayloadOut(workflowResponse);
String workflowState =
getFieldElementValue(payloadOut, WORKFLOW_COMMON_SCHEMA_NAME,
WORKFLOW_COMMON_NAMESPACE, LIFECYCLE_STATE_ELEMENT_NAME);
- if (Tools.notBlank(workflowState) && workflowState.equals(WorkflowClient.WORKFLOWSTATE_DELETED)) {
+ if (Tools.notBlank(workflowState) && workflowState.contains(WorkflowClient.WORKFLOWSTATE_DELETED)) {
isDeleted = true;
}
}
+
return isDeleted;
}
//
// Service Query Params
//
+ public static final String WORKFLOW_QUERY_ONLY_DELETED = "wf_only_deleted";
public static final String WORKFLOW_QUERY_NONDELETED = "wf_deleted";
public static final String WORKFLOWSTATE_QUERY = "wf_deleted";
public static final String TARGET_DOCHANDLER = "wf_dochandler";
// see default-life-cycle-contrib.xml in the Nuxeo server configuration
//
private static final HashMap<String, String> statesMappedToTransitions;
- static
- {
+ static {
statesMappedToTransitions = new HashMap<String, String>();
statesMappedToTransitions.put(WORKFLOWSTATE_DELETED, WORKFLOWTRANSITION_DELETE);
statesMappedToTransitions.put("c", "d");
}
-
@Override
public String getServiceName() {
String result = null;
String includeDeleted = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_NONDELETED);
+ String includeOnlyDeleted = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_ONLY_DELETED);
+
if (includeDeleted != null && includeDeleted.equalsIgnoreCase(Boolean.FALSE.toString())) {
- result = "ecm:currentLifeCycleState <> 'deleted'";
+ result = String.format("(ecm:currentLifeCycleState <> '%s' AND ecm:currentLifeCycleState <> '%s')",
+ WorkflowClient.WORKFLOWSTATE_DELETED, WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED);
+ } else if (includeOnlyDeleted != null && includeOnlyDeleted.equalsIgnoreCase(Boolean.TRUE.toString())) {
+ result = String.format("(ecm:currentLifeCycleState <> '%s' AND ecm:currentLifeCycleState <> '%s')",
+ WorkflowClient.WORKFLOWSTATE_PROJECT, WorkflowClient.WORKFLOWSTATE_LOCKED);
}
return result;
// reflect the values of those parameters in the document filter
// to specify sort ordering, pagination, etc.
//
- if (this.getQueryParams() != null) {
- docFilter.setSortOrder(this.getQueryParams());
- docFilter.setPagination(this.getQueryParams());
- String workflowWhereClause = buildWorkflowWhereClause(queryParams);
+ MultivaluedMap<String, String> queryParameters = this.getQueryParams();
+ if (queryParameters != null) {
+ docFilter.setSortOrder(queryParameters);
+ docFilter.setPagination(queryParameters);
+ String workflowWhereClause = buildWorkflowWhereClause(queryParameters);
if (workflowWhereClause != null) {
docFilter.appendWhereClause(workflowWhereClause, IQueryManager.SEARCH_QUALIFIER_AND);
}
addOutputPart(unQObjectProperties, schema, partMeta);
}
}
-
- /**
- * Get the identifier for the transition that sets a document to
- * the supplied, destination workflow state.
- *
- * @param state a destination workflow state.
- * @return an identifier for the transition required to
- * place the document in that workflow state.
- */
- @Deprecated
- private String getTransitionFromState(String state) {
- String result = TRANSITION_UNKNOWN;
-
- // FIXME We may wish to add calls, such as those in
- // org.nuxeo.ecm.core.lifecycle.impl.LifeCycleImpl, to validate incoming
- // destination workflow state and the set of allowable state transitions.
-
- if (state.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_DELETED)) {
- result = WorkflowClient.WORKFLOWTRANSITION_DELETE;
- } else if (state.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_ACTIVE)) {
- result = WorkflowClient.WORKFLOWTRANSITION_UNDELETE; //FIXME, could also be transition WORKFLOWTRANSITION_UNLOCK
- } else if (state.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_LOCKED)) {
- result = WorkflowClient.WORKFLOWTRANSITION_LOCK;
- } else {
- logger.warn("An attempt was made to transition a document to an unknown workflow state = "
- + state);
- }
-
- return result;
- }
/*
* Maps the transition name to handle existing states like "locked" and "deleted". This allows us to do things like lock "deleted"
boolean includeDeleted = includeDeletedStr == null ? true : Boolean.parseBoolean(includeDeletedStr);
if (includeDeleted == false) {
//
- // We don't wanted soft-deleted object, so throw an exception if this one is soft-deleted.
+ // We don't wanted soft-deleted objects, so throw an exception if this one is soft-deleted.
//
- if (currentState.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_DELETED)) {
+ if (currentState.contains(WorkflowClient.WORKFLOWSTATE_DELETED)) {
String msg = "The GET assertion that docModel not be in 'deleted' workflow state failed.";
logger.debug(msg);
throw new DocumentNotFoundException(msg);
String includeDeleted = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_NONDELETED);
if (includeDeleted != null && includeDeleted.equalsIgnoreCase(Boolean.FALSE.toString())) {
whereClause = whereClause
- + " AND (misc.lifecyclestate <> '" + WorkflowClient.WORKFLOWSTATE_DELETED + "')";
+ + " AND (misc.lifecyclestate <> '" + WorkflowClient.WORKFLOWSTATE_DELETED + "')"
+ + " AND (misc.lifecyclestate <> '" + WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED + "')";
}
// If a particular authority is specified, restrict the query further