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 > }