]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
f0c44db0028f9b404ff9f7e64dc14223bfe596aa
[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  *  Unless required by applicable law or agreed to in writing, software
19  *  distributed under the License is distributed on an "AS IS" BASIS,
20  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  *  See the License for the specific language governing permissions and
22  *  limitations under the License.
23  */
24 package org.collectionspace.services.nuxeo.client.rest;
25
26 import java.io.ByteArrayInputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import org.collectionspace.services.common.repository.DocumentException;
34 import org.collectionspace.services.common.repository.DocumentHandler;
35 import org.collectionspace.services.common.repository.RepositoryClient;
36
37 import org.restlet.data.Request;
38
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import java.util.List;
43 import java.util.Map;
44
45 import org.collectionspace.services.common.ServiceConfig;
46 import org.collectionspace.services.common.RepositoryClientConfigType;
47 import org.collectionspace.services.common.ServiceMain;
48 import org.collectionspace.services.common.config.TenantBindingConfigReader;
49 import org.collectionspace.services.common.context.ServiceContext;
50 import org.collectionspace.services.common.repository.BadRequestException;
51 import org.collectionspace.services.common.repository.DocumentNotFoundException;
52 import org.collectionspace.services.common.repository.DocumentHandler.Action;
53 import org.dom4j.Document;
54 import org.dom4j.Element;
55 import org.dom4j.io.SAXReader;
56 import org.dom4j.tree.DefaultDocument;
57 import org.restlet.data.MediaType;
58 import org.restlet.data.Method;
59 import org.restlet.data.Response;
60 import org.restlet.data.Status;
61 import org.restlet.resource.OutputRepresentation;
62 import org.restlet.resource.Representation;
63
64 /**
65  * RepositoryRESTClient is used to perform CRUD operations on documents
66  * in Nuxeo repository using Nuxeo RESTful APIs. It uses @see DocumentHandler
67  * as IOHandler with the client.
68  *
69  * v2 NuxeoClient
70  *
71  * $LastChangedRevision: $
72  * $LastChangedDate: $
73  */
74 public class RepositoryRESTClient implements RepositoryClient {
75
76     private final Logger logger = LoggerFactory.getLogger(RepositoryRESTClient.class);
77     private NuxeoRESTClient nuxeoRestClient;
78
79     public RepositoryRESTClient() {
80     }
81
82     @Override
83     public String create(ServiceContext ctx, DocumentHandler handler) throws BadRequestException, DocumentException {
84
85         if(handler.getDocumentType() == null){
86             throw new IllegalArgumentException("RepositoryRESTClient.create: docType is missing");
87         }
88         if(handler == null){
89             throw new IllegalArgumentException("RepositoryRESTClient.create: handler is missing");
90         }
91         String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
92         if(nuxeoWspaceId == null){
93             throw new DocumentNotFoundException("Unable to find workspace for service " + ctx.getServiceName() +
94                     " check if the mapping exists in service-config.xml or " +
95                     " the the mapped workspace exists in the Nuxeo repository");
96         }
97         try{
98             RepresentationHandler repHandler = (RepresentationHandler) handler;
99             repHandler.prepare(Action.CREATE);
100             List<String> pathParams = new ArrayList<String>();
101             pathParams.add("default");
102             pathParams.add(nuxeoWspaceId);
103             pathParams.add("createDocument");
104             if(repHandler.getPathParams().size() > 0){
105                 pathParams.addAll(repHandler.getPathParams());
106             }
107             Map<String, String> queryParams = new HashMap<String, String>();
108             queryParams.put("docType", handler.getDocumentType());
109             // a default title for the Dublin Core schema
110             queryParams.put("dublincore:title", "CollectionSpace-" + handler.getDocumentType());
111             if(repHandler.getQueryParams().size() > 0){
112                 queryParams.putAll(repHandler.getQueryParams());
113             }
114
115             String completeURL = getNuxeoRestClient().buildUrl(pathParams, queryParams);
116             if(logger.isDebugEnabled()){
117                 logger.debug("create using url=" + completeURL);
118             }
119             Request request = buildRequest(Method.POST, completeURL);
120
121             //write out create stream, this is not needed as queryParams
122             //contain the document
123             final InputStream in = new ByteArrayInputStream(new byte[0]);
124             request.setEntity(new OutputRepresentation(
125                     MediaType.MULTIPART_FORM_DATA) {
126
127                 @Override
128                 public void write(OutputStream outputStream) throws IOException {
129                     byte[] buffer = new byte[1024 * 64];
130                     int read;
131                     while((read = in.read(buffer)) != -1){
132                         outputStream.write(buffer, 0, read);
133                     }
134                 }
135             });
136             //following call to handler.handle is not needed as queryparams
137             //contains the real data
138             RepresentationWrapper wrapDoc = new RepresentationWrapper(new DefaultDocument());
139             repHandler.handle(Action.CREATE, wrapDoc);
140             //read response
141             //Nuxeo does not set 201 SUCCESS_CREATED on successful creation
142             Document document = executeRequest(request, completeURL, Status.SUCCESS_OK);
143             //handle is not needed on create as queryparams have all data
144             repHandler.complete(Action.CREATE, wrapDoc);
145             return extractId(document);
146
147         }catch(Exception e){
148             if(logger.isDebugEnabled()){
149                 logger.debug("Caught exception ", e);
150             }
151             throw new DocumentException(e);
152         }finally{
153         }
154     }
155
156     @Override
157     public void get(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException {
158
159         if(handler == null){
160             throw new IllegalArgumentException("RepositoryRESTClient.get: handler is missing");
161         }
162
163         try{
164             RepresentationHandler repHandler = (RepresentationHandler) handler;
165             repHandler.prepare(Action.GET);
166             ArrayList pathParams = new ArrayList();
167             pathParams.add("default");
168             pathParams.add(id);
169             pathParams.add("export");
170             if(repHandler.getPathParams().size() > 0){
171                 pathParams.addAll(repHandler.getPathParams());
172             }
173             HashMap<String, String> queryParams = new HashMap<String, String>();
174             queryParams.put("format", "XML");
175             if(repHandler.getQueryParams().size() > 0){
176                 queryParams.putAll(repHandler.getQueryParams());
177             }
178             String completeURL = getNuxeoRestClient().buildUrl(pathParams, queryParams);
179             if(logger.isDebugEnabled()){
180                 logger.debug("get using url=" + completeURL);
181             }
182             Request request = buildRequest(Method.GET, completeURL);
183             Document document = executeRequest(request, completeURL, Status.SUCCESS_OK);
184             RepresentationWrapper wrapDoc = new RepresentationWrapper(document);
185             repHandler.handle(Action.GET, wrapDoc);
186             repHandler.complete(Action.GET, wrapDoc);
187         }catch(Exception e){
188             if(logger.isDebugEnabled()){
189                 logger.debug("Caught exception ", e);
190             }
191             throw new DocumentException(e);
192         }finally{
193         }
194     }
195
196     @Override
197     public void getAll(ServiceContext ctx, DocumentHandler handler) throws DocumentNotFoundException, DocumentException {
198         if(handler == null){
199             throw new IllegalArgumentException("RepositoryRESTClient.getAll: handler is missing");
200         }
201         String nuxeoWspaceId = ctx.getRepositoryWorkspaceId();
202         if(nuxeoWspaceId == null){
203             throw new DocumentNotFoundException("Unable to find workspace for service " + ctx.getServiceName() +
204                     " check if the mapping exists in service-config.xml or " +
205                     " the the mapped workspace exists in the Nuxeo repository");
206         }
207         try{
208             RepresentationHandler repHandler = (RepresentationHandler) handler;
209             repHandler.prepare(Action.GET_ALL);
210             ArrayList pathParams = new ArrayList();
211             pathParams.add("default");
212             pathParams.add(nuxeoWspaceId);
213             pathParams.add("browse");
214             if(repHandler.getPathParams().size() > 0){
215                 pathParams.addAll(repHandler.getPathParams());
216             }
217             String completeURL = getNuxeoRestClient().buildUrl(pathParams, repHandler.getQueryParams());
218             if(logger.isDebugEnabled()){
219                 logger.debug("getAll using url=" + completeURL);
220             }
221             Request request = buildRequest(Method.GET, completeURL);
222             Document document = executeRequest(request, completeURL, Status.SUCCESS_OK);
223             RepresentationWrapper wrapDoc = new RepresentationWrapper(document);
224             repHandler.handle(Action.GET_ALL, wrapDoc);
225             repHandler.complete(Action.GET_ALL, wrapDoc);
226         }catch(Exception e){
227             if(logger.isDebugEnabled()){
228                 logger.debug("Caught exception ", e);
229             }
230             throw new DocumentException(e);
231         }finally{
232         }
233     }
234
235     @Override
236     public void update(ServiceContext ctx, String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException {
237         if(handler == null){
238             throw new IllegalArgumentException("RepositoryRESTClient.update: handler is missing");
239         }
240
241         try{
242             RepresentationHandler repHandler = (RepresentationHandler) handler;
243             repHandler.prepare(Action.UPDATE);
244             List<String> pathParams = new ArrayList<String>();
245             pathParams.add("default");
246             pathParams.add(id);
247             pathParams.add("updateDocumentRestlet");
248             if(repHandler.getPathParams().size() > 0){
249                 pathParams.addAll(repHandler.getPathParams());
250             }
251             String completeURL = getNuxeoRestClient().buildUrl(pathParams, repHandler.getQueryParams());
252             if(logger.isDebugEnabled()){
253                 logger.debug("update using url=" + completeURL);
254             }
255             //repHandler.handle is not needed as queryParams contain all the data
256             RepresentationWrapper wrapDoc = new RepresentationWrapper(new DefaultDocument());
257             repHandler.handle(Action.UPDATE, wrapDoc);
258             Request request = buildRequest(Method.PUT, completeURL);
259             Document document = executeRequest(request, completeURL, Status.SUCCESS_OK);
260             repHandler.complete(Action.UPDATE, wrapDoc);
261         }catch(Exception e){
262             if(logger.isDebugEnabled()){
263                 logger.debug("Caught exception ", e);
264             }
265             throw new DocumentException(e);
266         }finally{
267         }
268     }
269
270     @Override
271     public void delete(ServiceContext ctx, String id) throws DocumentNotFoundException, DocumentException {
272
273         if(logger.isDebugEnabled()){
274             logger.debug("deleting document with id=" + id);
275         }
276
277         try{
278             List<String> pathParams = new ArrayList<String>();
279             pathParams.add("default");
280             pathParams.add(id);
281             pathParams.add("deleteDocumentRestlet");
282
283             Map<String, String> queryParams = new HashMap<String, String>();
284             String completeURL = getNuxeoRestClient().buildUrl(pathParams, queryParams);
285             if(logger.isDebugEnabled()){
286                 logger.debug("delete using url=" + completeURL);
287             }
288             Request request = buildRequest(Method.DELETE, completeURL);
289             Document document = executeRequest(request, completeURL, Status.SUCCESS_OK);
290             //FIXME error handling?
291             //            Document document = service.deleteCollectionObject(csid);
292 //            Element root = document.getRootElement();
293 //            for(Iterator i = root.elementIterator(); i.hasNext();){
294 //                Element element = (Element) i.next();
295 //                if("docRef".equals(element.getName())){
296 //                    String status = (String) element.getData();
297 //                    verbose("deleteCollectionObjectt response: " + status);
298 //                }
299 //            }
300
301         }catch(Exception e){
302             if(logger.isDebugEnabled()){
303                 logger.debug("Caught exception ", e);
304             }
305             throw new DocumentException(e);
306         }finally{
307         }
308     }
309
310     @Override
311     public String createWorkspace(String tenantDomain, String workspaceName) throws Exception {
312         throw new UnsupportedOperationException();
313     }
314
315     @Override
316     public String getWorkspaceId(String tenantDomain, String workspaceName) throws Exception {
317         throw new UnsupportedOperationException();
318     }
319
320     /**
321      * buildRequest build HTTP request given parameters
322      * @param method
323      * @param completeURL
324      * @return
325      */
326     private Request buildRequest(Method method, String completeURL) {
327         Request request = new Request(method, completeURL);
328         getNuxeoRestClient().setupAuth(request);
329         getNuxeoRestClient().setupCookies(request);
330         return request;
331     }
332
333     /**
334      * executeRequest execute given HTTP request
335      * @param request
336      * @param completeURL
337      * @return
338      * @throws Exception
339      */
340     private Document executeRequest(Request request, String completeURL, Status expected) throws Exception {
341         //execute
342         Response res = getNuxeoRestClient().getRestClient().handle(request);
343         Status status = res.getStatus();
344         if(status.getCode() != expected.getCode()){
345             logger.error("failed to execute request=" + request.getMethod() +
346                     " with error status=" + status +
347                     " url=" + completeURL +
348                     " response=" + res.toString());
349             throw new DocumentException(status.getCode(), status.getDescription());
350         }
351         Representation rep = res.getEntity();
352
353         //read response
354         return retrieveResponse(rep);
355     }
356
357     /**
358      * retrieveResponse retrieves DOM document from Restlet Represeantion
359      * @param request
360      * @return
361      * @throws Exception
362      */
363     private Document retrieveResponse(Representation rep) throws Exception {
364         SAXReader reader = new SAXReader();
365         Document document = reader.read(rep.getStream());
366         return document;
367     }
368
369     /**
370      * extractId extract document id from response
371      * @param document
372      * @return
373      */
374     private String extractId(Document document) {
375         String csid = null;
376         Element root = document.getRootElement();
377         for(Iterator i = root.elementIterator(); i.hasNext();){
378             Element element = (Element) i.next();
379             if("docRef".equals(element.getName())){
380                 csid = (String) element.getData();
381                 break;
382             }
383         }
384         return csid;
385     }
386
387     private NuxeoRESTClient getNuxeoRestClient() {
388         if(nuxeoRestClient == null){
389             ServiceConfig sconfig = ServiceMain.getInstance().getServiceConfig();
390             //assumption: there is only one client and that also is rest
391             RepositoryClientConfigType repConfig = sconfig.getRepositoryClient();
392             String protocol = "http";
393             if(repConfig.getProtocol() != null && !"".equals(repConfig.getProtocol())){
394                 protocol = repConfig.getProtocol();
395             }
396             NuxeoRESTClient tempClient = new NuxeoRESTClient(protocol,
397                     repConfig.getHost(), "" + repConfig.getPort());
398
399             tempClient.setBasicAuthentication(repConfig.getUser(), repConfig.getPassword());
400
401             nuxeoRestClient = tempClient;
402
403         }
404         return nuxeoRestClient;
405     }
406 }