Java tutorial
/* * $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; } }