]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
a2d05fa2cc63fd6bf600ee225a9dc23ae223fc7d
[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.context.ServiceContext;
24 import org.collectionspace.services.common.document.BadRequestException;
25 import org.collectionspace.services.common.document.DocumentException;
26 import org.collectionspace.services.common.document.DocumentFilter;
27 import org.collectionspace.services.common.document.DocumentHandler;
28 import org.collectionspace.services.common.document.DocumentNotFoundException;
29 import org.collectionspace.services.common.repository.RepositoryClient;
30 import org.collectionspace.services.common.document.DocumentHandler.Action;
31 import org.collectionspace.services.common.document.DocumentWrapper;
32 import org.collectionspace.services.common.document.DocumentWrapperImpl;
33 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
34 import org.nuxeo.common.utils.IdUtils;
35 import org.nuxeo.ecm.core.api.ClientException;
36 import org.nuxeo.ecm.core.api.DocumentModel;
37 import org.nuxeo.ecm.core.api.DocumentModelList;
38 import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
39 import org.nuxeo.ecm.core.api.DocumentRef;
40 import org.nuxeo.ecm.core.api.IdRef;
41 import org.nuxeo.ecm.core.api.PathRef;
42 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
43 import org.nuxeo.ecm.core.client.NuxeoClient;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * RepositoryJavaClient is used to perform CRUD operations on documents in Nuxeo
49  * repository using Remote Java APIs. It uses @see DocumentHandler as IOHandler
50  * with the client.
51  * 
52  * $LastChangedRevision: $ $LastChangedDate: $
53  */
54 public class RepositoryJavaClientImpl implements RepositoryClient {
55
56     private final Logger logger = LoggerFactory.getLogger(RepositoryJavaClientImpl.class);
57
58     public RepositoryJavaClientImpl() {
59     }
60
61     /**
62      * create document in the Nuxeo repository
63      *
64      * @param ctx service context under which this method is invoked
65      * @param docType
66      *            of the document created
67      * @param handler
68      *            should be used by the caller to provide and transform the
69      *            document
70      * @return id in repository of the newly created document
71      * @throws DocumentException
72      */
73     @Override
74     public String create(ServiceContext ctx,
75             DocumentHandler handler) throws BadRequestException,
76             DocumentException {
77
78         if (ctx.getDocumentType() == null) {
79             throw new IllegalArgumentException(
80                     "RepositoryJavaClient.create: docType is missing");
81         }
82         if (handler == null) {
83             throw new IllegalArgumentException(
84                     "RepositoryJavaClient.create: handler is missing");
85         }
86         String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
87         if (nuxeoWspaceId == null) {
88             throw new DocumentNotFoundException(
89                     "Unable to find workspace for service " + ctx.getServiceName()
90                     + " check if the workspace exists in the Nuxeo repository");
91         }
92         RepositoryInstance repoSession = null;
93         try {
94             handler.prepare(Action.CREATE);
95             repoSession = getRepositorySession();
96             DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);
97             DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);
98             String wspacePath = wspaceDoc.getPathAsString();
99             //give our own ID so PathRef could be constructed later on
100             String id = IdUtils.generateId(UUID.randomUUID().toString());
101             // create document model
102             DocumentModel doc = repoSession.createDocumentModel(wspacePath, id,
103                     ctx.getDocumentType());
104             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
105             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
106             handler.handle(Action.CREATE, wrapDoc);
107             // create document with documentmodel
108             doc = repoSession.createDocument(doc);
109             repoSession.save();
110             handler.complete(Action.CREATE, wrapDoc);
111             return id;
112         } catch (BadRequestException bre) {
113             throw bre;
114         } catch (Exception e) {
115             if (logger.isDebugEnabled()) {
116                 logger.debug("Caught exception ", e);
117             }
118             throw new DocumentException(e);
119         } finally {
120             if (repoSession != null) {
121                 releaseRepositorySession(repoSession);
122             }
123         }
124
125     }
126     
127     /**
128      * get document from the Nuxeo repository
129      * @param ctx service context under which this method is invoked
130      * @param id
131      *            of the document to retrieve
132      * @param handler
133      *            should be used by the caller to provide and transform the
134      *            document
135      * @throws DocumentException
136      */
137     @Override
138     public void get(ServiceContext ctx, String id, DocumentHandler handler)
139             throws DocumentNotFoundException, DocumentException {
140
141         if (handler == null) {
142             throw new IllegalArgumentException(
143                     "RepositoryJavaClient.get: handler is missing");
144         }
145         RepositoryInstance repoSession = null;
146
147         try {
148             handler.prepare(Action.GET);
149             repoSession = getRepositorySession();
150             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
151             DocumentModel doc = null;
152             try {
153                 doc = repoSession.getDocument(docRef);
154             } catch (ClientException ce) {
155                 String msg = "could not find document with id=" + id;
156                 logger.error(msg, ce);
157                 throw new DocumentNotFoundException(msg, ce);
158             }
159             //set reposession to handle the document
160             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
161             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
162             handler.handle(Action.GET, wrapDoc);
163             handler.complete(Action.GET, wrapDoc);
164         } catch (IllegalArgumentException iae) {
165             throw iae;
166         } catch (DocumentException de) {
167             throw de;
168         } catch (Exception e) {
169             if (logger.isDebugEnabled()) {
170                 logger.debug("Caught exception ", e);
171             }
172             throw new DocumentException(e);
173         } finally {
174             if (repoSession != null) {
175                 releaseRepositorySession(repoSession);
176             }
177         }
178     }
179
180     /**
181      * get wrapped documentModel from the Nuxeo repository
182      * @param ctx service context under which this method is invoked
183      * @param id
184      *            of the document to retrieve
185      * @throws DocumentException
186      */
187     @Override
188     public DocumentWrapper<DocumentModel> getDoc(
189                 ServiceContext ctx, String id)
190             throws DocumentNotFoundException, DocumentException {
191         RepositoryInstance repoSession = null;
192         DocumentWrapper<DocumentModel> wrapDoc = null;
193
194         try {
195             repoSession = getRepositorySession();
196             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
197             DocumentModel doc = null;
198             try {
199                 doc = repoSession.getDocument(docRef);
200             } catch (ClientException ce) {
201                 String msg = "could not find document with id=" + id;
202                 logger.error(msg, ce);
203                 throw new DocumentNotFoundException(msg, ce);
204             }
205             wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
206         } catch (IllegalArgumentException iae) {
207             throw iae;
208         } catch (DocumentException de) {
209             throw de;
210         } catch (Exception e) {
211             if (logger.isDebugEnabled()) {
212                 logger.debug("Caught exception ", e);
213             }
214             throw new DocumentException(e);
215         } finally {
216             if (repoSession != null) {
217                 releaseRepositorySession(repoSession);
218             }
219         }
220         return wrapDoc;
221     }
222
223     @Override
224     public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
225                 throws DocumentNotFoundException, DocumentException {
226         if (handler == null) {
227             throw new IllegalArgumentException(
228                     "RepositoryJavaClient.getAll: handler is missing");
229         }
230
231         RepositoryInstance repoSession = null;
232
233         try {
234             handler.prepare(Action.GET_ALL);
235             repoSession = getRepositorySession();
236             DocumentModelList docModelList = new DocumentModelListImpl();
237             //FIXME: Should be using NuxeoUtils.createPathRef for security reasons
238             for (String csid : csidList) {
239                 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
240                 DocumentModel docModel = repoSession.getDocument(docRef);
241                 docModelList.add(docModel);
242             }
243
244             //set reposession to handle the document
245             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
246             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docModelList);
247             handler.handle(Action.GET_ALL, wrapDoc);
248             handler.complete(Action.GET_ALL, wrapDoc);
249         } catch (DocumentException de) {
250             throw de;
251         } catch (Exception e) {
252             if (logger.isDebugEnabled()) {
253                 logger.debug("Caught exception ", e);
254             }
255             throw new DocumentException(e);
256         } finally {
257             if (repoSession != null) {
258                 releaseRepositorySession(repoSession);
259             }
260         }
261     }
262     
263     /**
264      * getAll get all documents for an entity entity service from the Nuxeo
265      * repository
266      *
267      * @param ctx service context under which this method is invoked
268      * @param handler
269      *            should be used by the caller to provide and transform the
270      *            document
271      * @throws DocumentException
272      */
273     @Override
274     public void getAll(ServiceContext ctx, DocumentHandler handler)
275             throws DocumentNotFoundException, DocumentException {
276         if (handler == null) {
277             throw new IllegalArgumentException(
278                     "RepositoryJavaClient.getAll: handler is missing");
279         }
280         String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
281         if (nuxeoWspaceId == null) {
282             throw new DocumentNotFoundException(
283                     "Unable to find workspace for service "
284                     + ctx.getServiceName()
285                     + " check if the workspace exists in the Nuxeo repository");
286         }
287         RepositoryInstance repoSession = null;
288
289         try {
290             handler.prepare(Action.GET_ALL);
291             repoSession = getRepositorySession();
292             DocumentRef wsDocRef = new IdRef(nuxeoWspaceId);
293             DocumentModelList docList = repoSession.getChildren(wsDocRef);
294             //set reposession to handle the document
295             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
296             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
297             handler.handle(Action.GET_ALL, wrapDoc);
298             handler.complete(Action.GET_ALL, wrapDoc);
299         } catch (DocumentException de) {
300             throw de;
301         } catch (Exception e) {
302             if (logger.isDebugEnabled()) {
303                 logger.debug("Caught exception ", e);
304             }
305             throw new DocumentException(e);
306         } finally {
307             if (repoSession != null) {
308                 releaseRepositorySession(repoSession);
309             }
310         }
311     }
312
313     /**
314      * getFiltered get all documents for an entity service from the Document repository,
315      * given filter parameters specified by the handler. 
316      * @param ctx service context under which this method is invoked
317      * @param handler should be used by the caller to provide and transform the document
318      * @throws DocumentNotFoundException if workspace not found
319      * @throws DocumentException
320      */
321     public void getFiltered(ServiceContext ctx, DocumentHandler handler)
322             throws DocumentNotFoundException, DocumentException {
323         if (handler == null) {
324             throw new IllegalArgumentException(
325                     "RepositoryJavaClient.getFiltered: handler is missing");
326         }
327         DocumentFilter docFilter = handler.getDocumentFilter();
328         if (docFilter == null) {
329             throw new IllegalArgumentException(
330                     "RepositoryJavaClient.getFiltered: handler has no Filter specified");
331         }
332         String docType = ctx.getDocumentType();
333         if (docType == null) {
334             throw new DocumentNotFoundException(
335                     "Unable to find DocumentType for service " + ctx.getServiceName());
336         }
337         String domain = ctx.getRepositoryDomainName();
338         if (domain == null) {
339             throw new DocumentNotFoundException(
340                     "Unable to find Domain for service " + ctx.getServiceName());
341         }
342         RepositoryInstance repoSession = null;
343         try {
344             handler.prepare(Action.GET_ALL);
345             repoSession = getRepositorySession();
346             StringBuilder query = new StringBuilder("SELECT * FROM ");
347             query.append(docType);
348             String where = docFilter.getWhereClause();
349             // TODO This is a slow method for tenant-filter
350             // We should make this a property that is indexed.
351             query.append(" WHERE ecm:path STARTSWITH '/" + domain + "'");
352             if ((null != where) && (where.length() > 0)) {
353                 // Due to an apparent bug/issue in how Nuxeo translates the NXQL query string
354                 // into SQL, we need to parenthesize our 'where' clause
355                 query.append(" AND " + "(" + where +")" + "AND ecm:isProxy = 0");
356             }
357             DocumentModelList docList = null;
358             // If we have limit and/or offset, then pass true to get totalSize
359             // in returned DocumentModelList.
360             if ((docFilter.getOffset() > 0) || (docFilter.getPageSize() > 0)) {
361                 docList = repoSession.query(query.toString(), null,
362                         docFilter.getPageSize(), docFilter.getOffset(), true);
363             } else {
364                 docList = repoSession.query(query.toString());
365             }
366             
367             if (logger.isDebugEnabled()) {
368                 logger.debug("Executed NXQL query: " + query.toString());
369             }
370             
371             //set repoSession to handle the document
372             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
373             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
374             handler.handle(Action.GET_ALL, wrapDoc);
375             handler.complete(Action.GET_ALL, wrapDoc);
376         } catch (DocumentException de) {
377             throw de;
378         } catch (Exception e) {
379             if (logger.isDebugEnabled()) {
380                 logger.debug("Caught exception ", e);
381             }
382             throw new DocumentException(e);
383         } finally {
384             if (repoSession != null) {
385                 releaseRepositorySession(repoSession);
386             }
387         }
388     }
389
390     /**
391      * update given document in the Nuxeo repository
392      *
393      * @param ctx service context under which this method is invoked
394      * @param id
395      *            of the document
396      * @param handler
397      *            should be used by the caller to provide and transform the
398      *            document
399      * @throws DocumentException
400      */
401     @Override
402     public void update(ServiceContext ctx, String id, DocumentHandler handler)
403             throws BadRequestException, DocumentNotFoundException,
404             DocumentException {
405         if (handler == null) {
406             throw new IllegalArgumentException(
407                     "RepositoryJavaClient.update: handler is missing");
408         }
409         RepositoryInstance repoSession = null;
410         try {
411             handler.prepare(Action.UPDATE);
412             repoSession = getRepositorySession();
413             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
414             DocumentModel doc = null;
415             try {
416                 doc = repoSession.getDocument(docRef);
417             } catch (ClientException ce) {
418                 String msg = "Could not find document to update with id=" + id;
419                 logger.error(msg, ce);
420                 throw new DocumentNotFoundException(msg, ce);
421             }
422             //set reposession to handle the document
423             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
424             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
425             handler.handle(Action.UPDATE, wrapDoc);
426             repoSession.saveDocument(doc);
427             repoSession.save();
428             handler.complete(Action.UPDATE, wrapDoc);
429         } catch (BadRequestException bre) {
430             throw bre;
431         } catch (DocumentException de) {
432             throw de;
433         } catch (Exception e) {
434             if (logger.isDebugEnabled()) {
435                 logger.debug("Caught exception ", e);
436             }
437             throw new DocumentException(e);
438         } finally {
439             if (repoSession != null) {
440                 releaseRepositorySession(repoSession);
441             }
442         }
443     }
444
445     /**
446      * delete a document from the Nuxeo repository
447      * @param ctx service context under which this method is invoked
448      * @param id
449      *            of the document
450      * @throws DocumentException
451      */
452     @Override
453     public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException,
454             DocumentException {
455
456         if (logger.isDebugEnabled()) {
457             logger.debug("deleting document with id=" + id);
458         }
459         RepositoryInstance repoSession = null;
460         try {
461             repoSession = getRepositorySession();
462             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
463             try {
464                 repoSession.removeDocument(docRef);
465             } catch (ClientException ce) {
466                 String msg = "could not find document to delete with id=" + id;
467                 logger.error(msg, ce);
468                 throw new DocumentNotFoundException(msg, ce);
469             }
470             repoSession.save();
471         } catch (DocumentException de) {
472             throw de;
473         } catch (Exception e) {
474             if (logger.isDebugEnabled()) {
475                 logger.debug("Caught exception ", e);
476             }
477             throw new DocumentException(e);
478         } finally {
479             if (repoSession != null) {
480                 releaseRepositorySession(repoSession);
481             }
482         }
483     }
484
485     @Override
486     public String createWorkspace(String tenantDomain, String workspaceName) throws Exception {
487         RepositoryInstance repoSession = null;
488         String workspaceId = null;
489         try {
490             repoSession = getRepositorySession();
491             DocumentRef docRef = new PathRef(
492                     "/" + tenantDomain
493                     + "/" + "workspaces");
494             DocumentModel parent = repoSession.getDocument(docRef);
495             DocumentModel doc = repoSession.createDocumentModel(parent.getPathAsString(),
496                     workspaceName, "Workspace");
497             doc.setPropertyValue("dc:title", workspaceName);
498             doc.setPropertyValue("dc:description", "A CollectionSpace workspace for "
499                     + workspaceName);
500             doc = repoSession.createDocument(doc);
501             workspaceId = doc.getId();
502             repoSession.save();
503             if (logger.isDebugEnabled()) {
504                 logger.debug("created workspace name=" + workspaceName
505                         + " id=" + workspaceId);
506             }
507         } catch (Exception e) {
508             if (logger.isDebugEnabled()) {
509                 logger.debug("createWorkspace caught exception ", e);
510             }
511             throw e;
512         } finally {
513             if (repoSession != null) {
514                 releaseRepositorySession(repoSession);
515             }
516         }
517         return workspaceId;
518     }
519
520     @Override
521     public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
522         String workspaceId = null;
523         RepositoryInstance repoSession = null;
524         try {
525             repoSession = getRepositorySession();
526             DocumentRef docRef = new PathRef(
527                     "/" + tenantDomain
528                     + "/" + "workspaces"
529                     + "/" + workspaceName);
530             DocumentModel workspace = repoSession.getDocument(docRef);
531             workspaceId = workspace.getId();
532         } catch (DocumentException de) {
533             throw de;
534         } catch (Exception e) {
535             if (logger.isDebugEnabled()) {
536                 logger.debug("Caught exception ", e);
537             }
538             throw new DocumentException(e);
539         } finally {
540             if (repoSession != null) {
541                 releaseRepositorySession(repoSession);
542             }
543         }
544         return workspaceId;
545     }
546
547     private RepositoryInstance getRepositorySession() throws Exception {
548         // FIXME: is it possible to reuse repository session?
549         // Authentication failures happen while trying to reuse the session
550         NuxeoClient client = NuxeoConnector.getInstance().getClient();
551         RepositoryInstance repoSession = client.openRepository();
552         if (logger.isDebugEnabled()) {
553             logger.debug("getRepository() repository root: " + repoSession.getRootDocument());
554         }
555         return repoSession;
556     }
557
558     private void releaseRepositorySession(RepositoryInstance repoSession) {
559         try {
560             NuxeoClient client = NuxeoConnector.getInstance().getClient();
561             // release session
562             client.releaseRepository(repoSession);
563         } catch (Exception e) {
564             logger.error("Could not close the repository session", e);
565             // no need to throw this service specific exception
566         }
567     }
568 }