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