]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
96d887e650ab977f44cfe0a8612b01a688aa64c8
[tmp/jakarta-migration.git] /
1 /**
2  *  This document is a part of the source code and related artifacts
3  *  for CollectionSpace, an open source collections management system
4  *  for museums and related institutions:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
18  *  Unless required by applicable law or agreed to in writing, software
19  *  distributed under the License is distributed on an "AS IS" BASIS,
20  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  *  See the License for the specific language governing permissions and
22  *  limitations under the License.
23  */
24 package org.collectionspace.services.common.vocabulary;
25
26 import org.collectionspace.services.client.IClientQueryParams;
27 import org.collectionspace.services.client.IQueryManager;
28 import org.collectionspace.services.client.PoxPayloadIn;
29 import org.collectionspace.services.client.PoxPayloadOut;
30 import org.collectionspace.services.client.workflow.WorkflowClient;
31 import org.collectionspace.services.common.ClientType;
32 import org.collectionspace.services.common.ResourceBase;
33 import org.collectionspace.services.common.ResourceMap;
34 import org.collectionspace.services.common.ServiceMain;
35 import org.collectionspace.services.common.ServiceMessages;
36 import org.collectionspace.services.common.XmlTools;
37 import org.collectionspace.services.common.api.RefName;
38 import org.collectionspace.services.common.api.Tools;
39 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
40 import org.collectionspace.services.common.authorityref.AuthorityRefList;
41 import org.collectionspace.services.common.context.JaxRsContext;
42 import org.collectionspace.services.common.context.MultipartServiceContext;
43 import org.collectionspace.services.common.context.MultipartServiceContextImpl;
44 import org.collectionspace.services.common.context.RemoteServiceContext;
45 import org.collectionspace.services.common.context.ServiceBindingUtils;
46 import org.collectionspace.services.common.context.ServiceContext;
47 import org.collectionspace.services.common.document.DocumentException;
48 import org.collectionspace.services.common.document.DocumentFilter;
49 import org.collectionspace.services.common.document.DocumentHandler;
50 import org.collectionspace.services.common.document.DocumentNotFoundException;
51 import org.collectionspace.services.common.document.DocumentWrapper;
52 import org.collectionspace.services.common.query.QueryManager;
53 import org.collectionspace.services.common.repository.RepositoryClient;
54 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler;
55 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler;
56 import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;
57 import org.collectionspace.services.jaxb.AbstractCommonList;
58 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
59 import org.collectionspace.services.relation.RelationResource;
60 import org.collectionspace.services.relation.RelationsCommonList;
61 import org.collectionspace.services.relation.RelationshipType;
62 import org.jboss.resteasy.util.HttpResponseCodes;
63 import org.nuxeo.ecm.core.api.DocumentModel;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 import javax.ws.rs.Consumes;
68 import javax.ws.rs.DELETE;
69 import javax.ws.rs.GET;
70 import javax.ws.rs.POST;
71 import javax.ws.rs.PUT;
72 import javax.ws.rs.Path;
73 import javax.ws.rs.PathParam;
74 import javax.ws.rs.Produces;
75 import javax.ws.rs.QueryParam;
76 import javax.ws.rs.WebApplicationException;
77 import javax.ws.rs.core.Context;
78 import javax.ws.rs.core.MultivaluedMap;
79 import javax.ws.rs.core.Request;
80 import javax.ws.rs.core.Response;
81 import javax.ws.rs.core.UriBuilder;
82 import javax.ws.rs.core.UriInfo;
83
84 import java.util.ArrayList;
85 import java.util.List;
86
87 /**
88  * The Class AuthorityResource.
89  */
90 @Consumes("application/xml")
91 @Produces("application/xml")
92 public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
93         extends ResourceBase {
94
95     protected Class<AuthCommon> authCommonClass;
96     protected Class<?> resourceClass;
97     protected String authorityCommonSchemaName;
98     protected String authorityItemCommonSchemaName;
99     final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType();
100     final static String URN_PREFIX = "urn:cspace:";
101     final static int URN_PREFIX_LEN = URN_PREFIX.length();
102     final static String URN_PREFIX_NAME = "name(";
103     final static int URN_NAME_PREFIX_LEN = URN_PREFIX_LEN + URN_PREFIX_NAME.length();
104     final static String URN_PREFIX_ID = "id(";
105     final static int URN_ID_PREFIX_LEN = URN_PREFIX_LEN + URN_PREFIX_ID.length();
106     final static String FETCH_SHORT_ID = "_fetch_";
107     final Logger logger = LoggerFactory.getLogger(AuthorityResource.class);
108
109     public enum SpecifierForm {
110
111         CSID, URN_NAME
112     };
113
114     public class Specifier {
115
116         public SpecifierForm form;
117         public String value;
118
119         Specifier(SpecifierForm form, String value) {
120             this.form = form;
121             this.value = value;
122         }
123     }
124
125     protected Specifier getSpecifier(String specifierIn, String method, String op) throws WebApplicationException {
126         if (logger.isDebugEnabled()) {
127             logger.debug("getSpecifier called by: " + method + " with specifier: " + specifierIn);
128         }
129         if (specifierIn != null) {
130             if (!specifierIn.startsWith(URN_PREFIX)) {
131                 // We'll assume it is a CSID and complain if it does not match
132                 return new Specifier(SpecifierForm.CSID, specifierIn);
133             } else {
134                 if (specifierIn.startsWith(URN_PREFIX_NAME, URN_PREFIX_LEN)) {
135                     int closeParen = specifierIn.indexOf(')', URN_NAME_PREFIX_LEN);
136                     if (closeParen >= 0) {
137                         return new Specifier(SpecifierForm.URN_NAME,
138                                 specifierIn.substring(URN_NAME_PREFIX_LEN, closeParen));
139                     }
140                 } else if (specifierIn.startsWith(URN_PREFIX_ID, URN_PREFIX_LEN)) {
141                     int closeParen = specifierIn.indexOf(')', URN_ID_PREFIX_LEN);
142                     if (closeParen >= 0) {
143                         return new Specifier(SpecifierForm.CSID,
144                                 specifierIn.substring(URN_ID_PREFIX_LEN, closeParen));
145                     }
146                 }
147             }
148         }
149         logger.error(method + ": bad or missing specifier!");
150         Response response = Response.status(Response.Status.BAD_REQUEST).entity(
151                 op + " failed on bad or missing Authority specifier").type(
152                 "text/plain").build();
153         throw new WebApplicationException(response);
154     }
155
156     /**
157      * Instantiates a new Authority resource.
158      */
159     public AuthorityResource(Class<AuthCommon> authCommonClass, Class<?> resourceClass,
160             String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
161         this.authCommonClass = authCommonClass;
162         this.resourceClass = resourceClass;
163         this.authorityCommonSchemaName = authorityCommonSchemaName;
164         this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
165     }
166
167     public abstract String getItemServiceName();
168
169     @Override
170     protected String getVersionString() {
171         return "$LastChangedRevision: 2617 $";
172     }
173
174     @Override
175     public Class<AuthCommon> getCommonPartClass() {
176         return authCommonClass;
177     }
178
179     /**
180      * Creates the item document handler.
181      * 
182      * @param ctx the ctx
183      * @param inAuthority the in vocabulary
184      * 
185      * @return the document handler
186      * 
187      * @throws Exception the exception
188      */
189     protected DocumentHandler createItemDocumentHandler(
190             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
191             String inAuthority, String parentShortIdentifier)
192             throws Exception {
193         String authorityRefNameBase;
194         AuthorityItemDocumentModelHandler<?> docHandler;
195
196         if (parentShortIdentifier == null) {
197             authorityRefNameBase = null;
198         } else {
199             ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx =
200                     createServiceContext(getServiceName());
201             if (parentShortIdentifier.equals(FETCH_SHORT_ID)) {
202                 // Get from parent document
203                 parentShortIdentifier = getAuthShortIdentifier(parentCtx, inAuthority);
204             }
205             authorityRefNameBase = buildAuthorityRefNameBase(parentCtx, parentShortIdentifier);
206         }
207
208         docHandler = (AuthorityItemDocumentModelHandler<?>) createDocumentHandler(ctx,
209                 ctx.getCommonPartLabel(getItemServiceName()),
210                 authCommonClass);
211         docHandler.setInAuthority(inAuthority);
212         docHandler.setAuthorityRefNameBase(authorityRefNameBase);
213
214         return docHandler;
215     }
216
217     public String getAuthShortIdentifier(
218             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String authCSID)
219             throws DocumentNotFoundException, DocumentException {
220         String shortIdentifier = null;
221         try {
222             DocumentWrapper<DocumentModel> wrapDoc = getRepositoryClient(ctx).getDocFromCsid(ctx, authCSID);
223             AuthorityDocumentModelHandler<?> handler =
224                     (AuthorityDocumentModelHandler<?>) createDocumentHandler(ctx);
225             shortIdentifier = handler.getShortIdentifier(wrapDoc, authorityCommonSchemaName);
226         } catch (Exception e) {
227             if (logger.isDebugEnabled()) {
228                 logger.debug("Caught exception ", e);
229             }
230             throw new DocumentException(e);
231         }
232         return shortIdentifier;
233     }
234
235     protected String buildAuthorityRefNameBase(
236             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String shortIdentifier) {
237         RefName.Authority authority = RefName.buildAuthority(ctx.getTenantName(),
238                 ctx.getServiceName(), shortIdentifier, null);
239         return authority.toString();
240     }
241
242     public static class CsidAndShortIdentifier {
243
244         String CSID;
245         String shortIdentifier;
246     }
247
248     public String lookupParentCSID(String parentspecifier, String method, String op, MultivaluedMap<String, String> queryParams)
249             throws Exception {
250         CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(parentspecifier, method, op, queryParams);
251         return tempResult.CSID;
252     }
253
254     public CsidAndShortIdentifier lookupParentCSIDAndShortIdentifer(String parentspecifier, String method, String op, MultivaluedMap<String, String> queryParams)
255             throws Exception {
256         CsidAndShortIdentifier result = new CsidAndShortIdentifier();
257         Specifier parentSpec = getSpecifier(parentspecifier, method, op);
258         // Note that we have to create the service context for the Items, not the main service
259         String parentcsid;
260         String parentShortIdentifier;
261         if (parentSpec.form == SpecifierForm.CSID) {
262             parentShortIdentifier = null;
263             parentcsid = parentSpec.value;
264             // Uncomment when app layer is ready to integrate
265             // Uncommented since refNames are currently only generated if not present - ADR CSPACE-3178
266             parentShortIdentifier = FETCH_SHORT_ID;
267         } else {
268             parentShortIdentifier = parentSpec.value;
269             String whereClause = buildWhereForAuthByName(parentSpec.value);
270             ServiceContext ctx = createServiceContext(getServiceName(), queryParams);
271             parentcsid = getRepositoryClient(ctx).findDocCSID(ctx, whereClause); //FIXME: REM - If the parent has been soft-deleted, should we be looking for the item?
272         }
273         result.CSID = parentcsid;
274         result.shortIdentifier = parentShortIdentifier;
275         return result;
276     }
277
278     public String lookupItemCSID(String itemspecifier, String parentcsid, String method, String op, ServiceContext ctx)
279             throws DocumentException {
280         String itemcsid;
281         Specifier itemSpec = getSpecifier(itemspecifier, method, op);
282         if (itemSpec.form == SpecifierForm.CSID) {
283             itemcsid = itemSpec.value;
284         } else {
285             String itemWhereClause = buildWhereForAuthItemByName(itemSpec.value, parentcsid);
286             itemcsid = getRepositoryClient(ctx).findDocCSID(ctx, itemWhereClause); //FIXME: REM - Should we be looking for the 'wf_deleted' query param and filtering on it?
287         }
288         return itemcsid;
289     }
290
291     /*
292      * Generally, callers will first call RefName.AuthorityItem.parse with a refName, and then 
293      * use the returned item.inAuthority.resource and a resourceMap to get a service-specific
294      * Resource. They then call this method on that resource.
295      */
296     @Override
297         public DocumentModel getDocModelForAuthorityItem(RefName.AuthorityItem item) 
298                         throws Exception, DocumentNotFoundException {
299         if(item == null) {
300                 return null;
301         }
302         String whereClause = buildWhereForAuthByName(item.getParentShortIdentifier());
303         // Ensure we have the right context.
304         ServiceContext ctx = createServiceContext(item.inAuthority.resource);
305         
306         String parentcsid = getRepositoryClient(ctx).findDocCSID(ctx, whereClause);
307
308         String itemWhereClause = buildWhereForAuthItemByName(item.getShortIdentifier(), parentcsid);
309         ctx = createServiceContext(getItemServiceName());
310         DocumentWrapper<DocumentModel> docWrapper = getRepositoryClient(ctx).findDoc(ctx, itemWhereClause);
311         DocumentModel docModel = docWrapper.getWrappedObject();
312         return docModel;
313     }
314
315
316     @POST
317     public Response createAuthority(String xmlPayload) {
318         try {
319             PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
320             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(input);
321             DocumentHandler handler = createDocumentHandler(ctx);
322             String csid = getRepositoryClient(ctx).create(ctx, handler);
323             UriBuilder path = UriBuilder.fromResource(resourceClass);
324             path.path("" + csid);
325             Response response = Response.created(path.build()).build();
326             return response;
327         } catch (Exception e) {
328             throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
329         }
330     }
331
332     protected String buildWhereForAuthByName(String name) {
333         return authorityCommonSchemaName
334                 + ":" + AuthorityJAXBSchema.SHORT_IDENTIFIER
335                 + "='" + name + "'";
336     }
337
338     protected String buildWhereForAuthItemByName(String name, String parentcsid) {
339         return authorityItemCommonSchemaName
340                 + ":" + AuthorityItemJAXBSchema.SHORT_IDENTIFIER
341                 + "='" + name + "' AND "
342                 + authorityItemCommonSchemaName + ":"
343                 + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
344                 + "'" + parentcsid + "'";
345     }
346
347     /**
348      * Gets the authority.
349      * 
350      * @param specifier either a CSID or one of the urn forms
351      * 
352      * @return the authority
353      */
354     @GET
355     @Path("{csid}")
356     @Override
357     public byte[] get( // getAuthority(
358             @Context UriInfo ui,
359             @PathParam("csid") String specifier) {
360         PoxPayloadOut result = null;
361         try {
362             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
363             DocumentHandler handler = createDocumentHandler(ctx);
364
365             Specifier spec = getSpecifier(specifier, "getAuthority", "GET");
366             if (spec.form == SpecifierForm.CSID) {
367                 if (logger.isDebugEnabled()) {
368                     logger.debug("getAuthority with csid=" + spec.value);
369                 }
370                 getRepositoryClient(ctx).get(ctx, spec.value, handler);
371             } else {
372                 String whereClause = buildWhereForAuthByName(spec.value);
373                 DocumentFilter myFilter = new DocumentFilter(whereClause, 0, 1);
374                 handler.setDocumentFilter(myFilter);
375                 getRepositoryClient(ctx).get(ctx, handler);
376             }
377             result = ctx.getOutput();
378
379         } catch (Exception e) {
380             throw bigReThrow(e, ServiceMessages.GET_FAILED, specifier);
381         }
382
383         if (result == null) {
384             Response response = Response.status(Response.Status.NOT_FOUND).entity(
385                     "Get failed, the requested Authority specifier:" + specifier + ": was not found.").type(
386                     "text/plain").build();
387             throw new WebApplicationException(response);
388         }
389
390         return result.getBytes();
391     }
392
393     /**
394      * Finds and populates the authority list.
395      * 
396      * @param ui the ui
397      * 
398      * @return the authority list
399      */
400     @GET
401     @Produces("application/xml")
402     public AbstractCommonList getAuthorityList(@Context UriInfo ui) {
403         try {
404             MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
405             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(queryParams);
406             DocumentHandler handler = createDocumentHandler(ctx);
407             DocumentFilter myFilter = handler.getDocumentFilter();
408             // Need to make the default sort order for authority items
409             // be on the displayName field
410             String sortBy = queryParams.getFirst(IClientQueryParams.SORT_BY_PARAM);
411             if (sortBy == null || sortBy.isEmpty()) {
412                 String qualifiedDisplayNameField = authorityCommonSchemaName + ":"
413                         + AuthorityItemJAXBSchema.DISPLAY_NAME;
414                 myFilter.setOrderByClause(qualifiedDisplayNameField);
415             }
416             String nameQ = queryParams.getFirst("refName");
417             if (nameQ != null) {
418                 myFilter.setWhereClause(authorityCommonSchemaName + ":refName='" + nameQ + "'");
419             }
420             getRepositoryClient(ctx).getFiltered(ctx, handler);
421             return (AbstractCommonList) handler.getCommonPartList();
422         } catch (Exception e) {
423             throw bigReThrow(e, ServiceMessages.GET_FAILED);
424         }
425     }
426
427     /**
428      * Update authority.
429      *
430      * @param specifier the csid or id
431      *
432      * @return the multipart output
433      */
434     @PUT
435     @Path("{csid}")
436     public byte[] updateAuthority(
437             @PathParam("csid") String specifier,
438             String xmlPayload) {
439         PoxPayloadOut result = null;
440         try {
441             PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
442             Specifier spec = getSpecifier(specifier, "updateAuthority", "UPDATE");
443             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
444             DocumentHandler handler = createDocumentHandler(ctx);
445             String csid;
446             if (spec.form == SpecifierForm.CSID) {
447                 csid = spec.value;
448             } else {
449                 String whereClause = buildWhereForAuthByName(spec.value);
450                 csid = getRepositoryClient(ctx).findDocCSID(ctx, whereClause);
451             }
452             getRepositoryClient(ctx).update(ctx, csid, handler);
453             result = ctx.getOutput();
454         } catch (Exception e) {
455             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
456         }
457         return result.getBytes();
458     }
459
460     /**
461      * Delete authority.
462      * 
463      * @param csid the csid
464      * 
465      * @return the response
466      */
467     @DELETE
468     @Path("{csid}")
469     public Response deleteAuthority(@PathParam("csid") String csid) {
470         if (logger.isDebugEnabled()) {
471             logger.debug("deleteAuthority with csid=" + csid);
472         }
473         try {
474             ensureCSID(csid, ServiceMessages.DELETE_FAILED, "Authority.csid");
475             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
476             getRepositoryClient(ctx).delete(ctx, csid);
477             return Response.status(HttpResponseCodes.SC_OK).build();
478         } catch (Exception e) {
479             throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid);
480         }
481     }
482
483     /*************************************************************************
484      * Create an AuthorityItem - this is a sub-resource of Authority
485      * @param specifier either a CSID or one of the urn forms
486      * @return Authority item response
487      *************************************************************************/
488     @POST
489     @Path("{csid}/items")
490     public Response createAuthorityItem(@Context ResourceMap resourceMap, @Context UriInfo ui, 
491                 @PathParam("csid") String specifier, String xmlPayload) {
492         try {
493             PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
494             ServiceContext ctx = createServiceContext(getItemServiceName(), input);
495             ctx.setResourceMap(resourceMap);
496             ctx.setUriInfo(ui);    //Laramie
497
498             // Note: must have the parentShortId, to do the create.
499             CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(specifier, "createAuthorityItem", "CREATE_ITEM", null);
500             DocumentHandler handler = createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
501             String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
502             UriBuilder path = UriBuilder.fromResource(resourceClass);
503             path.path(parent.CSID + "/items/" + itemcsid);
504             Response response = Response.created(path.build()).build();
505             return response;
506         } catch (Exception e) {
507             throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
508         }
509     }
510
511     @GET
512     @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
513     public byte[] getItemWorkflow(
514             @PathParam("csid") String csid,
515             @PathParam("itemcsid") String itemcsid) {
516         PoxPayloadOut result = null;
517
518         try {
519             ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
520             String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
521
522             MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
523             WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
524             ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
525             getRepositoryClient(ctx).get(ctx, itemcsid, handler);
526             result = ctx.getOutput();
527         } catch (Exception e) {
528             throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
529         }
530         return result.getBytes();
531     }
532
533     @PUT
534     @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
535     public byte[] updateWorkflow(
536             @PathParam("csid") String csid,
537             @PathParam("itemcsid") String itemcsid,
538             String xmlPayload) {
539         PoxPayloadOut result = null;
540         try {
541             ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
542             String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
543
544             PoxPayloadIn workflowUpdate = new PoxPayloadIn(xmlPayload);
545             MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, workflowUpdate);
546             WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
547             ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
548             getRepositoryClient(ctx).update(ctx, itemcsid, handler);
549             result = ctx.getOutput();
550         } catch (Exception e) {
551             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
552         }
553         return result.getBytes();
554     }
555
556     /**
557      * Gets the authority item.
558      * 
559      * @param parentspecifier either a CSID or one of the urn forms
560      * @param itemspecifier either a CSID or one of the urn forms
561      * 
562      * @return the authority item
563      */
564     @GET
565     @Path("{csid}/items/{itemcsid}")
566     public byte[] getAuthorityItem(
567             @Context Request request,
568             @Context UriInfo ui,
569             @PathParam("csid") String parentspecifier,
570             @PathParam("itemcsid") String itemspecifier) {
571         PoxPayloadOut result = null;
572         try {
573             JaxRsContext jaxRsContext = new JaxRsContext(request, ui);
574             MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
575             String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItem(parent)", "GET_ITEM", queryParams);
576
577             RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
578             ctx = (RemoteServiceContext) createServiceContext(getItemServiceName(), queryParams);
579             ctx.setJaxRsContext(jaxRsContext);
580
581             ctx.setUriInfo(ui); //ARG!   must pass this or subsequent calls will not have a ui.
582
583             // We omit the parentShortId, only needed when doing a create...
584             DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid, null);
585
586             Specifier itemSpec = getSpecifier(itemspecifier, "getAuthorityItem(item)", "GET_ITEM");
587             if (itemSpec.form == SpecifierForm.CSID) {
588                 getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
589             } else {
590                 String itemWhereClause =
591                         buildWhereForAuthItemByName(itemSpec.value, parentcsid);
592                 DocumentFilter myFilter = new DocumentFilter(itemWhereClause, 0, 1);
593                 handler.setDocumentFilter(myFilter);
594                 getRepositoryClient(ctx).get(ctx, handler);
595             }
596             // TODO should we assert that the item is in the passed vocab?
597             result = ctx.getOutput();
598         } catch (Exception e) {
599             throw bigReThrow(e, ServiceMessages.GET_FAILED);
600         }
601         if (result == null) {
602             Response response = Response.status(Response.Status.NOT_FOUND).entity(
603                     "Get failed, the requested AuthorityItem specifier:" + itemspecifier + ": was not found.").type(
604                     "text/plain").build();
605             throw new WebApplicationException(response);
606         }
607         return result.getBytes();
608     }
609
610     /**
611      * Gets the authorityItem list for the specified authority
612      * If partialPerm is specified, keywords will be ignored.
613      * 
614      * @param specifier either a CSID or one of the urn forms
615      * @param partialTerm if non-null, matches partial terms
616      * @param keywords if non-null, matches terms in the keyword index for items
617      * @param ui passed to include additional parameters, like pagination controls
618      * 
619      * @return the authorityItem list
620      */
621     @GET
622     @Path("{csid}/items")
623     @Produces("application/xml")
624     public AbstractCommonList getAuthorityItemList(@PathParam("csid") String specifier,
625             @Context UriInfo ui) {
626         try {
627             MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
628             String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
629             String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
630             String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
631
632             String qualifiedDisplayNameField = authorityItemCommonSchemaName + ":"
633                     + AuthorityItemJAXBSchema.DISPLAY_NAME;
634
635             // Note that docType defaults to the ServiceName, so we're fine with that.
636             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
637
638             String parentcsid = lookupParentCSID(specifier, "getAuthorityItemList", "LIST", queryParams);
639
640             ctx = createServiceContext(getItemServiceName(), queryParams);
641             // We omit the parentShortId, only needed when doing a create...
642             DocumentHandler handler = createItemDocumentHandler(ctx,
643                     parentcsid, null);
644             DocumentFilter myFilter = handler.getDocumentFilter();
645             // Need to make the default sort order for authority items
646             // be on the displayName field
647             String sortBy = queryParams.getFirst(IClientQueryParams.SORT_BY_PARAM);
648             if (sortBy == null || sortBy.isEmpty()) {
649                 myFilter.setOrderByClause(qualifiedDisplayNameField);
650             }
651
652             myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
653                     + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
654                     + "'" + parentcsid + "'",
655                     IQueryManager.SEARCH_QUALIFIER_AND);
656
657             // AND vocabularyitems_common:displayName LIKE '%partialTerm%'
658             // NOTE: Partial terms searches are mutually exclusive to keyword and advanced-search, but
659             // the PT query param trumps the KW and AS query params.
660             if (partialTerm != null && !partialTerm.isEmpty()) {
661                 String ptClause = QueryManager.createWhereClauseForPartialMatch(
662                         qualifiedDisplayNameField, partialTerm);
663                 myFilter.appendWhereClause(ptClause, IQueryManager.SEARCH_QUALIFIER_AND);
664             } else if (keywords != null || advancedSearch != null) {
665 //                              String kwdClause = QueryManager.createWhereClauseFromKeywords(keywords);
666 //                              myFilter.appendWhereClause(kwdClause, IQueryManager.SEARCH_QUALIFIER_AND);
667                 return search(ctx, handler, queryParams, keywords, advancedSearch);
668             }
669             if (logger.isDebugEnabled()) {
670                 logger.debug("getAuthorityItemList filtered WHERE clause: "
671                         + myFilter.getWhereClause());
672             }
673             getRepositoryClient(ctx).getFiltered(ctx, handler);
674             return (AbstractCommonList) handler.getCommonPartList();
675         } catch (Exception e) {
676             throw bigReThrow(e, ServiceMessages.LIST_FAILED);
677         }
678     }
679
680     /**
681      * Gets the entities referencing this Authority item instance. The service type
682      * can be passed as a query param "type", and must match a configured type
683      * for the service bindings. If not set, the type defaults to
684      * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
685      *
686      * @param parentspecifier either a CSID or one of the urn forms
687      * @param itemspecifier either a CSID or one of the urn forms
688      * @param ui the ui
689      * 
690      * @return the info for the referencing objects
691      */
692     @GET
693     @Path("{csid}/items/{itemcsid}/refObjs")
694     @Produces("application/xml")
695     public AuthorityRefDocList getReferencingObjects(
696             @PathParam("csid") String parentspecifier,
697             @PathParam("itemcsid") String itemspecifier,
698             @Context UriInfo ui) {
699         AuthorityRefDocList authRefDocList = null;
700         try {
701             MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
702
703             String parentcsid = lookupParentCSID(parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", queryParams);
704
705             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), queryParams);
706             String itemcsid = lookupItemCSID(itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS", ctx);
707
708             // Note that we have to create the service context for the Items, not the main service
709             // We omit the parentShortId, only needed when doing a create...
710             DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid, null);
711             RepositoryClient repoClient = getRepositoryClient(ctx);
712             DocumentFilter myFilter = handler.getDocumentFilter();
713             String serviceType = ServiceBindingUtils.SERVICE_TYPE_PROCEDURE;
714             List<String> list = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
715             if (list != null) {
716                 serviceType = list.get(0);
717             }
718             DocumentWrapper<DocumentModel> docWrapper = repoClient.getDoc(ctx, itemcsid);
719             DocumentModel docModel = docWrapper.getWrappedObject();
720             String refName = (String) docModel.getPropertyValue(AuthorityItemJAXBSchema.REF_NAME);
721
722             authRefDocList = RefNameServiceUtils.getAuthorityRefDocs(ctx,
723                     repoClient,
724                     serviceType,
725                     refName,
726                     myFilter.getPageSize(), myFilter.getStartPage(), true /*computeTotal*/);
727         } catch (Exception e) {
728             throw bigReThrow(e, ServiceMessages.GET_FAILED);
729         }
730         if (authRefDocList == null) {
731             Response response = Response.status(Response.Status.NOT_FOUND).entity(
732                     "Get failed, the requested Item CSID:" + itemspecifier + ": was not found.").type(
733                     "text/plain").build();
734             throw new WebApplicationException(response);
735         }
736         return authRefDocList;
737     }
738
739     /**
740      * Gets the authority terms used in the indicated Authority item.
741      *
742      * @param parentspecifier either a CSID or one of the urn forms
743      * @param itemspecifier either a CSID or one of the urn forms
744      * @param ui passed to include additional parameters, like pagination controls
745      *
746      * @return the authority refs for the Authority item.
747      */
748     @GET
749     @Path("{csid}/items/{itemcsid}/authorityrefs")
750     @Produces("application/xml")
751     public AuthorityRefList getAuthorityItemAuthorityRefs(
752             @PathParam("csid") String parentspecifier,
753             @PathParam("itemcsid") String itemspecifier,
754             @Context UriInfo ui) {
755         AuthorityRefList authRefList = null;
756         try {
757             // Note that we have to create the service context for the Items, not the main service
758             MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
759             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
760
761             String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", queryParams);
762
763             ctx = createServiceContext(getItemServiceName(), queryParams);
764             // We omit the parentShortId, only needed when doing a create...
765             RemoteDocumentModelHandlerImpl handler =
766                     (RemoteDocumentModelHandlerImpl) createItemDocumentHandler(ctx, parentcsid, null);
767
768             String itemcsid = lookupItemCSID(itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS", ctx);
769
770             DocumentWrapper<DocumentModel> docWrapper = getRepositoryClient(ctx).getDoc(ctx, itemcsid);
771             List<String> authRefFields =
772                     ((MultipartServiceContextImpl) ctx).getCommonPartPropertyValues(
773                     ServiceBindingUtils.AUTH_REF_PROP, ServiceBindingUtils.QUALIFIED_PROP_NAMES);
774             authRefList = handler.getAuthorityRefs(docWrapper, authRefFields);
775         } catch (Exception e) {
776             throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
777         }
778         return authRefList;
779     }
780
781     /**
782      * Update authorityItem.
783      * 
784      * @param parentspecifier either a CSID or one of the urn forms
785      * @param itemspecifier either a CSID or one of the urn forms
786      *
787      * @return the multipart output
788      */
789     @PUT
790     @Path("{csid}/items/{itemcsid}")
791     public byte[] updateAuthorityItem(
792                 @Context ResourceMap resourceMap, 
793             @Context UriInfo ui,
794             @PathParam("csid") String parentspecifier,
795             @PathParam("itemcsid") String itemspecifier,
796             String xmlPayload) {
797         PoxPayloadOut result = null;
798         try {
799             PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
800             // Note that we have to create the service context for the Items, not the main service
801             //Laramie CSPACE-3175.  passing null for queryParams, because prior to this refactor, the code moved to lookupParentCSID in this instance called the version of getServiceContext() that passes null
802             String parentcsid = lookupParentCSID(parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
803
804             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), theUpdate);
805             ctx.setResourceMap(resourceMap);
806             String itemcsid = lookupItemCSID(itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM", ctx);
807
808             // We omit the parentShortId, only needed when doing a create...
809             DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid, null);
810             ctx.setUriInfo(ui);
811             getRepositoryClient(ctx).update(ctx, itemcsid, handler);
812             result = ctx.getOutput();
813
814         } catch (Exception e) {
815             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
816         }
817         return result.getBytes();
818     }
819
820     /**
821      * Delete authorityItem.
822      * 
823      * @param parentcsid the parentcsid
824      * @param itemcsid the itemcsid
825      * 
826      * @return the response
827      */
828     @DELETE
829     @Path("{csid}/items/{itemcsid}")
830     public Response deleteAuthorityItem(
831             @PathParam("csid") String parentcsid,
832             @PathParam("itemcsid") String itemcsid) {
833         //try{
834         if (logger.isDebugEnabled()) {
835             logger.debug("deleteAuthorityItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
836         }
837         try {
838             ensureCSID(parentcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
839             ensureCSID(itemcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
840             //Laramie, removing this catch, since it will surely fail below, since itemcsid or parentcsid will be null.
841             // }catch (Throwable t){
842             //    System.out.println("ERROR in setting up DELETE: "+t);
843             // }
844             // try {
845             // Note that we have to create the service context for the Items, not the main service
846             ServiceContext ctx = createServiceContext(getItemServiceName());
847             getRepositoryClient(ctx).delete(ctx, itemcsid);
848             return Response.status(HttpResponseCodes.SC_OK).build();
849         } catch (Exception e) {
850             throw bigReThrow(e, ServiceMessages.DELETE_FAILED + "  itemcsid: " + itemcsid + " parentcsid:" + parentcsid);
851         }
852     }
853     public final static String hierarchy = "hierarchy";
854
855     @GET
856     @Path("{csid}/items/{itemcsid}/" + hierarchy)
857     @Produces("application/xml")
858     public String getHierarchy(@PathParam("csid") String csid,
859             @PathParam("itemcsid") String itemcsid,
860             @Context UriInfo ui) throws Exception {
861         try {
862             // All items in dive can look at their child uri's to get uri.  So we calculate the very first one.  We could also do a GET and look at the common part uri field, but why...?
863             String calledUri = ui.getPath();
864             String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
865             ServiceContext ctx = createServiceContext(getItemServiceName());
866             ctx.setUriInfo(ui);
867             String direction = ui.getQueryParameters().getFirst(Hierarchy.directionQP);
868             if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
869                 return Hierarchy.surface(ctx, itemcsid, uri);
870             } else {
871                 return Hierarchy.dive(ctx, itemcsid, uri);
872             }
873         } catch (Exception e) {
874             throw bigReThrow(e, "Error showing hierarchy", itemcsid);
875         }
876     }
877 }