--- /dev/null
+/**
+ * This document is a part of the source code and related artifacts
+ * for CollectionSpace, an open source collections management system
+ * for museums and related institutions:
+
+ * http://www.collectionspace.org
+ * http://wiki.collectionspace.org
+
+ * Copyright 2009 University of California at Berkeley
+
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+
+ * You may obtain a copy of the ECL 2.0 License at
+
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.collectionspace.services.common.vocabulary;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.collectionspace.services.client.IQueryManager;
+import org.collectionspace.services.client.PoxPayloadIn;
+import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.client.workflow.WorkflowClient;
+import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
+import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
+import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler;
+import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;
+import org.collectionspace.services.common.AbstractMultiPartCollectionSpaceResourceImpl;
+import org.collectionspace.services.common.ClientType;
+import org.collectionspace.services.common.ServiceMain;
+import org.collectionspace.services.common.ServiceMessages;
+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.BadRequestException;
+import org.collectionspace.services.common.document.DocumentFilter;
+import org.collectionspace.services.common.document.DocumentHandler;
+import org.collectionspace.services.common.document.DocumentNotFoundException;
+import org.collectionspace.services.common.document.DocumentWrapper;
+import org.collectionspace.services.common.repository.RepositoryClient;
+import org.collectionspace.services.common.security.UnauthorizedException;
+import org.collectionspace.services.common.query.QueryManager;
+import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
+import org.jboss.resteasy.util.HttpResponseCodes;
+import org.nuxeo.ecm.core.api.DocumentModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The Class AuthorityResource.
+ */
+@Consumes("application/xml")
+@Produces("application/xml")
+public abstract class AuthorityResource<AuthCommon, AuthCommonList, AuthItemCommonList, AuthItemHandler> extends
+ AbstractMultiPartCollectionSpaceResourceImpl {
+
+ protected Class<AuthCommon> authCommonClass;
+ protected Class<?> resourceClass;
+ protected String authorityCommonSchemaName;
+ protected String authorityItemCommonSchemaName;
+
+ final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType();
+
+ final static String URN_PREFIX = "urn:cspace:";
+ final static int URN_PREFIX_LEN = URN_PREFIX.length();
+ final static String URN_PREFIX_NAME = "name(";
+ final static int URN_NAME_PREFIX_LEN = URN_PREFIX_LEN + URN_PREFIX_NAME.length();
+ final static String URN_PREFIX_ID = "id(";
+ final static int URN_ID_PREFIX_LEN = URN_PREFIX_LEN + URN_PREFIX_ID.length();
+
+ final Logger logger = LoggerFactory.getLogger(AuthorityResource.class);
+
+ public enum SpecifierForm { CSID, URN_NAME };
+
+ public class Specifier {
+ public SpecifierForm form;
+ public String value;
+ Specifier(SpecifierForm form, String value) {
+ this.form = form;
+ this.value = value;
+ }
+ }
+
+ protected Specifier getSpecifier(String specifierIn, String method, String op) throws WebApplicationException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("getSpecifier called by: "+method+" with specifier: "+specifierIn);
+ }
+ if (specifierIn != null) {
+ if(!specifierIn.startsWith(URN_PREFIX)) {
+ // We'll assume it is a CSID and complain if it does not match
+ return new Specifier(SpecifierForm.CSID, specifierIn);
+ } else {
+ if(specifierIn.startsWith(URN_PREFIX_NAME, URN_PREFIX_LEN)) {
+ int closeParen = specifierIn.indexOf(')', URN_NAME_PREFIX_LEN);
+ if(closeParen>=0) {
+ return new Specifier(SpecifierForm.URN_NAME,
+ specifierIn.substring(URN_NAME_PREFIX_LEN, closeParen));
+ }
+ } else if(specifierIn.startsWith(URN_PREFIX_ID, URN_PREFIX_LEN)) {
+ int closeParen = specifierIn.indexOf(')', URN_ID_PREFIX_LEN);
+ if(closeParen>=0) {
+ return new Specifier(SpecifierForm.CSID,
+ specifierIn.substring(URN_ID_PREFIX_LEN, closeParen));
+ }
+ }
+ }
+ }
+ logger.error(method+": bad or missing specifier!");
+ Response response = Response.status(Response.Status.BAD_REQUEST).entity(
+ op+" failed on bad or missing Authority specifier").type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ }
+
+ /**
+ * Instantiates a new Authority resource.
+ */
+ public AuthorityResource(Class<AuthCommon> authCommonClass, Class<?> resourceClass,
+ String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
+ this.authCommonClass = authCommonClass;
+ this.resourceClass = resourceClass;
+ this.authorityCommonSchemaName = authorityCommonSchemaName;
+ this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
+ }
+
+ public abstract String getItemServiceName();
+
+ /* (non-Javadoc)
+ * @see org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl#getVersionString()
+ */
+ @Override
+ protected String getVersionString() {
+ /** The last change revision. */
+ final String lastChangeRevision = "$LastChangedRevision: 2617 $";
+ return lastChangeRevision;
+ }
+
+ /* (non-Javadoc)
+ * @see org.collectionspace.services.common.CollectionSpaceResource#getCommonPartClass()
+ */
+ @Override
+ public Class<AuthCommon> getCommonPartClass() {
+ return authCommonClass;
+ }
+
+ /**
+ * Creates the item document handler.
+ *
+ * @param ctx the ctx
+ * @param inAuthority the in vocabulary
+ *
+ * @return the document handler
+ *
+ * @throws Exception the exception
+ */
+ public DocumentHandler createItemDocumentHandler(
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
+ String inAuthority)
+ throws Exception {
+ AuthItemHandler docHandler;
+
+ docHandler = (AuthItemHandler)createDocumentHandler(ctx,
+ ctx.getCommonPartLabel(getItemServiceName()),
+ authCommonClass);
+ ((AuthorityItemDocumentModelHandler<?,?>)docHandler).setInAuthority(inAuthority);
+
+ return (DocumentHandler)docHandler;
+ }
+
+ /**
+ * Creates the authority.
+ *
+ * @param input the input
+ *
+ * @return the response
+ */
+ @POST
+ public Response createAuthority(String xmlPayload) {
+ try {
+ PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(input);
+ DocumentHandler handler = createDocumentHandler(ctx);
+ String csid = getRepositoryClient(ctx).create(ctx, handler);
+ UriBuilder path = UriBuilder.fromResource(resourceClass);
+ path.path("" + csid);
+ Response response = Response.created(path.build()).build();
+ return response;
+ } catch (BadRequestException bre) {
+ Response response = Response.status(
+ Response.Status.BAD_REQUEST).entity("Create failed reason " + bre.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Create failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Caught exception in createVocabulary", e);
+ }
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Create failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ }
+
+ protected String buildWhereForAuthByName(String name) {
+ return authorityCommonSchemaName+
+ ":"+AuthorityJAXBSchema.SHORT_IDENTIFIER+
+ "='"+name+"'";
+ }
+
+ protected String buildWhereForAuthItemByName(String name, String parentcsid) {
+ return
+ authorityItemCommonSchemaName+
+ ":"+AuthorityItemJAXBSchema.SHORT_IDENTIFIER+
+ "='"+name+"' AND "
+ + authorityItemCommonSchemaName + ":"
+ + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
+ + "'" + parentcsid + "'";
+ }
+
+ /**
+ * Gets the authority.
+ *
+ * @param specifier either a CSID or one of the urn forms
+ *
+ * @return the authority
+ */
+ @GET
+ @Path("{csid}")
+ public byte[] getAuthority(@PathParam("csid") String specifier) {
+ PoxPayloadOut result = null;
+ try {
+ Specifier spec = getSpecifier(specifier, "getAuthority", "GET");
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
+ DocumentHandler handler = createDocumentHandler(ctx);
+ if(spec.form == SpecifierForm.CSID) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("getAuthority with csid=" + spec.value);
+ }
+ getRepositoryClient(ctx).get(ctx, spec.value, handler);
+ } else {
+ String whereClause = buildWhereForAuthByName(spec.value);
+ DocumentFilter myFilter = new DocumentFilter(whereClause, 0, 1);
+ handler.setDocumentFilter(myFilter);
+ getRepositoryClient(ctx).get(ctx, handler);
+ }
+ result = ctx.getOutput();
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Get failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (DocumentNotFoundException dnfe) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("getAuthority", dnfe);
+ }
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(
+ "Get failed on Authority specifier=" + specifier).type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("getAuthority", e);
+ }
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+
+ if (result == null) {
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(
+ "Get failed, the requested Authority specifier:" + specifier + ": was not found.").type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ }
+
+ return result.getBytes();
+ }
+
+ /**
+ * Finds and populates the authority list.
+ *
+ * @param ui the ui
+ *
+ * @return the authority list
+ */
+ @GET
+ @Produces("application/xml")
+ public AuthCommonList getAuthorityList(@Context UriInfo ui) {
+ try {
+ MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(queryParams);
+ DocumentHandler handler = createDocumentHandler(ctx);
+ DocumentFilter myFilter = handler.getDocumentFilter();
+ String nameQ = queryParams.getFirst("refName");
+ if (nameQ != null) {
+ myFilter.setWhereClause(authorityCommonSchemaName+":refName='" + nameQ + "'");
+ }
+ getRepositoryClient(ctx).getFiltered(ctx, handler);
+ return (AuthCommonList) handler.getCommonPartList();
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Index failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Caught exception in getAuthorityList", e);
+ }
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Index failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ }
+
+ /**
+ * Update authority.
+ *
+ * @param specifier the csid or id
+ * @param theUpdate the the update
+ *
+ * @return the multipart output
+ */
+ @PUT
+ @Path("{csid}")
+ public byte[] updateAuthority(
+ @PathParam("csid") String specifier,
+ String xmlPayload) {
+ PoxPayloadOut result = null;
+ try {
+ PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
+ Specifier spec = getSpecifier(specifier, "updateAuthority", "UPDATE");
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
+ DocumentHandler handler = createDocumentHandler(ctx);
+ String csid;
+ if(spec.form==SpecifierForm.CSID) {
+ csid = spec.value;
+ } else {
+ String whereClause = buildWhereForAuthByName(spec.value);
+ csid = getRepositoryClient(ctx).findDocCSID(ctx, whereClause);
+ }
+ getRepositoryClient(ctx).update(ctx, csid, handler);
+ result = ctx.getOutput();
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Update failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (DocumentNotFoundException dnfe) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("caught exception in updateAuthority", dnfe);
+ }
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(
+ "Update failed on Authority specifier=" + specifier).type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ return result.getBytes();
+ }
+
+ /**
+ * Delete authority.
+ *
+ * @param csid the csid
+ *
+ * @return the response
+ */
+ @DELETE
+ @Path("{csid}")
+ public Response deleteAuthority(@PathParam("csid") String csid) {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("deleteAuthority with csid=" + csid);
+ }
+ if (csid == null || "".equals(csid)) {
+ logger.error("deleteAuthority: missing csid!");
+ Response response = Response.status(Response.Status.BAD_REQUEST).entity(
+ "delete failed on Authority csid=" + csid).type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ try {
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
+ getRepositoryClient(ctx).delete(ctx, csid);
+ return Response.status(HttpResponseCodes.SC_OK).build();
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Delete failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (DocumentNotFoundException dnfe) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("caught exception in deleteAuthority", dnfe);
+ }
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(
+ "Delete failed on Authority csid=" + csid).type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Delete failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+
+ }
+
+ /*************************************************************************
+ * Create an AuthorityItem - this is a sub-resource of Authority
+ * @param specifier either a CSID or one of the urn forms
+ * @param input the payload
+ * @return Authority item response
+ *************************************************************************/
+ @POST
+ @Path("{csid}/items")
+ public Response createAuthorityItem(@PathParam("csid") String specifier, String xmlPayload) {
+ try {
+ PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
+ Specifier spec = getSpecifier(specifier, "createAuthorityItem", "CREATE_ITEM");
+ String parentcsid;
+ if(spec.form==SpecifierForm.CSID) {
+ parentcsid = spec.value;
+ } else {
+ String whereClause = buildWhereForAuthByName(spec.value);
+ ctx = createServiceContext(getServiceName());
+ parentcsid = getRepositoryClient(ctx).findDocCSID(ctx, whereClause);
+ }
+ ctx = createServiceContext(getItemServiceName(), input);
+ DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
+ String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
+ UriBuilder path = UriBuilder.fromResource(resourceClass);
+ path.path(parentcsid + "/items/" + itemcsid);
+ Response response = Response.created(path.build()).build();
+ return response;
+ } catch (BadRequestException bre) {
+ Response response = Response.status(
+ Response.Status.BAD_REQUEST).entity("Create failed reason " + bre.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Create failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Caught exception in createAuthorityItem", e);
+ }
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Create failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ }
+
+ @GET
+ @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
+ public byte[] getItemWorkflow(
+ @PathParam("csid") String csid,
+ @PathParam("itemcsid") String itemcsid) {
+ PoxPayloadOut result = null;
+
+ try {
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
+ String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
+
+ MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
+ WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
+ ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
+ getRepositoryClient(ctx).get(ctx, itemcsid, handler);
+ result = ctx.getOutput();
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
+ }
+
+ return result.getBytes();
+ }
+
+ @PUT
+ @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
+ public byte[] updateWorkflow(
+ @PathParam("csid") String csid,
+ @PathParam("itemcsid") String itemcsid,
+ String xmlPayload) {
+ PoxPayloadOut result = null;
+ try {
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
+ String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
+
+ PoxPayloadIn workflowUpdate = new PoxPayloadIn(xmlPayload);
+ MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, workflowUpdate);
+ 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();
+ }
+
+
+ /**
+ * Gets the authority item.
+ *
+ * @param parentspecifier either a CSID or one of the urn forms
+ * @param itemspecifier either a CSID or one of the urn forms
+ *
+ * @return the authority item
+ */
+ @GET
+ @Path("{csid}/items/{itemcsid}")
+ public byte[] getAuthorityItem(
+ @Context Request request,
+ @Context UriInfo ui,
+ @PathParam("csid") String parentspecifier,
+ @PathParam("itemcsid") String itemspecifier) {
+ PoxPayloadOut result = null;
+ try {
+ JaxRsContext jaxRsContext = new JaxRsContext(request, ui);
+
+ Specifier parentSpec = getSpecifier(parentspecifier, "getAuthorityItem(parent)", "GET_ITEM");
+ Specifier itemSpec = getSpecifier(itemspecifier, "getAuthorityItem(item)", "GET_ITEM");
+ // Note that we have to create the service context for the Items, not the main service
+ RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
+ String parentcsid;
+ if(parentSpec.form==SpecifierForm.CSID) {
+ parentcsid = parentSpec.value;
+ } else {
+ String whereClause = buildWhereForAuthByName(parentSpec.value);
+ ctx = (RemoteServiceContext)createServiceContext(getServiceName());
+ parentcsid = getRepositoryClient(ctx).findDocCSID(ctx, whereClause);
+ }
+ ctx = (RemoteServiceContext)createServiceContext(getItemServiceName());
+ ctx.setJaxRsContext(jaxRsContext);
+ DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
+ if(itemSpec.form==SpecifierForm.CSID) {
+ getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
+ } else {
+ String itemWhereClause =
+ buildWhereForAuthItemByName(itemSpec.value, parentcsid);
+ DocumentFilter myFilter = new DocumentFilter(itemWhereClause, 0, 1);
+ handler.setDocumentFilter(myFilter);
+ getRepositoryClient(ctx).get(ctx, handler);
+ }
+ // TODO should we assert that the item is in the passed vocab?
+ result = ctx.getOutput();
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Get failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (DocumentNotFoundException dnfe) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("getAuthorityItem", dnfe);
+ }
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(
+ "Get failed on AuthorityItem specifier=" + itemspecifier).type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("getAuthorityItem", e);
+ }
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ if (result == null) {
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(
+ "Get failed, the requested AuthorityItem specifier:" + itemspecifier + ": was not found.").type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ return result.getBytes();
+ }
+
+
+ /**
+ * Gets the authorityItem list for the specified authority
+ * If partialPerm is specified, keywords will be ignored.
+ *
+ * @param specifier either a CSID or one of the urn forms
+ * @param partialTerm if non-null, matches partial terms
+ * @param keywords if non-null, matches terms in the keyword index for items
+ * @param ui passed to include additional parameters, like pagination controls
+ *
+ * @return the authorityItem list
+ */
+ @GET
+ @Path("{csid}/items")
+ @Produces("application/xml")
+ public AuthItemCommonList getAuthorityItemList(
+ @PathParam("csid") String specifier,
+ @QueryParam(IQueryManager.SEARCH_TYPE_PARTIALTERM) String partialTerm,
+ @QueryParam(IQueryManager.SEARCH_TYPE_KEYWORDS_KW) String keywords,
+ @Context UriInfo ui) {
+ try {
+ Specifier spec = getSpecifier(specifier, "getAuthorityItemList", "LIST");
+ MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
+ // Note that docType defaults to the ServiceName, so we're fine with that.
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
+ String parentcsid;
+ if(spec.form==SpecifierForm.CSID) {
+ parentcsid = spec.value;
+ } else {
+ String whereClause = buildWhereForAuthByName(spec.value);
+ ctx = createServiceContext(getServiceName());
+ parentcsid = getRepositoryClient(ctx).findDocCSID(ctx, whereClause);
+ }
+ ctx = createServiceContext(getItemServiceName(), queryParams);
+ DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
+ DocumentFilter myFilter = handler.getDocumentFilter();
+ myFilter.setWhereClause(
+ authorityItemCommonSchemaName + ":"
+ + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
+ + "'" + parentcsid + "'");
+
+ // AND vocabularyitems_common:displayName LIKE '%partialTerm%'
+ if (partialTerm != null && !partialTerm.isEmpty()) {
+ String ptClause = QueryManager.createWhereClauseForPartialMatch(
+ authorityItemCommonSchemaName + ":"
+ + AuthorityItemJAXBSchema.DISPLAY_NAME, partialTerm );
+ myFilter.appendWhereClause(ptClause, IQueryManager.SEARCH_QUALIFIER_AND);
+ } else if (keywords != null) {
+ String kwdClause = QueryManager.createWhereClauseFromKeywords(keywords);
+ myFilter.appendWhereClause(kwdClause, IQueryManager.SEARCH_QUALIFIER_AND);
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("getAuthorityItemList filtered WHERE clause: "
+ + myFilter.getWhereClause());
+ }
+ getRepositoryClient(ctx).getFiltered(ctx, handler);
+ return (AuthItemCommonList) handler.getCommonPartList();
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Index failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Caught exception in getAuthorityItemList", e);
+ }
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Index failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ }
+
+ /**
+ * Gets the entities referencing this Authority item instance. The service type
+ * can be passed as a query param "type", and must match a configured type
+ * for the service bindings. If not set, the type defaults to
+ * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
+ *
+ * @param parentspecifier either a CSID or one of the urn forms
+ * @param itemspecifier either a CSID or one of the urn forms
+ * @param ui the ui
+ *
+ * @return the info for the referencing objects
+ */
+ @GET
+ @Path("{csid}/items/{itemcsid}/refObjs")
+ @Produces("application/xml")
+ public AuthorityRefDocList getReferencingObjects(
+ @PathParam("csid") String parentspecifier,
+ @PathParam("itemcsid") String itemspecifier,
+ @Context UriInfo ui) {
+ AuthorityRefDocList authRefDocList = null;
+ try {
+ MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
+ Specifier parentSpec = getSpecifier(parentspecifier,
+ "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS");
+ Specifier itemSpec = getSpecifier(itemspecifier,
+ "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
+ // Note that we have to create the service context for the Items, not the main service
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
+ String parentcsid;
+ if(parentSpec.form==SpecifierForm.CSID) {
+ parentcsid = parentSpec.value;
+ } else {
+ String whereClause = buildWhereForAuthByName(parentSpec.value);
+ ctx = createServiceContext(getServiceName());
+ parentcsid = getRepositoryClient(ctx).findDocCSID(ctx, whereClause);
+ }
+ ctx = createServiceContext(getItemServiceName(), queryParams);
+ String itemcsid;
+ if(itemSpec.form==SpecifierForm.CSID) {
+ itemcsid = itemSpec.value;
+ } else {
+ String itemWhereClause =
+ buildWhereForAuthItemByName(itemSpec.value, parentcsid);
+ itemcsid = getRepositoryClient(ctx).findDocCSID(ctx, itemWhereClause);
+ }
+ // Note that we have to create the service context for the Items, not the main service
+ DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
+ RepositoryClient repoClient = getRepositoryClient(ctx);
+ DocumentFilter myFilter = handler.getDocumentFilter();
+ String serviceType = ServiceBindingUtils.SERVICE_TYPE_PROCEDURE;
+ List<String> list = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
+ if (list != null) {
+ serviceType = list.get(0);
+ }
+ DocumentWrapper<DocumentModel> docWrapper = repoClient.getDoc(ctx, itemcsid);
+ DocumentModel docModel = docWrapper.getWrappedObject();
+ String refName = (String)docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
+
+ authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(ctx,
+ repoClient,
+ serviceType,
+ refName,
+ myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/ );
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Get failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (DocumentNotFoundException dnfe) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("getReferencingObjects", dnfe);
+ }
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(
+ "GetReferencingObjects failed with parentspecifier="
+ + parentspecifier + " and itemspecifier=" + itemspecifier).type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) { // Includes DocumentException
+ if (logger.isDebugEnabled()) {
+ logger.debug("GetReferencingObjects", e);
+ }
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ if (authRefDocList == null) {
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(
+ "Get failed, the requested Item CSID:" + itemspecifier + ": was not found.").type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ return authRefDocList;
+ }
+
+ /**
+ * Gets the authority terms used in the indicated Authority item.
+ *
+ * @param parentspecifier either a CSID or one of the urn forms
+ * @param itemspecifier either a CSID or one of the urn forms
+ * @param ui passed to include additional parameters, like pagination controls
+ *
+ * @return the authority refs for the Authority item.
+ */
+ @GET
+ @Path("{csid}/items/{itemcsid}/authorityrefs")
+ @Produces("application/xml")
+ public AuthorityRefList getAuthorityItemAuthorityRefs(
+ @PathParam("csid") String parentspecifier,
+ @PathParam("itemcsid") String itemspecifier,
+ @Context UriInfo ui) {
+ AuthorityRefList authRefList = null;
+ try {
+ Specifier parentSpec = getSpecifier(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS");
+ Specifier itemSpec = getSpecifier(itemspecifier, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
+ // Note that we have to create the service context for the Items, not the main service
+ MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
+ String parentcsid;
+ if(parentSpec.form==SpecifierForm.CSID) {
+ parentcsid = parentSpec.value;
+ } else {
+ String whereClause = buildWhereForAuthByName(parentSpec.value);
+ ctx = createServiceContext(getServiceName());
+ parentcsid = getRepositoryClient(ctx).findDocCSID(ctx, whereClause);
+ }
+ ctx = createServiceContext(getItemServiceName(), queryParams);
+ RemoteDocumentModelHandlerImpl handler =
+ (RemoteDocumentModelHandlerImpl) createItemDocumentHandler(ctx, parentcsid);
+ String itemcsid;
+ if(itemSpec.form==SpecifierForm.CSID) {
+ itemcsid = itemSpec.value;
+ } else {
+ String itemWhereClause =
+ buildWhereForAuthItemByName(itemSpec.value, parentcsid);
+ itemcsid = getRepositoryClient(ctx).findDocCSID(ctx, itemWhereClause);
+ }
+ DocumentWrapper<DocumentModel> docWrapper =
+ getRepositoryClient(ctx).getDoc(ctx, itemcsid);
+ List<String> authRefFields =
+ ((MultipartServiceContextImpl)ctx).getCommonPartPropertyValues(
+ ServiceBindingUtils.AUTH_REF_PROP, ServiceBindingUtils.QUALIFIED_PROP_NAMES);
+ authRefList = handler.getAuthorityRefs(docWrapper, authRefFields);
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Failed to retrieve authority references: reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Caught exception in getAuthorityRefs", e);
+ }
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Failed to retrieve authority references").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ return authRefList;
+ }
+
+ /**
+ * Update authorityItem.
+ *
+ * @param parentspecifier either a CSID or one of the urn forms
+ * @param itemspecifier either a CSID or one of the urn forms
+ * @param theUpdate the the update
+ *
+ * @return the multipart output
+ */
+ @PUT
+ @Path("{csid}/items/{itemcsid}")
+ public byte[] updateAuthorityItem(
+ @PathParam("csid") String parentspecifier,
+ @PathParam("itemcsid") String itemspecifier,
+ String xmlPayload) {
+ PoxPayloadOut result = null;
+ try {
+ PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
+ Specifier parentSpec = getSpecifier(parentspecifier,
+ "updateAuthorityItem(parent)", "UPDATE_ITEM");
+ Specifier itemSpec = getSpecifier(itemspecifier,
+ "updateAuthorityItem(item)", "UPDATE_ITEM");
+ // Note that we have to create the service context for the Items, not the main service
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
+ String parentcsid;
+ if(parentSpec.form==SpecifierForm.CSID) {
+ parentcsid = parentSpec.value;
+ } else {
+ String whereClause = buildWhereForAuthByName(parentSpec.value);
+ ctx = createServiceContext(getServiceName());
+ parentcsid = getRepositoryClient(ctx).findDocCSID(ctx, whereClause);
+ }
+ ctx = createServiceContext(getItemServiceName(), theUpdate);
+ String itemcsid;
+ if(itemSpec.form==SpecifierForm.CSID) {
+ itemcsid = itemSpec.value;
+ } else {
+ String itemWhereClause =
+ buildWhereForAuthItemByName(itemSpec.value, parentcsid);
+ itemcsid = getRepositoryClient(ctx).findDocCSID(ctx, itemWhereClause);
+ }
+ // Note that we have to create the service context for the Items, not the main service
+ DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid);
+ getRepositoryClient(ctx).update(ctx, itemcsid, handler);
+ result = ctx.getOutput();
+ } catch (BadRequestException bre) {
+ Response response = Response.status(
+ Response.Status.BAD_REQUEST).entity("Create failed reason " + bre.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Update failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (DocumentNotFoundException dnfe) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("caught DNF exception in updateAuthorityItem", dnfe);
+ }
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(
+ "Update failed on AuthorityItem csid=" + itemspecifier).type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ return result.getBytes();
+ }
+
+ /**
+ * Delete authorityItem.
+ *
+ * @param parentcsid the parentcsid
+ * @param itemcsid the itemcsid
+ *
+ * @return the response
+ */
+ @DELETE
+ @Path("{csid}/items/{itemcsid}")
+ public Response deleteAuthorityItem(
+ @PathParam("csid") String parentcsid,
+ @PathParam("itemcsid") String itemcsid) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("deleteAuthorityItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
+ }
+ if (parentcsid == null || "".equals(parentcsid)) {
+ logger.error("deleteVocabularyItem: missing csid!");
+ Response response = Response.status(Response.Status.BAD_REQUEST).entity(
+ "delete failed on AuthorityItem parentcsid=" + parentcsid).type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ if (itemcsid == null || "".equals(itemcsid)) {
+ logger.error("deleteVocabularyItem: missing itemcsid!");
+ Response response = Response.status(Response.Status.BAD_REQUEST).entity(
+ "delete failed on AuthorityItem=" + itemcsid).type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ try {
+ // Note that we have to create the service context for the Items, not the main service
+ ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName());
+ getRepositoryClient(ctx).delete(ctx, itemcsid);
+ return Response.status(HttpResponseCodes.SC_OK).build();
+ } catch (UnauthorizedException ue) {
+ Response response = Response.status(
+ Response.Status.UNAUTHORIZED).entity("Delete failed reason " + ue.getErrorReason()).type("text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (DocumentNotFoundException dnfe) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("caught exception in deleteAuthorityItem", dnfe);
+ }
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(
+ "Delete failed on AuthorityItem itemcsid=" + itemcsid).type(
+ "text/plain").build();
+ throw new WebApplicationException(response);
+ } catch (Exception e) {
+ Response response = Response.status(
+ Response.Status.INTERNAL_SERVER_ERROR).entity("Delete failed").type("text/plain").build();
+ throw new WebApplicationException(response);
+ }
+ }
+
+}
--- /dev/null
+/**\r
+ * This document is a part of the source code and related artifacts\r
+ * for CollectionSpace, an open source collections management system\r
+ * for museums and related institutions:\r
+\r
+ * http://www.collectionspace.org\r
+ * http://wiki.collectionspace.org\r
+\r
+ * Copyright 2009 University of California at Berkeley\r
+\r
+ * Licensed under the Educational Community License (ECL), Version 2.0.\r
+ * You may not use this file except in compliance with this License.\r
+\r
+ * You may obtain a copy of the ECL 2.0 License at\r
+\r
+ * https://source.collectionspace.org/collection-space/LICENSE.txt\r
+\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.collectionspace.services.common.vocabulary;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.nuxeo.ecm.core.api.ClientException;\r
+import org.nuxeo.ecm.core.api.DocumentModel;\r
+import org.nuxeo.ecm.core.api.DocumentModelList;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import org.collectionspace.services.common.ServiceMain;\r
+import org.collectionspace.services.common.context.ServiceContext;\r
+import org.collectionspace.services.common.authorityref.AuthorityRefDocList;\r
+import org.collectionspace.services.common.authorityref.AuthorityRefList;\r
+import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;\r
+import org.collectionspace.services.common.context.ServiceBindingUtils;\r
+import org.collectionspace.services.common.document.DocumentException;\r
+import org.collectionspace.services.common.document.DocumentNotFoundException;\r
+import org.collectionspace.services.common.document.DocumentUtils;\r
+import org.collectionspace.services.common.document.DocumentWrapper;\r
+import org.collectionspace.services.common.repository.RepositoryClient;\r
+import org.collectionspace.services.common.service.ServiceBindingType;\r
+import org.collectionspace.services.jaxb.AbstractCommonList;\r
+import org.collectionspace.services.nuxeo.util.NuxeoUtils;\r
+\r
+/**\r
+ * RefNameServiceUtils is a collection of services utilities related to refName usage.\r
+ *\r
+ * $LastChangedRevision: $\r
+ * $LastChangedDate: $\r
+ */\r
+public class RefNameServiceUtils {\r
+\r
+ private final Logger logger = LoggerFactory.getLogger(RefNameServiceUtils.class);\r
+\r
+ public static AuthorityRefDocList getAuthorityRefDocs(ServiceContext ctx,\r
+ RepositoryClient repoClient,\r
+ String serviceType,\r
+ String refName,\r
+ int pageSize, int pageNum, boolean computeTotal) throws DocumentException, DocumentNotFoundException {\r
+ AuthorityRefDocList wrapperList = new AuthorityRefDocList();\r
+ AbstractCommonList commonList = (AbstractCommonList) wrapperList;\r
+ commonList.setPageNum(pageNum);\r
+ commonList.setPageSize(pageSize);\r
+\r
+ \r
+ List<AuthorityRefDocList.AuthorityRefDocItem> list =\r
+ wrapperList.getAuthorityRefDocItem();\r
+ TenantBindingConfigReaderImpl tReader =\r
+ ServiceMain.getInstance().getTenantBindingConfigReader();\r
+ List<ServiceBindingType> servicebindings = tReader.getServiceBindingsByType(ctx.getTenantId(), serviceType);\r
+ if (servicebindings == null || servicebindings.isEmpty()) {\r
+ return null;\r
+ }\r
+ // Need to escape the quotes in the refName\r
+ // TODO What if they are already escaped?\r
+ String escapedRefName = refName.replaceAll("'", "\\\\'");\r
+// String domain = \r
+// tReader.getTenantBinding(ctx.getTenantId()).getRepositoryDomain();\r
+ ArrayList<String> docTypes = new ArrayList<String>();\r
+ Map<String, ServiceBindingType> queriedServiceBindings = new HashMap<String, ServiceBindingType>();\r
+ Map<String, Map<String, String>> authRefFieldsByService = new HashMap<String, Map<String, String>>();\r
+ StringBuilder whereClause = new StringBuilder();\r
+ boolean fFirst = true;\r
+ List<String> authRefFieldPaths = new ArrayList<String>();\r
+ for (ServiceBindingType sb : servicebindings) {\r
+ // Gets the property names for each part, qualified with the part label (which\r
+ // is also the table name, the way that the repository works).\r
+ authRefFieldPaths =\r
+ ServiceBindingUtils.getAllPartsPropertyValues(sb,\r
+ ServiceBindingUtils.AUTH_REF_PROP, ServiceBindingUtils.QUALIFIED_PROP_NAMES);\r
+ if (authRefFieldPaths.isEmpty()) {\r
+ continue;\r
+ }\r
+ String authRefPath = "";\r
+ String ancestorAuthRefFieldName = "";\r
+ Map<String, String> authRefFields = new HashMap<String, String>();\r
+ for (int i = 0; i < authRefFieldPaths.size(); i++) {\r
+ // fieldName = DocumentUtils.getDescendantOrAncestor(authRefFields.get(i));\r
+ // For simple field values, we just search on the item.\r
+ // For simple repeating scalars, we just search the group field \r
+ // For repeating complex types, we will need to do more.\r
+ authRefPath = authRefFieldPaths.get(i);\r
+ ancestorAuthRefFieldName = DocumentUtils.getAncestorAuthRefFieldName(authRefFieldPaths.get(i));\r
+ authRefFields.put(authRefPath, ancestorAuthRefFieldName);\r
+ }\r
+\r
+ String docType = sb.getObject().getName();\r
+ queriedServiceBindings.put(docType, sb);\r
+ authRefFieldsByService.put(docType, authRefFields);\r
+ docTypes.add(docType);\r
+ Collection<String> fields = authRefFields.values();\r
+ for (String field : fields) {\r
+ // Build up the where clause for each authRef field\r
+ if (fFirst) {\r
+ fFirst = false;\r
+ } else {\r
+ whereClause.append(" OR ");\r
+ }\r
+ //whereClause.append(prefix);\r
+ whereClause.append(field);\r
+ whereClause.append("='");\r
+ whereClause.append(escapedRefName);\r
+ whereClause.append("'");\r
+ }\r
+ }\r
+ String whereClauseStr = whereClause.toString(); // for debugging\r
+ if (fFirst) // found no authRef fields - nothing to query\r
+ {\r
+ return wrapperList;\r
+ }\r
+ String fullQuery = whereClause.toString(); // for debug\r
+ // Now we have to issue the search\r
+ DocumentWrapper<DocumentModelList> docListWrapper = repoClient.findDocs(ctx,\r
+ docTypes, whereClause.toString(), pageSize, pageNum, computeTotal);\r
+ // Now we gather the info for each document into the list and return\r
+ DocumentModelList docList = docListWrapper.getWrappedObject();\r
+ // Set num of items in list. this is useful to our testing framework.\r
+ commonList.setItemsInPage(docList.size());\r
+ // set the total result size\r
+ commonList.setTotalItems(docList.totalSize());\r
+ Iterator<DocumentModel> iter = docList.iterator();\r
+ while (iter.hasNext()) {\r
+ DocumentModel docModel = iter.next();\r
+ AuthorityRefDocList.AuthorityRefDocItem ilistItem = new AuthorityRefDocList.AuthorityRefDocItem();\r
+ String csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());\r
+ String docType = docModel.getDocumentType().getName();\r
+ ServiceBindingType sb = queriedServiceBindings.get(docType);\r
+ if (sb == null) {\r
+ throw new RuntimeException(\r
+ "getAuthorityRefDocs: No Service Binding for docType: " + docType);\r
+ }\r
+ String serviceContextPath = "/" + sb.getName().toLowerCase() + "/";\r
+ // The id and URI are the same on all doctypes\r
+ ilistItem.setDocId(csid);\r
+ ilistItem.setUri(serviceContextPath + csid);\r
+ ilistItem.setDocType(docType);\r
+ ilistItem.setDocNumber(\r
+ ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NUMBER_PROP, docModel));\r
+ ilistItem.setDocName(\r
+ ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NAME_PROP, docModel));\r
+ // Now, we have to loop over the authRefFieldsByService to figure\r
+ // out which field matched this. Ignore multiple matches.\r
+ Map<String,String> matchingAuthRefFields = authRefFieldsByService.get(docType);\r
+ if (matchingAuthRefFields == null || matchingAuthRefFields.isEmpty()) {\r
+ throw new RuntimeException(\r
+ "getAuthorityRefDocs: internal logic error: can't fetch authRefFields for DocType.");\r
+ }\r
+ String authRefAncestorField = "";\r
+ String authRefDescendantField = "";\r
+ String sourceField = "";\r
+ boolean fRefFound = false;\r
+ // Use this if we go to qualified field names\r
+ for (String path : matchingAuthRefFields.keySet()) {\r
+ try {\r
+ // This is the field name we show in the return info\r
+ authRefAncestorField = (String) matchingAuthRefFields.get(path);\r
+ // This is the qualified field we have to get from the doc model\r
+ authRefDescendantField = DocumentUtils.getDescendantOrAncestor(path);\r
+ // The ancestor field is part-schema (tablename) qualified\r
+ String[] strings = authRefAncestorField.split(":");\r
+ if (strings.length != 2) {\r
+ throw new RuntimeException(\r
+ "getAuthorityRefDocs: Bad configuration of path to authority reference field.");\r
+ }\r
+ // strings[0] holds a schema name, such as "intakes_common"\r
+ //\r
+ // strings[1] holds:\r
+ // * The name of an authority reference field, such as "depositor";\r
+ // or\r
+ // * The name of an ancestor (e.g. parent, grandparent ...) field,\r
+ // such as "fieldCollectors", of a repeatable authority reference\r
+ // field, such as "fieldCollector".\r
+ // TODO - if the value is not simple, or repeating scalar, need a more\r
+ // sophisticated fetch. \r
+ Object fieldValue = docModel.getProperty(strings[0], strings[1]);\r
+ // We cannot be sure why we have this doc, so look for matches\r
+ boolean fRefMatches = refNameFoundInField(refName, fieldValue);\r
+ if (fRefMatches) {\r
+ sourceField = authRefDescendantField;\r
+ // Handle multiple fields matching in one Doc. See CSPACE-2863.\r
+ if(fRefFound) {\r
+ // We already added ilistItem, so we need to clone that and add again\r
+ ilistItem = cloneAuthRefDocItem(ilistItem, sourceField);\r
+ } else {\r
+ ilistItem.setSourceField(sourceField);\r
+ fRefFound = true;\r
+ }\r
+ list.add(ilistItem);\r
+ }\r
+\r
+ } catch (ClientException ce) {\r
+ throw new RuntimeException(\r
+ "getAuthorityRefDocs: Problem fetching: " + sourceField, ce);\r
+ }\r
+ }\r
+ if (!fRefFound) {\r
+ throw new RuntimeException(\r
+ "getAuthorityRefDocs: Could not find refname in object:"\r
+ + docType + ":" + csid);\r
+ }\r
+ }\r
+ return wrapperList;\r
+ }\r
+ \r
+ private static AuthorityRefDocList.AuthorityRefDocItem cloneAuthRefDocItem(\r
+ AuthorityRefDocList.AuthorityRefDocItem ilistItem, String sourceField) {\r
+ AuthorityRefDocList.AuthorityRefDocItem newlistItem = new AuthorityRefDocList.AuthorityRefDocItem();\r
+ newlistItem.setDocId(ilistItem.getDocId());\r
+ newlistItem.setDocName(ilistItem.getDocName());\r
+ newlistItem.setDocNumber(ilistItem.getDocNumber());\r
+ newlistItem.setDocType(ilistItem.getDocType());\r
+ newlistItem.setUri(ilistItem.getUri());\r
+ newlistItem.setSourceField(sourceField);\r
+ return newlistItem;\r
+ }\r
+\r
+ /*\r
+ * Identifies whether the refName was found in the supplied field.\r
+ *\r
+ * Only works for:\r
+ * * Scalar fields\r
+ * * Repeatable scalar fields (aka multi-valued fields)\r
+ *\r
+ * Does not work for:\r
+ * * Structured fields (complexTypes)\r
+ * * Repeatable structured fields (repeatable complexTypes)\r
+ */\r
+ private static boolean refNameFoundInField(String refName, Object fieldValue) {\r
+\r
+ boolean result = false;\r
+ if (fieldValue instanceof List) {\r
+ List<String> fieldValueList = (List) fieldValue;\r
+ for (String listItemValue : fieldValueList) {\r
+ if (refName.equalsIgnoreCase(listItemValue)) {\r
+ result = true;\r
+ break;\r
+ }\r
+\r
+ }\r
+ } else if (fieldValue instanceof String){\r
+ if (refName.equalsIgnoreCase((String)fieldValue)) {\r
+ result = true;\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+}\r
+\r
--- /dev/null
+/**\r
+ * This document is a part of the source code and related artifacts\r
+ * for CollectionSpace, an open source collections management system\r
+ * for museums and related institutions:\r
+\r
+ * http://www.collectionspace.org\r
+ * http://wiki.collectionspace.org\r
+\r
+ * Copyright 2009 University of California at Berkeley\r
+\r
+ * Licensed under the Educational Community License (ECL), Version 2.0.\r
+ * You may not use this file except in compliance with this License.\r
+\r
+ * You may obtain a copy of the ECL 2.0 License at\r
+\r
+ * https://source.collectionspace.org/collection-space/LICENSE.txt\r
+\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.collectionspace.services.common.vocabulary;\r
+\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+/**\r
+ * RefNameUtils is a collection of utilities related to refName URN strings\r
+ * refNames are URNs that reference a document entity, often an authority or \r
+ * authority term. They are strings that take the form (for authorities):\r
+ * urn:cspace:org.collectionspace.demo:vocabulary:name(Entry Methods)'Entry Methods'\r
+ * or the form (for authority terms):\r
+ * urn:cspace:org.collectionspace.demo:vocabulary:name(Entry Methods):item:name(Loan)'Loan'\r
+ *\r
+ * $LastChangedRevision: $\r
+ * $LastChangedDate: $\r
+ */\r
+public class RefNameUtils {\r
+\r
+ private final Logger logger = LoggerFactory.getLogger(RefNameUtils.class);\r
+\r
+ public static final String URN_PREFIX = "urn:cspace:";\r
+ public static final int URN_PREFIX_LEN = 11;\r
+ public static final String URN_NAME_PREFIX = "urn:cspace:name(";\r
+ public static final int URN_NAME_PREFIX_LEN = 16;\r
+ // FIXME Should not be hard-coded\r
+ private static final String ITEMS_REGEX = "item|person|organization";\r
+ // In a list of tokens, these are indices for each part\r
+ private static final int DOMAIN_TOKEN = 0; // e.g., 'org.collectionspace.demo'\r
+ private static final int RESOURCE_TOKEN = 1; // vocabulary, personauthority, etc.\r
+ private static final int AUTH_INSTANCE_TOKEN = 2; // name(Entry Methods)'Entry Methods'\r
+ private static final int ITEMS_TOKEN = 3; // 'item', 'person', etc.\r
+ private static final int ITEM_INSTANCE_TOKEN = 4; // name(Entry Methods)'Entry Methods'\r
+ // Tokenizing the INSTANCE, these are indices for each item-part\r
+ private static final int INSTANCE_SPEC_TYPE_TOKEN = 0; // 'name' or 'id' \r
+ private static final int INSTANCE_SPEC_TOKEN = 1; // name or id value\r
+ private static final int INSTANCE_DISPLAYNAME_TOKEN = 2;// optional displayName suffix\r
+ private static final int INSTANCE_TOKENS_MIN = 2;\r
+ private static final int INSTANCE_TOKENS_MAX = 3;\r
+ public static final String SEPARATOR = ":";\r
+\r
+ public static class AuthorityInfo {\r
+ private final Logger logger = LoggerFactory.getLogger(AuthorityInfo.class);\r
+ private static int MIN_TOKENS = 3;\r
+ public String domain;\r
+ public String resource;\r
+ public String csid;\r
+ public String name;\r
+ public String displayName;\r
+ \r
+ public AuthorityInfo(String refNameTokens[]) throws Exception {\r
+ try {\r
+ if(refNameTokens.length < MIN_TOKENS) {\r
+ throw new IllegalArgumentException("Malformed refName for Authority (too few tokens)");\r
+ }\r
+ this.domain = refNameTokens[DOMAIN_TOKEN]; \r
+ this.resource = refNameTokens[RESOURCE_TOKEN];\r
+ String idTokens[] = refNameTokens[AUTH_INSTANCE_TOKEN].split("[()]", INSTANCE_TOKENS_MAX);\r
+ if(idTokens.length<INSTANCE_TOKENS_MIN) {\r
+ throw new IllegalArgumentException("Missing/malformed identifier");\r
+ }\r
+ if(idTokens[INSTANCE_SPEC_TYPE_TOKEN].equals("name")) {\r
+ this.name = idTokens[INSTANCE_SPEC_TOKEN];\r
+ this.csid = null;\r
+ } else if(idTokens[INSTANCE_SPEC_TYPE_TOKEN].startsWith("id")) {\r
+ this.csid = idTokens[INSTANCE_SPEC_TOKEN];\r
+ this.name = null;\r
+ } else {\r
+ throw new IllegalArgumentException("Identifier type must be 'name' or 'id'");\r
+ }\r
+ // displayName is always in quotes, so must have at least 3 chars\r
+ this.displayName = \r
+ ((idTokens.length<INSTANCE_TOKENS_MAX)||(idTokens[INSTANCE_DISPLAYNAME_TOKEN].length()<3))? null:\r
+ idTokens[INSTANCE_DISPLAYNAME_TOKEN].substring(1, idTokens[INSTANCE_DISPLAYNAME_TOKEN].length()-1);\r
+ } catch (Exception e) {\r
+ if (logger.isDebugEnabled()) {\r
+ logger.debug("Problem Building AuthorityInfo from tokens: " \r
+ + RefNameUtils.implodeStringArray(refNameTokens, ", "));\r
+ }\r
+ throw e;\r
+ }\r
+ }\r
+ \r
+ public String getRelativeUri() {\r
+ StringBuilder uri = new StringBuilder();\r
+ // FIXME This should not be hard-coded.\r
+ if(resource.equals("vocabulary")) {\r
+ uri.append("/vocabularies/");\r
+ } else if(resource.equals("personauthority")) {\r
+ uri.append("/personauthorities/");\r
+ } else if(resource.equals("orgauthority")) {\r
+ uri.append("/orgauthorities/");\r
+ } else {\r
+ throw new RuntimeException("Illegal Authority Type: " + resource);\r
+ }\r
+ if(csid!=null) {\r
+ uri.append(csid);\r
+ } else if(name!=null) {\r
+ uri.append("urn:cspace:name("+name+")");\r
+ } else {\r
+ throw new RuntimeException("Missing id/name specifier");\r
+ }\r
+ return uri.toString();\r
+ }\r
+ };\r
+\r
+ public static class AuthorityTermInfo {\r
+ private final Logger logger = LoggerFactory.getLogger(AuthorityTermInfo.class);\r
+ private static int MIN_TOKENS = 5;\r
+ public AuthorityInfo inAuthority;\r
+ public String csid;\r
+ public String name;\r
+ public String displayName;\r
+ \r
+ public AuthorityTermInfo(String refNameTokens[]) throws Exception {\r
+ try {\r
+ if(refNameTokens.length < MIN_TOKENS) {\r
+ throw new IllegalArgumentException("Malformed refName for AuthorityTerm (too few tokens)");\r
+ }\r
+ this.inAuthority = new AuthorityInfo(refNameTokens); \r
+ if(!refNameTokens[ITEMS_TOKEN].matches(ITEMS_REGEX)) {\r
+ throw new IllegalArgumentException("Item spec must be one of: "+ITEMS_REGEX);\r
+ }\r
+ String idTokens[] = refNameTokens[ITEM_INSTANCE_TOKEN].split("[\\(\\)]", 3);\r
+ if(idTokens.length<INSTANCE_TOKENS_MIN) {\r
+ throw new IllegalArgumentException("Missing/malformed identifier");\r
+ }\r
+ if(idTokens[INSTANCE_SPEC_TYPE_TOKEN].equals("name")) {\r
+ this.name = idTokens[INSTANCE_SPEC_TOKEN];\r
+ this.csid = null;\r
+ } else if(idTokens[INSTANCE_SPEC_TYPE_TOKEN].startsWith("id")) {\r
+ this.csid = idTokens[INSTANCE_SPEC_TOKEN];\r
+ this.name = null;\r
+ } else {\r
+ throw new IllegalArgumentException("Identifier type must be 'name' or 'id'");\r
+ }\r
+ // displayName is always in quotes, so must have at least 3 chars\r
+ this.displayName = \r
+ ((idTokens.length<INSTANCE_TOKENS_MAX)||(idTokens[INSTANCE_DISPLAYNAME_TOKEN].length()<3))? null:\r
+ idTokens[INSTANCE_DISPLAYNAME_TOKEN].substring(1, idTokens[INSTANCE_DISPLAYNAME_TOKEN].length()-1);\r
+ } catch (Exception e) {\r
+ if (logger.isDebugEnabled()) {\r
+ logger.debug("Problem Building AuthorityTermInfo from tokens: " \r
+ + RefNameUtils.implodeStringArray(refNameTokens, ", "));\r
+ }\r
+ throw e;\r
+ }\r
+ }\r
+ \r
+ public String getRelativeUri() {\r
+ StringBuilder uri = new StringBuilder(inAuthority.getRelativeUri()+"/items/");\r
+ if(csid!=null) {\r
+ uri.append(csid);\r
+ } else if(name!=null) {\r
+ uri.append("urn:cspace:name("+name+")");\r
+ } else {\r
+ throw new RuntimeException("Missing id/name specifier");\r
+ }\r
+ return uri.toString();\r
+ }\r
+ };\r
+\r
+ public static AuthorityInfo parseAuthorityInfo(String refName)\r
+ throws Exception {\r
+ if(refName==null || !refName.startsWith(URN_PREFIX))\r
+ throw new RuntimeException( "Null or invalid refName syntax");\r
+ return new AuthorityInfo(refName.substring(URN_PREFIX_LEN).split(SEPARATOR));\r
+ }\r
+\r
+ public static AuthorityTermInfo parseAuthorityTermInfo(String refName)\r
+ throws Exception {\r
+ if(refName==null || !refName.startsWith(URN_PREFIX))\r
+ throw new RuntimeException( "Null or invalid refName syntax");\r
+ return new AuthorityTermInfo(refName.substring(URN_PREFIX_LEN).split(SEPARATOR));\r
+ }\r
+\r
+ public static String implodeStringArray(String tokens[], String separator) {\r
+ if (tokens.length==0) {\r
+ return "";\r
+ } else {\r
+ StringBuffer sb = new StringBuffer();\r
+ sb.append(tokens[0]);\r
+ for (int i=1;i<tokens.length;i++) {\r
+ sb.append(separator);\r
+ sb.append(tokens[i]);\r
+ }\r
+ return sb.toString();\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Returns the name / shortIdentifier value of an authority item in a refName\r
+ */\r
+ public static String getItemShortId(String refName) {\r
+ String name = "";\r
+ try {\r
+ String [] refNameTokens = refName.substring(URN_PREFIX_LEN).split(SEPARATOR);\r
+ AuthorityTermInfo authTermInfo = new AuthorityTermInfo(refNameTokens);\r
+ name = authTermInfo.name;\r
+ } catch(Exception e) {\r
+ // do nothing\r
+ }\r
+ return name;\r
+ }\r
+\r
+ /**\r
+ * Creates a refName in the name / shortIdentifier form.\r
+ *\r
+ * @param shortId a shortIdentifier for an authority or one of its terms\r
+ * @return a refName for that authority or term, in the name / shortIdentifier form.\r
+ * If the provided shortIdentifier is null or empty, returns\r
+ * the empty string.\r
+ */\r
+ public static String createShortIdRefName(String shortId) {\r
+ if (shortId == null || shortId.trim().isEmpty()) {\r
+ return "";\r
+ } else {\r
+ return "urn:cspace:name("+shortId+")";\r
+ }\r
+ }\r
+ \r
+}\r
+\r