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