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