log4j.logger.org.collectionspace.services.nuxeo.client.java.NuxeoClientEmbedded=ERROR
log4j.logger.org.collectionspace.services.nuxeo.client.java.RepositoryClientImpl=ERROR
log4j.logger.org.collectionspace.services.common.security.SecurityInterceptor=TRACE
+log4j.logger.org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl=DEBUG
#log4j.logger.org.collectionspace.services.nuxeo.client.java=ERROR
#log4j.logger.org.collectionspace.services.common.storage.JDBCTools=ERROR
#log4j.logger.org.collectionspace.services.common.profile.CSpaceFilter=ERROR
* @return
* @throws Exception
*/
- private PoxPayloadOut synchronizeItem(
+ @SuppressWarnings("unchecked")
+ private PoxPayloadOut synchronizeItem(
ServiceContext ctx,
String parentIdentifier,
String itemIdentifier,
existingCtx.getUriInfo());
if (existingCtx.getCurrentRepositorySession() != null) {
ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
+
}
result = synchronizeItem(ctx, parentIdentifier, itemIdentifier, syncHierarchicalRelationships);
* @throws Exception
*/
@SuppressWarnings("rawtypes")
- public void deleteAuthorityItem(ServiceContext existingCtx,
+ public boolean deleteAuthorityItem(ServiceContext existingCtx,
String parentIdentifier,
String itemIdentifier,
boolean shouldUpdateRevNumber
) throws Exception {
- Response result = null;
+ boolean result = true;
ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getUriInfo());
if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
}
String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
- DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
- ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, shouldUpdateRevNumber); // Sometimes we can only soft-delete, so if it is during a sync we dont' update the revision number
-
- getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
+ AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler) createDocumentHandler(ctx);
+ handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
+ result = getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
+
+ return result;
}
@GET
ServiceContext parentCtx = new MultipartServiceContextImpl(serviceName);
AuthorityClient client = (AuthorityClient) parentCtx.getClient(CollectionSpaceClient.SAS_CLIENT_PROPERTIES_FILENAME);
- Response res = client.readNamedItemInNamedAuthority(specifier.getParentSpecifier().getURNValue(), specifier.getItemSpecifier().getURNValue(),
+ Response res = client.readItem(specifier.getParentSpecifier().getURNValue(), specifier.getItemSpecifier().getURNValue(),
AuthorityClient.INCLUDE_DELETED_ITEMS, syncHierarchicalRelationships);
try {
import java.util.List;
import java.util.Map;
+import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.collectionspace.services.client.AbstractCommonListUtils;
import org.collectionspace.services.client.XmlTools;
import org.collectionspace.services.client.workflow.WorkflowClient;
import org.collectionspace.services.common.ResourceMap;
+import org.collectionspace.services.common.api.CommonAPI;
import org.collectionspace.services.common.api.RefName;
import org.collectionspace.services.common.api.RefName.Authority;
import org.collectionspace.services.common.api.RefNameUtils;
if (itemsInLocalAuthority.size() > 0) {
ArrayList<String> remainingItems = itemsInLocalAuthority; // now a subset of local items that no longer exist on the SAS, so we need to try to delete them (or mark them as deprecated if they still have records referencing them)
//
- // We now need to either hard-deleted or deprecate the remaining authorities
+ // We now need to either hard-delete or deprecate the remaining authorities
//
- long processed = deleteOrDeprecateItems(ctx, remainingItems);
+ long processed = deleteOrDeprecateItems(ctx, sasAuthoritySpecifier, remainingItems);
if (processed != remainingItems.size()) {
throw new Exception("Encountered unexpected exception trying to delete or deprecated authority items during synchronization.");
}
}
//
- // We need to synchronize the hierarchy relationships
+ // Now that we've sync'd all the items, we need to synchronize the hierarchy relationships
//
- itemList = getItemList(sasPayloadInItemList); // Really need to re-request the sasPayload? I don't think so.
- if (itemList != null) {
- for (Element e:itemList) {
- String remoteRefName = XmlTools.getElementValue(e, "refName");
- itemsInRemoteAuthority.add(remoteRefName);
- long status = syncRemoteItemRelationshipsWithLocalItem(ctx, remoteRefName);
- if (status == 1) {
- created++;
- } else if (status == 0) {
- synched++;
- } else {
- alreadySynched++;
- }
- totalItemsProcessed++;
- }
- }
+ for (String itemShortId:itemsInRemoteAuthority) {
+ long status = syncRemoteItemRelationshipsWithLocalItem(ctx, sasAuthoritySpecifier, itemShortId);
+ if (status == 1) {
+ created++;
+ } else if (status == 0) {
+ synched++;
+ } else {
+ alreadySynched++;
+ }
+ totalItemsProcessed++;
+ }
logger.info(String.format("Total number of items processed during sync: %d", totalItemsProcessed));
logger.info(String.format("Number of items synchronized: %d", synched));
* @return
* @throws Exception
*/
- private long deleteOrDeprecateItems(ServiceContext ctx, ArrayList<String> refNameList) throws Exception {
+ @SuppressWarnings("rawtypes")
+ private long deleteOrDeprecateItems(ServiceContext ctx, Specifier authoritySpecifier, ArrayList<String> itemShortIdList) throws Exception {
long result = 0;
-
+ AuthorityItemSpecifier authorityItemSpecificer = null;
+
ctx.setProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY, false); // Don't update the revision number when we delete or deprecate the item
- for (String itemRefName:refNameList) {
- AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
- AuthorityItemSpecifier authorityItemSpecificer = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authorityTermInfo.inAuthority.name,
- authorityTermInfo.name);
-
+ for (String itemShortId:itemShortIdList) {
AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
try {
+ authorityItemSpecificer = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authoritySpecifier.value,
+ itemShortId);
authorityResource.deleteAuthorityItem(ctx,
- Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name),
- Specifier.createShortIdURNValue(authorityTermInfo.name),
+ authorityItemSpecificer.getParentSpecifier().getURNValue(),
+ authorityItemSpecificer.getItemSpecifier().getURNValue(),
AuthorityServiceUtils.DONT_UPDATE_REV); // Since we're sync'ing, we shouldn't update the revision number (obviously this only applies to soft-deletes since hard-deletes destroy the record)
result++;
} catch (DocumentReferenceException de) {
- logger.info(String.format("Authority item '%s' has existing references and cannot be removed during sync.",
- itemRefName), de);
+ logger.info(String.format("Authority item with '%s' has existing references and cannot be removed during sync.",
+ authorityItemSpecificer), de);
boolean marked = AuthorityServiceUtils.markAuthorityItemAsDeprecated(ctx, authorityItemCommonSchemaName,
authorityItemSpecificer);
if (marked == true) {
result++;
}
} catch (Exception e) {
- logger.warn(String.format("Unable to delete authority item '%s'", itemRefName), e);
+ logger.warn(String.format("Unable to delete authority item '%s'", authorityItemSpecificer), e);
throw e;
}
}
if (logger.isWarnEnabled() == true) {
- if (result != refNameList.size()) {
+ if (result != itemShortIdList.size()) {
logger.warn(String.format("Unable to delete or deprecate some authority items during synchronization with SAS. Deleted or deprecated %d of %d. See the services log file for details.",
- result, refNameList.size()));
+ result, itemShortIdList.size()));
}
}
* @param itemIdentifier - Must be in short-id-refname form -i.e., urn:cspace:name(shortid)
* @throws Exception
*/
- protected void createLocalItem(ServiceContext ctx, String parentIdentifier, String itemIdentifier) throws Exception {
+ protected void createLocalItem(ServiceContext ctx, String parentIdentifier, String itemIdentifier, Boolean syncHierarchicalRelationships) throws Exception {
//
// Create a URN short ID specifier for the getting a copy of the remote authority item
//
// Get the remote payload
//
PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(sasAuthorityItemSpecifier,
- ctx.getServiceName(), getEntityResponseType());
+ ctx.getServiceName(), getEntityResponseType(), syncHierarchicalRelationships);
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
// Document not found, means we need to create an item/term that exists only on the SAS
//
logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
- createLocalItem(ctx, parentIdentifier, itemIdentifier);
+ createLocalItem(ctx, parentIdentifier, itemIdentifier, AuthorityClient.DONT_INCLUDE_RELATIONS);
return 1; // exit with status of 1 means we created a new authority item
}
//
* @return
* @throws Exception
*/
- protected long syncRemoteItemRelationshipsWithLocalItem(ServiceContext ctx, String itemRefName) throws Exception {
+ protected long syncRemoteItemRelationshipsWithLocalItem(ServiceContext ctx, Specifier authoritySpecifier, String itemShortId) throws Exception {
long result = -1;
- //
- // WARNING: THIS CODE IS NOT IMPLEMENTED YET
- //
- if (result == -1) return result;
- //
- // Using the item refname (with no local CSID), create specifiers that we'll use to find the local versions
- //
-
- AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(itemRefName);
- String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
- String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
+ String parentIdentifier = authoritySpecifier.getURNValue();
+ String itemIdentifier = Specifier.createShortIdURNValue(itemShortId);
//
// We'll use the Authority JAX-RS resource to peform sync operations (creates and updates)
//
AuthorityResource authorityResource = (AuthorityResource) ctx.getResource();
PoxPayloadOut localItemPayloadOut;
try {
+ MultivaluedMap queryParams = ctx.getQueryParams();
localItemPayloadOut = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
} catch (DocumentNotFoundException dnf) {
//
// Document not found, means we need to create an item/term that exists only on the SAS
//
- logger.info(String.format("Remote item with refname='%s' doesn't exist locally, so we'll create it.", itemRefName));
- createLocalItem(ctx, parentIdentifier, itemIdentifier);
- return 1; // exit with status of 1 means we created a new authority item
+ logger.info(String.format("Remote item with short ID ='%s' doesn't exist locally, so we can't synchronize its relationships.", itemShortId));
+ return result;
}
//
- // If we get here, we know the item exists both locally and remotely, so we need to synchronize them.
+ // If we get here, we know the item exists both locally and remotely, so we need to synchronize the hierarchy relationships.
//
//
try {
- PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier, true);
+ PoxPayloadOut theUpdate = authorityResource.synchronizeItemWithExistingContext(ctx, parentIdentifier, itemIdentifier, AuthorityClient.INCLUDE_RELATIONS);
if (theUpdate != null) {
result = 0; // means we needed to sync this item with SAS
logger.debug(String.format("Sync'd authority item parent='%s' id='%s with SAS. Updated payload is: \n%s",
import org.collectionspace.services.client.AuthorityClient;
import org.collectionspace.services.client.IQueryManager;
+import org.collectionspace.services.client.PayloadInputPart;
import org.collectionspace.services.client.PoxPayloadIn;
import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.client.RelationClient;
import org.collectionspace.services.client.workflow.WorkflowClient;
import org.collectionspace.services.common.ServiceMain;
import org.collectionspace.services.common.UriTemplateRegistry;
import org.nuxeo.ecm.core.api.ClientException;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.model.PropertyException;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.core.MultivaluedMap;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
}
}
}
-
+
/**
- * This method synchronizes/updates a single authority item resource.
- * for the handleSync method, the wrapDoc argument contains a authority item specifier.
+ *
+ * @param wrapDoc
+ * @return
+ * @throws Exception
*/
+ protected boolean handleRelationsSync(DocumentWrapper<Object> wrapDoc) throws Exception {
+ boolean result = false;
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
+
+ //
+ // Get information about the local authority item so we can compare with corresponding item on the shared authority server
+ //
+ AuthorityItemSpecifier authorityItemSpecifier = (AuthorityItemSpecifier) wrapDoc.getWrappedObject();
+ DocumentModel itemDocModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), getAuthorityItemCommonSchemaName(),
+ authorityItemSpecifier);
+ if (itemDocModel == null) {
+ throw new DocumentNotFoundException(String.format("Could not find authority item resource with CSID='%s'",
+ authorityItemSpecifier.getItemSpecifier().value));
+ }
+ Long localItemRev = (Long) NuxeoUtils.getProperyValue(itemDocModel, AuthorityItemJAXBSchema.REV);
+ Boolean localIsProposed = (Boolean) NuxeoUtils.getProperyValue(itemDocModel, AuthorityItemJAXBSchema.PROPOSED);
+ String localItemCsid = itemDocModel.getName();
+ String localItemWorkflowState = itemDocModel.getCurrentLifeCycleState();
+ String itemShortId = (String) NuxeoUtils.getProperyValue(itemDocModel, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
+
+ //
+ // Now get the item's Authority (the parent) information
+ //
+ DocumentModel authorityDocModel = NuxeoUtils.getDocFromSpecifier(ctx, getRepositorySession(), authorityCommonSchemaName,
+ authorityItemSpecifier.getParentSpecifier());
+ String authorityShortId = (String) NuxeoUtils.getProperyValue(authorityDocModel, AuthorityJAXBSchema.SHORT_IDENTIFIER);
+ String localParentCsid = authorityDocModel.getName();
+ //
+ // Using the short IDs of the local authority and item, create URN specifiers and retrieve the SAS authority item
+ //
+ AuthorityItemSpecifier sasAuthorityItemSpecifier = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authorityShortId, itemShortId);
+ // Get the shared authority server's copy
+ PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(sasAuthorityItemSpecifier,
+ getAuthorityServicePath(), getEntityResponseType(), AuthorityClient.INCLUDE_RELATIONS);
+ Long sasRev = getRevision(sasPayloadIn);
+ String sasWorkflowState = getWorkflowState(sasPayloadIn);
+
+ //
+ // Get the RelationsCommonList and remove the CSIDs since they are for remote items only. We'll use
+ // the refnames in the payload instead to find the local CSIDs
+ //
+ PayloadInputPart relationsCommonListPart = sasPayloadIn.getPart(RelationClient.SERVICE_COMMON_LIST_NAME);
+ relationsCommonListPart.clearElementBody(); // clear the existing DOM element that was created from the incoming XML payload
+ RelationsCommonList rcl = (RelationsCommonList) relationsCommonListPart.getBody(); // Get the JAX-B object and clear the CSID values
+ for (RelationsCommonList.RelationListItem listItem : rcl.getRelationListItem()) {
+ // clear the remote relation item's CSID
+ listItem.setCsid(null);
+ // clear the remote subject's CSID
+ listItem.setSubjectCsid(null);
+ listItem.getSubject().setCsid(null);
+ listItem.getSubject().setUri(null);
+ // clear the remote object's CSID
+ listItem.setObjectCsid(null);
+ listItem.getObject().setCsid(null);
+ listItem.getObject().setUri(null);
+ }
+
+ //
+ // Remove all the payload parts except the relations part since we only want to sync the relationships
+ //
+ ArrayList<PayloadInputPart> newPartList = new ArrayList<PayloadInputPart>();
+ newPartList.add(relationsCommonListPart); // add our CSID filtered RelationsCommonList part
+ sasPayloadIn.setParts(newPartList);
+ sasPayloadIn = new PoxPayloadIn(sasPayloadIn.toXML()); // Builds a new payload using the current set of parts -i.e., just the relations part
+
+ 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(),
+ ctx.getUriInfo(),
+ localParentCsid, // parent's CSID
+ localItemCsid, // item's CSID
+ sasPayloadIn, // the payload from the remote SAS
+ AuthorityServiceUtils.DONT_UPDATE_REV, // don't update the parent's revision number
+ AuthorityServiceUtils.NOT_PROPOSED, // The items is not proposed, make it a real SAS item now
+ AuthorityServiceUtils.SAS_ITEM); // Since we're sync'ing, this must be a SAS item
+ if (payloadOut != null) {
+ ctx.setOutput(payloadOut);
+ result = true;
+ }
+
+ return result;
+ }
+
@Override
public boolean handleSync(DocumentWrapper<Object> wrapDoc) throws Exception {
boolean result = false;
+
+ if (this.getShouldSyncHierarchicalRelationships() == true) {
+ result = handleRelationsSync(wrapDoc);
+ } else {
+ result = handlePayloadSync(wrapDoc);
+ }
+
+ return result;
+ }
+
+ /**
+ *
+ * @param wrapDoc
+ * @return
+ * @throws Exception
+ */
+ protected boolean handlePayloadSync(DocumentWrapper<Object> wrapDoc) throws Exception {
+ boolean result = false;
ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = getServiceContext();
//
AuthorityItemSpecifier sasAuthorityItemSpecifier = new AuthorityItemSpecifier(SpecifierForm.URN_NAME, authorityShortId, itemShortId);
// Get the shared authority server's copy
PoxPayloadIn sasPayloadIn = AuthorityServiceUtils.requestPayloadIn(sasAuthorityItemSpecifier,
- getAuthorityServicePath(), getEntityResponseType());
+ getAuthorityServicePath(), getEntityResponseType(), AuthorityClient.DONT_INCLUDE_RELATIONS);
Long sasRev = getRevision(sasPayloadIn);
String sasWorkflowState = getWorkflowState(sasPayloadIn);
//
}
result = true;
}
- //
- // We need to synchronize the hierarchy relationships here.
- //
return result;
}
//
// If all the refs are to soft-deleted objects, we should soft-delete this authority item instead of hard-deleting it and instead of failing.
//
- Boolean shouldUpdateRev = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
String parentCsid = (String) NuxeoUtils.getProperyValue(docModel, AuthorityItemJAXBSchema.IN_AUTHORITY);
String itemCsid = docModel.getName();
AuthorityResource authorityResource = (AuthorityResource) ctx.getResource(getAuthorityServicePath());
authorityResource.updateItemWorkflowWithTransition(ctx, parentCsid, itemCsid, WorkflowClient.WORKFLOWTRANSITION_DELETE,
- shouldUpdateRev != null ? shouldUpdateRev : true);
- result = false; // Don't delete since we just soft-deleted it.
+ this.getShouldUpdateRevNumber());
+ result = false; // Don't delete since we just soft-deleted it.
}
}
+ //
+ // Since we've changed the state of the parent by deleting (or soft-deleting) one of its items, we might need to update the parent rev number
+ //
+ if (getShouldUpdateRevNumber() == true) {
+ updateRevNumbers(wrapDoc);
+ }
+
return result;
}
public static final Boolean INCLUDE_DELETED_ITEMS = true;
public static final Boolean INCLUDE_RELATIONS = true;
+ public static final Boolean DONT_INCLUDE_RELATIONS = !INCLUDE_RELATIONS;
/*
* Basic CRUD operations
Response readItem(String vcsid, String csid);
//(R)ead Item
- Response readItem(String vcsid, String csid, Boolean includeDeleted);
+ Response readItem(String vcsid, String csid, Boolean includeDeleted);
+
+ //(R)ead Item
+ Response readItem(String authShortId, String itemShortId, Boolean includeDeleted, Boolean includeRelations);
//(U)pdate Item
Response updateItem(String vcsid, String csid, PoxPayloadOut poxPayloadOut);
//(D)elete Item
Response deleteItem(String vcsid, String csid);
+ //(D)elete Item
+ Response deleteNamedItemInNamedAuthority(String authShortId, String itemShortId);
+
+
// Get a list of objects that
Response getReferencingObjects(
String parentcsid,
//(R)ead Item
@Override
public Response readItem(String vcsid, String csid) {
- return getProxy().readItem(vcsid, csid, INCLUDE_DELETE_TRUE);
+ return getProxy().readItem(vcsid, csid, INCLUDE_DELETE_TRUE, INCLUDE_RELATIONS_FALSE);
}
@Override
public Response readItem(String vcsid, String csid, Boolean includeDeleted) {
- return getProxy().readItem(vcsid, csid, includeDeleted.toString());
+ return getProxy().readItem(vcsid, csid, includeDeleted.toString(), INCLUDE_RELATIONS_FALSE);
+ }
+
+ @Override
+ public Response readItem(String vcsid, String csid, Boolean includeDeleted, Boolean includeRelations) {
+ return getProxy().readItem(vcsid, csid, includeDeleted.toString(), includeRelations.toString());
}
//(U)pdate Item
return getProxy().deleteItem(vcsid, csid);
}
+ //(D)elete Item
+ @Override
+ public Response deleteNamedItemInNamedAuthority(String authShortId, String itemShortId) {
+ return getProxy().deleteNamedItemInNamedAuthority(authShortId, itemShortId);
+ }
+
+
@Override
public Response getReferencingObjects( // ClientResponse<AuthorityRefDocList>
String parentcsid,
@Path("/{vcsid}/items/{csid}")
Response readItem(@PathParam("vcsid") String vcsid,
@PathParam("csid") String csid,
- @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState);
+ @QueryParam(WorkflowClient.WORKFLOWSTATE_QUERY) String workflowState,
+ @QueryParam(CommonAPI.showRelations_QP) String showRelations);
+
//(U)pdate Item
@PUT
//(U)pdate Item
@PUT
@Path("/urn:cspace:name({specifier})/items/urn:cspace:name({itemspecifier})")
- Response updateNamedItemInNamedAuthority(@PathParam("specifier")String specifier,
- @PathParam("itemspecifier")String itemspecifier, byte[] xmlPayload);
+ Response updateNamedItemInNamedAuthority(
+ @PathParam("specifier")String specifier,
+ @PathParam("itemspecifier")String itemspecifier,
+ byte[] xmlPayload);
//(D)elete Item
@DELETE
@Path("/{vcsid}/items/{csid}")
Response deleteItem(@PathParam("vcsid") String vcsid, @PathParam("csid") String csid);
+ //(D)elete Item
+ @DELETE
+ @Path("/urn:cspace:name({specifier})/items/urn:cspace:name({itemspecifier})")
+ public Response deleteNamedItemInNamedAuthority(
+ @PathParam("specifier")String specifier,
+ @PathParam("itemspecifier")String itemspecifier);
+
+
/**
* Get a list of objects that reference a given authority term.
*
abstract public String asXML();
+ /**
+ * Clear the root DOM element
+ */
+ public void clearElementBody() {
+ elementBody = null;
+ }
+
public Element asElement() {
Element result = elementBody;
// if we don't already have an Element, let's try to create one from a JAXB object
import javax.xml.transform.stream.StreamSource;
import com.sun.xml.bind.api.impl.NameConverter;
-import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FileUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
parseParts();
}
+ /**
+ * Creates and returns an XML string representation of ourself.
+ *
+ * @return the string
+ */
+ public String toXML() {
+ String result = null;
+ Document document = createDOMFromParts();
+
+ result = document.asXML();
+
+ if (logger.isTraceEnabled() == true) {
+ logger.trace("\n\n<<<< Payload : BEGIN <<<<\n" + result + "\n<<<< Payload : END <<<<\n");
+ }
+
+ return result;
+ }
+
+ protected Document createDOMFromParts() {
+ Document result = null;
+
+ Document document = DocumentHelper.createDocument();
+ document.setXMLEncoding("UTF-8");
+ document.setName(getName());
+ Element root = document.addElement( "document" );
+ root.addAttribute("name", getName());
+
+ Iterator<PT> it = getParts().iterator();
+ while (it.hasNext() == true) {
+ PT outPart = it.next();
+ Element element = outPart.asElement();
+ if (element != null) {
+ root.add(element.detach());
+ } else {
+ //Add if (logger.isTraceEnabled() == true) logger.trace("Output part: " + outPart.getLabel() + " was empty.");
+ }
+ }
+ result = document;
+
+ return result;
+ }
+
/**
* Instantiates a new PoxPayload by parsing the payload into a DOM4j
* Document instance
public List<PT> getParts() {
return parts;
}
+
+ /**
+ * Set a new set of parts.
+ *
+ * @param newParts
+ */
+ public void setParts(ArrayList<PT> newParts) {
+ this.parts = newParts;
+ }
/**
* Adds a POX part to the list of existing parts with the label 'label'.
public PT addPart(PT entity) {
parts.add(entity);
return entity;
- }
+ }
+
+ /**
+ * Removes a POX part from our list of parts
+ * @param entity
+ */
+ public void removePart(PT entity) {
+ parts.remove(entity);
+ }
/**
* Gets the Java package name from the specified namespace. This method
public String asXML() {
return toXML();
}
-
- /**
- * Creates and returns an XML string representation of ourself.
- *
- * @return the string
- */
- public String toXML() {
- String result = null;
- Document document = createDOMFromParts();
-
- result = document.asXML();
-
- if (logger.isTraceEnabled() == true) {
- logger.trace("\n\n<<<< Payload Out : BEGIN <<<<\n" + result + "\n<<<< Payload Out : END <<<<\n");
- }
-
- return result;
- }
-
- private Document createDOMFromParts() {
- Document result = null;
-
- Document document = DocumentHelper.createDocument();
- document.setXMLEncoding("UTF-8");
- document.setName(getName());
- Element root = document.addElement( "document" );
- root.addAttribute("name", getName());
-
- Iterator<PayloadOutputPart> it = getParts().iterator();
- while (it.hasNext() == true) {
- PayloadOutputPart outPart = it.next();
- Element element = outPart.asElement();
- if (element != null) {
- root.add(element.detach());
- } else {
- //Add if (logger.isTraceEnabled() == true) logger.trace("Output part: " + outPart.getLabel() + " was empty.");
- }
- }
- result = document;
- return result;
- }
-
/**
* Gets the DOM object that we created at init time. This should never be null;
*
}
}
+ @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
+ dependsOnMethods = {"updateLocalItemWithSync", "CRUDTests"})
+ public void deleteLocalItemWithSync(String testName) throws Exception {
+ final int itemIndexToDelete = 1;
+ //
+ // First check to see if we support sync.
+ //
+ AuthorityClient client = (AuthorityClient) getClientInstance();
+ if (client.supportsSync() == false) {
+ return; // Exit the test since this authority doesn't support synchronization
+ }
+
+ // Perform test setup for a DELETE.
+ setupDelete();
+ AUTHORITY_ITEM_TYPE theUpdate = null;
+
+ // Delete an item from the SAS server
+ AuthorityClient sasClient = (AuthorityClient) this.getSASClientInstance();
+ Response res = sasClient.deleteNamedItemInNamedAuthority(knownSASAuthorityResourceIdentifier, knownSASItemIdentifiersList.get(itemIndexToDelete));
+ try {
+ Assert.assertEquals(res.getStatus(), testExpectedStatusCode);
+ } finally {
+ res.close();
+ }
+
+ // Synchronize the local item's parent authority and verify the delete we just made
+ // to the SAS takes place locally after the sync -i.e., the local item should be deleted as well.
+ setupSync();
+ AuthorityClient localClient = (AuthorityClient) this.getClientInstance();
+ Response response = localClient.syncByName(knownSASAuthorityResourceIdentifier); // Notice we're using the Short ID (short ID is the same on the local and SAS)
+ try {
+ int statusCode = response.getStatus();
+ Assert.assertTrue(testRequestType.isValidStatusCode(statusCode), invalidStatusCodeMessage(testRequestType, statusCode));
+ Assert.assertEquals(statusCode, testExpectedStatusCode);
+ } finally {
+ response.close();
+ }
+
+ // Verify that the local item has been deleted.
+ setupReadNonExistent();
+ res = localClient.readNamedItemInNamedAuthority(knownSASAuthorityResourceIdentifier, knownSASItemIdentifiersList.get(itemIndexToDelete));
+ try {
+ Assert.assertEquals(res.getStatus(), testExpectedStatusCode);
+ knownSASItemIdentifiersList.remove(0); // remove it from our known set now that we've deleted it
+ } finally {
+ res.close();
+ }
+ }
+
+ /**
+ * We create a new item on the SAS, perform a sync with the local authority, and verify the local authority contains a copy
+ * of the SAS item.
+ */
@Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
dependsOnMethods = {"veryifySyncWithSAS", "CRUDTests"})
public void updateLocalItemWithSync(String testName) throws Exception {
#
# URL of the CollectionSpace server and user credentials
#
-cspace.url=http://qa.collectionspace.org:8180/cspace-services/
+cspace.url=http://localhost:8180/cspace-services/
cspace.ssl=false
cspace.auth=true
-cspace.user=admin@materials.collectionspace.org
+cspace.user=admin@testsci.collectionspace.org
cspace.password=Administrator
#
# default tenant information
#
-cspace.tenant=2000
-cspace.tenantID=materials.collectionspace.org
\ No newline at end of file
+cspace.tenant=2
+cspace.tenantID=testsci.collectionspace.org
\ No newline at end of file
@Deprecated
public Object getInputPart(String label, Class clazz) throws IOException {
return getInputPart(label);
- }
+ }
/* (non-Javadoc)
* @see org.collectionspace.services.common.context.MultipartServiceContext#getInputPart(java.lang.String, java.lang.Class)
* @throws DocumentNotFoundException if entity not found
* @throws DocumentException
*/
- void delete(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException;
+ boolean delete(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException;
/**
* @throws DocumentException
*/
@Override
- public void delete(ServiceContext ctx, String id, DocumentHandler handler)
+ public boolean delete(ServiceContext ctx, String id, DocumentHandler handler)
throws DocumentNotFoundException, DocumentException {
-
+ boolean result = true;
+
if (ctx == null) {
throw new IllegalArgumentException(
"delete : ctx is missing");
JpaStorageUtils.releaseEntityManagerFactory(emf);
}
}
+
+ return result;
}
/**
* @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String)
*/
@Override
- public void delete(ServiceContext ctx, String id, DocumentHandler handler)
+ public boolean delete(ServiceContext ctx, String id, DocumentHandler handler)
throws DocumentNotFoundException, DocumentException {
+ boolean result = true;
+
if (ctx == null) {
throw new IllegalArgumentException(
"delete(ctx, ix, handler): ctx is missing");
throw new IllegalArgumentException(
"delete(ctx, ix, handler): handler is missing");
}
+
EntityManagerFactory emf = null;
EntityManager em = null;
try {
JpaStorageUtils.releaseEntityManagerFactory(emf);
}
}
+
+ return result;
}
/**
public Specifier getItemSpecifier() {
return this.itemSpecifier;
}
+
+ @Override
+ public String toString() {
+ String result = "%s/items/%s";
+
+ try {
+ result = String.format(result, this.parentSpecifier.getURNValue(), this.itemSpecifier.getURNValue());
+ } catch (Exception e) {
+ result = "Unknown error trying to get string representation of Specifier.";
+ logger.error(result, e);
+ }
+
+ return result;
+ }
}
public static class AuthRefConfigInfo {
if (logger.isTraceEnabled()) {
logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " got existing relations.");
}
+ } else {
+ // For debugging purpose only.
+ if (logger.isDebugEnabled()) {
+ String debugMsg = "AuthItemDocHndler.updateRelations for: " + itemCSID + " with an fUpdate value of FALSE.";
+ logger.debug(debugMsg);
+ throw new Exception(debugMsg);
+ }
}
for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
if (logger.isTraceEnabled()) {
logger.trace("AuthItemDocHndler.updateRelations for: " + itemCSID + " done.");
}
- //We return all elements on the inbound list, since we have just worked to make them exist in the system
+ // We return all elements on the inbound list, since we have just worked to make them exist in the system
// and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
return relationsCommonListBody;
}
* @throws DocumentException
*/
@Override
- public void delete(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException,
+ public boolean delete(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException,
DocumentException, TransactionException {
+ boolean result = true;
+
if (ctx == null) {
throw new IllegalArgumentException(
"delete(ctx, ix, handler): ctx is missing");
((DocumentModelHandler) handler).setRepositorySession(repoSession);
if (handler.handle(Action.DELETE, wrapDoc)) {
repoSession.removeDocument(docRef);
+ } else {
+ result = false; // delete failed for some reason
}
} catch (ClientException ce) {
String msg = logException(ce, "Could not find document to delete with CSID=" + id);
releaseRepositorySession(ctx, repoSession);
}
}
+
+ return result;
}
/* (non-Javadoc)
import java.util.regex.Pattern;
+import org.collectionspace.services.relation.RelationsCommonList;
import org.collectionspace.services.vocabulary.VocabularyitemsCommon;
+import org.collectionspace.services.client.RelationClient;
import org.collectionspace.services.common.context.MultipartServiceContext;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.DocumentHandler.Action;
}
try {
- MultipartServiceContext mctx = (MultipartServiceContext) ctx;
- VocabularyitemsCommon vocabItem = (VocabularyitemsCommon) mctx.getInputPart(mctx.getCommonPartLabel(),
- VocabularyitemsCommon.class);
- String msg = "";
+ String errMessage = "";
boolean invalid = false;
+ MultipartServiceContext mctx = (MultipartServiceContext) ctx;
+ VocabularyitemsCommon vocabItem = (VocabularyitemsCommon) mctx.getInputPart(mctx.getCommonPartLabel());
- // Validation occurring on both creates and updates
- String displayName = vocabItem.getDisplayName();
- if ((displayName == null) || (displayName.trim().length() < 2)) {
- invalid = true;
- msg += "displayName must be non-null and contain at least 2 non-whitespace characters";
- }
-
- // Validation specific to creates or updates
- if (action.equals(Action.CREATE)) {
- String shortId = vocabItem.getShortIdentifier();
- // Per CSPACE-2215, shortIdentifier values that are null (missing)
- // oe the empty string are now legally accepted in create payloads.
- // In either of those cases, a short identifier will be synthesized from
- // a display name or supplied in another manner.
- if ((shortId != null) && (shortIdBadPattern.matcher(shortId).find())) {
+ if (vocabItem != null) {
+ // Validation occurring on both creates and updates
+ String displayName = vocabItem.getDisplayName();
+ if (displayName == null || displayName.trim().length() < 2) {
+ invalid = true;
+ errMessage += "displayName must be non-null and contain at least 2 non-whitespace characters";
+ }
+
+ // Validation specific to creates or updates
+ if (action.equals(Action.CREATE)) {
+ String shortId = vocabItem.getShortIdentifier();
+ // Per CSPACE-2215, shortIdentifier values that are null (missing
+ // or the empty string) are now legally accepted in CREATE/POST payloads.
+ // In either of these cases, a short identifier will be synthesized from
+ // a display name or supplied in another manner.
+ if ((shortId != null) && (shortIdBadPattern.matcher(shortId).find())) {
+ invalid = true;
+ errMessage += "shortIdentifier must only contain standard word characters";
+ }
+ } else if (action.equals(Action.UPDATE)) {
+ // What is this ELSE clause for?
+ }
+ } else {
+ RelationsCommonList rcl = (RelationsCommonList) mctx.getInputPart(RelationClient.SERVICE_COMMON_LIST_NAME);
+ if (rcl == null) {
invalid = true;
- msg += "shortIdentifier must only contain standard word characters";
- }
- } else if (action.equals(Action.UPDATE)) {
+ errMessage += "The vocabulary item payload is missing both a common payload and relations part. At lease one of these must exist in the payload.";
+ }
}
-
+
if (invalid) {
- logger.error(msg);
- throw new InvalidDocumentException(msg);
+ logger.error(errMessage);
+ throw new InvalidDocumentException(errMessage);
}
} catch (InvalidDocumentException ide) {
throw ide;