org.eclipse.orion.server.cf.servlets.AbstractRESTHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.orion.server.cf.servlets.AbstractRESTHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2013 IBM Corporation and others 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 * IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.orion.server.cf.servlets;

import java.io.InputStreamReader;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.orion.internal.server.servlets.ServletResourceHandler;
import org.eclipse.orion.internal.server.servlets.task.TaskJobHandler;
import org.eclipse.orion.server.cf.jobs.CFJob;
import org.eclipse.orion.server.cf.objects.CFObject;
import org.eclipse.orion.server.core.ServerStatus;
import org.eclipse.orion.server.servlets.JsonURIUnqualificationStrategy;
import org.eclipse.osgi.util.NLS;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An abstract REST object handler. The class contains a set of default helper methods
 * for common functions, e. g. resource extraction, error handing, etc.
 */
public abstract class AbstractRESTHandler<T extends CFObject> extends ServletResourceHandler<String> {

    private final Logger logger = LoggerFactory.getLogger("org.eclipse.orion.server.cf"); //$NON-NLS-1$

    protected ServletResourceHandler<IStatus> statusHandler;

    public AbstractRESTHandler(ServletResourceHandler<IStatus> statusHandler) {
        this.statusHandler = statusHandler;
    }

    /**
     * Builds the handled resource according to custom criteria.
     * @param request The request object used to build the resource.
     * @param path Path suffix required to handle the request.
     * @throws CoreException if the resource cannot be constructed due to an internal server error.
     * @return <code>null</code> if the resource cannot be constructed due to invalid request, the resource object otherwise.
     */
    protected abstract T buildResource(HttpServletRequest request, String path) throws CoreException;

    /**
     * Helper method for PUT data extraction.
     * @param request The PUT requested to be processed.
     * @return The extracted data JSON or null if none provided or invalid JSON format.
     */
    protected JSONObject extractJSONData(final HttpServletRequest request) {
        try {
            JSONTokener tokener = new JSONTokener(new InputStreamReader(request.getInputStream()));
            return new JSONObject(tokener);
        } catch (Exception ex) {
            return null;
        }
    }

    protected JSONObject extractJSONData(final String param) {
        try {
            return param != null ? new JSONObject(URLDecoder.decode(param, "UTF8")) : null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Handles a GET request. Note this method is meant to be overridden in descendant classes.
     * @param request The GET request being handled.
     * @param response The response associated with the request.
     * @param path Path suffix required to handle the request.
     * @return A {@link JazzJob} which returns the requested resource on completion.
     */
    protected CFJob handleGet(T resource, final HttpServletRequest request, final HttpServletResponse response,
            final String path) {
        return new CFJob(request, false) {
            @Override
            protected IStatus performJob() {
                String msg = NLS.bind("Failed to handle request for {0}", path); //$NON-NLS-1$
                return new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_IMPLEMENTED, msg, null);
            }
        };
    }

    /**
     * Handles an idempotent PUT request. Note this method is meant to be overridden in descendant classes.
     * @param request The PUT request being handled.
     * @param response The response associated with the request.
     * @param path Path suffix required to handle the request.
     * @return A {@link JazzJob} which returns the PUT request result on completion. 
     */
    protected CFJob handlePut(T resource, final HttpServletRequest request, final HttpServletResponse response,
            final String path) {
        return new CFJob(request, false) {
            @Override
            protected IStatus performJob() {
                String msg = NLS.bind("Failed to handle request for {0}", path); //$NON-NLS-1$
                return new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_IMPLEMENTED, msg, null);
            }
        };
    }

    /**
     * Handles a POST request. Note this method is meant to be overridden in descendant classes.
     * The POST request is not idempotent as PUT, although it may handle similar operations.
     * @param request The POST request being handled.
     * @param response The response associated with the request.
     * @param path Path suffix required to handle the request.
     * @return A {@link JazzJob} which returns the POST request result on completion.
     */
    protected CFJob handlePost(final T resource, final HttpServletRequest request,
            final HttpServletResponse response, final String path) {
        return new CFJob(request, false) {
            @Override
            protected IStatus performJob() {
                String msg = NLS.bind("Failed to handle request for {0}", path); //$NON-NLS-1$
                return new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_IMPLEMENTED, msg, null);
            }
        };
    }

    /**
     * Handles a DELETE request. Note this method is meant to be overridden in descendant classes.
     * @param request The DELETE request being handled.
     * @param response The response associated with the request.
     * @param path Path suffix required to handle the request.
     * @return A {@link JazzJob} which returns the DELETE request result on completion.
     */
    protected CFJob handleDelete(T resource, final HttpServletRequest request, final HttpServletResponse response,
            final String path) {
        return new CFJob(request, false) {
            @Override
            protected IStatus performJob() {
                String msg = NLS.bind("Failed to handle request for {0}", path); //$NON-NLS-1$
                return new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_IMPLEMENTED, msg, null);
            }
        };
    }

    /**
     * A helper method which handles returning a 404 HTTP error status.
     * @param request The request being handled.
     * @param response The response associated with the request.
     * @param path Path mapped to the handled request. Used to display the error message.
     * @return <code>true</code> iff the 404 has been sent, <code>false</code> otherwise.
     */
    protected boolean handleNotExistingResource(HttpServletRequest request, HttpServletResponse response,
            String path) throws ServletException {
        String msg = NLS.bind("Failed to handle request for {0}", path); //$NON-NLS-1$
        ServerStatus status = new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_FOUND, msg, null);
        return statusHandler.handleRequest(request, response, status);
    }

    /**
     * A helper method which handles returning a 409 HTTP error status.
     * @param request The request being handled.
     * @param response The response associated with the request.
     * @param path Path mapped to the handled request. Used to display the error message.
     * @return <code>true</code> iff the 409 has been sent, <code>false</code> otherwise.
     */
    protected boolean handleConflictingResource(HttpServletRequest request, HttpServletResponse response,
            String path) throws ServletException {
        String msg = NLS.bind("Failed to handle request for {0}", path); //$NON-NLS-1$
        ServerStatus status = new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_CONFLICT, msg, null);
        return statusHandler.handleRequest(request, response, status);
    }

    @Override
    public boolean handleRequest(HttpServletRequest request, HttpServletResponse response, String path)
            throws ServletException {
        try {
            /* build the request resource */
            T resource = buildResource(request, path);

            switch (getMethod(request)) {
            case GET:
                CFJob getJob = handleGet(resource, request, response, path);
                return TaskJobHandler.handleTaskJob(request, response, getJob, statusHandler,
                        JsonURIUnqualificationStrategy.LOCATION_ONLY);

            case PUT:
                CFJob putJob = handlePut(resource, request, response, path);
                return TaskJobHandler.handleTaskJob(request, response, putJob, statusHandler,
                        JsonURIUnqualificationStrategy.LOCATION_ONLY);

            case POST:
                CFJob postJob = handlePost(resource, request, response, path);
                return TaskJobHandler.handleTaskJob(request, response, postJob, statusHandler,
                        JsonURIUnqualificationStrategy.LOCATION_ONLY);

            case DELETE:
                CFJob deleteJob = handleDelete(resource, request, response, path);
                return TaskJobHandler.handleTaskJob(request, response, deleteJob, statusHandler,
                        JsonURIUnqualificationStrategy.LOCATION_ONLY);

            default:
                /* we don't know how to handle this request */
                return false;
            }
        } catch (Exception e) {
            String msg = NLS.bind("Failed to handle request for {0}", path); //$NON-NLS-1$
            ServerStatus status = new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg,
                    e);
            logger.error(msg, e);
            return statusHandler.handleRequest(request, response, status);
        }
    }
}