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