/** * DownloadJob.java * * Created on 25.08.2010 */ package org.mage.plugins.card.dl; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Proxy; import java.net.URL; import java.net.URLConnection; import javax.swing.BoundedRangeModel; import javax.swing.DefaultBoundedRangeModel; import org.mage.plugins.card.dl.beans.properties.Property; import org.mage.plugins.card.dl.lm.AbstractLaternaBean; import org.mage.plugins.card.utils.CardImageUtils; /** * The class DownloadJob. * * @version V0.0 25.08.2010 * @author Clemens Koza */ public class DownloadJob extends AbstractLaternaBean { public enum State { NEW, WORKING, FINISHED, ABORTED } private final String name; private final Source source; private final Destination destination; private final Property<State> state = properties.property("state", State.NEW); private final Property<String> message = properties.property("message"); private final Property<Exception> error = properties.property("error"); private final BoundedRangeModel progress = new DefaultBoundedRangeModel(); public DownloadJob(String name, Source source, Destination destination) { this.name = name; this.source = source; this.destination = destination; } /** * Sets the job's state. If the state is {@link State#ABORTED}, it instead * sets the error to "ABORTED" * * @param state */ public void setState(State state) { if (state == State.ABORTED) { setError("ABORTED"); } else { this.state.setValue(state); } } /** * Sets the job's state to {@link State#ABORTED} and the error message to * the given message. Logs a warning with the given message. * * @param message */ public void setError(String message) { setError(message, null); } /** * Sets the job's state to {@link State#ABORTED} and the error to the given * exception. Logs a warning with the given exception. * * @param error */ public void setError(Exception error) { setError(null, error); } /** * Sets the job's state to {@link State#ABORTED} and the error to the given * exception. Logs a warning with the given message and exception. * * @param message * @param error */ public void setError(String message, Exception error) { if (message == null) { message = "Download of " + name + "from " + source.toString() + " caused error: " + error.toString(); } // log.warn(message, error); log.warn(message); this.state.setValue(State.ABORTED); this.error.setValue(error); this.message.setValue(message); } /** * Sets the job's message. * * @param message */ public void setMessage(String message) { this.message.setValue(message); } public BoundedRangeModel getProgress() { return progress; } public State getState() { return state.getValue(); } public Exception getError() { return error.getValue(); } public String getMessage() { return message.getValue(); } public String getName() { return name; } public Source getSource() { return source; } public Destination getDestination() { return destination; } public static Source fromURL(final String url) { return fromURL(CardImageUtils.getProxyFromPreferences(), url); } public static Source fromURL(final URL url) { return fromURL(CardImageUtils.getProxyFromPreferences(), url); } public static Source fromURL(final Proxy proxy, final String url) { return new Source() { private URLConnection c; public URLConnection getConnection() throws IOException { if (c == null) { c = proxy == null ? new URL(url).openConnection() : new URL(url).openConnection(proxy); } return c; } @Override public InputStream open() throws IOException { return getConnection().getInputStream(); } @Override public int length() throws IOException { return getConnection().getContentLength(); } @Override public String toString() { return proxy != null ? proxy.type().toString() + ' ' : url; } }; } public static Source fromURL(final Proxy proxy, final URL url) { return new Source() { private URLConnection c; public URLConnection getConnection() throws IOException { if (c == null) { c = proxy == null ? url.openConnection() : url.openConnection(proxy); } return c; } @Override public InputStream open() throws IOException { return getConnection().getInputStream(); } @Override public int length() throws IOException { return getConnection().getContentLength(); } @Override public String toString() { return proxy != null ? proxy.type().toString() + ' ' : String.valueOf(url); } }; } public static Destination toFile(final String file) { return toFile(new File(file)); } public static Destination toFile(final File file) { return new Destination() { @Override public OutputStream open() throws IOException { File parent = file.getAbsoluteFile().getParentFile(); //Trying to create the directory before checking it exists makes it threadsafe if (!parent.mkdirs() && !parent.exists()) { throw new IOException(parent + ": directory could not be created"); } return new FileOutputStream(file); } @Override public boolean isValid() throws IOException { if (file.isFile()) { return file.length() > 0; } return false; } @Override public boolean exists() { return file.isFile(); } @Override public void delete() throws IOException { if (file.exists() && !file.delete()) { throw new IOException(file + " couldn't be deleted"); } } }; } public interface Source { InputStream open() throws IOException; int length() throws IOException; } public interface Destination { OutputStream open() throws IOException; boolean exists() throws IOException; boolean isValid() throws IOException; void delete() throws IOException; } }