From: Richard Millet Date: Fri, 8 Apr 2011 20:12:38 +0000 (+0000) Subject: CSPACE-3779: Adding new authority module. X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=ed4151bccc2101861d0be5604058ec631fa45da7;p=tmp%2Fjakarta-migration.git CSPACE-3779: Adding new authority module. --- diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityItemJAXBSchema.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityItemJAXBSchema.java new file mode 100644 index 000000000..b6be3b3bf --- /dev/null +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityItemJAXBSchema.java @@ -0,0 +1,42 @@ +/** + * 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; + +/** + * @author pschmitz + * + */ +public interface AuthorityItemJAXBSchema { + final static String DISPLAY_NAME = "displayName"; + final static String DISPLAY_NAME_COMPUTED = "displayNameComputed"; + final static String SHORT_DISPLAY_NAME = "shortDisplayName"; + final static String SHORT_DISPLAY_NAME_COMPUTED = "shortDisplayNameComputed"; + final static String IN_AUTHORITY = "inAuthority"; + final static String REF_NAME = "refName"; + final static String SHORT_IDENTIFIER = "shortIdentifier"; + final static String TERM_STATUS = "termStatus"; + final static String CSID = "csid"; +} + + diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityItemListItemJAXBSchema.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityItemListItemJAXBSchema.java new file mode 100644 index 000000000..b5d2f0d81 --- /dev/null +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityItemListItemJAXBSchema.java @@ -0,0 +1,33 @@ +/** + * 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; + +public interface AuthorityItemListItemJAXBSchema { + final static String DISPLAY_NAME = "displayName"; + final static String SHORT_DISPLAY_NAME = "shortDisplayName"; + final static String REF_NAME = "refName"; + final static String SHORT_IDENTIFIER = "shortIdentifier"; + final static String CSID = "csid"; + final static String URI = "url"; +} diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityJAXBSchema.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityJAXBSchema.java new file mode 100644 index 000000000..456ea65e0 --- /dev/null +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityJAXBSchema.java @@ -0,0 +1,38 @@ +/** + * 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; + +/** + * @author pschmitz + * + */ +public interface AuthorityJAXBSchema { + final static String DISPLAY_NAME = "displayName"; + final static String SHORT_IDENTIFIER = "shortIdentifier"; + final static String REF_NAME = "refName"; + final static String VOCAB_TYPE = "vocabType"; + final static String CSID = "csid"; +} + + diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityListItemJAXBSchema.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityListItemJAXBSchema.java new file mode 100644 index 000000000..b02c59a34 --- /dev/null +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityListItemJAXBSchema.java @@ -0,0 +1,33 @@ +/** + * 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; + +public interface AuthorityListItemJAXBSchema { + final static String DISPLAY_NAME = "displayName"; + final static String REF_NAME = "refName"; + final static String SHORT_IDENTIFIER = "shortIdentifier"; + final static String VOCAB_TYPE = "vocabType"; + final static String CSID = "csid"; + final static String URI = "url"; +} diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java new file mode 100644 index 000000000..a5fce2fe3 --- /dev/null +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java @@ -0,0 +1,956 @@ +/** + * 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 extends + AbstractMultiPartCollectionSpaceResourceImpl { + + protected Class 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 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 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 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 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 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 queryParams = ui.getQueryParameters(); + ServiceContext 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 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 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 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 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 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 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 queryParams = ui.getQueryParameters(); + // Note that docType defaults to the ServiceName, so we're fine with that. + ServiceContext 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 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 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 list = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP); + if (list != null) { + serviceType = list.get(0); + } + DocumentWrapper 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 queryParams = ui.getQueryParameters(); + ServiceContext 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 docWrapper = + getRepositoryClient(ctx).getDoc(ctx, itemcsid); + List 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 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 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); + } + } + +} diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/IVocabManager.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/IVocabManager.java new file mode 100644 index 000000000..c39206bba --- /dev/null +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/IVocabManager.java @@ -0,0 +1,7 @@ +package org.collectionspace.services.common.vocabulary; + +public interface IVocabManager { + + public void exampleMethod(String someParam); + +} diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/RefNameServiceUtils.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/RefNameServiceUtils.java new file mode 100644 index 000000000..004785164 --- /dev/null +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/RefNameServiceUtils.java @@ -0,0 +1,277 @@ +/** + * 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.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.nuxeo.ecm.core.api.ClientException; +import org.nuxeo.ecm.core.api.DocumentModel; +import org.nuxeo.ecm.core.api.DocumentModelList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.context.ServiceContext; +import org.collectionspace.services.common.authorityref.AuthorityRefDocList; +import org.collectionspace.services.common.authorityref.AuthorityRefList; +import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; +import org.collectionspace.services.common.context.ServiceBindingUtils; +import org.collectionspace.services.common.document.DocumentException; +import org.collectionspace.services.common.document.DocumentNotFoundException; +import org.collectionspace.services.common.document.DocumentUtils; +import org.collectionspace.services.common.document.DocumentWrapper; +import org.collectionspace.services.common.repository.RepositoryClient; +import org.collectionspace.services.common.service.ServiceBindingType; +import org.collectionspace.services.jaxb.AbstractCommonList; +import org.collectionspace.services.nuxeo.util.NuxeoUtils; + +/** + * RefNameServiceUtils is a collection of services utilities related to refName usage. + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class RefNameServiceUtils { + + private final Logger logger = LoggerFactory.getLogger(RefNameServiceUtils.class); + + public static AuthorityRefDocList getAuthorityRefDocs(ServiceContext ctx, + RepositoryClient repoClient, + String serviceType, + String refName, + int pageSize, int pageNum, boolean computeTotal) throws DocumentException, DocumentNotFoundException { + AuthorityRefDocList wrapperList = new AuthorityRefDocList(); + AbstractCommonList commonList = (AbstractCommonList) wrapperList; + commonList.setPageNum(pageNum); + commonList.setPageSize(pageSize); + + + List list = + wrapperList.getAuthorityRefDocItem(); + TenantBindingConfigReaderImpl tReader = + ServiceMain.getInstance().getTenantBindingConfigReader(); + List servicebindings = tReader.getServiceBindingsByType(ctx.getTenantId(), serviceType); + if (servicebindings == null || servicebindings.isEmpty()) { + return null; + } + // Need to escape the quotes in the refName + // TODO What if they are already escaped? + String escapedRefName = refName.replaceAll("'", "\\\\'"); +// String domain = +// tReader.getTenantBinding(ctx.getTenantId()).getRepositoryDomain(); + ArrayList docTypes = new ArrayList(); + Map queriedServiceBindings = new HashMap(); + Map> authRefFieldsByService = new HashMap>(); + StringBuilder whereClause = new StringBuilder(); + boolean fFirst = true; + List authRefFieldPaths = new ArrayList(); + for (ServiceBindingType sb : servicebindings) { + // Gets the property names for each part, qualified with the part label (which + // is also the table name, the way that the repository works). + authRefFieldPaths = + ServiceBindingUtils.getAllPartsPropertyValues(sb, + ServiceBindingUtils.AUTH_REF_PROP, ServiceBindingUtils.QUALIFIED_PROP_NAMES); + if (authRefFieldPaths.isEmpty()) { + continue; + } + String authRefPath = ""; + String ancestorAuthRefFieldName = ""; + Map authRefFields = new HashMap(); + for (int i = 0; i < authRefFieldPaths.size(); i++) { + // fieldName = DocumentUtils.getDescendantOrAncestor(authRefFields.get(i)); + // For simple field values, we just search on the item. + // For simple repeating scalars, we just search the group field + // For repeating complex types, we will need to do more. + authRefPath = authRefFieldPaths.get(i); + ancestorAuthRefFieldName = DocumentUtils.getAncestorAuthRefFieldName(authRefFieldPaths.get(i)); + authRefFields.put(authRefPath, ancestorAuthRefFieldName); + } + + String docType = sb.getObject().getName(); + queriedServiceBindings.put(docType, sb); + authRefFieldsByService.put(docType, authRefFields); + docTypes.add(docType); + Collection fields = authRefFields.values(); + for (String field : fields) { + // Build up the where clause for each authRef field + if (fFirst) { + fFirst = false; + } else { + whereClause.append(" OR "); + } + //whereClause.append(prefix); + whereClause.append(field); + whereClause.append("='"); + whereClause.append(escapedRefName); + whereClause.append("'"); + } + } + String whereClauseStr = whereClause.toString(); // for debugging + if (fFirst) // found no authRef fields - nothing to query + { + return wrapperList; + } + String fullQuery = whereClause.toString(); // for debug + // Now we have to issue the search + DocumentWrapper docListWrapper = repoClient.findDocs(ctx, + docTypes, whereClause.toString(), pageSize, pageNum, computeTotal); + // Now we gather the info for each document into the list and return + DocumentModelList docList = docListWrapper.getWrappedObject(); + // Set num of items in list. this is useful to our testing framework. + commonList.setItemsInPage(docList.size()); + // set the total result size + commonList.setTotalItems(docList.totalSize()); + Iterator iter = docList.iterator(); + while (iter.hasNext()) { + DocumentModel docModel = iter.next(); + AuthorityRefDocList.AuthorityRefDocItem ilistItem = new AuthorityRefDocList.AuthorityRefDocItem(); + String csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString()); + String docType = docModel.getDocumentType().getName(); + ServiceBindingType sb = queriedServiceBindings.get(docType); + if (sb == null) { + throw new RuntimeException( + "getAuthorityRefDocs: No Service Binding for docType: " + docType); + } + String serviceContextPath = "/" + sb.getName().toLowerCase() + "/"; + // The id and URI are the same on all doctypes + ilistItem.setDocId(csid); + ilistItem.setUri(serviceContextPath + csid); + ilistItem.setDocType(docType); + ilistItem.setDocNumber( + ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NUMBER_PROP, docModel)); + ilistItem.setDocName( + ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NAME_PROP, docModel)); + // Now, we have to loop over the authRefFieldsByService to figure + // out which field matched this. Ignore multiple matches. + Map matchingAuthRefFields = authRefFieldsByService.get(docType); + if (matchingAuthRefFields == null || matchingAuthRefFields.isEmpty()) { + throw new RuntimeException( + "getAuthorityRefDocs: internal logic error: can't fetch authRefFields for DocType."); + } + String authRefAncestorField = ""; + String authRefDescendantField = ""; + String sourceField = ""; + boolean fRefFound = false; + // Use this if we go to qualified field names + for (String path : matchingAuthRefFields.keySet()) { + try { + // This is the field name we show in the return info + authRefAncestorField = (String) matchingAuthRefFields.get(path); + // This is the qualified field we have to get from the doc model + authRefDescendantField = DocumentUtils.getDescendantOrAncestor(path); + // The ancestor field is part-schema (tablename) qualified + String[] strings = authRefAncestorField.split(":"); + if (strings.length != 2) { + throw new RuntimeException( + "getAuthorityRefDocs: Bad configuration of path to authority reference field."); + } + // strings[0] holds a schema name, such as "intakes_common" + // + // strings[1] holds: + // * The name of an authority reference field, such as "depositor"; + // or + // * The name of an ancestor (e.g. parent, grandparent ...) field, + // such as "fieldCollectors", of a repeatable authority reference + // field, such as "fieldCollector". + // TODO - if the value is not simple, or repeating scalar, need a more + // sophisticated fetch. + Object fieldValue = docModel.getProperty(strings[0], strings[1]); + // We cannot be sure why we have this doc, so look for matches + boolean fRefMatches = refNameFoundInField(refName, fieldValue); + if (fRefMatches) { + sourceField = authRefDescendantField; + // Handle multiple fields matching in one Doc. See CSPACE-2863. + if(fRefFound) { + // We already added ilistItem, so we need to clone that and add again + ilistItem = cloneAuthRefDocItem(ilistItem, sourceField); + } else { + ilistItem.setSourceField(sourceField); + fRefFound = true; + } + list.add(ilistItem); + } + + } catch (ClientException ce) { + throw new RuntimeException( + "getAuthorityRefDocs: Problem fetching: " + sourceField, ce); + } + } + if (!fRefFound) { + throw new RuntimeException( + "getAuthorityRefDocs: Could not find refname in object:" + + docType + ":" + csid); + } + } + return wrapperList; + } + + private static AuthorityRefDocList.AuthorityRefDocItem cloneAuthRefDocItem( + AuthorityRefDocList.AuthorityRefDocItem ilistItem, String sourceField) { + AuthorityRefDocList.AuthorityRefDocItem newlistItem = new AuthorityRefDocList.AuthorityRefDocItem(); + newlistItem.setDocId(ilistItem.getDocId()); + newlistItem.setDocName(ilistItem.getDocName()); + newlistItem.setDocNumber(ilistItem.getDocNumber()); + newlistItem.setDocType(ilistItem.getDocType()); + newlistItem.setUri(ilistItem.getUri()); + newlistItem.setSourceField(sourceField); + return newlistItem; + } + + /* + * Identifies whether the refName was found in the supplied field. + * + * Only works for: + * * Scalar fields + * * Repeatable scalar fields (aka multi-valued fields) + * + * Does not work for: + * * Structured fields (complexTypes) + * * Repeatable structured fields (repeatable complexTypes) + */ + private static boolean refNameFoundInField(String refName, Object fieldValue) { + + boolean result = false; + if (fieldValue instanceof List) { + List fieldValueList = (List) fieldValue; + for (String listItemValue : fieldValueList) { + if (refName.equalsIgnoreCase(listItemValue)) { + result = true; + break; + } + + } + } else if (fieldValue instanceof String){ + if (refName.equalsIgnoreCase((String)fieldValue)) { + result = true; + } + } + return result; + } +} + diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/RefNameUtils.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/RefNameUtils.java new file mode 100644 index 000000000..7a54b2e5b --- /dev/null +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/RefNameUtils.java @@ -0,0 +1,245 @@ +/** + * 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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * RefNameUtils is a collection of utilities related to refName URN strings + * refNames are URNs that reference a document entity, often an authority or + * authority term. They are strings that take the form (for authorities): + * urn:cspace:org.collectionspace.demo:vocabulary:name(Entry Methods)'Entry Methods' + * or the form (for authority terms): + * urn:cspace:org.collectionspace.demo:vocabulary:name(Entry Methods):item:name(Loan)'Loan' + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class RefNameUtils { + + private final Logger logger = LoggerFactory.getLogger(RefNameUtils.class); + + public static final String URN_PREFIX = "urn:cspace:"; + public static final int URN_PREFIX_LEN = 11; + public static final String URN_NAME_PREFIX = "urn:cspace:name("; + public static final int URN_NAME_PREFIX_LEN = 16; + // FIXME Should not be hard-coded + private static final String ITEMS_REGEX = "item|person|organization"; + // In a list of tokens, these are indices for each part + private static final int DOMAIN_TOKEN = 0; // e.g., 'org.collectionspace.demo' + private static final int RESOURCE_TOKEN = 1; // vocabulary, personauthority, etc. + private static final int AUTH_INSTANCE_TOKEN = 2; // name(Entry Methods)'Entry Methods' + private static final int ITEMS_TOKEN = 3; // 'item', 'person', etc. + private static final int ITEM_INSTANCE_TOKEN = 4; // name(Entry Methods)'Entry Methods' + // Tokenizing the INSTANCE, these are indices for each item-part + private static final int INSTANCE_SPEC_TYPE_TOKEN = 0; // 'name' or 'id' + private static final int INSTANCE_SPEC_TOKEN = 1; // name or id value + private static final int INSTANCE_DISPLAYNAME_TOKEN = 2;// optional displayName suffix + private static final int INSTANCE_TOKENS_MIN = 2; + private static final int INSTANCE_TOKENS_MAX = 3; + public static final String SEPARATOR = ":"; + + public static class AuthorityInfo { + private final Logger logger = LoggerFactory.getLogger(AuthorityInfo.class); + private static int MIN_TOKENS = 3; + public String domain; + public String resource; + public String csid; + public String name; + public String displayName; + + public AuthorityInfo(String refNameTokens[]) throws Exception { + try { + if(refNameTokens.length < MIN_TOKENS) { + throw new IllegalArgumentException("Malformed refName for Authority (too few tokens)"); + } + this.domain = refNameTokens[DOMAIN_TOKEN]; + this.resource = refNameTokens[RESOURCE_TOKEN]; + String idTokens[] = refNameTokens[AUTH_INSTANCE_TOKEN].split("[()]", INSTANCE_TOKENS_MAX); + if(idTokens.length + extends RemoteDocumentModelHandlerImpl { + + private String authorityCommonSchemaName; + + /** + * authority is used to stash JAXB object to use when handle is called + * for Action.CREATE, Action.UPDATE or Action.GET + */ + private AuthCommon authority; + /** + * authorityList is stashed when handle is called + * for ACTION.GET_ALL + */ + private AuthCommonList authorityList; + + + public AuthorityDocumentModelHandler(String authorityCommonSchemaName) { + this.authorityCommonSchemaName = authorityCommonSchemaName; + } + + /** + * getCommonPart get associated authority + * @return + */ + @Override + public AuthCommon getCommonPart() { + return authority; + } + + /** + * setCommonPart set associated authority + * @param authority + */ + @Override + public void setCommonPart(AuthCommon authority) { + this.authority = authority; + } + + /** + * getCommonPartList get associated authority (for index/GET_ALL) + * @return + */ + @Override + public AuthCommonList getCommonPartList() { + return authorityList; + } + + /* (non-Javadoc) + * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#setCommonPartList(java.lang.Object) + */ + @Override + public void setCommonPartList(AuthCommonList authorityList) { + this.authorityList = authorityList; + } + + /* (non-Javadoc) + * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#extractCommonPart(org.collectionspace.services.common.document.DocumentWrapper) + */ + @Override + public AuthCommon extractCommonPart(DocumentWrapper wrapDoc) + throws Exception { + throw new UnsupportedOperationException(); + } + + /* (non-Javadoc) + * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#fillCommonPart(java.lang.Object, org.collectionspace.services.common.document.DocumentWrapper) + */ + @Override + public void fillCommonPart(AuthCommon vocabularyObject, DocumentWrapper wrapDoc) throws Exception { + throw new UnsupportedOperationException(); + } + + /* (non-Javadoc) + * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType) + */ + @Override + protected Map extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta) + throws Exception { + Map unQObjectProperties = super.extractPart(docModel, schema, partMeta); + + // Add the CSID to the common part + if (partMeta.getLabel().equalsIgnoreCase(authorityCommonSchemaName)) { + String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString()); + unQObjectProperties.put("csid", csid); + } + + return unQObjectProperties; + } + +} + diff --git a/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java new file mode 100644 index 000000000..6421c54db --- /dev/null +++ b/services/authority/src/main/java/org/collectionspace/services/common/vocabulary/nuxeo/AuthorityItemDocumentModelHandler.java @@ -0,0 +1,174 @@ +/** + * 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.nuxeo; + +import java.util.Map; + +import org.collectionspace.services.common.document.DocumentWrapper; +import org.collectionspace.services.common.service.ObjectPartType; +import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema; +import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl; +import org.collectionspace.services.nuxeo.util.NuxeoUtils; +import org.nuxeo.ecm.core.api.DocumentModel; + +/** + * AuthorityItemDocumentModelHandler + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public abstract class AuthorityItemDocumentModelHandler + extends RemoteDocumentModelHandlerImpl { + + private String authorityItemCommonSchemaName; + + //private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class); + /** + * item is used to stash JAXB object to use when handle is called + * for Action.CREATE, Action.UPDATE or Action.GET + */ + protected AICommon item; + /** + * itemList is stashed when handle is called + * for ACTION.GET_ALL + */ + protected AICommonList itemList; + + /** + * inVocabulary is the parent Authority for this context + */ + protected String inAuthority; + + public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) { + this.authorityItemCommonSchemaName = authorityItemCommonSchemaName; + } + + public String getInAuthority() { + return inAuthority; + } + + public void setInAuthority(String inAuthority) { + this.inAuthority = inAuthority; + } + + /* (non-Javadoc) + * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper) + */ + @Override + public void handleCreate(DocumentWrapper wrapDoc) throws Exception { + // first fill all the parts of the document + super.handleCreate(wrapDoc); + handleInAuthority(wrapDoc.getWrappedObject()); + } + + /** + * Check the logic around the parent pointer. Note that we only need do this on + * create, since we have logic to make this read-only on update. + * + * @param docModel + * + * @throws Exception the exception + */ + private void handleInAuthority(DocumentModel docModel) throws Exception { + docModel.setProperty(authorityItemCommonSchemaName, + AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority); + } + + + /** + * getCommonPart get associated item + * @return + */ + @Override + public AICommon getCommonPart() { + return item; + } + + /** + * setCommonPart set associated item + * @param vocabularyItem + */ + @Override + public void setCommonPart(AICommon item) { + this.item = item; + } + + /** + * getCommonPartList get associated item (for index/GET_ALL) + * @return + */ + @Override + public AICommonList getCommonPartList() { + return itemList; + } + + @Override + public void setCommonPartList(AICommonList itemList) { + this.itemList = itemList; + } + + @Override + public AICommon extractCommonPart(DocumentWrapper wrapDoc) + throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + public void fillCommonPart(AICommon itemObject, DocumentWrapper wrapDoc) throws Exception { + throw new UnsupportedOperationException(); + } + + /* (non-Javadoc) + * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType) + */ + @Override + protected Map extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta) + throws Exception { + Map unQObjectProperties = super.extractPart(docModel, schema, partMeta); + + // Add the CSID to the common part + if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) { + String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString()); + unQObjectProperties.put("csid", csid); + } + + return unQObjectProperties; + } + + /** + * Filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure that + * the parent link remains untouched. + * @param objectProps the properties parsed from the update payload + * @param partMeta metadata for the object to fill + */ + @Override + public void filterReadOnlyPropertiesForPart( + Map objectProps, ObjectPartType partMeta) { + super.filterReadOnlyPropertiesForPart(objectProps, partMeta); + objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY); + objectProps.remove(AuthorityItemJAXBSchema.CSID); + } + +} +