]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
4bd7077265fb9ae29c4b478b75bb50db676f2566
[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 ResourceMap resourceMap,
573                 @Context UriInfo uriInfo,               
574             @PathParam("csid") String specifier,
575             String xmlPayload) {
576         PoxPayloadOut result = null;
577         try {
578             PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
579             Specifier spec = Specifier.getSpecifier(specifier, "updateAuthority", "UPDATE");
580             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
581             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
582             String csid;
583             if (spec.form == SpecifierForm.CSID) {
584                 csid = spec.value;
585             } else {
586                 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
587                 csid = getRepositoryClient(ctx).findDocCSID(null, ctx, whereClause);
588             }
589             getRepositoryClient(ctx).update(ctx, csid, handler);
590             result = ctx.getOutput();
591         } catch (Exception e) {
592             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
593         }
594         return result.getBytes();
595     }
596     
597     /**
598      * Delete all the items in an authority list.
599      * 
600      * @param specifier
601      * @param uriInfo
602      * @return
603      */
604     @DELETE
605     @Path("{csid}/items")
606     public Response deleteAuthorityItemList(@PathParam("csid") String specifier,
607             @Context UriInfo uriInfo) {
608         uriInfo = new UriInfoWrapper(uriInfo);
609
610         try {
611             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
612                         RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient = this.getRepositoryClient(ctx);
613             
614                         CoreSessionInterface repoSession = repoClient.getRepositorySession(ctx);
615                         try {
616                     DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
617                     //
618                     // Delete all the items one by one
619                     //
620                         AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
621                         for (ListItem item : itemsList.getListItem()) {
622                         deleteAuthorityItem(ctx, specifier, getCsid(item), AuthorityServiceUtils.UPDATE_REV);
623                         }
624                         } catch (Throwable t) {
625                 repoSession.setTransactionRollbackOnly();
626                 throw t;
627             } finally {
628                 repoClient.releaseRepositorySession(ctx, repoSession);
629             }
630
631             return Response.status(HttpResponseCodes.SC_OK).build();
632         } catch (Exception e) {
633             throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
634         }
635     }
636     
637     /**
638      * Delete authority
639      * 
640      * @param csid the csid or a URN specifier form -e.g., urn:cspace:name(OurMuseumPersonAuthority)
641      * 
642      * @return the response
643      */
644     @DELETE
645     @Path("{csid}")
646     public Response deleteAuthority( // # Delete this authority and all of it's items.
647             @Context Request request,
648             @Context UriInfo uriInfo,
649             @PathParam("csid") String specifier) {
650         uriInfo = new UriInfoWrapper(uriInfo);
651
652         if (logger.isDebugEnabled()) {
653             logger.debug("deleteAuthority with specifier=" + specifier);
654         }
655         
656         try {
657             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
658             Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
659                         RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient = this.getRepositoryClient(ctx);
660             
661                         CoreSessionInterface repoSession = repoClient.getRepositorySession(ctx);
662                         try {
663                     DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
664                     //
665                     // First try to delete all the items
666                     //
667                         AbstractCommonList itemsList = this.getAuthorityItemList(ctx, specifier, uriInfo);
668                         for (ListItem item : itemsList.getListItem()) {
669                         deleteAuthorityItem(ctx, specifier, getCsid(item), AuthorityServiceUtils.UPDATE_REV);
670                         }
671
672                     //
673                     // Lastly, delete the parent/container
674                     //
675                     if (spec.form == SpecifierForm.CSID) {
676                         if (logger.isDebugEnabled()) {
677                             logger.debug("deleteAuthority with csid=" + spec.value);
678                         }
679                         ensureCSID(spec.value, ServiceMessages.DELETE_FAILED, "Authority.csid");
680                         getRepositoryClient(ctx).delete(ctx, spec.value, handler);
681                     } else {
682                         if (logger.isDebugEnabled()) {
683                             logger.debug("deleteAuthority with specifier=" + spec.value);
684                         }               
685                         String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
686                         getRepositoryClient(ctx).deleteWithWhereClause(ctx, whereClause, handler);
687                     }
688                         } catch (Throwable t) {
689                 repoSession.setTransactionRollbackOnly();
690                 throw t;
691             } finally {
692                 repoClient.releaseRepositorySession(ctx, repoSession);
693             }
694
695             return Response.status(HttpResponseCodes.SC_OK).build();
696         } catch (Exception e) {
697             throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
698         }
699     }
700     
701         private String getCsid(ListItem item) {
702                 String result = null;
703                 
704                 for (Element ele : item.getAny()) {
705                         String elementName = ele.getTagName().toLowerCase();
706                         if (elementName.equals("csid")) {
707                                 result = ele.getTextContent();
708                                 break;
709                         }
710                 }
711                 
712                 return result;
713         }
714
715         /**
716      * 
717      * @param ctx
718      * @param parentspecifier           - ID of the container. Can be URN or CSID form
719      * @param shouldUpdateRevNumber - Indicates if the revision number should be updated on create -won't do this when synching with SAS
720      * @param isProposed                                - In a shared authority context, indicates if this item just a proposed item and not yet part of the SAS authority
721      * @return
722      * @throws Exception
723      */
724     protected Response createAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String parentIdentifier,
725                 boolean shouldUpdateRevNumber,
726                 boolean isProposed,
727                 boolean isSasItem) throws Exception {
728         Response result = null;
729         
730         // Note: must have the parentShortId, to do the create.
731         CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "createAuthorityItem", "CREATE_ITEM", null);
732         AuthorityItemDocumentModelHandler handler = 
733                 (AuthorityItemDocumentModelHandler) createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
734         handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
735         handler.setIsProposed(isProposed);
736         handler.setIsSASItem(isSasItem);
737         // Make the client call
738         String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
739         
740         // Build the JAX-RS response
741         UriBuilder path = UriBuilder.fromResource(resourceClass);
742         path.path(parent.CSID + "/items/" + itemcsid);
743         result = Response.created(path.build()).build();
744
745         return result;
746     }
747     
748     public PoxPayloadOut updateAuthorityItem(
749                 ServiceContext<PoxPayloadIn, PoxPayloadOut> itemServiceCtx, // Ok to be null.  Will be null on PUT calls, but not on sync calls
750                 ResourceMap resourceMap, 
751             UriInfo uriInfo,
752             String parentspecifier,
753             String itemspecifier,
754             PoxPayloadIn theUpdate,
755             boolean shouldUpdateRevNumber,
756             Boolean isProposed,
757             Boolean isSASItem
758             ) throws Exception {
759         PoxPayloadOut result = null;
760         
761         CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(itemServiceCtx, parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
762         String parentcsid = csidAndShortId.CSID;
763         String parentShortId = csidAndShortId.shortIdentifier;
764         //
765         // If the itemServiceCtx context is not null, use it.  Otherwise, create a new context
766         //
767         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = itemServiceCtx;
768         if (ctx == null) {
769                 ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
770         } else {
771                 ctx.setInput(theUpdate); // the update payload
772         }
773         
774         String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM"); //use itemServiceCtx if it is not null
775
776         // We omit the parentShortId, only needed when doing a create...
777         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, parentShortId);
778         handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
779         //
780         // Update the SAS fields if either value is non-null
781         //
782         boolean updateSASFields = isProposed != null || isSASItem != null;
783         handler.setshouldUpdateSASFields(updateSASFields);
784         if (updateSASFields == true) {
785                 handler.setshouldUpdateSASFields(true);
786                 if (isProposed != null) {
787                         handler.setIsProposed(isProposed);
788                 }
789                 if (isSASItem != null) {
790                         handler.setIsSASItem(isSASItem);
791                 }
792         }
793         
794         getRepositoryClient(ctx).update(ctx, itemcsid, handler);
795         result = ctx.getOutput();
796
797         return result;
798     }    
799
800     /**
801      * Called with an existing context.
802      * @param parentCtx
803      * @param parentIdentifier
804      * @param input
805      * @return
806      * @throws Exception
807      */
808     public Response createAuthorityItemWithParentContext(ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx,
809                 String parentIdentifier,
810                 PoxPayloadIn input,
811                 boolean shouldUpdateRevNumber,
812                 boolean isProposed,
813                 boolean isSASItem) throws Exception {
814         Response result = null;
815         
816         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input,
817                         parentCtx.getResourceMap(), parentCtx.getUriInfo());
818         if (parentCtx.getCurrentRepositorySession() != null) {
819                 ctx.setCurrentRepositorySession(parentCtx.getCurrentRepositorySession());
820         }
821         result = this.createAuthorityItem(ctx, parentIdentifier, shouldUpdateRevNumber, isProposed, isSASItem);
822
823         return result;
824     }
825         
826     /*************************************************************************
827      * Create an AuthorityItem - this is a sub-resource of Authority
828      * @param specifier either a CSID or one of the urn forms
829      * @return Authority item response
830      *************************************************************************/
831     @POST
832     @Path("{csid}/items")
833     public Response createAuthorityItem(
834                 @Context ResourceMap resourceMap,
835                 @Context UriInfo uriInfo,
836                 @PathParam("csid") String parentIdentifier, // Either a CSID or a URN form -e.g., a8ad38ec-1d7d-4bf2-bd31 or urn:cspace:name(bugsbunny)
837                 String xmlPayload) {
838         uriInfo = new UriInfoWrapper(uriInfo);
839         Response result = null;
840         
841         try {
842             PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
843             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
844             result = this.createAuthorityItem(ctx, parentIdentifier, AuthorityServiceUtils.UPDATE_REV,
845                         AuthorityServiceUtils.PROPOSED, AuthorityServiceUtils.NOT_SAS_ITEM);
846         } catch (Exception e) {
847             throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
848         }
849
850         return result;
851     }
852
853     @GET
854     @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
855     public byte[] getItemWorkflow(
856             @PathParam("csid") String csid,
857             @PathParam("itemcsid") String itemcsid) {
858         PoxPayloadOut result = null;
859
860         try {
861             ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
862             String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
863
864             MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
865             WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
866             ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
867             getRepositoryClient(ctx).get(ctx, itemcsid, handler);
868             result = ctx.getOutput();
869         } catch (Exception e) {
870             throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
871         }
872         return result.getBytes();
873     }
874
875     //FIXME: This method is almost identical to the method org.collectionspace.services.common.updateWorkflowWithTransition() so
876     // they should be consolidated -be DRY (D)on't (R)epeat (Y)ourself.
877     @PUT
878     @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
879     public byte[] updateItemWorkflowWithTransition(
880             @Context UriInfo uriInfo,
881             @PathParam("csid") String parentIdentifier,
882             @PathParam("itemcsid") String itemIdentifier,
883             @PathParam("transition") String transition) {
884         uriInfo = new UriInfoWrapper(uriInfo);
885         PoxPayloadOut result = null;
886         
887         try {
888             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
889             result = updateItemWorkflowWithTransition(ctx, 
890                         parentIdentifier, itemIdentifier, transition, AuthorityServiceUtils.UPDATE_REV);
891         } catch (Exception e) {
892             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, parentIdentifier);
893         }
894         
895         return result.getBytes();
896     }
897     
898     /**
899      * Update an authority item's workflow state.
900      * @param existingContext
901      * @param csid
902      * @param itemcsid
903      * @param transition
904      * @return
905      * @throws DocumentReferenceException 
906      */
907     public PoxPayloadOut updateItemWorkflowWithTransition(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
908             String parentIdentifier,
909             String itemIdentifier,
910             String transition,
911             boolean updateRevNumber) throws DocumentReferenceException {
912         PoxPayloadOut result = null;
913         
914         try {
915                 //
916                 // We need CSIDs for both the parent authority and the authority item
917                 //
918             CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(existingContext, parentIdentifier, "updateItemWorkflowWithTransition(parent)", "UPDATE_ITEM", null);
919             String itemCsid = lookupItemCSID(existingContext, itemIdentifier, csidAndShortId.CSID, "updateAuthorityItem(item)", "UPDATE_ITEM");
920
921             //
922                 // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
923                 //
924                 PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(), 
925                                 WorkflowClient.SERVICE_COMMONPART_NAME);
926             MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
927             if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
928                 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());// If a repo session is already open, we need to use it and not create a new one
929             }
930             //
931             // Create a service context and document handler for the target resource -not the workflow resource itself.
932             //
933             ServiceContext<PoxPayloadIn, PoxPayloadOut> targetCtx = createServiceContext(getItemServiceName(), existingContext.getUriInfo());
934             AuthorityItemDocumentModelHandler targetDocHandler = (AuthorityItemDocumentModelHandler) this.createDocumentHandler(targetCtx);
935             targetDocHandler.setShouldUpdateRevNumber(updateRevNumber);
936             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
937             //
938             // When looking for the document, we need to use the parent/target resource's workspace name -not the "workflow" workspace name
939             //
940             String targetWorkspaceName = targetCtx.getRepositoryWorkspaceName();
941             ctx.setRespositoryWorkspaceName(targetWorkspaceName); //find the document in the parent's workspace
942             
943                 // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
944             TransitionDef transitionDef = getTransitionDef(targetCtx, transition);
945             if (transitionDef == null) {
946                 throw new DocumentException(String.format("The document with ID='%s' does not support the workflow transition '%s'.",
947                                 itemIdentifier, transition));
948             }
949             ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
950             
951             WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
952             getRepositoryClient(ctx).update(ctx, itemCsid, handler);
953             result = ctx.getOutput();
954         } catch (DocumentReferenceException de) {
955                 throw de;
956         } catch (Exception e) {
957             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, itemIdentifier);
958         }
959         
960         return result;
961     }
962     
963     private PoxPayloadOut getAuthorityItem(
964                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
965             String parentIdentifier,
966             String itemIdentifier) throws Exception {
967         PoxPayloadOut result = null;
968         
969         String parentcsid = lookupParentCSID(ctx, parentIdentifier, "getAuthorityItem(parent)", "GET_ITEM", null);
970         // We omit the parentShortId, only needed when doing a create...
971         DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
972
973         Specifier itemSpec = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem(item)", "GET_ITEM");
974         if (itemSpec.form == SpecifierForm.CSID) {
975             // TODO should we assert that the item is in the passed vocab?
976             getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
977         } else {
978             String itemWhereClause =
979                         RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
980             DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
981             handler.setDocumentFilter(myFilter);
982             getRepositoryClient(ctx).get(ctx, handler);
983         }
984         
985         result = (PoxPayloadOut) ctx.getOutput();
986         if (result != null) {
987                 String inAuthority = XmlTools.getElementValue(result.getDOMDocument(), "//" + AuthorityItemJAXBSchema.IN_AUTHORITY);
988                 if (inAuthority.equalsIgnoreCase(parentcsid) == false) {
989                         throw new Exception(String.format("Looked up item = '%s' and found with inAuthority = '%s', but expected inAuthority = '%s'.",
990                                         itemSpec.value, inAuthority, parentcsid));
991                 }
992         }
993         
994         return result;
995     }
996
997     public PoxPayloadOut getAuthorityItemWithExistingContext(
998                 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
999             String parentIdentifier,
1000             String itemIdentifier) throws Exception {
1001         PoxPayloadOut result = null;
1002         
1003         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getResourceMap(), existingCtx.getUriInfo());
1004         if (existingCtx.getCurrentRepositorySession() != null) {
1005                 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession()); // Reuse the current repo session if one exists
1006                 ctx.setProperties(existingCtx.getProperties());
1007         }
1008         result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1009         
1010         return result;
1011     }
1012     
1013     /**
1014      * Gets the authority item.
1015      * 
1016      * @param parentspecifier either a CSID or one of the urn forms
1017      * @param itemspecifier either a CSID or one of the urn forms
1018      * 
1019      * @return the authority item
1020      */
1021     @GET
1022     @Path("{csid}/items/{itemcsid}")
1023     public byte[] getAuthorityItem(
1024             @Context Request request,
1025             @Context UriInfo uriInfo,
1026                 @Context ResourceMap resourceMap,            
1027             @PathParam("csid") String parentIdentifier,
1028             @PathParam("itemcsid") String itemIdentifier) {
1029         uriInfo = new UriInfoWrapper(uriInfo);
1030         PoxPayloadOut result = null;
1031         try {
1032             RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = 
1033                         (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
1034
1035             JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // Needed for getting account permissions part of the resource
1036             ctx.setJaxRsContext(jaxRsContext);
1037             
1038             result = getAuthorityItem(ctx, parentIdentifier, itemIdentifier);
1039         } catch (DocumentNotFoundException dnf) {
1040             throw bigReThrow(dnf, ServiceMessages.resourceNotFoundMsg(itemIdentifier));
1041         } catch (Exception e) {
1042             throw bigReThrow(e, ServiceMessages.GET_FAILED);
1043         }
1044                 
1045         return result.getBytes();
1046     }
1047
1048     /*
1049      * Most of the authority child classes will/should use this implementation.  However, the Vocabulary service's item schema is
1050      * different enough that it will have to override this method in it's resource class.
1051      */
1052     @Override
1053         protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1054                 String result = null;
1055
1056                 result = NuxeoUtils.getPrimaryElPathPropertyName(
1057                                 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
1058                                 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
1059
1060                 return result;
1061         }
1062         
1063     @Override
1064         protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1065                 String result = null;
1066                 
1067                 result = NuxeoUtils.getMultiElPathPropertyName(
1068                                 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
1069                                 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
1070
1071                 return result;
1072         }
1073     
1074     /**
1075      * Gets the authorityItem list for the specified authority
1076      * If partialPerm is specified, keywords will be ignored.
1077      * 
1078      * @param authorityIdentifier either a CSID or one of the urn forms
1079      * @param partialTerm if non-null, matches partial terms
1080      * @param keywords if non-null, matches terms in the keyword index for items
1081      * @param ui passed to include additional parameters, like pagination controls
1082      *
1083      */
1084     public AbstractCommonList getAuthorityItemList(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
1085                 String authorityIdentifier,
1086             UriInfo uriInfo) throws Exception {
1087         AbstractCommonList result = null;
1088         
1089         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1090         MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1091         if (existingContext != null && existingContext.getCurrentRepositorySession() != null) { // Merge some of the existing context properties with our new context
1092                 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());
1093                 ctx.setProperties(existingContext.getProperties());
1094         }
1095             
1096         String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
1097         String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
1098         String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
1099         String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
1100         String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
1101
1102         // For the wildcard case, parentcsid is null, but docHandler will deal with this.
1103         // We omit the parentShortId, only needed when doing a create...
1104         String parentcsid = PARENT_WILDCARD.equals(authorityIdentifier) ? null :
1105                         lookupParentCSID(ctx, authorityIdentifier, "getAuthorityItemList", "LIST", uriInfo);
1106         DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
1107                 createItemDocumentHandler(ctx, parentcsid, null);
1108         
1109         DocumentFilter myFilter = handler.getDocumentFilter();
1110         // If we are not wildcarding the parent, add a restriction
1111         if (parentcsid != null) {
1112             myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
1113                     + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
1114                     + "'" + parentcsid + "'",
1115                     IQueryManager.SEARCH_QUALIFIER_AND);
1116         }
1117
1118         if (Tools.notBlank(termStatus)) {
1119                 // Start with the qualified termStatus field
1120                 String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
1121                     + AuthorityItemJAXBSchema.TERM_STATUS;
1122                 String[] filterTerms = termStatus.trim().split("\\|");
1123                 String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
1124             myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
1125         }
1126
1127         result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);            
1128         
1129         return result;
1130     }
1131     
1132     /**
1133      * Gets the authorityItem list for the specified authority
1134      * If partialPerm is specified, keywords will be ignored.
1135      * 
1136      * @param authorityIdentifier either a CSID or one of the urn forms
1137      * @param partialTerm if non-null, matches partial terms
1138      * @param keywords if non-null, matches terms in the keyword index for items
1139      * @param ui passed to include additional parameters, like pagination controls
1140      * 
1141      * @return the authorityItem list
1142      */
1143     @GET
1144     @Path("{csid}/items")
1145     @Produces("application/xml")
1146     public AbstractCommonList getAuthorityItemList(@PathParam("csid") String authorityIdentifier,
1147             @Context UriInfo uriInfo) {
1148         uriInfo = new UriInfoWrapper(uriInfo);
1149         AbstractCommonList result = null;
1150         
1151         try {
1152             result = getAuthorityItemList(NULL_CONTEXT, authorityIdentifier, uriInfo);    
1153         } catch (Exception e) {
1154             throw bigReThrow(e, ServiceMessages.LIST_FAILED);
1155         }
1156         
1157         return result;
1158     }
1159
1160     /**
1161      * @return the name of the property used to specify references for items in this type of
1162      * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
1163      * Some types (like Vocabulary) use a separate property.
1164      */
1165     protected String getRefPropName() {
1166         return ServiceBindingUtils.AUTH_REF_PROP;
1167     }
1168     
1169     /**
1170      * Gets the entities referencing this Authority item instance. The service type
1171      * can be passed as a query param "type", and must match a configured type
1172      * for the service bindings. If not set, the type defaults to
1173      * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
1174      *
1175      * @param parentspecifier either a CSID or one of the urn forms
1176      * @param itemspecifier either a CSID or one of the urn forms
1177      * @param ui the ui
1178      * 
1179      * @return the info for the referencing objects
1180      */
1181     @GET
1182     @Path("{csid}/items/{itemcsid}/refObjs")
1183     @Produces("application/xml")
1184     public AuthorityRefDocList getReferencingObjects(
1185             @PathParam("csid") String parentSpecifier,
1186             @PathParam("itemcsid") String itemSpecifier,
1187             @Context UriTemplateRegistry uriTemplateRegistry,
1188             @Context UriInfo uriInfo) {
1189         uriInfo = new UriInfoWrapper(uriInfo);
1190         AuthorityRefDocList authRefDocList = null;
1191         try {
1192             authRefDocList = getReferencingObjects(null, parentSpecifier, itemSpecifier, uriTemplateRegistry, uriInfo);
1193         } catch (Exception e) {
1194             throw bigReThrow(e, ServiceMessages.GET_FAILED);
1195         }
1196         
1197         if (authRefDocList == null) {
1198             Response response = Response.status(Response.Status.NOT_FOUND).entity(
1199                     "Get failed, the requested Item CSID:" + itemSpecifier + ": was not found.").type(
1200                     "text/plain").build();
1201             throw new CSWebApplicationException(response);
1202         }
1203         return authRefDocList;
1204     }
1205     
1206     public AuthorityRefDocList getReferencingObjects(
1207                 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingContext,
1208             String parentspecifier,
1209             String itemspecifier,
1210             UriTemplateRegistry uriTemplateRegistry,
1211             UriInfo uriInfo) throws Exception {
1212         //uriInfo = new UriInfoWrapper(uriInfo);
1213         AuthorityRefDocList authRefDocList = null;
1214  
1215         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1216         MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1217         //
1218         // Merge parts of existing context with our new context
1219         //
1220         if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1221                 ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());  // If one exists, use the existing repo session
1222                 ctx.setProperties(existingContext.getProperties());
1223         }
1224
1225         String parentcsid = lookupParentCSID(ctx, parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1226         String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1227         
1228         // Remove the "type" property from the query params
1229         List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);        
1230         if (serviceTypes == null || serviceTypes.isEmpty()) {
1231                 serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1232         }
1233             
1234         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1235         authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
1236
1237         return authRefDocList;
1238     }
1239
1240     /**
1241      * Gets the authority terms used in the indicated Authority item.
1242      *
1243      * @param parentspecifier either a CSID or one of the urn forms
1244      * @param itemspecifier either a CSID or one of the urn forms
1245      * @param ui passed to include additional parameters, like pagination controls
1246      *
1247      * @return the authority refs for the Authority item.
1248      */
1249     @GET
1250     @Path("{csid}/items/{itemcsid}/authorityrefs")
1251     @Produces("application/xml")
1252     public AuthorityRefList getAuthorityItemAuthorityRefs(
1253             @PathParam("csid") String parentspecifier,
1254             @PathParam("itemcsid") String itemspecifier,
1255             @Context UriInfo uriInfo) {
1256         uriInfo = new UriInfoWrapper(uriInfo);
1257         AuthorityRefList authRefList = null;
1258         
1259         try {
1260             // Note that we have to create the service context for the Items, not the main service
1261             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1262             String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1263             // We omit the parentShortId, only needed when doing a create...
1264             DocumentModelHandler<?, AbstractCommonList> handler =
1265                     (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1266
1267             String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1268
1269             List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1270             authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1271         } catch (Exception e) {
1272             throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1273         }
1274         
1275         return authRefList;
1276     }
1277     
1278     /**
1279      * Synchronizes a local authority item with a share authority server (SAS) item.
1280      * @param ctx
1281      * @param parentIdentifier
1282      * @param itemIdentifier
1283      * @return
1284      * @throws Exception
1285      */
1286     private PoxPayloadOut synchronizeItem(
1287                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
1288             String parentIdentifier,
1289             String itemIdentifier,
1290             boolean syncHierarchicalRelationships) throws Exception {
1291         PoxPayloadOut result = null;
1292         AuthorityItemSpecifier specifier;
1293         boolean neededSync = false;
1294
1295         CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1296         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1297         handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1298         handler.setIsSASItem(AuthorityServiceUtils.SAS_ITEM); // Since we're sync'ing, this is now a SAS controlled item
1299         handler.setShouldSyncHierarchicalRelationships(syncHierarchicalRelationships);
1300         // Create an authority item specifier
1301         Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1302         Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1303         specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1304         //
1305         neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1306         if (neededSync == true) {
1307                 result = (PoxPayloadOut) ctx.getOutput();
1308         }
1309         
1310         return result;
1311     }
1312
1313     /**
1314      * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1315      * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1316      * local authority.  The parent context was created for the authority (parent) because the sync started there.
1317      * @param existingCtx
1318      * @param parentIdentifier
1319      * @param itemIdentifier
1320      * @return
1321      * @throws Exception
1322      */
1323     public PoxPayloadOut synchronizeItemWithExistingContext(
1324                 ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1325             String parentIdentifier,
1326             String itemIdentifier,
1327             boolean syncHierarchicalRelationships
1328             ) throws Exception {
1329         PoxPayloadOut result = null;
1330         
1331         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1332                         existingCtx.getResourceMap(),
1333                         existingCtx.getUriInfo());
1334         if (existingCtx.getCurrentRepositorySession() != null) {
1335                 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1336                 
1337         }
1338         result = synchronizeItem(ctx, parentIdentifier, itemIdentifier, syncHierarchicalRelationships);
1339         
1340         return result;
1341     }
1342     
1343     /**
1344      * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1345      * 
1346      * @param specifier either CSIDs and/or one of the urn forms
1347      * 
1348      * @return the authority item if it was updated/synchronized with SAS item; otherwise empty
1349      */
1350     @POST
1351     @Path("{csid}/items/{itemcsid}/sync")
1352     public byte[] synchronizeItem(
1353                 @Context ResourceMap resourceMap,
1354             @Context UriInfo uriInfo,
1355             @PathParam("csid") String parentIdentifier,
1356             @PathParam("itemcsid") String itemIdentifier) {
1357         uriInfo = new UriInfoWrapper(uriInfo);
1358         byte[] result;
1359         boolean neededSync = false;
1360         PoxPayloadOut payloadOut = null;
1361         
1362         try {
1363             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1364             payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier, true);
1365             if (payloadOut != null) {
1366                 neededSync = true;
1367             }
1368         } catch (Exception e) {
1369             throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1370         }
1371
1372         //
1373         // If a sync was needed and was successful, return a copy of the updated resource.  Acts like an UPDATE.
1374         //
1375         if (neededSync == true) {
1376                 result = payloadOut.getBytes();
1377         } else {
1378                 result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1379                                 itemIdentifier).getBytes();
1380                 Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1381             throw new CSWebApplicationException(response);
1382         }
1383         
1384         return result;
1385     }
1386     
1387     /**
1388      * Update authorityItem.
1389      * 
1390      * @param parentspecifier either a CSID or one of the urn forms
1391      * @param itemspecifier either a CSID or one of the urn forms
1392      *
1393      * @return the multipart output
1394      */
1395     @PUT
1396     @Path("{csid}/items/{itemcsid}")
1397     public byte[] updateAuthorityItem(
1398                 @Context ResourceMap resourceMap, 
1399             @Context UriInfo uriInfo,
1400             @PathParam("csid") String parentSpecifier,
1401             @PathParam("itemcsid") String itemSpecifier,
1402             String xmlPayload) {
1403         uriInfo = new UriInfoWrapper(uriInfo);
1404         PoxPayloadOut result = null;
1405         
1406         try {
1407             PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1408             result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1409                         AuthorityServiceUtils.UPDATE_REV,                       // passing TRUE so rev num increases, passing
1410                         AuthorityServiceUtils.NO_CHANGE,        // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1411                         AuthorityServiceUtils.NO_CHANGE);       // don't change the state of the "sas" field -we could be performing a sync or just a plain update
1412         } catch (Exception e) {
1413             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1414         }
1415         
1416         return result.getBytes();
1417     }
1418     
1419
1420
1421     /**
1422      * Delete authorityItem.
1423      * 
1424      * @param parentIdentifier the parentcsid
1425      * @param itemIdentifier the itemcsid
1426      * 
1427      * @return the response
1428      */
1429     @DELETE
1430     @Path("{csid}/items/{itemcsid}")
1431     public Response deleteAuthorityItem(
1432             @Context UriInfo uriInfo,
1433             @PathParam("csid") String parentIdentifier,
1434             @PathParam("itemcsid") String itemIdentifier) {
1435         uriInfo = new UriInfoWrapper(uriInfo);
1436         Response result = null;
1437
1438         ensureCSID(parentIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1439         ensureCSID(itemIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1440         if (logger.isDebugEnabled()) {
1441             logger.debug("deleteAuthorityItem with parentcsid=" + parentIdentifier + " and itemcsid=" + itemIdentifier);
1442         }
1443         
1444         try {
1445             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1446             deleteAuthorityItem(ctx, parentIdentifier, itemIdentifier, AuthorityServiceUtils.UPDATE_REV);
1447             result = Response.status(HttpResponseCodes.SC_OK).build();
1448         } catch (Exception e) {
1449             throw bigReThrow(e, ServiceMessages.DELETE_FAILED + "  itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier);
1450         }
1451
1452         return result;
1453     }
1454
1455     /**
1456      * 
1457      * @param existingCtx
1458      * @param parentIdentifier
1459      * @param itemIdentifier
1460      * @throws Exception
1461      */
1462         public boolean deleteAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1463             String parentIdentifier,
1464             String itemIdentifier,
1465             boolean shouldUpdateRevNumber
1466             ) throws Exception {
1467         boolean result = true;
1468         
1469         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getUriInfo());
1470         if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1471                 ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1472                 ctx.setProperties(existingCtx.getProperties());
1473         }
1474         
1475         String parentcsid = null;
1476         try {
1477                 parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1478         } catch (DocumentNotFoundException de) {
1479                 String msg = String.format("Could not find parent with ID='%s' when trying to delete item ID='%s'",
1480                                 parentIdentifier, itemIdentifier);
1481                 logger.warn(msg);
1482                 throw de;
1483         }
1484         String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1485         
1486         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler) createDocumentHandler(ctx);
1487         handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1488         result = getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
1489         
1490         return result;
1491     }
1492
1493     @GET
1494     @Path("{csid}/items/{itemcsid}/" + hierarchy)
1495     @Produces("application/xml")
1496     public String getHierarchy(
1497                 @PathParam("csid") String parentIdentifier,
1498             @PathParam("itemcsid") String itemIdentifier,
1499             @Context UriInfo uriInfo) throws Exception {
1500         uriInfo = new UriInfoWrapper(uriInfo);
1501         String result = null;
1502
1503         try {
1504                 //
1505             // 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...?
1506                 //
1507             String calledUri = uriInfo.getPath();
1508             String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1509             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1510             
1511             String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1512             String itemcsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1513             
1514             String direction = uriInfo.getQueryParameters().getFirst(Hierarchy.directionQP);
1515             if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1516                 result = Hierarchy.surface(ctx, itemcsid, uri);
1517             } else {
1518                 result = Hierarchy.dive(ctx, itemcsid, uri);
1519             }            
1520         } catch (Exception e) {
1521             throw bigReThrow(e, "Error showing hierarchy for authority item: ", itemIdentifier);
1522         }
1523         
1524         return result;
1525     }
1526     
1527     /**
1528      * 
1529      * @param tenantId
1530      * @return
1531      */
1532     public String getItemDocType(String tenantId) {
1533         return getDocType(tenantId, getItemServiceName());
1534     }
1535         
1536     /**
1537      * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1538      * for the current resource, for all tenants
1539      * 
1540      * @return a map of URI templates for the current resource, for all tenants
1541      */
1542     @Override
1543     public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1544         Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1545                 super.getUriRegistryEntries();
1546         List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1547         for (String tenantId : tenantIds) {
1548                 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1549         }
1550         return uriRegistryEntriesMap;
1551     }
1552     
1553     /**
1554      * 
1555      */
1556     @Override
1557         public ServiceDescription getDescription(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1558         ServiceDescription result = super.getDescription(ctx);
1559         result.setSubresourceDocumentType(this.getItemDocType(ctx.getTenantId()));
1560         return result;
1561     }
1562
1563         public Response createAuthority(String xmlPayload) {
1564                 return this.createAuthority(null, null, xmlPayload);
1565         }    
1566     
1567 }