/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or 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 Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * 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://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.ext.servlet; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.restlet.Context; import org.restlet.Restlet; import org.restlet.data.Reference; import org.restlet.engine.Engine; import org.restlet.engine.adapter.HttpRequest; import org.restlet.engine.adapter.HttpResponse; import org.restlet.ext.servlet.internal.ServletCall; import org.restlet.ext.servlet.internal.ServletLogger; import org.restlet.ext.servlet.internal.ServletServerAdapter; import org.restlet.routing.Router; /** * HTTP adapter from Servlet calls to Restlet calls. This class can be used in * any Servlet, just create a new instance and override the service() method in * your Servlet to delegate all those calls to this class's service() method. * Remember to set the next {@link Restlet}, for example using a {@link Router} * instance. You can get the Restlet context directly on instances of this * class, it will be based on the parent Servlet's context for logging purpose.<br> * <br> * This class is especially useful when directly integrating Restlets with * Spring managed Web applications. Here is a simple usage example: * * <pre> * public class TestServlet extends HttpServlet { * private ServletAdapter adapter; * * public void init() throws ServletException { * super.init(); * this.adapter = new ServletAdapter(getServletContext()); * * Restlet trace = new Restlet(this.adapter.getContext()) { * public void handle(Request req, Response res) { * getLogger().info("Hello World"); * res.setEntity("Hello World!", MediaType.TEXT_PLAIN); * } * }; * * this.adapter.setNext(trace); * } * * protected void service(HttpServletRequest req, HttpServletResponse res) * throws ServletException, IOException { * this.adapter.service(req, res); * } * } * </pre> * * @author Jerome Louvel */ public class ServletAdapter extends ServletServerAdapter { /** The next Restlet. */ private volatile Restlet next; /** * Constructor. Remember to manually set the "target" property before * invoking the service() method. * * @param context * The Servlet context. */ public ServletAdapter(ServletContext context) { this(context, null); } /** * Constructor. * * @param context * The Servlet context. * @param next * The next Restlet. */ public ServletAdapter(ServletContext context, Restlet next) { // [ifndef gae] instruction super(new Context(new ServletLogger(context))); // [ifdef gae] instruction uncomment // super(new Context()); this.next = next; } /** * Returns the base reference of new Restlet requests. * * @param request * The Servlet request. * @return The base reference of new Restlet requests. */ public Reference getBaseRef(HttpServletRequest request) { Reference result = null; final String basePath = request.getContextPath() + request.getServletPath(); final String baseUri = request.getRequestURL().toString(); // Path starts at first slash after scheme:// final int pathStart = baseUri.indexOf("/", request.getScheme().length() + 3); if (basePath.length() == 0) { // basePath is empty in case the webapp is mounted on root context if (pathStart != -1) { result = new Reference(baseUri.substring(0, pathStart)); } else { result = new Reference(baseUri); } } else { if (pathStart != -1) { final int baseIndex = baseUri.indexOf(basePath, pathStart); if (baseIndex != -1) { result = new Reference(baseUri.substring(0, baseIndex + basePath.length())); } } } return result; } /** * Returns the next Restlet. * * @return The next Restlet. */ public Restlet getNext() { return this.next; } /** * Returns the root reference of new Restlet requests. By default it returns * the result of getBaseRef(). * * @param request * The Servlet request. * @return The root reference of new Restlet requests. */ public Reference getRootRef(HttpServletRequest request) { return getBaseRef(request); } /** * Services a HTTP Servlet request as a Restlet request handled by the * "target" Restlet. * * @param request * The HTTP Servlet request. * @param response * The HTTP Servlet response. */ public void service(HttpServletRequest request, HttpServletResponse response) { if (getNext() != null) { try { // Set the current context Context.setCurrent(getContext()); // Convert the Servlet call to a Restlet call ServletCall servletCall = new ServletCall( request.getLocalAddr(), request.getLocalPort(), request, response); HttpRequest httpRequest = toRequest(servletCall); HttpResponse httpResponse = new HttpResponse(servletCall, httpRequest); // Adjust the relative reference httpRequest.getResourceRef().setBaseRef(getBaseRef(request)); // Adjust the root reference httpRequest.setRootRef(getRootRef(request)); // Handle the request and commit the response getNext().handle(httpRequest, httpResponse); commit(httpResponse); } finally { Engine.clearThreadLocalVariables(); } } else { getLogger().warning("Unable to find the Restlet target"); } } /** * Sets the next Restlet. * * @param next * The next Restlet. */ public void setNext(Restlet next) { this.next = next; } }