| /* |
| * Copyright 2010 Google Inc. |
| * |
| * Licensed 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 com.google.web.bindery.requestfactory.server; |
| |
| import com.google.gwt.user.server.rpc.RPCServletUtils; |
| import com.google.web.bindery.requestfactory.shared.RequestFactory; |
| |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import javax.servlet.ServletContext; |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServlet; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| /** |
| * Handles GWT RequestFactory JSON requests. |
| */ |
| @SuppressWarnings("serial") |
| public class RequestFactoryServlet extends HttpServlet { |
| |
| private static final boolean DUMP_PAYLOAD = Boolean.getBoolean("gwt.rpc.dumpPayload"); |
| private static final String JSON_CHARSET = "UTF-8"; |
| private static final String JSON_CONTENT_TYPE = "application/json"; |
| private static final Logger log = Logger |
| .getLogger(RequestFactoryServlet.class.getCanonicalName()); |
| |
| /** |
| * These ThreadLocals are used to allow service objects to obtain access to |
| * the HTTP transaction. |
| */ |
| private static final ThreadLocal<ServletContext> perThreadContext = |
| new ThreadLocal<ServletContext>(); |
| private static final ThreadLocal<HttpServletRequest> perThreadRequest = |
| new ThreadLocal<HttpServletRequest>(); |
| private static final ThreadLocal<HttpServletResponse> perThreadResponse = |
| new ThreadLocal<HttpServletResponse>(); |
| |
| /** |
| * Returns the thread-local {@link HttpServletRequest}. |
| * |
| * @return an {@link HttpServletRequest} instance |
| */ |
| public static HttpServletRequest getThreadLocalRequest() { |
| return perThreadRequest.get(); |
| } |
| |
| /** |
| * Returns the thread-local {@link HttpServletResponse}. |
| * |
| * @return an {@link HttpServletResponse} instance |
| */ |
| public static HttpServletResponse getThreadLocalResponse() { |
| return perThreadResponse.get(); |
| } |
| |
| /** |
| * Returns the thread-local {@link ServletContext} |
| * |
| * @return the {@link ServletContext} associated with this servlet |
| */ |
| public static ServletContext getThreadLocalServletContext() { |
| return perThreadContext.get(); |
| } |
| |
| private final SimpleRequestProcessor processor; |
| |
| /** |
| * Constructs a new {@link RequestFactoryServlet} with a |
| * {@code DefaultExceptionHandler}. |
| */ |
| public RequestFactoryServlet() { |
| this(new DefaultExceptionHandler()); |
| } |
| |
| /** |
| * Use this constructor in subclasses to provide a custom |
| * {@link ExceptionHandler}. |
| * |
| * @param exceptionHandler an {@link ExceptionHandler} instance |
| * @param serviceDecorators an array of ServiceLayerDecorators that change how |
| * the RequestFactory request processor interact with the domain |
| * objects |
| */ |
| public RequestFactoryServlet(ExceptionHandler exceptionHandler, |
| ServiceLayerDecorator... serviceDecorators) { |
| processor = new SimpleRequestProcessor(ServiceLayer.create(serviceDecorators)); |
| processor.setExceptionHandler(exceptionHandler); |
| } |
| |
| /** |
| * Processes a POST to the server. |
| * |
| * @param request an {@link HttpServletRequest} instance |
| * @param response an {@link HttpServletResponse} instance |
| * @throws IOException if an internal I/O error occurs |
| * @throws ServletException if an error occurs in the servlet |
| */ |
| @Override |
| protected void doPost(HttpServletRequest request, HttpServletResponse response) |
| throws IOException, ServletException { |
| |
| perThreadContext.set(getServletContext()); |
| perThreadRequest.set(request); |
| perThreadResponse.set(response); |
| |
| // No new code should be placed outside of this try block. |
| try { |
| ensureConfig(); |
| String jsonRequestString = |
| RPCServletUtils.readContent(request, JSON_CONTENT_TYPE, JSON_CHARSET); |
| if (DUMP_PAYLOAD) { |
| System.out.println(">>> " + jsonRequestString); |
| } |
| |
| try { |
| String payload = processor.process(jsonRequestString); |
| if (DUMP_PAYLOAD) { |
| System.out.println("<<< " + payload); |
| } |
| response.setStatus(HttpServletResponse.SC_OK); |
| response.setContentType(RequestFactory.JSON_CONTENT_TYPE_UTF8); |
| // The Writer must be obtained after setting the content type |
| PrintWriter writer = response.getWriter(); |
| writer.print(payload); |
| writer.flush(); |
| } catch (RuntimeException e) { |
| response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
| log.log(Level.SEVERE, "Unexpected error", e); |
| } |
| } finally { |
| perThreadContext.set(null); |
| perThreadRequest.set(null); |
| perThreadResponse.set(null); |
| } |
| } |
| |
| private void ensureConfig() { |
| String symbolMapsDirectory = getServletConfig().getInitParameter("symbolMapsDirectory"); |
| if (symbolMapsDirectory != null) { |
| Logging.setSymbolMapsDirectory(symbolMapsDirectory); |
| } |
| } |
| } |