From 4bb8ff29d813cee1ab7b759774b4c5afccdfacfd Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Wed, 19 Nov 2008 16:22:31 +0000 Subject: [PATCH] * improved DownloadTask * added ByteBufferOutputStream --- .../tuned/ByteBufferOutputStream.java | 95 +++++++++++++++++++ .../net/sourceforge/tuned/DownloadTask.java | 82 ++++++++-------- 2 files changed, 137 insertions(+), 40 deletions(-) create mode 100644 source/net/sourceforge/tuned/ByteBufferOutputStream.java diff --git a/source/net/sourceforge/tuned/ByteBufferOutputStream.java b/source/net/sourceforge/tuned/ByteBufferOutputStream.java new file mode 100644 index 00000000..00f91ca6 --- /dev/null +++ b/source/net/sourceforge/tuned/ByteBufferOutputStream.java @@ -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); + } + +} diff --git a/source/net/sourceforge/tuned/DownloadTask.java b/source/net/sourceforge/tuned/DownloadTask.java index 171349e9..65b54604 100644 --- a/source/net/sourceforge/tuned/DownloadTask.java +++ b/source/net/sourceforge/tuned/DownloadTask.java @@ -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 { 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 requestHeaders = new HashMap(); - private final Map responseHeaders = new HashMap(); + private Map postParameters; + private Map requestHeaders; + private Map> responseHeaders; public DownloadTask(URL url) { - this(url, null); - } - - - public DownloadTask(URL url, Map 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 entry : requestHeaders.entrySet()) { + connection.addRequestProperty(entry.getKey(), entry.getValue()); + } } return connection; @@ -80,33 +70,28 @@ public class DownloadTask extends SwingWorker { 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 { } } 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 { } - public void setRequestHeader(String name, String value) { - requestHeaders.put(name, value); + public void setRequestHeaders(Map requestHeaders) { + this.requestHeaders = new HashMap(requestHeaders); } - public Map getResponseHeaders() { - return Collections.unmodifiableMap(responseHeaders); + public void setPostParameters(Map postParameters) { + this.postParameters = new HashMap(postParameters); + } + + + public Map> getResponseHeaders() { + return responseHeaders; + } + + + public Map getPostParameters() { + return postParameters; + } + + + public Map getRequestHeaders() { + return requestHeaders; }