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