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