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

com.cerner.beadledom.client.resteasy.ApacheHttpClient4Dot3Engine Maven / Gradle / Ivy

There is a newer version: 4.1.2
Show newest version
package com.cerner.beadledom.client.resteasy;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.MultivaluedMap;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.DeferredFileOutputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocation;
import org.jboss.resteasy.client.jaxrs.internal.ClientResponse;
import org.jboss.resteasy.logging.Logger;

/**
 * This client is extended from the {@link ApacheHttpClient4Engine} to provide support for adding
 * request configuration information to each HTTP request.
 *
 * 

Note: Most of the contents of this class are copied from * {@link ApacheHttpClient4Engine}. * * @author John Leacox * @author Sundeep Paruvu * @since 1.0 * @see ApacheHttpClient4Engine */ @SuppressWarnings(value = "") class ApacheHttpClient4Dot3Engine extends ApacheHttpClient4Engine { private static final Logger logger = Logger.getLogger(ApacheHttpClient4Dot3Engine.class); public ApacheHttpClient4Dot3Engine(HttpClient httpClient, HttpContext httpContext) { super(httpClient, httpContext); this.httpClient = httpClient; this.httpContext = httpContext; } @SuppressWarnings("unchecked") @Override public ClientResponse invoke(ClientInvocation request) { String uri = request.getUri().toString(); final HttpRequestBase httpMethod = createHttpMethod(uri, request.getMethod()); final HttpResponse res; try { loadHttpMethod(request, httpMethod); httpMethod.setConfig((RequestConfig) httpContext.getAttribute(HttpClientContext.REQUEST_CONFIG)); res = httpClient.execute(httpMethod, httpContext); } catch (Exception e) { throw new ProcessingException("Unable to invoke request", e); } finally { cleanUpAfterExecute(httpMethod); } ClientResponse response = new ClientResponse(request.getClientConfiguration()) { InputStream stream; InputStream hc4Stream; @Override protected void setInputStream(InputStream is) { stream = is; } public InputStream getInputStream() { if (stream == null) { HttpEntity entity = res.getEntity(); if (entity == null) { return null; } try { hc4Stream = entity.getContent(); stream = createBufferedStream(hc4Stream); } catch (IOException e) { throw new RuntimeException(e); } } return stream; } public void releaseConnection() throws IOException { // Apache Client 4 is stupid, You have to get the InputStream and close it if there is an entity // otherwise the connection is never released. There is, of course, no close() method on response // to make this easier. try { // Another stupid thing...TCK is testing a specific exception from stream.close() // so, we let it propagate up. if (stream != null) { stream.close(); } else { InputStream is = getInputStream(); if (is != null) { is.close(); } } } finally { // just in case the input stream was entirely replaced and not wrapped, we need // to close the apache client input stream. if (hc4Stream != null) { try { hc4Stream.close(); } catch (IOException ignored) { } } else { try { HttpEntity entity = res.getEntity(); if (entity != null) { entity.getContent().close(); } } catch (IOException ignored) { } } } } }; response.setProperties(request.getMutableProperties()); response.setStatus(res.getStatusLine().getStatusCode()); response.setHeaders(extractHeaders(res)); response.setClientConfiguration(request.getClientConfiguration()); return response; } protected HttpRequestBase createHttpMethod(String url, String restVerb) { if ("GET".equals(restVerb)) { return new HttpGet(url); } else if ("POST".equals(restVerb)) { return new HttpPost(url); } else { final String verb = restVerb; return new HttpPost(url) { @Override public String getMethod() { return verb; } }; } } protected void loadHttpMethod(final ClientInvocation request, HttpRequestBase httpMethod) throws Exception { if (request.getEntity() != null) { if (httpMethod instanceof HttpGet) { throw new ProcessingException("A GET request cannot have a body."); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); request.getDelegatingOutputStream().setDelegate(baos); try { HttpEntity entity = buildEntity(request); HttpPost post = (HttpPost) httpMethod; commitHeaders(request, httpMethod); post.setEntity(entity); } catch (IOException e) { throw new RuntimeException(e); } } else // no body { commitHeaders(request, httpMethod); } } protected void commitHeaders(ClientInvocation request, HttpRequestBase httpMethod) { MultivaluedMap headers = request.getHeaders().asMap(); for (Map.Entry> header : headers.entrySet()) { List values = header.getValue(); for (String value : values) { // System.out.println(String.format("setting %s = %s", header.getKey(), value)); httpMethod.addHeader(header.getKey(), value); } } } @Override public void close() { if (closed) { return; } if (CloseableHttpClient.class.isAssignableFrom(httpClient.getClass())) { IOUtils.closeQuietly((CloseableHttpClient) httpClient); } closed = true; } public void finalize() throws Throwable { close(); super.finalize(); } /** * If passed httpMethod is of type HttpPost then obtain its entity. If the entity has an enclosing File then * delete it by invoking this method after the request has completed. The entity will have an enclosing File * only if it was too huge to fit into memory. * * @param httpMethod - the httpMethod to clean up. */ protected void cleanUpAfterExecute(final HttpRequestBase httpMethod) { if (httpMethod != null && httpMethod instanceof HttpPost) { HttpPost postMethod = (HttpPost) httpMethod; HttpEntity entity = postMethod.getEntity(); if (entity != null && entity instanceof FileExposingFileEntity) { File tempRequestFile = ((FileExposingFileEntity) entity).getFile(); try { boolean isDeleted = tempRequestFile.delete(); if (!isDeleted) { handleFileNotDeletedError(tempRequestFile, null); } } catch (Exception ex) { handleFileNotDeletedError(tempRequestFile, ex); } } } } /** * Build the HttpEntity to be sent to the Service as part of (POST) request. Creates a off-memory * {@link FileExposingFileEntity} or a regular in-memory {@link ByteArrayEntity} depending on if the request * OutputStream fit into memory when built by calling. * * @param request - * @return - the built HttpEntity * @throws IOException - */ protected HttpEntity buildEntity(final ClientInvocation request) throws IOException { HttpEntity entityToBuild = null; DeferredFileOutputStream memoryManagedOutStream = writeRequestBodyToOutputStream(request); if (memoryManagedOutStream.isInMemory()) { ByteArrayEntity entityToBuildByteArray = new ByteArrayEntity(memoryManagedOutStream.getData()); entityToBuildByteArray.setContentType( new BasicHeader(HTTP.CONTENT_TYPE, request.getHeaders().getMediaType().toString())); entityToBuild = entityToBuildByteArray; } else { File requestBodyFile = memoryManagedOutStream.getFile(); requestBodyFile.deleteOnExit(); entityToBuild = new FileExposingFileEntity( memoryManagedOutStream.getFile(), request.getHeaders().getMediaType().toString()); } return entityToBuild; } /** * Creates the request OutputStream, to be sent to the end Service invoked, as a * DeferredFileOutputStream. * * * @param request - * @return - DeferredFileOutputStream with the ClientRequest written out per HTTP specification. * @throws IOException - */ private DeferredFileOutputStream writeRequestBodyToOutputStream(final ClientInvocation request) throws IOException { DeferredFileOutputStream memoryManagedOutStream = new DeferredFileOutputStream( this.fileUploadInMemoryThresholdLimit * getMemoryUnitMultiplier(), getTempfilePrefix(), ".tmp", this.fileUploadTempFileDir); request.getDelegatingOutputStream().setDelegate(memoryManagedOutStream); request.writeRequestBody(request.getEntityStream()); memoryManagedOutStream.close(); return memoryManagedOutStream; } /** * @return - the constant to multiply {@link #fileUploadInMemoryThresholdLimit} with based on * {@link #fileUploadMemoryUnit} enumeration value. */ private int getMemoryUnitMultiplier() { switch (this.fileUploadMemoryUnit) { case BY: return 1; case KB: return 1024; case MB: return 1024 * 1024; case GB: return 1024 * 1024 * 1024; } return 1; } /** * Log that the file did not get deleted but prevent the request from failing by eating the exception. The file * has been registered to delete on exit, so it will get deleted eventually. * * @param tempRequestFile - * @param ex - a null may be passed in which case this param gets ignored. */ private void handleFileNotDeletedError(File tempRequestFile, Exception ex) { logger.warn( "Could not delete file' " + tempRequestFile.getAbsolutePath() + "' for request: ", ex); } /** * We use {@link org.apache.http.entity.FileEntity} as the {@link HttpEntity} implementation when the request OutputStream has been * saved to a File on disk (because it was too large to fit into memory see however, we have to delete * the File supporting the FileEntity, otherwise the disk will soon run out of space - remember * that there can be very huge files, in GB range, processed on a regular basis - and FileEntity exposes its * content File as a protected field. For the enclosing parent class ( {@link ApacheHttpClient4Dot3Engine} ) to be * able to get a handle to this content File and delete it, this class expose the content File.
* This class is private scoped to prevent access to this content File outside of the parent class. * * @author Sandeep Tikoo */ private static class FileExposingFileEntity extends FileEntity { /** * @param pFile - * @param pContentType - */ public FileExposingFileEntity(File pFile, String pContentType) { super(pFile, ContentType.create(pContentType)); } /** * @return - the content File enclosed by this FileEntity. */ File getFile() { return this.file; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy