]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
efca5dcebf8ac723724eb880e3adf8c78947d72f
[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.util.List;
27 import java.util.Map;
28
29 import javax.ws.rs.Consumes;
30 import javax.ws.rs.DELETE;
31 import javax.ws.rs.GET;
32 import javax.ws.rs.POST;
33 import javax.ws.rs.PUT;
34 import javax.ws.rs.Path;
35 import javax.ws.rs.PathParam;
36 import javax.ws.rs.Produces;
37 import javax.ws.rs.core.Context;
38 import javax.ws.rs.core.MultivaluedMap;
39 import javax.ws.rs.core.Request;
40 import javax.ws.rs.core.Response;
41 import javax.ws.rs.core.UriBuilder;
42 import javax.ws.rs.core.UriInfo;
43 import javax.ws.rs.core.Response.ResponseBuilder;
44
45 import org.collectionspace.services.client.IClientQueryParams;
46 import org.collectionspace.services.client.IQueryManager;
47 import org.collectionspace.services.client.PoxPayload;
48 import org.collectionspace.services.client.PoxPayloadIn;
49 import org.collectionspace.services.client.PoxPayloadOut;
50 import org.collectionspace.services.client.XmlTools;
51 import org.collectionspace.services.client.workflow.WorkflowClient;
52
53 import org.collectionspace.services.common.CSWebApplicationException;
54 import org.collectionspace.services.common.NuxeoBasedResource;
55 import org.collectionspace.services.common.ResourceMap;
56 import org.collectionspace.services.common.ServiceMain;
57 import org.collectionspace.services.common.ServiceMessages;
58 import org.collectionspace.services.common.StoredValuesUriTemplate;
59 import org.collectionspace.services.common.UriInfoWrapper;
60 import org.collectionspace.services.common.UriTemplateFactory;
61 import org.collectionspace.services.common.UriTemplateRegistryKey;
62 import org.collectionspace.services.common.api.RefName;
63 import org.collectionspace.services.common.api.RefNameUtils;
64 import org.collectionspace.services.common.api.RefNameUtils.AuthorityTermInfo;
65 import org.collectionspace.services.common.api.Tools;
66 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
67 import org.collectionspace.services.common.authorityref.AuthorityRefList;
68 import org.collectionspace.services.common.context.JaxRsContext;
69 import org.collectionspace.services.common.context.MultipartServiceContext;
70 import org.collectionspace.services.common.context.RemoteServiceContext;
71 import org.collectionspace.services.common.context.ServiceBindingUtils;
72 import org.collectionspace.services.common.context.ServiceContext;
73 import org.collectionspace.services.common.document.DocumentException;
74 import org.collectionspace.services.common.document.DocumentFilter;
75 import org.collectionspace.services.common.document.DocumentHandler;
76 import org.collectionspace.services.common.document.DocumentNotFoundException;
77 import org.collectionspace.services.common.document.DocumentReferenceException;
78 import org.collectionspace.services.common.document.DocumentWrapper;
79 import org.collectionspace.services.common.document.Hierarchy;
80 import org.collectionspace.services.common.query.QueryManager;
81 import org.collectionspace.services.common.repository.RepositoryClient;
82 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler;
83 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler;
84 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
85 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.SpecifierForm;
86 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
87
88 import org.collectionspace.services.config.ClientType;
89 import org.collectionspace.services.config.service.ServiceBindingType;
90 import org.collectionspace.services.jaxb.AbstractCommonList;
91 import org.collectionspace.services.jaxb.AbstractCommonList.ListItem;
92 import org.collectionspace.services.lifecycle.TransitionDef;
93 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
94 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
95 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentFilter;
96 import org.collectionspace.services.nuxeo.client.java.NuxeoRepositoryClientImpl;
97 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
98 import org.collectionspace.services.workflow.WorkflowCommon;
99 import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;
100 import org.collectionspace.services.description.ServiceDescription;
101
102 import org.jboss.resteasy.util.HttpResponseCodes;
103 import org.nuxeo.ecm.core.api.DocumentModel;
104 import org.nuxeo.ecm.core.api.DocumentModelList;
105 import org.slf4j.Logger;
106 import org.slf4j.LoggerFactory;
107 import org.w3c.dom.Element;
108
109 /**
110  * The Class AuthorityResource.
111  */
112
113 @SuppressWarnings({"rawtypes", "unchecked"})
114 @Consumes("application/xml")
115 @Produces("application/xml")
116 public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
117         extends NuxeoBasedResource {
118
119     final Logger logger = LoggerFactory.getLogger(AuthorityResource.class);
120
121     final static String SEARCH_TYPE_TERMSTATUS = "ts";
122     public final static String hierarchy = "hierarchy";
123
124     private static final Integer PAGE_NUM_FROM_QUERYPARAMS = null;
125     private static final Integer PAGE_SIZE_FROM_QUERYPARAMS = null;
126
127     protected Class<AuthCommon> authCommonClass;
128     protected Class<?> resourceClass;
129     protected String authorityCommonSchemaName;
130     protected String authorityItemCommonSchemaName;
131     final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType(); //FIXME: REM - 3 Why is this field needed?  I see no references to it.
132
133     final static String FETCH_SHORT_ID = "_fetch_";
134     public final static String PARENT_WILDCARD = "_ALL_";
135     protected static final boolean DONT_INCLUDE_ITEMS = false;
136     protected static final boolean INCLUDE_ITEMS = true;
137
138     /**
139      * Instantiates a new Authority resource.
140      */
141     public AuthorityResource(Class<AuthCommon> authCommonClass, Class<?> resourceClass,
142             String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
143         this.authCommonClass = authCommonClass;
144         this.resourceClass = resourceClass;
145         this.authorityCommonSchemaName = authorityCommonSchemaName;
146         this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
147     }
148
149     public abstract String getItemServiceName();
150
151     public abstract String getItemTermInfoGroupXPathBase();
152
153     @Override
154     protected String getVersionString() {
155         return "$LastChangedRevision: 2617 $";
156     }
157
158     @Override
159     public Class<AuthCommon> getCommonPartClass() {
160         return authCommonClass;
161     }
162
163     /**
164      * Creates the item document handler.
165      *
166      * @param ctx the ctx
167      * @param inAuthority the in vocabulary
168      *
169      * @return the document handler
170      *
171      * @throws Exception the exception
172      */
173     protected DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> createItemDocumentHandler(
174             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
175             String inAuthority, String containerShortIdentifier)
176             throws Exception {
177         String authorityRefNameBase;
178         AuthorityItemDocumentModelHandler<?> docHandler;
179
180         if (containerShortIdentifier == null) {
181             authorityRefNameBase = null;
182         } else {
183             ServiceContext<PoxPayloadIn, PoxPayloadOut> containerCtx = createServiceContext(getServiceName());
184             if (containerShortIdentifier.equals(FETCH_SHORT_ID)) { // We need to fetch this from the repo
185                 if (ctx.getCurrentRepositorySession() != null) {
186                     containerCtx.setCurrentRepositorySession(ctx.getCurrentRepositorySession()); // We need to use the current repo session if one exists
187                 }
188                 // Get from parent document
189                 containerShortIdentifier = getAuthShortIdentifier(containerCtx, inAuthority);
190             }
191             authorityRefNameBase = buildAuthorityRefNameBase(containerCtx, containerShortIdentifier);
192         }
193
194         docHandler = (AuthorityItemDocumentModelHandler<?>) createDocumentHandler(ctx,
195                 ctx.getCommonPartLabel(getItemServiceName()),
196                 authCommonClass);
197         // FIXME - Richard and Aron think the following three lines should
198         // be in the constructor for the AuthorityItemDocumentModelHandler
199         // because all three are required fields.
200         docHandler.setInAuthority(inAuthority);
201         docHandler.setAuthorityRefNameBase(authorityRefNameBase);
202         docHandler.setItemTermInfoGroupXPathBase(getItemTermInfoGroupXPathBase());
203         return docHandler;
204     }
205
206     public String getAuthShortIdentifier(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String authCSID)
207             throws DocumentNotFoundException, DocumentException {
208         String shortIdentifier = null;
209
210         try {
211             AuthorityDocumentModelHandler<?> handler = (AuthorityDocumentModelHandler<?>) createDocumentHandler(ctx);
212             shortIdentifier = handler.getShortIdentifier(ctx, authCSID, authorityCommonSchemaName);
213         } catch (Exception e) {
214             if (logger.isDebugEnabled()) {
215                 logger.debug("Caught exception ", e);
216             }
217             throw new DocumentException(e);
218         }
219
220         return shortIdentifier;
221     }
222
223     protected String buildAuthorityRefNameBase(
224             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String shortIdentifier) {
225         RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
226                 ctx.getServiceName(),
227                 null,    // Only use shortId form!!!
228                 shortIdentifier, null);
229         return authority.toString();
230     }
231
232     public static class CsidAndShortIdentifier {
233         String CSID;
234         String shortIdentifier;
235     }
236
237     protected String lookupParentCSID(String parentspecifier, String method,
238             String op, UriInfo uriInfo) throws Exception {
239         CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(NULL_CONTEXT,
240                 parentspecifier, method, op, uriInfo);
241         return tempResult.CSID;
242     }
243
244     protected String lookupParentCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String parentspecifier, String method,
245             String op, UriInfo uriInfo) throws Exception {
246         CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(ctx,
247                 parentspecifier, method, op, uriInfo);
248         return tempResult.CSID;
249     }
250
251
252     private CsidAndShortIdentifier lookupParentCSIDAndShortIdentifer(
253             ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx, // Ok to be null
254             String parentIdentifier,
255             String method,
256             String op,
257             UriInfo uriInfo)
258             throws Exception {
259         CsidAndShortIdentifier result = new CsidAndShortIdentifier();
260         Specifier parentSpec = Specifier.getSpecifier(parentIdentifier, method, op);
261
262         String parentcsid;
263         String parentShortIdentifier;
264         if (parentSpec.form == SpecifierForm.CSID) {
265             parentShortIdentifier = null;
266             parentcsid = parentSpec.value;
267             // Uncomment when app layer is ready to integrate
268             // Uncommented since refNames are currently only generated if not present - ADR CSPACE-3178
269             parentShortIdentifier = FETCH_SHORT_ID;
270         } else {
271             parentShortIdentifier = parentSpec.value;
272             String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, parentShortIdentifier);
273             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getServiceName(), uriInfo);
274             CoreSessionInterface repoSession = null;
275             if (existingCtx != null) {
276                 repoSession = (CoreSessionInterface) existingCtx.getCurrentRepositorySession();  // We want to use the thread's current repo session
277             }
278             parentcsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, whereClause); //FIXME: REM - If the parent has been soft-deleted, should we be looking for the item?
279         }
280
281         result.CSID = parentcsid;
282         result.shortIdentifier = parentShortIdentifier;
283
284         return result;
285     }
286
287     public String lookupItemCSID(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext, String itemSpecifier, String parentCsid, String method, String op)
288             throws Exception {
289         String itemCsid;
290         Specifier itemSpec = Specifier.getSpecifier(itemSpecifier, method, op);
291
292         if (itemSpec.form == SpecifierForm.CSID) {
293             itemCsid = itemSpec.value;
294         } else {
295             CoreSessionInterface repoSession = null;
296             MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(getItemServiceName());
297
298             if (existingContext != null) {
299                 repoSession = (CoreSessionInterface) existingContext.getCurrentRepositorySession();  // We want to use the thread's current repo session
300             }
301
302             String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentCsid);
303             itemCsid = getRepositoryClient(ctx).findDocCSID(repoSession, ctx, itemWhereClause); //FIXME: REM - Should we be looking for the 'wf_deleted' query param and filtering on it?
304         }
305
306         return itemCsid;
307     }
308
309     /*
310      * Generally, callers will first call RefName.AuthorityItem.parse with a refName, and then
311      * use the returned item.inAuthority.resource and a resourceMap to get a service-specific
312      * Resource. They then call this method on that resource.
313      */
314     @Override
315        public DocumentModel getDocModelForAuthorityItem(CoreSessionInterface repoSession, RefName.AuthorityItem item)
316                throws Exception, DocumentNotFoundException {
317         if (item == null) {
318             return null;
319         }
320         String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, item.getParentShortIdentifier());
321         // Ensure we have the right context.
322         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(item.inAuthority.resource);
323
324         // HACK - this really must be moved to the doc handler, not here. No Nuxeo specific stuff here!
325         NuxeoRepositoryClientImpl client = (NuxeoRepositoryClientImpl)getRepositoryClient(ctx);
326         String parentcsid = client.findDocCSID(repoSession, ctx, whereClause);
327
328         String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, item.getShortIdentifier(), parentcsid);
329         ctx = createServiceContext(getItemServiceName());
330         DocumentWrapper<DocumentModel> docWrapper = client.findDoc(repoSession, ctx, itemWhereClause);
331         DocumentModel docModel = docWrapper.getWrappedObject();
332         return docModel;
333     }
334
335
336     @POST
337     public Response createAuthority(
338             @Context ResourceMap resourceMap,
339             @Context UriInfo uriInfo,
340             String xmlPayload) {
341         //
342         // Requests to create new authorities come in on new threads. Unfortunately, we need to synchronize those threads on this block because, as of 8/27/2015, we can't seem to get Nuxeo
343         // transaction code to deal with a database level UNIQUE constraint violations on the 'shortidentifier' column of the vocabularies_common table.
344         // Therefore, to prevent having multiple authorities with the same shortid, we need to synchronize
345         // the code that creates new authorities.  The authority document model handler will first check for authorities with the same short id before
346         // trying to create a new authority.
347         //
348         synchronized(AuthorityResource.class) {
349             try {
350                 PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
351                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(input);
352                 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
353
354                 String csid = getRepositoryClient(ctx).create(ctx, handler);
355                 UriBuilder path = UriBuilder.fromResource(resourceClass);
356                 path.path("" + csid);
357                 Response response = Response.created(path.build()).build();
358                 return response;
359             } catch (Exception e) {
360                 throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
361             }
362         }
363     }
364
365     protected boolean supportsReplicating(String tenantId, String serviceName) {
366         boolean result = false;
367
368         ServiceBindingType sb = getTenantBindingsReader().getServiceBinding(tenantId, getServiceName());
369         result = sb.isSupportsReplicating();
370
371         return result;
372     }
373
374     /**
375      * Synchronizes the authority and its items/terms with a Shared Authority Server.
376      *
377      * @param specifier either a CSID or one of the urn forms
378      *
379      * @return the authority
380      */
381     @POST
382     @Path("{csid}/sync")
383     public byte[] synchronize(
384             @Context Request request,
385             @Context UriInfo uriInfo,
386             @PathParam("csid") String identifier) {
387         uriInfo = new UriInfoWrapper(uriInfo);
388         byte[] result;
389         boolean neededSync = false;
390         PoxPayloadOut payloadOut = null;
391         Specifier specifier;
392
393         //
394         // Prevent multiple SAS synchronizations from occurring simultaneously by synchronizing this method.
395         //
396         synchronized(AuthorityResource.class) {
397             try {
398                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
399                 /*
400                  * Make sure this authority service supports synchronization
401                  */
402                 if (supportsReplicating(ctx.getTenantId(), ctx.getServiceName()) == false) {
403                     throw new DocumentException(Response.Status.FORBIDDEN.getStatusCode());
404                 }
405                 AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler)createDocumentHandler(ctx);
406                 specifier = Specifier.getSpecifier(identifier, "getAuthority", "GET");
407                 handler.setShouldUpdateRevNumber(AuthorityServiceUtils.DONT_UPDATE_REV); // Never update rev number on sync calls
408                 neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
409                 payloadOut = ctx.getOutput();
410             } catch (Exception e) {
411                 throw bigReThrow(e, ServiceMessages.SYNC_FAILED, identifier);
412             }
413
414             //
415             // If a sync was needed and was successful, return a copy of the updated resource.  Acts like an UPDATE.
416             //
417             if (neededSync == true) {
418                 result = payloadOut.getBytes();
419             } else {
420                 result = String.format("Authority resource '%s' was already in sync with shared authority server.",
421                         specifier.value).getBytes();
422                 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
423                 throw new CSWebApplicationException(response);
424             }
425         }
426
427         return result;
428     }
429
430     /*
431      * Builds a cached JAX-RS response.
432      */
433     protected Response buildResponse(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, PoxPayloadOut payloadOut) {
434         Response result = null;
435
436         ResponseBuilder responseBuilder = Response.ok(payloadOut.getBytes());
437         this.setCacheControl(ctx, responseBuilder);
438         result = responseBuilder.build();
439
440         return result;
441     }
442
443     /**
444      * Gets the authority.
445      *
446      * @param specifier either a CSID or one of the urn forms
447      *
448      * @return the authority
449      */
450     @GET
451     @Path("{csid}")
452     @Override
453     public Response get(
454             @Context Request request,
455             @Context ResourceMap resourceMap,
456             @Context UriInfo uriInfo,
457             @PathParam("csid") String specifier) {
458         Response result = null;
459         uriInfo = new UriInfoWrapper(uriInfo);
460         PoxPayloadOut payloadout = null;
461
462         try {
463             //
464             // If the specifier is a fully qualified authority term refname, then return the term payload in the response
465             //
466             if (RefNameUtils.isTermRefname(specifier)) {
467                 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(specifier);
468                 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
469                 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
470                 result = this.getAuthorityItemResponse(request, uriInfo, resourceMap, parentIdentifier, itemIdentifier);
471             } else {
472                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(request, uriInfo);
473                 payloadout = getAuthority(ctx, request, uriInfo, specifier, DONT_INCLUDE_ITEMS);
474                 result = buildResponse(ctx, payloadout);
475             }
476         } catch (Exception e) {
477             throw bigReThrow(e, ServiceMessages.GET_FAILED, specifier);
478         }
479
480         if (result == null) {
481             Response response = Response.status(Response.Status.NOT_FOUND).entity(
482                     "GET request failed. The requested Authority specifier:" + specifier + ": was not found.").type(
483                     "text/plain").build();
484             throw new CSWebApplicationException(response);
485         }
486
487         return result;
488     }
489
490     protected PoxPayloadOut getAuthority(
491             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
492             Request request,
493             UriInfo uriInfo,
494             String specifier,
495             boolean includeItems) throws Exception {
496         uriInfo = new UriInfoWrapper(uriInfo);
497         PoxPayloadOut payloadout = null;
498
499         DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> docHandler = createDocumentHandler(ctx);
500         Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
501         if (spec.form == SpecifierForm.CSID) {
502             if (logger.isDebugEnabled()) {
503                 logger.debug("getAuthority with csid=" + spec.value);
504             }
505             getRepositoryClient(ctx).get(ctx, spec.value, docHandler);
506         } else {
507             String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
508             DocumentFilter myFilter = new NuxeoDocumentFilter(whereClause, 0, 1);
509             docHandler.setDocumentFilter(myFilter);
510             getRepositoryClient(ctx).get(ctx, docHandler);
511         }
512
513         payloadout = ctx.getOutput();
514         if (includeItems == true) {
515             AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
516             payloadout.addPart(PoxPayload.ABSTRACT_COMMON_LIST_ROOT_ELEMENT_LABEL, itemsList);
517         }
518
519         return payloadout;
520     }
521
522     /**
523      * Finds and populates the authority list.
524      *
525      * @param ui the ui
526      *
527      * @return the authority list
528      */
529     @GET
530     @Produces("application/xml")
531     public AbstractCommonList getAuthorityList(@Context UriInfo uriInfo) { //FIXME - REM 5/3/2012 - This is not reachable from the JAX-RS dispatcher.  Instead the equivalent method in ResourceBase is getting called.
532         uriInfo = new UriInfoWrapper(uriInfo);
533         AbstractCommonList result = null;
534
535         try {
536             MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
537             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
538
539             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
540             DocumentFilter myFilter = handler.getDocumentFilter();
541             // Need to make the default sort order for authority items
542             // be on the displayName field
543             String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
544             if (orderBy == null || orderBy.isEmpty()) {
545                 String qualifiedDisplayNameField = authorityCommonSchemaName + ":"
546                         + AuthorityItemJAXBSchema.DISPLAY_NAME;
547                 myFilter.setOrderByClause(qualifiedDisplayNameField);
548             }
549             String nameQ = queryParams.getFirst("refName");
550             if (nameQ != null) {
551                 myFilter.setWhereClause(authorityCommonSchemaName + ":refName='" + nameQ + "'");
552             }
553             //getRepositoryClient(ctx).getFiltered(ctx, handler); # Something here?
554             String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
555             result = search(ctx, handler, uriInfo, orderBy, null, advancedSearch, null);
556             result = handler.getCommonPartList();
557         } catch (Exception e) {
558             throw bigReThrow(e, ServiceMessages.GET_FAILED);
559         }
560
561         return result;
562     }
563
564     /**
565      * Overriding this methods to see if we should update the revision number during the update.  We don't
566      * want to update the rev number of synchronization operations.
567      */
568     @Override
569     protected PoxPayloadOut update(String csid,
570             PoxPayloadIn theUpdate, // not used in this method, but could be used by an overriding method
571             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx)
572             throws Exception {
573         AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler) createDocumentHandler(ctx);
574         Boolean shouldUpdateRev = (Boolean) ctx.getProperty(AuthorityServiceUtils.SHOULD_UPDATE_REV_PROPERTY);
575         if (shouldUpdateRev != null) {
576             handler.setShouldUpdateRevNumber(shouldUpdateRev);
577         }
578         getRepositoryClient(ctx).update(ctx, csid, handler);
579         return ctx.getOutput();
580     }
581
582     /**
583      * Update authority.
584      *
585      * @param specifier the csid or id
586      *
587      * @return the multipart output
588      */
589     @PUT
590     @Path("{csid}")
591     public byte[] updateAuthority(
592             @Context Request request,
593             @Context ResourceMap resourceMap,
594             @Context UriInfo uriInfo,
595             @PathParam("csid") String specifier,
596             String xmlPayload) {
597         PoxPayloadOut result = null;
598         try {
599             PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
600             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
601             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
602             Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
603             String csid = getCsid(ctx, spec);
604             getRepositoryClient(ctx).update(ctx, csid, handler);
605             result = ctx.getOutput();
606         } catch (Exception e) {
607             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
608         }
609         return result.getBytes();
610     }
611
612     /**
613      * Delete all the items in an authority list.
614      *
615      * @param specifier
616      * @param uriInfo
617      * @return
618      */
619     @DELETE
620     @Path("{csid}/items")
621     public Response deleteAuthorityItemList(@PathParam("csid") String specifier,
622             @Context UriInfo uriInfo) {
623         uriInfo = new UriInfoWrapper(uriInfo);
624
625         try {
626             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
627             RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient = this.getRepositoryClient(ctx);
628
629             CoreSessionInterface repoSession = repoClient.getRepositorySession(ctx);
630             try {
631                 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
632                 //
633                 // Delete all the items one by one
634                 //
635                 AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
636                 for (ListItem item : itemsList.getListItem()) {
637                     deleteAuthorityItem(ctx, specifier, getCsid(item), AuthorityServiceUtils.UPDATE_REV);
638                 }
639             } catch (Throwable t) {
640                 repoSession.setTransactionRollbackOnly();
641                 throw t;
642             } finally {
643                 repoClient.releaseRepositorySession(ctx, repoSession);
644             }
645
646             return Response.status(HttpResponseCodes.SC_OK).build();
647         } catch (Exception e) {
648             throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
649         }
650     }
651
652     /**
653      * Delete authority
654      *
655      * @param csid the csid or a URN specifier form -e.g., urn:cspace:name(OurMuseumPersonAuthority)
656      *
657      * @return the response
658      */
659     @DELETE
660     @Path("{csid}")
661     public Response deleteAuthority( // # Delete this authority and all of it's items.
662             @Context Request request,
663             @Context UriInfo uriInfo,
664             @PathParam("csid") String specifier) {
665         uriInfo = new UriInfoWrapper(uriInfo);
666
667         if (logger.isDebugEnabled()) {
668             logger.debug("deleteAuthority with specifier=" + specifier);
669         }
670
671         try {
672             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
673             Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
674             RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient = this.getRepositoryClient(ctx);
675
676             CoreSessionInterface repoSession = repoClient.getRepositorySession(ctx);
677             try {
678                 DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
679                 //
680                 // First try to delete all the items
681                 //
682                 AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
683                 for (ListItem item : itemsList.getListItem()) {
684                     deleteAuthorityItem(ctx, specifier, getCsid(item), AuthorityServiceUtils.UPDATE_REV);
685                 }
686
687                 //
688                 // Lastly, delete the parent/container
689                 //
690                 if (spec.form == SpecifierForm.CSID) {
691                     if (logger.isDebugEnabled()) {
692                         logger.debug("deleteAuthority with csid=" + spec.value);
693                     }
694                     ensureCSID(spec.value, ServiceMessages.DELETE_FAILED, "Authority.csid");
695                     getRepositoryClient(ctx).delete(ctx, spec.value, handler);
696                 } else {
697                     if (logger.isDebugEnabled()) {
698                         logger.debug("deleteAuthority with specifier=" + spec.value);
699                     }
700                     String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
701                     getRepositoryClient(ctx).deleteWithWhereClause(ctx, whereClause, handler);
702                 }
703             } catch (Throwable t) {
704                 repoSession.setTransactionRollbackOnly();
705                 throw t;
706             } finally {
707                 repoClient.releaseRepositorySession(ctx, repoSession);
708             }
709
710             return Response.status(HttpResponseCodes.SC_OK).build();
711         } catch (Exception e) {
712             throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
713         }
714     }
715
716     protected String getCsid(ListItem item) {
717         String result = null;
718
719         for (Element ele : item.getAny()) {
720             String elementName = ele.getTagName().toLowerCase();
721             if (elementName.equals("csid")) {
722                 result = ele.getTextContent();
723                 break;
724             }
725         }
726
727         return result;
728     }
729
730     /**
731      *
732      * @param ctx
733      * @param parentspecifier        - ID of the container. Can be URN or CSID form
734      * @param shouldUpdateRevNumber - Indicates if the revision number should be updated on create -won't do this when synching with SAS
735      * @param isProposed                - In a shared authority context, indicates if this item just a proposed item and not yet part of the SAS authority
736      * @return
737      * @throws Exception
738      */
739     protected Response createAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String parentIdentifier,
740             boolean shouldUpdateRevNumber,
741             boolean isProposed,
742             boolean isSasItem) throws Exception {
743         Response result = null;
744
745         // Note: must have the parentShortId, to do the create.
746         CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "createAuthorityItem", "CREATE_ITEM", null);
747         AuthorityItemDocumentModelHandler handler =
748             (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
749         handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
750         handler.setIsProposed(isProposed);
751         handler.setIsSASItem(isSasItem);
752         // Make the client call
753         String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
754
755         // Build the JAX-RS response
756         UriBuilder path = UriBuilder.fromResource(resourceClass);
757         path.path(parent.CSID + "/items/" + itemcsid);
758         result = Response.created(path.build()).build();
759
760         return result;
761     }
762
763     public PoxPayloadOut updateAuthorityItem(
764             ServiceContext<PoxPayloadIn, PoxPayloadOut> itemServiceCtx, // Ok to be null.  Will be null on PUT calls, but not on sync calls
765             ResourceMap resourceMap,
766             UriInfo uriInfo,
767             String parentspecifier,
768             String itemspecifier,
769             PoxPayloadIn theUpdate,
770             boolean shouldUpdateRevNumber,
771             Boolean isProposed,
772             Boolean isSASItem
773             ) throws Exception {
774         PoxPayloadOut result = null;
775
776         CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
777         String parentcsid = csidAndShortId.CSID;
778         String parentShortId = csidAndShortId.shortIdentifier;
779         //
780         // If the itemServiceCtx context is not null, use it.  Otherwise, create a new context
781         //
782         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = itemServiceCtx;
783         if (ctx == null) {
784             ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
785         } else {
786             ctx.setInput(theUpdate); // the update payload
787         }
788
789         String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM"); //use itemServiceCtx if it is not null
790
791         // We omit the parentShortId, only needed when doing a create...
792         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
793         handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
794         //
795         // Update the SAS fields if either value is non-null
796         //
797         boolean updateSASFields = isProposed != null || isSASItem != null;
798         handler.setshouldUpdateSASFields(updateSASFields);
799         if (updateSASFields == true) {
800             handler.setshouldUpdateSASFields(true);
801             if (isProposed != null) {
802                 handler.setIsProposed(isProposed);
803             }
804             if (isSASItem != null) {
805                 handler.setIsSASItem(isSASItem);
806             }
807         }
808
809         getRepositoryClient(ctx).update(ctx, itemcsid, handler);
810         result = ctx.getOutput();
811
812         return result;
813     }
814
815     /**
816      * Called with an existing context.
817      * @param parentCtx
818      * @param parentIdentifier
819      * @param input
820      * @return
821      * @throws Exception
822      */
823     public Response createAuthorityItemWithParentContext(ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx,
824             String parentIdentifier,
825             PoxPayloadIn input,
826             boolean shouldUpdateRevNumber,
827             boolean isProposed,
828             boolean isSASItem) throws Exception {
829         Response result = null;
830
831         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input,
832                 parentCtx.getResourceMap(), parentCtx.getUriInfo());
833         if (parentCtx.getCurrentRepositorySession() != null) {
834             ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession());
835         }
836         result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed, isSASItem);
837
838         return result;
839     }
840
841     /*************************************************************************
842      * Create an AuthorityItem - this is a sub-resource of Authority
843      * @param specifier either a CSID or one of the urn forms
844      * @return Authority item response
845      *************************************************************************/
846     @POST
847     @Path("{csid}/items")
848     public Response createAuthorityItem(
849             @Context ResourceMap resourceMap,
850             @Context UriInfo uriInfo,
851             @PathParam("csid") String parentIdentifier, // Either a CSID or a URN form -e.g., a8ad38ec-1d7d-4bf2-bd31 or urn:cspace:name(bugsbunny)
852             String xmlPayload) {
853         uriInfo = new UriInfoWrapper(uriInfo);
854         Response result = null;
855
856         try {
857             PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
858             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
859             result = this.createAuthorityItem(ctx, parentIdentifier, AuthorityServiceUtils.UPDATE_REV,
860                     AuthorityServiceUtils.PROPOSED, AuthorityServiceUtils.NOT_SAS_ITEM);
861         } catch (Exception e) {
862             throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
863         }
864
865         return result;
866     }
867
868     @GET
869     @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
870     public byte[] getItemWorkflow(
871             @PathParam("csid") String csid,
872             @PathParam("itemcsid") String itemcsid) {
873         PoxPayloadOut result = null;
874
875         try {
876             ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
877             String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
878
879             MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
880             WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
881             ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
882             getRepositoryClient(ctx).get(ctx, itemcsid, handler);
883             result = ctx.getOutput();
884         } catch (Exception e) {
885             throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
886         }
887         return result.getBytes();
888     }
889
890     /*
891      * We should consider changing this code.  The RepositoryClient (from call to getRepositoryClient) could support a call doWorkflowTransition() instead?
892      */
893     @Override
894     @PUT
895     @Path("{csid}" + WorkflowClient.SERVICE_PATH + "/" + "{transition}")
896     public byte[] updateWorkflowWithTransition(
897             @Context UriInfo uriInfo,
898             @PathParam("csid") String specifier,
899             @PathParam("transition") String transition) {
900         PoxPayloadOut result = null;
901
902         Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
903         String csid = null;
904         try {
905             csid = getCsid(null, spec);
906             result = updateWorkflowWithTransition(NULL_CONTEXT, uriInfo, csid, transition);
907         } catch (Exception e) {
908             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
909         }
910
911         return result.getBytes();
912     }
913
914     //FIXME: This method is almost identical to the method org.collectionspace.services.common.updateWorkflowWithTransition() so
915     // they should be consolidated -be DRY (D)on't (R)epeat (Y)ourself.
916     @PUT
917     @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
918     public byte[] updateItemWorkflowWithTransition(
919             @Context UriInfo uriInfo,
920             @PathParam("csid") String parentIdentifier,
921             @PathParam("itemcsid") String itemIdentifier,
922             @PathParam("transition") String transition) {
923         uriInfo = new UriInfoWrapper(uriInfo);
924         PoxPayloadOut result = null;
925
926         try {
927             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
928             result = updateItemWorkflowWithTransition(ctx,
929                     parentIdentifier, itemIdentifier, transition, AuthorityServiceUtils.UPDATE_REV);
930         } catch (Exception e) {
931             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, parentIdentifier);
932         }
933
934         return result.getBytes();
935     }
936
937     /**
938      * Update an authority item's workflow state.
939      * @param existingContext
940      * @param csid
941      * @param itemcsid
942      * @param transition
943      * @return
944      * @throws DocumentReferenceException
945      */
946     public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
947             String parentIdentifier,
948             String itemIdentifier,
949             String transition,
950             boolean updateRevNumber) throws DocumentReferenceException {
951         PoxPayloadOut result = null;
952
953         try {
954             //
955             // We need CSIDs for both the parent authority and the authority item
956             //
957             CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(existingContext, parentIdentifier, "updateItemWorkflowWithTransition(parent)", "UPDATE_ITEM", null);
958             String itemCsid = lookupItemCSID(existingContext, itemIdentifier, csidAndShortId.CSID, "updateAuthorityItem(item)", "UPDATE_ITEM");
959
960             //
961             // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
962             //
963             PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(),
964                     WorkflowClient.SERVICE_COMMONPART_NAME);
965             MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
966             if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
967                 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());// If a repo session is already open, we need to use it and not create a new one
968             }
969             //
970             // Create a service context and document handler for the target resource -not the workflow resource itself.
971             //
972             ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName(), existingContext.getUriInfo());
973             AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
974             targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
975             ctx.setProperty(WorkflowClient.TARGET_DOCHANDLER, targetDocHandler); //added as a context param for the workflow document handler -it will call the parent's dochandler "prepareForWorkflowTranstion" method
976             //
977             // When looking for the document, we need to use the parent/target resource's workspace name -not the "workflow" workspace name
978             //
979             String targetWorkspaceName = targetCtx.getRepositoryWorkspaceName();
980             ctx.setRespositoryWorkspaceName(targetWorkspaceName); //find the document in the parent's workspace
981
982             // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
983             TransitionDef transitionDef = getTransitionDef(targetCtx, transition);
984             if (transitionDef == null) {
985                 throw new DocumentException(String.format("The document with ID='%s' does not support the workflow transition '%s'.",
986                         itemIdentifier, transition));
987             }
988             ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
989
990             WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
991             getRepositoryClient(ctx).update(ctx, itemCsid, handler);
992             result = ctx.getOutput();
993         } catch (DocumentReferenceException de) {
994             throw de;
995         } catch (Exception e) {
996             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemIdentifier);
997         }
998
999         return result;
1000     }
1001
1002     protected PoxPayloadOut getAuthorityItem(
1003             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
1004             String parentIdentifier,
1005             String itemIdentifier) throws Exception {
1006         PoxPayloadOut result = null;
1007
1008         String parentcsid = lookupParentCSID(ctx, parentIdentifier, "getAuthorityItem(parent)", "GET_ITEM", null);
1009         // We omit the parentShortId, only needed when doing a create...
1010         DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
1011
1012         Specifier itemSpec = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem(item)", "GET_ITEM");
1013         if (itemSpec.form == SpecifierForm.CSID) {
1014             // TODO should we assert that the item is in the passed vocab?
1015             getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
1016         } else {
1017             String itemWhereClause =
1018                     RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
1019             DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
1020             handler.setDocumentFilter(myFilter);
1021             getRepositoryClient(ctx).get(ctx, handler);
1022         }
1023
1024         result = (PoxPayloadOut) ctx.getOutput();
1025         if (result != null) {
1026             String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY);
1027             if (inAuthority.equalsIgnoreCase(parentcsid) == false) {
1028                 throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.",
1029                         itemSpec.value, inAuthority, parentcsid));
1030             }
1031         }
1032
1033         return result;
1034     }
1035
1036     public PoxPayloadOut getAuthorityItemWithExistingContext(
1037             ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1038             String parentIdentifier,
1039             String itemIdentifier) throws Exception {
1040         PoxPayloadOut result = null;
1041
1042         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getResourceMap(), existingCtx.getUriInfo());
1043         if (existingCtx.getCurrentRepositorySession() != null) {
1044             ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
1045             ctx.setProperties(existingCtx.getProperties());
1046         }
1047         result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1048
1049         return result;
1050     }
1051
1052     /**
1053      * Gets the authority item.
1054      *
1055      * @param parentspecifier either a CSID or one of the urn forms
1056      * @param itemspecifier either a CSID or one of the urn forms
1057      *
1058      * @return the authority item
1059      */
1060     @GET
1061     @Path("{csid}/items/{itemcsid}")
1062     public byte[] getAuthorityItem(
1063             @Context Request request,
1064             @Context UriInfo uriInfo,
1065             @Context ResourceMap resourceMap,
1066             @PathParam("csid") String parentIdentifier,
1067             @PathParam("itemcsid") String itemIdentifier) {
1068         uriInfo = new UriInfoWrapper(uriInfo);
1069         PoxPayloadOut result = null;
1070
1071         result = this.getAuthorityItemPayload(request, uriInfo, resourceMap, parentIdentifier, itemIdentifier);
1072
1073         return result.getBytes();
1074     }
1075
1076
1077     public PoxPayloadOut getAuthorityItemPayload(
1078             @Context Request request,
1079             @Context UriInfo uriInfo,
1080             @Context ResourceMap resourceMap,
1081             @PathParam("csid") String parentIdentifier,
1082             @PathParam("itemcsid") String itemIdentifier) {
1083         uriInfo = new UriInfoWrapper(uriInfo);
1084         PoxPayloadOut result = null;
1085         try {
1086             RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx =
1087                     (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
1088
1089             JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
1090             ctx.setJaxRsContext(jaxRsContext);
1091
1092             result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1093         } catch (DocumentNotFoundException dnf) {
1094             throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
1095         } catch (Exception e) {
1096             throw bigReThrow(e, ServiceMessages.GET_FAILED);
1097         }
1098
1099         return result;
1100     }
1101
1102     public Response getAuthorityItemResponse(
1103             @Context Request request,
1104             @Context UriInfo uriInfo,
1105             @Context ResourceMap resourceMap,
1106             @PathParam("csid") String parentIdentifier,
1107             @PathParam("itemcsid") String itemIdentifier) {
1108         uriInfo = new UriInfoWrapper(uriInfo);
1109         PoxPayloadOut payloadout = null;
1110         RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
1111
1112         try {
1113             ctx = (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
1114
1115             JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
1116             ctx.setJaxRsContext(jaxRsContext);
1117
1118             payloadout = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1119         } catch (DocumentNotFoundException dnf) {
1120             throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
1121         } catch (Exception e) {
1122             throw bigReThrow(e, ServiceMessages.GET_FAILED);
1123         }
1124
1125         return buildResponse(ctx, payloadout);
1126     }
1127
1128
1129     /*
1130      * Most of the authority child classes will/should use this implementation.  However, the Vocabulary service's item schema is
1131      * different enough that it will have to override this method in it's resource class.
1132      */
1133     @Override
1134     protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1135         String result = null;
1136
1137         result = NuxeoUtils.getPrimaryElPathPropertyName(
1138                 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
1139                 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
1140
1141         return result;
1142     }
1143
1144     @Override
1145     protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1146         String result = null;
1147
1148         result = NuxeoUtils.getMultiElPathPropertyName(
1149                 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
1150                 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
1151
1152         return result;
1153     }
1154
1155     /**
1156      * Gets the authorityItem list for the specified authority
1157      * If partialPerm is specified, keywords will be ignored.
1158      *
1159      * @param authorityIdentifier either a CSID or one of the urn forms
1160      * @param partialTerm if non-null, matches partial terms
1161      * @param keywords if non-null, matches terms in the keyword index for items
1162      * @param ui passed to include additional parameters, like pagination controls
1163      *
1164      */
1165     public AbstractCommonList getAuthorityItemList(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
1166             String authorityIdentifier,
1167             UriInfo uriInfo) throws Exception {
1168         AbstractCommonList result = null;
1169
1170         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1171         MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1172         if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context
1173             ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());
1174             ctx.setProperties(existingContext.getProperties());
1175         }
1176
1177         String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
1178         String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
1179         String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
1180         String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
1181         String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
1182
1183         // For the wildcard case, parentcsid is null, but docHandler will deal with this.
1184         // We omit the parentShortId, only needed when doing a create...
1185         String parentcsid = PARENT_WILDCARD.equals(authorityIdentifier) ? null :
1186             lookupParentCSID(ctx, authorityIdentifier, "getAuthorityItemList", "LIST", uriInfo);
1187         DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
1188             createItemDocumentHandler(ctx, parentcsid, null);
1189
1190         DocumentFilter myFilter = handler.getDocumentFilter();
1191         // If we are not wildcarding the parent, add a restriction
1192         if (parentcsid != null) {
1193             myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
1194                     + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
1195                     + "'" + parentcsid + "'",
1196                     IQueryManager.SEARCH_QUALIFIER_AND);
1197         }
1198
1199         if (Tools.notBlank(termStatus)) {
1200             // Start with the qualified termStatus field
1201             String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
1202                     + AuthorityItemJAXBSchema.TERM_STATUS;
1203             String[] filterTerms = termStatus.trim().split("\\|");
1204             String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
1205             myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
1206         }
1207
1208         result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);
1209
1210         return result;
1211     }
1212
1213     /**
1214      * Gets the authorityItem list for the specified authority
1215      * If partialPerm is specified, keywords will be ignored.
1216      *
1217      * @param authorityIdentifier either a CSID or one of the urn forms
1218      * @param partialTerm if non-null, matches partial terms
1219      * @param keywords if non-null, matches terms in the keyword index for items
1220      * @param ui passed to include additional parameters, like pagination controls
1221      *
1222      * @return the authorityItem list
1223      */
1224     @GET
1225     @Path("{csid}/items")
1226     @Produces("application/xml")
1227     public AbstractCommonList getAuthorityItemList(@PathParam("csid") String authorityIdentifier,
1228             @Context UriInfo uriInfo) {
1229         uriInfo = new UriInfoWrapper(uriInfo);
1230         AbstractCommonList result = null;
1231
1232         try {
1233             result = getAuthorityItemList(NULL_CONTEXT, authorityIdentifier, uriInfo);
1234         } catch (Exception e) {
1235             throw bigReThrow(e, ServiceMessages.LIST_FAILED);
1236         }
1237
1238         return result;
1239     }
1240
1241     /**
1242      * @return the name of the property used to specify references for items in this type of
1243      * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
1244      * Some types (like Vocabulary) use a separate property.
1245      */
1246     protected String getRefPropName() {
1247         return ServiceBindingUtils.AUTH_REF_PROP;
1248     }
1249
1250     /**
1251      * Gets the entities referencing this Authority item instance. The service type
1252      * can be passed as a query param "type", and must match a configured type
1253      * for the service bindings. If not set, the type defaults to
1254      * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
1255      *
1256      * @param parentspecifier either a CSID or one of the urn forms
1257      * @param itemspecifier either a CSID or one of the urn forms
1258      * @param ui the ui
1259      *
1260      * @return the info for the referencing objects
1261      */
1262     @GET
1263     @Path("{csid}/items/{itemcsid}/refObjs")
1264     @Produces("application/xml")
1265     public AuthorityRefDocList getReferencingObjects(
1266             @PathParam("csid") String parentSpecifier,
1267             @PathParam("itemcsid") String itemSpecifier,
1268             @Context UriInfo uriInfo) {
1269         uriInfo = new UriInfoWrapper(uriInfo);
1270         AuthorityRefDocList authRefDocList = null;
1271         try {
1272             authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriInfo, PAGE_NUM_FROM_QUERYPARAMS, PAGE_SIZE_FROM_QUERYPARAMS, true, true);
1273         } catch (Exception e) {
1274             throw bigReThrow(e, ServiceMessages.GET_FAILED);
1275         }
1276
1277         if (authRefDocList == null) {
1278             Response response = Response.status(Response.Status.NOT_FOUND).entity(
1279                     "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
1280                     "text/plain").build();
1281             throw new CSWebApplicationException(response);
1282         }
1283         return authRefDocList;
1284     }
1285
1286     public AuthorityRefDocList getReferencingObjects(
1287             ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
1288             String parentspecifier,
1289             String itemspecifier,
1290             UriInfo uriInfo,
1291             Integer pageNum,
1292             Integer pageSize,
1293             boolean useDefaultOrderByClause,
1294             boolean computeTotal) throws Exception {
1295         AuthorityRefDocList authRefDocList = null;
1296
1297         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1298         MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1299         //
1300         // Merge parts of existing context with our new context
1301         //
1302         if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1303             ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());  // If one exists, use the existing repo session
1304             ctx.setProperties(existingContext.getProperties());
1305         }
1306
1307         String parentcsid = lookupParentCSID(ctx, parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1308         String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1309
1310         // Remove the "type" property from the query params
1311         List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
1312         if (serviceTypes == null || serviceTypes.isEmpty()) {
1313             serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1314         }
1315
1316         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1317         authRefDocList = handler.getReferencingObjects(ctx, serviceTypes, getRefPropName(), itemcsid, pageNum, pageSize, useDefaultOrderByClause, computeTotal);
1318
1319         return authRefDocList;
1320     }
1321
1322     /**
1323      * Gets the authority terms used in the indicated Authority item.
1324      *
1325      * @param parentspecifier either a CSID or one of the urn forms
1326      * @param itemspecifier either a CSID or one of the urn forms
1327      * @param ui passed to include additional parameters, like pagination controls
1328      *
1329      * @return the authority refs for the Authority item.
1330      */
1331     @GET
1332     @Path("{csid}/items/{itemcsid}/authorityrefs")
1333     @Produces("application/xml")
1334     public AuthorityRefList getAuthorityItemAuthorityRefs(
1335             @PathParam("csid") String parentspecifier,
1336             @PathParam("itemcsid") String itemspecifier,
1337             @Context UriInfo uriInfo) {
1338         uriInfo = new UriInfoWrapper(uriInfo);
1339         AuthorityRefList authRefList = null;
1340
1341         try {
1342             // Note that we have to create the service context for the Items, not the main service
1343             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1344             String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1345             // We omit the parentShortId, only needed when doing a create...
1346             DocumentModelHandler<?, AbstractCommonList> handler =
1347                     (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1348
1349             String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1350
1351             List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1352             authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1353         } catch (Exception e) {
1354             throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1355         }
1356
1357         return authRefList;
1358     }
1359
1360     /**
1361      * Synchronizes a local authority item with a share authority server (SAS) item.
1362      * @param ctx
1363      * @param parentIdentifier
1364      * @param itemIdentifier
1365      * @return
1366      * @throws Exception
1367      */
1368     private PoxPayloadOut synchronizeItem(
1369             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
1370             String parentIdentifier,
1371             String itemIdentifier,
1372             boolean syncHierarchicalRelationships) throws Exception {
1373         PoxPayloadOut result = null;
1374         AuthorityItemSpecifier specifier;
1375         boolean neededSync = false;
1376
1377         CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1378         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1379         handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1380         handler.setIsSASItem(AuthorityServiceUtils.SAS_ITEM); // Since we're sync'ing, this is now a SAS controlled item
1381         handler.setShouldSyncHierarchicalRelationships(syncHierarchicalRelationships);
1382         // Create an authority item specifier
1383         Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1384         Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1385         specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1386         //
1387         neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1388         if (neededSync == true) {
1389             result = (PoxPayloadOut) ctx.getOutput();
1390         }
1391
1392         return result;
1393     }
1394
1395     /**
1396      * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1397      * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1398      * local authority.  The parent context was created for the authority (parent) because the sync started there.
1399      * @param existingCtx
1400      * @param parentIdentifier
1401      * @param itemIdentifier
1402      * @return
1403      * @throws Exception
1404      */
1405     public PoxPayloadOut synchronizeItemWithExistingContext(
1406             ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1407             String parentIdentifier,
1408             String itemIdentifier,
1409             boolean syncHierarchicalRelationships
1410             ) throws Exception {
1411         PoxPayloadOut result = null;
1412
1413         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1414                 existingCtx.getResourceMap(),
1415                 existingCtx.getUriInfo());
1416         if (existingCtx.getCurrentRepositorySession() != null) {
1417             ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1418
1419         }
1420         result = synchronizeItem(ctx, parentIdentifier, itemIdentifier, syncHierarchicalRelationships);
1421
1422         return result;
1423     }
1424
1425     /**
1426      * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1427      *
1428      * @param specifier either CSIDs and/or one of the urn forms
1429      *
1430      * @return the authority item if it was updated/synchronized with SAS item; otherwise empty
1431      */
1432     @POST
1433     @Path("{csid}/items/{itemcsid}/sync")
1434     public byte[] synchronizeItem(
1435             @Context ResourceMap resourceMap,
1436             @Context UriInfo uriInfo,
1437             @PathParam("csid") String parentIdentifier,
1438             @PathParam("itemcsid") String itemIdentifier) {
1439         uriInfo = new UriInfoWrapper(uriInfo);
1440         byte[] result;
1441         boolean neededSync = false;
1442         PoxPayloadOut payloadOut = null;
1443
1444         try {
1445             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1446             payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier, true);
1447             if (payloadOut != null) {
1448                 neededSync = true;
1449             }
1450         } catch (Exception e) {
1451             throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1452         }
1453
1454         //
1455         // If a sync was needed and was successful, return a copy of the updated resource.  Acts like an UPDATE.
1456         //
1457         if (neededSync == true) {
1458             result = payloadOut.getBytes();
1459         } else {
1460             result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1461                     itemIdentifier).getBytes();
1462             Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1463             throw new CSWebApplicationException(response);
1464         }
1465
1466         return result;
1467     }
1468
1469     /**
1470      * Update authorityItem.
1471      *
1472      * @param parentspecifier either a CSID or one of the urn forms
1473      * @param itemspecifier either a CSID or one of the urn forms
1474      *
1475      * @return the multipart output
1476      */
1477     @PUT
1478     @Path("{csid}/items/{itemcsid}")
1479     public byte[] updateAuthorityItem(
1480             @Context ResourceMap resourceMap,
1481             @Context UriInfo uriInfo,
1482             @PathParam("csid") String parentSpecifier,
1483             @PathParam("itemcsid") String itemSpecifier,
1484             String xmlPayload) {
1485         uriInfo = new UriInfoWrapper(uriInfo);
1486         PoxPayloadOut result = null;
1487
1488         try {
1489             PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1490             result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1491                     AuthorityServiceUtils.UPDATE_REV,            // passing TRUE so rev num increases, passing
1492                     AuthorityServiceUtils.NO_CHANGE,    // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1493                     AuthorityServiceUtils.NO_CHANGE);    // don't change the state of the "sas" field -we could be performing a sync or just a plain update
1494         } catch (Exception e) {
1495             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1496         }
1497
1498         return result.getBytes();
1499     }
1500
1501
1502
1503     /**
1504      * Delete authorityItem.
1505      *
1506      * @param parentIdentifier the parentcsid
1507      * @param itemIdentifier the itemcsid
1508      *
1509      * @return the response
1510      */
1511     @DELETE
1512     @Path("{csid}/items/{itemcsid}")
1513     public Response deleteAuthorityItem(
1514             @Context UriInfo uriInfo,
1515             @PathParam("csid") String parentIdentifier,
1516             @PathParam("itemcsid") String itemIdentifier) {
1517         uriInfo = new UriInfoWrapper(uriInfo);
1518         Response result = null;
1519
1520         ensureCSID(parentIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1521         ensureCSID(itemIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1522         if (logger.isDebugEnabled()) {
1523             logger.debug("deleteAuthorityItem with parentcsid=" + parentIdentifier + " and itemcsid=" + itemIdentifier);
1524         }
1525
1526         try {
1527             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1528             deleteAuthorityItem(ctx, parentIdentifier, itemIdentifier, AuthorityServiceUtils.UPDATE_REV);
1529             result = Response.status(HttpResponseCodes.SC_OK).build();
1530         } catch (Exception e) {
1531             throw bigReThrow(e, ServiceMessages.DELETE_FAILED + "  itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier);
1532         }
1533
1534         return result;
1535     }
1536
1537     /**
1538      *
1539      * @param existingCtx
1540      * @param parentIdentifier
1541      * @param itemIdentifier
1542      * @throws Exception
1543      */
1544     public boolean deleteAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1545             String parentIdentifier,
1546             String itemIdentifier,
1547             boolean shouldUpdateRevNumber
1548             ) throws Exception {
1549         boolean result = true;
1550
1551         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getUriInfo());
1552         if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1553             ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1554             ctx.setProperties(existingCtx.getProperties());
1555         }
1556
1557         String parentcsid = null;
1558         try {
1559             parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1560         } catch (DocumentNotFoundException de) {
1561             String msg = String.format("Could not find parent with ID='%s' when trying to delete item ID='%s'",
1562                     parentIdentifier, itemIdentifier);
1563             logger.warn(msg);
1564             throw de;
1565         }
1566         String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1567
1568         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler) createDocumentHandler(ctx);
1569         handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1570         result = getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
1571
1572         return result;
1573     }
1574
1575     @GET
1576     @Path("{csid}/items/{itemcsid}/" + hierarchy)
1577     @Produces("application/xml")
1578     public String getHierarchy(
1579             @PathParam("csid") String parentIdentifier,
1580             @PathParam("itemcsid") String itemIdentifier,
1581             @Context UriInfo uriInfo) throws Exception {
1582         uriInfo = new UriInfoWrapper(uriInfo);
1583         String result = null;
1584
1585         try {
1586             //
1587             // 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...?
1588             //
1589             String calledUri = uriInfo.getPath();
1590             String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1591             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1592
1593             String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1594             String itemcsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1595
1596             String direction = uriInfo.getQueryParameters().getFirst(Hierarchy.directionQP);
1597             if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1598                 result = Hierarchy.surface(ctx, itemcsid, uri);
1599             } else {
1600                 result = Hierarchy.dive(ctx, itemcsid, uri);
1601             }
1602         } catch (Exception e) {
1603             throw bigReThrow(e, "Error showing hierarchy for authority item: ", itemIdentifier);
1604         }
1605
1606         return result;
1607     }
1608
1609     /**
1610      *
1611      * @param tenantId
1612      * @return
1613      */
1614     public String getItemDocType(String tenantId) {
1615         return getDocType(tenantId, getItemServiceName());
1616     }
1617
1618     /**
1619      * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1620      * for the current resource, for all tenants
1621      *
1622      * @return a map of URI templates for the current resource, for all tenants
1623      */
1624     @Override
1625     public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1626         Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1627                 super.getUriRegistryEntries();
1628         List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1629         for (String tenantId : tenantIds) {
1630                 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1631         }
1632         return uriRegistryEntriesMap;
1633     }
1634
1635     /**
1636      *
1637      */
1638     @Override
1639     public ServiceDescription getDescription(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1640         ServiceDescription result = super.getDescription(ctx);
1641         result.setSubresourceDocumentType(this.getItemDocType(ctx.getTenantId()));
1642         return result;
1643     }
1644
1645     public Response createAuthority(String xmlPayload) {
1646         return this.createAuthority(null, null, xmlPayload);
1647     }
1648
1649     protected String getCsid(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, Specifier specifier) throws Exception {
1650         String csid;
1651
1652         if (ctx == null) {
1653             ctx = createServiceContext(getServiceName());
1654         }
1655
1656         if (specifier.form == SpecifierForm.CSID) {
1657             csid = specifier.value;
1658         } else {
1659             String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, specifier.value);
1660             csid = getRepositoryClient(ctx).findDocCSID(null, ctx, whereClause);
1661         }
1662
1663         return csid;
1664     }
1665
1666 }