Package org.restlet.ext.jaxrs.internal.util

Source Code of org.restlet.ext.jaxrs.internal.util.ExceptionHandler

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.ext.jaxrs.internal.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Variant;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;

import org.restlet.Request;
import org.restlet.Restlet;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.ext.jaxrs.InstantiateException;
import org.restlet.ext.jaxrs.internal.core.CallContext;
import org.restlet.ext.jaxrs.internal.exceptions.ConvertRepresentationException;
import org.restlet.ext.jaxrs.internal.exceptions.MethodInvokeException;
import org.restlet.ext.jaxrs.internal.exceptions.MissingAnnotationException;
import org.restlet.ext.jaxrs.internal.exceptions.NotAcceptableWebAppException;
import org.restlet.ext.jaxrs.internal.exceptions.RequestHandledException;
import org.restlet.ext.jaxrs.internal.exceptions.UnsupportedMediaTypeWebAppException;
import org.restlet.ext.jaxrs.internal.wrappers.AbstractMethodWrapper;
import org.restlet.ext.jaxrs.internal.wrappers.ResourceMethod;

/**
* <p>
* This class contains the methods to handle exceptions occuring in the
* {@link org.restlet.ext.jaxrs.JaxRsRestlet}, e.g. while identifying the method
* that should handle the request.<br>
* Therefor it contains some Restlets that handles this exceptions.
* </p>
* <p>
* Perhaps this class gets again public. Perhaps the special Restlets for
* handling will be removed, or stay only for 404.
* </p>
*
* @author Stephan Koops
*/
public class ExceptionHandler {

    private static final String HEADER_ALLOW = "Allow";

    /**
     * @param supporting
     * @return
     */
    private static Set<Variant> getSupportedVariants(
            Collection<ResourceMethod> supporting) {
        final Set<Variant> supportedVariants = new HashSet<Variant>();
        for (final ResourceMethod resourceMethod : supporting) {
            supportedVariants.addAll(resourceMethod.getSupportedVariants());
        }
        return supportedVariants;
    }

    private final Logger logger;

    private volatile Restlet noResMethodHandler;

    private volatile Restlet noResourceClHandler;

    private volatile Restlet noRootResClHandler;

    /**
     * Creates a new ExceptionHandler.
     *
     * @param logger
     *            the logger to use
     */
    public ExceptionHandler(Logger logger) {
        this.logger = logger;
    }

    /**
     * handles a {@link ConvertRepresentationException}
     *
     * @param cre
     * @return (static the thrown exeption for the compiler)
     * @throws WebApplicationException
     */
    public WebApplicationException convertRepresentationExc(
            ConvertRepresentationException cre) throws WebApplicationException {
        final ResponseBuilder rb = Response.status(Status.BAD_REQUEST);
        final StringWriter stw = new StringWriter();
        cre.printStackTrace(new PrintWriter(stw));
        rb.entity(stw.toString());
        throw new WebApplicationException(cre, rb.build());
    }

    /**
     * Returns the Restlet that is called, if no resource method class could be
     * found.
     *
     * @return the Restlet that is called, if no resource method class could be
     *         found.
     * @see #setNoResMethodHandler(Restlet)
     */
    public Restlet getNoResMethodHandler() {
        return noResMethodHandler;
    }

    /**
     * Returns the Restlet that is called, if no resource class could be found.
     *
     * @return the Restlet that is called, if no resource class could be found.
     */
    public Restlet getNoResourceClHandler() {
        return noResourceClHandler;
    }

    /**
     * Returns the Restlet that is called, if no root resource class could be
     * found.
     *
     * @return the Restlet that is called, if no root resource class could be
     *         found.
     * @see #setNoRootResClHandler(Restlet)
     */
    public Restlet getNoRootResClHandler() {
        return noRootResClHandler;
    }

    /**
     * Handles the given Exception, catched by an invoke of a resource method or
     * a creation if a sub resource object.
     *
     * @param exception
     * @param callContext
     *            Contains the encoded template Parameters, that are read from
     *            the called URI, the Restlet {@link org.restlet.Request} and
     *            the Restlet {@link org.restlet.Response}.
     * @param methodName
     * @param logMessage
     * @return staticly to throw, if needed by compiler.
     * @throws RequestHandledException
     *             throws this message to exit the method and indicate, that the
     *             request was handled.
     * @throws RequestHandledException
     */
    public RequestHandledException instantiateExecption(
            InstantiateException exception, CallContext callContext,
            String logMessage) throws RequestHandledException {
        callContext.getResponse().setStatus(
                org.restlet.data.Status.SERVER_ERROR_INTERNAL);
        this.logger.log(Level.WARNING, logMessage, exception.getCause());
        exception.printStackTrace();
        throw new RequestHandledException();
    }

    /**
     * Handles the given Exception, catched by an invoke of a resource method or
     * a creation if a sub resource object.
     *
     * @param exception
     * @param callContext
     *            Contains the encoded template Parameters, that are read from
     *            the called URI, the Restlet {@link org.restlet.Request} and
     *            the Restlet {@link org.restlet.Response}.
     * @param methodName
     * @param logMessage
     * @return staticly to throw, if needed by compiler.
     * @throws RequestHandledException
     *             throws this message to exit the method and indicate, that the
     *             request was handled.
     * @throws RequestHandledException
     */
    public RequestHandledException methodInvokeException(
            MethodInvokeException exception, CallContext callContext,
            String logMessage) throws RequestHandledException {
        callContext.getResponse().setStatus(
                org.restlet.data.Status.SERVER_ERROR_INTERNAL);
        this.logger.log(Level.WARNING, logMessage, exception.getCause());
        exception.printStackTrace();
        throw new RequestHandledException();
    }

    /**
     * @param allowedMethods
     * @throws WebApplicationException
     */
    public void methodNotAllowed(Set<Method> allowedMethods)
            throws WebApplicationException {
        final ResponseBuilder rb = Response
                .status(org.restlet.data.Status.CLIENT_ERROR_METHOD_NOT_ALLOWED
                        .getCode());
        rb.header(HEADER_ALLOW, Util.toString(allowedMethods, ", "));
        throw new WebApplicationException(rb.build());
    }

    /**
     * Handles the given Exception, catched by an invoke of a resource method or
     * a creation if a sub resource object.
     *
     * @param exception
     * @param callContext
     *            Contains the encoded template Parameters, that are read from
     *            the called URI, the Restlet {@link org.restlet.Request} and
     *            the Restlet {@link org.restlet.Response}.
     * @param methodName
     * @param logMessage
     * @return staticly to throw, if needed by compiler.
     * @throws RequestHandledException
     *             throws this message to exit the method and indicate, that the
     *             request was handled.
     * @throws RequestHandledException
     */
    public RequestHandledException missingAnnotation(
            MissingAnnotationException exception, CallContext callContext,
            String logMessage) throws RequestHandledException {
        callContext.getResponse().setStatus(
                org.restlet.data.Status.SERVER_ERROR_INTERNAL);
        if (exception != null) {
            logMessage += ": " + exception.getMessage();
        }
        this.logger.log(Level.WARNING, logMessage);
        throw new RequestHandledException();
    }

    /**
     * @param entityClass
     * @param genericType
     * @param annotations
     * @param respMediaType
     * @param accMediaTypes
     * @return (static the thrown exeption for the compiler)
     * @throws WebApplicationException
     *             the exception to throw according to the JAX-RS specification.
     */
    public WebApplicationException noMessageBodyWriter(
            Class<? extends Object> entityClass, Type genericType,
            Annotation[] annotations, MediaType respMediaType,
            SortedMetadata<MediaType> accMediaTypes)
            throws WebApplicationException {
        String warning = "No message body writer found for class "
                + entityClass + ", genericType " + genericType;
        if (respMediaType != null) {
            warning += "; response media type should be: " + respMediaType;
        }
        if (accMediaTypes != null) {
            warning += "; accepted media types are: " + accMediaTypes;
        }
        this.logger.warning(warning);
        annotations.toString(); // LATER log also annotations
        // NICE get as parameters the accMediaTypes and the entityClass.
        // and return supported MediaTypes as entity
        throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
    }

    /**
     * see spec, section 3.7.2, item 3(a).4
     *
     * @param supporting
     *            the methods supporting the requested resource and the given
     *            HTTP method.
     * @throws WebApplicationException
     */
    public void noResourceMethodForAccMediaTypes(
            Collection<ResourceMethod> supporting)
            throws WebApplicationException {
        final Set<Variant> supportedVariants = getSupportedVariants(supporting);
        throw new NotAcceptableWebAppException(supportedVariants);
    }

    /**
     * see spec, section 3.8, item 6
     *
     * @return staticly to throw, if needed by compiler.
     * @throws WebApplicationException
     */
    public WebApplicationException notAcceptableWhileDetermineMediaType()
            throws WebApplicationException {
        // NICE return supported MediaTypes as entity
        throw new WebApplicationException(Status.NOT_ACCEPTABLE);
    }

    /**
     * Handles the case, if no resource method was found. If a Restlet to handle
     * this case was given (see {@link #setNoResMethodHandler(Restlet)}), it is
     * called. Otherwise a {@link WebApplicationException} with status 404 is
     * thrown (see JAX-RS specification)
     *
     * @throws WebApplicationException
     * @throws RequestHandledException
     */
    public void resourceMethodNotFound() throws WebApplicationException,
            RequestHandledException {
        if (this.noResMethodHandler != null) {
            this.noResMethodHandler.handle(Request.getCurrent(),
                    org.restlet.Response.getCurrent());
            throw new RequestHandledException();
        }

        throw new WebApplicationException(Status.NOT_FOUND);
    }

    /**
     * Handles the case, if no resource class was found. If a Restlet to handle
     * this case was given (see {@link #setNoResourceClHandler(Restlet)}), it is
     * called. Otherwise a {@link WebApplicationException} with status 404 is
     * thrown (see spec, section 3.7.2, item 2e)
     *
     * @throws WebApplicationException
     * @throws RequestHandledException
     */
    public void resourceNotFound() throws WebApplicationException,
            RequestHandledException {
        if (this.noResourceClHandler != null) {
            this.noResourceClHandler.handle(Request.getCurrent(),
                    org.restlet.Response.getCurrent());
            throw new RequestHandledException();
        }

        throw new WebApplicationException(Status.NOT_FOUND);
    }

    /**
     * Handles the case, if no root resource class was found. If a Restlet to
     * handle this case was given (see {@link #setNoRootResClHandler(Restlet)}),
     * it is called. Otherwise a {@link WebApplicationException} with status 404
     * is thrown (see JAX-RS specification, section 3.7.2, item 1d)
     *
     * @throws WebApplicationException
     * @throws RequestHandledException
     */
    public void rootResourceNotFound() throws WebApplicationException,
            RequestHandledException {
        if (this.noRootResClHandler != null) {
            this.noRootResClHandler.handle(Request.getCurrent(),
                    org.restlet.Response.getCurrent());
            throw new RequestHandledException();
        }

        throw new WebApplicationException(Status.NOT_FOUND);
    }

    /**
     * Handles the given Exception, catched by an invoke of a resource method or
     * a creation if a sub resource object.
     *
     * @param exception
     *            the exception to log
     * @param jaxRsMethod
     *            the called method when the exception occurs. May be null.
     * @param callContext
     *            Contains the encoded template Parameters, that are read from
     *            the called URI, the Restlet {@link org.restlet.Request} and
     *            the Restlet {@link org.restlet.Response}.
     * @param logMessage
     * @param methodName
     * @return staticly to throw, if needed by compiler.
     * @throws RequestHandledException
     *             throws this message to exit the method and indicate, that the
     *             request was handled.
     * @throws RequestHandledException
     */
    public RequestHandledException runtimeExecption(RuntimeException exception,
            AbstractMethodWrapper jaxRsMethod, CallContext callContext,
            String logMessage) throws RequestHandledException {
        callContext.getResponse().setStatus(
                org.restlet.data.Status.SERVER_ERROR_INTERNAL);
        if (jaxRsMethod != null) {
            logMessage = jaxRsMethod + ": " + logMessage;
        }
        this.logger.log(Level.WARNING, jaxRsMethod + ": " + logMessage,
                exception);
        exception.printStackTrace();
        throw new RequestHandledException();
    }

    /**
     * Sets the Restlet that will handle the {@link Request}s, if no resource
     * method could be found.
     *
     * @param noResMethodHandler
     *            the noResMethodHandler to set
     * @see #getNoResMethodHandler()
     * @see #setNoResourceClHandler(Restlet)
     * @see #setNoRootResClHandler(Restlet)
     */
    public void setNoResMethodHandler(Restlet noResMethodHandler) {
        this.noResMethodHandler = noResMethodHandler;
    }

    /**
     * Sets the Restlet that will handle the {@link Request}s, if no resource
     * class could be found.
     *
     * @param noResourceClHandler
     *            the noResourceClHandler to set
     * @see #getNoResourceClHandler()
     * @see #setNoResMethodHandler(Restlet)
     * @see #setNoRootResClHandler(Restlet)
     */
    public void setNoResourceClHandler(Restlet noResourceClHandler) {
        this.noResourceClHandler = noResourceClHandler;
    }

    /**
     * Sets the Restlet that is called, if no root resource class could be
     * found.
     *
     * @param noRootResClHandler
     *            the Restlet to call, if no root resource class could be found.
     * @see #getNoRootResClHandler(Restlet)
     * @see #setNoResourceClHandler()
     * @see #setNoResMethodHandler(Restlet)
     */
    public void setNoRootResClHandler(Restlet noRootResClHandler) {
        this.noRootResClHandler = noRootResClHandler;
    }

    /**
     * see spec, section 3.7.2, item 3 (a) .3
     *
     * @param accepting
     *            resource methods for the requested resource and the given HTTP
     *            method.
     * @throws WebApplicationException
     */
    public void unsupportedMediaType(Collection<ResourceMethod> accepting)
            throws WebApplicationException {
        final Set<Variant> acceptedVariants = getSupportedVariants(accepting);
        throw new UnsupportedMediaTypeWebAppException(acceptedVariants);
    }
}
TOP

Related Classes of org.restlet.ext.jaxrs.internal.util.ExceptionHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.