]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
5339dcbe517a57ddc90d9115f236b8120fda7573
[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.util.Hashtable;
21 import java.util.List;
22 import java.util.Set;
23 import java.util.UUID;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26 import java.util.regex.PatternSyntaxException;
27
28 import javax.ws.rs.WebApplicationException;
29 import javax.ws.rs.core.MultivaluedMap;
30
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.datetime.GregorianCalendarDateTimeUtils;
37 import org.collectionspace.services.common.query.QueryContext;
38 import org.collectionspace.services.common.repository.RepositoryClient;
39 import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;
40 import org.collectionspace.services.common.profile.Profiler;
41 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
42
43 import org.collectionspace.services.common.document.BadRequestException;
44 import org.collectionspace.services.common.document.DocumentException;
45 import org.collectionspace.services.common.document.DocumentFilter;
46 import org.collectionspace.services.common.document.DocumentHandler;
47 import org.collectionspace.services.common.document.DocumentNotFoundException;
48 import org.collectionspace.services.common.document.DocumentHandler.Action;
49 import org.collectionspace.services.common.document.DocumentWrapper;
50 import org.collectionspace.services.common.document.DocumentWrapperImpl;
51
52 import org.nuxeo.common.utils.IdUtils;
53 import org.nuxeo.ecm.core.api.ClientException;
54 import org.nuxeo.ecm.core.api.DocumentModel;
55 import org.nuxeo.ecm.core.api.DocumentModelList;
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 //import org.nuxeo.ecm.core.client.NuxeoClient;
62 import org.nuxeo.ecm.core.schema.SchemaManager;
63 import org.nuxeo.runtime.api.Framework;
64
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68 /**
69  * RepositoryJavaClient is used to perform CRUD operations on documents in Nuxeo
70  * repository using Remote Java APIs. It uses @see DocumentHandler as IOHandler
71  * with the client.
72  * 
73  * $LastChangedRevision: $ $LastChangedDate: $
74  */
75 public class RepositoryJavaClientImpl implements RepositoryClient<PoxPayloadIn, PoxPayloadOut> {
76
77     /** The logger. */
78     private final Logger logger = LoggerFactory.getLogger(RepositoryJavaClientImpl.class);
79 //    private final Logger profilerLogger = LoggerFactory.getLogger("remperf");
80 //    private String foo = Profiler.createLogger();
81
82     public static final String NUXEO_CORE_TYPE_DOMAIN = "Domain";
83     public static final String NUXEO_CORE_TYPE_WORKSPACEROOT = "WorkspaceRoot";
84     
85     /**
86      * Instantiates a new repository java client impl.
87      */
88     public RepositoryJavaClientImpl() {
89         //Empty constructor
90         
91     }
92
93     public void assertWorkflowState(ServiceContext ctx,
94                 DocumentModel docModel) throws DocumentNotFoundException, ClientException {
95         MultivaluedMap<String, String> queryParams = ctx.getQueryParams();
96         if (queryParams != null) {
97                 //
98                 // Look for the workflow "delete" query param and see if we need to assert that the
99                 // docModel is in a non-deleted workflow state.
100                 //
101                 String currentState = docModel.getCurrentLifeCycleState();
102                 String includeDeletedStr = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_NONDELETED);
103                 boolean includeDeleted = includeDeletedStr == null ? true : Boolean.parseBoolean(includeDeletedStr);
104                 if (includeDeleted == false) {
105                         //
106                         // We don't wanted soft-deleted object, so throw an exception if this one is soft-deleted.
107                         //
108                         if (currentState.equalsIgnoreCase(WorkflowClient.WORKFLOWSTATE_DELETED)) {
109                                 String msg = "GET assertion that docModel not be in 'deleted' workflow state failed.";
110                                 logger.debug(msg);
111                                 throw new DocumentNotFoundException(msg);
112                         }
113                 }
114         }
115     }
116     
117     /**
118      * create document in the Nuxeo repository
119      *
120      * @param ctx service context under which this method is invoked
121      * @param handler
122      *            should be used by the caller to provide and transform the
123      *            document
124      * @return id in repository of the newly created document
125      * @throws DocumentException
126      */
127     @Override
128     public String create(ServiceContext ctx,
129             DocumentHandler handler) throws BadRequestException,
130             DocumentException {
131
132         String docType = NuxeoUtils.getTenantQualifiedDocType(ctx); //ctx.getDocumentType();
133         if (docType == null) {
134             throw new IllegalArgumentException(
135                     "RepositoryJavaClient.create: docType is missing");
136         }
137         
138         if (handler == null) {
139             throw new IllegalArgumentException(
140                     "RepositoryJavaClient.create: handler is missing");
141         }
142         String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
143         if (nuxeoWspaceId == null) {
144             throw new DocumentNotFoundException(
145                     "Unable to find workspace for service " + ctx.getServiceName()
146                     + " check if the workspace exists in the Nuxeo repository");
147         }
148         RepositoryInstance repoSession = null;
149         try {
150             handler.prepare(Action.CREATE);
151             repoSession = getRepositorySession();
152             DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);
153             DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);
154             String wspacePath = wspaceDoc.getPathAsString();
155             //give our own ID so PathRef could be constructed later on
156             String id = IdUtils.generateId(UUID.randomUUID().toString());
157             // create document model
158             DocumentModel doc = repoSession.createDocumentModel(wspacePath, id, docType);
159             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
160             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
161             handler.handle(Action.CREATE, wrapDoc);
162             // create document with documentmodel
163             doc = repoSession.createDocument(doc);
164             repoSession.save();
165 // TODO for sub-docs need to call into the handler to let it deal with subitems. Pass in the id,
166 // and assume the handler has the state it needs (doc fragments). 
167             handler.complete(Action.CREATE, wrapDoc);
168             return id;
169         } catch (BadRequestException bre) {
170             throw bre;
171         } catch (Exception e) {
172             if (logger.isDebugEnabled()) {
173                 logger.debug("Caught exception ", e);
174             }
175             throw new DocumentException(e);
176         } finally {
177             if (repoSession != null) {
178                 releaseRepositorySession(repoSession);
179             }
180         }
181
182     }
183
184     /**
185      * get document from the Nuxeo repository
186      * @param ctx service context under which this method is invoked
187      * @param id
188      *            of the document to retrieve
189      * @param handler
190      *            should be used by the caller to provide and transform the
191      *            document
192      * @throws DocumentException
193      */
194     @Override
195     public void get(ServiceContext ctx, String id, DocumentHandler handler)
196             throws DocumentNotFoundException, DocumentException {
197
198         if (handler == null) {
199             throw new IllegalArgumentException(
200                     "RepositoryJavaClient.get: handler is missing");
201         }
202         RepositoryInstance repoSession = null;
203
204         try {
205             handler.prepare(Action.GET);
206             repoSession = getRepositorySession();
207             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
208             DocumentModel docModel = null;
209             try {
210                 docModel = repoSession.getDocument(docRef);
211                 assertWorkflowState(ctx, docModel);
212             } catch (ClientException ce) {
213                 String msg = "Could not find document with id=" + id;
214                 logger.error(msg, ce);
215                 throw new DocumentNotFoundException(msg, ce);
216             }
217             //set reposession to handle the document
218             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
219             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(docModel);
220             handler.handle(Action.GET, wrapDoc);
221             handler.complete(Action.GET, wrapDoc);
222         } catch (IllegalArgumentException iae) {
223             throw iae;
224         } catch (DocumentException de) {
225             throw de;
226         } catch (Exception e) {
227             if (logger.isDebugEnabled()) {
228                 logger.debug("Caught exception ", e);
229             }
230             throw new DocumentException(e);
231         } finally {
232             if (repoSession != null) {
233                 releaseRepositorySession(repoSession);
234             }
235         }
236     }
237
238     /**
239      * get document from the Nuxeo repository, using the docFilter params.
240      * @param ctx service context under which this method is invoked
241      * @param handler
242      *            should be used by the caller to provide and transform the
243      *            document. Handler must have a docFilter set to return a single item.
244      * @throws DocumentException
245      */
246     @Override
247     public void get(ServiceContext ctx, DocumentHandler handler)
248             throws DocumentNotFoundException, DocumentException {
249         QueryContext queryContext = new QueryContext(ctx, handler);
250         RepositoryInstance repoSession = null;
251
252         try {
253             handler.prepare(Action.GET);
254             repoSession = getRepositorySession();
255
256             DocumentModelList docList = null;
257             // force limit to 1, and ignore totalSize
258             String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
259             docList = repoSession.query(query, null, 1, 0, false);
260             if (docList.size() != 1) {
261                 throw new DocumentNotFoundException("No document found matching filter params.");
262             }
263             DocumentModel doc = docList.get(0);
264
265             if (logger.isDebugEnabled()) {
266                 logger.debug("Executed NXQL query: " + query);
267             }
268
269             //set reposession to handle the document
270             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
271             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
272             handler.handle(Action.GET, wrapDoc);
273             handler.complete(Action.GET, wrapDoc);
274         } catch (IllegalArgumentException iae) {
275             throw iae;
276         } catch (DocumentException de) {
277             throw de;
278         } catch (Exception e) {
279             if (logger.isDebugEnabled()) {
280                 logger.debug("Caught exception ", e);
281             }
282             throw new DocumentException(e);
283         } finally {
284             if (repoSession != null) {
285                 releaseRepositorySession(repoSession);
286             }
287         }
288     }
289     
290     /**
291      * Get wrapped documentModel from the Nuxeo repository.  The search is restricted to the workspace
292      * of the current context.
293      * 
294      * @param ctx service context under which this method is invoked
295      * @param id
296      *            of the document to retrieve
297      * @throws DocumentException
298      */
299     @Override
300     public DocumentWrapper<DocumentModel> getDoc(
301             ServiceContext ctx, String csid)
302             throws DocumentNotFoundException, DocumentException {
303         RepositoryInstance repoSession = null;
304         DocumentWrapper<DocumentModel> wrapDoc = null;
305
306         try {
307             repoSession = getRepositorySession();
308             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
309             DocumentModel doc = null;
310             try {
311                 doc = repoSession.getDocument(docRef);
312             } catch (ClientException ce) {
313                 String msg = "could not find document with id=" + csid;
314                 logger.error(msg, ce);
315                 throw new DocumentNotFoundException(msg, ce);
316             }
317             wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
318         } catch (IllegalArgumentException iae) {
319             throw iae;
320         } catch (DocumentException de) {
321             throw de;
322         } catch (Exception e) {
323             if (logger.isDebugEnabled()) {
324                 logger.debug("Caught exception ", e);
325             }
326             throw new DocumentException(e);
327         } finally {
328             if (repoSession != null) {
329                 releaseRepositorySession(repoSession);
330             }
331         }
332         return wrapDoc;
333     }
334
335     /**
336      * find wrapped documentModel from the Nuxeo repository
337      * @param ctx service context under which this method is invoked
338      * @param whereClause where NXQL where clause to get the document
339      * @throws DocumentException
340      */
341     @Override
342     public DocumentWrapper<DocumentModel> findDoc(
343             ServiceContext ctx, String whereClause)
344             throws DocumentNotFoundException, DocumentException {
345         RepositoryInstance repoSession = null;
346         DocumentWrapper<DocumentModel> wrapDoc = null;
347
348         try {
349             QueryContext queryContext = new QueryContext(ctx, whereClause);
350             repoSession = getRepositorySession();
351             DocumentModelList docList = null;
352             // force limit to 1, and ignore totalSize
353             String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
354             docList = repoSession.query(query,
355                     null, //Filter
356                     1, //limit
357                     0, //offset
358                     false); //countTotal
359             if (docList.size() != 1) {
360                 if (logger.isDebugEnabled()) {
361                     logger.debug("findDoc: Query found: " + docList.size() + " items.");
362                     logger.debug(" Query: " + query);
363                 }
364                 throw new DocumentNotFoundException("No document found matching filter params.");
365             }
366             DocumentModel doc = docList.get(0);
367             wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
368         } catch (IllegalArgumentException iae) {
369             throw iae;
370         } catch (DocumentException de) {
371             throw de;
372         } catch (Exception e) {
373             if (logger.isDebugEnabled()) {
374                 logger.debug("Caught exception ", e);
375             }
376             throw new DocumentException(e);
377         } finally {
378             if (repoSession != null) {
379                 releaseRepositorySession(repoSession);
380             }
381         }
382         return wrapDoc;
383     }
384
385     /**
386      * find doc and return CSID from the Nuxeo repository
387      * @param ctx service context under which this method is invoked
388      * @param whereClause where NXQL where clause to get the document
389      * @throws DocumentException
390      */
391     @Override
392     public String findDocCSID(
393             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String whereClause)
394             throws DocumentNotFoundException, DocumentException {
395         String csid = null;
396         try {
397             DocumentWrapper<DocumentModel> wrapDoc = findDoc(ctx, whereClause);
398             DocumentModel docModel = wrapDoc.getWrappedObject();
399             csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
400         } catch (DocumentNotFoundException dnfe) {
401             throw dnfe;
402         } catch (IllegalArgumentException iae) {
403             throw iae;
404         } catch (DocumentException de) {
405             throw de;
406         } catch (Exception e) {
407             if (logger.isDebugEnabled()) {
408                 logger.debug("Caught exception ", e);
409             }
410             throw new DocumentException(e);
411         }
412         return csid;
413     }
414
415     /**
416      * Find a list of documentModels from the Nuxeo repository
417      * @param docTypes a list of DocType names to match
418      * @param  whereClause where the clause to qualify on
419      * @return
420      */
421     @Override
422     public DocumentWrapper<DocumentModelList> findDocs(
423             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
424             List<String> docTypes,
425             String whereClause,
426             int pageSize, int pageNum, boolean computeTotal)
427             throws DocumentNotFoundException, DocumentException {
428         RepositoryInstance repoSession = null;
429         DocumentWrapper<DocumentModelList> wrapDoc = null;
430
431         try {
432             if (docTypes == null || docTypes.size() < 1) {
433                 throw new DocumentNotFoundException(
434                         "findDocs must specify at least one DocumentType.");
435             }
436             repoSession = getRepositorySession();
437             DocumentModelList docList = null;
438             // force limit to 1, and ignore totalSize
439             QueryContext queryContext = new QueryContext(ctx, whereClause);
440             String query = NuxeoUtils.buildNXQLQuery(docTypes, queryContext);
441             docList = repoSession.query(query, null, pageSize, pageNum, computeTotal);
442             wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
443         } catch (IllegalArgumentException iae) {
444             throw iae;
445         } catch (Exception e) {
446             if (logger.isDebugEnabled()) {
447                 logger.debug("Caught exception ", e);
448             }
449             throw new DocumentException(e);
450         } finally {
451             if (repoSession != null) {
452                 releaseRepositorySession(repoSession);
453             }
454         }
455         return wrapDoc;
456     }
457
458     /* (non-Javadoc)
459      * @see org.collectionspace.services.common.storage.StorageClient#get(org.collectionspace.services.common.context.ServiceContext, java.util.List, org.collectionspace.services.common.document.DocumentHandler)
460      */
461     @Override
462     public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
463             throws DocumentNotFoundException, DocumentException {
464         if (handler == null) {
465             throw new IllegalArgumentException(
466                     "RepositoryJavaClient.getAll: handler is missing");
467         }
468
469         RepositoryInstance repoSession = null;
470
471         try {
472             handler.prepare(Action.GET_ALL);
473             repoSession = getRepositorySession();
474             DocumentModelList docModelList = new DocumentModelListImpl();
475             //FIXME: Should be using NuxeoUtils.createPathRef for security reasons
476             for (String csid : csidList) {
477                 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
478                 DocumentModel docModel = repoSession.getDocument(docRef);
479                 docModelList.add(docModel);
480             }
481
482             //set reposession to handle the document
483             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
484             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docModelList);
485             handler.handle(Action.GET_ALL, wrapDoc);
486             handler.complete(Action.GET_ALL, wrapDoc);
487         } catch (DocumentException de) {
488             throw de;
489         } catch (Exception e) {
490             if (logger.isDebugEnabled()) {
491                 logger.debug("Caught exception ", e);
492             }
493             throw new DocumentException(e);
494         } finally {
495             if (repoSession != null) {
496                 releaseRepositorySession(repoSession);
497             }
498         }
499     }
500
501     /**
502      * getAll get all documents for an entity entity service from the Nuxeo
503      * repository
504      *
505      * @param ctx service context under which this method is invoked
506      * @param handler
507      *            should be used by the caller to provide and transform the
508      *            document
509      * @throws DocumentException
510      */
511     @Override
512     public void getAll(ServiceContext ctx, DocumentHandler handler)
513             throws DocumentNotFoundException, DocumentException {
514         if (handler == null) {
515             throw new IllegalArgumentException(
516                     "RepositoryJavaClient.getAll: handler is missing");
517         }
518         String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
519         if (nuxeoWspaceId == null) {
520             throw new DocumentNotFoundException(
521                     "Unable to find workspace for service "
522                     + ctx.getServiceName()
523                     + " check if the workspace exists in the Nuxeo repository");
524         }
525         RepositoryInstance repoSession = null;
526
527         try {
528             handler.prepare(Action.GET_ALL);
529             repoSession = getRepositorySession();
530             DocumentRef wsDocRef = new IdRef(nuxeoWspaceId);
531             DocumentModelList docList = repoSession.getChildren(wsDocRef);
532             //set reposession to handle the document
533             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
534             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
535             handler.handle(Action.GET_ALL, wrapDoc);
536             handler.complete(Action.GET_ALL, wrapDoc);
537         } catch (DocumentException de) {
538             throw de;
539         } catch (Exception e) {
540             if (logger.isDebugEnabled()) {
541                 logger.debug("Caught exception ", e);
542             }
543             throw new DocumentException(e);
544         } finally {
545             if (repoSession != null) {
546                 releaseRepositorySession(repoSession);
547             }
548         }
549     }
550     
551     private boolean isClauseEmpty(String theString) {
552         boolean result = true;
553         if (theString != null && !theString.isEmpty()) {
554                 result = false;
555         }
556         return result;
557     }
558
559     /*
560      * A method to find a CollectionSpace document (of any type) given just a service context and
561      * its CSID.  A search across *all* service workspaces (within a given tenant context) is performed to find
562      * the document
563      * 
564      * This query searches Nuxeo's Hierarchy table where our CSIDs are stored in the "name" column.
565      */
566     @Override
567     public DocumentWrapper<DocumentModel> getDocFromCsid(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
568                 String csid)
569             throws Exception {
570         DocumentWrapper<DocumentModel> result = null;
571         RepositoryInstance repoSession = getRepositorySession();
572         try {
573                 result = new DocumentWrapperImpl(NuxeoUtils.getDocFromCsid(repoSession, ctx, csid));
574         } finally {
575             if (repoSession != null) {
576                 releaseRepositorySession(repoSession);
577             }
578         }
579         return result;
580     }
581
582     /**
583      * find doc and return CSID from the Nuxeo repository
584      * @param ctx service context under which this method is invoked
585      * @param whereClause where NXQL where clause to get the document
586      * @throws DocumentException
587      */
588     @Override
589     public String getDocURI(DocumentWrapper<DocumentModel> wrappedDoc) throws ClientException {
590         DocumentModel docModel = wrappedDoc.getWrappedObject();
591         String uri = (String)docModel.getProperty(DocumentModelHandler.COLLECTIONSPACE_CORE_SCHEMA,
592                                 DocumentModelHandler.COLLECTIONSPACE_CORE_URI);
593         return uri;
594     }
595
596
597     /**
598      * getFiltered get all documents for an entity service from the Document repository,
599      * given filter parameters specified by the handler. 
600      * @param ctx service context under which this method is invoked
601      * @param handler should be used by the caller to provide and transform the document
602      * @throws DocumentNotFoundException if workspace not found
603      * @throws DocumentException
604      */
605     @Override
606     public void getFiltered(ServiceContext ctx, DocumentHandler handler)
607             throws DocumentNotFoundException, DocumentException {
608
609         DocumentFilter filter = handler.getDocumentFilter();
610         String oldOrderBy = filter.getOrderByClause();
611         if (isClauseEmpty(oldOrderBy) == true){
612             filter.setOrderByClause(DocumentFilter.ORDER_BY_LAST_UPDATED);  //per http://issues.collectionspace.org/browse/CSPACE-705
613         }
614         QueryContext queryContext = new QueryContext(ctx, handler);
615         RepositoryInstance repoSession = null;
616         try {
617             handler.prepare(Action.GET_ALL);
618             repoSession = getRepositorySession();
619             DocumentModelList docList = null;
620             String query = NuxeoUtils.buildNXQLQuery(ctx, queryContext);
621
622             if (logger.isDebugEnabled()) {
623                 logger.debug("Executing NXQL query: " + query.toString());
624             }
625
626             // If we have limit and/or offset, then pass true to get totalSize
627             // in returned DocumentModelList.
628                 Profiler profiler = new Profiler(this, 2);
629                 profiler.log("Executing NXQL query: " + query.toString());
630                 profiler.start();
631             if ((queryContext.getDocFilter().getOffset() > 0) || (queryContext.getDocFilter().getPageSize() > 0)) {
632                 docList = repoSession.query(query, null,
633                         queryContext.getDocFilter().getPageSize(), queryContext.getDocFilter().getOffset(), true);
634             } else {
635                 docList = repoSession.query(query);
636             }
637             profiler.stop();
638
639             //set repoSession to handle the document
640             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
641             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
642             handler.handle(Action.GET_ALL, wrapDoc);
643             handler.complete(Action.GET_ALL, wrapDoc);
644         } catch (DocumentException de) {
645             throw de;
646         } catch (Exception e) {
647             if (logger.isDebugEnabled()) {
648                 logger.debug("Caught exception ", e);
649             }
650             throw new DocumentException(e);
651         } finally {
652             if (repoSession != null) {
653                 releaseRepositorySession(repoSession);
654             }
655         }
656     }
657
658     /**
659      * update given document in the Nuxeo repository
660      *
661      * @param ctx service context under which this method is invoked
662      * @param id
663      *            of the document
664      * @param handler
665      *            should be used by the caller to provide and transform the
666      *            document
667      * @throws DocumentException
668      */
669     @Override
670     public void update(ServiceContext ctx, String id, DocumentHandler handler)
671             throws BadRequestException, DocumentNotFoundException,
672             DocumentException {
673         if (handler == null) {
674             throw new IllegalArgumentException(
675                     "RepositoryJavaClient.update: handler is missing");
676         }
677         RepositoryInstance repoSession = null;
678         try {
679             handler.prepare(Action.UPDATE);
680             repoSession = getRepositorySession();
681             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
682             DocumentModel doc = null;
683             try {
684                 doc = repoSession.getDocument(docRef);
685             } catch (ClientException ce) {
686                 String msg = "Could not find document to update with id=" + id;
687                 logger.error(msg, ce);
688                 throw new DocumentNotFoundException(msg, ce);
689             }
690             //set reposession to handle the document
691             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
692             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
693             handler.handle(Action.UPDATE, wrapDoc);
694             repoSession.saveDocument(doc);
695             repoSession.save();
696             handler.complete(Action.UPDATE, wrapDoc);
697         } catch (BadRequestException bre) {
698             throw bre;
699         } catch (DocumentException de) {
700             throw de;
701         } catch (WebApplicationException wae){
702             throw wae;
703         } catch (Exception e) {
704             if (logger.isDebugEnabled()) {
705                 logger.debug("Caught exception ", e);
706             }
707             throw new DocumentException(e);
708         } finally {
709             if (repoSession != null) {
710                 releaseRepositorySession(repoSession);
711             }
712         }
713     }
714
715     /**
716      * delete a document from the Nuxeo repository
717      * @param ctx service context under which this method is invoked
718      * @param id
719      *            of the document
720      * @throws DocumentException
721      */
722     @Override
723     public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException,
724             DocumentException {
725
726         if (logger.isDebugEnabled()) {
727             logger.debug("deleting document with id=" + id);
728         }
729         RepositoryInstance repoSession = null;
730         try {
731             repoSession = getRepositorySession();
732             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
733             try {
734                 repoSession.removeDocument(docRef);
735             } catch (ClientException ce) {
736                 String msg = "could not find document to delete with id=" + id;
737                 logger.error(msg, ce);
738                 throw new DocumentNotFoundException(msg, ce);
739             }
740             repoSession.save();
741         } catch (DocumentException de) {
742             throw de;
743         } catch (Exception e) {
744             if (logger.isDebugEnabled()) {
745                 logger.debug("Caught exception ", e);
746             }
747             throw new DocumentException(e);
748         } finally {
749             if (repoSession != null) {
750                 releaseRepositorySession(repoSession);
751             }
752         }
753     }
754
755     /* (non-Javadoc)
756      * @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String, org.collectionspace.services.common.document.DocumentHandler)
757      */
758     @Override
759     public void delete(ServiceContext ctx, String id, DocumentHandler handler)
760             throws DocumentNotFoundException, DocumentException {
761         throw new UnsupportedOperationException();
762     }
763
764     @Override
765     public Hashtable<String, String> retrieveWorkspaceIds(String domainName) throws Exception {
766         return NuxeoConnectorEmbedded.getInstance().retrieveWorkspaceIds(domainName);
767     }
768
769     @Override
770     public String createDomain(String domainName) throws Exception {
771         RepositoryInstance repoSession = null;
772         String domainId = null;
773         try {
774                 //
775                 // First create the top-level domain directory
776                 //
777             repoSession = getRepositorySession();
778             DocumentRef parentDocRef = new PathRef("/");
779             DocumentModel parentDoc = repoSession.getDocument(parentDocRef);
780             DocumentModel domainDoc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
781                     domainName, NUXEO_CORE_TYPE_DOMAIN);
782             domainDoc.setPropertyValue("dc:title", domainName);
783             domainDoc.setPropertyValue("dc:description", "A CollectionSpace domain "
784                     + domainName);
785             domainDoc = repoSession.createDocument(domainDoc);
786             domainId = domainDoc.getId();
787             repoSession.save();
788             //
789             // Next, create a "Workspaces" root directory to contain the workspace folders for the individual service documents
790             //
791             DocumentModel workspacesRoot = repoSession.createDocumentModel(domainDoc.getPathAsString(),
792                         NuxeoUtils.Workspaces, NUXEO_CORE_TYPE_WORKSPACEROOT);
793             workspacesRoot.setPropertyValue("dc:title", NuxeoUtils.Workspaces);
794             workspacesRoot.setPropertyValue("dc:description", "A CollectionSpace workspaces directory for "
795                     + domainDoc.getPathAsString());
796             workspacesRoot = repoSession.createDocument(workspacesRoot);
797             String workspacesRootId = workspacesRoot.getId();
798             
799             if (logger.isDebugEnabled()) {
800                 logger.debug("Created tenant domain name=" + domainName
801                         + " id=" + domainId + " " +
802                         NuxeoUtils.Workspaces + " id=" + workspacesRootId);
803             }
804         } catch (Exception e) {
805             if (logger.isDebugEnabled()) {
806                 logger.debug("createTenantSpace caught exception ", e);
807             }
808             throw e;
809         } finally {
810             if (repoSession != null) {
811                 releaseRepositorySession(repoSession);
812             }
813         }
814         return domainId;
815     }
816
817     @Override
818     public String getDomainId(String domainName) throws Exception {
819         String domainId = null;
820         RepositoryInstance repoSession = null;
821         
822         if (domainName != null && !domainName.isEmpty()) {
823                 try {
824                     repoSession = getRepositorySession();
825                     DocumentRef docRef = new PathRef(
826                             "/" + domainName);
827                     DocumentModel domain = repoSession.getDocument(docRef);
828                     domainId = domain.getId();
829                 } catch (Exception e) {
830                     if (logger.isTraceEnabled()) {
831                         logger.trace("Caught exception ", e);
832                     }
833                     //there is no way to identify if document does not exist due to
834                     //lack of typed exception for getDocument method
835                     return null;
836                 } finally {
837                     if (repoSession != null) {
838                         releaseRepositorySession(repoSession);
839                     }
840                 }
841         }
842         
843         return domainId;
844     }
845
846     /* (non-Javadoc)
847      * @see org.collectionspace.services.common.repository.RepositoryClient#createWorkspace(java.lang.String, java.lang.String)
848      */
849     @Override
850     public String createWorkspace(String domainName, String workspaceName) throws Exception {
851         RepositoryInstance repoSession = null;
852         String workspaceId = null;
853         try {
854             repoSession = getRepositorySession();
855             DocumentRef parentDocRef = new PathRef(
856                     "/" + domainName
857                     + "/" + NuxeoUtils.Workspaces);
858             DocumentModel parentDoc = repoSession.getDocument(parentDocRef);
859             DocumentModel doc = repoSession.createDocumentModel(parentDoc.getPathAsString(),
860                     workspaceName, "Workspace");
861             doc.setPropertyValue("dc:title", workspaceName);
862             doc.setPropertyValue("dc:description", "A CollectionSpace workspace for "
863                     + workspaceName);
864             doc = repoSession.createDocument(doc);
865             workspaceId = doc.getId();
866             repoSession.save();
867             if (logger.isDebugEnabled()) {
868                 logger.debug("created workspace name=" + workspaceName
869                         + " id=" + workspaceId);
870             }
871         } catch (Exception e) {
872             if (logger.isDebugEnabled()) {
873                 logger.debug("createWorkspace caught exception ", e);
874             }
875             throw e;
876         } finally {
877             if (repoSession != null) {
878                 releaseRepositorySession(repoSession);
879             }
880         }
881         return workspaceId;
882     }
883
884     /* (non-Javadoc)
885      * @see org.collectionspace.services.common.repository.RepositoryClient#getWorkspaceId(java.lang.String, java.lang.String)
886      */
887     @Override
888     public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
889         String workspaceId = null;
890         RepositoryInstance repoSession = null;
891         try {
892             repoSession = getRepositorySession();
893             DocumentRef docRef = new PathRef(
894                     "/" + tenantDomain
895                     + "/" + NuxeoUtils.Workspaces
896                     + "/" + workspaceName);
897             DocumentModel workspace = repoSession.getDocument(docRef);
898             workspaceId = workspace.getId();
899         } catch (DocumentException de) {
900             throw de;
901         } catch (Exception e) {
902             if (logger.isDebugEnabled()) {
903                 logger.debug("Caught exception ", e);
904             }
905             throw new DocumentException(e);
906         } finally {
907             if (repoSession != null) {
908                 releaseRepositorySession(repoSession);
909             }
910         }
911         return workspaceId;
912     }
913
914
915     /**
916      * Gets the repository session.
917      *
918      * @return the repository session
919      * @throws Exception the exception
920      */
921     private RepositoryInstance getRepositorySession() throws Exception {
922         // FIXME: is it possible to reuse repository session?
923         // Authentication failures happen while trying to reuse the session
924         Profiler profiler = new Profiler("getRepositorySession():", 2);
925         profiler.start();
926         NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
927         RepositoryInstance repoSession = client.openRepository();
928         if (logger.isDebugEnabled()) {
929             logger.debug("getRepository() repository root: " + repoSession.getRootDocument());
930         }
931         profiler.stop();
932         return repoSession;
933     }
934
935     /**
936      * Release repository session.
937      *
938      * @param repoSession the repo session
939      */
940     private void releaseRepositorySession(RepositoryInstance repoSession) {
941         try {
942             NuxeoClientEmbedded client = NuxeoConnectorEmbedded.getInstance().getClient();
943             // release session
944             client.releaseRepository(repoSession);
945         } catch (Exception e) {
946             logger.error("Could not close the repository session", e);
947             // no need to throw this service specific exception
948         }
949     }
950
951 }