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