Delete temporary files - java

I have developed a rest client using spring mvc which upload files and form data to a rest service using Jersey.
I can able to see the files that i uploaded, in rest client's Tomcat home directory.
How can i automatically delete the file that is stored in my tomcat, after i get a success response.
Some of my configuration for your reference,
Multipart config in "web.xml"
<multipart-config>
<location>/tmp</location>
<max-file-size>26214400</max-file-size>
<max-request-size>31457280</max-request-size>
<file-size-threshold>0</file-size-threshold>
</multipart-config>
multipart config in "dispatcher-servlet.xml"
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
My business logic,
public Map<Object, Object> upload(ModelMap model) {
Map<Object, Object> responseMap = new HashMap<>();
sendMailBean = (SendMailBean) model.get("sendMailBean");
FormDataMultiPart formDataMultiPart = new FormDataMultiPart();
formDataMultiPart.field("firstName", sendMailBean.getFirstname());
formDataMultiPart.field("lastName", sendMailBean.getLastname());
formDataMultiPart.field("fromAddress", sendMailBean.getEmail());
formDataMultiPart.field("subject", sendMailBean.getSubject());
formDataMultiPart.field("text", sendMailBean.getMessage());
List<MultipartFile> files = sendMailBean.getAttachments();
try {
for(MultipartFile file : files) {
File convFile = convert(file);
FileDataBodyPart filePart = new FileDataBodyPart("files", convFile);
filePart.setContentDisposition(FormDataContentDisposition.name("files").fileName(file.getOriginalFilename()).build());
formDataMultiPart.bodyPart(filePart);
}
Client client = new Client();
WebResource webResource = client.resource(----rest url-----);
ClientResponse response = webResource.type(MediaType.MULTIPART_FORM_DATA).post(ClientResponse.class, formDataMultiPart);
if (response.getStatus() != 200) {
model.addAttribute("errormsg", "Failed : HTTP error code : " + response.getStatus());
responseMap.put("model", model);
responseMap.put("redirectToPage", "redirect:/views/error");
} else {
// responseMap.put("redirectToPage", "/views/email");
responseMap.put("model", model);
responseMap.put("redirectToPage", "");
}
}catch (Exception e) {
e.printStackTrace();
}
return responseMap;
}
public File convert(MultipartFile file)
{
File convFile = new File(file.getOriginalFilename());
try {
convFile.createNewFile();
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
return convFile;
}

I've had the same problem.
The best way for GC to delete the tmp file is to ensure your inputstream is closed after using it.
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException io) {
}
}
}
For some odd reason the inputstream stays open even after your rest service executes; this prevents the GC collect and delete it.

Looks like the problem lies with the fileoutstream logic to convert multipart file to file. Below is the workaround that i used to resolve this,
I replaced the conversion logic to,
public File multipartToFile(MultipartFile file) throws IllegalStateException, IOException
{
File tmpFile = new File(System.getProperty("user.dir") + File.separator + file.getOriginalFilename());
file.transferTo(tmpFile);
return tmpFile;
}
and for each multipart file iteration, i have put the converted file to a list and after I finished uploading the file, I iterated my list and deleted the file.
Cheers.

Related

Destination file already exists and could not be deleted when upload

My web app is made on Spring MVC. I have a method where the user can upload PDFs
.
The I am sending the file as mutlipart file to the server. Every time the user uploads.
All what I want is to send the files as attachments in that email.
My code
private File prepareAttachment(final MultipartFile mFile) {
File file = new File(System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + mFile.getOriginalFilename());
try {
if(file.exists()) {
file.delete();
}
mFile.transferTo(file);
} catch (FileNotFoundException fnfE) {
file.delete();
LOG.error(" file was not found.", fnfE);
} catch (IOException ioE) {
file.delete();
LOG.error("file has failed to upload.", ioE);
}
return file;
}
calling the method to prepare the attachment:
MimeMessagePreparator preparator = new MimeMessagePreparator() {
#Override
public void prepare(final MimeMessage mimeMessage) throws Exception {
File file = prepareAttachment(form.getFile());
File file2 = prepareAttachment(form.getFile2());
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true);
message.addAttachment(form.getFile().getOriginalFilename(), file);
message.addAttachment(form.getFile2().getOriginalFilename(), file2);
Getting exception:
2017-08-28 15:10:59,549 ERROR com.menards.requestForms.business.service.EmailService - file has failed to upload.
java.io.IOException: Destination file [C:\opt\tcserver\main\temp] already exists and could not be deleted
at org.springframework.web.multipart.commons.CommonsMultipartFile.transferTo(CommonsMultipartFile.java:160) ~[spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at com.menards.requestForms.business.service.EmailService.prepareAttachment(EmailService.java:552) ~[classes/:?]
this will work perfectly if I comment out adding the second file :(
message.addAttachment(form.getFile2().getOriginalFilename(), file2);
any advise?
Generally, you shouldn't let your users determine the path of a file that you're creating on your server - it introduces a lot of security vulnerabilities. In this case, they may be attempting to create a temp file that has the same as some other file in your temp directory, potentially one that has nothing to do with your current application. File.createTempFile ensures that it creates a file with a unique name on each invocation.
It's also good practice to clean up temp files as soon as you're finished with them, so you don't have to worry about maintaining state on your server between method calls. This can sometimes create code that's a bit busy with catch/finally blocks, but it's worth it to avoid waking up at 3 AM to a hard disk that's full of garbage temp files.
I'd implement this roughly as:
private File prepareAttachment(final MultipartFile mFile) throws IOException {
File tmp = null;
try {
tmp = File.createTempFile("upload", ".tmp");
mFile.transferTo(tmp);
return tmp;
} catch (IOException ioE) {
if (tmp != null) {
tmp.delete();
}
LOG.error("file has failed to upload.", ioE);
throw ioE;
}
}
MimeMessagePreparator preparator = new MimeMessagePreparator() {
#Override
public void prepare(final MimeMessage mimeMessage) throws Exception {
File file1 = null;
File file2 = null;
try {
file1 = prepareAttachment(form.getFile());
file2 = prepareAttachment(form.getFile2());
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true);
message.addAttachment(form.getFile().getOriginalFilename(), file1);
message.addAttachment(form.getFile2().getOriginalFilename(), file2);
// do your other stuff
} catch (IOException e) {
// some sort of error-handling, probably returning a message with an error status
} finally {
if (file1 != null) {
file1.delete();
}
if (file2 != null) {
file2.delete();
}
}
}
};

Delete file after Dropbox transfer fails

I try to use the official Dropbox API for uploading a zip file to my account. My project is a desktop application (standard Java). My code looks like this:
public void uploadZipFile(File file) throws Exception {
FileInputStream fis = new FileInputStream(file);
try {
getClient(accessToken).uploadFile("/" + file.getName(), DbxWriteMode.add(), file.length(), fis);
} finally {
fis.close();
}
}
private DbxClient getClient(String accessToken) {
DbxRequestConfig dbxRequestConfig = new DbxRequestConfig(Constants.APP_NAME, Locale.getDefault().toString());
return new DbxClient(dbxRequestConfig, accessToken);
}
And I call it:
File zipFile = new File("C:\\Test\\MyFile.zip");
try {
uploadZipFile(zipFile);
} catch (Exception e) {
e.printStackTrace();
}
The file is transferred without any problems but then I want to delete the file after synchronization:
File zipFile = new File("C:\\Test\\MyFile.zip");
try {
uploadZipFile(zipFile);
System.out.println(zipFile.delete());
} catch (Exception e) {
e.printStackTrace();
}
The file is transferred successfully again, but the file still exists in the local file system and the delete method returns false.

Missing bytes when calling HttpServletRequest.getInputSteam() method

I am creating Restful web service that accepts any file and saves it into filesystem. I am using Dropwizard to implement the service and Postman/RestClient to hit the request with data. I am not creating multipart (form-data) request.
Every thing is working fine except the file saved has first character missing. Here is my code for calling the service method and saving it into file system:
Input Request:
http://localhost:8080/test/request/Sample.txt
Sample.txt
Test Content
Rest Controller
#PUT
#Consumes(value = MediaType.WILDCARD)
#Path("/test/request/{fileName}")
public Response authenticateDevice(#PathParam("fileName") String fileName, #Context HttpServletRequest request) throws IOException {
.......
InputStream inputStream = request.getInputStream();
writeFile(inputStream, fileName);
......
}
private void writeFile(InputStream inputStream, String fileName) {
OutputStream os = null;
try {
File file = new File(this.directory);
file.mkdirs();
if (file.exists()) {
os = new FileOutputStream(this.directory + fileName);
logger.info("File Written Successfully.");
} else {
logger.info("Problem Creating directory. File can not be saved!");
}
byte[] buffer = new byte[inputStream.available()];
int n;
while ((n = inputStream.read(buffer)) != -1) {
os.write(buffer, 0, n);
}
} catch (Exception e) {
logger.error("Error in writing to File::" + e);
} finally {
try {
os.close();
inputStream.close();
} catch (IOException e) {
logger.error("Error in closing input/output stream::" + e);
}
}
}
In output, file is saved but first character from the content is missing.
Output:
Sample.txt:
est Content
In above output file, character T is missing and this happens for all the file formats.
I don't know what point I am missing here.
Please help me out on this.
Thank You.

Sending a Zip file to Rest WebService

I'm trying to implement a method in my java based application that involves uploading a zip file to my server. Client is java, server is java (REST , jboss 7) . In the past I successfully managed to upload image files, but now, with a zip file i am having issues and my main doubt is if these issues are client related or server related (or both) .
So , my client looks like this
final HttpHeaders headers = HttpClientUtils.headersJSONAndAcceptJSON();
MultiValueMap<String, Object> requestMap = new LinkedMultiValueMap<String, Object>();
addMap("filename", filename, requestMap);
addMap("contenttype", contentType, requestMap);
addMap("type", type, requestMap);
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
int b = -1;
//file data is the inputstream created from the File
while ( (b = filedata.read())>= 0 ) {
bout.write(b);
}
ByteArrayResource rs = new ByteArrayResource( bout.toByteArray() ){
#Override
public String getFilename() {
return "";
}
};
addMap("resource", rs, requestMap);
} catch (IOException e1) {
throw new IllegalStateException("Error");
}
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.setAccept(Arrays.asList(HttpClientUtils.mtypeJSONUtf8()));
final String url = this.baseURL + summaryURL;
try {
ResponseEntity<Summary> rEntity = restTemplate.exchange(
url,
HttpMethod.POST,
HttpClientUtils.entity(headers, requestMap),
Summary.class
(...)
and meanwhile on the server side I have
#POST
#Path("/")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces("application/json; charset=UTF-8")
public Summary addImportedSummary(#MultipartForm FileUploadFormObj imp)
{
Summary importedSummary = new Summary();
Map<String , String> newpath = new HashMap<String, String>();
if(imp.getFileData() != null)
{
ZipInputStream zip = new ZipInputStream(imp.getFileData());
ZipEntry entry;
try {
while ((entry = zip.getNextEntry()) != null)
{
if(entry.getName().endsWith(".html") || entry.getName().endsWith(".htm"))
{
if(entry.getSize() > 0)
{
StringWriter writer = new StringWriter();
IOUtils.copy(zip, writer, "UTF-8");
String content = writer.toString();
//do something with the content
}
}
}
zip.close();
} catch (IOException e) {
throw new BadRequestException("Error " + e);
}
}
The problem happens when I try to copy the file content with IOUtils or any other reader. I always get the exception
ZipException too many length or distance symbols
Now, I think the problem might be in the way I am sending the data due to the file being a zip but I don't know exactly where the problem is. Did everyone ever ran into a similar problem?

JAX-RS - Wink - Correct way to read a file, using Wink Client

Related to this question which is about how to send a binary file to a client. I am doing this, actually my method #Produces("application/zip"), and it works well for the browser client. Now I'm trying to write some automated tests against the rest service, using the Wink client. So my question is not how to send the file to the client, but for how to consume the file, as a java rest client (in this case Apache Wink).
My resource method looks something like the below... Once I have a Wink ClientResponse object, how can I get the file from it so I can work with it?
#GET
#Path("/file")
#Produces("application/zip")
public javax.ws.rs.core.Response getFile() {
filesToZip.put("file.txt", myText);
ResponseBuilder responseBuilder = null;
javax.ws.rs.core.Response response = null;
InputStream in = null;
try {
in = new FileInputStream( createZipFile( filesToZip ) );
responseBuilder = javax.ws.rs.core.Response.ok(in, MediaType.APPLICATION_OCTET_STREAM_TYPE);
response = responseBuilder.header("content-disposition", "inline;filename="file.zip").build();
} catch( FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
return response;
The method that actually creates the zip file looks like this
private String createZipFile( Map<String,String> zipFiles ) {
ZipOutputStream zos = null;
File file = null;
String createdFileCanonicalPath = null;
try {
// create a temp file -- the ZIP Container
file = File.createTempFile("files", ".zip");
zos = new ZipOutputStream( new FileOutputStream(file));
// for each entry in the Map, create an inner zip entry
for (Iterator<Map.Entry<String, String>> it = zipFiles.entrySet().iterator(); it.hasNext();){
Map.Entry<String, String> entry = it.next();
String innerFileName = entry.getKey();
String textContent = entry.getValue();
zos.putNextEntry( new ZipEntry(innerFileName) );
StringBuilder sb = new StringBuilder();
byte[] contentInBytes = sb.append(textContent).toString().getBytes();
zos.write(contentInBytes, 0, contentInBytes.length);
zos.closeEntry();
}
zos.flush();
zos.close();
createdFileCanonicalPath = file.getCanonicalPath();
} catch (SecurityException se) {
se.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (zos != null) {
zos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return createdFileCanonicalPath;
}
You can consume it simply as input stream and use ZipInputStream to unzip it.
Here's example using Apache HTTP Client:
HttpClient httpclient = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
get.addHeader(new BasicHeader("Accept", "application/zip"));
HttpResponse response = httpclient.execute(get);
InputStream is = response.getEntity().getContent();
ZipInputStream zip = new ZipInputStream(is);

Categories

Resources