* improved DownloadTask

* added ByteBufferOutputStream
This commit is contained in:
Reinhard Pointner 2008-11-19 16:22:31 +00:00
parent e0d52fb515
commit 4bb8ff29d8
2 changed files with 137 additions and 40 deletions

View File

@ -0,0 +1,95 @@
package net.sourceforge.tuned;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
public class ByteBufferOutputStream extends OutputStream {
private ByteBuffer buffer;
private final float loadFactor;
public ByteBufferOutputStream(int initialCapacity) {
this(initialCapacity, 1.0f);
}
public ByteBufferOutputStream(int initialCapacity, float loadFactor) {
if (initialCapacity <= 0)
throw new IllegalArgumentException("initialCapacity must be greater than 0");
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("loadFactor must be greater than 0");
this.buffer = ByteBuffer.allocate(initialCapacity);
this.loadFactor = loadFactor;
}
@Override
public synchronized void write(int b) throws IOException {
ensureCapacity(buffer.position() + 1);
buffer.put((byte) b);
}
@Override
public synchronized void write(byte[] src) throws IOException {
ensureCapacity(buffer.position() + src.length);
buffer.put(src);
}
@Override
public synchronized void write(byte[] src, int offset, int length) throws IOException {
ensureCapacity(buffer.position() + length);
buffer.put(src, offset, length);
}
public synchronized void ensureCapacity(int minCapacity) {
if (minCapacity <= buffer.capacity())
return;
// calculate new buffer size with load factor
int newCapacity = (int) (buffer.capacity() * (1 + loadFactor));
// ensure minCapacity
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// create new buffer with increased capacity
ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity);
// copy current data to new buffer
buffer.flip();
newBuffer.put(buffer);
buffer = newBuffer;
}
public synchronized ByteBuffer getByteBuffer() {
ByteBuffer result = buffer.duplicate();
// flip buffer so it can be read
result.flip();
return result;
}
public synchronized int transferFrom(ReadableByteChannel channel) throws IOException {
// make sure buffer is not at its limit
ensureCapacity(buffer.position() + 1);
return channel.read(buffer);
}
}

View File

@ -2,19 +2,18 @@
package net.sourceforge.tuned;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
@ -36,38 +35,29 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
DONE
}
private static final int BUFFER_SIZE = 4 * 1024;
private URL url;
private ByteBuffer postdata;
private long size = -1;
private long bytesRead = 0;
private DownloadState state = DownloadState.PENDING;
private final Map<String, String> requestHeaders = new HashMap<String, String>();
private final Map<String, String> responseHeaders = new HashMap<String, String>();
private Map<String, String> postParameters;
private Map<String, String> requestHeaders;
private Map<String, List<String>> responseHeaders;
public DownloadTask(URL url) {
this(url, null);
}
public DownloadTask(URL url, Map<String, String> postParameters) {
this.url = url;
if (postParameters != null) {
this.postdata = encodeParameters(postParameters);
}
}
protected HttpURLConnection createConnection() throws Exception {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
for (String key : requestHeaders.keySet()) {
connection.addRequestProperty(key, requestHeaders.get(key));
if (requestHeaders != null) {
for (Entry<String, String> entry : requestHeaders.entrySet()) {
connection.addRequestProperty(entry.getKey(), entry.getValue());
}
}
return connection;
@ -80,33 +70,28 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
HttpURLConnection connection = createConnection();
if (postdata != null) {
if (postParameters != null) {
connection.setRequestMethod("POST");
connection.setDoOutput(true);
WritableByteChannel out = Channels.newChannel(connection.getOutputStream());
out.write(postdata);
out.write(encodeParameters(postParameters));
out.close();
}
size = connection.getContentLength();
for (String key : connection.getHeaderFields().keySet()) {
responseHeaders.put(key, connection.getHeaderField(key));
}
responseHeaders = connection.getHeaderFields();
setDownloadState(DownloadState.DOWNLOADING);
InputStream in = connection.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max((int) size, BUFFER_SIZE));
ReadableByteChannel in = Channels.newChannel(connection.getInputStream());
ByteBufferOutputStream buffer = new ByteBufferOutputStream((int) (size > 0 ? size : 32 * 1024));
byte[] buffer = new byte[BUFFER_SIZE];
int len = 0;
int count = 0;
try {
while (((len = in.read(buffer)) >= 0) && !isCancelled()) {
out.write(buffer, 0, len);
bytesRead += len;
while (!isCancelled() && ((count = buffer.transferFrom(in)) >= 0)) {
bytesRead += count;
firePropertyChange(DOWNLOAD_PROGRESS, null, bytesRead);
@ -116,17 +101,19 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
}
} catch (IOException e) {
// IOException (Premature EOF) is always thrown when the size of
// the response body is not known in advance, so we ignore it
// the response body is not known in advance, so we ignore it, if that is the case
if (isDownloadSizeKnown())
throw e;
} finally {
in.close();
out.close();
buffer.close();
// download either finished or an exception is thrown
setDownloadState(DownloadState.DONE);
}
setDownloadState(DownloadState.DONE);
return ByteBuffer.wrap(out.toByteArray());
return buffer.getByteBuffer();
}
@ -161,13 +148,28 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
}
public void setRequestHeader(String name, String value) {
requestHeaders.put(name, value);
public void setRequestHeaders(Map<String, String> requestHeaders) {
this.requestHeaders = new HashMap<String, String>(requestHeaders);
}
public Map<String, String> getResponseHeaders() {
return Collections.unmodifiableMap(responseHeaders);
public void setPostParameters(Map<String, String> postParameters) {
this.postParameters = new HashMap<String, String>(postParameters);
}
public Map<String, List<String>> getResponseHeaders() {
return responseHeaders;
}
public Map<String, String> getPostParameters() {
return postParameters;
}
public Map<String, String> getRequestHeaders() {
return requestHeaders;
}