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