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:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
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.
24 package org.collectionspace.services.servicegroup.nuxeo;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
32 import javax.ws.rs.core.MultivaluedMap;
33 import javax.ws.rs.core.Response;
35 import org.collectionspace.services.nuxeo.client.java.CommonList;
36 import org.collectionspace.services.nuxeo.client.java.NuxeoDocumentModelHandler;
37 import org.collectionspace.services.nuxeo.client.java.CoreSessionInterface;
38 import org.collectionspace.services.nuxeo.client.java.NuxeoRepositoryClientImpl;
39 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
40 import org.collectionspace.services.jaxb.AbstractCommonList;
41 import org.collectionspace.services.client.CollectionSpaceClient;
42 import org.collectionspace.services.client.IQueryManager;
43 import org.collectionspace.services.client.IRelationsManager;
44 import org.collectionspace.services.client.PoxPayloadIn;
45 import org.collectionspace.services.client.PoxPayloadOut;
46 import org.collectionspace.services.common.NuxeoBasedResource;
47 import org.collectionspace.services.common.CSWebApplicationException;
48 import org.collectionspace.services.common.ServiceMain;
49 import org.collectionspace.services.common.ServiceMessages;
50 import org.collectionspace.services.common.StoredValuesUriTemplate;
51 import org.collectionspace.services.common.UriTemplateFactory;
52 import org.collectionspace.services.common.UriTemplateRegistry;
53 import org.collectionspace.services.common.UriTemplateRegistryKey;
54 import org.collectionspace.services.common.api.RefName;
55 import org.collectionspace.services.common.api.RefNameUtils;
56 import org.collectionspace.services.common.api.RefNameUtils.AuthorityTermInfo;
57 import org.collectionspace.services.common.api.Tools;
58 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
59 import org.collectionspace.services.common.context.AbstractServiceContextImpl;
60 import org.collectionspace.services.common.context.ServiceBindingUtils;
61 import org.collectionspace.services.common.context.ServiceContext;
62 import org.collectionspace.services.common.document.DocumentException;
63 import org.collectionspace.services.common.document.DocumentFilter;
64 import org.collectionspace.services.common.document.DocumentNotFoundException;
65 import org.collectionspace.services.common.document.DocumentWrapper;
66 import org.collectionspace.services.common.document.TransactionException;
67 import org.collectionspace.services.common.security.SecurityUtils;
68 import org.collectionspace.services.common.query.QueryContext;
69 import org.collectionspace.services.common.query.nuxeo.QueryManagerNuxeoImpl;
70 import org.collectionspace.services.common.relation.nuxeo.RelationsUtils;
71 import org.collectionspace.services.config.service.ListResultField;
72 import org.collectionspace.services.config.service.ServiceBindingType;
73 import org.collectionspace.services.config.service.ServiceObjectType;
74 import org.collectionspace.services.servicegroup.ServicegroupsCommon;
75 import org.collectionspace.services.common.vocabulary.AuthorityResource;
76 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
77 import org.nuxeo.ecm.core.api.DocumentModel;
78 import org.nuxeo.ecm.core.api.DocumentModelList;
79 import org.nuxeo.ecm.core.api.PropertyException;
80 import org.slf4j.Logger;
81 import org.slf4j.LoggerFactory;
83 public class ServiceGroupDocumentModelHandler
84 extends NuxeoDocumentModelHandler<ServicegroupsCommon> {
86 protected final Logger logger = LoggerFactory.getLogger(this.getClass());
88 protected static final int NUM_META_FIELDS = 4; // the number of meta fields -i.e., DOC_TYPE_FIELD, DOC_NUMBER_FIELD, DOC_NAME_FIELD, STANDARD_LIST_MARK_RT_FIELD
89 protected static final String DOC_TYPE_FIELD = "docType";
90 protected static final String DOC_NUMBER_FIELD = "docNumber";
91 protected static final String DOC_NAME_FIELD = "docName";
92 protected static final String STANDARD_LIST_MARK_RT_FIELD = "related";
95 // Returns a service payload for an authority item
97 private PoxPayloadOut getAuthorityItem(ServiceContext ctx, String termRefName) throws Exception {
98 PoxPayloadOut result = null;
100 RefName.AuthorityItem item = RefName.AuthorityItem.parse(termRefName, true);
101 AuthorityResource authorityResource = (AuthorityResource) ctx.getResourceMap().get(item.inAuthority.resource);
103 AuthorityTermInfo authorityTermInfo = RefNameUtils.parseAuthorityTermInfo(termRefName);
104 String parentIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.inAuthority.name);
105 String itemIdentifier = Specifier.createShortIdURNValue(authorityTermInfo.name);
107 result = authorityResource.getAuthorityItemWithExistingContext(ctx, parentIdentifier, itemIdentifier);
112 public PoxPayloadOut getResourceItemForCsid(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
113 List<String> serviceGroupNames,
114 String csid) throws DocumentException {
115 PoxPayloadOut result = null;
116 CoreSessionInterface repoSession = null;
117 boolean releaseRepoSession = false;
120 NuxeoRepositoryClientImpl repoClient = (NuxeoRepositoryClientImpl)this.getRepositoryClient(ctx);
121 repoSession = this.getRepositorySession();
122 if (repoSession == null) {
123 repoSession = repoClient.getRepositorySession(ctx);
124 releaseRepoSession = true;
127 Map<String, ServiceBindingType> queriedServiceBindings = new HashMap<String, ServiceBindingType>();
128 DocumentModelList docList = this.getDocListForGroup(ctx, serviceGroupNames, queriedServiceBindings,
129 repoSession, repoClient);
130 if (docList == null) { // found no authRef fields - nothing to process
131 throw new DocumentNotFoundException();
133 DocumentModel docModel = docList.get(0);
135 // Determine if the docModel is an authority term, object, or some other procedure record.
137 String termRefName = (String) NuxeoUtils.getProperyValue(docModel, CollectionSpaceClient.COLLECTIONSPACE_CORE_REFNAME);
138 if (isAuthorityTermDocument(termRefName) == true) {
139 result = getAuthorityItem(ctx, termRefName);
141 TenantBindingConfigReaderImpl bindingReader = ServiceMain.getInstance().getTenantBindingConfigReader();
142 String serviceName = ServiceBindingUtils.getServiceNameFromObjectName(bindingReader, ctx.getTenantId(),
143 docModel.getDocumentType().getName());
144 NuxeoBasedResource resource = (NuxeoBasedResource) ctx.getResourceMap().get(serviceName);
145 result = resource.getWithParentCtx(ctx, csid);
147 } catch (DocumentException de) {
149 } catch (Exception e) {
150 if (logger.isDebugEnabled()) {
151 logger.debug("Caught exception ", e);
153 throw new DocumentException(e);
155 if (releaseRepoSession && repoSession != null) {
156 repoClient.releaseRepositorySession(ctx, repoSession);
159 } catch (Exception e) {
160 if (logger.isDebugEnabled()) {
161 logger.debug("Caught exception ", e);
163 throw new DocumentException(e);
169 private boolean isAuthorityTermDocument(String termRefName) {
170 boolean result = true;
173 //String inAuthorityCsid = (String) NuxeoUtils.getProperyValue(docModel, "inAuthority"); //docModel.getPropertyValue("inAuthority"); // AuthorityItemJAXBSchema.IN_AUTHORITY
174 //String refName = (String) NuxeoUtils.getProperyValue(docModel, CollectionSpaceClient.COLLECTIONSPACE_CORE_REFNAME);
175 RefName.AuthorityItem item = RefName.AuthorityItem.parse(termRefName, true);
176 } catch (IllegalArgumentException e) {
183 private DocumentModelList getDocListForGroup(
184 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
185 List<String> serviceGroupNames,
186 Map<String, ServiceBindingType> queriedServiceBindings,
187 CoreSessionInterface repoSession,
188 NuxeoRepositoryClientImpl repoClient) throws Exception {
190 NuxeoRepositoryClientImpl nuxeoRepoClient = (NuxeoRepositoryClientImpl)repoClient;
191 // Get the service bindings for this tenant
192 TenantBindingConfigReaderImpl tReader = ServiceMain.getInstance().getTenantBindingConfigReader();
193 // We need to get all the procedures, authorities, and objects.
194 List<ServiceBindingType> servicebindings =
195 tReader.getServiceBindingsByType(ctx.getTenantId(), serviceGroupNames);
196 if (servicebindings == null || servicebindings.isEmpty()) {
197 Response response = Response.status(Response.Status.NOT_FOUND).entity(
198 ServiceMessages.READ_FAILED +
199 ServiceMessages.resourceNotFoundMsg(implode(serviceGroupNames, ","))).type("text/plain").build();
200 throw new CSWebApplicationException(response);
203 servicebindings = SecurityUtils.getReadableServiceBindingsForCurrentUser(servicebindings);
204 // Build the list of docTypes for allowed serviceBindings
205 ArrayList<String> docTypes = new ArrayList<String>();
206 for(ServiceBindingType binding:servicebindings) {
207 ServiceObjectType serviceObj = binding.getObject();
208 if(serviceObj!=null) {
209 String docType = serviceObj.getName();
210 docTypes.add(docType);
211 queriedServiceBindings.put(docType, binding);
215 // This should be type "Document" but CMIS is gagging on that right now.
216 ctx.getQueryParams().add(IQueryManager.SELECT_DOC_TYPE_FIELD, QueryManagerNuxeoImpl.COLLECTIONSPACE_DOCUMENT_TYPE);
218 // Now we have to issue the search
219 // The findDocs() method will build a QueryContext, which wants to see a docType for our context
220 ctx.setDocumentType(QueryManagerNuxeoImpl.NUXEO_DOCUMENT_TYPE);
221 DocumentWrapper<DocumentModelList> docListWrapper =
222 nuxeoRepoClient.findDocs(ctx, this, repoSession, docTypes );
223 // Now we gather the info for each document into the list and return
224 DocumentModelList docList = docListWrapper.getWrappedObject();
229 public AbstractCommonList getItemListForGroup(
230 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
231 List<String> serviceGroupNames) throws Exception {
232 CommonList commonList = new CommonList();
233 AbstractCommonList list = (AbstractCommonList)commonList;
234 CoreSessionInterface repoSession = null;
235 boolean releaseRepoSession = false;
238 DocumentFilter myFilter = getDocumentFilter();
239 int pageSize = myFilter.getPageSize();
240 int pageNum = myFilter.getStartPage();
241 list.setPageNum(pageNum);
242 list.setPageSize(pageSize);
244 NuxeoRepositoryClientImpl repoClient = (NuxeoRepositoryClientImpl)this.getRepositoryClient(ctx);
245 repoSession = this.getRepositorySession();
246 if (repoSession == null) {
247 repoSession = repoClient.getRepositorySession(ctx);
248 releaseRepoSession = true;
251 Map<String, ServiceBindingType> queriedServiceBindings = new HashMap<String, ServiceBindingType>();
252 DocumentModelList docList = this.getDocListForGroup(ctx, serviceGroupNames, queriedServiceBindings,
253 repoSession, repoClient);
254 if (docList == null) { // found no authRef fields - nothing to process
257 processDocList(ctx, docList, queriedServiceBindings, commonList);
258 list.setItemsInPage(docList.size());
259 list.setTotalItems(docList.totalSize());
260 } catch (DocumentException de) {
262 } catch (Exception e) {
263 if (logger.isDebugEnabled()) {
264 logger.debug("Caught exception ", e);
266 throw new DocumentException(e);
268 if (releaseRepoSession && repoSession != null) {
269 repoClient.releaseRepositorySession(ctx, repoSession);
272 } catch (Exception e) {
273 if (logger.isDebugEnabled()) {
274 logger.debug("Caught exception ", e);
276 throw new DocumentException(e);
282 // Move this to a Utils class!
283 public static String implode(List<String> stringList, String sep) {
284 StringBuilder sb = new StringBuilder();
286 boolean fFirst = false;
287 for (String name:stringList) {
296 return sb.toString();
299 private String getUriFromServiceBinding(ServiceBindingType sb, String csid) {
300 return "/" + sb.getName().toLowerCase() + "/" + csid;
303 private void processDocList(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
304 DocumentModelList docList,
305 Map<String, ServiceBindingType> queriedServiceBindings,
306 CommonList list) throws DocumentException {
308 String tenantId = ctx.getTenantId();
309 CoreSessionInterface repoSession = null;
310 NuxeoRepositoryClientImpl repoClient = null;
311 boolean releaseRepoSession = false;
313 MultivaluedMap<String, String> queryParams = getServiceContext().getQueryParams();
314 String markRtSbj = queryParams.getFirst(IQueryManager.MARK_RELATED_TO_CSID_AS_SUBJECT);
315 if (Tools.isBlank(markRtSbj)) {
319 String markRtSbjOrObj = queryParams.getFirst(IQueryManager.MARK_RELATED_TO_CSID_AS_EITHER);
320 if (Tools.isBlank(markRtSbjOrObj)) {
321 markRtSbjOrObj = null;
323 if (Tools.isBlank(markRtSbj) == false) {
324 logger.warn(String.format("Ignoring query param %s='%s' since overriding query param %s='%s' exists.",
325 IQueryManager.MARK_RELATED_TO_CSID_AS_SUBJECT, markRtSbj, IQueryManager.MARK_RELATED_TO_CSID_AS_EITHER, markRtSbjOrObj));
327 markRtSbj = markRtSbjOrObj; // Mark the record as related independent of whether it is the subject or object of a relationship
331 if (markRtSbj != null) {
332 repoClient = (NuxeoRepositoryClientImpl) this.getRepositoryClient(ctx);
333 NuxeoRepositoryClientImpl nuxeoRepoClient = (NuxeoRepositoryClientImpl) repoClient;
334 repoSession = this.getRepositorySession();
335 if (repoSession == null) {
336 repoSession = repoClient.getRepositorySession(ctx);
337 releaseRepoSession = true;
341 String fields[] = new String[NUM_META_FIELDS + NUM_STANDARD_LIST_RESULT_FIELDS];
342 fields[0] = STANDARD_LIST_CSID_FIELD;
343 fields[1] = STANDARD_LIST_URI_FIELD;
344 fields[2] = STANDARD_LIST_UPDATED_AT_FIELD;
345 fields[3] = STANDARD_LIST_WORKFLOW_FIELD;
346 fields[4] = STANDARD_LIST_REFNAME_FIELD;
347 fields[5] = DOC_NAME_FIELD;
348 fields[6] = DOC_NUMBER_FIELD;
349 fields[7] = DOC_TYPE_FIELD;
350 if (markRtSbj != null) {
351 fields[8] = STANDARD_LIST_MARK_RT_FIELD;
354 list.setFieldsReturned(fields);
356 Iterator<DocumentModel> iter = docList.iterator();
357 HashMap<String, Object> item = new HashMap<String, Object>();
358 while (iter.hasNext()) {
359 DocumentModel docModel = iter.next();
360 String docType = docModel.getDocumentType().getName();
361 docType = ServiceBindingUtils.getUnqualifiedTenantDocType(docType);
362 ServiceBindingType sb = queriedServiceBindings.get(docType);
364 throw new RuntimeException("processDocList: No Service Binding for docType: " + docType);
367 String csid = NuxeoUtils.getCsid(docModel);
368 item.put(STANDARD_LIST_CSID_FIELD, csid);
371 // If the mark-related query param was set, check to see if the doc we're processing
372 // is related to the value specified in the mark-related query param.
374 if (markRtSbj != null) {
375 String relationClause = RelationsUtils.buildWhereClause(markRtSbj, null, null, csid, null, markRtSbj == markRtSbjOrObj);
376 String whereClause = relationClause + IQueryManager.SEARCH_QUALIFIER_AND
377 + NuxeoUtils.buildWorkflowNotDeletedWhereClause();
378 QueryContext queryContext = new QueryContext(ctx, whereClause);
379 queryContext.setDocType(IRelationsManager.DOC_TYPE);
380 String query = NuxeoUtils.buildNXQLQuery(queryContext);
381 // Search for 1 relation that matches. 1 is enough to fail
383 DocumentModelList queryDocList = repoSession.query(query, null, 1, 0, false);
384 item.put(STANDARD_LIST_MARK_RT_FIELD, queryDocList.isEmpty() ? "false" : "true");
387 UriTemplateRegistry uriTemplateRegistry = ServiceMain.getInstance().getUriTemplateRegistry();
388 StoredValuesUriTemplate storedValuesResourceTemplate = uriTemplateRegistry.get(new UriTemplateRegistryKey(tenantId, docType));
389 Map<String, String> additionalValues = new HashMap<String, String>();
390 if (storedValuesResourceTemplate.getUriTemplateType() == UriTemplateFactory.ITEM) {
392 String inAuthorityCsid = (String) NuxeoUtils.getProperyValue(docModel, "inAuthority"); //docModel.getPropertyValue("inAuthority"); // AuthorityItemJAXBSchema.IN_AUTHORITY
393 additionalValues.put(UriTemplateFactory.IDENTIFIER_VAR, inAuthorityCsid);
394 additionalValues.put(UriTemplateFactory.ITEM_IDENTIFIER_VAR, csid);
395 } catch (Exception e) {
396 String msg = String.format("Could not extract inAuthority property from authority item with CSID = ", docModel.getName());
400 additionalValues.put(UriTemplateFactory.IDENTIFIER_VAR, csid);
403 String uriStr = storedValuesResourceTemplate.buildUri(additionalValues);
404 item.put(STANDARD_LIST_URI_FIELD, uriStr);
406 item.put(STANDARD_LIST_UPDATED_AT_FIELD, getUpdatedAtAsString(docModel));
407 item.put(STANDARD_LIST_WORKFLOW_FIELD, docModel.getCurrentLifeCycleState());
408 item.put(STANDARD_LIST_REFNAME_FIELD, getRefname(docModel));
409 } catch(Exception e) {
410 logger.error("Error getting core values for doc ["+csid+"]: "+e.getLocalizedMessage());
413 String value = ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NUMBER_PROP, docModel);
415 item.put(DOC_NUMBER_FIELD, value);
418 value = ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NAME_PROP, docModel);
420 item.put(DOC_NAME_FIELD, value);
423 item.put(DOC_TYPE_FIELD, docType);
424 // add the item to the list
428 } catch (Exception e) {
429 if (logger.isDebugEnabled()) {
430 logger.debug("Caught exception ", e);
432 throw new DocumentException(e);
434 // If we got/acquired a new session then we're responsible for releasing it.
435 if (releaseRepoSession && repoSession != null) {
436 repoClient.releaseRepositorySession(ctx, repoSession);