]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
cd67fd3aa0dd9dde841c9d0fce4743de7b65d51a
[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
44 import org.collectionspace.services.client.IClientQueryParams;
45 import org.collectionspace.services.client.IQueryManager;
46 import org.collectionspace.services.client.PoxPayloadIn;
47 import org.collectionspace.services.client.PoxPayloadOut;
48 import org.collectionspace.services.client.workflow.WorkflowClient;
49 import org.collectionspace.services.common.CSWebApplicationException;
50 import org.collectionspace.services.common.NuxeoBasedResource;
51 import org.collectionspace.services.common.ResourceMap;
52 import org.collectionspace.services.common.ServiceMain;
53 import org.collectionspace.services.common.ServiceMessages;
54 import org.collectionspace.services.common.StoredValuesUriTemplate;
55 import org.collectionspace.services.common.UriTemplateFactory;
56 import org.collectionspace.services.common.UriTemplateRegistry;
57 import org.collectionspace.services.common.UriTemplateRegistryKey;
58 import org.collectionspace.services.common.api.RefName;
59 import org.collectionspace.services.common.api.Tools;
60 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
61 import org.collectionspace.services.common.authorityref.AuthorityRefList;
62 import org.collectionspace.services.common.context.JaxRsContext;
63 import org.collectionspace.services.common.context.MultipartServiceContext;
64 import org.collectionspace.services.common.context.RemoteServiceContext;
65 import org.collectionspace.services.common.context.ServiceBindingUtils;
66 import org.collectionspace.services.common.context.ServiceContext;
67 import org.collectionspace.services.common.document.DocumentException;
68 import org.collectionspace.services.common.document.DocumentFilter;
69 import org.collectionspace.services.common.document.DocumentHandler;
70 import org.collectionspace.services.common.document.DocumentNotFoundException;
71 import org.collectionspace.services.common.document.DocumentWrapper;
72 import org.collectionspace.services.common.document.Hierarchy;
73 import org.collectionspace.services.common.query.QueryManager;
74 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler;
75 import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler;
76 import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;
77 import org.collectionspace.services.config.ClientType;
78 import org.collectionspace.services.jaxb.AbstractCommonList;
79 import org.collectionspace.services.lifecycle.TransitionDef;
80 import org.collectionspace.services.nuxeo.client.java.DocumentModelHandler;
81 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
82 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentFilter;
83 import org.collectionspace.services.nuxeo.client.java.RepositoryClientImpl;
84 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
85 import org.collectionspace.services.workflow.WorkflowCommon;
86 import org.jboss.resteasy.util.HttpResponseCodes;
87 import org.nuxeo.ecm.core.api.DocumentModel;
88 import org.nuxeo.ecm.core.api.DocumentModelList;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
91
92 /**
93  * The Class AuthorityResource.
94  */
95 /**
96  * @author pschmitz
97  *
98  * @param <AuthCommon>
99  * @param <AuthItemHandler>
100  */
101 /**
102  * @author pschmitz
103  *
104  * @param <AuthCommon>
105  * @param <AuthItemHandler>
106  */
107 @Consumes("application/xml")
108 @Produces("application/xml")
109 public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
110         extends NuxeoBasedResource {
111         
112         final static String SEARCH_TYPE_TERMSTATUS = "ts";
113
114     protected Class<AuthCommon> authCommonClass;
115     protected Class<?> resourceClass;
116     protected String authorityCommonSchemaName;
117     protected String authorityItemCommonSchemaName;
118     final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType(); //FIXME: REM - 3 Why is this field needed?  I see no references to it.
119     final static String URN_PREFIX = "urn:cspace:";
120     final static int URN_PREFIX_LEN = URN_PREFIX.length();
121     final static String URN_PREFIX_NAME = "name(";
122     final static int URN_NAME_PREFIX_LEN = URN_PREFIX_LEN + URN_PREFIX_NAME.length();
123     final static String URN_PREFIX_ID = "id(";
124     final static int URN_ID_PREFIX_LEN = URN_PREFIX_LEN + URN_PREFIX_ID.length();
125     final static String FETCH_SHORT_ID = "_fetch_";
126     public final static String PARENT_WILDCARD = "_ALL_";
127         
128     final Logger logger = LoggerFactory.getLogger(AuthorityResource.class);
129
130     public enum SpecifierForm {
131
132         CSID, URN_NAME
133     };
134
135     public class Specifier {
136
137         public SpecifierForm form;
138         public String value;
139
140         Specifier(SpecifierForm form, String value) {
141             this.form = form;
142             this.value = value;
143         }
144     }
145
146     protected Specifier getSpecifier(String specifierIn, String method, String op) throws CSWebApplicationException {
147         if (logger.isDebugEnabled()) {
148             logger.debug("getSpecifier called by: " + method + " with specifier: " + specifierIn);
149         }
150         if (specifierIn != null) {
151             if (!specifierIn.startsWith(URN_PREFIX)) {
152                 // We'll assume it is a CSID and complain if it does not match
153                 return new Specifier(SpecifierForm.CSID, specifierIn);
154             } else {
155                 if (specifierIn.startsWith(URN_PREFIX_NAME, URN_PREFIX_LEN)) {
156                     int closeParen = specifierIn.indexOf(')', URN_NAME_PREFIX_LEN);
157                     if (closeParen >= 0) {
158                         return new Specifier(SpecifierForm.URN_NAME,
159                                 specifierIn.substring(URN_NAME_PREFIX_LEN, closeParen));
160                     }
161                 } else if (specifierIn.startsWith(URN_PREFIX_ID, URN_PREFIX_LEN)) {
162                     int closeParen = specifierIn.indexOf(')', URN_ID_PREFIX_LEN);
163                     if (closeParen >= 0) {
164                         return new Specifier(SpecifierForm.CSID,
165                                 specifierIn.substring(URN_ID_PREFIX_LEN, closeParen));
166                     }
167                 }
168             }
169         }
170         logger.error(method + ": bad or missing specifier!");
171         Response response = Response.status(Response.Status.BAD_REQUEST).entity(
172                 op + " failed on bad or missing Authority specifier").type(
173                 "text/plain").build();
174         throw new CSWebApplicationException(response);
175     }
176
177     /**
178      * Instantiates a new Authority resource.
179      */
180     public AuthorityResource(Class<AuthCommon> authCommonClass, Class<?> resourceClass,
181             String authorityCommonSchemaName, String authorityItemCommonSchemaName) {
182         this.authCommonClass = authCommonClass;
183         this.resourceClass = resourceClass;
184         this.authorityCommonSchemaName = authorityCommonSchemaName;
185         this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
186     }
187
188     public abstract String getItemServiceName();
189     
190     public abstract String getItemTermInfoGroupXPathBase();
191
192     @Override
193     protected String getVersionString() {
194         return "$LastChangedRevision: 2617 $";
195     }
196
197     @Override
198     public Class<AuthCommon> getCommonPartClass() {
199         return authCommonClass;
200     }
201
202     /**
203      * Creates the item document handler.
204      * 
205      * @param ctx the ctx
206      * @param inAuthority the in vocabulary
207      * 
208      * @return the document handler
209      * 
210      * @throws Exception the exception
211      */
212     protected DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> createItemDocumentHandler(
213             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
214             String inAuthority, String parentShortIdentifier)
215             throws Exception {
216         String authorityRefNameBase;
217         AuthorityItemDocumentModelHandler<?> docHandler;
218
219         if (parentShortIdentifier == null) {
220             authorityRefNameBase = null;
221         } else {
222             ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx =
223                     createServiceContext(getServiceName());
224             if (parentShortIdentifier.equals(FETCH_SHORT_ID)) {
225                 // Get from parent document
226                 parentShortIdentifier = getAuthShortIdentifier(parentCtx, inAuthority);
227             }
228             authorityRefNameBase = buildAuthorityRefNameBase(parentCtx, parentShortIdentifier);
229         }
230
231         docHandler = (AuthorityItemDocumentModelHandler<?>) createDocumentHandler(ctx,
232                 ctx.getCommonPartLabel(getItemServiceName()),
233                 authCommonClass);
234         // FIXME - Richard and Aron think the following three lines should
235         // be in the constructor for the AuthorityItemDocumentModelHandler
236         // because all three are required fields.
237         docHandler.setInAuthority(inAuthority);
238         docHandler.setAuthorityRefNameBase(authorityRefNameBase);
239         docHandler.setItemTermInfoGroupXPathBase(getItemTermInfoGroupXPathBase());
240         return docHandler;
241     }
242
243     public String getAuthShortIdentifier(
244             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String authCSID)
245             throws DocumentNotFoundException, DocumentException {
246         String shortIdentifier = null;
247         try {
248             AuthorityDocumentModelHandler<?> handler =
249                     (AuthorityDocumentModelHandler<?>) createDocumentHandler(ctx);
250             shortIdentifier = handler.getShortIdentifier(authCSID, authorityCommonSchemaName);
251         } catch (Exception e) {
252             if (logger.isDebugEnabled()) {
253                 logger.debug("Caught exception ", e);
254             }
255             throw new DocumentException(e);
256         }
257         return shortIdentifier;
258     }
259
260     protected String buildAuthorityRefNameBase(
261             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String shortIdentifier) {
262         RefName.Authority authority = RefName.Authority.buildAuthority(ctx.getTenantName(),
263                 ctx.getServiceName(), 
264                 null,   // Only use shortId form!!!
265                 shortIdentifier, null);
266         return authority.toString();
267     }
268
269     public static class CsidAndShortIdentifier {
270         String CSID;
271         String shortIdentifier;
272     }
273
274         protected String lookupParentCSID(String parentspecifier, String method,
275                         String op, UriInfo uriInfo) throws Exception {
276                 CsidAndShortIdentifier tempResult = lookupParentCSIDAndShortIdentifer(
277                                 parentspecifier, method, op, uriInfo);
278                 return tempResult.CSID;
279         }
280
281     private CsidAndShortIdentifier lookupParentCSIDAndShortIdentifer(
282                 String parentspecifier,
283                 String method,
284                 String op,
285                 UriInfo uriInfo)
286             throws Exception {
287         CsidAndShortIdentifier result = new CsidAndShortIdentifier();
288         Specifier parentSpec = getSpecifier(parentspecifier, method, op);
289         // Note that we have to create the service context for the Items, not the main service
290         String parentcsid;
291         String parentShortIdentifier;
292         if (parentSpec.form == SpecifierForm.CSID) {
293             parentShortIdentifier = null;
294             parentcsid = parentSpec.value;
295             // Uncomment when app layer is ready to integrate
296             // Uncommented since refNames are currently only generated if not present - ADR CSPACE-3178
297             parentShortIdentifier = FETCH_SHORT_ID;
298         } else {
299             parentShortIdentifier = parentSpec.value;
300             String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, parentSpec.value);
301             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getServiceName(), uriInfo);
302             parentcsid = getRepositoryClient(ctx).findDocCSID(null, ctx, whereClause); //FIXME: REM - If the parent has been soft-deleted, should we be looking for the item?
303         }
304         result.CSID = parentcsid;
305         result.shortIdentifier = parentShortIdentifier;
306         return result;
307     }
308
309     public String lookupItemCSID(String itemspecifier, String parentcsid, String method, String op, ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx)
310             throws DocumentException {
311         String itemcsid;
312         Specifier itemSpec = getSpecifier(itemspecifier, method, op);
313         if (itemSpec.form == SpecifierForm.CSID) {
314             itemcsid = itemSpec.value;
315         } else {
316             String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
317             itemcsid = getRepositoryClient(ctx).findDocCSID(null, ctx, itemWhereClause); //FIXME: REM - Should we be looking for the 'wf_deleted' query param and filtering on it?
318         }
319         return itemcsid;
320     }
321
322     /*
323      * Generally, callers will first call RefName.AuthorityItem.parse with a refName, and then 
324      * use the returned item.inAuthority.resource and a resourceMap to get a service-specific
325      * Resource. They then call this method on that resource.
326      */
327     @Override
328         public DocumentModel getDocModelForAuthorityItem(CoreSessionInterface repoSession, RefName.AuthorityItem item) 
329                         throws Exception, DocumentNotFoundException {
330         if(item == null) {
331                 return null;
332         }
333         String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, item.getParentShortIdentifier());
334         // Ensure we have the right context.
335         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(item.inAuthority.resource);
336         
337         // HACK - this really must be moved to the doc handler, not here. No Nuxeo specific stuff here!
338         RepositoryClientImpl client = (RepositoryClientImpl)getRepositoryClient(ctx);
339         String parentcsid = client.findDocCSID(repoSession, ctx, whereClause);
340
341         String itemWhereClause = RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, item.getShortIdentifier(), parentcsid);
342         ctx = createServiceContext(getItemServiceName());
343         DocumentWrapper<DocumentModel> docWrapper = client.findDoc(repoSession, ctx, itemWhereClause);
344         DocumentModel docModel = docWrapper.getWrappedObject();
345         return docModel;
346     }
347
348
349     @POST
350     public Response createAuthority(String xmlPayload) {
351         //
352         // 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
353         // transaction code to deal with a database level UNIQUE constraint violations on the 'shortidentifier' column of the vocabularies_common table.
354         // Therefore, to prevent having multiple authorities with the same shortid, we need to synchronize
355         // the code that creates new authorities.  The authority document model handler will first check for authorities with the same short id before
356         // trying to create a new authority.
357         //
358         synchronized(AuthorityResource.class) {
359                 try {
360                     PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
361                     ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(input);
362                     DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
363                     String csid = getRepositoryClient(ctx).create(ctx, handler);
364                     UriBuilder path = UriBuilder.fromResource(resourceClass);
365                     path.path("" + csid);
366                     Response response = Response.created(path.build()).build();
367                     return response;
368                 } catch (Exception e) {
369                     throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
370                 }
371         }
372     }
373
374
375     /**
376      * Synchronizes the authority and its terms with a Shared Authority Server.
377      * 
378      * @param specifier either a CSID or one of the urn forms
379      * 
380      * @return the authority
381      */
382     @GET
383     @Path("{csid}/sync")
384     public Response synchronize(
385             @Context Request request,
386             @Context UriInfo ui,
387             @PathParam("csid") String csid) {
388         boolean result = false;
389         Specifier specifier;
390         
391         try {
392             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
393             AuthorityDocumentModelHandler handler = (AuthorityDocumentModelHandler)createDocumentHandler(ctx);
394             specifier = getSpecifier(csid, "getAuthority", "GET");
395             result = handler.synchronize(specifier);       
396         } catch (Exception e) {
397             throw bigReThrow(e, ServiceMessages.SYNC_FAILED, csid);
398         }
399
400         if (result == false) {
401             Response response = Response.status(Response.Status.NOT_FOUND).entity(
402                     "Get failed, the requested Authority specifier:" + specifier + ": was not found.").type(
403                     "text/plain").build();
404             throw new CSWebApplicationException(response);
405         }
406
407         return Response.status(Response.Status.OK).entity(
408                 "Synchronization completed, the requested Authority specifier:" + specifier.value + ": was synchronized.").type(
409                 "text/plain").build();
410     }
411     
412     /**
413      * Gets the authority.
414      * 
415      * @param specifier either a CSID or one of the urn forms
416      * 
417      * @return the authority
418      */
419     @GET
420     @Path("{csid}")
421     @Override
422     public byte[] get(
423             @Context Request request,
424             @Context UriInfo ui,
425             @PathParam("csid") String specifier) {
426         PoxPayloadOut result = null;
427         try {
428             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
429             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
430
431             Specifier spec = getSpecifier(specifier, "getAuthority", "GET");
432             if (spec.form == SpecifierForm.CSID) {
433                 if (logger.isDebugEnabled()) {
434                     logger.debug("getAuthority with csid=" + spec.value);
435                 }
436                 getRepositoryClient(ctx).get(ctx, spec.value, handler);
437             } else {
438                 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
439                 DocumentFilter myFilter = new NuxeoDocumentFilter(whereClause, 0, 1);
440                 handler.setDocumentFilter(myFilter);
441                 getRepositoryClient(ctx).get(ctx, handler);
442             }
443             result = ctx.getOutput();
444
445         } catch (Exception e) {
446             throw bigReThrow(e, ServiceMessages.GET_FAILED, specifier);
447         }
448
449         if (result == null) {
450             Response response = Response.status(Response.Status.NOT_FOUND).entity(
451                     "Get failed, the requested Authority specifier:" + specifier + ": was not found.").type(
452                     "text/plain").build();
453             throw new CSWebApplicationException(response);
454         }
455
456         return result.getBytes();
457     }
458
459     /**
460      * Finds and populates the authority list.
461      * 
462      * @param ui the ui
463      * 
464      * @return the authority list
465      */
466     @GET
467     @Produces("application/xml")
468     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.
469         AbstractCommonList result = null;
470         
471         try {
472             MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
473             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
474             
475             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
476             DocumentFilter myFilter = handler.getDocumentFilter();
477             // Need to make the default sort order for authority items
478             // be on the displayName field
479             String sortBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
480             if (sortBy == null || sortBy.isEmpty()) {
481                 String qualifiedDisplayNameField = authorityCommonSchemaName + ":"
482                         + AuthorityItemJAXBSchema.DISPLAY_NAME;
483                 myFilter.setOrderByClause(qualifiedDisplayNameField);
484             }
485             String nameQ = queryParams.getFirst("refName");
486             if (nameQ != null) {
487                 myFilter.setWhereClause(authorityCommonSchemaName + ":refName='" + nameQ + "'");
488             }
489             getRepositoryClient(ctx).getFiltered(ctx, handler);
490             result = handler.getCommonPartList();
491         } catch (Exception e) {
492             throw bigReThrow(e, ServiceMessages.GET_FAILED);
493         }
494         
495         return result;
496     }
497     
498     /**
499      * Update authority.
500      *
501      * @param specifier the csid or id
502      *
503      * @return the multipart output
504      */
505     @PUT
506     @Path("{csid}")
507     public byte[] updateAuthority(
508             @PathParam("csid") String specifier,
509             String xmlPayload) {
510         PoxPayloadOut result = null;
511         try {
512             PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
513             Specifier spec = getSpecifier(specifier, "updateAuthority", "UPDATE");
514             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(theUpdate);
515             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
516             String csid;
517             if (spec.form == SpecifierForm.CSID) {
518                 csid = spec.value;
519             } else {
520                 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
521                 csid = getRepositoryClient(ctx).findDocCSID(null, ctx, whereClause);
522             }
523             getRepositoryClient(ctx).update(ctx, csid, handler);
524             result = ctx.getOutput();
525         } catch (Exception e) {
526             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
527         }
528         return result.getBytes();
529     }
530
531     /**
532      * Delete authority.
533      * 
534      * @param csid the csid
535      * 
536      * @return the response
537      */
538     @Deprecated
539 //    @DELETE
540     @Path("{csid}")
541     public Response old_deleteAuthority(@PathParam("csid") String csid) {
542         if (logger.isDebugEnabled()) {
543             logger.debug("deleteAuthority with csid=" + csid);
544         }
545         try {
546             ensureCSID(csid, ServiceMessages.DELETE_FAILED, "Authority.csid");
547             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
548             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
549             getRepositoryClient(ctx).delete(ctx, csid, handler);
550             return Response.status(HttpResponseCodes.SC_OK).build();
551         } catch (Exception e) {
552             throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid);
553         }
554     }
555     
556     /**
557      * Delete authority
558      * 
559      * @param csid the csid or a URN specifier form -e.g., urn:cspace:name(OurMuseumPersonAuthority)
560      * 
561      * @return the response
562      */
563     @DELETE
564     @Path("{csid}")
565     public Response deleteAuthority(
566             @Context Request request,
567             @Context UriInfo ui,
568             @PathParam("csid") String specifier) {
569         if (logger.isDebugEnabled()) {
570             logger.debug("deleteAuthority with specifier=" + specifier);
571         }
572         
573         try {
574             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(ui);
575             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
576
577             Specifier spec = getSpecifier(specifier, "getAuthority", "GET");
578             if (spec.form == SpecifierForm.CSID) {
579                 if (logger.isDebugEnabled()) {
580                     logger.debug("deleteAuthority with csid=" + spec.value);
581                 }
582                 ensureCSID(spec.value, ServiceMessages.DELETE_FAILED, "Authority.csid");
583                 getRepositoryClient(ctx).delete(ctx, spec.value, handler);
584             } else {
585                 if (logger.isDebugEnabled()) {
586                     logger.debug("deleteAuthority with specifier=" + spec.value);
587                 }               
588                 String whereClause = RefNameServiceUtils.buildWhereForAuthByName(authorityCommonSchemaName, spec.value);
589                 getRepositoryClient(ctx).deleteWithWhereClause(ctx, whereClause, handler);
590             }
591             
592             return Response.status(HttpResponseCodes.SC_OK).build();
593         } catch (Exception e) {
594             throw bigReThrow(e, ServiceMessages.DELETE_FAILED, specifier);
595         }
596     }
597     
598
599     /*************************************************************************
600      * Create an AuthorityItem - this is a sub-resource of Authority
601      * @param specifier either a CSID or one of the urn forms
602      * @return Authority item response
603      *************************************************************************/
604     @POST
605     @Path("{csid}/items")
606     public Response createAuthorityItem(
607                 @Context ResourceMap resourceMap,
608                 @Context UriInfo uriInfo, 
609                 @PathParam("csid") String parentspecifier,
610                 String xmlPayload) {
611         Response result = null;
612         
613         try {
614             PoxPayloadIn input = new PoxPayloadIn(xmlPayload);
615             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), input, resourceMap, uriInfo);
616
617             // Note: must have the parentShortId, to do the create.
618             CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(parentspecifier, "createAuthorityItem", "CREATE_ITEM", null);
619             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = 
620                 createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
621             String itemcsid = getRepositoryClient(ctx).create(ctx, handler);
622             UriBuilder path = UriBuilder.fromResource(resourceClass);
623             path.path(parent.CSID + "/items/" + itemcsid);
624             result = Response.created(path.build()).build();
625         } catch (Exception e) {
626             throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
627         }
628         
629         return result;
630     }
631
632     @GET
633     @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH)
634     public byte[] getItemWorkflow(
635             @PathParam("csid") String csid,
636             @PathParam("itemcsid") String itemcsid) {
637         PoxPayloadOut result = null;
638
639         try {
640             ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
641             String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
642
643             MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME);
644             WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
645             ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
646             getRepositoryClient(ctx).get(ctx, itemcsid, handler);
647             result = ctx.getOutput();
648         } catch (Exception e) {
649             throw bigReThrow(e, ServiceMessages.READ_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
650         }
651         return result.getBytes();
652     }
653
654     //FIXME: This method is almost identical to the method org.collectionspace.services.common.updateWorkflowWithTransition() so
655     // they should be consolidated -be DRY (don't repeat yourself).
656     @PUT
657     @Path("{csid}/items/{itemcsid}" + WorkflowClient.SERVICE_PATH + "/{transition}")
658     public byte[] updateItemWorkflowWithTransition(
659             @PathParam("csid") String csid,
660             @PathParam("itemcsid") String itemcsid,
661             @PathParam("transition") String transition) {
662         PoxPayloadOut result = null;
663         
664         try {
665                 //
666                 // Create an empty workflow_commons input part and set it into a new "workflow" sub-resource context
667                 PoxPayloadIn input = new PoxPayloadIn(WorkflowClient.SERVICE_PAYLOAD_NAME, new WorkflowCommon(), 
668                                 WorkflowClient.SERVICE_COMMONPART_NAME);
669             MultipartServiceContext ctx = (MultipartServiceContext) createServiceContext(WorkflowClient.SERVICE_NAME, input);
670
671             // Create a service context and document handler for the parent resource.
672             ServiceContext<PoxPayloadIn, PoxPayloadOut> parentCtx = createServiceContext(getItemServiceName());
673             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> parentDocHandler = this.createDocumentHandler(parentCtx);
674             ctx.setProperty(WorkflowClient.PARENT_DOCHANDLER, parentDocHandler); //added as a context param for the workflow document handler -it will call the parent's dochandler "prepareForWorkflowTranstion" method
675
676             // When looking for the document, we need to use the parent's workspace name -not the "workflow" workspace name
677             String parentWorkspaceName = parentCtx.getRepositoryWorkspaceName();
678             ctx.setRespositoryWorkspaceName(parentWorkspaceName); //find the document in the parent's workspace
679             
680                 // Get the type of transition we're being asked to make and store it as a context parameter -used by the workflow document handler
681             TransitionDef transitionDef = getTransitionDef(parentCtx, transition);
682             ctx.setProperty(WorkflowClient.TRANSITION_ID, transitionDef);
683             
684             WorkflowDocumentModelHandler handler = createWorkflowDocumentHandler(ctx);
685             getRepositoryClient(ctx).update(ctx, itemcsid, handler);
686             result = ctx.getOutput();
687         } catch (Exception e) {
688             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED + WorkflowClient.SERVICE_PAYLOAD_NAME, csid);
689         }
690         
691         return result.getBytes();
692     }
693
694     /**
695      * Gets the authority item.
696      * 
697      * @param parentspecifier either a CSID or one of the urn forms
698      * @param itemspecifier either a CSID or one of the urn forms
699      * 
700      * @return the authority item
701      */
702     @GET
703     @Path("{csid}/items/{itemcsid}")
704     public byte[] getAuthorityItem(
705             @Context Request request,
706             @Context UriInfo uriInfo,
707                 @Context ResourceMap resourceMap,            
708             @PathParam("csid") String parentspecifier,
709             @PathParam("itemcsid") String itemspecifier) {
710         PoxPayloadOut result = null;
711         try {
712             String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItem(parent)", "GET_ITEM", uriInfo);
713
714             RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = 
715                 (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(getItemServiceName(), resourceMap, uriInfo);
716             
717             JaxRsContext jaxRsContext = new JaxRsContext(request, uriInfo); // REM - Why are we setting this?  Who is using the getter?
718             ctx.setJaxRsContext(jaxRsContext);
719
720             // We omit the parentShortId, only needed when doing a create...
721             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, null);
722
723             Specifier itemSpec = getSpecifier(itemspecifier, "getAuthorityItem(item)", "GET_ITEM");
724             if (itemSpec.form == SpecifierForm.CSID) {
725                 getRepositoryClient(ctx).get(ctx, itemSpec.value, handler);
726             } else {
727                 String itemWhereClause =
728                                 RefNameServiceUtils.buildWhereForAuthItemByName(authorityItemCommonSchemaName, itemSpec.value, parentcsid);
729                 DocumentFilter myFilter = new NuxeoDocumentFilter(itemWhereClause, 0, 1); // start at page 0 and get 1 item
730                 handler.setDocumentFilter(myFilter);
731                 getRepositoryClient(ctx).get(ctx, handler);
732             }
733             // TODO should we assert that the item is in the passed vocab?
734             result = ctx.getOutput();
735         } catch (Exception e) {
736             throw bigReThrow(e, ServiceMessages.GET_FAILED);
737         }
738         
739         if (result == null) {
740             Response response = Response.status(Response.Status.NOT_FOUND).entity(
741                     "Get failed, the requested AuthorityItem specifier:" + itemspecifier + ": was not found.").type(
742                     "text/plain").build();
743             throw new CSWebApplicationException(response);
744         }
745         
746         return result.getBytes();
747     }
748
749     /*
750      * Most of the authority child classes will/should use this implementation.  However, the Vocabulary service's item schema is
751      * different enough that it will have to override this method in it's resource class.
752      */
753     @Override
754         protected String getOrderByField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
755                 String result = null;
756
757                 result = NuxeoUtils.getPrimaryElPathPropertyName(
758                                 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
759                                 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
760
761                 return result;
762         }
763         
764     @Override
765         protected String getPartialTermMatchField(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
766                 String result = null;
767                 
768                 result = NuxeoUtils.getMultiElPathPropertyName(
769                                 authorityItemCommonSchemaName, getItemTermInfoGroupXPathBase(),
770                                 AuthorityItemJAXBSchema.TERM_DISPLAY_NAME);
771
772                 return result;
773         }
774     
775     /**
776      * Gets the authorityItem list for the specified authority
777      * If partialPerm is specified, keywords will be ignored.
778      * 
779      * @param specifier either a CSID or one of the urn forms
780      * @param partialTerm if non-null, matches partial terms
781      * @param keywords if non-null, matches terms in the keyword index for items
782      * @param ui passed to include additional parameters, like pagination controls
783      * 
784      * @return the authorityItem list
785      */
786     @GET
787     @Path("{csid}/items")
788     @Produces("application/xml")
789     public AbstractCommonList getAuthorityItemList(@PathParam("csid") String specifier,
790             @Context UriInfo uriInfo) {
791         AbstractCommonList result = null;
792         
793         try {
794             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
795             MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
796             
797             String orderBy = queryParams.getFirst(IClientQueryParams.ORDER_BY_PARAM);
798             String termStatus = queryParams.getFirst(SEARCH_TYPE_TERMSTATUS);
799             String keywords = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_KW);
800             String advancedSearch = queryParams.getFirst(IQueryManager.SEARCH_TYPE_KEYWORDS_AS);
801             String partialTerm = queryParams.getFirst(IQueryManager.SEARCH_TYPE_PARTIALTERM);
802
803             // For the wildcard case, parentcsid is null, but docHandler will deal with this.
804             // We omit the parentShortId, only needed when doing a create...
805             String parentcsid = PARENT_WILDCARD.equals(specifier) ? null :
806                                 lookupParentCSID(specifier, "getAuthorityItemList", "LIST", uriInfo);
807             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler =
808                 createItemDocumentHandler(ctx, parentcsid, null);
809             
810             DocumentFilter myFilter = handler.getDocumentFilter();
811             // If we are not wildcarding the parent, add a restriction
812             if (parentcsid != null) {
813                     myFilter.appendWhereClause(authorityItemCommonSchemaName + ":"
814                             + AuthorityItemJAXBSchema.IN_AUTHORITY + "="
815                             + "'" + parentcsid + "'",
816                             IQueryManager.SEARCH_QUALIFIER_AND);
817             }
818
819             if (Tools.notBlank(termStatus)) {
820                 // Start with the qualified termStatus field
821                 String qualifiedTermStatusField = authorityItemCommonSchemaName + ":"
822                         + AuthorityItemJAXBSchema.TERM_STATUS;
823                 String[] filterTerms = termStatus.trim().split("\\|");
824                 String tsClause = QueryManager.createWhereClauseToFilterFromStringList(qualifiedTermStatusField, filterTerms, IQueryManager.FILTER_EXCLUDE);
825                 myFilter.appendWhereClause(tsClause, IQueryManager.SEARCH_QUALIFIER_AND);
826             }
827
828             result = search(ctx, handler, uriInfo, orderBy, keywords, advancedSearch, partialTerm);            
829         } catch (Exception e) {
830             throw bigReThrow(e, ServiceMessages.LIST_FAILED);
831         }
832         
833         return result;
834     }
835
836     /**
837      * @return the name of the property used to specify references for items in this type of
838      * authority. For most authorities, it is ServiceBindingUtils.AUTH_REF_PROP ("authRef").
839      * Some types (like Vocabulary) use a separate property.
840      */
841     protected String getRefPropName() {
842         return ServiceBindingUtils.AUTH_REF_PROP;
843     }
844     
845     /**
846      * Gets the entities referencing this Authority item instance. The service type
847      * can be passed as a query param "type", and must match a configured type
848      * for the service bindings. If not set, the type defaults to
849      * ServiceBindingUtils.SERVICE_TYPE_PROCEDURE.
850      *
851      * @param parentspecifier either a CSID or one of the urn forms
852      * @param itemspecifier either a CSID or one of the urn forms
853      * @param ui the ui
854      * 
855      * @return the info for the referencing objects
856      */
857     @GET
858     @Path("{csid}/items/{itemcsid}/refObjs")
859     @Produces("application/xml")
860     public AuthorityRefDocList getReferencingObjects(
861             @PathParam("csid") String parentspecifier,
862             @PathParam("itemcsid") String itemspecifier,
863             @Context UriTemplateRegistry uriTemplateRegistry,
864             @Context UriInfo uriInfo) {
865         AuthorityRefDocList authRefDocList = null;
866         try {
867             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
868             MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
869
870             String parentcsid = lookupParentCSID(parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
871             String itemcsid = lookupItemCSID(itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS", ctx);
872
873             List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);
874             if(serviceTypes == null || serviceTypes.isEmpty()) {
875                 serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
876             }
877             
878             // Note that we have to create the service context for the Items, not the main service
879             // We omit the parentShortId, only needed when doing a create...
880             AuthorityItemDocumentModelHandler<?> handler = (AuthorityItemDocumentModelHandler<?>)
881                                                                                                 createItemDocumentHandler(ctx, parentcsid, null);
882
883             authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
884         } catch (Exception e) {
885             throw bigReThrow(e, ServiceMessages.GET_FAILED);
886         }
887         if (authRefDocList == null) {
888             Response response = Response.status(Response.Status.NOT_FOUND).entity(
889                     "Get failed, the requested Item CSID:" + itemspecifier + ": was not found.").type(
890                     "text/plain").build();
891             throw new CSWebApplicationException(response);
892         }
893         return authRefDocList;
894     }
895
896     /**
897      * Gets the authority terms used in the indicated Authority item.
898      *
899      * @param parentspecifier either a CSID or one of the urn forms
900      * @param itemspecifier either a CSID or one of the urn forms
901      * @param ui passed to include additional parameters, like pagination controls
902      *
903      * @return the authority refs for the Authority item.
904      */
905     @GET
906     @Path("{csid}/items/{itemcsid}/authorityrefs")
907     @Produces("application/xml")
908     public AuthorityRefList getAuthorityItemAuthorityRefs(
909             @PathParam("csid") String parentspecifier,
910             @PathParam("itemcsid") String itemspecifier,
911             @Context UriInfo uriInfo) {
912         AuthorityRefList authRefList = null;
913         try {
914             // Note that we have to create the service context for the Items, not the main service
915             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
916             MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
917             String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
918             // We omit the parentShortId, only needed when doing a create...
919             DocumentModelHandler<?, AbstractCommonList> handler =
920                     (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
921
922             String itemcsid = lookupItemCSID(itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS", ctx);
923
924             List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
925             authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
926         } catch (Exception e) {
927             throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
928         }
929         return authRefList;
930     }
931
932     /**
933      * Update authorityItem.
934      * 
935      * @param parentspecifier either a CSID or one of the urn forms
936      * @param itemspecifier either a CSID or one of the urn forms
937      *
938      * @return the multipart output
939      */
940     @PUT
941     @Path("{csid}/items/{itemcsid}")
942     public byte[] updateAuthorityItem(
943                 @Context ResourceMap resourceMap, 
944             @Context UriInfo uriInfo,
945             @PathParam("csid") String parentspecifier,
946             @PathParam("itemcsid") String itemspecifier,
947             String xmlPayload) {
948         PoxPayloadOut result = null;
949         try {
950             PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
951             // Note that we have to create the service context for the Items, not the main service
952             // Laramie CSPACE-3175.  passing null for queryParams, because prior to this refactor, the code moved to lookupParentCSID in this instance called the version of getServiceContext() that passes null
953             CsidAndShortIdentifier csidAndShortId = lookupParentCSIDAndShortIdentifer(parentspecifier, "updateAuthorityItem(parent)", "UPDATE_ITEM", null);
954             String parentcsid = csidAndShortId.CSID;
955             String parentShortId = csidAndShortId.shortIdentifier;
956
957             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), theUpdate, resourceMap, uriInfo);
958             String itemcsid = lookupItemCSID(itemspecifier, parentcsid, "updateAuthorityItem(item)", "UPDATE_ITEM", ctx);
959
960             // We omit the parentShortId, only needed when doing a create...
961             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createItemDocumentHandler(ctx, parentcsid, parentShortId);
962             getRepositoryClient(ctx).update(ctx, itemcsid, handler);
963             result = ctx.getOutput();
964
965         } catch (Exception e) {
966             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
967         }
968         return result.getBytes();
969     }
970
971     /**
972      * Delete authorityItem.
973      * 
974      * @param parentcsid the parentcsid
975      * @param itemcsid the itemcsid
976      * 
977      * @return the response
978      */
979     @DELETE
980     @Path("{csid}/items/{itemcsid}")
981     public Response deleteAuthorityItem(
982             @PathParam("csid") String parentcsid,
983             @PathParam("itemcsid") String itemcsid) {
984         //try{
985         if (logger.isDebugEnabled()) {
986             logger.debug("deleteAuthorityItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid);
987         }
988         try {
989             ensureCSID(parentcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
990             ensureCSID(itemcsid, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
991             //Laramie, removing this catch, since it will surely fail below, since itemcsid or parentcsid will be null.
992             // }catch (Throwable t){
993             //    System.out.println("ERROR in setting up DELETE: "+t);
994             // }
995             // try {
996             // Note that we have to create the service context for the Items, not the main service
997             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName());
998             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
999             getRepositoryClient(ctx).delete(ctx, itemcsid, handler);
1000             return Response.status(HttpResponseCodes.SC_OK).build();
1001         } catch (Exception e) {
1002             throw bigReThrow(e, ServiceMessages.DELETE_FAILED + "  itemcsid: " + itemcsid + " parentcsid:" + parentcsid);
1003         }
1004     }
1005     public final static String hierarchy = "hierarchy";
1006
1007     @GET
1008     @Path("{csid}/items/{itemcsid}/" + hierarchy)
1009     @Produces("application/xml")
1010     public String getHierarchy(@PathParam("csid") String csid,
1011             @PathParam("itemcsid") String itemcsid,
1012             @Context UriInfo ui) throws Exception {
1013         try {
1014             // 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...?
1015             String calledUri = ui.getPath();
1016             String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1017             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), ui);
1018             ctx.setUriInfo(ui);
1019             String direction = ui.getQueryParameters().getFirst(Hierarchy.directionQP);
1020             if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1021                 return Hierarchy.surface(ctx, itemcsid, uri);
1022             } else {
1023                 return Hierarchy.dive(ctx, itemcsid, uri);
1024             }
1025         } catch (Exception e) {
1026             throw bigReThrow(e, "Error showing hierarchy", itemcsid);
1027         }
1028     }
1029     
1030     protected String getItemDocType(String tenantId) {
1031         return getDocType(tenantId, getItemServiceName());
1032     }
1033         
1034     /**
1035      * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1036      * for the current resource, for all tenants
1037      * 
1038      * @return a map of URI templates for the current resource, for all tenants
1039      */
1040     @Override
1041     public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1042         Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1043                 super.getUriRegistryEntries();
1044         List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1045         for (String tenantId : tenantIds) {
1046                 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1047         }
1048         return uriRegistryEntriesMap;
1049     }
1050   
1051 }