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 package org.collectionspace.services.nuxeo.client.java;
20 import java.io.Serializable;
21 import java.util.Hashtable;
22 import java.util.Iterator;
23 import java.util.List;
25 import java.util.UUID;
27 import javax.ws.rs.WebApplicationException;
28 import javax.ws.rs.core.MultivaluedMap;
30 import org.collectionspace.services.client.PoxPayloadIn;
31 import org.collectionspace.services.client.PoxPayloadOut;
32 import org.collectionspace.services.client.workflow.WorkflowClient;
33 import org.collectionspace.services.common.context.ServiceContext;
34 import org.collectionspace.services.common.query.QueryContext;
35 import org.collectionspace.services.common.repository.RepositoryClient;
36 import org.collectionspace.services.common.profile.Profiler;
37 import org.collectionspace.services.lifecycle.TransitionDef;
38 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
40 import org.collectionspace.services.common.document.BadRequestException;
41 import org.collectionspace.services.common.document.DocumentException;
42 import org.collectionspace.services.common.document.DocumentFilter;
43 import org.collectionspace.services.common.document.DocumentHandler;
44 import org.collectionspace.services.common.document.DocumentNotFoundException;
45 import org.collectionspace.services.common.document.DocumentHandler.Action;
46 import org.collectionspace.services.common.document.DocumentWrapper;
47 import org.collectionspace.services.common.document.DocumentWrapperImpl;
49 import org.nuxeo.common.utils.IdUtils;
50 import org.nuxeo.ecm.core.api.ClientException;
51 import org.nuxeo.ecm.core.api.DocumentModel;
52 import org.nuxeo.ecm.core.api.DocumentModelList;
53 import org.nuxeo.ecm.core.api.IterableQueryResult;
54 import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
55 import org.nuxeo.ecm.core.api.DocumentRef;
56 import org.nuxeo.ecm.core.api.IdRef;
57 import org.nuxeo.ecm.core.api.PathRef;
58 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
61 // CSPACE-5036 - How to make CMISQL queries from Nuxeo
63 import org.apache.chemistry.opencmis.commons.server.CallContext;
64 import org.apache.chemistry.opencmis.server.impl.CallContextImpl;
65 import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoCmisService;
66 import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoRepository;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
72 * RepositoryJavaClient is used to perform CRUD operations on documents in Nuxeo
73 * repository using Remote Java APIs. It uses @see DocumentHandler as IOHandler
76 * $LastChangedRevision: $ $LastChangedDate: $
78 public class RepositoryJavaClientImpl implements RepositoryClient<PoxPayloadIn, PoxPayloadOut> {
81 private final Logger logger = LoggerFactory.getLogger(RepositoryJavaClientImpl.class);
82 // private final Logger profilerLogger = LoggerFactory.getLogger("remperf");
83 // private String foo = Profiler.createLogger();
85 public static final String NUXEO_CORE_TYPE_DOMAIN = "Domain";
86 public static final String NUXEO_CORE_TYPE_WORKSPACEROOT = "WorkspaceRoot";
89 * Instantiates a new repository java client impl.
91 public RepositoryJavaClientImpl() {
96 public void assertWorkflowState(ServiceContext ctx,
97 DocumentModel docModel) throws DocumentNotFoundException, ClientException {
98 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
99 if (queryParams != null) {
101 // Look for the workflow "delete" query param and see if we need to assert that the
102 // docModel is in a non-deleted workflow state.
104 String currentState = docModel.getCurrentLifeCycleState();
105 String includeDeletedStr = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_NONDELETED);
106 boolean includeDeleted = includeDeletedStr == null ? true : Boolean.parseBoolean(includeDeletedStr);
107 if (includeDeleted == false) {
109 // We don't wanted soft-deleted object, so throw an exception if this one is soft-deleted.
111 if (currentState.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_DELETED)) {
112 String msg = "The GET assertion that docModel not be in 'deleted' workflow state failed.";
114 throw new DocumentNotFoundException(msg);
121 * create document in the Nuxeo repository
123 * @param ctx service context under which this method is invoked
125 * should be used by the caller to provide and transform the
127 * @return id in repository of the newly created document
128 * @throws DocumentException
131 public String create(ServiceContext ctx,
132 DocumentHandler handler) throws BadRequestException,
135 String docType = NuxeoUtils.getTenantQualifiedDocType(ctx); //ctx.getDocumentType();
136 if (docType == null) {
137 throw new IllegalArgumentException(
138 "RepositoryJavaClient.create: docType is missing");
141 if (handler == null) {
142 throw new IllegalArgumentException(
143 "RepositoryJavaClient.create: handler is missing");
145 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
146 if (nuxeoWspaceId == null) {
147 throw new DocumentNotFoundException(
148 "Unable to find workspace for service " + ctx.getServiceName()
149 + " check if the workspace exists in the Nuxeo repository");
152 RepositoryInstance repoSession = null;
154 handler.prepare(Action.CREATE);
155 repoSession = getRepositorySession();
156 DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);
157 DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);
158 String wspacePath = wspaceDoc.getPathAsString();
159 //give our own ID so PathRef could be constructed later on
160 String id = IdUtils.generateId(UUID.randomUUID().toString());
161 // create document model
162 DocumentModel doc = repoSession.createDocumentModel(wspacePath, id, docType);
163 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
164 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
165 handler.handle(Action.CREATE, wrapDoc);
166 // create document with documentmodel
167 doc = repoSession.createDocument(doc);
169 // TODO for sub-docs need to call into the handler to let it deal with subitems. Pass in the id,
170 // and assume the handler has the state it needs (doc fragments).
171 handler.complete(Action.CREATE, wrapDoc);
173 } catch (BadRequestException bre) {
175 } catch (Exception e) {
176 logger.error("Caught exception ", e);
177 throw new DocumentException(e);
179 if (repoSession != null) {
180 releaseRepositorySession(repoSession);
187 * get document from the Nuxeo repository
188 * @param ctx service context under which this method is invoked
190 * of the document to retrieve
192 * should be used by the caller to provide and transform the
194 * @throws DocumentException
197 public void get(ServiceContext ctx, String id, DocumentHandler handler)
198 throws DocumentNotFoundException, DocumentException {
200 if (handler == null) {
201 throw new IllegalArgumentException(
202 "RepositoryJavaClient.get: handler is missing");
205 RepositoryInstance repoSession = null;
207 handler.prepare(Action.GET);
208 repoSession = getRepositorySession();
209 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
210 DocumentModel docModel = null;
212 docModel = repoSession.getDocument(docRef);
213 assertWorkflowState(ctx, docModel);
214 } catch (ClientException ce) {
215 String msg = logException(ce, "Could not find document with CSID=" + id);
216 throw new DocumentNotFoundException(msg, ce);
219 // Set repository session to handle the document
221 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
222 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(docModel);
223 handler.handle(Action.GET, wrapDoc);
224 handler.complete(Action.GET, wrapDoc);
225 } catch (IllegalArgumentException iae) {
227 } catch (DocumentException de) {
229 } catch (Exception e) {
230 if (logger.isDebugEnabled()) {
231 logger.debug("Caught exception ", e);
233 throw new DocumentException(e);
235 if (repoSession != null) {
236 releaseRepositorySession(repoSession);
242 * get document from the Nuxeo repository, using the docFilter params.
243 * @param ctx service context under which this method is invoked
245 * should be used by the caller to provide and transform the
246 * document. Handler must have a docFilter set to return a single item.
247 * @throws DocumentException
250 public void get(ServiceContext ctx, DocumentHandler handler)
251 throws DocumentNotFoundException, DocumentException {
252 QueryContext queryContext = new QueryContext(ctx, handler);
253 RepositoryInstance repoSession = null;
256 handler.prepare(Action.GET);
257 repoSession = getRepositorySession();
259 DocumentModelList docList = null;
260 // force limit to 1, and ignore totalSize
261 String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
262 docList = repoSession.query(query, null, 1, 0, false);
263 if (docList.size() != 1) {
264 throw new DocumentNotFoundException("No document found matching filter params: " + query);
266 DocumentModel doc = docList.get(0);
268 if (logger.isDebugEnabled()) {
269 logger.debug("Executed NXQL query: " + query);
272 //set reposession to handle the document
273 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
274 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
275 handler.handle(Action.GET, wrapDoc);
276 handler.complete(Action.GET, wrapDoc);
277 } catch (IllegalArgumentException iae) {
279 } catch (DocumentException de) {
281 } catch (Exception e) {
282 if (logger.isDebugEnabled()) {
283 logger.debug("Caught exception ", e);
285 throw new DocumentException(e);
287 if (repoSession != null) {
288 releaseRepositorySession(repoSession);
293 public DocumentWrapper<DocumentModel> getDoc(
294 RepositoryInstance repoSession,
295 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
296 String csid) throws DocumentNotFoundException, DocumentException {
297 DocumentWrapper<DocumentModel> wrapDoc = null;
300 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
301 DocumentModel doc = null;
303 doc = repoSession.getDocument(docRef);
304 } catch (ClientException ce) {
305 String msg = logException(ce, "Could not find document with CSID=" + csid);
306 throw new DocumentNotFoundException(msg, ce);
308 wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
309 } catch (IllegalArgumentException iae) {
311 } catch (DocumentException de) {
319 * Get wrapped documentModel from the Nuxeo repository. The search is restricted to the workspace
320 * of the current context.
322 * @param ctx service context under which this method is invoked
324 * of the document to retrieve
325 * @throws DocumentException
328 public DocumentWrapper<DocumentModel> getDoc(
329 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
330 String csid) throws DocumentNotFoundException, DocumentException {
331 RepositoryInstance repoSession = null;
332 DocumentWrapper<DocumentModel> wrapDoc = null;
335 // Open a new repository session
336 repoSession = getRepositorySession();
337 wrapDoc = getDoc(repoSession, ctx, csid);
338 } catch (IllegalArgumentException iae) {
340 } catch (DocumentException de) {
342 } catch (Exception e) {
343 if (logger.isDebugEnabled()) {
344 logger.debug("Caught exception ", e);
346 throw new DocumentException(e);
348 if (repoSession != null) {
349 releaseRepositorySession(repoSession);
353 if (logger.isWarnEnabled() == true) {
354 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
359 public DocumentWrapper<DocumentModel> findDoc(
360 RepositoryInstance repoSession,
361 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
363 throws DocumentNotFoundException, DocumentException {
364 DocumentWrapper<DocumentModel> wrapDoc = null;
367 QueryContext queryContext = new QueryContext(ctx, whereClause);
368 DocumentModelList docList = null;
369 // force limit to 1, and ignore totalSize
370 String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
371 docList = repoSession.query(query,
376 if (docList.size() != 1) {
377 if (logger.isDebugEnabled()) {
378 logger.debug("findDoc: Query found: " + docList.size() + " items.");
379 logger.debug(" Query: " + query);
381 throw new DocumentNotFoundException("No document found matching filter params: " + query);
383 DocumentModel doc = docList.get(0);
384 wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
385 } catch (IllegalArgumentException iae) {
387 } catch (DocumentException de) {
389 } catch (Exception e) {
390 if (logger.isDebugEnabled()) {
391 logger.debug("Caught exception ", e);
393 throw new DocumentException(e);
400 * find wrapped documentModel from the Nuxeo repository
401 * @param ctx service context under which this method is invoked
402 * @param whereClause where NXQL where clause to get the document
403 * @throws DocumentException
406 public DocumentWrapper<DocumentModel> findDoc(
407 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
409 throws DocumentNotFoundException, DocumentException {
410 RepositoryInstance repoSession = null;
411 DocumentWrapper<DocumentModel> wrapDoc = null;
414 repoSession = getRepositorySession();
415 wrapDoc = findDoc(repoSession, ctx, whereClause);
416 } catch (Exception e) {
417 throw new DocumentException("Unable to create a Nuxeo repository session.", e);
419 if (repoSession != null) {
420 releaseRepositorySession(repoSession);
424 if (logger.isWarnEnabled() == true) {
425 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
432 * find doc and return CSID from the Nuxeo repository
433 * @param ctx service context under which this method is invoked
434 * @param whereClause where NXQL where clause to get the document
435 * @throws DocumentException
438 public String findDocCSID(RepositoryInstance repoSession,
439 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String whereClause)
440 throws DocumentNotFoundException, DocumentException {
442 boolean releaseSession = false;
444 if(repoSession== null) {
445 repoSession = this.getRepositorySession();
446 releaseSession = true;
448 DocumentWrapper<DocumentModel> wrapDoc = findDoc(repoSession, ctx, whereClause);
449 DocumentModel docModel = wrapDoc.getWrappedObject();
450 csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
451 } catch (DocumentNotFoundException dnfe) {
453 } catch (IllegalArgumentException iae) {
455 } catch (DocumentException de) {
457 } catch (Exception e) {
458 if (logger.isDebugEnabled()) {
459 logger.debug("Caught exception ", e);
461 throw new DocumentException(e);
463 if(releaseSession && (repoSession != null)) {
464 this.releaseRepositorySession(repoSession);
470 public DocumentWrapper<DocumentModelList> findDocs(
471 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
472 RepositoryInstance repoSession,
473 List<String> docTypes,
475 int pageSize, int pageNum, boolean computeTotal)
476 throws DocumentNotFoundException, DocumentException {
477 DocumentWrapper<DocumentModelList> wrapDoc = null;
480 if (docTypes == null || docTypes.size() < 1) {
481 throw new DocumentNotFoundException(
482 "The findDocs() method must specify at least one DocumentType.");
484 DocumentModelList docList = null;
485 QueryContext queryContext = new QueryContext(ctx, whereClause);
486 String query = NuxeoUtils.buildNXQLQuery(docTypes, queryContext);
487 if (logger.isDebugEnabled()) {
488 logger.debug("findDocs() NXQL: "+query);
490 docList = repoSession.query(query, null, pageSize, pageNum, computeTotal);
491 wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
492 } catch (IllegalArgumentException iae) {
494 } catch (Exception e) {
495 if (logger.isDebugEnabled()) {
496 logger.debug("Caught exception ", e);
498 throw new DocumentException(e);
505 * Find a list of documentModels from the Nuxeo repository
506 * @param docTypes a list of DocType names to match
507 * @param whereClause where the clause to qualify on
511 public DocumentWrapper<DocumentModelList> findDocs(
512 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
513 List<String> docTypes,
515 int pageSize, int pageNum, boolean computeTotal)
516 throws DocumentNotFoundException, DocumentException {
517 RepositoryInstance repoSession = null;
518 DocumentWrapper<DocumentModelList> wrapDoc = null;
521 repoSession = getRepositorySession();
522 wrapDoc = findDocs(ctx, repoSession, docTypes, whereClause,
523 pageSize, pageNum, computeTotal);
524 } catch (IllegalArgumentException iae) {
526 } catch (Exception e) {
527 if (logger.isDebugEnabled()) {
528 logger.debug("Caught exception ", e);
530 throw new DocumentException(e);
532 if (repoSession != null) {
533 releaseRepositorySession(repoSession);
537 if (logger.isWarnEnabled() == true) {
538 logger.warn("Returned DocumentModelList instance was created with a repository session that is now closed.");
545 * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.util.List, org.collectionspace.services.common.document.DocumentHandler)
548 public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
549 throws DocumentNotFoundException, DocumentException {
550 if (handler == null) {
551 throw new IllegalArgumentException(
552 "RepositoryJavaClient.getAll: handler is missing");
555 RepositoryInstance repoSession = null;
557 handler.prepare(Action.GET_ALL);
558 repoSession = getRepositorySession();
559 DocumentModelList docModelList = new DocumentModelListImpl();
560 //FIXME: Should be using NuxeoUtils.createPathRef for security reasons
561 for (String csid : csidList) {
562 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
563 DocumentModel docModel = repoSession.getDocument(docRef);
564 docModelList.add(docModel);
567 //set reposession to handle the document
568 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
569 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docModelList);
570 handler.handle(Action.GET_ALL, wrapDoc);
571 handler.complete(Action.GET_ALL, wrapDoc);
572 } catch (DocumentException de) {
574 } catch (Exception e) {
575 if (logger.isDebugEnabled()) {
576 logger.debug("Caught exception ", e);
578 throw new DocumentException(e);
580 if (repoSession != null) {
581 releaseRepositorySession(repoSession);
587 * getAll get all documents for an entity entity service from the Nuxeo
590 * @param ctx service context under which this method is invoked
592 * should be used by the caller to provide and transform the
594 * @throws DocumentException
597 public void getAll(ServiceContext ctx, DocumentHandler handler)
598 throws DocumentNotFoundException, DocumentException {
599 if (handler == null) {
600 throw new IllegalArgumentException(
601 "RepositoryJavaClient.getAll: handler is missing");
603 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
604 if (nuxeoWspaceId == null) {
605 throw new DocumentNotFoundException(
606 "Unable to find workspace for service "
607 + ctx.getServiceName()
608 + " check if the workspace exists in the Nuxeo repository.");
611 RepositoryInstance repoSession = null;
613 handler.prepare(Action.GET_ALL);
614 repoSession = getRepositorySession();
615 DocumentRef wsDocRef = new IdRef(nuxeoWspaceId);
616 DocumentModelList docList = repoSession.getChildren(wsDocRef);
617 //set reposession to handle the document
618 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
619 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
620 handler.handle(Action.GET_ALL, wrapDoc);
621 handler.complete(Action.GET_ALL, wrapDoc);
622 } catch (DocumentException de) {
624 } catch (Exception e) {
625 if (logger.isDebugEnabled()) {
626 logger.debug("Caught exception ", e);
628 throw new DocumentException(e);
630 if (repoSession != null) {
631 releaseRepositorySession(repoSession);
636 private boolean isClauseEmpty(String theString) {
637 boolean result = true;
638 if (theString != null && !theString.isEmpty()) {
644 public DocumentWrapper<DocumentModel> getDocFromCsid(
645 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
646 RepositoryInstance repoSession,
649 DocumentWrapper<DocumentModel> result = null;
651 result = new DocumentWrapperImpl(NuxeoUtils.getDocFromCsid(ctx, repoSession, csid));
657 * A method to find a CollectionSpace document (of any type) given just a service context and
658 * its CSID. A search across *all* service workspaces (within a given tenant context) is performed to find
661 * This query searches Nuxeo's Hierarchy table where our CSIDs are stored in the "name" column.
664 public DocumentWrapper<DocumentModel> getDocFromCsid(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
667 DocumentWrapper<DocumentModel> result = null;
668 RepositoryInstance repoSession = null;
670 repoSession = getRepositorySession();
671 result = getDocFromCsid(ctx, repoSession, csid);
673 if (repoSession != null) {
674 releaseRepositorySession(repoSession);
678 if (logger.isWarnEnabled() == true) {
679 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
686 * find doc and return CSID from the Nuxeo repository
687 * @param ctx service context under which this method is invoked
688 * @param whereClause where NXQL where clause to get the document
689 * @throws DocumentException
692 public String getDocURI(DocumentWrapper<DocumentModel> wrappedDoc) throws ClientException {
693 DocumentModel docModel = wrappedDoc.getWrappedObject();
694 String uri = (String)docModel.getProperty(DocumentModelHandler.COLLECTIONSPACE_CORE_SCHEMA,
695 DocumentModelHandler.COLLECTIONSPACE_CORE_URI);
700 * See CSPACE-5036 - How to make CMISQL queries from Nuxeo
702 private void makeCMISQLQuery(RepositoryInstance repoSession, String query) {
703 // the NuxeoRepository should be constructed only once, then cached
704 // (its construction is expensive)
706 NuxeoRepository repo = new NuxeoRepository(repoSession.getRepositoryName(),
707 repoSession.getRootDocument().getId());
708 logger.debug("Repository ID:" + repo.getId() + " Root folder:" + repo.getRootFolderId());
710 CallContextImpl callContext = new CallContextImpl(CallContext.BINDING_LOCAL,
711 repo.getId(), false);
712 callContext.put(CallContext.USERNAME, repoSession.getPrincipal().getName());
713 NuxeoCmisService cmisService = new NuxeoCmisService(repo, callContext, repoSession);
715 IterableQueryResult result = repoSession.queryAndFetch(query, "CMISQL", cmisService);
716 for (Map<String, Serializable> row : result) {
718 // "dc:title is: " + (String)row.get("dc:title")
719 "" + " Hierarchy Table ID is:" + row.get("cmis:objectId")
720 + " cmis:name is: " + row.get("cmis:name")
721 // + " nuxeo:lifecycleState is: " + row.get("nuxeo:lifecycleState")
724 } catch (ClientException e) {
725 // TODO Auto-generated catch block
731 * getFiltered get all documents for an entity service from the Document repository,
732 * given filter parameters specified by the handler.
733 * @param ctx service context under which this method is invoked
734 * @param handler should be used by the caller to provide and transform the document
735 * @throws DocumentNotFoundException if workspace not found
736 * @throws DocumentException
739 public void getFiltered(ServiceContext ctx, DocumentHandler handler)
740 throws DocumentNotFoundException, DocumentException {
742 DocumentFilter filter = handler.getDocumentFilter();
743 String oldOrderBy = filter.getOrderByClause();
744 if (isClauseEmpty(oldOrderBy) == true){
745 filter.setOrderByClause(DocumentFilter.ORDER_BY_LAST_UPDATED); //per http://issues.collectionspace.org/browse/CSPACE-705 (Doesn't this conflict with what happens with the QueryContext instance that we create below?)
747 QueryContext queryContext = new QueryContext(ctx, handler);
749 RepositoryInstance repoSession = null;
751 handler.prepare(Action.GET_ALL);
752 repoSession = getRepositorySession();
754 // CSPACE-5036 - How to make CMISQL queries from Nuxeo
758 String query1 = "SELECT A.intakes_common:entryReason FROM Intake A"; // try eaee111c-a8d8-48c7-95cb
759 makeCMISQLQuery(repoSession, query1);
761 String query2 = "SELECT * FROM Intake A where A.intakes_common:entryReason <> 'foo'"; // try eaee111c-a8d8-48c7-95cb
762 makeCMISQLQuery(repoSession, query2);
764 String query3 = "SELECT A.cmis:objectId, A.dc:title FROM Intake A where A.intakes_common:entryReason <> 'foo'"; // try eaee111c-a8d8-48c7-95cb
765 makeCMISQLQuery(repoSession, query3);
767 String query4 = "SELECT A.cmis:objectId, A.dc:title FROM Intake A where A.intakes_common:entryReason = '38ed4b32-e38f-4f82-adaa'";
768 makeCMISQLQuery(repoSession, query4);
770 String query5 = "SELECT A.cmis:name, A.dc:title, B.intakes_common:entryReason FROM Dimension A JOIN Intake B ON A.cmis:name = B.intakes_common:entryReason"; // try eaee111c-a8d8-48c7-95cb
771 makeCMISQLQuery(repoSession, query5);
773 String query6 = "SELECT A.cmis:name, A.dc:title, B.intakes_common:entryReason FROM Dimension A JOIN Intake B ON A.dc:title = B.intakes_common:entryReason"; // try eaee111c-a8d8-48c7-95cb
774 makeCMISQLQuery(repoSession, query6);
776 query6 = "SELECT A.cmis:name, A.dc:title, B.intakes_common:entryReason FROM Dimension A JOIN Intake B ON B.intakes_common:entryReason = A.dc:title"; // try eaee111c-a8d8-48c7-95cb
777 makeCMISQLQuery(repoSession, query6);
779 String query7 = "SELECT B.intakes_common:entryReason FROM Intake B"; // try eaee111c-a8d8-48c7-95cb
780 makeCMISQLQuery(repoSession, query7);
783 DocumentModelList docList = null;
784 String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
786 if (logger.isDebugEnabled()) {
787 logger.debug("Executing NXQL query: " + query.toString());
790 // If we have limit and/or offset, then pass true to get totalSize
791 // in returned DocumentModelList.
792 Profiler profiler = new Profiler(this, 2);
793 profiler.log("Executing NXQL query: " + query.toString());
795 if ((queryContext.getDocFilter().getOffset() > 0) || (queryContext.getDocFilter().getPageSize() > 0)) {
796 docList = repoSession.query(query, null,
797 queryContext.getDocFilter().getPageSize(), queryContext.getDocFilter().getOffset(), true);
799 docList = repoSession.query(query);
803 //set repoSession to handle the document
804 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
805 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
806 handler.handle(Action.GET_ALL, wrapDoc);
807 handler.complete(Action.GET_ALL, wrapDoc);
808 } catch (DocumentException de) {
810 } catch (Exception e) {
811 if (logger.isDebugEnabled()) {
812 logger.debug("Caught exception ", e);
814 throw new DocumentException(e);
816 if (repoSession != null) {
817 releaseRepositorySession(repoSession);
822 private String logException(Exception e, String msg) {
823 String result = null;
825 String exceptionMessage = e.getMessage();
826 exceptionMessage = exceptionMessage != null ? exceptionMessage : "<No details provided>";
827 result = msg = msg + ". Caught exception:" + exceptionMessage;
829 if (logger.isTraceEnabled() == true) {
830 logger.error(msg, e);
839 * update given document in the Nuxeo repository
841 * @param ctx service context under which this method is invoked
845 * should be used by the caller to provide and transform the
847 * @throws DocumentException
850 public void update(ServiceContext ctx, String csid, DocumentHandler handler)
851 throws BadRequestException, DocumentNotFoundException,
853 if (handler == null) {
854 throw new IllegalArgumentException(
855 "RepositoryJavaClient.update: document handler is missing.");
858 RepositoryInstance repoSession = null;
860 handler.prepare(Action.UPDATE);
861 repoSession = getRepositorySession();
862 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
863 DocumentModel doc = null;
865 doc = repoSession.getDocument(docRef);
866 } catch (ClientException ce) {
867 String msg = logException(ce, "Could not find document to update with CSID=" + csid);
868 throw new DocumentNotFoundException(msg, ce);
871 // Set reposession to handle the document
873 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
874 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
875 handler.handle(Action.UPDATE, wrapDoc);
876 repoSession.saveDocument(doc);
878 handler.complete(Action.UPDATE, wrapDoc);
879 } catch (BadRequestException bre) {
881 } catch (DocumentException de) {
883 } catch (WebApplicationException wae){
885 } catch (Exception e) {
886 if (logger.isDebugEnabled()) {
887 logger.debug("Caught exception ", e);
889 throw new DocumentException(e);
891 if (repoSession != null) {
892 releaseRepositorySession(repoSession);
898 * Save a documentModel to the Nuxeo repository.
899 * @param ctx service context under which this method is invoked
900 * @param docModel the document to save
901 * @param fSaveSession if TRUE, will call CoreSession.save() to save accumulated changes.
902 * @throws DocumentException
904 public void saveDocWithoutHandlerProcessing(
905 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
906 RepositoryInstance repoSession,
907 DocumentModel docModel,
908 boolean fSaveSession)
909 throws ClientException, DocumentException {
912 repoSession.saveDocument(docModel);
916 } catch (ClientException ce) {
918 } catch (Exception e) {
919 if (logger.isDebugEnabled()) {
920 logger.debug("Caught exception ", e);
922 throw new DocumentException(e);
928 * Save a list of documentModels to the Nuxeo repository.
930 * @param ctx service context under which this method is invoked
931 * @param docModel the document to save
932 * @param fSaveSession if TRUE, will call CoreSession.save() to save accumulated changes.
933 * @throws DocumentException
935 public void saveDocListWithoutHandlerProcessing(
936 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
937 RepositoryInstance repoSession,
938 DocumentModelList docList,
939 boolean fSaveSession)
940 throws ClientException, DocumentException {
942 repoSession = getRepositorySession();
943 DocumentModel[] docModelArray = new DocumentModel[docList.size()];
944 repoSession.saveDocuments(docList.toArray(docModelArray));
948 } catch (ClientException ce) {
950 } catch (Exception e) {
951 logger.error("Caught exception ", e);
952 throw new DocumentException(e);
957 * delete a document from the Nuxeo repository
958 * @param ctx service context under which this method is invoked
961 * @throws DocumentException
964 public void delete(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException,
967 throw new IllegalArgumentException(
968 "delete(ctx, ix, handler): ctx is missing");
970 if (handler == null) {
971 throw new IllegalArgumentException(
972 "delete(ctx, ix, handler): handler is missing");
974 if (logger.isDebugEnabled()) {
975 logger.debug("Deleting document with CSID=" + id);
977 RepositoryInstance repoSession = null;
979 handler.prepare(Action.DELETE);
980 repoSession = getRepositorySession();
981 DocumentWrapper<DocumentModel> wrapDoc = null;
983 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
984 wrapDoc = new DocumentWrapperImpl<DocumentModel>(repoSession.getDocument(docRef));
985 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
986 handler.handle(Action.DELETE, wrapDoc);
987 repoSession.removeDocument(docRef);
988 } catch (ClientException ce) {
989 String msg = logException(ce, "Could not find document to delete with CSID=" + id);
990 throw new DocumentNotFoundException(msg, ce);
993 handler.complete(Action.DELETE, wrapDoc);
994 } catch (DocumentException de) {
996 } catch (Exception e) {
997 if (logger.isDebugEnabled()) {
998 logger.debug("Caught exception ", e);
1000 throw new DocumentException(e);
1002 if (repoSession != null) {
1003 releaseRepositorySession(repoSession);
1009 * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
1013 public void delete(@SuppressWarnings("rawtypes") ServiceContext ctx, String id)
1014 throws DocumentNotFoundException, DocumentException {
1015 throw new UnsupportedOperationException();
1016 // Use the other delete instead
1020 public Hashtable<String, String> retrieveWorkspaceIds(String domainName) throws Exception {
1021 return NuxeoConnectorEmbedded.getInstance().retrieveWorkspaceIds(domainName);
1025 public String createDomain(String domainName) throws Exception {
1026 RepositoryInstance repoSession = null;
1027 String domainId = null;
1030 // First create the top-level domain directory
1032 repoSession = getRepositorySession();
1033 DocumentRef parentDocRef = new PathRef("/");
1034 DocumentModel parentDoc = repoSession.getDocument(parentDocRef);
1035 DocumentModel domainDoc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
1036 domainName, NUXEO_CORE_TYPE_DOMAIN);
1037 domainDoc.setPropertyValue("dc:title", domainName);
1038 domainDoc.setPropertyValue("dc:description", "A CollectionSpace domain "
1040 domainDoc = repoSession.createDocument(domainDoc);
1041 domainId = domainDoc.getId();
1044 // Next, create a "Workspaces" root directory to contain the workspace folders for the individual service documents
1046 DocumentModel workspacesRoot = repoSession.createDocumentModel(domainDoc.getPathAsString(),
1047 NuxeoUtils.Workspaces, NUXEO_CORE_TYPE_WORKSPACEROOT);
1048 workspacesRoot.setPropertyValue("dc:title", NuxeoUtils.Workspaces);
1049 workspacesRoot.setPropertyValue("dc:description", "A CollectionSpace workspaces directory for "
1050 + domainDoc.getPathAsString());
1051 workspacesRoot = repoSession.createDocument(workspacesRoot);
1052 String workspacesRootId = workspacesRoot.getId();
1055 if (logger.isDebugEnabled()) {
1056 logger.debug("Created tenant domain name=" + domainName
1057 + " id=" + domainId + " " +
1058 NuxeoUtils.Workspaces + " id=" + workspacesRootId);
1059 logger.debug("Path to Domain: "+domainDoc.getPathAsString());
1060 logger.debug("Path to Workspaces root: "+workspacesRoot.getPathAsString());
1062 } catch (Exception e) {
1063 if (logger.isDebugEnabled()) {
1064 logger.debug("Could not create tenant domain name=" + domainName + " caught exception ", e);
1068 if (repoSession != null) {
1069 releaseRepositorySession(repoSession);
1077 public String getDomainId(String domainName) throws Exception {
1078 String domainId = null;
1079 RepositoryInstance repoSession = null;
1081 if (domainName != null && !domainName.isEmpty()) {
1083 repoSession = getRepositorySession();
1084 DocumentRef docRef = new PathRef(
1086 DocumentModel domain = repoSession.getDocument(docRef);
1087 domainId = domain.getId();
1088 } catch (Exception e) {
1089 if (logger.isTraceEnabled()) {
1090 logger.trace("Caught exception ", e);
1092 //there is no way to identify if document does not exist due to
1093 //lack of typed exception for getDocument method
1096 if (repoSession != null) {
1097 releaseRepositorySession(repoSession);
1106 * Returns the workspaces root directory for a given domain.
1108 private DocumentModel getWorkspacesRoot(RepositoryInstance repoSession,
1109 String domainName) throws Exception {
1110 DocumentModel result = null;
1112 String domainPath = "/" + domainName;
1113 DocumentRef parentDocRef = new PathRef(domainPath);
1114 DocumentModelList domainChildrenList = repoSession.getChildren(
1116 Iterator<DocumentModel> witer = domainChildrenList.iterator();
1117 while (witer.hasNext()) {
1118 DocumentModel childNode = witer.next();
1119 if (NuxeoUtils.Workspaces.equalsIgnoreCase(childNode.getName())) {
1121 logger.trace("Found workspaces directory at: " + result.getPathAsString());
1126 if (result == null) {
1127 throw new ClientException("Could not find workspace root directory in: "
1135 * @see org.collectionspace.services.common.repository.RepositoryClient#createWorkspace(java.lang.String, java.lang.String)
1138 public String createWorkspace(String domainName, String workspaceName) throws Exception {
1139 RepositoryInstance repoSession = null;
1140 String workspaceId = null;
1142 repoSession = getRepositorySession();
1143 DocumentModel parentDoc = getWorkspacesRoot(repoSession, domainName);
1144 DocumentModel doc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
1145 workspaceName, NuxeoUtils.WORKSPACE_DOCUMENT_TYPE);
1146 doc.setPropertyValue("dc:title", workspaceName);
1147 doc.setPropertyValue("dc:description", "A CollectionSpace workspace for "
1149 doc = repoSession.createDocument(doc);
1150 workspaceId = doc.getId();
1152 if (logger.isDebugEnabled()) {
1153 logger.debug("Created workspace name=" + workspaceName
1154 + " id=" + workspaceId);
1156 } catch (Exception e) {
1157 if (logger.isDebugEnabled()) {
1158 logger.debug("createWorkspace caught exception ", e);
1162 if (repoSession != null) {
1163 releaseRepositorySession(repoSession);
1170 * @see org.collectionspace.services.common.repository.RepositoryClient#getWorkspaceId(java.lang.String, java.lang.String)
1173 public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
1174 String workspaceId = null;
1176 RepositoryInstance repoSession = null;
1178 repoSession = getRepositorySession();
1179 DocumentRef docRef = new PathRef(
1181 + "/" + NuxeoUtils.Workspaces
1182 + "/" + workspaceName);
1183 DocumentModel workspace = repoSession.getDocument(docRef);
1184 workspaceId = workspace.getId();
1185 } catch (DocumentException de) {
1187 } catch (Exception e) {
1188 if (logger.isDebugEnabled()) {
1189 logger.debug("Caught exception ", e);
1191 throw new DocumentException(e);
1193 if (repoSession != null) {
1194 releaseRepositorySession(repoSession);
1203 * Gets the repository session. - Package access only.
1205 * @return the repository session
1206 * @throws Exception the exception
1208 public RepositoryInstance getRepositorySession() throws Exception {
1209 // FIXME: is it possible to reuse repository session?
1210 // Authentication failures happen while trying to reuse the session
1211 Profiler profiler = new Profiler("getRepositorySession():", 2);
1214 NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
1215 RepositoryInstance repoSession = client.openRepository();
1216 if (logger.isTraceEnabled()) {
1217 logger.trace("Testing call to getRepository() repository root: " + repoSession.getRootDocument());
1225 * Release repository session. - Package access only.
1227 * @param repoSession the repo session
1229 public void releaseRepositorySession(RepositoryInstance repoSession) {
1231 NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
1233 client.releaseRepository(repoSession);
1234 } catch (Exception e) {
1235 logger.error("Could not close the repository session", e);
1236 // no need to throw this service specific exception
1241 public void doWorkflowTransition(ServiceContext ctx, String id,
1242 DocumentHandler handler, TransitionDef transitionDef)
1243 throws BadRequestException, DocumentNotFoundException,
1245 // This is a placeholder for when we change the StorageClient interface to treat workflow transitions as 1st class operations like 'get', 'create', 'update, 'delete', etc