filebot/source/net/filebot/util/DownloadTask.java

153 lines
4.0 KiB
Java

package net.filebot.util;
import static java.nio.charset.StandardCharsets.*;
import static net.filebot.util.FileUtilities.*;
import static net.filebot.web.WebRequest.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.SwingWorker;
public class DownloadTask extends SwingWorker<ByteBuffer, Void> {
public static final String DOWNLOAD_STATE = "download state";
public static final String DOWNLOAD_PROGRESS = "download progress";
public static enum DownloadState {
PENDING, CONNECTING, DOWNLOADING, DONE
}
private URL url;
private long contentLength = -1;
private DownloadState state = DownloadState.PENDING;
private Map<String, String> postParameters;
private Map<String, String> requestHeaders;
private Map<String, List<String>> responseHeaders;
public DownloadTask(URL url) {
this.url = url;
}
protected HttpURLConnection createConnection() throws Exception {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (requestHeaders != null) {
for (Entry<String, String> entry : requestHeaders.entrySet()) {
connection.addRequestProperty(entry.getKey(), entry.getValue());
}
}
return connection;
}
@Override
protected ByteBuffer doInBackground() throws Exception {
setDownloadState(DownloadState.CONNECTING);
HttpURLConnection connection = createConnection();
if (postParameters != null) {
ByteBuffer postData = UTF_8.encode(encodeParameters(postParameters, true));
// 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(postData);
out.close();
}
contentLength = connection.getContentLength();
responseHeaders = connection.getHeaderFields();
setDownloadState(DownloadState.DOWNLOADING);
ReadableByteChannel in = Channels.newChannel(connection.getInputStream());
ByteBufferOutputStream buffer = new ByteBufferOutputStream((int) (contentLength > 0 ? contentLength : BUFFER_SIZE));
try {
while (!isCancelled() && ((buffer.transferFrom(in)) >= 0)) {
firePropertyChange(DOWNLOAD_PROGRESS, null, buffer.position());
if (isContentLengthKnown()) {
setProgress((int) ((buffer.position() * 100) / contentLength));
}
}
} catch (IOException e) {
// 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();
// download either finished or an exception is thrown
setDownloadState(DownloadState.DONE);
}
return buffer.getByteBuffer();
}
protected void setDownloadState(DownloadState state) {
this.state = state;
firePropertyChange(DOWNLOAD_STATE, null, state);
}
public DownloadState getDownloadState() {
return state;
}
public URL getUrl() {
return url;
}
public boolean isContentLengthKnown() {
return contentLength >= 0;
}
public long getContentLength() {
return contentLength;
}
public void setRequestHeaders(Map<String, String> requestHeaders) {
this.requestHeaders = new HashMap<String, String>(requestHeaders);
}
public void setPostParameters(Map<String, String> postParameters) {
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;
}
}