org.apache.chemistry.opencmis.server.impl.browser.CmisBrowserBindingServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.chemistry.opencmis.server.impl.browser.CmisBrowserBindingServlet.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.chemistry.opencmis.server.impl.browser;

import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisFilterNotValidException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisNameConstraintViolationException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisStreamNotSupportedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisVersioningException;
import org.apache.chemistry.opencmis.commons.impl.Constants;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_ADD_OBJECT_TO_FOLDER;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_APPLY_ACL;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_APPLY_POLICY;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CANCEL_CHECK_OUT;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CHECK_IN;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CHECK_OUT;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CREATE_DOCUMENT;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CREATE_DOCUMENT_FROM_SOURCE;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CREATE_FOLDER;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CREATE_POLICY;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_CREATE_RELATIONSHIP;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_DELETE;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_DELETE_CONTENT;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_DELETE_TREE;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_MOVE;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_QUERY;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_REMOVE_OBJECT_FROM_FOLDER;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_REMOVE_POLICY;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_SET_CONTENT;
import static org.apache.chemistry.opencmis.commons.impl.Constants.CMISACTION_UPDATE_PROPERTIES;
import static org.apache.chemistry.opencmis.commons.impl.Constants.PARAM_OBJECT_ID;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_ACL;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_ALLOWABLEACTIONS;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_CHECKEDOUT;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_CHILDREN;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_CONTENT;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_CONTENT_CHANGES;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_DESCENDANTS;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_FOLDER_TREE;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_LAST_RESULT;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_OBJECT;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_PARENT;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_PARENTS;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_POLICIES;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_PROPERTIES;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_QUERY;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_RELATIONSHIPS;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_RENDITIONS;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_REPOSITORY_INFO;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_TYPE_CHILDREN;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_TYPE_DEFINITION;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_TYPE_DESCENDANTS;
import static org.apache.chemistry.opencmis.commons.impl.Constants.SELECTOR_VERSIONS;
import static org.apache.chemistry.opencmis.commons.impl.JSONConstants.ERROR_EXCEPTION;
import static org.apache.chemistry.opencmis.commons.impl.JSONConstants.ERROR_MESSAGE;
import static org.apache.chemistry.opencmis.commons.impl.JSONConstants.ERROR_STACKTRACE;
import org.apache.chemistry.opencmis.commons.impl.json.JSONObject;
import org.apache.chemistry.opencmis.commons.server.CallContext;
import org.apache.chemistry.opencmis.commons.server.CmisService;
import org.apache.chemistry.opencmis.commons.server.CmisServiceFactory;
import org.apache.chemistry.opencmis.server.impl.CmisRepositoryContextListener;
import org.apache.chemistry.opencmis.server.impl.ServerVersion;
import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.CONTEXT_BASETYPE_ID;
import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.CONTEXT_TRANSACTION;
import org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.CallUrl;
import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.HTML_MIME_TYPE;
import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.JSON_MIME_TYPE;
import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.createCookieValue;
import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.prepareContext;
import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.setCookie;
import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.setStatus;
import static org.apache.chemistry.opencmis.server.impl.browser.BrowserBindingUtils.writeJSON;
import org.apache.chemistry.opencmis.server.shared.CallContextHandler;
import org.apache.chemistry.opencmis.server.shared.Dispatcher;
import static org.apache.chemistry.opencmis.server.shared.Dispatcher.METHOD_GET;
import static org.apache.chemistry.opencmis.server.shared.Dispatcher.METHOD_POST;
import org.apache.chemistry.opencmis.server.shared.ExceptionHelper;
import org.apache.chemistry.opencmis.server.shared.HttpUtils;
import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getStringParameter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CmisBrowserBindingServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    public static final String PARAM_CALL_CONTEXT_HANDLER = "callContextHandler";
    private static final Log LOG = LogFactory.getLog(CmisBrowserBindingServlet.class.getName());
    private File tempDir;
    private int memoryThreshold;
    private Dispatcher repositoryDispatcher;
    private Dispatcher rootDispatcher;
    private CallContextHandler callContextHandler;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        // initialize the call context handler
        callContextHandler = null;

        String callContextHandlerClass = config.getInitParameter(PARAM_CALL_CONTEXT_HANDLER);

        if (callContextHandlerClass != null) {
            try {
                callContextHandler = (CallContextHandler) Class.forName(callContextHandlerClass).newInstance();
            } catch (Exception e) {
                throw new ServletException("Could not load call context handler: " + e, e);
            }
        }

        // get memory threshold and temp directory
        CmisServiceFactory factory = (CmisServiceFactory) config.getServletContext()
                .getAttribute(CmisRepositoryContextListener.SERVICES_FACTORY);

        tempDir = factory.getTempDirectory();
        memoryThreshold = factory.getMemoryThreshold();

        // initialize the dispatchers
        repositoryDispatcher = new Dispatcher(false);
        rootDispatcher = new Dispatcher(false);

        try {
            repositoryDispatcher.addResource(SELECTOR_REPOSITORY_INFO, METHOD_GET, RepositoryService.class,
                    "getRepositoryInfo");
            repositoryDispatcher.addResource(SELECTOR_LAST_RESULT, METHOD_GET, RepositoryService.class,
                    "getLastResult");
            repositoryDispatcher.addResource(SELECTOR_TYPE_CHILDREN, METHOD_GET, RepositoryService.class,
                    "getTypeChildren");
            repositoryDispatcher.addResource(SELECTOR_TYPE_DESCENDANTS, METHOD_GET, RepositoryService.class,
                    "getTypeDescendants");
            repositoryDispatcher.addResource(SELECTOR_TYPE_DEFINITION, METHOD_GET, RepositoryService.class,
                    "getTypeDefinition");
            repositoryDispatcher.addResource(SELECTOR_QUERY, METHOD_GET, DiscoveryService.class, "query");
            repositoryDispatcher.addResource(SELECTOR_CHECKEDOUT, METHOD_GET, NavigationService.class,
                    "getCheckedOutDocs");
            repositoryDispatcher.addResource(SELECTOR_CONTENT_CHANGES, METHOD_GET, DiscoveryService.class,
                    "getContentChanges");

            repositoryDispatcher.addResource(CMISACTION_QUERY, METHOD_POST, DiscoveryService.class, "query");
            repositoryDispatcher.addResource(CMISACTION_CREATE_DOCUMENT, METHOD_POST, ObjectService.class,
                    "createDocument");
            repositoryDispatcher.addResource(CMISACTION_CREATE_DOCUMENT_FROM_SOURCE, METHOD_POST,
                    ObjectService.class, "createDocumentFromSource");
            repositoryDispatcher.addResource(CMISACTION_CREATE_POLICY, METHOD_POST, ObjectService.class,
                    "createPolicy");
            repositoryDispatcher.addResource(CMISACTION_CREATE_RELATIONSHIP, METHOD_POST, ObjectService.class,
                    "createRelationship");

            rootDispatcher.addResource(SELECTOR_OBJECT, METHOD_GET, ObjectService.class, "getObject");
            rootDispatcher.addResource(SELECTOR_PROPERTIES, METHOD_GET, ObjectService.class, "getProperties");
            rootDispatcher.addResource(SELECTOR_ALLOWABLEACTIONS, METHOD_GET, ObjectService.class,
                    "getAllowableActions");
            rootDispatcher.addResource(SELECTOR_RENDITIONS, METHOD_GET, ObjectService.class, "getRenditions");
            rootDispatcher.addResource(SELECTOR_CONTENT, METHOD_GET, ObjectService.class, "getContentStream");
            rootDispatcher.addResource(SELECTOR_CHILDREN, METHOD_GET, NavigationService.class, "getChildren");
            rootDispatcher.addResource(SELECTOR_DESCENDANTS, METHOD_GET, NavigationService.class, "getDescendants");
            rootDispatcher.addResource(SELECTOR_FOLDER_TREE, METHOD_GET, NavigationService.class, "getFolderTree");
            rootDispatcher.addResource(SELECTOR_PARENT, METHOD_GET, NavigationService.class, "getFolderParent");
            rootDispatcher.addResource(SELECTOR_PARENTS, METHOD_GET, NavigationService.class, "getObjectParents");
            rootDispatcher.addResource(SELECTOR_VERSIONS, METHOD_GET, VersioningService.class, "getAllVersions");
            rootDispatcher.addResource(SELECTOR_RELATIONSHIPS, METHOD_GET, RelationshipService.class,
                    "getObjectRelationships");
            rootDispatcher.addResource(SELECTOR_CHECKEDOUT, METHOD_GET, NavigationService.class,
                    "getCheckedOutDocs");
            rootDispatcher.addResource(SELECTOR_POLICIES, METHOD_GET, PolicyService.class, "getAppliedPolicies");
            rootDispatcher.addResource(SELECTOR_ACL, METHOD_GET, AclService.class, "getACL");

            rootDispatcher.addResource(CMISACTION_CREATE_DOCUMENT, METHOD_POST, ObjectService.class,
                    "createDocument");
            rootDispatcher.addResource(CMISACTION_CREATE_DOCUMENT_FROM_SOURCE, METHOD_POST, ObjectService.class,
                    "createDocumentFromSource");
            rootDispatcher.addResource(CMISACTION_CREATE_FOLDER, METHOD_POST, ObjectService.class, "createFolder");
            rootDispatcher.addResource(CMISACTION_CREATE_POLICY, METHOD_POST, ObjectService.class, "createPolicy");
            rootDispatcher.addResource(CMISACTION_UPDATE_PROPERTIES, METHOD_POST, ObjectService.class,
                    "updateProperties");
            rootDispatcher.addResource(CMISACTION_SET_CONTENT, METHOD_POST, ObjectService.class,
                    "setContentStream");
            rootDispatcher.addResource(CMISACTION_DELETE_CONTENT, METHOD_POST, ObjectService.class,
                    "deleteContentStream");
            rootDispatcher.addResource(CMISACTION_DELETE, METHOD_POST, ObjectService.class, "deleteObject");
            rootDispatcher.addResource(CMISACTION_DELETE_TREE, METHOD_POST, ObjectService.class, "deleteTree");
            rootDispatcher.addResource(CMISACTION_MOVE, METHOD_POST, ObjectService.class, "moveObject");
            rootDispatcher.addResource(CMISACTION_ADD_OBJECT_TO_FOLDER, METHOD_POST, MultiFilingService.class,
                    "addObjectToFolder");
            rootDispatcher.addResource(CMISACTION_REMOVE_OBJECT_FROM_FOLDER, METHOD_POST, MultiFilingService.class,
                    "removeObjectFromFolder");
            rootDispatcher.addResource(CMISACTION_CHECK_OUT, METHOD_POST, VersioningService.class, "checkOut");
            rootDispatcher.addResource(CMISACTION_CANCEL_CHECK_OUT, METHOD_POST, VersioningService.class,
                    "cancelCheckOut");
            rootDispatcher.addResource(CMISACTION_CHECK_IN, METHOD_POST, VersioningService.class, "checkIn");
            rootDispatcher.addResource(CMISACTION_APPLY_POLICY, METHOD_POST, PolicyService.class, "applyPolicy");
            rootDispatcher.addResource(CMISACTION_REMOVE_POLICY, METHOD_POST, PolicyService.class, "removePolicy");
            rootDispatcher.addResource(CMISACTION_APPLY_ACL, METHOD_POST, AclService.class, "applyACL");
        } catch (NoSuchMethodException e) {
            LOG.error("Cannot initialize dispatcher!", e);
        }
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // set default headers
        response.addHeader("Cache-Control", "private, max-age=0");
        response.addHeader("Server", ServerVersion.OPENCMIS_SERVER);

        // create a context object, dispatch and handle exceptions
        CallContext context = null;

        try {
            context = HttpUtils.createContext(request, response, getServletContext(), CallContext.BINDING_BROWSER,
                    callContextHandler, tempDir, memoryThreshold);
            dispatch(context, request, response);
        } catch (Exception e) {
            if (e instanceof CmisPermissionDeniedException) {
                if ((context == null) || (context.getUsername() == null)) {
                    response.setHeader("WWW-Authenticate", "Basic realm=\"CMIS\"");
                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization Required");
                } else {
                    printError(e, request, response, context);
                }
            } else {
                printError(e, request, response, context);
            }
        }

        // we are done.
        response.flushBuffer();
    }

    // --------------------------------------------------------
    private void dispatch(CallContext context, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        CmisService service = null;

        try {
            // get services factory
            CmisServiceFactory factory = (CmisServiceFactory) getServletContext()
                    .getAttribute(CmisRepositoryContextListener.SERVICES_FACTORY);

            if (factory == null) {
                throw new CmisRuntimeException("Service factory not available! Configuration problem?");
            }

            // get the service
            service = factory.getService(context);

            // analyze the path
            String[] pathFragments = HttpUtils.splitPath(request);

            if (pathFragments.length < 4) {
                // root -> repository infos
                RepositoryService.getRepositories(context, service, request, response);

                return;
            }

            // select dispatcher
            System.out.println("pathFragments.length=" + pathFragments.length);

            CallUrl callUrl = null;

            if (pathFragments.length == 4) {
                callUrl = CallUrl.REPOSITORY;
            } else if (BrowserBindingUtils.ROOT_PATH_FRAGMENT.equals(pathFragments[4])) {
                callUrl = CallUrl.ROOT;
            }

            if (callUrl == null) {
                throw new CmisNotSupportedException("Unknown operation");
            }

            String method = request.getMethod();
            String repositoryId = pathFragments[3];
            boolean methodFound = false;

            if (METHOD_GET.equals(method)) {
                String selector = getStringParameter(request, Constants.PARAM_SELECTOR);
                String objectId = getStringParameter(request, PARAM_OBJECT_ID);

                // add object id and object base type id to context
                prepareContext(context, callUrl, service, repositoryId, objectId, null, request);

                // dispatch
                if (callUrl == CallUrl.REPOSITORY) {
                    if (selector == null) {
                        selector = "";
                    }

                    methodFound = repositoryDispatcher.dispatch(selector, method, context, service, repositoryId,
                            request, response);
                } else if (callUrl == CallUrl.ROOT) {
                    // set default method if necessary
                    if (selector == null) {
                        try {
                            BaseTypeId basetype = BaseTypeId.fromValue((String) context.get(CONTEXT_BASETYPE_ID));

                            switch (basetype) {
                            case CMIS_DOCUMENT:
                                selector = SELECTOR_CONTENT;

                                break;

                            case CMIS_FOLDER:
                                selector = SELECTOR_CHILDREN;

                                break;

                            default:
                                selector = SELECTOR_OBJECT;

                                break;
                            }
                        } catch (Exception e) {
                            selector = SELECTOR_OBJECT;
                        }
                    }

                    methodFound = rootDispatcher.dispatch(selector, method, context, service, repositoryId, request,
                            response);
                }
            } else if (METHOD_POST.equals(method)) {
                POSTHttpServletRequestWrapper postRequest = new POSTHttpServletRequestWrapper(request, tempDir,
                        memoryThreshold);

                String cmisaction = getStringParameter(postRequest, Constants.CONTROL_CMISACTION);
                String objectId = getStringParameter(postRequest, Constants.CONTROL_OBJECT_ID);
                String transaction = getStringParameter(postRequest, Constants.CONTROL_TRANSACTION);

                if ((cmisaction == null) || (cmisaction.length() == 0)) {
                    throw new CmisNotSupportedException("Unknown action");
                }

                // add object id and object base type id to context
                prepareContext(context, callUrl, service, repositoryId, objectId, transaction, postRequest);

                // dispatch
                if (callUrl == CallUrl.REPOSITORY) {
                    methodFound = repositoryDispatcher.dispatch(cmisaction, method, context, service, repositoryId,
                            postRequest, response);
                } else if (callUrl == CallUrl.ROOT) {
                    methodFound = rootDispatcher.dispatch(cmisaction, method, context, service, repositoryId,
                            postRequest, response);
                }
            }

            // if the dispatcher couldn't find a matching method, return an
            // error message
            if (!methodFound) {
                throw new CmisNotSupportedException("Unknown operation");
            }
        } finally {
            if (service != null) {
                service.close();
            }
        }
    }

    /**
     * Translates an exception in an appropriate HTTP error code.
     */
    private static int getErrorCode(CmisBaseException ex) {
        if (ex instanceof CmisConstraintException) {
            return 409;
        } else if (ex instanceof CmisContentAlreadyExistsException) {
            return 409;
        } else if (ex instanceof CmisFilterNotValidException) {
            return 400;
        } else if (ex instanceof CmisInvalidArgumentException) {
            return 400;
        } else if (ex instanceof CmisNameConstraintViolationException) {
            return 409;
        } else if (ex instanceof CmisNotSupportedException) {
            return 405;
        } else if (ex instanceof CmisObjectNotFoundException) {
            return 404;
        } else if (ex instanceof CmisPermissionDeniedException) {
            return 403;
        } else if (ex instanceof CmisStorageException) {
            return 500;
        } else if (ex instanceof CmisStreamNotSupportedException) {
            return 403;
        } else if (ex instanceof CmisUpdateConflictException) {
            return 409;
        } else if (ex instanceof CmisVersioningException) {
            return 409;
        }

        return 500;
    }

    /**
     * Prints the error as JSON.
     */
    private static void printError(Exception ex, HttpServletRequest request, HttpServletResponse response,
            CallContext context) {
        int statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
        String exceptionName = "runtime";

        if (ex instanceof CmisRuntimeException) {
            LOG.error(ex.getMessage(), ex);
        } else if (ex instanceof CmisBaseException) {
            statusCode = getErrorCode((CmisBaseException) ex);
            exceptionName = ((CmisBaseException) ex).getExceptionName();
        } else {
            LOG.error(ex.getMessage(), ex);
        }

        String transaction = ((context == null) ? null : (String) context.get(CONTEXT_TRANSACTION));

        if (transaction == null) {
            setStatus(request, response, statusCode);
            response.setContentType(JSON_MIME_TYPE);

            JSONObject jsonResponse = new JSONObject();
            jsonResponse.put(ERROR_EXCEPTION, exceptionName);
            jsonResponse.put(ERROR_MESSAGE, ex.getMessage());

            String st = ExceptionHelper.getStacktraceAsString(ex);

            if (st != null) {
                jsonResponse.put(ERROR_STACKTRACE, st);
            }

            try {
                writeJSON(jsonResponse, request, response);
            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
            }
        } else {
            setStatus(request, response, HttpServletResponse.SC_OK);
            response.setContentType(HTML_MIME_TYPE);
            response.setContentLength(0);

            if (context != null) {
                setCookie(request, response, context.getRepositoryId(), transaction,
                        createCookieValue(statusCode, null, exceptionName, ex.getMessage()));
            }
        }
    }
}