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:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 package org.collectionspace.services.nuxeo.client.java;
20 import java.util.UUID;
22 import org.collectionspace.services.common.context.ServiceContext;
23 import org.collectionspace.services.common.document.BadRequestException;
24 import org.collectionspace.services.common.document.DocumentException;
25 import org.collectionspace.services.common.document.DocumentFilter;
26 import org.collectionspace.services.common.document.DocumentHandler;
27 import org.collectionspace.services.common.document.DocumentNotFoundException;
28 import org.collectionspace.services.common.repository.RepositoryClient;
29 import org.collectionspace.services.common.document.DocumentHandler.Action;
30 import org.collectionspace.services.common.document.DocumentWrapper;
31 import org.collectionspace.services.common.document.DocumentWrapperImpl;
32 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
33 import org.nuxeo.common.utils.IdUtils;
34 import org.nuxeo.ecm.core.api.ClientException;
35 import org.nuxeo.ecm.core.api.DocumentModel;
36 import org.nuxeo.ecm.core.api.DocumentModelList;
37 import org.nuxeo.ecm.core.api.DocumentRef;
38 import org.nuxeo.ecm.core.api.IdRef;
39 import org.nuxeo.ecm.core.api.PathRef;
40 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
41 import org.nuxeo.ecm.core.client.NuxeoClient;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 * RepositoryJavaClient is used to perform CRUD operations on documents in Nuxeo
47 * repository using Remote Java APIs. It uses @see DocumentHandler as IOHandler
50 * $LastChangedRevision: $ $LastChangedDate: $
52 public class RepositoryJavaClient implements RepositoryClient {
54 private final Logger logger = LoggerFactory.getLogger(RepositoryJavaClient.class);
56 public RepositoryJavaClient() {
60 * create document in the Nuxeo repository
62 * @param ctx service context under which this method is invoked
64 * of the document created
66 * should be used by the caller to provide and transform the
68 * @return id in repository of the newly created document
69 * @throws DocumentException
72 public String create(ServiceContext ctx,
73 DocumentHandler handler) throws BadRequestException,
76 if (ctx.getDocumentType() == null) {
77 throw new IllegalArgumentException(
78 "RepositoryJavaClient.create: docType is missing");
80 if (handler == null) {
81 throw new IllegalArgumentException(
82 "RepositoryJavaClient.create: handler is missing");
84 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
85 if (nuxeoWspaceId == null) {
86 throw new DocumentNotFoundException(
87 "Unable to find workspace for service " + ctx.getServiceName() +
88 " check if the workspace exists in the Nuxeo repository");
90 RepositoryInstance repoSession = null;
92 handler.prepare(Action.CREATE);
93 repoSession = getRepositorySession();
94 DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);
95 DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);
96 String wspacePath = wspaceDoc.getPathAsString();
97 //give our own ID so PathRef could be constructed later on
98 String id = IdUtils.generateId(UUID.randomUUID().toString());
99 // create document model
100 DocumentModel doc = repoSession.createDocumentModel(wspacePath, id,
101 ctx.getDocumentType());
102 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
103 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
104 handler.handle(Action.CREATE, wrapDoc);
105 // create document with documentmodel
106 doc = repoSession.createDocument(doc);
108 handler.complete(Action.CREATE, wrapDoc);
110 } catch (Exception e) {
111 if (logger.isDebugEnabled()) {
112 logger.debug("Caught exception ", e);
114 throw new DocumentException(e);
116 if (repoSession != null) {
117 releaseRepositorySession(repoSession);
124 * get document from the Nuxeo repository
125 * @param ctx service context under which this method is invoked
127 * of the document to retrieve
129 * should be used by the caller to provide and transform the
131 * @throws DocumentException
134 public void get(ServiceContext ctx, String id, DocumentHandler handler)
135 throws DocumentNotFoundException, DocumentException {
137 if (handler == null) {
138 throw new IllegalArgumentException(
139 "RepositoryJavaClient.get: handler is missing");
141 RepositoryInstance repoSession = null;
144 handler.prepare(Action.GET);
145 repoSession = getRepositorySession();
146 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
147 DocumentModel doc = null;
149 doc = repoSession.getDocument(docRef);
150 } catch (ClientException ce) {
151 String msg = "could not find document with id=" + id;
152 logger.error(msg, ce);
153 throw new DocumentNotFoundException(msg, ce);
155 //set reposession to handle the document
156 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
157 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
158 handler.handle(Action.GET, wrapDoc);
159 handler.complete(Action.GET, wrapDoc);
160 } catch (IllegalArgumentException iae) {
162 } catch (DocumentException de) {
164 } catch (Exception e) {
165 if (logger.isDebugEnabled()) {
166 logger.debug("Caught exception ", e);
168 throw new DocumentException(e);
170 if (repoSession != null) {
171 releaseRepositorySession(repoSession);
177 * getAll get all documents for an entity entity service from the Nuxeo
180 * @param ctx service context under which this method is invoked
182 * should be used by the caller to provide and transform the
184 * @throws DocumentException
187 public void getAll(ServiceContext ctx, DocumentHandler handler)
188 throws DocumentNotFoundException, DocumentException {
189 if (handler == null) {
190 throw new IllegalArgumentException(
191 "RepositoryJavaClient.getAll: handler is missing");
193 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
194 if (nuxeoWspaceId == null) {
195 throw new DocumentNotFoundException(
196 "Unable to find workspace for service " +
197 ctx.getServiceName() +
198 " check if the workspace exists in the Nuxeo repository");
200 RepositoryInstance repoSession = null;
203 handler.prepare(Action.GET_ALL);
204 repoSession = getRepositorySession();
205 DocumentRef wsDocRef = new IdRef(nuxeoWspaceId);
206 DocumentModelList docList = repoSession.getChildren(wsDocRef);
207 //set reposession to handle the document
208 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
209 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
210 handler.handle(Action.GET_ALL, wrapDoc);
211 handler.complete(Action.GET_ALL, wrapDoc);
212 } catch (DocumentException de) {
214 } catch (Exception e) {
215 if (logger.isDebugEnabled()) {
216 logger.debug("Caught exception ", e);
218 throw new DocumentException(e);
220 if (repoSession != null) {
221 releaseRepositorySession(repoSession);
227 * getFiltered get all documents for an entity service from the Document repository,
228 * given filter parameters specified by the handler.
229 * @param ctx service context under which this method is invoked
230 * @param handler should be used by the caller to provide and transform the document
231 * @throws DocumentNotFoundException if workspace not found
232 * @throws DocumentException
234 public void getFiltered(ServiceContext ctx, DocumentHandler handler)
235 throws DocumentNotFoundException, DocumentException {
236 if (handler == null) {
237 throw new IllegalArgumentException(
238 "RepositoryJavaClient.getFiltered: handler is missing");
240 DocumentFilter docFilter = handler.getDocumentFilter();
241 if (docFilter == null) {
242 throw new IllegalArgumentException(
243 "RepositoryJavaClient.getFiltered: handler has no Filter specified");
245 String docType = ctx.getDocumentType();
246 if (docType == null) {
247 throw new DocumentNotFoundException(
248 "Unable to find DocumentType for service " + ctx.getServiceName());
250 String domain = ctx.getRepositoryDomainName();
251 if (domain == null) {
252 throw new DocumentNotFoundException(
253 "Unable to find Domain for service " + ctx.getServiceName());
255 RepositoryInstance repoSession = null;
257 handler.prepare(Action.GET_ALL);
258 repoSession = getRepositorySession();
259 StringBuilder query = new StringBuilder("SELECT * FROM ");
260 query.append(docType);
261 String where = docFilter.getWhereClause();
262 // TODO This is a slow method for tenant-filter
263 // We should make this a property that is indexed.
264 query.append(" WHERE ecm:path STARTSWITH '/" + domain + "'");
265 if ((null != where) && (where.length() > 0)) {
266 // query.append(" AND " + where);
267 query.append(" AND " + where + "AND ecm:isProxy = 0");
269 DocumentModelList docList = null;
270 if ((docFilter.getOffset() > 0) || (docFilter.getPageSize() > 0)) {
271 docList = repoSession.query(query.toString(), null,
272 docFilter.getPageSize(), docFilter.getOffset(), false);
274 docList = repoSession.query(query.toString());
276 //set repoSession to handle the document
277 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
278 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
279 handler.handle(Action.GET_ALL, wrapDoc);
280 handler.complete(Action.GET_ALL, wrapDoc);
281 } catch (DocumentException de) {
283 } catch (Exception e) {
284 if (logger.isDebugEnabled()) {
285 logger.debug("Caught exception ", e);
287 throw new DocumentException(e);
289 if (repoSession != null) {
290 releaseRepositorySession(repoSession);
296 * update given document in the Nuxeo repository
298 * @param ctx service context under which this method is invoked
302 * should be used by the caller to provide and transform the
304 * @throws DocumentException
307 public void update(ServiceContext ctx, String id, DocumentHandler handler)
308 throws BadRequestException, DocumentNotFoundException,
310 if (handler == null) {
311 throw new IllegalArgumentException(
312 "RepositoryJavaClient.update: handler is missing");
314 RepositoryInstance repoSession = null;
316 handler.prepare(Action.UPDATE);
317 repoSession = getRepositorySession();
318 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
319 DocumentModel doc = null;
321 doc = repoSession.getDocument(docRef);
322 } catch (ClientException ce) {
323 String msg = "Could not find document to update with id=" + id;
324 logger.error(msg, ce);
325 throw new DocumentNotFoundException(msg, ce);
327 //set reposession to handle the document
328 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
329 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
330 handler.handle(Action.UPDATE, wrapDoc);
331 repoSession.saveDocument(doc);
333 handler.complete(Action.UPDATE, wrapDoc);
334 } catch (DocumentException de) {
336 } catch (Exception e) {
337 if (logger.isDebugEnabled()) {
338 logger.debug("Caught exception ", e);
340 throw new DocumentException(e);
342 if (repoSession != null) {
343 releaseRepositorySession(repoSession);
349 * delete a document from the Nuxeo repository
350 * @param ctx service context under which this method is invoked
353 * @throws DocumentException
356 public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException,
359 if (logger.isDebugEnabled()) {
360 logger.debug("deleting document with id=" + id);
362 RepositoryInstance repoSession = null;
364 repoSession = getRepositorySession();
365 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
367 repoSession.removeDocument(docRef);
368 } catch (ClientException ce) {
369 String msg = "could not find document to delete with id=" + id;
370 logger.error(msg, ce);
371 throw new DocumentNotFoundException(msg, ce);
374 } catch (DocumentException de) {
376 } catch (Exception e) {
377 if (logger.isDebugEnabled()) {
378 logger.debug("Caught exception ", e);
380 throw new DocumentException(e);
382 if (repoSession != null) {
383 releaseRepositorySession(repoSession);
389 public String createWorkspace(String tenantDomain, String workspaceName) throws Exception {
390 RepositoryInstance repoSession = null;
391 String workspaceId = null;
393 repoSession = getRepositorySession();
394 DocumentRef docRef = new PathRef(
397 DocumentModel parent = repoSession.getDocument(docRef);
398 DocumentModel doc = repoSession.createDocumentModel(parent.getPathAsString(),
399 workspaceName, "Workspace");
400 doc.setPropertyValue("dc:title", workspaceName);
401 doc.setPropertyValue("dc:description", "A CollectionSpace workspace for " +
403 doc = repoSession.createDocument(doc);
404 workspaceId = doc.getId();
406 if (logger.isDebugEnabled()) {
407 logger.debug("created workspace name=" + workspaceName +
408 " id=" + workspaceId);
410 } catch (Exception e) {
411 if (logger.isDebugEnabled()) {
412 logger.debug("createWorkspace caught exception ", e);
416 if (repoSession != null) {
417 releaseRepositorySession(repoSession);
424 public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
425 String workspaceId = null;
426 RepositoryInstance repoSession = null;
428 repoSession = getRepositorySession();
429 DocumentRef docRef = new PathRef(
432 "/" + workspaceName);
433 DocumentModel workspace = repoSession.getDocument(docRef);
434 workspaceId = workspace.getId();
435 } catch (DocumentException de) {
437 } catch (Exception e) {
438 if (logger.isDebugEnabled()) {
439 logger.debug("Caught exception ", e);
441 throw new DocumentException(e);
443 if (repoSession != null) {
444 releaseRepositorySession(repoSession);
450 private RepositoryInstance getRepositorySession() throws Exception {
451 // FIXME: is it possible to reuse repository session?
452 // Authentication failures happen while trying to reuse the session
453 NuxeoClient client = NuxeoConnector.getInstance().getClient();
454 RepositoryInstance repoSession = client.openRepository();
455 if (logger.isDebugEnabled()) {
456 logger.debug("getRepository() repository root: " + repoSession.getRootDocument());
461 private void releaseRepositorySession(RepositoryInstance repoSession) {
463 NuxeoClient client = NuxeoConnector.getInstance().getClient();
465 client.releaseRepository(repoSession);
466 } catch (Exception e) {
467 logger.error("Could not close the repository session", e);
468 // no need to throw this service specific exception