1 /* 2 * Copyright (C) 2012-2024 RRiBbit.org 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.rribbit.processing; 17 18 import java.io.InputStream; 19 import java.io.PrintWriter; 20 21 import jakarta.servlet.http.HttpServlet; 22 import jakarta.servlet.http.HttpServletRequest; 23 import jakarta.servlet.http.HttpServletResponse; 24 25 import org.rribbit.ListenerObject; 26 import org.rribbit.Request; 27 import org.rribbit.Response; 28 import org.rribbit.dispatching.HttpRequestDispatcher; 29 import org.rribbit.execution.ListenerObjectExecutor; 30 import org.rribbit.retrieval.ListenerObjectRetriever; 31 import org.rribbit.util.Base64Util; 32 import org.slf4j.Logger; 33 import org.slf4j.LoggerFactory; 34 35 /** 36 * This servlet processes requests that are dispatched by the {@link HttpRequestDispatcher}. It is not actually an implementation of {@link RequestProcessor}, but uses a nested 37 * {@link LocalRequestProcessor} to do the actual processing. This is not a problem though, since an {@link HttpRequestProcessorServlet} receives its requests via HTTP and not via 38 * a Java interface. It accepts a {@link ListenerObjectRetriever} and a {@link ListenerObjectExecutor}, just like any other {@link RequestProcessor}. 39 * <p /> 40 * RRiBbit over HTTP uses POST exclusively. Other HTTP methods are NOT used. 41 * <p /> 42 * This is an abstract class, because it needs a {@link ListenerObjectRetriever} and a {@link ListenerObjectExecutor} to do its work, just like any other {@link RequestProcessor}. 43 * These however, cannot be passed in the constructor, since passing objects in a constructor cannot be done with Java Servlets. The programmer must therefore subclass this class 44 * and provide a {@link ListenerObjectRetriever} and a {@link ListenerObjectExecutor} via the abstract methods. 45 * <p /> 46 * If you use Spring, then the {@link SpringHttpRequestProcessorServlet} provides an implementation of this class that retrieves the {@link ListenerObjectRetriever} and the 47 * {@link ListenerObjectExecutor} from the WebApplicationContext. 48 * <p /> 49 * An {@link HttpRequestProcessorServlet} can be mounted on an SSL or a non-SSL server, it should make no difference to its behaviour. 50 * 51 * @author G.J. Schouten 52 * 53 */ 54 public abstract class HttpRequestProcessorServlet extends HttpServlet { 55 56 private static final Logger log = LoggerFactory.getLogger(HttpRequestProcessorServlet.class); 57 58 protected RequestProcessor requestProcessor; 59 60 @Override 61 protected void doPost(HttpServletRequest servletRequest, HttpServletResponse servletResponse) { 62 63 log.info("Processing HTTP Request"); 64 try (InputStream requestInputStream = servletRequest.getInputStream()) { 65 log.info("Decoding Request"); 66 Request request = Base64Util.decodeInputStream(requestInputStream); 67 68 log.info("Processing decoded Request"); 69 Response<?> response = requestProcessor.processRequest(request); 70 71 log.info("Encoding Response"); 72 String responseString = Base64Util.encodeObject(response); 73 74 log.info("Returning Response"); 75 servletResponse.setHeader("Content-Type", "text/plain"); 76 try (PrintWriter writer = servletResponse.getWriter()) { 77 writer.write(responseString); 78 writer.flush(); 79 } 80 } catch (Exception e) { 81 log.error("Error during processing of HTTP Request", e); 82 } 83 } 84 85 /** 86 * When you override this, please make sure to call super.init(). 87 */ 88 @Override 89 public void init() { 90 requestProcessor = new LocalRequestProcessor(this.createListenerObjectRetriever(), this.createListenerObjectExecutor()); 91 } 92 93 /** 94 * Creates or fetches and returns a {@link ListenerObjectRetriever} that will be used to retrieve {@link ListenerObject}s. 95 * 96 * @return The {@link ListenerObjectRetriever} that will be used to retrieve {@link ListenerObject}s 97 */ 98 protected abstract ListenerObjectRetriever createListenerObjectRetriever(); 99 100 /** 101 * Creates or fetches and returns a {@link ListenerObjectExecutor} that will be used to execute {@link ListenerObject}s. 102 * 103 * @return The {@link ListenerObjectExecutor} that will be used to execute {@link ListenerObject}s 104 */ 105 protected abstract ListenerObjectExecutor createListenerObjectExecutor(); 106 }