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