2a4
> import org.apache.commons.io.output.DeferredFileOutputStream;
14a17
> import org.apache.http.entity.FileEntity;
17a21
> import org.apache.http.protocol.HTTP;
28a33
> import java.io.File;
30a36
> import java.lang.management.ManagementFactory;
33a40,41
> import java.util.logging.Level;
> import java.util.logging.Logger;
40a49,56
> /**
> * Used to build temp file prefix.
> */
> private static String processId = null;
> static {
> ApacheHttpClient4Executor.processId = ManagementFactory.getRuntimeMXBean().getName().replaceAll("[^0-9a-zA-Z]", "");
> }
>
42a59,90
> /**
> * For uploading File's over JAX-RS framework, this property, together with {@link #fileUploadMemoryUnit},
> * defines the maximum File size allowed in memory. If fileSize exceeds this size, it will be stored to
> * {@link #fileUploadTempFileDir}.
> *
> * Defaults to 1 MB
> */
> private int fileUploadInMemoryThresholdLimit = 1;
>
> /**
> * The unit for {@link #fileUploadInMemoryThresholdLimit}.
> *
> * Defaults to MB.
> *
> * @see MemoryUnit
> */
> private MemoryUnit fileUploadMemoryUnit = MemoryUnit.MB;
>
> /**
> * Temp directory to write output request stream to. Any file to be uploaded has to be written out to the
> * output request stream to be sent to the service and when the File is too huge the output request stream is
> * written out to the disk rather than to memory.
> *
> * Defaults to JVM temp directory.
> */
> private File fileUploadTempFileDir = new File(System.getProperty("java.io.tmpdir"));
>
> /**
> * Java Util Logger
> */
> private final static Logger LOGGER = Logger.getLogger(ApacheHttpClient4Executor.class.getName());
>
132a181,209
> } finally {
> cleanUpAfterExecute(httpMethod);
> }
> }
>
> /**
> * 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.
> *
> * @see #writeRequestBodyToOutputStream(ClientRequest)
> * @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);
> }
> }
> }
203,211c280
< request.writeRequestBody(request.getHeadersAsObjects(), baos);
< ByteArrayEntity entity = new ByteArrayEntity(baos.toByteArray())
< {
< @Override
< public Header getContentType()
< {
< return new BasicHeader("Content-Type", request.getBodyContentType().toString());
< }
< };
---
> HttpEntity entity = buildEntity(request);
226a296,423
> /**
> * 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 {@link #writeRequestBodyToOutputStream(ClientRequest)}.
> *
> * @param request -
> * @return - the built HttpEntity
> * @throws IOException -
> */
> protected HttpEntity buildEntity(final ClientRequest 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.getBodyContentType()
> .toString()));
> entityToBuild = entityToBuildByteArray;
> } else {
> File requestBodyFile = memoryManagedOutStream.getFile();
> requestBodyFile.deleteOnExit();
> entityToBuild =
> new FileExposingFileEntity(memoryManagedOutStream.getFile(), request.getBodyContentType()
> .toString());
> }
>
> return entityToBuild;
> }
>
> /**
> * Creates the request OutputStream, to be sent to the end Service invoked, as a * href="http://commons.apache.org/io/api-release/org/apache/commons/io/output/DeferredFileOutputStream.html"
> * >DeferredFileOutputStream.
> *
> *
> * @param request -
> * @return - DeferredFileOutputStream with the ClientRequest written out per HTTP specification.
> * @throws IOException -
> */
> private DeferredFileOutputStream writeRequestBodyToOutputStream(final ClientRequest request)
> throws IOException {
> DeferredFileOutputStream memoryManagedOutStream =
> new DeferredFileOutputStream(this.fileUploadInMemoryThresholdLimit * getMemoryUnitMultiplier(),
> getTempfilePrefix(), ".tmp", this.fileUploadTempFileDir);
> request.writeRequestBody(request.getHeadersAsObjects(), memoryManagedOutStream);
> 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;
> }
>
> /**
> * Use context information, which will include node name, to avoid conflicts in case of multiple VMS using same
> * temp directory location.
> *
> * @return -
> */
> protected String getTempfilePrefix() {
> return ApacheHttpClient4Executor.processId;
> }
>
> /**
> * 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) {
> if (LOGGER.isLoggable(Level.SEVERE)) {
> LOGGER.log(Level.SEVERE, "Could not delete file' " + tempRequestFile.getAbsolutePath()
> + "' for request: ", ex);
> }
> }
>
> /**
> * Setter for the {@link HttpClient} to which this class delegates the actual HTTP call. Note that this class
> * acts as the adapter between RestEasy and Apache HTTP Component library.
> *
> * @param pHttpClient -
> */
> void setHttpClient(HttpClient pHttpClient) {
> this.httpClient = pHttpClient;
> }
>
> /**
> * Setter for {@link #fileUploadInMemoryThresholdLimit}
> *
> * @param pInMemoryThresholdLimit - the inMemoryThresholdLimitMB to set
> */
> public void setFileUploadInMemoryThresholdLimit(int pInMemoryThresholdLimit) {
> this.fileUploadInMemoryThresholdLimit = pInMemoryThresholdLimit;
> }
>
> /**
> * Setter for {@link #fileUploadTempFileDir}
> *
> * @param pTempFileDir the tempFileDir to set
> */
> public void setFileUploadTempFileDir(File pTempFileDir) {
> this.fileUploadTempFileDir = pTempFileDir;
> }
>
> /**
> * Setter for {@link #fileUploadMemoryUnit}
> *
> * @param pMemoryUnit the memoryUnit to set
> */
> public void setFileUploadMemoryUnit(String pMemoryUnit) {
> this.fileUploadMemoryUnit = MemoryUnit.valueOf(pMemoryUnit);
> }
>
240a438,490
> /**
> * We use {@link 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
> * {@link RestCFHttpClientExecutor#writeRequestBodyToOutputStream(ClientRequest)}); 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 RestCFHttpClientExecutor} ) 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, pContentType);
> }
>
> /**
> * @return - the content File enclosed by this FileEntity.
> */
> File getFile() {
> return this.file;
> }
> }
>
> /**
> * Enumeration to represent memory units.
> */
> private static enum MemoryUnit {
> /**
> * Bytes
> */
> BY,
> /**
> * Killo Bytes
> */
> KB,
>
> /**
> * Mega Bytes
> */
> MB,
>
> /**
> * Giga Bytes
> */
> GB
> }