001 package org.openstreetmap.josm.gui.io;
002
003
004
005 // License: GPL. For details, see LICENSE file.
006
007 import static org.openstreetmap.josm.tools.I18n.tr;
008
009 import java.awt.Component;
010 import java.io.BufferedOutputStream;
011 import java.io.File;
012 import java.io.FileOutputStream;
013 import java.io.IOException;
014 import java.io.InputStream;
015 import java.io.OutputStream;
016 import java.net.HttpURLConnection;
017 import java.net.MalformedURLException;
018 import java.net.URL;
019
020 import java.net.URLConnection;
021 import java.util.Enumeration;
022
023 import java.util.zip.ZipEntry;
024 import java.util.zip.ZipFile;
025 import org.openstreetmap.josm.data.Version;
026 import org.openstreetmap.josm.gui.PleaseWaitDialog;
027 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
028 import org.openstreetmap.josm.tools.Utils;
029 import org.xml.sax.SAXException;
030
031
032 /**
033 * Asynchronous task for downloading andnd unpacking arbitrary file lists
034 * Shows progress bar when donloading
035 */
036 public class DownloadFileTask extends PleaseWaitRunnable{
037 private final String address;
038 private final File file;
039 private final boolean mkdir;
040 private final boolean unpack;
041
042 /**
043 * Creates the download task
044 *
045 * @param parent the parent component relative to which the {@link PleaseWaitDialog} is displayed
046 * @param title the title to display in the {@link PleaseWaitDialog}
047 * @throws IllegalArgumentException thrown if toUpdate is null
048 */
049 public DownloadFileTask(Component parent, String address, File file, boolean mkdir, boolean unpack) {
050 super(parent, tr("Downloading file"), false);
051 this.address = address;
052 this.file = file;
053 this.mkdir = mkdir;
054 this.unpack = unpack;
055
056 }
057
058 private static class DownloadException extends Exception {
059 public DownloadException(String msg) {
060 super(msg);
061 }
062 }
063
064 private boolean canceled;
065 private URLConnection downloadConnection;
066
067 private synchronized void closeConnectionIfNeeded() {
068 if (downloadConnection != null && downloadConnection instanceof HttpURLConnection) {
069 HttpURLConnection conn = ((HttpURLConnection) downloadConnection);
070 conn.disconnect();
071 }
072 downloadConnection = null;
073 }
074
075
076 @Override
077 protected void cancel() {
078 this.canceled = true;
079 closeConnectionIfNeeded();
080 }
081
082 @Override
083 protected void finish() {}
084
085 public void download() throws DownloadException {
086 OutputStream out = null;
087 InputStream in = null;
088 try {
089 if (mkdir) {
090 File newDir = file.getParentFile();
091 if (!newDir.exists()) {
092 newDir.mkdirs();
093 }
094 }
095
096 URL url = new URL(address);
097 int size;
098 synchronized(this) {
099 downloadConnection = url.openConnection();
100 downloadConnection.setRequestProperty("Cache-Control", "no-cache");
101 downloadConnection.setRequestProperty("User-Agent",Version.getInstance().getAgentString());
102 downloadConnection.setRequestProperty("Host", url.getHost());
103 downloadConnection.connect();
104 size = downloadConnection.getContentLength();
105 }
106
107 progressMonitor.setTicksCount(100);
108 progressMonitor.subTask(tr("Downloading File {0}: {1} bytes...", file.getName(),size));
109
110 in = downloadConnection.getInputStream();
111 out = new FileOutputStream(file);
112 byte[] buffer = new byte[32768];
113 int count=0;
114 int p1=0, p2=0;
115 for (int read = in.read(buffer); read != -1; read = in.read(buffer)) {
116 out.write(buffer, 0, read);
117 count+=read;
118 if (canceled) return;
119 p2 = 100 * count / size;
120 if (p2!=p1) {
121 progressMonitor.setTicks(p2);
122 p1=p2;
123 }
124 }
125 out.close();
126 System.out.println(tr("Download finished"));
127 if (unpack) {
128 System.out.println(tr("Unpacking {0} into {1}", file.getAbsolutePath(), file.getParent()));
129 unzipFileRecursively(file, file.getParent());
130 file.delete();
131 }
132 } catch(MalformedURLException e) {
133 String msg = tr("Warning: Cannot download file ''{0}''. Its download link ''{1}'' is not a valid URL. Skipping download.", file.getName(), address);
134 System.err.println(msg);
135 throw new DownloadException(msg);
136 } catch (IOException e) {
137 if (canceled)
138 return;
139 throw new DownloadException(e.getMessage());
140 } finally {
141 closeConnectionIfNeeded();
142 Utils.close(out);
143 }
144 }
145
146 @Override
147 protected void realRun() throws SAXException, IOException {
148 if (canceled) return;
149 try {
150 download();
151 } catch(DownloadException e) {
152 e.printStackTrace();
153 }
154 }
155
156 /**
157 * Replies true if the task was canceled by the user
158 *
159 * @return
160 */
161 public boolean isCanceled() {
162 return canceled;
163 }
164
165 /**
166 * Recursive unzipping function
167 * TODO: May be placed somewhere else - Tools.Utils?
168 * @param file
169 * @param dir
170 * @throws IOException
171 */
172 public static void unzipFileRecursively(File file, String dir) throws IOException {
173 OutputStream os = null;
174 InputStream is = null;
175 ZipFile zf = null;
176 try {
177 zf = new ZipFile(file);
178 Enumeration es = zf.entries();
179 ZipEntry ze;
180 while (es.hasMoreElements()) {
181 ze = (ZipEntry) es.nextElement();
182 File newFile = new File(dir, ze.getName());
183 if (ze.isDirectory()) {
184 newFile.mkdirs();
185 } else {
186 is = zf.getInputStream(ze);
187 os = new BufferedOutputStream(new FileOutputStream(newFile));
188 byte[] buffer = new byte[8192];
189 int read;
190 while ((read = is.read(buffer)) != -1) {
191 os.write(buffer, 0, read);
192 }
193 os.close();
194 is.close();
195 }
196 }
197 zf.close();
198 } finally {
199 if (zf!=null) zf.close();
200 }
201 }
202 }
203