]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
d56bc4749ce2f036c4852d364cd2575c0c1a2f2d
[tmp/jakarta-migration.git] /
1 /**
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:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17  */
18 package org.collectionspace.services.nuxeo.client.java;
19
20 import java.io.Serializable;
21 import java.util.Hashtable;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.UUID;
26
27 import javax.ws.rs.WebApplicationException;
28 import javax.ws.rs.core.MultivaluedMap;
29
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;
41
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;
50
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;
61
62 //
63 // CSPACE-5036 - How to make CMISQL queries from Nuxeo
64 //
65 import org.apache.chemistry.opencmis.commons.server.CallContext;
66 import org.apache.chemistry.opencmis.server.impl.CallContextImpl;
67 import org.apache.chemistry.opencmis.server.support.query.CmisQlExtParser_CmisBaseGrammar.boolean_factor_return;
68 import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoCmisService;
69 import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoRepository;
70
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 /**
75  * RepositoryJavaClient is used to perform CRUD operations on documents in Nuxeo
76  * repository using Remote Java APIs. It uses @see DocumentHandler as IOHandler
77  * with the client.
78  * 
79  * $LastChangedRevision: $ $LastChangedDate: $
80  */
81 public class RepositoryJavaClientImpl implements RepositoryClient<PoxPayloadIn, PoxPayloadOut> {
82
83     /** The logger. */
84     private final Logger logger = LoggerFactory.getLogger(RepositoryJavaClientImpl.class);
85 //    private final Logger profilerLogger = LoggerFactory.getLogger("remperf");
86 //    private String foo = Profiler.createLogger();
87
88     public static final String NUXEO_CORE_TYPE_DOMAIN = "Domain";
89     public static final String NUXEO_CORE_TYPE_WORKSPACEROOT = "WorkspaceRoot";
90     
91     /**
92      * Instantiates a new repository java client impl.
93      */
94     public RepositoryJavaClientImpl() {
95         //Empty constructor
96         
97     }
98
99     public void assertWorkflowState(ServiceContext ctx,
100                 DocumentModel docModel) throws DocumentNotFoundException, ClientException {
101         MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
102         if (queryParams != null) {
103                 //
104                 // Look for the workflow "delete" query param and see if we need to assert that the
105                 // docModel is in a non-deleted workflow state.
106                 //
107                 String currentState = docModel.getCurrentLifeCycleState();
108                 String includeDeletedStr = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_NONDELETED);
109                 boolean includeDeleted = includeDeletedStr == null ? true : Boolean.parseBoolean(includeDeletedStr);
110                 if (includeDeleted == false) {
111                         //
112                         // We don't wanted soft-deleted object, so throw an exception if this one is soft-deleted.
113                         //
114                         if (currentState.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_DELETED)) {
115                                 String msg = "The GET assertion that docModel not be in 'deleted' workflow state failed.";
116                                 logger.debug(msg);
117                                 throw new DocumentNotFoundException(msg);
118                         }
119                 }
120         }
121     }
122     
123     /**
124      * create document in the Nuxeo repository
125      *
126      * @param ctx service context under which this method is invoked
127      * @param handler
128      *            should be used by the caller to provide and transform the
129      *            document
130      * @return id in repository of the newly created document
131      * @throws DocumentException
132      */
133     @Override
134     public String create(ServiceContext ctx,
135             DocumentHandler handler) throws BadRequestException,
136             DocumentException {
137
138         String docType = NuxeoUtils.getTenantQualifiedDocType(ctx); //ctx.getDocumentType();
139         if (docType == null) {
140             throw new IllegalArgumentException(
141                     "RepositoryJavaClient.create: docType is missing");
142         }
143         
144         if (handler == null) {
145             throw new IllegalArgumentException(
146                     "RepositoryJavaClient.create: handler is missing");
147         }
148         String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
149         if (nuxeoWspaceId == null) {
150             throw new DocumentNotFoundException(
151                     "Unable to find workspace for service " + ctx.getServiceName()
152                     + " check if the workspace exists in the Nuxeo repository");
153         }
154         
155         RepositoryInstance repoSession = null;
156         try {
157             handler.prepare(Action.CREATE);
158             repoSession = getRepositorySession(ctx);
159             DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);
160             DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);
161             String wspacePath = wspaceDoc.getPathAsString();
162             //give our own ID so PathRef could be constructed later on
163             String id = IdUtils.generateId(UUID.randomUUID().toString());
164             // create document model
165             DocumentModel doc = repoSession.createDocumentModel(wspacePath, id, docType);
166             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
167             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
168             handler.handle(Action.CREATE, wrapDoc);
169             // create document with documentmodel
170             doc = repoSession.createDocument(doc);
171             repoSession.save();
172 // TODO for sub-docs need to call into the handler to let it deal with subitems. Pass in the id,
173 // and assume the handler has the state it needs (doc fragments). 
174             handler.complete(Action.CREATE, wrapDoc);
175             return id;
176         } catch (BadRequestException bre) {
177             throw bre;
178         } catch (Exception e) {
179                 logger.error("Caught exception ", e);
180             throw new DocumentException(e);
181         } finally {
182             if (repoSession != null) {
183                 releaseRepositorySession(ctx, repoSession);
184             }
185         }
186
187     }
188
189     /**
190      * get document from the Nuxeo repository
191      * @param ctx service context under which this method is invoked
192      * @param id
193      *            of the document to retrieve
194      * @param handler
195      *            should be used by the caller to provide and transform the
196      *            document
197      * @throws DocumentException
198      */
199     @Override
200     public void get(ServiceContext ctx, String id, DocumentHandler handler)
201             throws DocumentNotFoundException, DocumentException {
202
203         if (handler == null) {
204             throw new IllegalArgumentException(
205                     "RepositoryJavaClient.get: handler is missing");
206         }
207         
208         RepositoryInstance repoSession = null;
209         try {
210             handler.prepare(Action.GET);
211             repoSession = getRepositorySession(ctx);
212             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
213             DocumentModel docModel = null;
214             try {
215                 docModel = repoSession.getDocument(docRef);
216                 assertWorkflowState(ctx, docModel);
217             } catch (ClientException ce) {
218                 String msg = logException(ce, "Could not find document with CSID=" + id);
219                 throw new DocumentNotFoundException(msg, ce);
220             }
221             //
222             // Set repository session to handle the document
223             //
224             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
225             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(docModel);
226             handler.handle(Action.GET, wrapDoc);
227             handler.complete(Action.GET, wrapDoc);
228         } catch (IllegalArgumentException iae) {
229             throw iae;
230         } catch (DocumentException de) {
231             throw de;
232         } catch (Exception e) {
233             if (logger.isDebugEnabled()) {
234                 logger.debug("Caught exception ", e);
235             }
236             throw new DocumentException(e);
237         } finally {
238             if (repoSession != null) {
239                 releaseRepositorySession(ctx, repoSession);
240             }
241         }
242     }
243
244     /**
245      * get document from the Nuxeo repository, using the docFilter params.
246      * @param ctx service context under which this method is invoked
247      * @param handler
248      *            should be used by the caller to provide and transform the
249      *            document. Handler must have a docFilter set to return a single item.
250      * @throws DocumentException
251      */
252     @Override
253     public void get(ServiceContext ctx, DocumentHandler handler)
254             throws DocumentNotFoundException, DocumentException {
255         QueryContext queryContext = new QueryContext(ctx, handler);
256         RepositoryInstance repoSession = null;
257
258         try {
259             handler.prepare(Action.GET);
260             repoSession = getRepositorySession(ctx);
261
262             DocumentModelList docList = null;
263             // force limit to 1, and ignore totalSize
264             String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
265             docList = repoSession.query(query, null, 1, 0, false);
266             if (docList.size() != 1) {
267                 throw new DocumentNotFoundException("No document found matching filter params: " + query);
268             }
269             DocumentModel doc = docList.get(0);
270
271             if (logger.isDebugEnabled()) {
272                 logger.debug("Executed NXQL query: " + query);
273             }
274
275             //set reposession to handle the document
276             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
277             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
278             handler.handle(Action.GET, wrapDoc);
279             handler.complete(Action.GET, wrapDoc);
280         } catch (IllegalArgumentException iae) {
281             throw iae;
282         } catch (DocumentException de) {
283             throw de;
284         } catch (Exception e) {
285             if (logger.isDebugEnabled()) {
286                 logger.debug("Caught exception ", e);
287             }
288             throw new DocumentException(e);
289         } finally {
290             if (repoSession != null) {
291                 releaseRepositorySession(ctx, repoSession);
292             }
293         }
294     }
295     
296     public DocumentWrapper<DocumentModel> getDoc(
297                 RepositoryInstance repoSession,
298             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
299             String csid) throws DocumentNotFoundException, DocumentException {
300         DocumentWrapper<DocumentModel> wrapDoc = null;
301
302         try {
303             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
304             DocumentModel doc = null;
305             try {
306                 doc = repoSession.getDocument(docRef);
307             } catch (ClientException ce) {
308                 String msg = logException(ce, "Could not find document with CSID=" + csid);
309                 throw new DocumentNotFoundException(msg, ce);
310             }
311             wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
312         } catch (IllegalArgumentException iae) {
313             throw iae;
314         } catch (DocumentException de) {
315             throw de;
316         }
317
318         return wrapDoc;
319     }
320     
321     /**
322      * Get wrapped documentModel from the Nuxeo repository.  The search is restricted to the workspace
323      * of the current context.
324      * 
325      * @param ctx service context under which this method is invoked
326      * @param id
327      *            of the document to retrieve
328      * @throws DocumentException
329      */
330     @Override
331     public DocumentWrapper<DocumentModel> getDoc(
332             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
333             String csid) throws DocumentNotFoundException, DocumentException {
334         RepositoryInstance repoSession = null;
335         DocumentWrapper<DocumentModel> wrapDoc = null;
336
337         try {
338                 // Open a new repository session
339             repoSession = getRepositorySession(ctx);
340             wrapDoc = getDoc(repoSession, ctx, csid);
341         } catch (IllegalArgumentException iae) {
342             throw iae;
343         } catch (DocumentException de) {
344             throw de;
345         } catch (Exception e) {
346             if (logger.isDebugEnabled()) {
347                 logger.debug("Caught exception ", e);
348             }
349             throw new DocumentException(e);
350         } finally {
351             if (repoSession != null) {
352                 releaseRepositorySession(ctx, repoSession);
353             }
354         }
355         
356         if (logger.isWarnEnabled() == true) {
357                 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
358         }
359         return wrapDoc;
360     }
361
362     public DocumentWrapper<DocumentModel> findDoc(
363             RepositoryInstance repoSession,
364             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
365             String whereClause)
366             throws DocumentNotFoundException, DocumentException {
367         DocumentWrapper<DocumentModel> wrapDoc = null;
368
369         try {
370             QueryContext queryContext = new QueryContext(ctx, whereClause);
371             DocumentModelList docList = null;
372             // force limit to 1, and ignore totalSize
373             String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
374             docList = repoSession.query(query,
375                     null, //Filter
376                     1, //limit
377                     0, //offset
378                     false); //countTotal
379             if (docList.size() != 1) {
380                 if (logger.isDebugEnabled()) {
381                     logger.debug("findDoc: Query found: " + docList.size() + " items.");
382                     logger.debug(" Query: " + query);
383                 }
384                 throw new DocumentNotFoundException("No document found matching filter params: " + query);
385             }
386             DocumentModel doc = docList.get(0);
387             wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
388         } catch (IllegalArgumentException iae) {
389             throw iae;
390         } catch (DocumentException de) {
391             throw de;
392         } catch (Exception e) {
393             if (logger.isDebugEnabled()) {
394                 logger.debug("Caught exception ", e);
395             }
396             throw new DocumentException(e);
397         }
398         
399         return wrapDoc;
400     }
401     
402     /**
403      * find wrapped documentModel from the Nuxeo repository
404      * @param ctx service context under which this method is invoked
405      * @param whereClause where NXQL where clause to get the document
406      * @throws DocumentException
407      */
408     @Override
409     public DocumentWrapper<DocumentModel> findDoc(
410             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
411             String whereClause)
412                         throws DocumentNotFoundException, DocumentException {
413         RepositoryInstance repoSession = null;
414         DocumentWrapper<DocumentModel> wrapDoc = null;
415
416         try {
417             repoSession = getRepositorySession(ctx);
418             wrapDoc = findDoc(repoSession, ctx, whereClause);
419         } catch (Exception e) {
420                         throw new DocumentException("Unable to create a Nuxeo repository session.", e);
421                 } finally {
422             if (repoSession != null) {
423                 releaseRepositorySession(ctx, repoSession);
424             }
425         }
426         
427         if (logger.isWarnEnabled() == true) {
428                 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
429         }
430         
431         return wrapDoc;
432     }
433
434     /**
435      * find doc and return CSID from the Nuxeo repository
436      * @param ctx service context under which this method is invoked
437      * @param whereClause where NXQL where clause to get the document
438      * @throws DocumentException
439      */
440     @Override
441     public String findDocCSID(RepositoryInstance repoSession, 
442             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String whereClause)
443             throws DocumentNotFoundException, DocumentException {
444         String csid = null;
445         boolean releaseSession = false;
446         try {
447                 if (repoSession == null) {
448                         repoSession = this.getRepositorySession(ctx);
449                         releaseSession = true;
450                 }
451             DocumentWrapper<DocumentModel> wrapDoc = findDoc(repoSession, ctx, whereClause);
452             DocumentModel docModel = wrapDoc.getWrappedObject();
453             csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
454         } catch (DocumentNotFoundException dnfe) {
455             throw dnfe;
456         } catch (IllegalArgumentException iae) {
457             throw iae;
458         } catch (DocumentException de) {
459             throw de;
460         } catch (Exception e) {
461             if (logger.isDebugEnabled()) {
462                 logger.debug("Caught exception ", e);
463             }
464             throw new DocumentException(e);
465         } finally {
466                 if(releaseSession && (repoSession != null)) {
467                         this.releaseRepositorySession(ctx, repoSession);
468                 }
469         }
470         return csid;
471     }
472
473     public DocumentWrapper<DocumentModelList> findDocs(
474             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
475             RepositoryInstance repoSession,
476             List<String> docTypes,
477             String whereClause,
478             String orderByClause,
479             int pageSize,
480             int pageNum,
481             boolean computeTotal)
482                         throws DocumentNotFoundException, DocumentException {
483         DocumentWrapper<DocumentModelList> wrapDoc = null;
484
485         try {
486             if (docTypes == null || docTypes.size() < 1) {
487                 throw new DocumentNotFoundException(
488                         "The findDocs() method must specify at least one DocumentType.");
489             }
490             DocumentModelList docList = null;
491             QueryContext queryContext = new QueryContext(ctx, whereClause, orderByClause);
492             String query = NuxeoUtils.buildNXQLQuery(docTypes, queryContext);
493             if (logger.isDebugEnabled()) {
494                 logger.debug("findDocs() NXQL: "+query);
495             }
496             docList = repoSession.query(query, null, pageSize, pageSize*pageNum, computeTotal);
497             wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
498         } catch (IllegalArgumentException iae) {
499             throw iae;
500         } catch (Exception e) {
501             if (logger.isDebugEnabled()) {
502                 logger.debug("Caught exception ", e);
503             }
504             throw new DocumentException(e);
505         }
506                 
507         return wrapDoc;
508     }
509     
510     protected static String buildInListForDocTypes(List<String> docTypes) {
511         StringBuilder sb = new StringBuilder();
512         sb.append("(");
513         boolean first = true;
514         for(String docType:docTypes) {
515                 if(first) {
516                         first = false;
517                 } else {
518                         sb.append(",");
519                 }
520                         sb.append("'");
521                 sb.append(docType);
522                         sb.append("'");
523         }
524         sb.append(")");
525         return sb.toString();
526     }
527     
528     public DocumentWrapper<DocumentModelList> findDocs(
529             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
530             DocumentHandler handler,
531             RepositoryInstance repoSession,
532             List<String> docTypes)
533                         throws DocumentNotFoundException, DocumentException {
534         DocumentWrapper<DocumentModelList> wrapDoc = null;
535
536         DocumentFilter filter = handler.getDocumentFilter();
537         String oldOrderBy = filter.getOrderByClause();
538         if (isClauseEmpty(oldOrderBy) == true){
539             filter.setOrderByClause(DocumentFilter.ORDER_BY_LAST_UPDATED);
540         }
541         QueryContext queryContext = new QueryContext(ctx, handler);
542
543         try {
544             if (docTypes == null || docTypes.size() < 1) {
545                 throw new DocumentNotFoundException(
546                         "The findDocs() method must specify at least one DocumentType.");
547             }
548             DocumentModelList docList = null;
549                 if (handler.isCMISQuery() == true) {
550                         String inList = buildInListForDocTypes(docTypes);
551                         ctx.getQueryParams().add(IQueryManager.SEARCH_RELATED_MATCH_OBJ_DOCTYPES, inList);
552                         docList = getFilteredCMIS(repoSession, ctx, handler, queryContext);
553             } else {
554                 String query = NuxeoUtils.buildNXQLQuery(docTypes, queryContext);
555                 if (logger.isDebugEnabled()) {
556                     logger.debug("findDocs() NXQL: "+query);
557                 }
558                 docList = repoSession.query(query, null, filter.getPageSize(), filter.getOffset(), true);
559             }
560             wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
561         } catch (IllegalArgumentException iae) {
562             throw iae;
563         } catch (Exception e) {
564             if (logger.isDebugEnabled()) {
565                 logger.debug("Caught exception ", e);
566             }
567             throw new DocumentException(e);
568         }
569                 
570         return wrapDoc;
571     }
572     
573
574     
575     /**
576      * Find a list of documentModels from the Nuxeo repository
577      * @param docTypes a list of DocType names to match
578      * @param  whereClause where the clause to qualify on
579      * @return
580      */
581     @Override
582     public DocumentWrapper<DocumentModelList> findDocs(
583             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
584             List<String> docTypes,
585             String whereClause,
586             int pageSize, int pageNum, boolean computeTotal)
587             throws DocumentNotFoundException, DocumentException {
588         RepositoryInstance repoSession = null;
589         DocumentWrapper<DocumentModelList> wrapDoc = null;
590
591         try {
592             repoSession = getRepositorySession(ctx);
593             wrapDoc = findDocs(ctx, repoSession, docTypes, whereClause, null,
594                         pageSize, pageNum, computeTotal);
595         } catch (IllegalArgumentException iae) {
596             throw iae;
597         } catch (Exception e) {
598             if (logger.isDebugEnabled()) {
599                 logger.debug("Caught exception ", e);
600             }
601             throw new DocumentException(e);
602         } finally {
603             if (repoSession != null) {
604                 releaseRepositorySession(ctx, repoSession);
605             }
606         }
607         
608         if (logger.isWarnEnabled() == true) {
609                 logger.warn("Returned DocumentModelList instance was created with a repository session that is now closed.");
610         }
611         
612         return wrapDoc;
613     }
614
615     /* (non-Javadoc)
616      * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.util.List, org.collectionspace.services.common.document.DocumentHandler)
617      */
618     @Override
619     public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
620             throws DocumentNotFoundException, DocumentException {
621         if (handler == null) {
622             throw new IllegalArgumentException(
623                     "RepositoryJavaClient.getAll: handler is missing");
624         }
625
626         RepositoryInstance repoSession = null;
627         try {
628             handler.prepare(Action.GET_ALL);
629             repoSession = getRepositorySession(ctx);
630             DocumentModelList docModelList = new DocumentModelListImpl();
631             //FIXME: Should be using NuxeoUtils.createPathRef for security reasons
632             for (String csid : csidList) {
633                 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
634                 DocumentModel docModel = repoSession.getDocument(docRef);
635                 docModelList.add(docModel);
636             }
637
638             //set reposession to handle the document
639             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
640             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docModelList);
641             handler.handle(Action.GET_ALL, wrapDoc);
642             handler.complete(Action.GET_ALL, wrapDoc);
643         } catch (DocumentException de) {
644             throw de;
645         } catch (Exception e) {
646             if (logger.isDebugEnabled()) {
647                 logger.debug("Caught exception ", e);
648             }
649             throw new DocumentException(e);
650         } finally {
651             if (repoSession != null) {
652                 releaseRepositorySession(ctx, repoSession);
653             }
654         }
655     }
656
657     /**
658      * getAll get all documents for an entity entity service from the Nuxeo
659      * repository
660      *
661      * @param ctx service context under which this method is invoked
662      * @param handler
663      *            should be used by the caller to provide and transform the
664      *            document
665      * @throws DocumentException
666      */
667     @Override
668     public void getAll(ServiceContext ctx, DocumentHandler handler)
669             throws DocumentNotFoundException, DocumentException {
670         if (handler == null) {
671             throw new IllegalArgumentException(
672                     "RepositoryJavaClient.getAll: handler is missing");
673         }
674         String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
675         if (nuxeoWspaceId == null) {
676             throw new DocumentNotFoundException(
677                     "Unable to find workspace for service "
678                     + ctx.getServiceName()
679                     + " check if the workspace exists in the Nuxeo repository.");
680         }
681         
682         RepositoryInstance repoSession = null;
683         try {
684             handler.prepare(Action.GET_ALL);
685             repoSession = getRepositorySession(ctx);
686             DocumentRef wsDocRef = new IdRef(nuxeoWspaceId);
687             DocumentModelList docList = repoSession.getChildren(wsDocRef);
688             //set reposession to handle the document
689             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
690             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
691             handler.handle(Action.GET_ALL, wrapDoc);
692             handler.complete(Action.GET_ALL, wrapDoc);
693         } catch (DocumentException de) {
694             throw de;
695         } catch (Exception e) {
696             if (logger.isDebugEnabled()) {
697                 logger.debug("Caught exception ", e);
698             }
699             throw new DocumentException(e);
700         } finally {
701             if (repoSession != null) {
702                 releaseRepositorySession(ctx, repoSession);
703             }
704         }
705     }
706     
707     private boolean isClauseEmpty(String theString) {
708         boolean result = true;
709         if (theString != null && !theString.isEmpty()) {
710                 result = false;
711         }
712         return result;
713     }
714     
715     public DocumentWrapper<DocumentModel> getDocFromCsid(
716                 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
717                 RepositoryInstance repoSession,
718                 String csid)
719             throws Exception {
720         DocumentWrapper<DocumentModel> result = null;
721
722         result = new DocumentWrapperImpl(NuxeoUtils.getDocFromCsid(ctx, repoSession, csid));
723         
724         return result;
725     }    
726
727     /*
728      * A method to find a CollectionSpace document (of any type) given just a service context and
729      * its CSID.  A search across *all* service workspaces (within a given tenant context) is performed to find
730      * the document
731      * 
732      * This query searches Nuxeo's Hierarchy table where our CSIDs are stored in the "name" column.
733      */
734     @Override
735     public DocumentWrapper<DocumentModel> getDocFromCsid(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
736                 String csid)
737             throws Exception {
738         DocumentWrapper<DocumentModel> result = null;
739         RepositoryInstance repoSession = null;
740         try {
741                 repoSession = getRepositorySession(ctx);
742                 result = getDocFromCsid(ctx, repoSession, csid);
743         } finally {
744             if (repoSession != null) {
745                 releaseRepositorySession(ctx, repoSession);
746             }
747         }
748         
749         if (logger.isWarnEnabled() == true) {
750                 logger.warn("Returned DocumentModel instance was created with a repository session that is now closed.");
751         }
752         
753         return result;
754     }
755
756     /**
757      * find doc and return CSID from the Nuxeo repository
758      * @param ctx service context under which this method is invoked
759      * @param whereClause where NXQL where clause to get the document
760      * @throws DocumentException
761      */
762     @Override
763     public String getDocURI(DocumentWrapper<DocumentModel> wrappedDoc) throws ClientException {
764         DocumentModel docModel = wrappedDoc.getWrappedObject();
765         String uri = (String)docModel.getProperty(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA,
766                         CollectionSpaceClient.COLLECTIONSPACE_CORE_URI);
767         return uri;
768     }
769
770     /*
771      * See CSPACE-5036 - How to make CMISQL queries from Nuxeo
772      */
773         private IterableQueryResult makeCMISQLQuery(RepositoryInstance repoSession, String query, QueryContext queryContext) {
774                 IterableQueryResult result = null;
775                 
776                 // the NuxeoRepository should be constructed only once, then cached
777                 // (its construction is expensive)
778                 try {
779                         NuxeoRepository repo = new NuxeoRepository(
780                                         repoSession.getRepositoryName(), repoSession
781                                                         .getRootDocument().getId());
782                         logger.debug("Repository ID:" + repo.getId() + " Root folder:"
783                                         + repo.getRootFolderId());
784
785                         CallContextImpl callContext = new CallContextImpl(
786                                         CallContext.BINDING_LOCAL, repo.getId(), false);
787                         callContext.put(CallContext.USERNAME, repoSession.getPrincipal()
788                                         .getName());
789                         NuxeoCmisService cmisService = new NuxeoCmisService(repo,
790                                         callContext, repoSession);
791
792                         result = repoSession.queryAndFetch(query, "CMISQL", cmisService);
793                 } catch (ClientException e) {
794                         // TODO Auto-generated catch block
795                         logger.error("Encounter trouble making the following CMIS query: " + query, e);
796                 }
797                 
798                 return result;
799         }
800      
801     /**
802      * getFiltered get all documents for an entity service from the Document repository,
803      * given filter parameters specified by the handler. 
804      * @param ctx service context under which this method is invoked
805      * @param handler should be used by the caller to provide and transform the document
806      * @throws DocumentNotFoundException if workspace not found
807      * @throws DocumentException
808      */
809     @Override
810     public void getFiltered(ServiceContext ctx, DocumentHandler handler)
811             throws DocumentNotFoundException, DocumentException {
812
813         DocumentFilter filter = handler.getDocumentFilter();
814         String oldOrderBy = filter.getOrderByClause();
815         if (isClauseEmpty(oldOrderBy) == true){
816             filter.setOrderByClause(DocumentFilter.ORDER_BY_LAST_UPDATED);
817         }
818         QueryContext queryContext = new QueryContext(ctx, handler);
819
820         RepositoryInstance repoSession = null;
821         try {
822             handler.prepare(Action.GET_ALL);
823             repoSession = getRepositorySession(ctx); //Need a refcount here for the repository session?
824             
825             DocumentModelList docList = null;
826             String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
827
828             if (logger.isDebugEnabled()) {
829                 logger.debug("Executing NXQL query: " + query.toString());
830             }
831
832             // If we have limit and/or offset, then pass true to get totalSize
833             // in returned DocumentModelList.
834                 Profiler profiler = new Profiler(this, 2);
835                 profiler.log("Executing NXQL query: " + query.toString());
836                 profiler.start();
837                 if (handler.isCMISQuery() == true) {
838                         docList = getFilteredCMIS(repoSession, ctx, handler, queryContext); //FIXME: REM - Need to deal with paging info in CMIS query
839                 } else if ((queryContext.getDocFilter().getOffset() > 0) || (queryContext.getDocFilter().getPageSize() > 0)) {
840                 docList = repoSession.query(query, null,
841                         queryContext.getDocFilter().getPageSize(), queryContext.getDocFilter().getOffset(), true);
842             } else {
843                 docList = repoSession.query(query);
844             }
845             profiler.stop();
846
847             //set repoSession to handle the document
848             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
849             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
850             handler.handle(Action.GET_ALL, wrapDoc);
851             handler.complete(Action.GET_ALL, wrapDoc);
852         } catch (DocumentException de) {
853             throw de;
854         } catch (Exception e) {
855             if (logger.isDebugEnabled()) {
856                 logger.debug("Caught exception ", e);
857             }
858             throw new DocumentException(e);
859         } finally {
860             if (repoSession != null) {
861                 releaseRepositorySession(ctx, repoSession);
862             }
863         }
864     }
865
866     private DocumentModelList getFilteredCMIS(RepositoryInstance repoSession, ServiceContext ctx, DocumentHandler handler, QueryContext queryContext)
867             throws DocumentNotFoundException, DocumentException {
868
869         DocumentModelList result = new DocumentModelListImpl();
870         try {
871             String query = handler.getCMISQuery(queryContext);
872
873                 DocumentFilter docFilter = handler.getDocumentFilter();
874             int pageSize = docFilter.getPageSize();
875             int offset = docFilter.getOffset();
876             if (logger.isDebugEnabled()) {
877                 logger.debug("Executing CMIS query: " + query.toString()
878                                 + "with pageSize: "+pageSize+" at offset: "+offset);
879             }
880
881             // If we have limit and/or offset, then pass true to get totalSize
882             // in returned DocumentModelList.
883                 Profiler profiler = new Profiler(this, 2);
884                 profiler.log("Executing CMIS query: " + query.toString());
885                 profiler.start();
886                 //
887                 IterableQueryResult queryResult = makeCMISQLQuery(repoSession, query, queryContext);
888                 try {
889                 int totalSize = (int)queryResult.size();
890                 ((DocumentModelListImpl)result).setTotalSize(totalSize);
891                                 // Skip the rows before our offset
892                         if(offset>0) {
893                                 queryResult.skipTo(offset);
894                         }
895                         int nRows = 0;
896                         for (Map<String, Serializable> row : queryResult) {
897                                 logger.debug(""
898                                                 //                                      + " dc:title is: " + (String)row.get("dc:title")
899                                                 + " Hierarchy Table ID is:" + row.get(IQueryManager.CMIS_TARGET_NUXEO_ID)
900                                                 + " nuxeo:pathSegment is: " + row.get(IQueryManager.CMIS_TARGET_NAME)
901                                                 //                                      + " nuxeo:lifecycleState is: " + row.get("nuxeo:lifecycleState")
902                                                 );
903                                 String nuxeoId = (String) row.get(IQueryManager.CMIS_TARGET_NUXEO_ID);
904                                 DocumentModel docModel = NuxeoUtils.getDocumentModel(repoSession, nuxeoId);
905                                 result.add(docModel);
906                                 nRows++;
907                                 if(nRows >= pageSize) {
908                                         logger.debug("Got page full of items - quitting");
909                                         break;
910                                 }
911                         }
912                 } finally {
913                         queryResult.close();
914                 }
915                 //
916             profiler.stop();
917
918         } catch (Exception e) {
919             if (logger.isDebugEnabled()) {
920                 logger.debug("Caught exception ", e);
921             }
922             throw new DocumentException(e);
923         }
924         
925         //
926         // Since we're not supporting paging yet for CMIS queries, we need to perform
927         // a workaround for the paging information we return in our list of results
928         //
929         /*
930         if (result != null) {
931                 docFilter.setStartPage(0);
932                 if (totalSize > docFilter.getPageSize()) {
933                         docFilter.setPageSize(totalSize);
934                 ((DocumentModelListImpl)result).setTotalSize(totalSize);
935                 }
936         }
937         */
938         
939         return result;
940     }
941     
942     private String logException(Exception e, String msg) {
943         String result = null;
944         
945         String exceptionMessage = e.getMessage();
946         exceptionMessage = exceptionMessage != null ? exceptionMessage : "<No details provided>";
947         result = msg = msg + ". Caught exception:" + exceptionMessage;
948         
949         if (logger.isTraceEnabled() == true) {
950                 logger.error(msg, e);
951         } else {
952                 logger.error(msg);
953         }
954         
955         return result;
956     }
957     
958     /**
959      * update given document in the Nuxeo repository
960      *
961      * @param ctx service context under which this method is invoked
962      * @param id
963      *            of the document
964      * @param handler
965      *            should be used by the caller to provide and transform the
966      *            document
967      * @throws DocumentException
968      */
969     @Override
970     public void update(ServiceContext ctx, String csid, DocumentHandler handler)
971             throws BadRequestException, DocumentNotFoundException,
972             DocumentException {
973         if (handler == null) {
974             throw new IllegalArgumentException(
975                     "RepositoryJavaClient.update: document handler is missing.");
976         }
977         
978         RepositoryInstance repoSession = null;
979         try {
980             handler.prepare(Action.UPDATE);
981             repoSession = getRepositorySession(ctx);
982             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
983             DocumentModel doc = null;
984             try {
985                 doc = repoSession.getDocument(docRef);
986             } catch (ClientException ce) {
987                 String msg = logException(ce, "Could not find document to update with CSID=" + csid);
988                 throw new DocumentNotFoundException(msg, ce);
989             }
990             //
991             // Set reposession to handle the document
992             //
993             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
994             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
995             handler.handle(Action.UPDATE, wrapDoc);
996             repoSession.saveDocument(doc);
997             repoSession.save();
998             handler.complete(Action.UPDATE, wrapDoc);
999         } catch (BadRequestException bre) {
1000             throw bre;
1001         } catch (DocumentException de) {
1002             throw de;
1003         } catch (WebApplicationException wae){
1004             throw wae;
1005         } catch (Exception e) {
1006             if (logger.isDebugEnabled()) {
1007                 logger.debug("Caught exception ", e);
1008             }
1009             throw new DocumentException(e);
1010         } finally {
1011             if (repoSession != null) {
1012                 releaseRepositorySession(ctx, repoSession);
1013             }
1014         }
1015     }
1016     
1017     /**
1018      * Save a documentModel to the Nuxeo repository.
1019      * @param ctx service context under which this method is invoked
1020      * @param docModel the document to save
1021      * @param fSaveSession if TRUE, will call CoreSession.save() to save accumulated changes.
1022      * @throws DocumentException
1023      */
1024     public void saveDocWithoutHandlerProcessing(
1025             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
1026             RepositoryInstance repoSession,
1027             DocumentModel docModel,
1028             boolean fSaveSession)
1029             throws ClientException, DocumentException {
1030
1031         try {
1032             repoSession.saveDocument(docModel);
1033             if (fSaveSession) {
1034                 repoSession.save();
1035             }
1036         } catch (ClientException ce) {
1037             throw ce;
1038         } catch (Exception e) {
1039             if (logger.isDebugEnabled()) {
1040                 logger.debug("Caught exception ", e);
1041             }
1042             throw new DocumentException(e);
1043         }
1044     }
1045
1046
1047     /**
1048      * Save a list of documentModels to the Nuxeo repository.
1049      * 
1050      * @param ctx service context under which this method is invoked
1051      * @param docModel the document to save
1052      * @param fSaveSession if TRUE, will call CoreSession.save() to save accumulated changes.
1053      * @throws DocumentException
1054      */
1055     public void saveDocListWithoutHandlerProcessing(
1056             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
1057             RepositoryInstance repoSession,
1058             DocumentModelList docList, 
1059             boolean fSaveSession)
1060             throws ClientException, DocumentException {
1061         try {
1062             repoSession = getRepositorySession(ctx);
1063             DocumentModel[] docModelArray = new DocumentModel[docList.size()];
1064             repoSession.saveDocuments(docList.toArray(docModelArray));
1065             if (fSaveSession) {
1066                 repoSession.save();
1067             }
1068         } catch (ClientException ce) {
1069             throw ce;
1070         } catch (Exception e) {
1071             logger.error("Caught exception ", e);
1072             throw new DocumentException(e);
1073         }
1074     }
1075
1076     /**
1077      * delete a document from the Nuxeo repository
1078      * @param ctx service context under which this method is invoked
1079      * @param id
1080      *            of the document
1081      * @throws DocumentException
1082      */
1083     @Override
1084     public void delete(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException,
1085             DocumentException {
1086         if (ctx == null) {
1087             throw new IllegalArgumentException(
1088                     "delete(ctx, ix, handler): ctx is missing");
1089         }
1090         if (handler == null) {
1091             throw new IllegalArgumentException(
1092                     "delete(ctx, ix, handler): handler is missing");
1093         }
1094         if (logger.isDebugEnabled()) {
1095             logger.debug("Deleting document with CSID=" + id);
1096         }
1097         RepositoryInstance repoSession = null;
1098         try {
1099                 handler.prepare(Action.DELETE);
1100             repoSession = getRepositorySession(ctx);
1101             DocumentWrapper<DocumentModel> wrapDoc = null;
1102             try {
1103                 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
1104                     wrapDoc = new DocumentWrapperImpl<DocumentModel>(repoSession.getDocument(docRef));
1105                     ((DocumentModelHandler) handler).setRepositorySession(repoSession);
1106                     handler.handle(Action.DELETE, wrapDoc);
1107                 repoSession.removeDocument(docRef);
1108             } catch (ClientException ce) {
1109                 String msg = logException(ce, "Could not find document to delete with CSID=" + id);
1110                 throw new DocumentNotFoundException(msg, ce);
1111             }
1112             repoSession.save();
1113             handler.complete(Action.DELETE, wrapDoc);
1114         } catch (DocumentException de) {
1115             throw de;
1116         } catch (Exception e) {
1117             if (logger.isDebugEnabled()) {
1118                 logger.debug("Caught exception ", e);
1119             }
1120             throw new DocumentException(e);
1121         } finally {
1122             if (repoSession != null) {
1123                 releaseRepositorySession(ctx, repoSession);
1124             }
1125         }
1126     }
1127
1128     /* (non-Javadoc)
1129      * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
1130      */
1131     @Override
1132     @Deprecated
1133     public void delete(@SuppressWarnings("rawtypes") ServiceContext ctx, String id)
1134             throws DocumentNotFoundException, DocumentException {
1135         throw new UnsupportedOperationException();
1136         // Use the other delete instead
1137     }
1138
1139     @Override
1140     public Hashtable<String, String> retrieveWorkspaceIds(String domainName) throws Exception {
1141         return NuxeoConnectorEmbedded.getInstance().retrieveWorkspaceIds(domainName);
1142     }
1143
1144     @Override
1145     public String createDomain(String domainName) throws Exception {
1146         RepositoryInstance repoSession = null;
1147         String domainId = null;
1148         try {
1149                 //
1150                 // First create the top-level domain directory
1151                 //
1152             repoSession = getRepositorySession(null);
1153             DocumentRef parentDocRef = new PathRef("/");
1154             DocumentModel parentDoc = repoSession.getDocument(parentDocRef);
1155             DocumentModel domainDoc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
1156                     domainName, NUXEO_CORE_TYPE_DOMAIN);
1157             domainDoc.setPropertyValue("dc:title", domainName);
1158             domainDoc.setPropertyValue("dc:description", "A CollectionSpace domain "
1159                     + domainName);
1160             domainDoc = repoSession.createDocument(domainDoc);
1161             domainId = domainDoc.getId();
1162             repoSession.save();
1163             //
1164             // Next, create a "Workspaces" root directory to contain the workspace folders for the individual service documents
1165             //
1166             DocumentModel workspacesRoot = repoSession.createDocumentModel(domainDoc.getPathAsString(),
1167                         NuxeoUtils.Workspaces, NUXEO_CORE_TYPE_WORKSPACEROOT);
1168             workspacesRoot.setPropertyValue("dc:title", NuxeoUtils.Workspaces);
1169             workspacesRoot.setPropertyValue("dc:description", "A CollectionSpace workspaces directory for "
1170                     + domainDoc.getPathAsString());
1171             workspacesRoot = repoSession.createDocument(workspacesRoot);
1172             String workspacesRootId = workspacesRoot.getId();
1173             repoSession.save();
1174             
1175             if (logger.isDebugEnabled()) {
1176                 logger.debug("Created tenant domain name=" + domainName
1177                         + " id=" + domainId + " " +
1178                         NuxeoUtils.Workspaces + " id=" + workspacesRootId);
1179                 logger.debug("Path to Domain: "+domainDoc.getPathAsString());
1180                 logger.debug("Path to Workspaces root: "+workspacesRoot.getPathAsString());
1181             }
1182         } catch (Exception e) {
1183             if (logger.isDebugEnabled()) {
1184                 logger.debug("Could not create tenant domain name=" + domainName + " caught exception ", e);
1185             }
1186             throw e;
1187         } finally {
1188             if (repoSession != null) {
1189                 releaseRepositorySession(null, repoSession);
1190             }
1191         }
1192         
1193         return domainId;
1194     }
1195
1196     @Override
1197     public String getDomainId(String domainName) throws Exception {
1198         String domainId = null;
1199         RepositoryInstance repoSession = null;
1200         
1201         if (domainName != null && !domainName.isEmpty()) {
1202                 try {
1203                     repoSession = getRepositorySession(null);
1204                     DocumentRef docRef = new PathRef(
1205                             "/" + domainName);
1206                     DocumentModel domain = repoSession.getDocument(docRef);
1207                     domainId = domain.getId();
1208                 } catch (Exception e) {
1209                     if (logger.isTraceEnabled()) {
1210                         logger.trace("Caught exception ", e);
1211                     }
1212                     //there is no way to identify if document does not exist due to
1213                     //lack of typed exception for getDocument method
1214                     return null;
1215                 } finally {
1216                     if (repoSession != null) {
1217                         releaseRepositorySession(null, repoSession);
1218                     }
1219                 }
1220         }
1221         
1222         return domainId;
1223     }
1224
1225     /*
1226          * Returns the workspaces root directory for a given domain.
1227          */
1228         private DocumentModel getWorkspacesRoot(RepositoryInstance repoSession,
1229                         String domainName) throws Exception {
1230                 DocumentModel result = null;
1231                 
1232                 String domainPath = "/" + domainName;
1233                 DocumentRef parentDocRef = new PathRef(domainPath);
1234                 DocumentModelList domainChildrenList = repoSession.getChildren(
1235                                 parentDocRef);
1236                 Iterator<DocumentModel> witer = domainChildrenList.iterator();
1237                 while (witer.hasNext()) {
1238                         DocumentModel childNode = witer.next();
1239                         if (NuxeoUtils.Workspaces.equalsIgnoreCase(childNode.getName())) {
1240                                 result = childNode;
1241                                 logger.trace("Found workspaces directory at: " + result.getPathAsString());
1242                                 break;
1243                         }
1244                 }
1245                 
1246                 if (result == null) {
1247                         throw new ClientException("Could not find workspace root directory in: "
1248                                         + domainPath);
1249                 }
1250
1251                 return result;
1252         }
1253     
1254     /* (non-Javadoc)
1255      * @see org.collectionspace.services.common.repository.RepositoryClient#createWorkspace(java.lang.String, java.lang.String)
1256      */
1257     @Override
1258     public String createWorkspace(String domainName, String workspaceName) throws Exception {
1259         RepositoryInstance repoSession = null;
1260         String workspaceId = null;
1261         try {
1262             repoSession = getRepositorySession(null);
1263             DocumentModel parentDoc = getWorkspacesRoot(repoSession, domainName);
1264             
1265             if (logger.isTraceEnabled()) {
1266                     for (String facet : parentDoc.getFacets()) {
1267                         logger.debug("Facet: " + facet);
1268                     }
1269             }
1270             
1271             DocumentModel doc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
1272                     workspaceName, NuxeoUtils.WORKSPACE_DOCUMENT_TYPE);
1273             doc.setPropertyValue("dc:title", workspaceName);
1274             doc.setPropertyValue("dc:description", "A CollectionSpace workspace for "
1275                     + workspaceName);
1276             doc = repoSession.createDocument(doc);
1277             workspaceId = doc.getId();
1278             repoSession.save();
1279             if (logger.isDebugEnabled()) {
1280                 logger.debug("Created workspace name=" + workspaceName
1281                         + " id=" + workspaceId);
1282             }
1283         } catch (Exception e) {
1284             if (logger.isDebugEnabled()) {
1285                 logger.debug("createWorkspace caught exception ", e);
1286             }
1287             throw e;
1288         } finally {
1289             if (repoSession != null) {
1290                 releaseRepositorySession(null, repoSession);
1291             }
1292         }
1293         return workspaceId;
1294     }
1295
1296     /* (non-Javadoc)
1297      * @see org.collectionspace.services.common.repository.RepositoryClient#getWorkspaceId(java.lang.String, java.lang.String)
1298      */
1299     @Override
1300     public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
1301         String workspaceId = null;
1302         
1303         RepositoryInstance repoSession = null;
1304         try {
1305             repoSession = getRepositorySession(null);
1306             DocumentRef docRef = new PathRef(
1307                     "/" + tenantDomain
1308                     + "/" + NuxeoUtils.Workspaces
1309                     + "/" + workspaceName);
1310             DocumentModel workspace = repoSession.getDocument(docRef);
1311             workspaceId = workspace.getId();
1312         } catch (DocumentException de) {
1313             throw de;
1314         } catch (Exception e) {
1315             if (logger.isDebugEnabled()) {
1316                 logger.debug("Caught exception ", e);
1317             }
1318             throw new DocumentException(e);
1319         } finally {
1320             if (repoSession != null) {
1321                 releaseRepositorySession(null, repoSession);
1322             }
1323         }
1324         
1325         return workspaceId;
1326     }
1327
1328
1329     /**
1330      * Gets the repository session. - Package access only.
1331      *
1332      * @return the repository session
1333      * @throws Exception the exception
1334      */
1335     public RepositoryInstance getRepositorySession(ServiceContext ctx) throws Exception {
1336         RepositoryInstance repoSession = null;
1337         
1338         Profiler profiler = new Profiler("getRepositorySession():", 2);
1339         profiler.start();
1340                 
1341         if (ctx != null) {
1342                 repoSession = (RepositoryInstance)ctx.getCurrentRepositorySession();
1343             if (logger.isDebugEnabled() == true) {
1344                 if (repoSession != null) {
1345                         logger.warn("Reusing the current context's repository session.");
1346                 }
1347             }           
1348         }
1349         
1350         // If we couldn't find a repoSession from the service context then we need to create a new one
1351         if (repoSession == null) {
1352                 NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
1353                 repoSession = client.openRepository();
1354         }
1355         
1356         if (logger.isTraceEnabled()) {
1357             logger.trace("Testing call to getRepository() repository root: " + repoSession.getRootDocument());
1358         }
1359         
1360         profiler.stop();
1361         
1362         if (ctx != null) {
1363                 ctx.setCurrentRepositorySession(repoSession); // For reusing, save the repository session in the current service context
1364         }
1365         
1366         return repoSession;
1367     }
1368
1369     /**
1370      * Release repository session. - Package access only.
1371      *
1372      * @param repoSession the repo session
1373      */
1374     public void releaseRepositorySession(ServiceContext ctx, RepositoryInstance repoSession) {
1375         try {
1376             NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
1377             // release session
1378             if (ctx != null) {
1379                 ctx.clearCurrentRepositorySession(); //clear the current context of the now closed repo session
1380                 if (ctx.getCurrentRepositorySession() == null) {
1381                     client.releaseRepository(repoSession); //release the repo session if the service context's ref count is zeo.
1382                 }
1383             } else {
1384                 client.releaseRepository(repoSession); //repo session was acquired without a service context
1385             }
1386         } catch (Exception e) {
1387             logger.error("Could not close the repository session", e);
1388             // no need to throw this service specific exception
1389         }
1390     }
1391
1392         @Override
1393         public void doWorkflowTransition(ServiceContext ctx, String id,
1394                         DocumentHandler handler, TransitionDef transitionDef)
1395                         throws BadRequestException, DocumentNotFoundException,
1396                         DocumentException {
1397                 // 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
1398         }
1399
1400 }