1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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
150 CmisServiceFactory factory = (CmisServiceFactory) config.getServletContext().getAttribute(
151 CmisRepositoryContextListener.SERVICES_FACTORY);
152
153 tempDir = factory.getTempDirectory();
154 memoryThreshold = factory.getMemoryThreshold();
155
156
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
240 response.addHeader("Cache-Control", "private, max-age=0");
241 response.addHeader("Server", ServerVersion.OPENCMIS_SERVER);
242
243
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
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
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
281 service = factory.getService(context);
282
283
284 String[] pathFragments = HttpUtils.splitPath(request);
285
286 if (pathFragments.length < 1) {
287
288 RepositoryService.getRepositories(context, service, request, response);
289 return;
290 }
291
292
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
314 prepareContext(context, callUrl, service, repositoryId, objectId, null, request);
315
316
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
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
361 prepareContext(context, callUrl, service, repositoryId, objectId, transaction, postRequest);
362
363
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
374
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
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
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 }