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