* improved DownloadTask and ByteBufferOutputStream

* added unit test for ByteBufferOutputStream
This commit is contained in:
Reinhard Pointner 2008-11-22 15:30:33 +00:00
parent 892ada4df4
commit 74b6a8c1a9
5 changed files with 84 additions and 33 deletions

View File

@ -13,7 +13,7 @@ public class ByteBufferInputStream extends InputStream {
public ByteBufferInputStream(ByteBuffer buffer) { public ByteBufferInputStream(ByteBuffer buffer) {
this.buffer = buffer; this.buffer = buffer.duplicate();
} }

View File

@ -92,4 +92,14 @@ public class ByteBufferOutputStream extends OutputStream {
return channel.read(buffer); return channel.read(buffer);
} }
public synchronized int position() {
return buffer.position();
}
public synchronized int capacity() {
return buffer.capacity();
}
} }

View File

@ -37,8 +37,7 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
private URL url; private URL url;
private long size = -1; private long contentLength = -1;
private long bytesRead = 0;
private DownloadState state = DownloadState.PENDING; private DownloadState state = DownloadState.PENDING;
private Map<String, String> postParameters; private Map<String, String> postParameters;
@ -71,43 +70,47 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
HttpURLConnection connection = createConnection(); HttpURLConnection connection = createConnection();
if (postParameters != null) { 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.setRequestMethod("POST");
connection.setDoOutput(true); connection.setDoOutput(true);
// write post data
WritableByteChannel out = Channels.newChannel(connection.getOutputStream()); WritableByteChannel out = Channels.newChannel(connection.getOutputStream());
out.write(encodeParameters(postParameters)); out.write(postData);
out.close(); out.close();
} }
size = connection.getContentLength(); contentLength = connection.getContentLength();
responseHeaders = connection.getHeaderFields(); responseHeaders = connection.getHeaderFields();
setDownloadState(DownloadState.DOWNLOADING); setDownloadState(DownloadState.DOWNLOADING);
ReadableByteChannel in = Channels.newChannel(connection.getInputStream()); ReadableByteChannel in = Channels.newChannel(connection.getInputStream());
ByteBufferOutputStream buffer = new ByteBufferOutputStream((int) (size > 0 ? size : 32 * 1024)); ByteBufferOutputStream buffer = new ByteBufferOutputStream((int) (contentLength > 0 ? contentLength : 32 * 1024));
int count = 0;
try { try {
while (!isCancelled() && ((count = buffer.transferFrom(in)) >= 0)) { while (!isCancelled() && ((buffer.transferFrom(in)) >= 0)) {
bytesRead += count;
firePropertyChange(DOWNLOAD_PROGRESS, null, bytesRead); firePropertyChange(DOWNLOAD_PROGRESS, null, buffer.position());
if (isDownloadSizeKnown()) { if (isContentLengthKnown()) {
setProgress((int) ((bytesRead * 100) / size)); setProgress((int) ((buffer.position() * 100) / contentLength));
} }
} }
} catch (IOException e) { } catch (IOException e) {
// IOException (Premature EOF) is always thrown when the size of // if the content length is not known in advance an IOException (Premature EOF)
// the response body is not known in advance, so we ignore it, if that is the case // is always thrown after all the data has been read
if (isDownloadSizeKnown()) if (isContentLengthKnown())
throw e; throw e;
} finally { } finally {
in.close(); in.close();
buffer.close();
// download either finished or an exception is thrown // download either finished or an exception is thrown
setDownloadState(DownloadState.DONE); setDownloadState(DownloadState.DONE);
@ -133,18 +136,13 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
} }
public long getBytesRead() { public boolean isContentLengthKnown() {
return bytesRead; return contentLength >= 0;
} }
public boolean isDownloadSizeKnown() { public long getContentLength() {
return size >= 0; return contentLength;
}
public long getDownloadSize() {
return size;
} }
@ -173,13 +171,11 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
} }
protected static ByteBuffer encodeParameters(Map<String, String> parameters) { protected ByteBuffer encodeParameters(Map<String, String> parameters) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int i = 0;
for (Entry<String, String> entry : parameters.entrySet()) { for (Entry<String, String> entry : parameters.entrySet()) {
if (i > 0) if (sb.length() > 0)
sb.append("&"); sb.append("&");
sb.append(entry.getKey()); sb.append(entry.getKey());
@ -191,8 +187,6 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
// will never happen // will never happen
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e); Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
} }
i++;
} }
return Charset.forName("UTF-8").encode(sb.toString()); return Charset.forName("UTF-8").encode(sb.toString());

View File

@ -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());
}
}

View File

@ -11,7 +11,7 @@ import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class) @RunWith(Suite.class)
@SuiteClasses( { PreferencesMapTest.class, PreferencesListTest.class }) @SuiteClasses( { ByteBufferOutputStreamTest.class, PreferencesMapTest.class, PreferencesListTest.class })
public class TunedTestSuite { public class TunedTestSuite {
public static Test suite() { public static Test suite() {