Skip to content

Commit 3de4c15

Browse files
author
Igor Polevoy
committed
#252 Implement ability to automatically delete temporary file after sending it to client
1 parent df3699b commit 3de4c15

File tree

6 files changed

+100
-19
lines changed

6 files changed

+100
-19
lines changed

activeweb/src/main/java/org/javalite/activeweb/ControllerResponse.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package org.javalite.activeweb;
1717

18+
import java.io.IOException;
19+
import java.io.InputStream;
20+
import java.io.OutputStream;
1821
import java.util.HashMap;
1922
import java.util.Map;
2023

@@ -64,5 +67,14 @@ final void process(){
6467
doProcess();
6568
}
6669

70+
protected final void stream(InputStream in, OutputStream out) throws IOException {
71+
byte[] bytes = new byte[1024];
72+
int x;
73+
while((x = in.read(bytes)) != -1){
74+
out.write(bytes, 0, x);
75+
}
76+
in.close();
77+
}
78+
6779
abstract void doProcess();
6880
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.javalite.activeweb;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
import java.io.File;
7+
import java.io.FileInputStream;
8+
9+
/**
10+
* @author Igor Polevoy on 12/30/15.
11+
*/
12+
class FileResponse extends ControllerResponse {
13+
Logger logger = LoggerFactory.getLogger(FileResponse.class);
14+
15+
private File file;
16+
private boolean delete = false;
17+
18+
FileResponse(File file) {
19+
this.file = file;
20+
}
21+
22+
/**
23+
* @param delete true to delete file after sending to client
24+
*/
25+
FileResponse(File file, boolean delete) {
26+
this(file);
27+
this.delete = delete;
28+
}
29+
30+
@Override
31+
void doProcess() {
32+
try {
33+
stream(new FileInputStream(file), Context.getHttpResponse().getOutputStream());
34+
if (delete) {
35+
if (!file.delete()) {
36+
logger.warn("failed to delete file: " + file + " after processing");
37+
}
38+
}
39+
} catch (Exception e) {
40+
throw new ControllerException(e);
41+
}
42+
}
43+
44+
}

activeweb/src/main/java/org/javalite/activeweb/HttpSupport.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,12 +490,13 @@ protected HttpBuilder respond(String text){
490490
* "Content-Disposition" based on a file name.
491491
*
492492
* @param file file to download.
493+
* @param delete true to delete the file after processing
493494
* @return builder instance.
494495
* @throws FileNotFoundException thrown if file not found.
495496
*/
496-
protected HttpBuilder sendFile(File file) throws FileNotFoundException {
497+
protected HttpBuilder sendFile(File file, boolean delete) throws FileNotFoundException {
497498
try{
498-
StreamResponse resp = new StreamResponse(new FileInputStream(file));
499+
FileResponse resp = new FileResponse(file, delete);
499500
Context.setControllerResponse(resp);
500501
HttpBuilder builder = new HttpBuilder(resp);
501502
builder.header("Content-Disposition", "attachment; filename=" + file.getName());
@@ -505,6 +506,19 @@ protected HttpBuilder sendFile(File file) throws FileNotFoundException {
505506
}
506507
}
507508

509+
/**
510+
* Convenience method for downloading files. This method will force the browser to find a handler(external program)
511+
* for this file (content type) and will provide a name of file to the browser. This method sets an HTTP header
512+
* "Content-Disposition" based on a file name.
513+
*
514+
* @param file file to download.
515+
* @return builder instance.
516+
* @throws FileNotFoundException thrown if file not found.
517+
*/
518+
protected HttpBuilder sendFile(File file) throws FileNotFoundException {
519+
return sendFile(file, false);
520+
}
521+
508522

509523
/**
510524
* Convenience method to get file content from <code>multipart/form-data</code> request. If more than one files with the same

activeweb/src/main/java/org/javalite/activeweb/StreamResponse.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,11 @@ class StreamResponse extends ControllerResponse{
2828
StreamResponse(InputStream in){
2929
this.in = in;
3030
}
31+
3132
@Override
3233
void doProcess() {
3334
try{
34-
OutputStream out = Context.getHttpResponse().getOutputStream();
35-
byte[] bytes = new byte[1024];
36-
37-
int x;
38-
while((x = in.read(bytes)) != -1){
39-
out.write(bytes, 0, x);
40-
}
41-
out.flush();
42-
in.close();
35+
stream(in, Context.getHttpResponse().getOutputStream());
4336
}
4437
catch(Exception e){
4538
throw new ControllerException(e);

activeweb/src/test/java/app/controllers/StreamController.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static org.javalite.common.Collections.map;
2323

2424
import java.io.*;
25+
import java.nio.file.Files;
2526

2627
/**
2728
* @author Igor Polevoy
@@ -48,4 +49,9 @@ public void writeWithContentTypeAndHeaders() throws IOException {
4849
public void streamWithContentTypeAndHeaders() throws IOException {
4950
outputStream("text/plain", map("Content-Length", 5), 200).write("hello".getBytes());
5051
}
52+
53+
public void deleteFile() throws IOException {
54+
File f = new File(param("file"));
55+
sendFile(f, true);
56+
}
5157
}

activeweb/src/test/java/org/javalite/activeweb/StreamSpec.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,11 @@
1616

1717
package org.javalite.activeweb;
1818

19-
import org.javalite.test.jspec.JSpecSupport;
20-
import org.junit.Before;
2119
import org.junit.Test;
22-
import org.springframework.mock.web.MockFilterConfig;
23-
import org.springframework.mock.web.MockHttpServletRequest;
24-
import org.springframework.mock.web.MockHttpServletResponse;
2520

26-
import javax.servlet.FilterChain;
2721
import javax.servlet.ServletException;
28-
import javax.servlet.ServletRequest;
29-
import javax.servlet.ServletResponse;
22+
import java.io.File;
23+
import java.io.FileOutputStream;
3024
import java.io.IOException;
3125

3226
/**
@@ -87,4 +81,22 @@ public void shouldStreamWithContentTypeAndHeaders() throws ServletException, IOE
8781
a(response.getHeader("Content-Length")).shouldEqual("5");
8882
a(response.getContentType()).shouldEqual("text/plain");
8983
}
84+
85+
@Test
86+
public void shouldDeleteFileAfterProcessing() throws ServletException, IOException {
87+
88+
//create a file:
89+
File file = File.createTempFile("file123", "suffix");
90+
FileOutputStream outputStream = new FileOutputStream(file);
91+
outputStream.write("hello".getBytes());
92+
outputStream.flush();
93+
outputStream.close();
94+
95+
request.setServletPath("/stream/delete-file");
96+
request.setMethod("GET");
97+
request.setParameter("file", file.getCanonicalPath());
98+
dispatcher.doFilter(request, response, filterChain);
99+
a(response.getContentAsString()).shouldBeEqual("hello");
100+
the(file.exists()).shouldBeFalse();
101+
}
90102
}

0 commit comments

Comments
 (0)