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 (BadRequestException bre) {
112 } catch (Exception e) {
113 if (logger.isDebugEnabled()) {
114 logger.debug("Caught exception ", e);
116 throw new DocumentException(e);
118 if (repoSession != null) {
119 releaseRepositorySession(repoSession);
126 * get document from the Nuxeo repository
127 * @param ctx service context under which this method is invoked
129 * of the document to retrieve
131 * should be used by the caller to provide and transform the
133 * @throws DocumentException
136 public void get(ServiceContext ctx, String id, DocumentHandler handler)
137 throws DocumentNotFoundException, DocumentException {
139 if (handler == null) {
140 throw new IllegalArgumentException(
141 "RepositoryJavaClient.get: handler is missing");
143 RepositoryInstance repoSession = null;
146 handler.prepare(Action.GET);
147 repoSession = getRepositorySession();
148 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
149 DocumentModel doc = null;
151 doc = repoSession.getDocument(docRef);
152 } catch (ClientException ce) {
153 String msg = "could not find document with id=" + id;
154 logger.error(msg, ce);
155 throw new DocumentNotFoundException(msg, ce);
157 //set reposession to handle the document
158 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
159 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
160 handler.handle(Action.GET, wrapDoc);
161 handler.complete(Action.GET, wrapDoc);
162 } catch (IllegalArgumentException iae) {
164 } catch (DocumentException de) {
166 } catch (Exception e) {
167 if (logger.isDebugEnabled()) {
168 logger.debug("Caught exception ", e);
170 throw new DocumentException(e);
172 if (repoSession != null) {
173 releaseRepositorySession(repoSession);
179 * getAll get all documents for an entity entity service from the Nuxeo
182 * @param ctx service context under which this method is invoked
184 * should be used by the caller to provide and transform the
186 * @throws DocumentException
189 public void getAll(ServiceContext ctx, DocumentHandler handler)
190 throws DocumentNotFoundException, DocumentException {
191 if (handler == null) {
192 throw new IllegalArgumentException(
193 "RepositoryJavaClient.getAll: handler is missing");
195 String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
196 if (nuxeoWspaceId == null) {
197 throw new DocumentNotFoundException(
198 "Unable to find workspace for service "
199 + ctx.getServiceName()
200 + " check if the workspace exists in the Nuxeo repository");
202 RepositoryInstance repoSession = null;
205 handler.prepare(Action.GET_ALL);
206 repoSession = getRepositorySession();
207 DocumentRef wsDocRef = new IdRef(nuxeoWspaceId);
208 DocumentModelList docList = repoSession.getChildren(wsDocRef);
209 //set reposession to handle the document
210 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
211 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
212 handler.handle(Action.GET_ALL, wrapDoc);
213 handler.complete(Action.GET_ALL, wrapDoc);
214 } catch (DocumentException de) {
216 } catch (Exception e) {
217 if (logger.isDebugEnabled()) {
218 logger.debug("Caught exception ", e);
220 throw new DocumentException(e);
222 if (repoSession != null) {
223 releaseRepositorySession(repoSession);
229 * getFiltered get all documents for an entity service from the Document repository,
230 * given filter parameters specified by the handler.
231 * @param ctx service context under which this method is invoked
232 * @param handler should be used by the caller to provide and transform the document
233 * @throws DocumentNotFoundException if workspace not found
234 * @throws DocumentException
236 public void getFiltered(ServiceContext ctx, DocumentHandler handler)
237 throws DocumentNotFoundException, DocumentException {
238 if (handler == null) {
239 throw new IllegalArgumentException(
240 "RepositoryJavaClient.getFiltered: handler is missing");
242 DocumentFilter docFilter = handler.getDocumentFilter();
243 if (docFilter == null) {
244 throw new IllegalArgumentException(
245 "RepositoryJavaClient.getFiltered: handler has no Filter specified");
247 String docType = ctx.getDocumentType();
248 if (docType == null) {
249 throw new DocumentNotFoundException(
250 "Unable to find DocumentType for service " + ctx.getServiceName());
252 String domain = ctx.getRepositoryDomainName();
253 if (domain == null) {
254 throw new DocumentNotFoundException(
255 "Unable to find Domain for service " + ctx.getServiceName());
257 RepositoryInstance repoSession = null;
259 handler.prepare(Action.GET_ALL);
260 repoSession = getRepositorySession();
261 StringBuilder query = new StringBuilder("SELECT * FROM ");
262 query.append(docType);
263 String where = docFilter.getWhereClause();
264 // TODO This is a slow method for tenant-filter
265 // We should make this a property that is indexed.
266 query.append(" WHERE ecm:path STARTSWITH '/" + domain + "'");
267 if ((null != where) && (where.length() > 0)) {
268 // query.append(" AND " + where);
269 query.append(" AND " + where + "AND ecm:isProxy = 0");
271 DocumentModelList docList = null;
272 if ((docFilter.getOffset() > 0) || (docFilter.getPageSize() > 0)) {
273 docList = repoSession.query(query.toString(), null,
274 docFilter.getPageSize(), docFilter.getOffset(), false);
276 docList = repoSession.query(query.toString());
278 //set repoSession to handle the document
279 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
280 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
281 handler.handle(Action.GET_ALL, wrapDoc);
282 handler.complete(Action.GET_ALL, wrapDoc);
283 } catch (DocumentException de) {
285 } catch (Exception e) {
286 if (logger.isDebugEnabled()) {
287 logger.debug("Caught exception ", e);
289 throw new DocumentException(e);
291 if (repoSession != null) {
292 releaseRepositorySession(repoSession);
298 * update given document in the Nuxeo repository
300 * @param ctx service context under which this method is invoked
304 * should be used by the caller to provide and transform the
306 * @throws DocumentException
309 public void update(ServiceContext ctx, String id, DocumentHandler handler)
310 throws BadRequestException, DocumentNotFoundException,
312 if (handler == null) {
313 throw new IllegalArgumentException(
314 "RepositoryJavaClient.update: handler is missing");
316 RepositoryInstance repoSession = null;
318 handler.prepare(Action.UPDATE);
319 repoSession = getRepositorySession();
320 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
321 DocumentModel doc = null;
323 doc = repoSession.getDocument(docRef);
324 } catch (ClientException ce) {
325 String msg = "Could not find document to update with id=" + id;
326 logger.error(msg, ce);
327 throw new DocumentNotFoundException(msg, ce);
329 //set reposession to handle the document
330 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
331 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
332 handler.handle(Action.UPDATE, wrapDoc);
333 repoSession.saveDocument(doc);
335 handler.complete(Action.UPDATE, wrapDoc);
336 } catch (BadRequestException bre) {
338 } catch (DocumentException de) {
340 } catch (Exception e) {
341 if (logger.isDebugEnabled()) {
342 logger.debug("Caught exception ", e);
344 throw new DocumentException(e);
346 if (repoSession != null) {
347 releaseRepositorySession(repoSession);
353 * delete a document from the Nuxeo repository
354 * @param ctx service context under which this method is invoked
357 * @throws DocumentException
360 public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException,
363 if (logger.isDebugEnabled()) {
364 logger.debug("deleting document with id=" + id);
366 RepositoryInstance repoSession = null;
368 repoSession = getRepositorySession();
369 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
371 repoSession.removeDocument(docRef);
372 } catch (ClientException ce) {
373 String msg = "could not find document to delete with id=" + id;
374 logger.error(msg, ce);
375 throw new DocumentNotFoundException(msg, ce);
378 } catch (DocumentException de) {
380 } catch (Exception e) {
381 if (logger.isDebugEnabled()) {
382 logger.debug("Caught exception ", e);
384 throw new DocumentException(e);
386 if (repoSession != null) {
387 releaseRepositorySession(repoSession);
393 public String createWorkspace(String tenantDomain, String workspaceName) throws Exception {
394 RepositoryInstance repoSession = null;
395 String workspaceId = null;
397 repoSession = getRepositorySession();
398 DocumentRef docRef = new PathRef(
400 + "/" + "workspaces");
401 DocumentModel parent = repoSession.getDocument(docRef);
402 DocumentModel doc = repoSession.createDocumentModel(parent.getPathAsString(),
403 workspaceName, "Workspace");
404 doc.setPropertyValue("dc:title", workspaceName);
405 doc.setPropertyValue("dc:description", "A CollectionSpace workspace for "
407 doc = repoSession.createDocument(doc);
408 workspaceId = doc.getId();
410 if (logger.isDebugEnabled()) {
411 logger.debug("created workspace name=" + workspaceName
412 + " id=" + workspaceId);
414 } catch (Exception e) {
415 if (logger.isDebugEnabled()) {
416 logger.debug("createWorkspace caught exception ", e);
420 if (repoSession != null) {
421 releaseRepositorySession(repoSession);
428 public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
429 String workspaceId = null;
430 RepositoryInstance repoSession = null;
432 repoSession = getRepositorySession();
433 DocumentRef docRef = new PathRef(
436 + "/" + workspaceName);
437 DocumentModel workspace = repoSession.getDocument(docRef);
438 workspaceId = workspace.getId();
439 } catch (DocumentException de) {
441 } catch (Exception e) {
442 if (logger.isDebugEnabled()) {
443 logger.debug("Caught exception ", e);
445 throw new DocumentException(e);
447 if (repoSession != null) {
448 releaseRepositorySession(repoSession);
454 private RepositoryInstance getRepositorySession() throws Exception {
455 // FIXME: is it possible to reuse repository session?
456 // Authentication failures happen while trying to reuse the session
457 NuxeoClient client = NuxeoConnector.getInstance().getClient();
458 RepositoryInstance repoSession = client.openRepository();
459 if (logger.isDebugEnabled()) {
460 logger.debug("getRepository() repository root: " + repoSession.getRootDocument());
465 private void releaseRepositorySession(RepositoryInstance repoSession) {
467 NuxeoClient client = NuxeoConnector.getInstance().getClient();
469 client.releaseRepository(repoSession);
470 } catch (Exception e) {
471 logger.error("Could not close the repository session", e);
472 // no need to throw this service specific exception