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.Header;
36 import org.apache.http.HttpEntity;
37 import org.apache.http.HttpResponse;
38 import org.apache.http.entity.ContentType;
39 import org.apache.http.entity.FileEntity;
40 import org.apache.http.nio.ContentDecoder;
41 import org.apache.http.nio.ContentDecoderChannel;
42 import org.apache.http.nio.FileContentDecoder;
43 import org.apache.http.nio.IOControl;
44 import org.apache.http.nio.protocol.AbstractAsyncResponseConsumer;
45 import org.apache.http.protocol.HttpContext;
46 import org.apache.http.util.Asserts;
47
48
49
50
51
52
53
54
55
56
57 public abstract class ZeroCopyConsumer<T> extends AbstractAsyncResponseConsumer<T> {
58
59 private final File file;
60 private final RandomAccessFile accessfile;
61
62 private HttpResponse response;
63 private ContentType contentType;
64 private Header contentEncoding;
65 private FileChannel fileChannel;
66 private long idx = -1;
67
68 public ZeroCopyConsumer(final File file) throws FileNotFoundException {
69 super();
70 if (file == null) {
71 throw new IllegalArgumentException("File may nor be null");
72 }
73 this.file = file;
74 this.accessfile = new RandomAccessFile(this.file, "rw");
75 }
76
77 @Override
78 protected void onResponseReceived(final HttpResponse response) {
79 this.response = response;
80 }
81
82 @Override
83 protected void onEntityEnclosed(
84 final HttpEntity entity, final ContentType contentType) throws IOException {
85 this.contentType = contentType;
86 this.contentEncoding = entity.getContentEncoding();
87 this.fileChannel = this.accessfile.getChannel();
88 this.idx = 0;
89 }
90
91 @Override
92 protected void onContentReceived(
93 final ContentDecoder decoder, final IOControl ioControl) throws IOException {
94 Asserts.notNull(this.fileChannel, "File channel");
95 final long transferred;
96 if (decoder instanceof FileContentDecoder) {
97 transferred = ((FileContentDecoder)decoder).transfer(
98 this.fileChannel, this.idx, Integer.MAX_VALUE);
99 } else {
100 transferred = this.fileChannel.transferFrom(
101 new ContentDecoderChannel(decoder), this.idx, Integer.MAX_VALUE);
102 }
103 if (transferred > 0) {
104 this.idx += transferred;
105 }
106 if (decoder.isCompleted()) {
107 this.fileChannel.close();
108 }
109 }
110
111
112
113
114
115
116
117
118
119 protected abstract T process(
120 HttpResponse response, File file, ContentType contentType) throws Exception;
121
122 @Override
123 protected T buildResult(final HttpContext context) throws Exception {
124 final FileEntity entity = new FileEntity(this.file, this.contentType);
125 entity.setContentEncoding(this.contentEncoding);
126 this.response.setEntity(entity);
127 return process(this.response, this.file, this.contentType);
128 }
129
130 @Override
131 protected void releaseResources() {
132 try {
133 this.accessfile.close();
134 } catch (final IOException ignore) {
135 }
136 }
137
138 }