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