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.UUID;
22 import java.util.List;
24 import org.collectionspace.services.common.context.ServiceContext;
26 import org.collectionspace.services.common.document.BadRequestException;
27 import org.collectionspace.services.common.document.DocumentException;
28 import org.collectionspace.services.common.document.DocumentFilter;
29 import org.collectionspace.services.common.document.DocumentHandler;
30 import org.collectionspace.services.common.document.DocumentNotFoundException;
31 import org.collectionspace.services.common.document.DocumentHandler.Action;
32 import org.collectionspace.services.common.document.DocumentWrapper;
33 import org.collectionspace.services.common.document.DocumentWrapperImpl;
35 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
36 import org.collectionspace.services.common.query.IQueryManager;
37 import org.collectionspace.services.common.repository.RepositoryClient;
38 import org.collectionspace.services.common.profile.Profiler;
40 import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
41 import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput;
42 import org.nuxeo.common.utils.IdUtils;
43 import org.nuxeo.ecm.core.api.ClientException;
44 import org.nuxeo.ecm.core.api.DocumentModel;
45 import org.nuxeo.ecm.core.api.DocumentModelList;
46 import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
47 import org.nuxeo.ecm.core.api.DocumentRef;
48 import org.nuxeo.ecm.core.api.IdRef;
49 import org.nuxeo.ecm.core.api.PathRef;
50 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
51 import org.nuxeo.ecm.core.client.NuxeoClient;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
57 * RepositoryJavaClient is used to perform CRUD operations on documents in Nuxeo
58 * repository using Remote Java APIs. It uses @see DocumentHandler as IOHandler
61 * $LastChangedRevision: $ $LastChangedDate: $
63 public class RepositoryJavaClientImpl implements RepositoryClient {
66 * The Class QueryContext.
68 private class QueryContext {
72 /** The doc filter. */
73 DocumentFilter docFilter;
74 /** The where clause. */
76 /** The order by clause. */
84 * Instantiates a new query context.
87 * @throws DocumentNotFoundException the document not found exception
88 * @throws DocumentException the document exception
90 QueryContext(ServiceContext<MultipartInput, MultipartOutput> ctx) throws DocumentNotFoundException, DocumentException {
91 docType = ctx.getDocumentType();
92 if (docType == null) {
93 throw new DocumentNotFoundException(
94 "Unable to find DocumentType for service " + ctx.getServiceName());
96 domain = ctx.getRepositoryDomainName();
98 throw new DocumentNotFoundException(
99 "Unable to find Domain for service " + ctx.getServiceName());
101 tenantId = ctx.getTenantId();
102 if (tenantId == null) {
103 throw new IllegalArgumentException(
104 "Service context has no Tenant ID specified.");
109 * Instantiates a new query context.
112 * @param theWhereClause the where clause
113 * @throws DocumentNotFoundException the document not found exception
114 * @throws DocumentException the document exception
116 QueryContext(ServiceContext<MultipartInput, MultipartOutput> ctx,
117 String theWhereClause) throws DocumentNotFoundException, DocumentException {
119 whereClause = theWhereClause;
123 * Instantiates a new query context.
126 * @param handler the handler
127 * @throws DocumentNotFoundException the document not found exception
128 * @throws DocumentException the document exception
130 QueryContext(ServiceContext<MultipartInput, MultipartOutput> ctx,
131 DocumentHandler handler) throws DocumentNotFoundException, DocumentException {
133 if (handler == null) {
134 throw new IllegalArgumentException(
135 "Document handler is missing.");
137 docFilter = handler.getDocumentFilter();
138 if (docFilter == null) {
139 throw new IllegalArgumentException(
140 "Document handler has no Filter specified.");
142 whereClause = docFilter.getWhereClause();
143 orderByClause = docFilter.getOrderByClause();
147 private final Logger logger = LoggerFactory.getLogger(RepositoryJavaClientImpl.class);
148 // private final Logger profilerLogger = LoggerFactory.getLogger("remperf");
149 // private String foo = Profiler.createLogger();
151 * Instantiates a new repository java client impl.
153 public RepositoryJavaClientImpl() {
159 * Sets the collection space core values.
162 * @param documentModel the document model
163 * @throws ClientException the client exception
165 private void setCollectionSpaceCoreValues(ServiceContext<MultipartInput, MultipartOutput> ctx,
166 DocumentModel documentModel,
167 Action action) throws ClientException {
169 // Add the tenant ID value to the new entity
171 documentModel.setProperty(DocumentModelHandler.COLLECTIONSPACE_CORE_SCHEMA,
172 DocumentModelHandler.COLLECTIONSPACE_CORE_TENANTID,
176 //add creation date value
186 * create document in the Nuxeo repository
188 * @param ctx service context under which this method is invoked
190 * of the document created
192 * should be used by the caller to provide and transform the
194 * @return id in repository of the newly created document
195 * @throws DocumentException
198 public String create(ServiceContext ctx,
199 DocumentHandler handler) throws BadRequestException,
202 if (ctx.getDocumentType() == null) {
203 throw new IllegalArgumentException(
204 "RepositoryJavaClient.create: docType is missing");
206 if (handler == null) {
207 throw new IllegalArgumentException(
208 "RepositoryJavaClient.create: handler is missing");
210 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
211 if (nuxeoWspaceId == null) {
212 throw new DocumentNotFoundException(
213 "Unable to find workspace for service " + ctx.getServiceName()
214 + " check if the workspace exists in the Nuxeo repository");
216 RepositoryInstance repoSession = null;
218 handler.prepare(Action.CREATE);
219 repoSession = getRepositorySession();
220 DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);
221 DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);
222 String wspacePath = wspaceDoc.getPathAsString();
223 //give our own ID so PathRef could be constructed later on
224 String id = IdUtils.generateId(UUID.randomUUID().toString());
225 // create document model
226 DocumentModel doc = repoSession.createDocumentModel(wspacePath, id,
227 ctx.getDocumentType());
228 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
229 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
230 handler.handle(Action.CREATE, wrapDoc);
231 // create document with documentmodel
232 setCollectionSpaceCoreValues(ctx, doc, Action.CREATE);
233 doc = repoSession.createDocument(doc);
235 // TODO for sub-docs need to call into the handler to let it deal with subitems. Pass in the id,
236 // and assume the handler has the state it needs (doc fragments).
237 handler.complete(Action.CREATE, wrapDoc);
239 } catch (BadRequestException bre) {
241 } catch (Exception e) {
242 if (logger.isDebugEnabled()) {
243 logger.debug("Caught exception ", e);
245 throw new DocumentException(e);
247 if (repoSession != null) {
248 releaseRepositorySession(repoSession);
255 * get document from the Nuxeo repository
256 * @param ctx service context under which this method is invoked
258 * of the document to retrieve
260 * should be used by the caller to provide and transform the
262 * @throws DocumentException
265 public void get(ServiceContext ctx, String id, DocumentHandler handler)
266 throws DocumentNotFoundException, DocumentException {
268 if (handler == null) {
269 throw new IllegalArgumentException(
270 "RepositoryJavaClient.get: handler is missing");
272 RepositoryInstance repoSession = null;
275 handler.prepare(Action.GET);
276 repoSession = getRepositorySession();
277 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
278 DocumentModel doc = null;
280 doc = repoSession.getDocument(docRef);
281 } catch (ClientException ce) {
282 String msg = "could not find document with id=" + id;
283 logger.error(msg, ce);
284 throw new DocumentNotFoundException(msg, ce);
286 //set reposession to handle the document
287 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
288 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
289 handler.handle(Action.GET, wrapDoc);
290 handler.complete(Action.GET, wrapDoc);
291 } catch (IllegalArgumentException iae) {
293 } catch (DocumentException de) {
295 } catch (Exception e) {
296 if (logger.isDebugEnabled()) {
297 logger.debug("Caught exception ", e);
299 throw new DocumentException(e);
301 if (repoSession != null) {
302 releaseRepositorySession(repoSession);
308 * get document from the Nuxeo repository, using the docFilter params.
309 * @param ctx service context under which this method is invoked
311 * should be used by the caller to provide and transform the
312 * document. Handler must have a docFilter set to return a single item.
313 * @throws DocumentException
316 public void get(ServiceContext ctx, DocumentHandler handler)
317 throws DocumentNotFoundException, DocumentException {
318 QueryContext queryContext = new QueryContext(ctx, handler);
319 RepositoryInstance repoSession = null;
322 handler.prepare(Action.GET);
323 repoSession = getRepositorySession();
325 DocumentModelList docList = null;
326 // force limit to 1, and ignore totalSize
327 String query = buildNXQLQuery(queryContext);
328 docList = repoSession.query(query, null, 1, 0, false);
329 if (docList.size() != 1) {
330 throw new DocumentNotFoundException("No document found matching filter params.");
332 DocumentModel doc = docList.get(0);
334 if (logger.isDebugEnabled()) {
335 logger.debug("Executed NXQL query: " + query);
338 //set reposession to handle the document
339 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
340 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
341 handler.handle(Action.GET, wrapDoc);
342 handler.complete(Action.GET, wrapDoc);
343 } catch (IllegalArgumentException iae) {
345 } catch (DocumentException de) {
347 } catch (Exception e) {
348 if (logger.isDebugEnabled()) {
349 logger.debug("Caught exception ", e);
351 throw new DocumentException(e);
353 if (repoSession != null) {
354 releaseRepositorySession(repoSession);
360 * get wrapped documentModel from the Nuxeo repository
361 * @param ctx service context under which this method is invoked
363 * of the document to retrieve
364 * @throws DocumentException
367 public DocumentWrapper<DocumentModel> getDoc(
368 ServiceContext ctx, String id)
369 throws DocumentNotFoundException, DocumentException {
370 RepositoryInstance repoSession = null;
371 DocumentWrapper<DocumentModel> wrapDoc = null;
374 repoSession = getRepositorySession();
375 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
376 DocumentModel doc = null;
378 doc = repoSession.getDocument(docRef);
379 } catch (ClientException ce) {
380 String msg = "could not find document with id=" + id;
381 logger.error(msg, ce);
382 throw new DocumentNotFoundException(msg, ce);
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);
395 if (repoSession != null) {
396 releaseRepositorySession(repoSession);
403 * find wrapped documentModel from the Nuxeo repository
404 * @param ctx service context under which this method is invoked
405 * @param where NXQL where clause to get the document
406 * @throws DocumentException
409 public DocumentWrapper<DocumentModel> findDoc(
410 ServiceContext ctx, String whereClause)
411 throws DocumentNotFoundException, DocumentException {
412 RepositoryInstance repoSession = null;
413 DocumentWrapper<DocumentModel> wrapDoc = null;
416 QueryContext queryContext = new QueryContext(ctx, whereClause);
417 repoSession = getRepositorySession();
418 DocumentModelList docList = null;
419 // force limit to 1, and ignore totalSize
420 String query = buildNXQLQuery(queryContext);
421 docList = repoSession.query(query,
426 if (docList.size() != 1) {
427 if (logger.isDebugEnabled()) {
428 logger.debug("findDoc: Query found: " + docList.size() + " items.");
429 logger.debug(" Query: " + query);
431 throw new DocumentNotFoundException("No document found matching filter params.");
433 DocumentModel doc = docList.get(0);
434 wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
435 } catch (IllegalArgumentException iae) {
437 } catch (DocumentException de) {
439 } catch (Exception e) {
440 if (logger.isDebugEnabled()) {
441 logger.debug("Caught exception ", e);
443 throw new DocumentException(e);
445 if (repoSession != null) {
446 releaseRepositorySession(repoSession);
453 * find doc and return CSID from the Nuxeo repository
454 * @param ctx service context under which this method is invoked
455 * @param where NXQL where clause to get the document
456 * @throws DocumentException
459 public String findDocCSID(
460 ServiceContext ctx, String whereClause)
461 throws DocumentNotFoundException, DocumentException {
464 DocumentWrapper<DocumentModel> wrapDoc = findDoc(ctx, whereClause);
465 DocumentModel docModel = wrapDoc.getWrappedObject();
466 csid = NuxeoUtils.extractId(docModel.getPathAsString());
467 } catch (DocumentNotFoundException dnfe) {
469 } catch (IllegalArgumentException iae) {
471 } catch (DocumentException de) {
473 } catch (Exception e) {
474 if (logger.isDebugEnabled()) {
475 logger.debug("Caught exception ", e);
477 throw new DocumentException(e);
483 * Find a list of documentModels from the Nuxeo repository
484 * @param docTypes a list of DocType names to match
485 * @param where the clause to qualify on
486 * @param domain the domain for the associated services
490 public DocumentWrapper<DocumentModelList> findDocs(
492 List<String> docTypes,
494 int pageSize, int pageNum, boolean computeTotal)
495 throws DocumentNotFoundException, DocumentException {
496 RepositoryInstance repoSession = null;
497 DocumentWrapper<DocumentModelList> wrapDoc = null;
500 if (docTypes == null || docTypes.size() < 1) {
501 throw new DocumentNotFoundException(
502 "findDocs must specify at least one DocumentType.");
504 repoSession = getRepositorySession();
505 DocumentModelList docList = null;
506 // force limit to 1, and ignore totalSize
507 QueryContext queryContext = new QueryContext(ctx, whereClause);
508 String query = buildNXQLQuery(docTypes, queryContext);
509 docList = repoSession.query(query, null, pageSize, pageNum, computeTotal);
510 wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
511 } catch (IllegalArgumentException iae) {
513 } catch (Exception e) {
514 if (logger.isDebugEnabled()) {
515 logger.debug("Caught exception ", e);
517 throw new DocumentException(e);
519 if (repoSession != null) {
520 releaseRepositorySession(repoSession);
527 * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.util.List, org.collectionspace.services.common.document.DocumentHandler)
530 public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
531 throws DocumentNotFoundException, DocumentException {
532 if (handler == null) {
533 throw new IllegalArgumentException(
534 "RepositoryJavaClient.getAll: handler is missing");
537 RepositoryInstance repoSession = null;
540 handler.prepare(Action.GET_ALL);
541 repoSession = getRepositorySession();
542 DocumentModelList docModelList = new DocumentModelListImpl();
543 //FIXME: Should be using NuxeoUtils.createPathRef for security reasons
544 for (String csid : csidList) {
545 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
546 DocumentModel docModel = repoSession.getDocument(docRef);
547 docModelList.add(docModel);
550 //set reposession to handle the document
551 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
552 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docModelList);
553 handler.handle(Action.GET_ALL, wrapDoc);
554 handler.complete(Action.GET_ALL, wrapDoc);
555 } catch (DocumentException de) {
557 } catch (Exception e) {
558 if (logger.isDebugEnabled()) {
559 logger.debug("Caught exception ", e);
561 throw new DocumentException(e);
563 if (repoSession != null) {
564 releaseRepositorySession(repoSession);
570 * getAll get all documents for an entity entity service from the Nuxeo
573 * @param ctx service context under which this method is invoked
575 * should be used by the caller to provide and transform the
577 * @throws DocumentException
580 public void getAll(ServiceContext ctx, DocumentHandler handler)
581 throws DocumentNotFoundException, DocumentException {
582 if (handler == null) {
583 throw new IllegalArgumentException(
584 "RepositoryJavaClient.getAll: handler is missing");
586 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
587 if (nuxeoWspaceId == null) {
588 throw new DocumentNotFoundException(
589 "Unable to find workspace for service "
590 + ctx.getServiceName()
591 + " check if the workspace exists in the Nuxeo repository");
593 RepositoryInstance repoSession = null;
596 handler.prepare(Action.GET_ALL);
597 repoSession = getRepositorySession();
598 DocumentRef wsDocRef = new IdRef(nuxeoWspaceId);
599 DocumentModelList docList = repoSession.getChildren(wsDocRef);
600 //set reposession to handle the document
601 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
602 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
603 handler.handle(Action.GET_ALL, wrapDoc);
604 handler.complete(Action.GET_ALL, wrapDoc);
605 } catch (DocumentException de) {
607 } catch (Exception e) {
608 if (logger.isDebugEnabled()) {
609 logger.debug("Caught exception ", e);
611 throw new DocumentException(e);
613 if (repoSession != null) {
614 releaseRepositorySession(repoSession);
620 * getFiltered get all documents for an entity service from the Document repository,
621 * given filter parameters specified by the handler.
622 * @param ctx service context under which this method is invoked
623 * @param handler should be used by the caller to provide and transform the document
624 * @throws DocumentNotFoundException if workspace not found
625 * @throws DocumentException
628 public void getFiltered(ServiceContext ctx, DocumentHandler handler)
629 throws DocumentNotFoundException, DocumentException {
631 QueryContext queryContext = new QueryContext(ctx, handler);
633 RepositoryInstance repoSession = null;
635 handler.prepare(Action.GET_ALL);
636 repoSession = getRepositorySession();
637 DocumentModelList docList = null;
638 String query = buildNXQLQuery(queryContext);
640 if (logger.isDebugEnabled()) {
641 logger.debug("Executing NXQL query: " + query.toString());
644 // If we have limit and/or offset, then pass true to get totalSize
645 // in returned DocumentModelList.
646 Profiler profiler = new Profiler(this, 2);
647 profiler.log("Executing NXQL query: " + query.toString());
649 if ((queryContext.docFilter.getOffset() > 0) || (queryContext.docFilter.getPageSize() > 0)) {
650 docList = repoSession.query(query, null,
651 queryContext.docFilter.getPageSize(), queryContext.docFilter.getOffset(), true);
653 docList = repoSession.query(query);
657 //set repoSession to handle the document
658 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
659 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
660 handler.handle(Action.GET_ALL, wrapDoc);
661 handler.complete(Action.GET_ALL, wrapDoc);
662 } catch (DocumentException de) {
664 } catch (Exception e) {
665 if (logger.isDebugEnabled()) {
666 logger.debug("Caught exception ", e);
668 throw new DocumentException(e);
670 if (repoSession != null) {
671 releaseRepositorySession(repoSession);
677 * update given document in the Nuxeo repository
679 * @param ctx service context under which this method is invoked
683 * should be used by the caller to provide and transform the
685 * @throws DocumentException
688 public void update(ServiceContext ctx, String id, DocumentHandler handler)
689 throws BadRequestException, DocumentNotFoundException,
691 if (handler == null) {
692 throw new IllegalArgumentException(
693 "RepositoryJavaClient.update: handler is missing");
695 RepositoryInstance repoSession = null;
697 handler.prepare(Action.UPDATE);
698 repoSession = getRepositorySession();
699 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
700 DocumentModel doc = null;
702 doc = repoSession.getDocument(docRef);
703 } catch (ClientException ce) {
704 String msg = "Could not find document to update with id=" + id;
705 logger.error(msg, ce);
706 throw new DocumentNotFoundException(msg, ce);
708 //set reposession to handle the document
709 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
710 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
711 handler.handle(Action.UPDATE, wrapDoc);
712 setCollectionSpaceCoreValues(ctx, doc, Action.CREATE);
713 repoSession.saveDocument(doc);
715 handler.complete(Action.UPDATE, wrapDoc);
716 } catch (BadRequestException bre) {
718 } catch (DocumentException de) {
720 } catch (Exception e) {
721 if (logger.isDebugEnabled()) {
722 logger.debug("Caught exception ", e);
724 throw new DocumentException(e);
726 if (repoSession != null) {
727 releaseRepositorySession(repoSession);
733 * delete a document from the Nuxeo repository
734 * @param ctx service context under which this method is invoked
737 * @throws DocumentException
740 public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException,
743 if (logger.isDebugEnabled()) {
744 logger.debug("deleting document with id=" + id);
746 RepositoryInstance repoSession = null;
748 repoSession = getRepositorySession();
749 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
751 repoSession.removeDocument(docRef);
752 } catch (ClientException ce) {
753 String msg = "could not find document to delete with id=" + id;
754 logger.error(msg, ce);
755 throw new DocumentNotFoundException(msg, ce);
758 } catch (DocumentException de) {
760 } catch (Exception e) {
761 if (logger.isDebugEnabled()) {
762 logger.debug("Caught exception ", e);
764 throw new DocumentException(e);
766 if (repoSession != null) {
767 releaseRepositorySession(repoSession);
773 * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
776 public void delete(ServiceContext ctx, String id, DocumentHandler handler)
777 throws DocumentNotFoundException, DocumentException {
778 throw new UnsupportedOperationException();
782 public Hashtable<String, String> retrieveWorkspaceIds(String domainName) throws Exception {
783 return NuxeoConnector.getInstance().retrieveWorkspaceIds(domainName);
787 public String createDomain(String domainName) throws Exception {
788 RepositoryInstance repoSession = null;
789 String domainId = null;
791 repoSession = getRepositorySession();
792 DocumentRef parentDocRef = new PathRef("/");
793 DocumentModel parentDoc = repoSession.getDocument(parentDocRef);
794 DocumentModel doc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
795 domainName, "Domain");
796 doc.setPropertyValue("dc:title", domainName);
797 doc.setPropertyValue("dc:description", "A CollectionSpace domain "
799 doc = repoSession.createDocument(doc);
800 domainId = doc.getId();
802 if (logger.isDebugEnabled()) {
803 logger.debug("created tenant domain name=" + domainName
804 + " id=" + domainId);
806 } catch (Exception e) {
807 if (logger.isDebugEnabled()) {
808 logger.debug("createTenantSpace caught exception ", e);
812 if (repoSession != null) {
813 releaseRepositorySession(repoSession);
820 public String getDomainId(String domainName) throws Exception {
821 String domainId = null;
822 RepositoryInstance repoSession = null;
824 repoSession = getRepositorySession();
825 DocumentRef docRef = new PathRef(
827 DocumentModel domain = repoSession.getDocument(docRef);
828 domainId = domain.getId();
829 } catch (Exception e) {
830 if (logger.isDebugEnabled()) {
831 logger.debug("Caught exception ", e);
833 //there is no way to identify if document does not exist due to
834 //lack of typed exception for getDocument method
837 if (repoSession != null) {
838 releaseRepositorySession(repoSession);
845 * @see org.collectionspace.services.common.repository.RepositoryClient#createWorkspace(java.lang.String, java.lang.String)
848 public String createWorkspace(String domainName, String workspaceName) throws Exception {
849 RepositoryInstance repoSession = null;
850 String workspaceId = null;
852 repoSession = getRepositorySession();
853 DocumentRef parentDocRef = new PathRef(
855 + "/" + "workspaces");
856 DocumentModel parentDoc = repoSession.getDocument(parentDocRef);
857 DocumentModel doc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
858 workspaceName, "Workspace");
859 doc.setPropertyValue("dc:title", workspaceName);
860 doc.setPropertyValue("dc:description", "A CollectionSpace workspace for "
862 doc = repoSession.createDocument(doc);
863 workspaceId = doc.getId();
865 if (logger.isDebugEnabled()) {
866 logger.debug("created workspace name=" + workspaceName
867 + " id=" + workspaceId);
869 } catch (Exception e) {
870 if (logger.isDebugEnabled()) {
871 logger.debug("createWorkspace caught exception ", e);
875 if (repoSession != null) {
876 releaseRepositorySession(repoSession);
883 * @see org.collectionspace.services.common.repository.RepositoryClient#getWorkspaceId(java.lang.String, java.lang.String)
886 public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
887 String workspaceId = null;
888 RepositoryInstance repoSession = null;
890 repoSession = getRepositorySession();
891 DocumentRef docRef = new PathRef(
894 + "/" + workspaceName);
895 DocumentModel workspace = repoSession.getDocument(docRef);
896 workspaceId = workspace.getId();
897 } catch (DocumentException de) {
899 } catch (Exception e) {
900 if (logger.isDebugEnabled()) {
901 logger.debug("Caught exception ", e);
903 throw new DocumentException(e);
905 if (repoSession != null) {
906 releaseRepositorySession(repoSession);
913 * Append a WHERE clause to the NXQL query.
915 * @param query The NXQL query to which the WHERE clause will be appended.
916 * @param querycontext The query context, which provides the WHERE clause to append.
918 private final void appendNXQLWhere(StringBuilder query, QueryContext queryContext) {
920 // Restrict search to a specific Nuxeo domain
921 // TODO This is a slow method for tenant-filter
922 // We should make this a property that is indexed.
924 // query.append(" WHERE ecm:path STARTSWITH '/" + queryContext.domain + "'");
927 // Restrict search to the current tenant ID. Is the domain path filter (above) still needed?
929 query.append(/*IQueryManager.SEARCH_QUALIFIER_AND +*/ " WHERE " + DocumentModelHandler.COLLECTIONSPACE_CORE_SCHEMA + ":"
930 + DocumentModelHandler.COLLECTIONSPACE_CORE_TENANTID
931 + " = " + queryContext.tenantId);
933 // Finally, append the incoming where clause
935 String whereClause = queryContext.whereClause;
936 if (whereClause != null && ! whereClause.trim().isEmpty()) {
937 // Due to an apparent bug/issue in how Nuxeo translates the NXQL query string
938 // into SQL, we need to parenthesize our 'where' clause
939 query.append(IQueryManager.SEARCH_QUALIFIER_AND + "(" + whereClause + ")");
942 // Please lookup this use in Nuxeo support and document here
944 query.append(IQueryManager.SEARCH_QUALIFIER_AND + "ecm:isProxy = 0");
948 * Append an ORDER BY clause to the NXQL query.
950 * @param query The NXQL query to which the ORDER BY clause will be appended.
951 * @param querycontext The query context, which provides the ORDER BY clause to append.
953 private final void appendNXQLOrderBy(StringBuilder query, QueryContext queryContext) {
954 // Append the incoming ORDER BY clause
955 String orderByClause = queryContext.orderByClause;
956 if (orderByClause != null && ! orderByClause.trim().isEmpty()) {
957 // FIXME Verify whether enclosing parentheses may be required, and add
958 // them if so, as is being done in appendNXQLWhere.
959 query.append(" ORDER BY ");
960 query.append(orderByClause);
963 // FIXME Determine where and how to handle ASC[ending] and DESC[ending] qualifiers:
965 // Will these be included in the value of the relevant 'order by' query param?
967 // Will the format of the order by clause be verified, including placement of
968 // the 'order by' qualifiers?
973 * Builds an NXQL SELECT query for a single document type.
975 * @param queryContext The query context
976 * @return an NXQL query
978 private final String buildNXQLQuery(QueryContext queryContext) {
979 StringBuilder query = new StringBuilder("SELECT * FROM ");
980 query.append(queryContext.docType);
981 appendNXQLWhere(query, queryContext);
982 appendNXQLOrderBy(query, queryContext);
983 return query.toString();
987 * Builds an NXQL SELECT query across multiple document types.
989 * @param docTypes a list of document types to be queried
990 * @param queryContext the query context
991 * @return an NXQL query
993 private final String buildNXQLQuery(List<String> docTypes, QueryContext queryContext) {
994 StringBuilder query = new StringBuilder("SELECT * FROM ");
995 boolean fFirst = true;
996 for (String docType : docTypes) {
1002 query.append(docType);
1004 appendNXQLWhere(query, queryContext);
1005 // FIXME add 'order by' clause here, if appropriate
1006 return query.toString();
1010 * Gets the repository session.
1012 * @return the repository session
1013 * @throws Exception the exception
1015 private RepositoryInstance getRepositorySession() throws Exception {
1016 // FIXME: is it possible to reuse repository session?
1017 // Authentication failures happen while trying to reuse the session
1018 Profiler profiler = new Profiler("getRepositorySession():", 2);
1020 NuxeoClient client = NuxeoConnector.getInstance().getClient();
1021 RepositoryInstance repoSession = client.openRepository();
1022 if (logger.isTraceEnabled()) {
1023 logger.debug("getRepository() repository root: " + repoSession.getRootDocument());
1030 * Release repository session.
1032 * @param repoSession the repo session
1034 private void releaseRepositorySession(RepositoryInstance repoSession) {
1036 NuxeoClient client = NuxeoConnector.getInstance().getClient();
1038 client.releaseRepository(repoSession);
1039 } catch (Exception e) {
1040 logger.error("Could not close the repository session", e);
1041 // no need to throw this service specific exception