This project has retired. For details please refer to its Attic page.
CmisBrowserBindingServlet xref

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.server.impl.browser;
20  
21  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_ADD_OBJECT_TO_FOLDER;
22  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_APPLY_ACL;
23  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_APPLY_POLICY;
24  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CANCEL_CHECK_OUT;
25  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CHECK_IN;
26  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CHECK_OUT;
27  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CREATE_DOCUMENT;
28  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CREATE_DOCUMENT_FROM_SOURCE;
29  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CREATE_FOLDER;
30  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CREATE_POLICY;
31  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CREATE_RELATIONSHIP;
32  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_DELETE;
33  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_DELETE_CONTENT;
34  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_DELETE_TREE;
35  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_MOVE;
36  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_QUERY;
37  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_REMOVE_OBJECT_FROM_FOLDER;
38  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_REMOVE_POLICY;
39  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_SET_CONTENT;
40  import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_UPDATE_PROPERTIES;
41  import static org.apache.chemistry.opencmis.commons.impl.Constants.PARAM_OBJECT_ID;
42  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_ACL;
43  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_ALLOWABLEACTIONS;
44  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_CHECKEDOUT;
45  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_CHILDREN;
46  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_CONTENT;
47  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_CONTENT_CHANGES;
48  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_DESCENDANTS;
49  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_FOLDER_TREE;
50  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_LAST_RESULT;
51  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_OBJECT;
52  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_PARENT;
53  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_PARENTS;
54  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_POLICIES;
55  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_PROPERTIES;
56  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_QUERY;
57  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_RELATIONSHIPS;
58  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_RENDITIONS;
59  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_REPOSITORY_INFO;
60  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_TYPE_CHILDREN;
61  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_TYPE_DEFINITION;
62  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_TYPE_DESCENDANTS;
63  import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_VERSIONS;
64  import static org.apache.chemistry.opencmis.commons.impl.JSONConstants.ERROR_EXCEPTION;
65  import static org.apache.chemistry.opencmis.commons.impl.JSONConstants.ERROR_MESSAGE;
66  import static org.apache.chemistry.opencmis.commons.impl.JSONConstants.ERROR_STACKTRACE;
67  import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.CONTEXT_BASETYPE_ID;
68  import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.CONTEXT_TRANSACTION;
69  import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.HTML_MIME_TYPE;
70  import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.JSON_MIME_TYPE;
71  import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.createCookieValue;
72  import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.prepareContext;
73  import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.setCookie;
74  import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.setStatus;
75  import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.writeJSON;
76  import static org.apache.chemistry.opencmis.server.shared.Dispatcher.METHOD_GET;
77  import static org.apache.chemistry.opencmis.server.shared.Dispatcher.METHOD_POST;
78  import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getStringParameter;
79  
80  import java.io.File;
81  import java.io.IOException;
82  
83  import javax.servlet.ServletConfig;
84  import javax.servlet.ServletException;
85  import javax.servlet.http.HttpServlet;
86  import javax.servlet.http.HttpServletRequest;
87  import javax.servlet.http.HttpServletResponse;
88  
89  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
90  import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
91  import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
92  import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
93  import org.apache.chemistry.opencmis.commons.exceptions.CmisFilterNotValidException;
94  import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
95  import org.apache.chemistry.opencmis.commons.exceptions.CmisNameConstraintViolationException;
96  import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
97  import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
98  import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
99  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
100 import org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException;
101 import org.apache.chemistry.opencmis.commons.exceptions.CmisStreamNotSupportedException;
102 import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
103 import org.apache.chemistry.opencmis.commons.exceptions.CmisVersioningException;
104 import org.apache.chemistry.opencmis.commons.impl.Constants;
105 import org.apache.chemistry.opencmis.commons.impl.json.JSONObject;
106 import org.apache.chemistry.opencmis.commons.server.CallContext;
107 import org.apache.chemistry.opencmis.commons.server.CmisService;
108 import org.apache.chemistry.opencmis.commons.server.CmisServiceFactory;
109 import org.apache.chemistry.opencmis.server.impl.CmisRepositoryContextListener;
110 import org.apache.chemistry.opencmis.server.impl.ServerVersion;
111 import org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.CallUrl;
112 import org.apache.chemistry.opencmis.server.shared.CallContextHandler;
113 import org.apache.chemistry.opencmis.server.shared.Dispatcher;
114 import org.apache.chemistry.opencmis.server.shared.ExceptionHelper;
115 import org.apache.chemistry.opencmis.server.shared.HttpUtils;
116 import org.apache.commons.logging.Log;
117 import org.apache.commons.logging.LogFactory;
118 
119 public class CmisBrowserBindingServlet extends HttpServlet {
120 
121     private static final long serialVersionUID = 1L;
122 
123     public static final String PARAM_CALL_CONTEXT_HANDLER = "callContextHandler";
124 
125     private static final Log LOG = LogFactory.getLog(CmisBrowserBindingServlet.class.getName());
126 
127     private File tempDir;
128     private int memoryThreshold;
129 
130     private Dispatcher repositoryDispatcher;
131     private Dispatcher rootDispatcher;
132     private CallContextHandler callContextHandler;
133 
134     @Override
135     public void init(ServletConfig config) throws ServletException {
136         super.init(config);
137 
138         // initialize the call context handler
139         callContextHandler = null;
140         String callContextHandlerClass = config.getInitParameter(PARAM_CALL_CONTEXT_HANDLER);
141         if (callContextHandlerClass != null) {
142             try {
143                 callContextHandler = (CallContextHandler) Class.forName(callContextHandlerClass).newInstance();
144             } catch (Exception e) {
145                 throw new ServletException("Could not load call context handler: " + e, e);
146             }
147         }
148 
149         // get memory threshold and temp directory
150         CmisServiceFactory factory = (CmisServiceFactory) config.getServletContext().getAttribute(
151                 CmisRepositoryContextListener.SERVICES_FACTORY);
152 
153         tempDir = factory.getTempDirectory();
154         memoryThreshold = factory.getMemoryThreshold();
155 
156         // initialize the dispatchers
157         repositoryDispatcher = new Dispatcher(false);
158         rootDispatcher = new Dispatcher(false);
159 
160         try {
161             repositoryDispatcher.addResource(SELECTOR_REPOSITORY_INFO, METHOD_GET, RepositoryService.class,
162                     "getRepositoryInfo");
163             repositoryDispatcher
164                     .addResource(SELECTOR_LAST_RESULT, METHOD_GET, RepositoryService.class, "getLastResult");
165             repositoryDispatcher.addResource(SELECTOR_TYPE_CHILDREN, METHOD_GET, RepositoryService.class,
166                     "getTypeChildren");
167             repositoryDispatcher.addResource(SELECTOR_TYPE_DESCENDANTS, METHOD_GET, RepositoryService.class,
168                     "getTypeDescendants");
169             repositoryDispatcher.addResource(SELECTOR_TYPE_DEFINITION, METHOD_GET, RepositoryService.class,
170                     "getTypeDefinition");
171             repositoryDispatcher.addResource(SELECTOR_QUERY, METHOD_GET, DiscoveryService.class, "query");
172             repositoryDispatcher.addResource(SELECTOR_CHECKEDOUT, METHOD_GET, NavigationService.class,
173                     "getCheckedOutDocs");
174             repositoryDispatcher.addResource(SELECTOR_CONTENT_CHANGES, METHOD_GET, DiscoveryService.class,
175                     "getContentChanges");
176 
177             repositoryDispatcher.addResource(CMISACTION_QUERY, METHOD_POST, DiscoveryService.class, "query");
178             repositoryDispatcher.addResource(CMISACTION_CREATE_DOCUMENT, METHOD_POST, ObjectService.class,
179                     "createDocument");
180             repositoryDispatcher.addResource(CMISACTION_CREATE_DOCUMENT_FROM_SOURCE, METHOD_POST, ObjectService.class,
181                     "createDocumentFromSource");
182             repositoryDispatcher
183                     .addResource(CMISACTION_CREATE_POLICY, METHOD_POST, ObjectService.class, "createPolicy");
184             repositoryDispatcher.addResource(CMISACTION_CREATE_RELATIONSHIP, METHOD_POST, ObjectService.class,
185                     "createRelationship");
186 
187             rootDispatcher.addResource(SELECTOR_OBJECT, METHOD_GET, ObjectService.class, "getObject");
188             rootDispatcher.addResource(SELECTOR_PROPERTIES, METHOD_GET, ObjectService.class, "getProperties");
189             rootDispatcher.addResource(SELECTOR_ALLOWABLEACTIONS, METHOD_GET, ObjectService.class,
190                     "getAllowableActions");
191             rootDispatcher.addResource(SELECTOR_RENDITIONS, METHOD_GET, ObjectService.class, "getRenditions");
192             rootDispatcher.addResource(SELECTOR_CONTENT, METHOD_GET, ObjectService.class, "getContentStream");
193             rootDispatcher.addResource(SELECTOR_CHILDREN, METHOD_GET, NavigationService.class, "getChildren");
194             rootDispatcher.addResource(SELECTOR_DESCENDANTS, METHOD_GET, NavigationService.class, "getDescendants");
195             rootDispatcher.addResource(SELECTOR_FOLDER_TREE, METHOD_GET, NavigationService.class, "getFolderTree");
196             rootDispatcher.addResource(SELECTOR_PARENT, METHOD_GET, NavigationService.class, "getFolderParent");
197             rootDispatcher.addResource(SELECTOR_PARENTS, METHOD_GET, NavigationService.class, "getObjectParents");
198             rootDispatcher.addResource(SELECTOR_VERSIONS, METHOD_GET, VersioningService.class, "getAllVersions");
199             rootDispatcher.addResource(SELECTOR_RELATIONSHIPS, METHOD_GET, RelationshipService.class,
200                     "getObjectRelationships");
201             rootDispatcher.addResource(SELECTOR_CHECKEDOUT, METHOD_GET, NavigationService.class, "getCheckedOutDocs");
202             rootDispatcher.addResource(SELECTOR_POLICIES, METHOD_GET, PolicyService.class, "getAppliedPolicies");
203             rootDispatcher.addResource(SELECTOR_ACL, METHOD_GET, AclService.class, "getACL");
204 
205             rootDispatcher.addResource(CMISACTION_CREATE_DOCUMENT, METHOD_POST, ObjectService.class, "createDocument");
206             rootDispatcher.addResource(CMISACTION_CREATE_DOCUMENT_FROM_SOURCE, METHOD_POST, ObjectService.class,
207                     "createDocumentFromSource");
208             rootDispatcher.addResource(CMISACTION_CREATE_FOLDER, METHOD_POST, ObjectService.class, "createFolder");
209             rootDispatcher.addResource(CMISACTION_CREATE_POLICY, METHOD_POST, ObjectService.class, "createPolicy");
210             rootDispatcher.addResource(CMISACTION_UPDATE_PROPERTIES, METHOD_POST, ObjectService.class,
211                     "updateProperties");
212             rootDispatcher.addResource(CMISACTION_SET_CONTENT, METHOD_POST, ObjectService.class, "setContentStream");
213             rootDispatcher.addResource(CMISACTION_DELETE_CONTENT, METHOD_POST, ObjectService.class,
214                     "deleteContentStream");
215             rootDispatcher.addResource(CMISACTION_DELETE, METHOD_POST, ObjectService.class, "deleteObject");
216             rootDispatcher.addResource(CMISACTION_DELETE_TREE, METHOD_POST, ObjectService.class, "deleteTree");
217             rootDispatcher.addResource(CMISACTION_MOVE, METHOD_POST, ObjectService.class, "moveObject");
218             rootDispatcher.addResource(CMISACTION_ADD_OBJECT_TO_FOLDER, METHOD_POST, MultiFilingService.class,
219                     "addObjectToFolder");
220             rootDispatcher.addResource(CMISACTION_REMOVE_OBJECT_FROM_FOLDER, METHOD_POST, MultiFilingService.class,
221                     "removeObjectFromFolder");
222             rootDispatcher.addResource(CMISACTION_CHECK_OUT, METHOD_POST, VersioningService.class, "checkOut");
223             rootDispatcher.addResource(CMISACTION_CANCEL_CHECK_OUT, METHOD_POST, VersioningService.class,
224                     "cancelCheckOut");
225             rootDispatcher.addResource(CMISACTION_CHECK_IN, METHOD_POST, VersioningService.class, "checkIn");
226             rootDispatcher.addResource(CMISACTION_APPLY_POLICY, METHOD_POST, PolicyService.class, "applyPolicy");
227             rootDispatcher.addResource(CMISACTION_REMOVE_POLICY, METHOD_POST, PolicyService.class, "removePolicy");
228             rootDispatcher.addResource(CMISACTION_APPLY_ACL, METHOD_POST, AclService.class, "applyACL");
229 
230         } catch (NoSuchMethodException e) {
231             LOG.error("Cannot initialize dispatcher!", e);
232         }
233     }
234 
235     @Override
236     protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,
237             IOException {
238 
239         // set default headers
240         response.addHeader("Cache-Control", "private, max-age=0");
241         response.addHeader("Server", ServerVersion.OPENCMIS_SERVER);
242 
243         // create a context object, dispatch and handle exceptions
244         CallContext context = null;
245         try {
246             context = HttpUtils.createContext(request, response, getServletContext(), CallContext.BINDING_BROWSER,
247                     callContextHandler, tempDir, memoryThreshold);
248             dispatch(context, request, response);
249         } catch (Exception e) {
250             if (e instanceof CmisPermissionDeniedException) {
251                 if (context == null || context.getUsername() == null) {
252                     response.setHeader("WWW-Authenticate", "Basic realm=\"CMIS\"");
253                     response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization Required");
254                 } else {
255                     printError(e, request, response, context);
256                 }
257             } else {
258                 printError(e, request, response, context);
259             }
260         }
261 
262         // we are done.
263         response.flushBuffer();
264     }
265 
266     // --------------------------------------------------------
267 
268     private void dispatch(CallContext context, HttpServletRequest request, HttpServletResponse response)
269             throws Exception {
270         CmisService service = null;
271         try {
272             // get services factory
273             CmisServiceFactory factory = (CmisServiceFactory) getServletContext().getAttribute(
274                     CmisRepositoryContextListener.SERVICES_FACTORY);
275 
276             if (factory == null) {
277                 throw new CmisRuntimeException("Service factory not available! Configuration problem?");
278             }
279 
280             // get the service
281             service = factory.getService(context);
282 
283             // analyze the path
284             String[] pathFragments = HttpUtils.splitPath(request);
285 
286             if (pathFragments.length < 1) {
287                 // root -> repository infos
288                 RepositoryService.getRepositories(context, service, request, response);
289                 return;
290             }
291 
292             // select dispatcher
293 
294             CallUrl callUrl = null;
295             if (pathFragments.length == 1) {
296                 callUrl = CallUrl.REPOSITORY;
297             } else if (BrowserBindingUtils.ROOT_PATH_FRAGMENT.equals(pathFragments[1])) {
298                 callUrl = CallUrl.ROOT;
299             }
300 
301             if (callUrl == null) {
302                 throw new CmisNotSupportedException("Unknown operation");
303             }
304 
305             String method = request.getMethod();
306             String repositoryId = pathFragments[0];
307             boolean methodFound = false;
308 
309             if (METHOD_GET.equals(method)) {
310                 String selector = getStringParameter(request, Constants.PARAM_SELECTOR);
311                 String objectId = getStringParameter(request, PARAM_OBJECT_ID);
312 
313                 // add object id and object base type id to context
314                 prepareContext(context, callUrl, service, repositoryId, objectId, null, request);
315 
316                 // dispatch
317                 if (callUrl == CallUrl.REPOSITORY) {
318                     if (selector == null) {
319                         selector = "";
320                     }
321 
322                     methodFound = repositoryDispatcher.dispatch(selector, method, context, service, repositoryId,
323                             request, response);
324                 } else if (callUrl == CallUrl.ROOT) {
325                     // set default method if necessary
326                     if (selector == null) {
327                         try {
328                             BaseTypeId basetype = BaseTypeId.fromValue((String) context.get(CONTEXT_BASETYPE_ID));
329                             switch (basetype) {
330                             case CMIS_DOCUMENT:
331                                 selector = SELECTOR_CONTENT;
332                                 break;
333                             case CMIS_FOLDER:
334                                 selector = SELECTOR_CHILDREN;
335                                 break;
336                             default:
337                                 selector = SELECTOR_OBJECT;
338                                 break;
339                             }
340                         } catch (Exception e) {
341                             selector = SELECTOR_OBJECT;
342                         }
343                     }
344 
345                     methodFound = rootDispatcher.dispatch(selector, method, context, service, repositoryId, request,
346                             response);
347                 }
348             } else if (METHOD_POST.equals(method)) {
349                 POSTHttpServletRequestWrapper postRequest = new POSTHttpServletRequestWrapper(request, tempDir,
350                         memoryThreshold);
351 
352                 String cmisaction = getStringParameter(postRequest, Constants.CONTROL_CMISACTION);
353                 String objectId = getStringParameter(postRequest, Constants.CONTROL_OBJECT_ID);
354                 String transaction = getStringParameter(postRequest, Constants.CONTROL_TRANSACTION);
355 
356                 if (cmisaction == null || cmisaction.length() == 0) {
357                     throw new CmisNotSupportedException("Unknown action");
358                 }
359 
360                 // add object id and object base type id to context
361                 prepareContext(context, callUrl, service, repositoryId, objectId, transaction, postRequest);
362 
363                 // dispatch
364                 if (callUrl == CallUrl.REPOSITORY) {
365                     methodFound = repositoryDispatcher.dispatch(cmisaction, method, context, service, repositoryId,
366                             postRequest, response);
367                 } else if (callUrl == CallUrl.ROOT) {
368                     methodFound = rootDispatcher.dispatch(cmisaction, method, context, service, repositoryId,
369                             postRequest, response);
370                 }
371             }
372 
373             // if the dispatcher couldn't find a matching method, return an
374             // error message
375             if (!methodFound) {
376                 throw new CmisNotSupportedException("Unknown operation");
377             }
378         } finally {
379             if (service != null) {
380                 service.close();
381             }
382         }
383     }
384 
385     /**
386      * Translates an exception in an appropriate HTTP error code.
387      */
388     private static int getErrorCode(CmisBaseException ex) {
389         if (ex instanceof CmisConstraintException) {
390             return 409;
391         } else if (ex instanceof CmisContentAlreadyExistsException) {
392             return 409;
393         } else if (ex instanceof CmisFilterNotValidException) {
394             return 400;
395         } else if (ex instanceof CmisInvalidArgumentException) {
396             return 400;
397         } else if (ex instanceof CmisNameConstraintViolationException) {
398             return 409;
399         } else if (ex instanceof CmisNotSupportedException) {
400             return 405;
401         } else if (ex instanceof CmisObjectNotFoundException) {
402             return 404;
403         } else if (ex instanceof CmisPermissionDeniedException) {
404             return 403;
405         } else if (ex instanceof CmisStorageException) {
406             return 500;
407         } else if (ex instanceof CmisStreamNotSupportedException) {
408             return 403;
409         } else if (ex instanceof CmisUpdateConflictException) {
410             return 409;
411         } else if (ex instanceof CmisVersioningException) {
412             return 409;
413         }
414 
415         return 500;
416     }
417 
418     /**
419      * Prints the error as JSON.
420      */
421     private static void printError(Exception ex, HttpServletRequest request, HttpServletResponse response,
422             CallContext context) {
423         int statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
424         String exceptionName = "runtime";
425 
426         if (ex instanceof CmisRuntimeException) {
427             LOG.error(ex.getMessage(), ex);
428         } else if (ex instanceof CmisBaseException) {
429             statusCode = getErrorCode((CmisBaseException) ex);
430             exceptionName = ((CmisBaseException) ex).getExceptionName();
431         } else {
432             LOG.error(ex.getMessage(), ex);
433         }
434 
435         String transaction = (context == null ? null : (String) context.get(CONTEXT_TRANSACTION));
436 
437         if (transaction == null) {
438             setStatus(request, response, statusCode);
439             response.setContentType(JSON_MIME_TYPE);
440 
441             JSONObject jsonResponse = new JSONObject();
442             jsonResponse.put(ERROR_EXCEPTION, exceptionName);
443             jsonResponse.put(ERROR_MESSAGE, ex.getMessage());
444 
445             String st = ExceptionHelper.getStacktraceAsString(ex);
446             if (st != null) {
447                 jsonResponse.put(ERROR_STACKTRACE, st);
448             }
449 
450             try {
451                 writeJSON(jsonResponse, request, response);
452             } catch (Exception e) {
453                 LOG.error(e.getMessage(), e);
454             }
455         } else {
456             setStatus(request, response, HttpServletResponse.SC_OK);
457             response.setContentType(HTML_MIME_TYPE);
458             response.setContentLength(0);
459 
460             if (context != null) {
461                 setCookie(request, response, context.getRepositoryId(), transaction,
462                         createCookieValue(statusCode, null, exceptionName, ex.getMessage()));
463             }
464         }
465     }
466 }