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