From 74b6a8c1a937c0636e24ef19edb9d5b1081a55bc Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Sat, 22 Nov 2008 15:30:33 +0000 Subject: [PATCH] * improved DownloadTask and ByteBufferOutputStream * added unit test for ByteBufferOutputStream --- .../tuned/ByteBufferInputStream.java | 2 +- .../tuned/ByteBufferOutputStream.java | 10 ++++ .../net/sourceforge/tuned/DownloadTask.java | 56 +++++++++---------- .../tuned/ByteBufferOutputStreamTest.java | 47 ++++++++++++++++ .../net/sourceforge/tuned/TunedTestSuite.java | 2 +- 5 files changed, 84 insertions(+), 33 deletions(-) create mode 100644 test/net/sourceforge/tuned/ByteBufferOutputStreamTest.java diff --git a/source/net/sourceforge/tuned/ByteBufferInputStream.java b/source/net/sourceforge/tuned/ByteBufferInputStream.java index 3eeeac19..1fa5e911 100644 --- a/source/net/sourceforge/tuned/ByteBufferInputStream.java +++ b/source/net/sourceforge/tuned/ByteBufferInputStream.java @@ -13,7 +13,7 @@ public class ByteBufferInputStream extends InputStream { public ByteBufferInputStream(ByteBuffer buffer) { - this.buffer = buffer; + this.buffer = buffer.duplicate(); } diff --git a/source/net/sourceforge/tuned/ByteBufferOutputStream.java b/source/net/sourceforge/tuned/ByteBufferOutputStream.java index 00f91ca6..967aedd2 100644 --- a/source/net/sourceforge/tuned/ByteBufferOutputStream.java +++ b/source/net/sourceforge/tuned/ByteBufferOutputStream.java @@ -92,4 +92,14 @@ public class ByteBufferOutputStream extends OutputStream { return channel.read(buffer); } + + public synchronized int position() { + return buffer.position(); + } + + + public synchronized int capacity() { + return buffer.capacity(); + } + } diff --git a/source/net/sourceforge/tuned/DownloadTask.java b/source/net/sourceforge/tuned/DownloadTask.java index 65b54604..c86da16e 100644 --- a/source/net/sourceforge/tuned/DownloadTask.java +++ b/source/net/sourceforge/tuned/DownloadTask.java @@ -37,8 +37,7 @@ public class DownloadTask extends SwingWorker { private URL url; - private long size = -1; - private long bytesRead = 0; + private long contentLength = -1; private DownloadState state = DownloadState.PENDING; private Map postParameters; @@ -71,43 +70,47 @@ public class DownloadTask extends SwingWorker { HttpURLConnection connection = createConnection(); if (postParameters != null) { + ByteBuffer postData = encodeParameters(postParameters); + + // add content type and content length headers + connection.addRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + connection.addRequestProperty("Content-Length", String.valueOf(postData.remaining())); + connection.setRequestMethod("POST"); connection.setDoOutput(true); + + // write post data WritableByteChannel out = Channels.newChannel(connection.getOutputStream()); - out.write(encodeParameters(postParameters)); + out.write(postData); out.close(); } - size = connection.getContentLength(); + contentLength = connection.getContentLength(); responseHeaders = connection.getHeaderFields(); setDownloadState(DownloadState.DOWNLOADING); ReadableByteChannel in = Channels.newChannel(connection.getInputStream()); - ByteBufferOutputStream buffer = new ByteBufferOutputStream((int) (size > 0 ? size : 32 * 1024)); - - int count = 0; + ByteBufferOutputStream buffer = new ByteBufferOutputStream((int) (contentLength > 0 ? contentLength : 32 * 1024)); try { - while (!isCancelled() && ((count = buffer.transferFrom(in)) >= 0)) { - bytesRead += count; + while (!isCancelled() && ((buffer.transferFrom(in)) >= 0)) { - firePropertyChange(DOWNLOAD_PROGRESS, null, bytesRead); + firePropertyChange(DOWNLOAD_PROGRESS, null, buffer.position()); - if (isDownloadSizeKnown()) { - setProgress((int) ((bytesRead * 100) / size)); + if (isContentLengthKnown()) { + setProgress((int) ((buffer.position() * 100) / contentLength)); } } } 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, if that is the case - if (isDownloadSizeKnown()) + // if the content length is not known in advance an IOException (Premature EOF) + // is always thrown after all the data has been read + if (isContentLengthKnown()) throw e; } finally { in.close(); - buffer.close(); // download either finished or an exception is thrown setDownloadState(DownloadState.DONE); @@ -133,18 +136,13 @@ public class DownloadTask extends SwingWorker { } - public long getBytesRead() { - return bytesRead; + public boolean isContentLengthKnown() { + return contentLength >= 0; } - public boolean isDownloadSizeKnown() { - return size >= 0; - } - - - public long getDownloadSize() { - return size; + public long getContentLength() { + return contentLength; } @@ -173,13 +171,11 @@ public class DownloadTask extends SwingWorker { } - protected static ByteBuffer encodeParameters(Map parameters) { + protected ByteBuffer encodeParameters(Map parameters) { StringBuilder sb = new StringBuilder(); - int i = 0; - for (Entry entry : parameters.entrySet()) { - if (i > 0) + if (sb.length() > 0) sb.append("&"); sb.append(entry.getKey()); @@ -191,8 +187,6 @@ public class DownloadTask extends SwingWorker { // will never happen Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e); } - - i++; } return Charset.forName("UTF-8").encode(sb.toString()); diff --git a/test/net/sourceforge/tuned/ByteBufferOutputStreamTest.java b/test/net/sourceforge/tuned/ByteBufferOutputStreamTest.java new file mode 100644 index 00000000..9edb62ce --- /dev/null +++ b/test/net/sourceforge/tuned/ByteBufferOutputStreamTest.java @@ -0,0 +1,47 @@ + +package net.sourceforge.tuned; + + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.channels.Channels; +import java.nio.charset.Charset; + +import org.junit.Test; + + +public class ByteBufferOutputStreamTest { + + @Test + public void growBufferAsNeeded() throws Exception { + // initial buffer size of 1, increase size by a factor of 2 if a bigger buffer is needed + ByteBufferOutputStream buffer = new ByteBufferOutputStream(1, 1.0f); + + buffer.write("asdf".getBytes("utf-8")); + + // check content + assertEquals("asdf", Charset.forName("utf-8").decode(buffer.getByteBuffer()).toString()); + + // check capacity + assertEquals(4, buffer.capacity()); + } + + + @Test + public void transferFrom() throws Exception { + InputStream in = new ByteArrayInputStream("asdf".getBytes("utf-8")); + + ByteBufferOutputStream buffer = new ByteBufferOutputStream(4); + + int n = buffer.transferFrom(Channels.newChannel(in)); + + // check number of bytes transfered + assertEquals(4, n); + + // check content + assertEquals("asdf", Charset.forName("utf-8").decode(buffer.getByteBuffer()).toString()); + } + +} diff --git a/test/net/sourceforge/tuned/TunedTestSuite.java b/test/net/sourceforge/tuned/TunedTestSuite.java index c32e0d7d..c915f73c 100644 --- a/test/net/sourceforge/tuned/TunedTestSuite.java +++ b/test/net/sourceforge/tuned/TunedTestSuite.java @@ -11,7 +11,7 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses( { PreferencesMapTest.class, PreferencesListTest.class }) +@SuiteClasses( { ByteBufferOutputStreamTest.class, PreferencesMapTest.class, PreferencesListTest.class }) public class TunedTestSuite { public static Test suite() {