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