1 /*
2 * Copyright (C) 2012-2025 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 }