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 "RemoteRepositoryClient.create: docType is missing");
80 if (handler == null) {
81 throw new IllegalArgumentException(
82 "RemoteRepositoryClient.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 "RemoteRepositoryClient.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 "RemoteRepositoryClient.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 "RemoteRepositoryClient.getFiltered: handler is missing");
240 DocumentFilter docFilter = handler.getDocumentFilter();
241 if (docFilter == null) {
242 throw new IllegalArgumentException(
243 "RemoteRepositoryClient.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);
268 DocumentModelList docList = null;
269 if ((docFilter.getOffset() > 0) || (docFilter.getPageSize() > 0)) {
270 docList = repoSession.query(query.toString(), null,
271 docFilter.getPageSize(), docFilter.getOffset(), false);
273 docList = repoSession.query(query.toString());
275 //set repoSession to handle the document
276 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
277 DocumentWrapper<DocumentModelList> wrapDoc = new DocumentWrapperImpl<DocumentModelList>(docList);
278 handler.handle(Action.GET_ALL, wrapDoc);
279 handler.complete(Action.GET_ALL, wrapDoc);
280 } catch (DocumentException de) {
282 } catch (Exception e) {
283 if (logger.isDebugEnabled()) {
284 logger.debug("Caught exception ", e);
286 throw new DocumentException(e);
288 if (repoSession != null) {
289 releaseRepositorySession(repoSession);
295 * update given document in the Nuxeo repository
297 * @param ctx service context under which this method is invoked
301 * should be used by the caller to provide and transform the
303 * @throws DocumentException
306 public void update(ServiceContext ctx, String id, DocumentHandler handler)
307 throws BadRequestException, DocumentNotFoundException,
310 throw new BadRequestException(
311 "RemoteRepositoryClient.update: id is missing");
313 if (handler == null) {
314 throw new IllegalArgumentException(
315 "RemoteRepositoryClient.update: handler is missing");
317 RepositoryInstance repoSession = null;
319 handler.prepare(Action.UPDATE);
320 repoSession = getRepositorySession();
321 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
322 DocumentModel doc = null;
324 doc = repoSession.getDocument(docRef);
325 } catch (ClientException ce) {
326 String msg = "Could not find document to update with id=" + id;
327 logger.error(msg, ce);
328 throw new DocumentNotFoundException(msg, ce);
330 //set reposession to handle the document
331 ((DocumentModelHandler) handler).setRepositorySession(repoSession);
332 DocumentWrapper<DocumentModel> wrapDoc = new DocumentWrapperImpl<DocumentModel>(doc);
333 handler.handle(Action.UPDATE, wrapDoc);
334 repoSession.saveDocument(doc);
336 handler.complete(Action.UPDATE, wrapDoc);
337 } catch (DocumentException de) {
339 } catch (Exception e) {
340 if (logger.isDebugEnabled()) {
341 logger.debug("Caught exception ", e);
343 throw new DocumentException(e);
345 if (repoSession != null) {
346 releaseRepositorySession(repoSession);
352 * delete a document from the Nuxeo repository
353 * @param ctx service context under which this method is invoked
356 * @throws DocumentException
359 public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException,
362 if (logger.isDebugEnabled()) {
363 logger.debug("deleting document with id=" + id);
365 RepositoryInstance repoSession = null;
367 repoSession = getRepositorySession();
368 DocumentRef docRef = NuxeoUtils.createPathRef(ctx, id);
370 repoSession.removeDocument(docRef);
371 } catch (ClientException ce) {
372 String msg = "could not find document to delete with id=" + id;
373 logger.error(msg, ce);
374 throw new DocumentNotFoundException(msg, ce);
377 } catch (DocumentException de) {
379 } catch (Exception e) {
380 if (logger.isDebugEnabled()) {
381 logger.debug("Caught exception ", e);
383 throw new DocumentException(e);
385 if (repoSession != null) {
386 releaseRepositorySession(repoSession);
392 public String createWorkspace(String tenantDomain, String workspaceName) throws Exception {
393 RepositoryInstance repoSession = null;
394 String workspaceId = null;
396 repoSession = getRepositorySession();
397 DocumentRef docRef = new PathRef(
400 DocumentModel parent = repoSession.getDocument(docRef);
401 DocumentModel doc = repoSession.createDocumentModel(parent.getPathAsString(),
402 workspaceName, "Workspace");
403 doc.setPropertyValue("dc:title", workspaceName);
404 doc.setPropertyValue("dc:description", "A CollectionSpace workspace for " +
406 doc = repoSession.createDocument(doc);
407 workspaceId = doc.getId();
409 if (logger.isDebugEnabled()) {
410 logger.debug("created workspace name=" + workspaceName +
411 " id=" + workspaceId);
413 } catch (Exception e) {
414 if (logger.isDebugEnabled()) {
415 logger.debug("createWorkspace caught exception ", e);
419 if (repoSession != null) {
420 releaseRepositorySession(repoSession);
427 public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
428 String workspaceId = null;
429 RepositoryInstance repoSession = null;
431 repoSession = getRepositorySession();
432 DocumentRef docRef = new PathRef(
435 "/" + workspaceName);
436 DocumentModel workspace = repoSession.getDocument(docRef);
437 workspaceId = workspace.getId();
438 } catch (DocumentException de) {
440 } catch (Exception e) {
441 if (logger.isDebugEnabled()) {
442 logger.debug("Caught exception ", e);
444 throw new DocumentException(e);
446 if (repoSession != null) {
447 releaseRepositorySession(repoSession);
453 private RepositoryInstance getRepositorySession() throws Exception {
454 // FIXME: is it possible to reuse repository session?
455 // Authentication failures happen while trying to reuse the session
456 NuxeoClient client = NuxeoConnector.getInstance().getClient();
457 RepositoryInstance repoSession = client.openRepository();
458 if (logger.isDebugEnabled()) {
459 logger.debug("getRepository() repository root: " + repoSession.getRootDocument());
464 private void releaseRepositorySession(RepositoryInstance repoSession) {
466 NuxeoClient client = NuxeoConnector.getInstance().getClient();
468 client.releaseRepository(repoSession);
469 } catch (Exception e) {
470 logger.error("Could not close the repository session", e);
471 // no need to throw this service specific exception