com.moai.app.prox.resources.ProxResource.java Source code

Java tutorial

Introduction

Here is the source code for com.moai.app.prox.resources.ProxResource.java

Source

/*
 * $Header$
 *
 * Copyright (C) 2013 Escenic AS.
 * All Rights Reserved.  No use, copying or distribution of this
 * work may be made except in accordance with a valid license
 * agreement from Escenic AS.  This notice must be included on all
 * copies, modifications and derivatives of this work.
 */
package com.moai.app.prox.resources;

import com.moai.app.prox.HTTPMethod;
import com.moai.app.prox.core.Backend;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.core.ExtendedUriInfo;
import com.sun.jersey.api.core.HttpContext;
import com.sun.jersey.api.core.HttpRequestContext;
import org.apache.commons.io.IOUtils;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

/**
 * @author <a href="mailto:sai@vizrt.com">Sk.Mohd.Anwarul Islam</a>
 * @author last modified by $Author$
 * @version $Revision$ $Date$
 */
@Path("/{webservice}/{relativeUri:.*}")
@Produces("*/*")
public class ProxResource {
    private List<Backend> mBackends;
    private Client mClient;
    private Logger mLogger = Logger.getLogger(ProxResource.class.getName());
    private static List<String> hopByHopHeaders = new ArrayList<String>() {
        {
            add("Connection");
            add("Keep-Alive");
            add("Proxy-Authenticate");
            add("Proxy-Authorization");
            add("TE");
            add("Trailers");
            add("Transfer-Encoding");
            add("Upgrade");
            add("Content-Length");
        }
    };

    public ProxResource(final List<Backend> pBackends, final Client pClient) {
        mBackends = pBackends;
        mClient = pClient;
    }

    @GET
    public Response doProxyGet(final @PathParam("webservice") String pServiceName,
            final @Context HttpContext pHttpContext) {
        return doProxyService(pServiceName, pHttpContext);
    }

    @POST
    public Response doProxyPost(final @PathParam("webservice") String pServiceName,
            @Context HttpContext pHttpContext) {
        return doProxyService(pServiceName, pHttpContext);
    }

    @PUT
    public Response doProxyPut(final @PathParam("webservice") String pServiceName,
            @Context HttpContext pHttpContext) {
        return doProxyService(pServiceName, pHttpContext);
    }

    @OPTIONS
    public Response doProxyOptions(final @PathParam("webservice") String pServiceName,
            @Context HttpContext pHttpContext) {
        return doProxyService(pServiceName, pHttpContext);
    }

    @DELETE
    public Response doProxyDelete(final @PathParam("webservice") String pServiceName,
            @Context HttpContext pHttpContext) {
        return doProxyService(pServiceName, pHttpContext);
    }

    private StreamingOutput createStreamingResponse(final ClientResponse pClientResponse) {
        return new StreamingOutput() {
            @Override
            public void write(OutputStream pOutputStream) throws IOException, WebApplicationException {
                InputStream inputStream = pClientResponse.getEntityInputStream();
                IOUtils.copy(inputStream, pOutputStream);
                IOUtils.closeQuietly(inputStream);
            }
        };
    }

    private WebResource.Builder createWebResourceBuilder(final String pServiceName,
            final HttpRequestContext pRequestContext, final URI pTargetUri) {

        MultivaluedMap<String, String> queryParams = pRequestContext.getQueryParameters();
        MultivaluedMap<String, String> requestHeaders = pRequestContext.getRequestHeaders();

        WebResource resource = mClient.resource(pTargetUri);
        resource = resource.queryParams(queryParams);

        WebResource.Builder requestBuilder = resource.getRequestBuilder();
        copyRequestHeadersToClient(requestBuilder, requestHeaders);
        if (isEntityCopyRequired(pRequestContext)) {
            requestBuilder.entity(pRequestContext.getEntity(InputStream.class));
        }
        return requestBuilder;
    }

    private void copyRequestHeadersToClient(final WebResource.Builder pResourcePBuilder,
            final MultivaluedMap<String, String> pHeaderParams) {
        removeMapEntriesUsingList(pHeaderParams, hopByHopHeaders);
        Set<String> keySet = pHeaderParams.keySet();
        for (String headerName : keySet) {
            if (headerName.equalsIgnoreCase("Content-Length")) {
                continue;
            }
            List<String> headerValues = pHeaderParams.get(headerName);
            for (String value : headerValues) {
                pResourcePBuilder.header(headerName, value);
            }
        }
        pResourcePBuilder.header("Via", "theProx/1.1");
    }

    private <K, V> void removeMapEntriesUsingList(final Map<K, V> pMap, final List<K> pList) {
        for (K key : pList) {
            if (pMap.containsKey(key)) {
                pMap.remove(key);
            }
        }
    }

    private boolean isEntityCopyRequired(final HttpRequestContext pRequestContext) {
        String method = pRequestContext.getMethod();
        return "POST".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method);
    }

    private Response.ResponseBuilder createResponseFromClient(ClientResponse pClientResponse) {
        Response.ResponseBuilder builder = Response.status(pClientResponse.getClientResponseStatus());
        copyResponseHeadersFromClient(builder, pClientResponse);
        StreamingOutput streamingOutput = createStreamingResponse(pClientResponse);
        builder.entity(streamingOutput);
        return builder;
    }

    private void copyResponseHeadersFromClient(final Response.ResponseBuilder pBuilder,
            final ClientResponse pClientResponse) {
        MultivaluedMap<String, String> headers = pClientResponse.getHeaders();
        removeMapEntriesUsingList(headers, hopByHopHeaders);
        Set<String> keySet = headers.keySet();
        for (String headerName : keySet) {
            List<String> headerValues = headers.get(headerName);
            for (String value : headerValues) {
                pBuilder.header(headerName, value);
            }
        }
        pBuilder.header("Via", "theProx/1.1");
    }

    private Response doProxyService(final String pServiceName, final HttpContext pHttpContext) {
        final Backend backend = getBackend(pServiceName);
        if (backend == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
        HTTPMethod httpMethod = HTTPMethod.valueOf(pHttpContext.getRequest().getMethod());

        URI targetUri = getTargetUri(pHttpContext.getUriInfo(), backend);
        WebResource.Builder builder = createWebResourceBuilder(pServiceName, pHttpContext.getRequest(), targetUri);
        ClientResponse responseFromTarget;
        try {
            responseFromTarget = executeHttpRequest(builder, httpMethod);
            Response.ResponseBuilder responseBuilder = createResponseFromClient(responseFromTarget);
            return responseBuilder.build();
        } catch (Exception e) {
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
        }
    }

    private Backend getBackend(final String pServiceName) {
        for (final Backend backend : mBackends) {
            if (pServiceName.startsWith(backend.getPathPrefix())) {
                return backend;
            }
        }
        return null;
    }

    private URI getTargetUri(final ExtendedUriInfo pUriInfo, final Backend pBackend) {
        URI targetUri = getRequestUri(pUriInfo);
        UriBuilder uriBuilder = UriBuilder.fromUri(targetUri);
        targetUri = uriBuilder.host(pBackend.getHostName()).port(Integer.valueOf(pBackend.getPort())).build();
        return targetUri;
    }

    private URI getRequestUri(final ExtendedUriInfo pUriInfo) {
        return pUriInfo.getRequestUri();
    }

    private ClientResponse executeHttpRequest(final WebResource.Builder pBuilder, final HTTPMethod pRequestMethod) {
        ClientResponse clientResponse;
        switch (pRequestMethod) {
        case GET:
            clientResponse = pBuilder.get(ClientResponse.class);
            break;
        case POST:
            clientResponse = pBuilder.post(ClientResponse.class);
            break;
        case PUT:
            clientResponse = pBuilder.put(ClientResponse.class);
            break;
        case DELETE:
            clientResponse = pBuilder.delete(ClientResponse.class);
            break;
        case HEAD:
            clientResponse = pBuilder.head();
            break;
        case OPTIONS:
            clientResponse = pBuilder.options(ClientResponse.class);
            break;
        default:
            clientResponse = pBuilder.get(ClientResponse.class);
        }
        return clientResponse;
    }
}