1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.http.nio.client.methods;
28
29 import java.io.File;
30 import java.io.FileNotFoundException;
31 import java.io.IOException;
32 import java.io.RandomAccessFile;
33 import java.nio.channels.FileChannel;
34
35 import org.apache.http.HttpEntity;
36 import org.apache.http.HttpResponse;
37 import org.apache.http.entity.ContentType;
38 import org.apache.http.entity.FileEntity;
39 import org.apache.http.nio.ContentDecoder;
40 import org.apache.http.nio.ContentDecoderChannel;
41 import org.apache.http.nio.FileContentDecoder;
42 import org.apache.http.nio.IOControl;
43 import org.apache.http.nio.protocol.AbstractAsyncResponseConsumer;
44 import org.apache.http.protocol.HTTP;
45 import org.apache.http.protocol.HttpContext;
46 import org.apache.http.util.Asserts;
47
48 public abstract class ZeroCopyConsumer<T> extends AbstractAsyncResponseConsumer<T> {
49
50 private final File file;
51 private final RandomAccessFile accessfile;
52
53 private HttpResponse response;
54 private ContentType contentType;
55 private FileChannel fileChannel;
56 private long idx = -1;
57
58 public ZeroCopyConsumer(final File file) throws FileNotFoundException {
59 super();
60 if (file == null) {
61 throw new IllegalArgumentException("File may nor be null");
62 }
63 this.file = file;
64 this.accessfile = new RandomAccessFile(this.file, "rw");
65 }
66
67 @Override
68 protected void onResponseReceived(final HttpResponse response) {
69 this.response = response;
70 }
71
72 @Override
73 protected void onEntityEnclosed(
74 final HttpEntity entity, final ContentType contentType) throws IOException {
75 this.contentType = contentType;
76 this.fileChannel = this.accessfile.getChannel();
77 this.idx = 0;
78 }
79
80 @Override
81 protected void onContentReceived(
82 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
83 Asserts.notNull(this.fileChannel, "File channel");
84 long transferred;
85 if (decoder instanceof FileContentDecoder) {
86 transferred = ((FileContentDecoder)decoder).transfer(
87 this.fileChannel, this.idx, Integer.MAX_VALUE);
88 } else {
89 transferred = this.fileChannel.transferFrom(
90 new ContentDecoderChannel(decoder), this.idx, Integer.MAX_VALUE);
91 }
92 if (transferred > 0) {
93 this.idx += transferred;
94 }
95 if (decoder.isCompleted()) {
96 this.fileChannel.close();
97 }
98 }
99
100 protected abstract T process(
101 HttpResponse response, File file, ContentType contentType) throws Exception;
102
103 @Override
104 protected T buildResult(final HttpContext context) throws Exception {
105 final FileEntity entity = new FileEntity(this.file);
106 entity.setContentType(this.response.getFirstHeader(HTTP.CONTENT_TYPE));
107 this.response.setEntity(entity);
108 return process(this.response, this.file, this.contentType);
109 }
110
111 @Override
112 protected void releaseResources() {
113 try {
114 this.accessfile.close();
115 } catch (final IOException ignore) {
116 }
117 }
118
119 }