]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
2c13f9554c6942d7f3cd0ba91a0bb2b7ebfe78c3
[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         AuthorityRefDocList authRefDocList = null;
1216  
1217         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1218         MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
1219         //
1220         // Merge parts of existing context with our new context
1221         //
1222         if (existingContext != null && existingContext.getCurrentRepositorySession() != null) {
1223             ctx.setCurrentRepositorySession(existingContext.getCurrentRepositorySession());  // If one exists, use the existing repo session
1224             ctx.setProperties(existingContext.getProperties());
1225         }
1226
1227         String parentcsid = lookupParentCSID(ctx, parentspecifier, "getReferencingObjects(parent)", "GET_ITEM_REF_OBJS", uriInfo);
1228         String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getReferencingObjects(item)", "GET_ITEM_REF_OBJS");
1229         
1230         // Remove the "type" property from the query params
1231         List<String> serviceTypes = queryParams.remove(ServiceBindingUtils.SERVICE_TYPE_PROP);        
1232         if (serviceTypes == null || serviceTypes.isEmpty()) {
1233             serviceTypes = ServiceBindingUtils.getCommonServiceTypes(true); //CSPACE-5359: Should now include objects, procedures, and authorities
1234         }
1235             
1236         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parentcsid, null);
1237         authRefDocList = handler.getReferencingObjects(ctx, uriTemplateRegistry, serviceTypes, getRefPropName(), itemcsid);
1238
1239         return authRefDocList;
1240     }
1241
1242     /**
1243      * Gets the authority terms used in the indicated Authority item.
1244      *
1245      * @param parentspecifier either a CSID or one of the urn forms
1246      * @param itemspecifier either a CSID or one of the urn forms
1247      * @param ui passed to include additional parameters, like pagination controls
1248      *
1249      * @return the authority refs for the Authority item.
1250      */
1251     @GET
1252     @Path("{csid}/items/{itemcsid}/authorityrefs")
1253     @Produces("application/xml")
1254     public AuthorityRefList getAuthorityItemAuthorityRefs(
1255             @PathParam("csid") String parentspecifier,
1256             @PathParam("itemcsid") String itemspecifier,
1257             @Context UriInfo uriInfo) {
1258         uriInfo = new UriInfoWrapper(uriInfo);
1259         AuthorityRefList authRefList = null;
1260         
1261         try {
1262             // Note that we have to create the service context for the Items, not the main service
1263             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1264             String parentcsid = lookupParentCSID(parentspecifier, "getAuthorityItemAuthRefs(parent)", "GET_ITEM_AUTH_REFS", uriInfo);
1265             // We omit the parentShortId, only needed when doing a create...
1266             DocumentModelHandler<?, AbstractCommonList> handler =
1267                     (DocumentModelHandler<?, AbstractCommonList>)createItemDocumentHandler(ctx, parentcsid, null /*no parent short ID*/);
1268
1269             String itemcsid = lookupItemCSID(ctx, itemspecifier, parentcsid, "getAuthorityItemAuthRefs(item)", "GET_ITEM_AUTH_REFS");
1270
1271             List<RefNameServiceUtils.AuthRefConfigInfo> authRefsInfo = RefNameServiceUtils.getConfiguredAuthorityRefs(ctx);
1272             authRefList = handler.getAuthorityRefs(itemcsid, authRefsInfo);
1273         } catch (Exception e) {
1274             throw bigReThrow(e, ServiceMessages.GET_FAILED + " parentspecifier: " + parentspecifier + " itemspecifier:" + itemspecifier);
1275         }
1276         
1277         return authRefList;
1278     }
1279     
1280     /**
1281      * Synchronizes a local authority item with a share authority server (SAS) item.
1282      * @param ctx
1283      * @param parentIdentifier
1284      * @param itemIdentifier
1285      * @return
1286      * @throws Exception
1287      */
1288     private PoxPayloadOut synchronizeItem(
1289             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
1290             String parentIdentifier,
1291             String itemIdentifier,
1292             boolean syncHierarchicalRelationships) throws Exception {
1293         PoxPayloadOut result = null;
1294         AuthorityItemSpecifier specifier;
1295         boolean neededSync = false;
1296
1297         CsidAndShortIdentifier parent = lookupParentCSIDAndShortIdentifer(ctx, parentIdentifier, "syncAuthorityItem(parent)", "SYNC_ITEM", null);
1298         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler)createItemDocumentHandler(ctx, parent.CSID, parent.shortIdentifier);
1299         handler.setIsProposed(AuthorityServiceUtils.NOT_PROPOSED); // In case it was formally locally proposed, clear the proposed flag
1300         handler.setIsSASItem(AuthorityServiceUtils.SAS_ITEM); // Since we're sync'ing, this is now a SAS controlled item
1301         handler.setShouldSyncHierarchicalRelationships(syncHierarchicalRelationships);
1302         // Create an authority item specifier
1303         Specifier parentSpecifier = Specifier.getSpecifier(parent.CSID, "getAuthority", "GET");
1304         Specifier itemSpecifier = Specifier.getSpecifier(itemIdentifier, "getAuthorityItem", "GET");
1305         specifier = new AuthorityItemSpecifier(parentSpecifier, itemSpecifier);
1306         //
1307         neededSync = getRepositoryClient(ctx).synchronize(ctx, specifier, handler);
1308         if (neededSync == true) {
1309             result = (PoxPayloadOut) ctx.getOutput();
1310         }
1311         
1312         return result;
1313     }
1314
1315     /**
1316      * Using the parent and item ID, sync the local item with the SAS (shared authority server)
1317      * Used by the AuthorityItemDocumentModelHandler when synchronizing a list of remote authority items with a
1318      * local authority.  The parent context was created for the authority (parent) because the sync started there.
1319      * @param existingCtx
1320      * @param parentIdentifier
1321      * @param itemIdentifier
1322      * @return
1323      * @throws Exception
1324      */
1325     public PoxPayloadOut synchronizeItemWithExistingContext(
1326             ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1327             String parentIdentifier,
1328             String itemIdentifier,
1329             boolean syncHierarchicalRelationships
1330             ) throws Exception {
1331         PoxPayloadOut result = null;
1332         
1333         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(),
1334                 existingCtx.getResourceMap(),
1335                 existingCtx.getUriInfo());
1336         if (existingCtx.getCurrentRepositorySession() != null) {
1337             ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1338             
1339         }
1340         result = synchronizeItem(ctx, parentIdentifier, itemIdentifier, syncHierarchicalRelationships);
1341         
1342         return result;
1343     }
1344     
1345     /**
1346      * Synchronizes an authority item and with a Shared Authority Server (SAS) item.
1347      * 
1348      * @param specifier either CSIDs and/or one of the urn forms
1349      * 
1350      * @return the authority item if it was updated/synchronized with SAS item; otherwise empty
1351      */
1352     @POST
1353     @Path("{csid}/items/{itemcsid}/sync")
1354     public byte[] synchronizeItem(
1355             @Context ResourceMap resourceMap,
1356             @Context UriInfo uriInfo,
1357             @PathParam("csid") String parentIdentifier,
1358             @PathParam("itemcsid") String itemIdentifier) {
1359         uriInfo = new UriInfoWrapper(uriInfo);
1360         byte[] result;
1361         boolean neededSync = false;
1362         PoxPayloadOut payloadOut = null;
1363         
1364         try {
1365             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), null, resourceMap, uriInfo);
1366             payloadOut = this.synchronizeItem(ctx, parentIdentifier, itemIdentifier, true);
1367             if (payloadOut != null) {
1368                 neededSync = true;
1369             }
1370         } catch (Exception e) {
1371             throw bigReThrow(e, ServiceMessages.SYNC_FAILED, itemIdentifier);
1372         }
1373
1374         //
1375         // If a sync was needed and was successful, return a copy of the updated resource.  Acts like an UPDATE.
1376         //
1377         if (neededSync == true) {
1378             result = payloadOut.getBytes();
1379         } else {
1380             result = String.format("Authority item resource '%s' was already in sync with shared authority server.",
1381                     itemIdentifier).getBytes();
1382             Response response = Response.status(Response.Status.NOT_MODIFIED).entity(result).type("text/plain").build();
1383             throw new CSWebApplicationException(response);
1384         }
1385         
1386         return result;
1387     }
1388     
1389     /**
1390      * Update authorityItem.
1391      * 
1392      * @param parentspecifier either a CSID or one of the urn forms
1393      * @param itemspecifier either a CSID or one of the urn forms
1394      *
1395      * @return the multipart output
1396      */
1397     @PUT
1398     @Path("{csid}/items/{itemcsid}")
1399     public byte[] updateAuthorityItem(
1400             @Context ResourceMap resourceMap, 
1401             @Context UriInfo uriInfo,
1402             @PathParam("csid") String parentSpecifier,
1403             @PathParam("itemcsid") String itemSpecifier,
1404             String xmlPayload) {
1405         uriInfo = new UriInfoWrapper(uriInfo);
1406         PoxPayloadOut result = null;
1407         
1408         try {
1409             PoxPayloadIn theUpdate = new PoxPayloadIn(xmlPayload);
1410             result = updateAuthorityItem(null, resourceMap, uriInfo, parentSpecifier, itemSpecifier, theUpdate,
1411                     AuthorityServiceUtils.UPDATE_REV,            // passing TRUE so rev num increases, passing
1412                     AuthorityServiceUtils.NO_CHANGE,    // don't change the state of the "proposed" field -we could be performing a sync or just a plain update
1413                     AuthorityServiceUtils.NO_CHANGE);    // don't change the state of the "sas" field -we could be performing a sync or just a plain update
1414         } catch (Exception e) {
1415             throw bigReThrow(e, ServiceMessages.UPDATE_FAILED);
1416         }
1417         
1418         return result.getBytes();
1419     }
1420     
1421
1422
1423     /**
1424      * Delete authorityItem.
1425      * 
1426      * @param parentIdentifier the parentcsid
1427      * @param itemIdentifier the itemcsid
1428      * 
1429      * @return the response
1430      */
1431     @DELETE
1432     @Path("{csid}/items/{itemcsid}")
1433     public Response deleteAuthorityItem(
1434             @Context UriInfo uriInfo,
1435             @PathParam("csid") String parentIdentifier,
1436             @PathParam("itemcsid") String itemIdentifier) {
1437         uriInfo = new UriInfoWrapper(uriInfo);
1438         Response result = null;
1439
1440         ensureCSID(parentIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.parentcsid");
1441         ensureCSID(itemIdentifier, ServiceMessages.DELETE_FAILED, "AuthorityItem.itemcsid");
1442         if (logger.isDebugEnabled()) {
1443             logger.debug("deleteAuthorityItem with parentcsid=" + parentIdentifier + " and itemcsid=" + itemIdentifier);
1444         }
1445         
1446         try {
1447             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1448             deleteAuthorityItem(ctx, parentIdentifier, itemIdentifier, AuthorityServiceUtils.UPDATE_REV);
1449             result = Response.status(HttpResponseCodes.SC_OK).build();
1450         } catch (Exception e) {
1451             throw bigReThrow(e, ServiceMessages.DELETE_FAILED + "  itemcsid: " + itemIdentifier + " parentcsid:" + parentIdentifier);
1452         }
1453
1454         return result;
1455     }
1456
1457     /**
1458      * 
1459      * @param existingCtx
1460      * @param parentIdentifier
1461      * @param itemIdentifier
1462      * @throws Exception
1463      */
1464     public boolean deleteAuthorityItem(ServiceContext<PoxPayloadIn, PoxPayloadOut> existingCtx,
1465             String parentIdentifier,
1466             String itemIdentifier,
1467             boolean shouldUpdateRevNumber
1468             ) throws Exception {
1469         boolean result = true;
1470         
1471         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), existingCtx.getUriInfo());
1472         if (existingCtx != null && existingCtx.getCurrentRepositorySession() != null) {
1473             ctx.setCurrentRepositorySession(existingCtx.getCurrentRepositorySession());
1474             ctx.setProperties(existingCtx.getProperties());
1475         }
1476         
1477         String parentcsid = null;
1478         try {
1479             parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1480         } catch (DocumentNotFoundException de) {
1481             String msg = String.format("Could not find parent with ID='%s' when trying to delete item ID='%s'",
1482                     parentIdentifier, itemIdentifier);
1483             logger.warn(msg);
1484             throw de;
1485         }
1486         String itemCsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1487         
1488         AuthorityItemDocumentModelHandler handler = (AuthorityItemDocumentModelHandler) createDocumentHandler(ctx);
1489         handler.setShouldUpdateRevNumber(shouldUpdateRevNumber);
1490         result = getRepositoryClient(ctx).delete(ctx, itemCsid, handler);
1491         
1492         return result;
1493     }
1494
1495     @GET
1496     @Path("{csid}/items/{itemcsid}/" + hierarchy)
1497     @Produces("application/xml")
1498     public String getHierarchy(
1499             @PathParam("csid") String parentIdentifier,
1500             @PathParam("itemcsid") String itemIdentifier,
1501             @Context UriInfo uriInfo) throws Exception {
1502         uriInfo = new UriInfoWrapper(uriInfo);
1503         String result = null;
1504
1505         try {
1506             //
1507             // 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...?
1508             //
1509             String calledUri = uriInfo.getPath();
1510             String uri = "/" + calledUri.substring(0, (calledUri.length() - ("/" + hierarchy).length()));
1511             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(getItemServiceName(), uriInfo);
1512             
1513             String parentcsid = lookupParentCSID(ctx, parentIdentifier, "deleteAuthorityItem(parent)", "DELETE_ITEM", null);
1514             String itemcsid = lookupItemCSID(ctx, itemIdentifier, parentcsid, "deleteAuthorityItem(item)", "DELETE_ITEM"); //use itemServiceCtx if it is not null
1515             
1516             String direction = uriInfo.getQueryParameters().getFirst(Hierarchy.directionQP);
1517             if (Tools.notBlank(direction) && Hierarchy.direction_parents.equals(direction)) {
1518                 result = Hierarchy.surface(ctx, itemcsid, uri);
1519             } else {
1520                 result = Hierarchy.dive(ctx, itemcsid, uri);
1521             }            
1522         } catch (Exception e) {
1523             throw bigReThrow(e, "Error showing hierarchy for authority item: ", itemIdentifier);
1524         }
1525         
1526         return result;
1527     }
1528     
1529     /**
1530      * 
1531      * @param tenantId
1532      * @return
1533      */
1534     public String getItemDocType(String tenantId) {
1535         return getDocType(tenantId, getItemServiceName());
1536     }
1537         
1538     /**
1539      * Returns a UriRegistry entry: a map of tenant-qualified URI templates
1540      * for the current resource, for all tenants
1541      * 
1542      * @return a map of URI templates for the current resource, for all tenants
1543      */
1544     @Override
1545     public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
1546         Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
1547                 super.getUriRegistryEntries();
1548         List<String> tenantIds = getTenantBindingsReader().getTenantIds();
1549         for (String tenantId : tenantIds) {
1550                 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getItemDocType(tenantId), UriTemplateFactory.ITEM));
1551         }
1552         return uriRegistryEntriesMap;
1553     }
1554     
1555     /**
1556      * 
1557      */
1558     @Override
1559     public ServiceDescription getDescription(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
1560         ServiceDescription result = super.getDescription(ctx);
1561         result.setSubresourceDocumentType(this.getItemDocType(ctx.getTenantId()));
1562         return result;
1563     }
1564
1565     public Response createAuthority(String xmlPayload) {
1566         return this.createAuthority(null, null, xmlPayload);
1567     }    
1568     
1569 }