All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.lightblue.client.http.servlet.AbstractLightblueProxyServlet Maven / Gradle / Ivy

There is a newer version: 5.21.0
Show newest version
package com.redhat.lightblue.client.http.servlet;

import com.redhat.lightblue.client.LightblueClientConfiguration;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestWrapper;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * An injectable Lightblue proxy servlet, powered by Apache
 * {@link org.apache.http.impl.client.CloseableHttpClient}. See
 * {@link AbstractLightblueProxyServlet#AbstractLightblueProxyServlet(CloseableHttpClient, Instance)}
 * for how to setup the injection.
 */
public abstract class AbstractLightblueProxyServlet extends HttpServlet {
    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLightblueProxyServlet.class);

    /**
     * This is okay to share because of isRepeatable. Just don't go modifying
     * the headers or something willy nilly.
     */
    private static final HttpEntity ERROR_RESPONSE = new StringEntity(
            "{\"error\":\"There was a problem calling the lightblue service\"}",
            ContentType.APPLICATION_JSON);

    private final CloseableHttpClient httpClient;
    private final Instance configuration;

    /**
     * An {@link javax.inject.Inject @Inject}able constructor for the servlet.
     * To setup the dependency for the servlet, you will have to use Java CDI,
     * providing a {@link javax.enterprise.inject.Produces}-annotated method
     * whch instantiates an appropriately configured
     * {@link org.apache.http.impl.client.CloseableHttpClient} to use inside the
     * servlets, with a preferred scope (ideally
     * {@link javax.enterprise.context.ApplicationScoped}). To shutdown the
     * servlet, a "disposer" must also be provided using the
     * {@link javax.enterprise.inject.Disposes} annotation.
     *
     * 

* For convenience, lightblue-client provides factory methods for default * http clients with basic configuration. Of course, you are free to * configure the client however you need. * *

* An instance of * {@link com.redhat.lightblue.client.LightblueClientConfiguration} may also * be injected here, but it is optional. By default, this servlet will use * the configuration defined via * {@link com.redhat.lightblue.client.PropertiesLightblueClientConfiguration#fromDefault()}. * *

* Example producer and disposer: * *


     * public class ApplicationContext {
     *     {@literal@}Produces {@literal@}ApplicationScoped
     *     public LightblueClientConfiguration getLightblueClientConfiguration() {
     *         return PropertiesLightblueClientConfiguration.fromDefault();
     *     }
     *
     *     {@literal@}Produces {@literal@}ApplicationScoped
     *     public CloseableHttpClient getClient(LightblueClientConfiguration config) throws Exception {
     *         return ApacheHttpClients.fromLightblueClientConfiguration(config);
     *     }
     *
     *     public void closeHttpClient({@literal@}Disposes CloseableHttpClient client) throws IOException {
     *         client.close();
     *     }
     * }
     * 
* * @param httpClient The http client to use for this servlet. Servlets * should not * manage (e.g. close) the client; the client should manage its own * lifecycle with regards to the container. * * @see * Overview * of CDI — The Java EE 6 Tutorial */ @Inject public AbstractLightblueProxyServlet(CloseableHttpClient httpClient, Instance configuration) { this.httpClient = httpClient; this.configuration = configuration; } @Override protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("application/json"); try { HttpUriRequest apacheHttpRequest = proxyRequest(req); try (CloseableHttpResponse httpResponse = httpClient.execute(apacheHttpRequest)) { HttpEntity entity = httpResponse.getEntity(); entity.writeTo(res.getOutputStream()); } } catch (IOException | ServletException e) { ERROR_RESPONSE.writeTo(res.getOutputStream()); LOGGER.error("There was a problem calling the lightblue service", e); } } /** * Constructs a service URI from the given request. The request will have a * path for the servlet, which will contain information we need to pass on * to the service. For convenience, see * {@link #servicePathForRequest(javax.servlet.http.HttpServletRequest)}. * * @throws javax.servlet.ServletException */ protected abstract String serviceUriForRequest(HttpServletRequest request) throws ServletException; protected LightblueClientConfiguration configuration() { if (configuration.isUnsatisfied()) { return defaultConfiguration(); } return configuration.get(); } protected LightblueClientConfiguration defaultConfiguration() { return new LightblueServletContextConfiguration(getServletContext()) .lightblueClientConfiguration(); } /** * @return The url for the request with the context and the servlet path * stripped out, which leaves whatever wild cards were left that matched * this servlet. * *

* For example: *

    *
  • Given the request, * "http://my.site.com/app/get/the/thing?foo=bar"
  • *
  • and some servlet which maps to, "/get/*"
  • *
  • in an application with context, "/app"
  • *
  • then this method would return, "/the/thing?foo=bar"
  • *
*/ protected final String servicePathForRequest(HttpServletRequest request) { String pathInfo = request.getPathInfo(); String queryString = request.getQueryString(); String path = ""; if (pathInfo != null) { path += pathInfo; } if (queryString != null) { path += "?" + queryString; } return path; } protected final String getInitParamOrDefault(String key, String defaultValue) { String value = getInitParameter(key); return value == null ? defaultValue : value; } /** * For the given servlet request, return a new request object (for use with * Apache HttpClient), that may be executed in place of the original request * to make the real service call. * * @throws javax.servlet.ServletException */ private HttpUriRequest proxyRequest(HttpServletRequest request) throws ServletException, IOException { String newUri = serviceUriForRequest(request); BasicHttpEntityEnclosingRequest httpRequest = new BasicHttpEntityEnclosingRequest(request.getMethod(), newUri); HttpEntity entity = new InputStreamEntity(request.getInputStream(), request.getContentLength()); httpRequest.setEntity(entity); try { // Sadly have to do this to set the URI; it is not derived from the original httpRequest HttpRequestWrapper wrappedRequest = HttpRequestWrapper.wrap(httpRequest); wrappedRequest.setURI(new URI(newUri)); // Somehow, content type header does not come in the original request either wrappedRequest.setHeader("Content-Type", "application/json"); return wrappedRequest; } catch (URISyntaxException e) { LOGGER.error("Syntax exception in service URI, " + newUri, e); throw new LightblueServletException("Syntax exception in service URI, " + newUri, e); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy