HttpRequestProcessorServlet.java
/*
* Copyright (C) 2012-2024 RRiBbit.org
*
* 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
*
* https://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 org.rribbit.processing;
import java.io.InputStream;
import java.io.PrintWriter;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.rribbit.ListenerObject;
import org.rribbit.Request;
import org.rribbit.Response;
import org.rribbit.dispatching.HttpRequestDispatcher;
import org.rribbit.execution.ListenerObjectExecutor;
import org.rribbit.retrieval.ListenerObjectRetriever;
import org.rribbit.util.Base64Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This servlet processes requests that are dispatched by the {@link HttpRequestDispatcher}. It is not actually an implementation of {@link RequestProcessor}, but uses a nested
* {@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
* a Java interface. It accepts a {@link ListenerObjectRetriever} and a {@link ListenerObjectExecutor}, just like any other {@link RequestProcessor}.
* <p />
* RRiBbit over HTTP uses POST exclusively. Other HTTP methods are NOT used.
* <p />
* 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}.
* 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
* and provide a {@link ListenerObjectRetriever} and a {@link ListenerObjectExecutor} via the abstract methods.
* <p />
* If you use Spring, then the {@link SpringHttpRequestProcessorServlet} provides an implementation of this class that retrieves the {@link ListenerObjectRetriever} and the
* {@link ListenerObjectExecutor} from the WebApplicationContext.
* <p />
* An {@link HttpRequestProcessorServlet} can be mounted on an SSL or a non-SSL server, it should make no difference to its behaviour.
*
* @author G.J. Schouten
*
*/
public abstract class HttpRequestProcessorServlet extends HttpServlet {
private static final Logger log = LoggerFactory.getLogger(HttpRequestProcessorServlet.class);
protected RequestProcessor requestProcessor;
@Override
protected void doPost(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
log.info("Processing HTTP Request");
try (InputStream requestInputStream = servletRequest.getInputStream()) {
log.info("Decoding Request");
Request request = Base64Util.decodeInputStream(requestInputStream);
log.info("Processing decoded Request");
Response<?> response = requestProcessor.processRequest(request);
log.info("Encoding Response");
String responseString = Base64Util.encodeObject(response);
log.info("Returning Response");
servletResponse.setHeader("Content-Type", "text/plain");
try (PrintWriter writer = servletResponse.getWriter()) {
writer.write(responseString);
writer.flush();
}
} catch (Exception e) {
log.error("Error during processing of HTTP Request", e);
}
}
/**
* When you override this, please make sure to call super.init().
*/
@Override
public void init() {
requestProcessor = new LocalRequestProcessor(this.createListenerObjectRetriever(), this.createListenerObjectExecutor());
}
/**
* Creates or fetches and returns a {@link ListenerObjectRetriever} that will be used to retrieve {@link ListenerObject}s.
*
* @return The {@link ListenerObjectRetriever} that will be used to retrieve {@link ListenerObject}s
*/
protected abstract ListenerObjectRetriever createListenerObjectRetriever();
/**
* Creates or fetches and returns a {@link ListenerObjectExecutor} that will be used to execute {@link ListenerObject}s.
*
* @return The {@link ListenerObjectExecutor} that will be used to execute {@link ListenerObject}s
*/
protected abstract ListenerObjectExecutor createListenerObjectExecutor();
}