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.util.Hashtable;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.UUID;
25 import javax.ws.rs.WebApplicationException;
26 import javax.ws.rs.core.MultivaluedMap;
28 import org.collectionspace.services.client.PoxPayloadIn;
29 import org.collectionspace.services.client.PoxPayloadOut;
30 import org.collectionspace.services.client.workflow.WorkflowClient;
31 import org.collectionspace.services.common.context.ServiceContext;
32 import org.collectionspace.services.common.query.QueryContext;
33 import org.collectionspace.services.common.repository.RepositoryClient;
34 import org.collectionspace.services.common.profile.Profiler;
35 import org.collectionspace.services.lifecycle.TransitionDef;
36 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
38 import org.collectionspace.services.common.document.BadRequestException;
39 import org.collectionspace.services.common.document.DocumentException;
40 import org.collectionspace.services.common.document.DocumentFilter;
41 import org.collectionspace.services.common.document.DocumentHandler;
42 import org.collectionspace.services.common.document.DocumentNotFoundException;
43 import org.collectionspace.services.common.document.DocumentHandler.Action;
44 import org.collectionspace.services.common.document.DocumentWrapper;
45 import org.collectionspace.services.common.document.DocumentWrapperImpl;
47 import org.nuxeo.common.utils.IdUtils;
48 import org.nuxeo.ecm.core.api.ClientException;
49 import org.nuxeo.ecm.core.api.DocumentModel;
50 import org.nuxeo.ecm.core.api.DocumentModelList;
51 import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
52 import org.nuxeo.ecm.core.api.DocumentRef;
53 import org.nuxeo.ecm.core.api.IdRef;
54 import org.nuxeo.ecm.core.api.PathRef;
55 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
61 * RepositoryJavaClient is used to perform CRUD operations on documents in Nuxeo
62 * repository using Remote Java APIs. It uses @see DocumentHandler as IOHandler
65 * $LastChangedRevision: $ $LastChangedDate: $
67 public class RepositoryJavaClientImpl implements RepositoryClient<PoxPayloadIn, PoxPayloadOut> {
70 private final Logger logger = LoggerFactory.getLogger(RepositoryJavaClientImpl.class);
71 // private final Logger profilerLogger = LoggerFactory.getLogger("remperf");
72 // private String foo = Profiler.createLogger();
74 public static final String NUXEO_CORE_TYPE_DOMAIN = "Domain";
75 public static final String NUXEO_CORE_TYPE_WORKSPACEROOT = "WorkspaceRoot";
78 * Instantiates a new repository java client impl.
80 public RepositoryJavaClientImpl() {
85 public void assertWorkflowState(ServiceContext ctx,
86 DocumentModel docModel) throws DocumentNotFoundException, ClientException {
87 MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
88 if (queryParams != null) {
90 // Look for the workflow "delete" query param and see if we need to assert that the
91 // docModel is in a non-deleted workflow state.
93 String currentState = docModel.getCurrentLifeCycleState();
94 String includeDeletedStr = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_NONDELETED);
95 boolean includeDeleted = includeDeletedStr == null ? true : Boolean.parseBoolean(includeDeletedStr);
96 if (includeDeleted == false) {
98 // We don't wanted soft-deleted object, so throw an exception if this one is soft-deleted.
100 if (currentState.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_DELETED)) {
101 String msg = "The GET assertion that docModel not be in 'deleted' workflow state failed.";
103 throw new DocumentNotFoundException(msg);
110 * create document in the Nuxeo repository
112 * @param ctx service context under which this method is invoked
114 * should be used by the caller to provide and transform the
116 * @return id in repository of the newly created document
117 * @throws DocumentException
120 public String create(ServiceContext ctx,
121 DocumentHandler handler) throws BadRequestException,
124 String docType = NuxeoUtils.getTenantQualifiedDocType(ctx); //ctx.getDocumentType();
125 if (docType == null) {
126 throw new IllegalArgumentException(
127 "RepositoryJavaClient.create: docType is missing");
130 if (handler == null) {
131 throw new IllegalArgumentException(
132 "RepositoryJavaClient.create: handler is missing");
134 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
135 if (nuxeoWspaceId == null) {
136 throw new DocumentNotFoundException(
137 "Unable to find workspace for service " + ctx.getServiceName()
138 + " check if the workspace exists in the Nuxeo repository");
141 RepositoryInstance repoSession = null;
143 handler.prepare(Action.CREATE);
144 repoSession = getRepositorySession();
145 DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);
146 DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);
147 String wspacePath = wspaceDoc.getPathAsString();
148 //give our own ID so PathRef could be constructed later on
149 String id = IdUtils.generateId(UUID.randomUUID().toString());
150 // create document model
151 DocumentModel doc = repoSession.createDocumentModel(wspacePath, id, docType);
152 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
153 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
154 handler.handle(Action.CREATE, wrapDoc);
155 // create document with documentmodel
156 doc = repoSession.createDocument(doc);
158 // TODO for sub-docs need to call into the handler to let it deal with subitems. Pass in the id,
159 // and assume the handler has the state it needs (doc fragments).
160 handler.complete(Action.CREATE, wrapDoc);
162 } catch (BadRequestException bre) {
164 } catch (Exception e) {
165 logger.error("Caught exception ", e);
166 throw new DocumentException(e);
168 if (repoSession != null) {
169 releaseRepositorySession(repoSession);
176 * get document from the Nuxeo repository
177 * @param ctx service context under which this method is invoked
179 * of the document to retrieve
181 * should be used by the caller to provide and transform the
183 * @throws DocumentException
186 public void get(ServiceContext ctx, String id, DocumentHandler handler)
187 throws DocumentNotFoundException, DocumentException {
189 if (handler == null) {
190 throw new IllegalArgumentException(
191 "RepositoryJavaClient.get: handler is missing");
194 RepositoryInstance repoSession = null;
196 handler.prepare(Action.GET);
197 repoSession = getRepositorySession();
198 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
199 DocumentModel docModel = null;
201 docModel = repoSession.getDocument(docRef);
202 assertWorkflowState(ctx, docModel);
203 } catch (ClientException ce) {
204 String msg = logException(ce, "Could not find document with CSID=" + id);
205 throw new DocumentNotFoundException(msg, ce);
208 // Set repository session to handle the document
210 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
211 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(docModel);
212 handler.handle(Action.GET, wrapDoc);
213 handler.complete(Action.GET, wrapDoc);
214 } catch (IllegalArgumentException iae) {
216 } catch (DocumentException de) {
218 } catch (Exception e) {
219 if (logger.isDebugEnabled()) {
220 logger.debug("Caught exception ", e);
222 throw new DocumentException(e);
224 if (repoSession != null) {
225 releaseRepositorySession(repoSession);
231 * get document from the Nuxeo repository, using the docFilter params.
232 * @param ctx service context under which this method is invoked
234 * should be used by the caller to provide and transform the
235 * document. Handler must have a docFilter set to return a single item.
236 * @throws DocumentException
239 public void get(ServiceContext ctx, DocumentHandler handler)
240 throws DocumentNotFoundException, DocumentException {
241 QueryContext queryContext = new QueryContext(ctx, handler);
242 RepositoryInstance repoSession = null;
245 handler.prepare(Action.GET);
246 repoSession = getRepositorySession();
248 DocumentModelList docList = null;
249 // force limit to 1, and ignore totalSize
250 String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
251 docList = repoSession.query(query, null, 1, 0, false);
252 if (docList.size() != 1) {
253 throw new DocumentNotFoundException("No document found matching filter params: " + query);
255 DocumentModel doc = docList.get(0);
257 if (logger.isDebugEnabled()) {
258 logger.debug("Executed NXQL query: " + query);
261 //set reposession to handle the document
262 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
263 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
264 handler.handle(Action.GET, wrapDoc);
265 handler.complete(Action.GET, wrapDoc);
266 } catch (IllegalArgumentException iae) {
268 } catch (DocumentException de) {
270 } catch (Exception e) {
271 if (logger.isDebugEnabled()) {
272 logger.debug("Caught exception ", e);
274 throw new DocumentException(e);
276 if (repoSession != null) {
277 releaseRepositorySession(repoSession);
282 public DocumentWrapper<DocumentModel> getDoc(
283 RepositoryInstance repoSession,
284 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
285 String csid) throws DocumentNotFoundException, DocumentException {
286 DocumentWrapper<DocumentModel> wrapDoc = null;
289 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
290 DocumentModel doc = null;
292 doc = repoSession.getDocument(docRef);
293 } catch (ClientException ce) {
294 String msg = logException(ce, "Could not find document with CSID=" + csid);
295 throw new DocumentNotFoundException(msg, ce);
297 wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
298 } catch (IllegalArgumentException iae) {
300 } catch (DocumentException de) {
308 * Get wrapped documentModel from the Nuxeo repository. The search is restricted to the workspace
309 * of the current context.
311 * @param ctx service context under which this method is invoked
313 * of the document to retrieve
314 * @throws DocumentException
317 public DocumentWrapper<DocumentModel> getDoc(
318 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
319 String csid) throws DocumentNotFoundException, DocumentException {
320 RepositoryInstance repoSession = null;
321 DocumentWrapper<DocumentModel> wrapDoc = null;
324 // Open a new repository session
325 repoSession = getRepositorySession();
326 wrapDoc = getDoc(repoSession, ctx, csid);
327 } catch (IllegalArgumentException iae) {
329 } catch (DocumentException de) {
331 } catch (Exception e) {
332 if (logger.isDebugEnabled()) {
333 logger.debug("Caught exception ", e);
335 throw new DocumentException(e);
337 if (repoSession != null) {
338 releaseRepositorySession(repoSession);
342 if (logger.isWarnEnabled() == true) {
343 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
348 public DocumentWrapper<DocumentModel> findDoc(
349 RepositoryInstance repoSession,
350 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
352 throws DocumentNotFoundException, DocumentException {
353 DocumentWrapper<DocumentModel> wrapDoc = null;
356 QueryContext queryContext = new QueryContext(ctx, whereClause);
357 DocumentModelList docList = null;
358 // force limit to 1, and ignore totalSize
359 String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
360 docList = repoSession.query(query,
365 if (docList.size() != 1) {
366 if (logger.isDebugEnabled()) {
367 logger.debug("findDoc: Query found: " + docList.size() + " items.");
368 logger.debug(" Query: " + query);
370 throw new DocumentNotFoundException("No document found matching filter params: " + query);
372 DocumentModel doc = docList.get(0);
373 wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
374 } catch (IllegalArgumentException iae) {
376 } catch (DocumentException de) {
378 } catch (Exception e) {
379 if (logger.isDebugEnabled()) {
380 logger.debug("Caught exception ", e);
382 throw new DocumentException(e);
389 * find wrapped documentModel from the Nuxeo repository
390 * @param ctx service context under which this method is invoked
391 * @param whereClause where NXQL where clause to get the document
392 * @throws DocumentException
395 public DocumentWrapper<DocumentModel> findDoc(
396 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
398 throws DocumentNotFoundException, DocumentException {
399 RepositoryInstance repoSession = null;
400 DocumentWrapper<DocumentModel> wrapDoc = null;
403 repoSession = getRepositorySession();
404 wrapDoc = findDoc(repoSession, ctx, whereClause);
405 } catch (Exception e) {
406 throw new DocumentException("Unable to create a Nuxeo repository session.", e);
408 if (repoSession != null) {
409 releaseRepositorySession(repoSession);
413 if (logger.isWarnEnabled() == true) {
414 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
421 * find doc and return CSID from the Nuxeo repository
422 * @param ctx service context under which this method is invoked
423 * @param whereClause where NXQL where clause to get the document
424 * @throws DocumentException
427 public String findDocCSID(RepositoryInstance repoSession,
428 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String whereClause)
429 throws DocumentNotFoundException, DocumentException {
431 boolean releaseSession = false;
433 if(repoSession== null) {
434 repoSession = this.getRepositorySession();
435 releaseSession = true;
437 DocumentWrapper<DocumentModel> wrapDoc = findDoc(repoSession, ctx, whereClause);
438 DocumentModel docModel = wrapDoc.getWrappedObject();
439 csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
440 } catch (DocumentNotFoundException dnfe) {
442 } catch (IllegalArgumentException iae) {
444 } catch (DocumentException de) {
446 } catch (Exception e) {
447 if (logger.isDebugEnabled()) {
448 logger.debug("Caught exception ", e);
450 throw new DocumentException(e);
452 if(releaseSession && (repoSession != null)) {
453 this.releaseRepositorySession(repoSession);
459 public DocumentWrapper<DocumentModelList> findDocs(
460 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
461 RepositoryInstance repoSession,
462 List<String> docTypes,
464 int pageSize, int pageNum, boolean computeTotal)
465 throws DocumentNotFoundException, DocumentException {
466 DocumentWrapper<DocumentModelList> wrapDoc = null;
469 if (docTypes == null || docTypes.size() < 1) {
470 throw new DocumentNotFoundException(
471 "The findDocs() method must specify at least one DocumentType.");
473 DocumentModelList docList = null;
474 QueryContext queryContext = new QueryContext(ctx, whereClause);
475 String query = NuxeoUtils.buildNXQLQuery(docTypes, queryContext);
476 if (logger.isDebugEnabled()) {
477 logger.debug("findDocs() NXQL: "+query);
479 docList = repoSession.query(query, null, pageSize, pageNum, computeTotal);
480 wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
481 } catch (IllegalArgumentException iae) {
483 } catch (Exception e) {
484 if (logger.isDebugEnabled()) {
485 logger.debug("Caught exception ", e);
487 throw new DocumentException(e);
494 * Find a list of documentModels from the Nuxeo repository
495 * @param docTypes a list of DocType names to match
496 * @param whereClause where the clause to qualify on
500 public DocumentWrapper<DocumentModelList> findDocs(
501 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
502 List<String> docTypes,
504 int pageSize, int pageNum, boolean computeTotal)
505 throws DocumentNotFoundException, DocumentException {
506 RepositoryInstance repoSession = null;
507 DocumentWrapper<DocumentModelList> wrapDoc = null;
510 repoSession = getRepositorySession();
511 wrapDoc = findDocs(ctx, repoSession, docTypes, whereClause,
512 pageSize, pageNum, computeTotal);
513 } catch (IllegalArgumentException iae) {
515 } catch (Exception e) {
516 if (logger.isDebugEnabled()) {
517 logger.debug("Caught exception ", e);
519 throw new DocumentException(e);
521 if (repoSession != null) {
522 releaseRepositorySession(repoSession);
526 if (logger.isWarnEnabled() == true) {
527 logger.warn("Returned DocumentModelList instance was created with a repository session that is now closed.");
534 * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.util.List, org.collectionspace.services.common.document.DocumentHandler)
537 public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
538 throws DocumentNotFoundException, DocumentException {
539 if (handler == null) {
540 throw new IllegalArgumentException(
541 "RepositoryJavaClient.getAll: handler is missing");
544 RepositoryInstance repoSession = null;
546 handler.prepare(Action.GET_ALL);
547 repoSession = getRepositorySession();
548 DocumentModelList docModelList = new DocumentModelListImpl();
549 //FIXME: Should be using NuxeoUtils.createPathRef for security reasons
550 for (String csid : csidList) {
551 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
552 DocumentModel docModel = repoSession.getDocument(docRef);
553 docModelList.add(docModel);
556 //set reposession to handle the document
557 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
558 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docModelList);
559 handler.handle(Action.GET_ALL, wrapDoc);
560 handler.complete(Action.GET_ALL, wrapDoc);
561 } catch (DocumentException de) {
563 } catch (Exception e) {
564 if (logger.isDebugEnabled()) {
565 logger.debug("Caught exception ", e);
567 throw new DocumentException(e);
569 if (repoSession != null) {
570 releaseRepositorySession(repoSession);
576 * getAll get all documents for an entity entity service from the Nuxeo
579 * @param ctx service context under which this method is invoked
581 * should be used by the caller to provide and transform the
583 * @throws DocumentException
586 public void getAll(ServiceContext ctx, DocumentHandler handler)
587 throws DocumentNotFoundException, DocumentException {
588 if (handler == null) {
589 throw new IllegalArgumentException(
590 "RepositoryJavaClient.getAll: handler is missing");
592 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
593 if (nuxeoWspaceId == null) {
594 throw new DocumentNotFoundException(
595 "Unable to find workspace for service "
596 + ctx.getServiceName()
597 + " check if the workspace exists in the Nuxeo repository.");
600 RepositoryInstance repoSession = null;
602 handler.prepare(Action.GET_ALL);
603 repoSession = getRepositorySession();
604 DocumentRef wsDocRef = new IdRef(nuxeoWspaceId);
605 DocumentModelList docList = repoSession.getChildren(wsDocRef);
606 //set reposession to handle the document
607 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
608 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
609 handler.handle(Action.GET_ALL, wrapDoc);
610 handler.complete(Action.GET_ALL, wrapDoc);
611 } catch (DocumentException de) {
613 } catch (Exception e) {
614 if (logger.isDebugEnabled()) {
615 logger.debug("Caught exception ", e);
617 throw new DocumentException(e);
619 if (repoSession != null) {
620 releaseRepositorySession(repoSession);
625 private boolean isClauseEmpty(String theString) {
626 boolean result = true;
627 if (theString != null && !theString.isEmpty()) {
633 public DocumentWrapper<DocumentModel> getDocFromCsid(
634 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
635 RepositoryInstance repoSession,
638 DocumentWrapper<DocumentModel> result = null;
640 result = new DocumentWrapperImpl(NuxeoUtils.getDocFromCsid(ctx, repoSession, csid));
646 * A method to find a CollectionSpace document (of any type) given just a service context and
647 * its CSID. A search across *all* service workspaces (within a given tenant context) is performed to find
650 * This query searches Nuxeo's Hierarchy table where our CSIDs are stored in the "name" column.
653 public DocumentWrapper<DocumentModel> getDocFromCsid(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
656 DocumentWrapper<DocumentModel> result = null;
657 RepositoryInstance repoSession = null;
659 repoSession = getRepositorySession();
660 result = getDocFromCsid(ctx, repoSession, csid);
662 if (repoSession != null) {
663 releaseRepositorySession(repoSession);
667 if (logger.isWarnEnabled() == true) {
668 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
675 * find doc and return CSID from the Nuxeo repository
676 * @param ctx service context under which this method is invoked
677 * @param whereClause where NXQL where clause to get the document
678 * @throws DocumentException
681 public String getDocURI(DocumentWrapper<DocumentModel> wrappedDoc) throws ClientException {
682 DocumentModel docModel = wrappedDoc.getWrappedObject();
683 String uri = (String)docModel.getProperty(DocumentModelHandler.COLLECTIONSPACE_CORE_SCHEMA,
684 DocumentModelHandler.COLLECTIONSPACE_CORE_URI);
690 * getFiltered get all documents for an entity service from the Document repository,
691 * given filter parameters specified by the handler.
692 * @param ctx service context under which this method is invoked
693 * @param handler should be used by the caller to provide and transform the document
694 * @throws DocumentNotFoundException if workspace not found
695 * @throws DocumentException
698 public void getFiltered(ServiceContext ctx, DocumentHandler handler)
699 throws DocumentNotFoundException, DocumentException {
701 DocumentFilter filter = handler.getDocumentFilter();
702 String oldOrderBy = filter.getOrderByClause();
703 if (isClauseEmpty(oldOrderBy) == true){
704 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?)
706 QueryContext queryContext = new QueryContext(ctx, handler);
708 RepositoryInstance repoSession = null;
710 handler.prepare(Action.GET_ALL);
711 repoSession = getRepositorySession();
712 DocumentModelList docList = null;
713 String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
715 if (logger.isDebugEnabled()) {
716 logger.debug("Executing NXQL query: " + query.toString());
719 // If we have limit and/or offset, then pass true to get totalSize
720 // in returned DocumentModelList.
721 Profiler profiler = new Profiler(this, 2);
722 profiler.log("Executing NXQL query: " + query.toString());
724 if ((queryContext.getDocFilter().getOffset() > 0) || (queryContext.getDocFilter().getPageSize() > 0)) {
725 docList = repoSession.query(query, null,
726 queryContext.getDocFilter().getPageSize(), queryContext.getDocFilter().getOffset(), true);
728 docList = repoSession.query(query);
732 //set repoSession to handle the document
733 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
734 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
735 handler.handle(Action.GET_ALL, wrapDoc);
736 handler.complete(Action.GET_ALL, wrapDoc);
737 } catch (DocumentException de) {
739 } catch (Exception e) {
740 if (logger.isDebugEnabled()) {
741 logger.debug("Caught exception ", e);
743 throw new DocumentException(e);
745 if (repoSession != null) {
746 releaseRepositorySession(repoSession);
751 private String logException(Exception e, String msg) {
752 String result = null;
754 String exceptionMessage = e.getMessage();
755 exceptionMessage = exceptionMessage != null ? exceptionMessage : "<No details provided>";
756 result = msg = msg + ". Caught exception:" + exceptionMessage;
758 if (logger.isTraceEnabled() == true) {
759 logger.error(msg, e);
768 * update given document in the Nuxeo repository
770 * @param ctx service context under which this method is invoked
774 * should be used by the caller to provide and transform the
776 * @throws DocumentException
779 public void update(ServiceContext ctx, String csid, DocumentHandler handler)
780 throws BadRequestException, DocumentNotFoundException,
782 if (handler == null) {
783 throw new IllegalArgumentException(
784 "RepositoryJavaClient.update: document handler is missing.");
787 RepositoryInstance repoSession = null;
789 handler.prepare(Action.UPDATE);
790 repoSession = getRepositorySession();
791 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
792 DocumentModel doc = null;
794 doc = repoSession.getDocument(docRef);
795 } catch (ClientException ce) {
796 String msg = logException(ce, "Could not find document to update with CSID=" + csid);
797 throw new DocumentNotFoundException(msg, ce);
800 // Set reposession to handle the document
802 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
803 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
804 handler.handle(Action.UPDATE, wrapDoc);
805 repoSession.saveDocument(doc);
807 handler.complete(Action.UPDATE, wrapDoc);
808 } catch (BadRequestException bre) {
810 } catch (DocumentException de) {
812 } catch (WebApplicationException wae){
814 } catch (Exception e) {
815 if (logger.isDebugEnabled()) {
816 logger.debug("Caught exception ", e);
818 throw new DocumentException(e);
820 if (repoSession != null) {
821 releaseRepositorySession(repoSession);
827 * Save a documentModel to the Nuxeo repository.
828 * @param ctx service context under which this method is invoked
829 * @param docModel the document to save
830 * @param fSaveSession if TRUE, will call CoreSession.save() to save accumulated changes.
831 * @throws DocumentException
833 public void saveDocWithoutHandlerProcessing(
834 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
835 RepositoryInstance repoSession,
836 DocumentModel docModel,
837 boolean fSaveSession)
838 throws ClientException, DocumentException {
841 repoSession.saveDocument(docModel);
845 } catch (ClientException ce) {
847 } catch (Exception e) {
848 if (logger.isDebugEnabled()) {
849 logger.debug("Caught exception ", e);
851 throw new DocumentException(e);
857 * Save a list of documentModels to the Nuxeo repository.
859 * @param ctx service context under which this method is invoked
860 * @param docModel the document to save
861 * @param fSaveSession if TRUE, will call CoreSession.save() to save accumulated changes.
862 * @throws DocumentException
864 public void saveDocListWithoutHandlerProcessing(
865 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
866 RepositoryInstance repoSession,
867 DocumentModelList docList,
868 boolean fSaveSession)
869 throws ClientException, DocumentException {
871 repoSession = getRepositorySession();
872 DocumentModel[] docModelArray = new DocumentModel[docList.size()];
873 repoSession.saveDocuments(docList.toArray(docModelArray));
877 } catch (ClientException ce) {
879 } catch (Exception e) {
880 logger.error("Caught exception ", e);
881 throw new DocumentException(e);
886 * delete a document from the Nuxeo repository
887 * @param ctx service context under which this method is invoked
890 * @throws DocumentException
893 public void delete(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException,
896 throw new IllegalArgumentException(
897 "delete(ctx, ix, handler): ctx is missing");
899 if (handler == null) {
900 throw new IllegalArgumentException(
901 "delete(ctx, ix, handler): handler is missing");
903 if (logger.isDebugEnabled()) {
904 logger.debug("Deleting document with CSID=" + id);
906 RepositoryInstance repoSession = null;
908 handler.prepare(Action.DELETE);
909 repoSession = getRepositorySession();
910 DocumentWrapper<DocumentModel> wrapDoc = null;
912 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
913 wrapDoc = new DocumentWrapperImpl<DocumentModel>(repoSession.getDocument(docRef));
914 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
915 handler.handle(Action.DELETE, wrapDoc);
916 repoSession.removeDocument(docRef);
917 } catch (ClientException ce) {
918 String msg = logException(ce, "Could not find document to delete with CSID=" + id);
919 throw new DocumentNotFoundException(msg, ce);
922 handler.complete(Action.DELETE, wrapDoc);
923 } catch (DocumentException de) {
925 } catch (Exception e) {
926 if (logger.isDebugEnabled()) {
927 logger.debug("Caught exception ", e);
929 throw new DocumentException(e);
931 if (repoSession != null) {
932 releaseRepositorySession(repoSession);
938 * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
942 public void delete(@SuppressWarnings("rawtypes") ServiceContext ctx, String id)
943 throws DocumentNotFoundException, DocumentException {
944 throw new UnsupportedOperationException();
945 // Use the other delete instead
949 public Hashtable<String, String> retrieveWorkspaceIds(String domainName) throws Exception {
950 return NuxeoConnectorEmbedded.getInstance().retrieveWorkspaceIds(domainName);
954 public String createDomain(String domainName) throws Exception {
955 RepositoryInstance repoSession = null;
956 String domainId = null;
959 // First create the top-level domain directory
961 repoSession = getRepositorySession();
962 DocumentRef parentDocRef = new PathRef("/");
963 DocumentModel parentDoc = repoSession.getDocument(parentDocRef);
964 DocumentModel domainDoc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
965 domainName, NUXEO_CORE_TYPE_DOMAIN);
966 domainDoc.setPropertyValue("dc:title", domainName);
967 domainDoc.setPropertyValue("dc:description", "A CollectionSpace domain "
969 domainDoc = repoSession.createDocument(domainDoc);
970 domainId = domainDoc.getId();
973 // Next, create a "Workspaces" root directory to contain the workspace folders for the individual service documents
975 DocumentModel workspacesRoot = repoSession.createDocumentModel(domainDoc.getPathAsString(),
976 NuxeoUtils.Workspaces, NUXEO_CORE_TYPE_WORKSPACEROOT);
977 workspacesRoot.setPropertyValue("dc:title", NuxeoUtils.Workspaces);
978 workspacesRoot.setPropertyValue("dc:description", "A CollectionSpace workspaces directory for "
979 + domainDoc.getPathAsString());
980 workspacesRoot = repoSession.createDocument(workspacesRoot);
981 String workspacesRootId = workspacesRoot.getId();
984 if (logger.isDebugEnabled()) {
985 logger.debug("Created tenant domain name=" + domainName
986 + " id=" + domainId + " " +
987 NuxeoUtils.Workspaces + " id=" + workspacesRootId);
988 logger.debug("Path to Domain: "+domainDoc.getPathAsString());
989 logger.debug("Path to Workspaces root: "+workspacesRoot.getPathAsString());
991 } catch (Exception e) {
992 if (logger.isDebugEnabled()) {
993 logger.debug("Could not create tenant domain name=" + domainName + " caught exception ", e);
997 if (repoSession != null) {
998 releaseRepositorySession(repoSession);
1006 public String getDomainId(String domainName) throws Exception {
1007 String domainId = null;
1008 RepositoryInstance repoSession = null;
1010 if (domainName != null && !domainName.isEmpty()) {
1012 repoSession = getRepositorySession();
1013 DocumentRef docRef = new PathRef(
1015 DocumentModel domain = repoSession.getDocument(docRef);
1016 domainId = domain.getId();
1017 } catch (Exception e) {
1018 if (logger.isTraceEnabled()) {
1019 logger.trace("Caught exception ", e);
1021 //there is no way to identify if document does not exist due to
1022 //lack of typed exception for getDocument method
1025 if (repoSession != null) {
1026 releaseRepositorySession(repoSession);
1035 * Returns the workspaces root directory for a given domain.
1037 private DocumentModel getWorkspacesRoot(RepositoryInstance repoSession,
1038 String domainName) throws Exception {
1039 DocumentModel result = null;
1041 String domainPath = "/" + domainName;
1042 DocumentRef parentDocRef = new PathRef(domainPath);
1043 DocumentModelList domainChildrenList = repoSession.getChildren(
1045 Iterator<DocumentModel> witer = domainChildrenList.iterator();
1046 while (witer.hasNext()) {
1047 DocumentModel childNode = witer.next();
1048 if (NuxeoUtils.Workspaces.equalsIgnoreCase(childNode.getName())) {
1050 logger.trace("Found workspaces directory at: " + result.getPathAsString());
1055 if (result == null) {
1056 throw new ClientException("Could not find workspace root directory in: "
1064 * @see org.collectionspace.services.common.repository.RepositoryClient#createWorkspace(java.lang.String, java.lang.String)
1067 public String createWorkspace(String domainName, String workspaceName) throws Exception {
1068 RepositoryInstance repoSession = null;
1069 String workspaceId = null;
1071 repoSession = getRepositorySession();
1072 DocumentModel parentDoc = getWorkspacesRoot(repoSession, domainName);
1073 DocumentModel doc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
1074 workspaceName, NuxeoUtils.WORKSPACE_DOCUMENT_TYPE);
1075 doc.setPropertyValue("dc:title", workspaceName);
1076 doc.setPropertyValue("dc:description", "A CollectionSpace workspace for "
1078 doc = repoSession.createDocument(doc);
1079 workspaceId = doc.getId();
1081 if (logger.isDebugEnabled()) {
1082 logger.debug("Created workspace name=" + workspaceName
1083 + " id=" + workspaceId);
1085 } catch (Exception e) {
1086 if (logger.isDebugEnabled()) {
1087 logger.debug("createWorkspace caught exception ", e);
1091 if (repoSession != null) {
1092 releaseRepositorySession(repoSession);
1099 * @see org.collectionspace.services.common.repository.RepositoryClient#getWorkspaceId(java.lang.String, java.lang.String)
1102 public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
1103 String workspaceId = null;
1105 RepositoryInstance repoSession = null;
1107 repoSession = getRepositorySession();
1108 DocumentRef docRef = new PathRef(
1110 + "/" + NuxeoUtils.Workspaces
1111 + "/" + workspaceName);
1112 DocumentModel workspace = repoSession.getDocument(docRef);
1113 workspaceId = workspace.getId();
1114 } catch (DocumentException de) {
1116 } catch (Exception e) {
1117 if (logger.isDebugEnabled()) {
1118 logger.debug("Caught exception ", e);
1120 throw new DocumentException(e);
1122 if (repoSession != null) {
1123 releaseRepositorySession(repoSession);
1132 * Gets the repository session. - Package access only.
1134 * @return the repository session
1135 * @throws Exception the exception
1137 public RepositoryInstance getRepositorySession() throws Exception {
1138 // FIXME: is it possible to reuse repository session?
1139 // Authentication failures happen while trying to reuse the session
1140 Profiler profiler = new Profiler("getRepositorySession():", 2);
1143 NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
1144 RepositoryInstance repoSession = client.openRepository();
1145 if (logger.isTraceEnabled()) {
1146 logger.trace("Testing call to getRepository() repository root: " + repoSession.getRootDocument());
1154 * Release repository session. - Package access only.
1156 * @param repoSession the repo session
1158 public void releaseRepositorySession(RepositoryInstance repoSession) {
1160 NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
1162 client.releaseRepository(repoSession);
1163 } catch (Exception e) {
1164 logger.error("Could not close the repository session", e);
1165 // no need to throw this service specific exception
1170 public void doWorkflowTransition(ServiceContext ctx, String id,
1171 DocumentHandler handler, TransitionDef transitionDef)
1172 throws BadRequestException, DocumentNotFoundException,
1174 // 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