From a394f25a9698e7449775d3bfbe15e24c680f28b3 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Wed, 16 Mar 2011 03:25:14 -0400 Subject: [PATCH] Single-thread swing works, great start on uniform downloading, still a problem illustrated in AlTest. --- src/org/moparscape/res/ALTest.java | 50 +++ .../res/AbstractDownloadListener.java | 103 ++++++ src/org/moparscape/res/DownloadListener.java | 5 +- src/org/moparscape/res/ResourceGrabber.java | 348 +++++++++--------- src/org/moparscape/res/impl/Downloader.java | 104 +----- ...HTTPDownloader.java => URLDownloader.java} | 13 +- 6 files changed, 354 insertions(+), 269 deletions(-) create mode 100644 src/org/moparscape/res/ALTest.java create mode 100644 src/org/moparscape/res/AbstractDownloadListener.java rename src/org/moparscape/res/impl/{HTTPDownloader.java => URLDownloader.java} (89%) diff --git a/src/org/moparscape/res/ALTest.java b/src/org/moparscape/res/ALTest.java new file mode 100644 index 0000000..a62e337 --- /dev/null +++ b/src/org/moparscape/res/ALTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 moparisthebest + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Official forums are http://www.moparscape.org/smf/ + * Email me at admin@moparisthebest.com , I read it but don't usually respond. + */ + +package org.moparscape.res; + +import java.util.ArrayList; +import java.util.List; + +public class ALTest { + + public static void main(String[] args) throws Exception { + final List downloadItems = new ArrayList(5); + int uid = 0; + downloadItems.add(new ALTest(uid)); + System.out.println("downloads size: "+downloadItems.size()); + System.out.println("downloads contains(uid): "+downloadItems.contains(uid)); + System.out.println("downloads contains(Integer(uid)): "+downloadItems.contains(new Integer(uid))); + System.out.println("downloads contains(ALTest): "+downloadItems.contains(new ALTest(uid))); + } + + private int uid; + + public ALTest(int uid) { + this.uid = uid; + } + + @Override + public boolean equals(Object other) { + System.out.println("ALTest equals: " + other); + return ((other instanceof ALTest) && ((ALTest) other).uid == this.uid) || + ((other instanceof Integer) && other.equals(this.uid)); + } +} diff --git a/src/org/moparscape/res/AbstractDownloadListener.java b/src/org/moparscape/res/AbstractDownloadListener.java new file mode 100644 index 0000000..56edcf1 --- /dev/null +++ b/src/org/moparscape/res/AbstractDownloadListener.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2011 moparisthebest + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Official forums are http://www.moparscape.org/smf/ + * Email me at admin@moparisthebest.com , I read it but don't usually respond. + */ + +package org.moparscape.res; + +/** + * Created by IntelliJ IDEA. + * User: mopar + * Date: 3/15/11 + * Time: 9:36 PM + * To change this template use File | Settings | File Templates. + */ +public abstract class AbstractDownloadListener implements DownloadListener{ + + public enum Status { + NOT_STARTED, RUNNING, STARTING, FINISHED, EXTRACTING, STOPPED, ERROR + } + + private Status status = Status.NOT_STARTED; + + protected long length; + protected String info; + + protected int progress = 0; + protected String title = null; + protected String extraInfo = null; + + public Status getStatus(){ + return status; + } + + public void setRunning() { + status = Status.RUNNING; + } + + public void setStopped() { + status = Status.STOPPED; + } + + public void setProgress(int progress) { + this.progress = progress; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setExtraInfo(String extraInfo) { + this.extraInfo = extraInfo; + } + + public void starting(String title, long length, String info) { + status = Status.STARTING; + this.title = title; + this.length = length; + this.info = info; + } + + public void extracting(String title, long length, String info) { + status = Status.EXTRACTING; + this.title = title; + this.length = length; + this.info = info; + } + + public void finished(String savePath, String... filesDownloaded) { + // if it's an error, we want to ignore stopped + if(status == Status.ERROR) + return; + status = Status.FINISHED; + } + + public void stopped() { + // if it's an error, we want to ignore stopped + if(status == Status.ERROR) + return; + status = Status.STOPPED; + } + + public void error(String msg, Exception e) { + status = Status.ERROR; + this.extraInfo = msg; + progress = 0; + //e.printStackTrace(); + } +} diff --git a/src/org/moparscape/res/DownloadListener.java b/src/org/moparscape/res/DownloadListener.java index 5c305cf..23bd612 100644 --- a/src/org/moparscape/res/DownloadListener.java +++ b/src/org/moparscape/res/DownloadListener.java @@ -29,12 +29,13 @@ package org.moparscape.res; */ public interface DownloadListener { - public void incrementProgress(int inc); + public void setProgress(int progress); public void setTitle(String title); - public void setInfo(String info); + public void setExtraInfo(String extraInfo); public void starting(String title, long length, String info); public void extracting(String title, long length, String info); public void finished(String savePath, String... filesDownloaded); public void stopped(); public void error(String msg, Exception e); + } diff --git a/src/org/moparscape/res/ResourceGrabber.java b/src/org/moparscape/res/ResourceGrabber.java index 8015468..99dc91a 100644 --- a/src/org/moparscape/res/ResourceGrabber.java +++ b/src/org/moparscape/res/ResourceGrabber.java @@ -21,13 +21,14 @@ package org.moparscape.res; import org.moparscape.res.impl.Downloader; -import org.moparscape.res.impl.HTTPDownloader; +import org.moparscape.res.impl.URLDownloader; import javax.swing.*; import java.awt.*; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.net.MalformedURLException; +import java.util.ArrayList; /** * This class is meant to retrieve resources from a variety of URLs, including all supported by Java in addition to @@ -50,9 +51,15 @@ public class ResourceGrabber { private static final String javaClientLocation = "/tmp/"; private static final String javaClientURL = "http://www.moparscape.org/libs/"; + private final Downloader[] downloaders = new Downloader[]{new URLDownloader()}; + + private static final int delay = 500; //milliseconds + private static final int errorTicks = 20; // errorTicks * delay is how long errors will stay onscreen private JFrame frame = null; - Set downloadItems = Collections.synchronizedSet(new HashSet(5)); + private javax.swing.Timer timer = null; + + private final ArrayList downloadItems = new ArrayList(5); // this is only meant to be accessed by getUID(), which is synchronized private int currentUID = 0; @@ -68,16 +75,42 @@ public class ResourceGrabber { System.out.println("checksum: " + Downloader.checksum("/home/mopar/tests/extest", null, new String[]{"client_test.linux.x86", "client.zip.gz"}, false)); */ //System.out.println("filename: " + new URL("http://moparisthebest.com/bob/tom/cache.zip").getFile()); + ALTest.main(args);System.exit(0); ResourceGrabber rg = new ResourceGrabber(); + System.out.println("before downloads..."); //rg.download("http://www.moparisthebest.com/downloads/cedegaSRC.tar.gz", "/home/mopar/tests/extest", true); //rg.download("http://mirror01.th.ifl.net/releases//maverick/ubuntu-10.10-desktop-i386.iso", "/home/mopar/tests/extest", false); - //Thread.sleep(2000); - rg.download("https://www.moparscape.org/libs/client.zip.gz", "/home/mopar/tests/extest", true); + //Thread.sleep(30000); + int clientZipUID = rg.download("https://www.moparscape.org/libs/client.zip.gz", "/home/mopar/tests/extest", true); + rg.wait(clientZipUID); + System.out.println("after downloads..."); } - private int download(String url, String savePath, boolean extract) { + public void wait(int uid) throws InterruptedException { + synchronized (downloadItems) { + System.out.println("wait downloads size: "+downloadItems.size()); + System.out.println("wait downloads contains(uid): "+downloadItems.contains(new Integer(uid))); + System.out.println("wait downloads contains(DlListener): "+downloadItems.contains(new DlListener(uid, false))); + while(downloadItems.contains(uid)) + Thread.sleep(delay); + } + } + + public int download(String url, String savePath, boolean extract) throws MalformedURLException { + Downloader dlr = getSupportedDownloader(url); + int uid = getUID(); - new HTTPDownloader().download(url, savePath, new DlListener(uid, extract)); + DlListener dll = new DlListener(uid, extract); + dlr.download(url, savePath, dll); + synchronized (downloadItems) { + downloadItems.add(dll); + } + if (timer == null) { + timer = new Timer(delay, new GUIUpdater()); + timer.start(); + } else if (!timer.isRunning()) { + timer.start(); + } return uid; } @@ -85,29 +118,52 @@ public class ResourceGrabber { return this.currentUID++; } - private synchronized void checkFrame(final JPanel jp, int uid) { - // not allowed - if (jp == null) - return; + private Downloader getSupportedDownloader(String url) throws MalformedURLException{ + for(Downloader dl : this.downloaders) + if(dl.supportsURL(url)) + return dl; + throw new MalformedURLException("Unsupported URL: "+url); + } - boolean add = !downloadItems.contains(uid); - //System.out.println((add ? "adding" : "removing") + ": " + uid); - if (add) - downloadItems.add(uid); - else - downloadItems.remove(uid); - // handle UIDs - // if we are trying to add a panel and the frame is null - if (add && frame == null) { - try { - SwingUtilities.invokeAndWait( - new Runnable() { - public void run() { + private class GUIUpdater implements ActionListener { + + public void actionPerformed(ActionEvent e) { + synchronized (downloadItems) { + for (final Object o : downloadItems) { + final DlListener dll = (DlListener)o; + //System.out.println("uid : " + dll.uid); + //System.out.println("status: " + dll.getStatus().toString()); + switch (dll.getStatus()) { + case NOT_STARTED: + break; + case RUNNING: + // if its already running, we need to just update it + if (dll.title != null) + dll.dip.setTitle(dll.title); + //if (dll.progress != 0) + // dll.dip.setProgress(dll.progress); + if (dll.extraInfo != null) + dll.dip.setInfo(dll.extraInfo); + // set them all not to update + dll.title = null; + dll.extraInfo = null; + break; + // then we need to start it up + case STARTING: + dll.setRunning(); + // this means we are RE-starting for some reason, so it's already added to the frame + if (dll.dip != null) { + dll.dip.reset(dll.title, dll.length, dll.info); + break; + } + // otherwise, start fresh + dll.dip = new DownloadItemPanel(dll.title, dll.length, dll.info); + if (frame == null) { frame = new JFrame("Resource Grabber"); frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS)); - frame.getContentPane().add(jp); + frame.getContentPane().add(dll.dip); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.setResizable(false); @@ -116,56 +172,56 @@ public class ResourceGrabber { // when called after pack() frame.setLocationRelativeTo(null); frame.setVisible(true); - + // or if we are trying to add a panel and the frame is already set up + } else { + frame.getContentPane().add(dll.dip); } - } - ); - } catch (Exception e) { - e.printStackTrace(); - } - // or if we are trying to add a panel and the frame is already set up - } else if (add) { - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - if (frame != null) { - frame.getContentPane().add(jp); - frame.pack(); - } - } + break; + case FINISHED: + break; + case EXTRACTING: + dll.setRunning(); + dll.dip.reset(dll.title, dll.length, dll.info); + break; + case STOPPED: + // since we are already in the event thread, this executes right after this exits + // or at least never at the same time, which is all we need to worry about. + SwingUtilities.invokeLater( + new Runnable() { + public void run() { + synchronized (downloadItems) { + downloadItems.remove(dll); + if (frame == null) + return; + frame.getContentPane().remove(dll.dip); + if (downloadItems.isEmpty()) { + frame.dispose(); + frame = null; + timer.stop(); + } + } + } + }); + break; + case ERROR: + //System.out.println("Error uid: " + dll.uid); + if (dll.extraInfo != null) + dll.dip.error(dll.extraInfo); + dll.extraInfo = null; + // timeout error, once we reach errorTicks ticks change it to stopped + //System.out.println("error tick: " + dll.progress); + if (dll.progress++ > errorTicks) + dll.setStopped(); } - ); - // else we are not trying to remove a panel, and destroy the frame if there are no more items - } else if (frame != null && downloadItems.isEmpty()) { - try { - SwingUtilities.invokeAndWait( - new Runnable() { - public void run() { - frame.dispose(); - frame = null; - - } - } - ); - } catch (Exception e) { - e.printStackTrace(); + } } - // or just remove a single panel - } else if (frame != null) { - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - if (frame != null) { - frame.getContentPane().remove(jp); - frame.pack(); - } - } - } - ); + if (frame != null) + frame.pack(); } + } - private class DlListener implements DownloadListener { + private class DlListener extends AbstractDownloadListener { int uid; boolean extract; @@ -176,59 +232,31 @@ public class ResourceGrabber { this.extract = extract; } - public void incrementProgress(int inc) { - //DownloadItemPanel dip = downloadItems.get(uid); + @Override + public void setProgress(int progress) { + //super.setProgress(progress); + // it is safe to update the progress outside of the event thread, and it looks cleaner, so do it if (dip != null) - dip.addProgress(inc); - } - - public void setTitle(String title) { - //DownloadItemPanel dip = downloadItems.get(uid); - if (dip != null) - dip.setTitle(title); - } - - public void setInfo(String info) { - //DownloadItemPanel dip = downloadItems.get(uid); - if (dip != null) - dip.setInfo(info); - } - - public void starting(String title, long length, String info) { - dip = new DownloadItemPanel(title, length, info); - checkFrame(dip, uid); - } - - public void extracting(final String title, final long length, final String info) { - //DownloadItemPanel dip = downloadItems.get(uid); - if (dip != null) { - dip.reset(title, length, info); - //dip.reset(title, length, info); - /* - frame.getContentPane().remove(dip); - dip = new DownloadItemPanel(title, length, info); - frame.getContentPane().add(dip); - */ - } + dip.setProgress(progress); } public void finished(String savePath, String... filesDownloaded) { if (extract) for (String file : filesDownloaded) Downloader.extractFile(file, savePath, this); + super.finished(savePath, filesDownloaded); } - public void stopped() { - //System.out.println("Stopped uid: " + uid); - //DownloadItemPanel dip = downloadItems.get(uid); - checkFrame(dip, uid); - } - - public void error(String msg, Exception e) { - //To change body of implemented methods use File | Settings | File Templates. - System.out.println("Error uid: " + uid); - System.out.println(msg); - e.printStackTrace(); + /** + * This needs to be hacked to be equal to either another DlListener, or an integer uid value + * @param other + * @return + */ + @Override + public boolean equals(Object other) { + System.out.println("DlListener equals: "+other); + return ((other instanceof DlListener) && ((DlListener) other).uid == this.uid) || + ((other instanceof Integer) && other.equals(this.uid)); } } @@ -248,90 +276,50 @@ public class ResourceGrabber { this.add(this.titleLabel = new JLabel(sep + title + end), BorderLayout.NORTH); this.add(this.infoLabel = new JLabel(origInfo = info), BorderLayout.SOUTH); - progressBar = new JProgressBar(0, (int) length); - progressBar.setValue(0); - progressBar.setStringPainted(true); + progressBar = new JProgressBar(0, 100); + this.setLength(length); this.add(progressBar, BorderLayout.CENTER); } public void reset(final String title, final long length, final String info) { - try { - SwingUtilities.invokeAndWait( - new Runnable() { - public void run() { - titleLabel.setText(sep + title + end); - infoLabel.setText(origInfo = info); - progressBar.setValue(0); - progressBar.setMaximum((int) length); - if (frame != null) - frame.pack(); - } - } - ); - } catch (Exception e) { - e.printStackTrace(); - } + if (title != null) + titleLabel.setText(sep + title + end); + if (info != null) + infoLabel.setText(origInfo = info); + + this.setLength(length); + } public void error(final String error) { - try { - SwingUtilities.invokeAndWait( - new Runnable() { - public void run() { - infoLabel.setText("" + origInfo + "
Error: " + error + end); - progressBar.setIndeterminate(true); - if (frame != null) - frame.pack(); - } - } - ); - } catch (Exception e) { - e.printStackTrace(); - } + this.setInfo("Error: " + error); + this.setLength(-1); } - public void addProgress(int progress) { - this.setProgress(progressBar.getValue() + progress); + private void setLength(long length) { + if (length != -1) { + progressBar.setValue(0); + progressBar.setMaximum((int) length); + progressBar.setIndeterminate(false); + progressBar.setStringPainted(true); + } else { + progressBar.setIndeterminate(true); + progressBar.setStringPainted(false); + } + } public void setProgress(final int progress) { - try { - SwingUtilities.invokeAndWait( - new Runnable() { - public void run() { - progressBar.setValue(progress); - } - } - ); - } catch (Exception e) { - e.printStackTrace(); - } + progressBar.setValue(progress); } public void setTitle(final String title) { - setLabel(this.titleLabel, frame, title); + this.titleLabel.setText(sep + title + end); } public void setInfo(final String info) { - setLabel(this.infoLabel, frame, "" + origInfo + "
" + info + end); + this.infoLabel.setText("" + origInfo + "
" + info + end); } } - - private static void setLabel(final JLabel jl, final JFrame jf, final String content) { - try { - SwingUtilities.invokeAndWait( - new Runnable() { - public void run() { - jl.setText(content); - if (jf != null) - jf.pack(); - } - } - ); - } catch (Exception e) { - e.printStackTrace(); - } - } - } diff --git a/src/org/moparscape/res/impl/Downloader.java b/src/org/moparscape/res/impl/Downloader.java index 1dd728e..05d0ba0 100644 --- a/src/org/moparscape/res/impl/Downloader.java +++ b/src/org/moparscape/res/impl/Downloader.java @@ -39,7 +39,13 @@ public abstract class Downloader { public static final int bufferSize = 512; + // enforce empty default public constructor + public Downloader(){ + + } + public abstract void download(String url, String savePath, DownloadListener callback); + public abstract boolean supportsURL(String url); /** * Downloads resource specified by url to savePath. @@ -105,16 +111,19 @@ public abstract class Downloader { is = new ProgressInputStream(is, callback); } + //if(true)throw new RuntimeException("woohoo! fake exceptions!"); + if (fileName.endsWith(".zip.gz")) is = new GZIPInputStream(is); else if (fileName.endsWith(".gz")) { // strip .gz off the end fileName = file.getName(); fileName = fileName.substring(0, fileName.length() - 3); + // exception for java_client.exe if (badExtension(fileName)) return; if (callback != null) - callback.setInfo("Extracting File: " + fileName); + callback.setExtraInfo("Extracting File: " + fileName); writeStream(new GZIPInputStream(is), new FileOutputStream(savePath + fileName)); return; } else if (fileName.endsWith(".zip")) { @@ -133,19 +142,19 @@ public abstract class Downloader { File folder = new File(savePath + name); deleteDirectory(folder); if (callback != null) - callback.setInfo("Creating Directory: " + name); + callback.setExtraInfo("Creating Directory: " + name); folder.mkdir(); } else {// If the entry isn't a directory, then it should be a file? if (badExtension(entry.getName())) continue; if (callback != null) - callback.setInfo("Extracting File: " + name); + callback.setExtraInfo("Extracting File: " + name); writeStream(zin, new FileOutputStream(savePath + name)); } //try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } zin.close(); - } catch (IOException e) { + } catch (Exception e) { if (callback != null) callback.error("Extraction of this file failed: " + file.getAbsolutePath(), e); } @@ -218,7 +227,7 @@ public abstract class Downloader { protected static boolean badExtension(String file) { String[] badExts = new String[]{".exe", ".bat", ".cmd", ".com", ".sh", ".bash"}; for (String badExt : badExts) - if (file.endsWith(badExt)) + if (file.endsWith(badExt) && !file.endsWith("java_client.exe")) return true; return false; } @@ -233,87 +242,10 @@ public abstract class Downloader { return url.startsWith("magnet:") || url.endsWith(".torrent"); } - protected static class ProgressFrame { - - private enum Type { - HTTP, TORRENT, EXTRACT - } - - JFrame dlFrame = null; - JProgressBar progressBar = null; - JLabel bottom = null; - - String bottomLabel = null; - - public ProgressFrame(String url, String savePath, long length, Type pType) { - String title, topLabel; - switch (pType) { - case HTTP: - title = "HTTP Download Progress"; - topLabel = "Downloading " + url; - bottomLabel = "to " + savePath + "..."; - break; - - case TORRENT: - title = "Torrent Download Progress"; - topLabel = "Downloading " + url; - bottomLabel = "to " + savePath + "..."; - break; - - case EXTRACT: - title = "Extraction Progress"; - topLabel = "Extracting " + url; - bottomLabel = "to " + savePath + "..."; - break; - - default: - throw new RuntimeException("Unknown Progress Type."); - } - - dlFrame = new JFrame(title); - dlFrame.setLayout(new BorderLayout()); - progressBar = new JProgressBar(0, (int) length); - progressBar.setValue(0); - progressBar.setStringPainted(true); - dlFrame.getContentPane().add(new JLabel(topLabel), BorderLayout.NORTH); - dlFrame.getContentPane().add(progressBar, BorderLayout.CENTER); - dlFrame.getContentPane().add(bottom = new JLabel(bottomLabel), BorderLayout.SOUTH); - - dlFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - dlFrame.setResizable(false); - dlFrame.pack(); - // sets the frame to appear in the middle of the screen - // when called after pack() - dlFrame.setLocationRelativeTo(null); - dlFrame.setVisible(true); - } - - public ProgressFrame(String url, String savePath, long length) { - this(url, savePath, length, Type.HTTP); - } - - public void dispose() { - dlFrame.dispose(); - } - - public void addProgress(int progress) { - progressBar.setValue(progressBar.getValue() + progress); - } - - public void setProgress(int progress) { - progressBar.setValue(progress); - } - - public void setText(String text) { - bottom.setText("" + bottomLabel + "
" + text + ""); - dlFrame.pack(); - } - - } - protected static class ProgressInputStream extends FilterInputStream { private DownloadListener dl = null; + int progress = 0; protected ProgressInputStream(InputStream in, DownloadListener dl) { super(in); @@ -323,21 +255,21 @@ public abstract class Downloader { @Override public int read() throws IOException { int byteValue = super.read(); - if (byteValue != -1) dl.incrementProgress(1); + if (byteValue != -1) dl.setProgress(++progress); return byteValue; } @Override public int read(byte[] b) throws IOException { int bytesRead = super.read(b); - if (bytesRead != -1) dl.incrementProgress(bytesRead); + if (bytesRead != -1) dl.setProgress(progress += bytesRead); return bytesRead; } @Override public int read(byte[] b, int off, int len) throws IOException { int bytesRead = super.read(b, off, len); - if (bytesRead != -1) dl.incrementProgress(bytesRead); + if (bytesRead != -1) dl.setProgress(progress += bytesRead); return bytesRead; } diff --git a/src/org/moparscape/res/impl/HTTPDownloader.java b/src/org/moparscape/res/impl/URLDownloader.java similarity index 89% rename from src/org/moparscape/res/impl/HTTPDownloader.java rename to src/org/moparscape/res/impl/URLDownloader.java index da4dc62..cd0e8ec 100644 --- a/src/org/moparscape/res/impl/HTTPDownloader.java +++ b/src/org/moparscape/res/impl/URLDownloader.java @@ -27,6 +27,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; +import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; @@ -37,7 +38,7 @@ import java.net.URLConnection; * Time: 3:20 PM * To change this template use File | Settings | File Templates. */ -public class HTTPDownloader extends Downloader { +public class URLDownloader extends Downloader { public void download(final String url, final String savePath, final DownloadListener callback) { new Thread() { @@ -79,4 +80,14 @@ public class HTTPDownloader extends Downloader { } }.start(); } + + public boolean supportsURL(String url) { + // if it's a supported URL, return true + try { + new URL(url); + return true; + } catch (MalformedURLException e) { + return false; + } + } }