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.CollectionSpaceClient;
31 import org.collectionspace.services.client.IQueryManager;
32 import org.collectionspace.services.client.PoxPayloadIn;
33 import org.collectionspace.services.client.PoxPayloadOut;
34 import org.collectionspace.services.client.workflow.WorkflowClient;
35 import org.collectionspace.services.common.context.ServiceContext;
36 import org.collectionspace.services.common.query.QueryContext;
37 import org.collectionspace.services.common.repository.RepositoryClient;
38 import org.collectionspace.services.common.profile.Profiler;
39 import org.collectionspace.services.lifecycle.TransitionDef;
40 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
42 import org.collectionspace.services.common.document.BadRequestException;
43 import org.collectionspace.services.common.document.DocumentException;
44 import org.collectionspace.services.common.document.DocumentFilter;
45 import org.collectionspace.services.common.document.DocumentHandler;
46 import org.collectionspace.services.common.document.DocumentNotFoundException;
47 import org.collectionspace.services.common.document.DocumentHandler.Action;
48 import org.collectionspace.services.common.document.DocumentWrapper;
49 import org.collectionspace.services.common.document.DocumentWrapperImpl;
51 import org.nuxeo.common.utils.IdUtils;
52 import org.nuxeo.ecm.core.api.ClientException;
53 import org.nuxeo.ecm.core.api.DocumentModel;
54 import org.nuxeo.ecm.core.api.DocumentModelList;
55 import org.nuxeo.ecm.core.api.IterableQueryResult;
56 import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
57 import org.nuxeo.ecm.core.api.DocumentRef;
58 import org.nuxeo.ecm.core.api.IdRef;
59 import org.nuxeo.ecm.core.api.PathRef;
60 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
63 // CSPACE-5036 - How to make CMISQL queries from Nuxeo
65 import org.apache.chemistry.opencmis.commons.server.CallContext;
66 import org.apache.chemistry.opencmis.server.impl.CallContextImpl;
67 import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoCmisService;
68 import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoRepository;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
74 * RepositoryJavaClient is used to perform CRUD operations on documents in Nuxeo
75 * repository using Remote Java APIs. It uses @see DocumentHandler as IOHandler
78 * $LastChangedRevision: $ $LastChangedDate: $
80 public class RepositoryJavaClientImpl implements RepositoryClient<PoxPayloadIn, PoxPayloadOut> {
83 private final Logger logger = LoggerFactory.getLogger(RepositoryJavaClientImpl.class);
84 // private final Logger profilerLogger = LoggerFactory.getLogger("remperf");
85 // private String foo = Profiler.createLogger();
87 public static final String NUXEO_CORE_TYPE_DOMAIN = "Domain";
88 public static final String NUXEO_CORE_TYPE_WORKSPACEROOT = "WorkspaceRoot";
91 * Instantiates a new repository java client impl.
93 public RepositoryJavaClientImpl() {
98 public void assertWorkflowState(ServiceContext ctx,
99 DocumentModel docModel) throws DocumentNotFoundException, ClientException {
100 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
101 if (queryParams != null) {
103 // Look for the workflow "delete" query param and see if we need to assert that the
104 // docModel is in a non-deleted workflow state.
106 String currentState = docModel.getCurrentLifeCycleState();
107 String includeDeletedStr = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_NONDELETED);
108 boolean includeDeleted = includeDeletedStr == null ? true : Boolean.parseBoolean(includeDeletedStr);
109 if (includeDeleted == false) {
111 // We don't wanted soft-deleted object, so throw an exception if this one is soft-deleted.
113 if (currentState.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_DELETED)) {
114 String msg = "The GET assertion that docModel not be in 'deleted' workflow state failed.";
116 throw new DocumentNotFoundException(msg);
123 * create document in the Nuxeo repository
125 * @param ctx service context under which this method is invoked
127 * should be used by the caller to provide and transform the
129 * @return id in repository of the newly created document
130 * @throws DocumentException
133 public String create(ServiceContext ctx,
134 DocumentHandler handler) throws BadRequestException,
137 String docType = NuxeoUtils.getTenantQualifiedDocType(ctx); //ctx.getDocumentType();
138 if (docType == null) {
139 throw new IllegalArgumentException(
140 "RepositoryJavaClient.create: docType is missing");
143 if (handler == null) {
144 throw new IllegalArgumentException(
145 "RepositoryJavaClient.create: handler is missing");
147 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
148 if (nuxeoWspaceId == null) {
149 throw new DocumentNotFoundException(
150 "Unable to find workspace for service " + ctx.getServiceName()
151 + " check if the workspace exists in the Nuxeo repository");
154 RepositoryInstance repoSession = null;
156 handler.prepare(Action.CREATE);
157 repoSession = getRepositorySession();
158 DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);
159 DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);
160 String wspacePath = wspaceDoc.getPathAsString();
161 //give our own ID so PathRef could be constructed later on
162 String id = IdUtils.generateId(UUID.randomUUID().toString());
163 // create document model
164 DocumentModel doc = repoSession.createDocumentModel(wspacePath, id, docType);
165 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
166 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
167 handler.handle(Action.CREATE, wrapDoc);
168 // create document with documentmodel
169 doc = repoSession.createDocument(doc);
171 // TODO for sub-docs need to call into the handler to let it deal with subitems. Pass in the id,
172 // and assume the handler has the state it needs (doc fragments).
173 handler.complete(Action.CREATE, wrapDoc);
175 } catch (BadRequestException bre) {
177 } catch (Exception e) {
178 logger.error("Caught exception ", e);
179 throw new DocumentException(e);
181 if (repoSession != null) {
182 releaseRepositorySession(repoSession);
189 * get document from the Nuxeo repository
190 * @param ctx service context under which this method is invoked
192 * of the document to retrieve
194 * should be used by the caller to provide and transform the
196 * @throws DocumentException
199 public void get(ServiceContext ctx, String id, DocumentHandler handler)
200 throws DocumentNotFoundException, DocumentException {
202 if (handler == null) {
203 throw new IllegalArgumentException(
204 "RepositoryJavaClient.get: handler is missing");
207 RepositoryInstance repoSession = null;
209 handler.prepare(Action.GET);
210 repoSession = getRepositorySession();
211 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
212 DocumentModel docModel = null;
214 docModel = repoSession.getDocument(docRef);
215 assertWorkflowState(ctx, docModel);
216 } catch (ClientException ce) {
217 String msg = logException(ce, "Could not find document with CSID=" + id);
218 throw new DocumentNotFoundException(msg, ce);
221 // Set repository session to handle the document
223 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
224 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(docModel);
225 handler.handle(Action.GET, wrapDoc);
226 handler.complete(Action.GET, wrapDoc);
227 } catch (IllegalArgumentException iae) {
229 } catch (DocumentException de) {
231 } catch (Exception e) {
232 if (logger.isDebugEnabled()) {
233 logger.debug("Caught exception ", e);
235 throw new DocumentException(e);
237 if (repoSession != null) {
238 releaseRepositorySession(repoSession);
244 * get document from the Nuxeo repository, using the docFilter params.
245 * @param ctx service context under which this method is invoked
247 * should be used by the caller to provide and transform the
248 * document. Handler must have a docFilter set to return a single item.
249 * @throws DocumentException
252 public void get(ServiceContext ctx, DocumentHandler handler)
253 throws DocumentNotFoundException, DocumentException {
254 QueryContext queryContext = new QueryContext(ctx, handler);
255 RepositoryInstance repoSession = null;
258 handler.prepare(Action.GET);
259 repoSession = getRepositorySession();
261 DocumentModelList docList = null;
262 // force limit to 1, and ignore totalSize
263 String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
264 docList = repoSession.query(query, null, 1, 0, false);
265 if (docList.size() != 1) {
266 throw new DocumentNotFoundException("No document found matching filter params: " + query);
268 DocumentModel doc = docList.get(0);
270 if (logger.isDebugEnabled()) {
271 logger.debug("Executed NXQL query: " + query);
274 //set reposession to handle the document
275 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
276 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
277 handler.handle(Action.GET, wrapDoc);
278 handler.complete(Action.GET, wrapDoc);
279 } catch (IllegalArgumentException iae) {
281 } catch (DocumentException de) {
283 } catch (Exception e) {
284 if (logger.isDebugEnabled()) {
285 logger.debug("Caught exception ", e);
287 throw new DocumentException(e);
289 if (repoSession != null) {
290 releaseRepositorySession(repoSession);
295 public DocumentWrapper<DocumentModel> getDoc(
296 RepositoryInstance repoSession,
297 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
298 String csid) throws DocumentNotFoundException, DocumentException {
299 DocumentWrapper<DocumentModel> wrapDoc = null;
302 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
303 DocumentModel doc = null;
305 doc = repoSession.getDocument(docRef);
306 } catch (ClientException ce) {
307 String msg = logException(ce, "Could not find document with CSID=" + csid);
308 throw new DocumentNotFoundException(msg, ce);
310 wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
311 } catch (IllegalArgumentException iae) {
313 } catch (DocumentException de) {
321 * Get wrapped documentModel from the Nuxeo repository. The search is restricted to the workspace
322 * of the current context.
324 * @param ctx service context under which this method is invoked
326 * of the document to retrieve
327 * @throws DocumentException
330 public DocumentWrapper<DocumentModel> getDoc(
331 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
332 String csid) throws DocumentNotFoundException, DocumentException {
333 RepositoryInstance repoSession = null;
334 DocumentWrapper<DocumentModel> wrapDoc = null;
337 // Open a new repository session
338 repoSession = getRepositorySession();
339 wrapDoc = getDoc(repoSession, ctx, csid);
340 } catch (IllegalArgumentException iae) {
342 } catch (DocumentException de) {
344 } catch (Exception e) {
345 if (logger.isDebugEnabled()) {
346 logger.debug("Caught exception ", e);
348 throw new DocumentException(e);
350 if (repoSession != null) {
351 releaseRepositorySession(repoSession);
355 if (logger.isWarnEnabled() == true) {
356 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
361 public DocumentWrapper<DocumentModel> findDoc(
362 RepositoryInstance repoSession,
363 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
365 throws DocumentNotFoundException, DocumentException {
366 DocumentWrapper<DocumentModel> wrapDoc = null;
369 QueryContext queryContext = new QueryContext(ctx, whereClause);
370 DocumentModelList docList = null;
371 // force limit to 1, and ignore totalSize
372 String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
373 docList = repoSession.query(query,
378 if (docList.size() != 1) {
379 if (logger.isDebugEnabled()) {
380 logger.debug("findDoc: Query found: " + docList.size() + " items.");
381 logger.debug(" Query: " + query);
383 throw new DocumentNotFoundException("No document found matching filter params: " + query);
385 DocumentModel doc = docList.get(0);
386 wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
387 } catch (IllegalArgumentException iae) {
389 } catch (DocumentException de) {
391 } catch (Exception e) {
392 if (logger.isDebugEnabled()) {
393 logger.debug("Caught exception ", e);
395 throw new DocumentException(e);
402 * find wrapped documentModel from the Nuxeo repository
403 * @param ctx service context under which this method is invoked
404 * @param whereClause where NXQL where clause to get the document
405 * @throws DocumentException
408 public DocumentWrapper<DocumentModel> findDoc(
409 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
411 throws DocumentNotFoundException, DocumentException {
412 RepositoryInstance repoSession = null;
413 DocumentWrapper<DocumentModel> wrapDoc = null;
416 repoSession = getRepositorySession();
417 wrapDoc = findDoc(repoSession, ctx, whereClause);
418 } catch (Exception e) {
419 throw new DocumentException("Unable to create a Nuxeo repository session.", e);
421 if (repoSession != null) {
422 releaseRepositorySession(repoSession);
426 if (logger.isWarnEnabled() == true) {
427 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
434 * find doc and return CSID from the Nuxeo repository
435 * @param ctx service context under which this method is invoked
436 * @param whereClause where NXQL where clause to get the document
437 * @throws DocumentException
440 public String findDocCSID(RepositoryInstance repoSession,
441 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String whereClause)
442 throws DocumentNotFoundException, DocumentException {
444 boolean releaseSession = false;
446 if(repoSession== null) {
447 repoSession = this.getRepositorySession();
448 releaseSession = true;
450 DocumentWrapper<DocumentModel> wrapDoc = findDoc(repoSession, ctx, whereClause);
451 DocumentModel docModel = wrapDoc.getWrappedObject();
452 csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
453 } catch (DocumentNotFoundException dnfe) {
455 } catch (IllegalArgumentException iae) {
457 } catch (DocumentException de) {
459 } catch (Exception e) {
460 if (logger.isDebugEnabled()) {
461 logger.debug("Caught exception ", e);
463 throw new DocumentException(e);
465 if(releaseSession && (repoSession != null)) {
466 this.releaseRepositorySession(repoSession);
472 public DocumentWrapper<DocumentModelList> findDocs(
473 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
474 RepositoryInstance repoSession,
475 List<String> docTypes,
477 int pageSize, int pageNum, boolean computeTotal)
478 throws DocumentNotFoundException, DocumentException {
479 DocumentWrapper<DocumentModelList> wrapDoc = null;
482 if (docTypes == null || docTypes.size() < 1) {
483 throw new DocumentNotFoundException(
484 "The findDocs() method must specify at least one DocumentType.");
486 DocumentModelList docList = null;
487 QueryContext queryContext = new QueryContext(ctx, whereClause);
488 String query = NuxeoUtils.buildNXQLQuery(docTypes, queryContext);
489 if (logger.isDebugEnabled()) {
490 logger.debug("findDocs() NXQL: "+query);
492 docList = repoSession.query(query, null, pageSize, pageNum, computeTotal);
493 wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
494 } catch (IllegalArgumentException iae) {
496 } catch (Exception e) {
497 if (logger.isDebugEnabled()) {
498 logger.debug("Caught exception ", e);
500 throw new DocumentException(e);
507 * Find a list of documentModels from the Nuxeo repository
508 * @param docTypes a list of DocType names to match
509 * @param whereClause where the clause to qualify on
513 public DocumentWrapper<DocumentModelList> findDocs(
514 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
515 List<String> docTypes,
517 int pageSize, int pageNum, boolean computeTotal)
518 throws DocumentNotFoundException, DocumentException {
519 RepositoryInstance repoSession = null;
520 DocumentWrapper<DocumentModelList> wrapDoc = null;
523 repoSession = getRepositorySession();
524 wrapDoc = findDocs(ctx, repoSession, docTypes, whereClause,
525 pageSize, pageNum, computeTotal);
526 } catch (IllegalArgumentException iae) {
528 } catch (Exception e) {
529 if (logger.isDebugEnabled()) {
530 logger.debug("Caught exception ", e);
532 throw new DocumentException(e);
534 if (repoSession != null) {
535 releaseRepositorySession(repoSession);
539 if (logger.isWarnEnabled() == true) {
540 logger.warn("Returned DocumentModelList instance was created with a repository session that is now closed.");
547 * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.util.List, org.collectionspace.services.common.document.DocumentHandler)
550 public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
551 throws DocumentNotFoundException, DocumentException {
552 if (handler == null) {
553 throw new IllegalArgumentException(
554 "RepositoryJavaClient.getAll: handler is missing");
557 RepositoryInstance repoSession = null;
559 handler.prepare(Action.GET_ALL);
560 repoSession = getRepositorySession();
561 DocumentModelList docModelList = new DocumentModelListImpl();
562 //FIXME: Should be using NuxeoUtils.createPathRef for security reasons
563 for (String csid : csidList) {
564 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
565 DocumentModel docModel = repoSession.getDocument(docRef);
566 docModelList.add(docModel);
569 //set reposession to handle the document
570 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
571 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docModelList);
572 handler.handle(Action.GET_ALL, wrapDoc);
573 handler.complete(Action.GET_ALL, wrapDoc);
574 } catch (DocumentException de) {
576 } catch (Exception e) {
577 if (logger.isDebugEnabled()) {
578 logger.debug("Caught exception ", e);
580 throw new DocumentException(e);
582 if (repoSession != null) {
583 releaseRepositorySession(repoSession);
589 * getAll get all documents for an entity entity service from the Nuxeo
592 * @param ctx service context under which this method is invoked
594 * should be used by the caller to provide and transform the
596 * @throws DocumentException
599 public void getAll(ServiceContext ctx, DocumentHandler handler)
600 throws DocumentNotFoundException, DocumentException {
601 if (handler == null) {
602 throw new IllegalArgumentException(
603 "RepositoryJavaClient.getAll: handler is missing");
605 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
606 if (nuxeoWspaceId == null) {
607 throw new DocumentNotFoundException(
608 "Unable to find workspace for service "
609 + ctx.getServiceName()
610 + " check if the workspace exists in the Nuxeo repository.");
613 RepositoryInstance repoSession = null;
615 handler.prepare(Action.GET_ALL);
616 repoSession = getRepositorySession();
617 DocumentRef wsDocRef = new IdRef(nuxeoWspaceId);
618 DocumentModelList docList = repoSession.getChildren(wsDocRef);
619 //set reposession to handle the document
620 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
621 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
622 handler.handle(Action.GET_ALL, wrapDoc);
623 handler.complete(Action.GET_ALL, wrapDoc);
624 } catch (DocumentException de) {
626 } catch (Exception e) {
627 if (logger.isDebugEnabled()) {
628 logger.debug("Caught exception ", e);
630 throw new DocumentException(e);
632 if (repoSession != null) {
633 releaseRepositorySession(repoSession);
638 private boolean isClauseEmpty(String theString) {
639 boolean result = true;
640 if (theString != null && !theString.isEmpty()) {
646 public DocumentWrapper<DocumentModel> getDocFromCsid(
647 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
648 RepositoryInstance repoSession,
651 DocumentWrapper<DocumentModel> result = null;
653 result = new DocumentWrapperImpl(NuxeoUtils.getDocFromCsid(ctx, repoSession, csid));
659 * A method to find a CollectionSpace document (of any type) given just a service context and
660 * its CSID. A search across *all* service workspaces (within a given tenant context) is performed to find
663 * This query searches Nuxeo's Hierarchy table where our CSIDs are stored in the "name" column.
666 public DocumentWrapper<DocumentModel> getDocFromCsid(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
669 DocumentWrapper<DocumentModel> result = null;
670 RepositoryInstance repoSession = null;
672 repoSession = getRepositorySession();
673 result = getDocFromCsid(ctx, repoSession, csid);
675 if (repoSession != null) {
676 releaseRepositorySession(repoSession);
680 if (logger.isWarnEnabled() == true) {
681 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
688 * find doc and return CSID from the Nuxeo repository
689 * @param ctx service context under which this method is invoked
690 * @param whereClause where NXQL where clause to get the document
691 * @throws DocumentException
694 public String getDocURI(DocumentWrapper<DocumentModel> wrappedDoc) throws ClientException {
695 DocumentModel docModel = wrappedDoc.getWrappedObject();
696 String uri = (String)docModel.getProperty(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA,
697 CollectionSpaceClient.COLLECTIONSPACE_CORE_URI);
702 * See CSPACE-5036 - How to make CMISQL queries from Nuxeo
704 private IterableQueryResult makeCMISQLQuery(RepositoryInstance repoSession, String query) {
705 IterableQueryResult result = null;
707 // the NuxeoRepository should be constructed only once, then cached
708 // (its construction is expensive)
710 NuxeoRepository repo = new NuxeoRepository(
711 repoSession.getRepositoryName(), repoSession
712 .getRootDocument().getId());
713 logger.debug("Repository ID:" + repo.getId() + " Root folder:"
714 + repo.getRootFolderId());
716 CallContextImpl callContext = new CallContextImpl(
717 CallContext.BINDING_LOCAL, repo.getId(), false);
718 callContext.put(CallContext.USERNAME, repoSession.getPrincipal()
720 NuxeoCmisService cmisService = new NuxeoCmisService(repo,
721 callContext, repoSession);
723 result = repoSession.queryAndFetch(query,
724 "CMISQL", cmisService);
725 } catch (ClientException e) {
726 // TODO Auto-generated catch block
727 logger.error("Encounter trouble making the following CMIS query: " + query, e);
734 * getFiltered get all documents for an entity service from the Document repository,
735 * given filter parameters specified by the handler.
736 * @param ctx service context under which this method is invoked
737 * @param handler should be used by the caller to provide and transform the document
738 * @throws DocumentNotFoundException if workspace not found
739 * @throws DocumentException
742 public void getFiltered(ServiceContext ctx, DocumentHandler handler)
743 throws DocumentNotFoundException, DocumentException {
745 DocumentFilter filter = handler.getDocumentFilter();
746 String oldOrderBy = filter.getOrderByClause();
747 if (isClauseEmpty(oldOrderBy) == true){
748 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?)
750 QueryContext queryContext = new QueryContext(ctx, handler);
752 RepositoryInstance repoSession = null;
754 handler.prepare(Action.GET_ALL);
755 repoSession = getRepositorySession();
757 DocumentModelList docList = null;
758 String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
760 if (logger.isDebugEnabled()) {
761 logger.debug("Executing NXQL query: " + query.toString());
764 // If we have limit and/or offset, then pass true to get totalSize
765 // in returned DocumentModelList.
766 Profiler profiler = new Profiler(this, 2);
767 profiler.log("Executing NXQL query: " + query.toString());
769 if (handler.isCMISQuery() == true) {
770 docList = getFilteredCMIS(repoSession, ctx, handler, queryContext); //FIXME: REM - Need to deal with paging info in CMIS query
771 } else if ((queryContext.getDocFilter().getOffset() > 0) || (queryContext.getDocFilter().getPageSize() > 0)) {
772 docList = repoSession.query(query, null,
773 queryContext.getDocFilter().getPageSize(), queryContext.getDocFilter().getOffset(), true);
775 docList = repoSession.query(query);
779 //set repoSession to handle the document
780 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
781 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
782 handler.handle(Action.GET_ALL, wrapDoc);
783 handler.complete(Action.GET_ALL, wrapDoc);
784 } catch (DocumentException de) {
786 } catch (Exception e) {
787 if (logger.isDebugEnabled()) {
788 logger.debug("Caught exception ", e);
790 throw new DocumentException(e);
792 if (repoSession != null) {
793 releaseRepositorySession(repoSession);
798 private DocumentModelList getFilteredCMIS(RepositoryInstance repoSession, ServiceContext ctx, DocumentHandler handler, QueryContext queryContext)
799 throws DocumentNotFoundException, DocumentException {
801 DocumentModelList result = new DocumentModelListImpl();
803 String query = handler.getCMISQuery();
805 if (logger.isDebugEnabled()) {
806 logger.debug("Executing CMIS query: " + query.toString());
809 // If we have limit and/or offset, then pass true to get totalSize
810 // in returned DocumentModelList.
811 Profiler profiler = new Profiler(this, 2);
812 profiler.log("Executing CMIS query: " + query.toString());
815 IterableQueryResult queryResult = makeCMISQLQuery(repoSession, query);
817 for (Map<String, Serializable> row : queryResult) {
819 // + " dc:title is: " + (String)row.get("dc:title")
820 + " Hierarchy Table ID is:" + row.get(IQueryManager.CMIS_TARGET_NUXEO_ID)
821 + " cmis:name is: " + row.get(IQueryManager.CMIS_TARGET_NAME)
822 // + " nuxeo:lifecycleState is: " + row.get("nuxeo:lifecycleState")
824 String nuxeoId = (String) row.get(IQueryManager.CMIS_TARGET_NUXEO_ID);
825 DocumentModel docModel = NuxeoUtils.getDocumentModel(repoSession, nuxeoId);
826 result.add(docModel);
834 } catch (Exception e) {
835 if (logger.isDebugEnabled()) {
836 logger.debug("Caught exception ", e);
838 throw new DocumentException(e);
844 private String logException(Exception e, String msg) {
845 String result = null;
847 String exceptionMessage = e.getMessage();
848 exceptionMessage = exceptionMessage != null ? exceptionMessage : "<No details provided>";
849 result = msg = msg + ". Caught exception:" + exceptionMessage;
851 if (logger.isTraceEnabled() == true) {
852 logger.error(msg, e);
861 * update given document in the Nuxeo repository
863 * @param ctx service context under which this method is invoked
867 * should be used by the caller to provide and transform the
869 * @throws DocumentException
872 public void update(ServiceContext ctx, String csid, DocumentHandler handler)
873 throws BadRequestException, DocumentNotFoundException,
875 if (handler == null) {
876 throw new IllegalArgumentException(
877 "RepositoryJavaClient.update: document handler is missing.");
880 RepositoryInstance repoSession = null;
882 handler.prepare(Action.UPDATE);
883 repoSession = getRepositorySession();
884 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
885 DocumentModel doc = null;
887 doc = repoSession.getDocument(docRef);
888 } catch (ClientException ce) {
889 String msg = logException(ce, "Could not find document to update with CSID=" + csid);
890 throw new DocumentNotFoundException(msg, ce);
893 // Set reposession to handle the document
895 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
896 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
897 handler.handle(Action.UPDATE, wrapDoc);
898 repoSession.saveDocument(doc);
900 handler.complete(Action.UPDATE, wrapDoc);
901 } catch (BadRequestException bre) {
903 } catch (DocumentException de) {
905 } catch (WebApplicationException wae){
907 } catch (Exception e) {
908 if (logger.isDebugEnabled()) {
909 logger.debug("Caught exception ", e);
911 throw new DocumentException(e);
913 if (repoSession != null) {
914 releaseRepositorySession(repoSession);
920 * Save a documentModel to the Nuxeo repository.
921 * @param ctx service context under which this method is invoked
922 * @param docModel the document to save
923 * @param fSaveSession if TRUE, will call CoreSession.save() to save accumulated changes.
924 * @throws DocumentException
926 public void saveDocWithoutHandlerProcessing(
927 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
928 RepositoryInstance repoSession,
929 DocumentModel docModel,
930 boolean fSaveSession)
931 throws ClientException, DocumentException {
934 repoSession.saveDocument(docModel);
938 } catch (ClientException ce) {
940 } catch (Exception e) {
941 if (logger.isDebugEnabled()) {
942 logger.debug("Caught exception ", e);
944 throw new DocumentException(e);
950 * Save a list of documentModels to the Nuxeo repository.
952 * @param ctx service context under which this method is invoked
953 * @param docModel the document to save
954 * @param fSaveSession if TRUE, will call CoreSession.save() to save accumulated changes.
955 * @throws DocumentException
957 public void saveDocListWithoutHandlerProcessing(
958 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
959 RepositoryInstance repoSession,
960 DocumentModelList docList,
961 boolean fSaveSession)
962 throws ClientException, DocumentException {
964 repoSession = getRepositorySession();
965 DocumentModel[] docModelArray = new DocumentModel[docList.size()];
966 repoSession.saveDocuments(docList.toArray(docModelArray));
970 } catch (ClientException ce) {
972 } catch (Exception e) {
973 logger.error("Caught exception ", e);
974 throw new DocumentException(e);
979 * delete a document from the Nuxeo repository
980 * @param ctx service context under which this method is invoked
983 * @throws DocumentException
986 public void delete(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException,
989 throw new IllegalArgumentException(
990 "delete(ctx, ix, handler): ctx is missing");
992 if (handler == null) {
993 throw new IllegalArgumentException(
994 "delete(ctx, ix, handler): handler is missing");
996 if (logger.isDebugEnabled()) {
997 logger.debug("Deleting document with CSID=" + id);
999 RepositoryInstance repoSession = null;
1001 handler.prepare(Action.DELETE);
1002 repoSession = getRepositorySession();
1003 DocumentWrapper<DocumentModel> wrapDoc = null;
1005 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
1006 wrapDoc = new DocumentWrapperImpl<DocumentModel>(repoSession.getDocument(docRef));
1007 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
1008 handler.handle(Action.DELETE, wrapDoc);
1009 repoSession.removeDocument(docRef);
1010 } catch (ClientException ce) {
1011 String msg = logException(ce, "Could not find document to delete with CSID=" + id);
1012 throw new DocumentNotFoundException(msg, ce);
1015 handler.complete(Action.DELETE, wrapDoc);
1016 } catch (DocumentException de) {
1018 } catch (Exception e) {
1019 if (logger.isDebugEnabled()) {
1020 logger.debug("Caught exception ", e);
1022 throw new DocumentException(e);
1024 if (repoSession != null) {
1025 releaseRepositorySession(repoSession);
1031 * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
1035 public void delete(@SuppressWarnings("rawtypes") ServiceContext ctx, String id)
1036 throws DocumentNotFoundException, DocumentException {
1037 throw new UnsupportedOperationException();
1038 // Use the other delete instead
1042 public Hashtable<String, String> retrieveWorkspaceIds(String domainName) throws Exception {
1043 return NuxeoConnectorEmbedded.getInstance().retrieveWorkspaceIds(domainName);
1047 public String createDomain(String domainName) throws Exception {
1048 RepositoryInstance repoSession = null;
1049 String domainId = null;
1052 // First create the top-level domain directory
1054 repoSession = getRepositorySession();
1055 DocumentRef parentDocRef = new PathRef("/");
1056 DocumentModel parentDoc = repoSession.getDocument(parentDocRef);
1057 DocumentModel domainDoc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
1058 domainName, NUXEO_CORE_TYPE_DOMAIN);
1059 domainDoc.setPropertyValue("dc:title", domainName);
1060 domainDoc.setPropertyValue("dc:description", "A CollectionSpace domain "
1062 domainDoc = repoSession.createDocument(domainDoc);
1063 domainId = domainDoc.getId();
1066 // Next, create a "Workspaces" root directory to contain the workspace folders for the individual service documents
1068 DocumentModel workspacesRoot = repoSession.createDocumentModel(domainDoc.getPathAsString(),
1069 NuxeoUtils.Workspaces, NUXEO_CORE_TYPE_WORKSPACEROOT);
1070 workspacesRoot.setPropertyValue("dc:title", NuxeoUtils.Workspaces);
1071 workspacesRoot.setPropertyValue("dc:description", "A CollectionSpace workspaces directory for "
1072 + domainDoc.getPathAsString());
1073 workspacesRoot = repoSession.createDocument(workspacesRoot);
1074 String workspacesRootId = workspacesRoot.getId();
1077 if (logger.isDebugEnabled()) {
1078 logger.debug("Created tenant domain name=" + domainName
1079 + " id=" + domainId + " " +
1080 NuxeoUtils.Workspaces + " id=" + workspacesRootId);
1081 logger.debug("Path to Domain: "+domainDoc.getPathAsString());
1082 logger.debug("Path to Workspaces root: "+workspacesRoot.getPathAsString());
1084 } catch (Exception e) {
1085 if (logger.isDebugEnabled()) {
1086 logger.debug("Could not create tenant domain name=" + domainName + " caught exception ", e);
1090 if (repoSession != null) {
1091 releaseRepositorySession(repoSession);
1099 public String getDomainId(String domainName) throws Exception {
1100 String domainId = null;
1101 RepositoryInstance repoSession = null;
1103 if (domainName != null && !domainName.isEmpty()) {
1105 repoSession = getRepositorySession();
1106 DocumentRef docRef = new PathRef(
1108 DocumentModel domain = repoSession.getDocument(docRef);
1109 domainId = domain.getId();
1110 } catch (Exception e) {
1111 if (logger.isTraceEnabled()) {
1112 logger.trace("Caught exception ", e);
1114 //there is no way to identify if document does not exist due to
1115 //lack of typed exception for getDocument method
1118 if (repoSession != null) {
1119 releaseRepositorySession(repoSession);
1128 * Returns the workspaces root directory for a given domain.
1130 private DocumentModel getWorkspacesRoot(RepositoryInstance repoSession,
1131 String domainName) throws Exception {
1132 DocumentModel result = null;
1134 String domainPath = "/" + domainName;
1135 DocumentRef parentDocRef = new PathRef(domainPath);
1136 DocumentModelList domainChildrenList = repoSession.getChildren(
1138 Iterator<DocumentModel> witer = domainChildrenList.iterator();
1139 while (witer.hasNext()) {
1140 DocumentModel childNode = witer.next();
1141 if (NuxeoUtils.Workspaces.equalsIgnoreCase(childNode.getName())) {
1143 logger.trace("Found workspaces directory at: " + result.getPathAsString());
1148 if (result == null) {
1149 throw new ClientException("Could not find workspace root directory in: "
1157 * @see org.collectionspace.services.common.repository.RepositoryClient#createWorkspace(java.lang.String, java.lang.String)
1160 public String createWorkspace(String domainName, String workspaceName) throws Exception {
1161 RepositoryInstance repoSession = null;
1162 String workspaceId = null;
1164 repoSession = getRepositorySession();
1165 DocumentModel parentDoc = getWorkspacesRoot(repoSession, domainName);
1166 DocumentModel doc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
1167 workspaceName, NuxeoUtils.WORKSPACE_DOCUMENT_TYPE);
1168 doc.setPropertyValue("dc:title", workspaceName);
1169 doc.setPropertyValue("dc:description", "A CollectionSpace workspace for "
1171 doc = repoSession.createDocument(doc);
1172 workspaceId = doc.getId();
1174 if (logger.isDebugEnabled()) {
1175 logger.debug("Created workspace name=" + workspaceName
1176 + " id=" + workspaceId);
1178 } catch (Exception e) {
1179 if (logger.isDebugEnabled()) {
1180 logger.debug("createWorkspace caught exception ", e);
1184 if (repoSession != null) {
1185 releaseRepositorySession(repoSession);
1192 * @see org.collectionspace.services.common.repository.RepositoryClient#getWorkspaceId(java.lang.String, java.lang.String)
1195 public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
1196 String workspaceId = null;
1198 RepositoryInstance repoSession = null;
1200 repoSession = getRepositorySession();
1201 DocumentRef docRef = new PathRef(
1203 + "/" + NuxeoUtils.Workspaces
1204 + "/" + workspaceName);
1205 DocumentModel workspace = repoSession.getDocument(docRef);
1206 workspaceId = workspace.getId();
1207 } catch (DocumentException de) {
1209 } catch (Exception e) {
1210 if (logger.isDebugEnabled()) {
1211 logger.debug("Caught exception ", e);
1213 throw new DocumentException(e);
1215 if (repoSession != null) {
1216 releaseRepositorySession(repoSession);
1225 * Gets the repository session. - Package access only.
1227 * @return the repository session
1228 * @throws Exception the exception
1230 public RepositoryInstance getRepositorySession() throws Exception {
1231 // FIXME: is it possible to reuse repository session?
1232 // Authentication failures happen while trying to reuse the session
1233 Profiler profiler = new Profiler("getRepositorySession():", 2);
1236 NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
1237 RepositoryInstance repoSession = client.openRepository();
1238 if (logger.isTraceEnabled()) {
1239 logger.trace("Testing call to getRepository() repository root: " + repoSession.getRootDocument());
1247 * Release repository session. - Package access only.
1249 * @param repoSession the repo session
1251 public void releaseRepositorySession(RepositoryInstance repoSession) {
1253 NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
1255 client.releaseRepository(repoSession);
1256 } catch (Exception e) {
1257 logger.error("Could not close the repository session", e);
1258 // no need to throw this service specific exception
1263 public void doWorkflowTransition(ServiceContext ctx, String id,
1264 DocumentHandler handler, TransitionDef transitionDef)
1265 throws BadRequestException, DocumentNotFoundException,
1267 // 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