]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
620fa66aac98fe07949136391da28484f9544805
[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     @Override
181     public void get(ServiceContext ctx, List<String> csidList, DocumentHandler handler)
182                 throws DocumentNotFoundException, DocumentException {
183         if (handler == null) {
184             throw new IllegalArgumentException(
185                     "RepositoryJavaClient.getAll: handler is missing");
186         }
187
188         RepositoryInstance repoSession = null;
189
190         try {
191             handler.prepare(Action.GET_ALL);
192             repoSession = getRepositorySession();
193             DocumentModelList docModelList = new DocumentModelListImpl();
194             //FIXME: Should be using NuxeoUtils.createPathRef for security reasons
195             for (String csid : csidList) {
196                 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, csid);
197                 DocumentModel docModel = repoSession.getDocument(docRef);
198                 docModelList.add(docModel);
199             }
200
201             //set reposession to handle the document
202             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
203             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docModelList);
204             handler.handle(Action.GET_ALL, wrapDoc);
205             handler.complete(Action.GET_ALL, wrapDoc);
206         } catch (DocumentException de) {
207             throw de;
208         } catch (Exception e) {
209             if (logger.isDebugEnabled()) {
210                 logger.debug("Caught exception ", e);
211             }
212             throw new DocumentException(e);
213         } finally {
214             if (repoSession != null) {
215                 releaseRepositorySession(repoSession);
216             }
217         }
218     }
219     
220     /**
221      * getAll get all documents for an entity entity service from the Nuxeo
222      * repository
223      *
224      * @param ctx service context under which this method is invoked
225      * @param handler
226      *            should be used by the caller to provide and transform the
227      *            document
228      * @throws DocumentException
229      */
230     @Override
231     public void getAll(ServiceContext ctx, DocumentHandler handler)
232             throws DocumentNotFoundException, DocumentException {
233         if (handler == null) {
234             throw new IllegalArgumentException(
235                     "RepositoryJavaClient.getAll: handler is missing");
236         }
237         String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
238         if (nuxeoWspaceId == null) {
239             throw new DocumentNotFoundException(
240                     "Unable to find workspace for service "
241                     + ctx.getServiceName()
242                     + " check if the workspace exists in the Nuxeo repository");
243         }
244         RepositoryInstance repoSession = null;
245
246         try {
247             handler.prepare(Action.GET_ALL);
248             repoSession = getRepositorySession();
249             DocumentRef wsDocRef = new IdRef(nuxeoWspaceId);
250             DocumentModelList docList = repoSession.getChildren(wsDocRef);
251             //set reposession to handle the document
252             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
253             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
254             handler.handle(Action.GET_ALL, wrapDoc);
255             handler.complete(Action.GET_ALL, wrapDoc);
256         } catch (DocumentException de) {
257             throw de;
258         } catch (Exception e) {
259             if (logger.isDebugEnabled()) {
260                 logger.debug("Caught exception ", e);
261             }
262             throw new DocumentException(e);
263         } finally {
264             if (repoSession != null) {
265                 releaseRepositorySession(repoSession);
266             }
267         }
268     }
269
270     /**
271      * getFiltered get all documents for an entity service from the Document repository,
272      * given filter parameters specified by the handler. 
273      * @param ctx service context under which this method is invoked
274      * @param handler should be used by the caller to provide and transform the document
275      * @throws DocumentNotFoundException if workspace not found
276      * @throws DocumentException
277      */
278     public void getFiltered(ServiceContext ctx, DocumentHandler handler)
279             throws DocumentNotFoundException, DocumentException {
280         if (handler == null) {
281             throw new IllegalArgumentException(
282                     "RepositoryJavaClient.getFiltered: handler is missing");
283         }
284         DocumentFilter docFilter = handler.getDocumentFilter();
285         if (docFilter == null) {
286             throw new IllegalArgumentException(
287                     "RepositoryJavaClient.getFiltered: handler has no Filter specified");
288         }
289         String docType = ctx.getDocumentType();
290         if (docType == null) {
291             throw new DocumentNotFoundException(
292                     "Unable to find DocumentType for service " + ctx.getServiceName());
293         }
294         String domain = ctx.getRepositoryDomainName();
295         if (domain == null) {
296             throw new DocumentNotFoundException(
297                     "Unable to find Domain for service " + ctx.getServiceName());
298         }
299         RepositoryInstance repoSession = null;
300         try {
301             handler.prepare(Action.GET_ALL);
302             repoSession = getRepositorySession();
303             StringBuilder query = new StringBuilder("SELECT * FROM ");
304             query.append(docType);
305             String where = docFilter.getWhereClause();
306             // TODO This is a slow method for tenant-filter
307             // We should make this a property that is indexed.
308             query.append(" WHERE ecm:path STARTSWITH '/" + domain + "'");
309             if ((null != where) && (where.length() > 0)) {
310                 // Due to an apparent bug/issue in how Nuxeo translates the NXQL query string
311                 // into SQL, we need to parenthesize our 'where' clause
312                 query.append(" AND " + "(" + where +")" + "AND ecm:isProxy = 0");
313             }
314             DocumentModelList docList = null;
315             // If we have limit and/or offset, then pass true to get totalSize
316             // in returned DocumentModelList.
317             if ((docFilter.getOffset() > 0) || (docFilter.getPageSize() > 0)) {
318                 docList = repoSession.query(query.toString(), null,
319                         docFilter.getPageSize(), docFilter.getOffset(), true);
320             } else {
321                 docList = repoSession.query(query.toString());
322             }
323             
324             if (logger.isDebugEnabled()) {
325                 logger.debug("Executed NXQL query: " + query.toString());
326             }
327             
328             //set repoSession to handle the document
329             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
330             DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
331             handler.handle(Action.GET_ALL, wrapDoc);
332             handler.complete(Action.GET_ALL, wrapDoc);
333         } catch (DocumentException de) {
334             throw de;
335         } catch (Exception e) {
336             if (logger.isDebugEnabled()) {
337                 logger.debug("Caught exception ", e);
338             }
339             throw new DocumentException(e);
340         } finally {
341             if (repoSession != null) {
342                 releaseRepositorySession(repoSession);
343             }
344         }
345     }
346
347     /**
348      * update given document in the Nuxeo repository
349      *
350      * @param ctx service context under which this method is invoked
351      * @param id
352      *            of the document
353      * @param handler
354      *            should be used by the caller to provide and transform the
355      *            document
356      * @throws DocumentException
357      */
358     @Override
359     public void update(ServiceContext ctx, String id, DocumentHandler handler)
360             throws BadRequestException, DocumentNotFoundException,
361             DocumentException {
362         if (handler == null) {
363             throw new IllegalArgumentException(
364                     "RepositoryJavaClient.update: handler is missing");
365         }
366         RepositoryInstance repoSession = null;
367         try {
368             handler.prepare(Action.UPDATE);
369             repoSession = getRepositorySession();
370             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
371             DocumentModel doc = null;
372             try {
373                 doc = repoSession.getDocument(docRef);
374             } catch (ClientException ce) {
375                 String msg = "Could not find document to update with id=" + id;
376                 logger.error(msg, ce);
377                 throw new DocumentNotFoundException(msg, ce);
378             }
379             //set reposession to handle the document
380             ((DocumentModelHandler) handler).setRepositorySession(repoSession);
381             DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
382             handler.handle(Action.UPDATE, wrapDoc);
383             repoSession.saveDocument(doc);
384             repoSession.save();
385             handler.complete(Action.UPDATE, wrapDoc);
386         } catch (BadRequestException bre) {
387             throw bre;
388         } catch (DocumentException de) {
389             throw de;
390         } catch (Exception e) {
391             if (logger.isDebugEnabled()) {
392                 logger.debug("Caught exception ", e);
393             }
394             throw new DocumentException(e);
395         } finally {
396             if (repoSession != null) {
397                 releaseRepositorySession(repoSession);
398             }
399         }
400     }
401
402     /**
403      * delete a document from the Nuxeo repository
404      * @param ctx service context under which this method is invoked
405      * @param id
406      *            of the document
407      * @throws DocumentException
408      */
409     @Override
410     public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException,
411             DocumentException {
412
413         if (logger.isDebugEnabled()) {
414             logger.debug("deleting document with id=" + id);
415         }
416         RepositoryInstance repoSession = null;
417         try {
418             repoSession = getRepositorySession();
419             DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
420             try {
421                 repoSession.removeDocument(docRef);
422             } catch (ClientException ce) {
423                 String msg = "could not find document to delete with id=" + id;
424                 logger.error(msg, ce);
425                 throw new DocumentNotFoundException(msg, ce);
426             }
427             repoSession.save();
428         } catch (DocumentException de) {
429             throw de;
430         } catch (Exception e) {
431             if (logger.isDebugEnabled()) {
432                 logger.debug("Caught exception ", e);
433             }
434             throw new DocumentException(e);
435         } finally {
436             if (repoSession != null) {
437                 releaseRepositorySession(repoSession);
438             }
439         }
440     }
441
442     @Override
443     public String createWorkspace(String tenantDomain, String workspaceName) throws Exception {
444         RepositoryInstance repoSession = null;
445         String workspaceId = null;
446         try {
447             repoSession = getRepositorySession();
448             DocumentRef docRef = new PathRef(
449                     "/" + tenantDomain
450                     + "/" + "workspaces");
451             DocumentModel parent = repoSession.getDocument(docRef);
452             DocumentModel doc = repoSession.createDocumentModel(parent.getPathAsString(),
453                     workspaceName, "Workspace");
454             doc.setPropertyValue("dc:title", workspaceName);
455             doc.setPropertyValue("dc:description", "A CollectionSpace workspace for "
456                     + workspaceName);
457             doc = repoSession.createDocument(doc);
458             workspaceId = doc.getId();
459             repoSession.save();
460             if (logger.isDebugEnabled()) {
461                 logger.debug("created workspace name=" + workspaceName
462                         + " id=" + workspaceId);
463             }
464         } catch (Exception e) {
465             if (logger.isDebugEnabled()) {
466                 logger.debug("createWorkspace caught exception ", e);
467             }
468             throw e;
469         } finally {
470             if (repoSession != null) {
471                 releaseRepositorySession(repoSession);
472             }
473         }
474         return workspaceId;
475     }
476
477     @Override
478     public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
479         String workspaceId = null;
480         RepositoryInstance repoSession = null;
481         try {
482             repoSession = getRepositorySession();
483             DocumentRef docRef = new PathRef(
484                     "/" + tenantDomain
485                     + "/" + "workspaces"
486                     + "/" + workspaceName);
487             DocumentModel workspace = repoSession.getDocument(docRef);
488             workspaceId = workspace.getId();
489         } catch (DocumentException de) {
490             throw de;
491         } catch (Exception e) {
492             if (logger.isDebugEnabled()) {
493                 logger.debug("Caught exception ", e);
494             }
495             throw new DocumentException(e);
496         } finally {
497             if (repoSession != null) {
498                 releaseRepositorySession(repoSession);
499             }
500         }
501         return workspaceId;
502     }
503
504     private RepositoryInstance getRepositorySession() throws Exception {
505         // FIXME: is it possible to reuse repository session?
506         // Authentication failures happen while trying to reuse the session
507         NuxeoClient client = NuxeoConnector.getInstance().getClient();
508         RepositoryInstance repoSession = client.openRepository();
509         if (logger.isDebugEnabled()) {
510             logger.debug("getRepository() repository root: " + repoSession.getRootDocument());
511         }
512         return repoSession;
513     }
514
515     private void releaseRepositorySession(RepositoryInstance repoSession) {
516         try {
517             NuxeoClient client = NuxeoConnector.getInstance().getClient();
518             // release session
519             client.releaseRepository(repoSession);
520         } catch (Exception e) {
521             logger.error("Could not close the repository session", e);
522             // no need to throw this service specific exception
523         }
524     }
525 }