* improved DownloadTask and ByteBufferOutputStream
* added unit test for ByteBufferOutputStream
This commit is contained in:
parent
892ada4df4
commit
74b6a8c1a9
|
@ -13,7 +13,7 @@ public class ByteBufferInputStream extends InputStream {
|
||||||
|
|
||||||
|
|
||||||
public ByteBufferInputStream(ByteBuffer buffer) {
|
public ByteBufferInputStream(ByteBuffer buffer) {
|
||||||
this.buffer = buffer;
|
this.buffer = buffer.duplicate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue