source: josm/trunk/src/org/openstreetmap/josm/gui/io/DownloadFileTask.java@ 7661

Last change on this file since 7661 was 7089, checked in by Don-vip, 10 years ago

see #8465 - Use of new Java 7 zip constructors allowing to specify a charset for entries names

File size: 6.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.io.BufferedOutputStream;
8import java.io.File;
9import java.io.FileOutputStream;
10import java.io.IOException;
11import java.io.InputStream;
12import java.io.OutputStream;
13import java.net.HttpURLConnection;
14import java.net.MalformedURLException;
15import java.net.URL;
16import java.nio.charset.StandardCharsets;
17import java.util.Enumeration;
18import java.util.zip.ZipEntry;
19import java.util.zip.ZipFile;
20
21import org.openstreetmap.josm.Main;
22import org.openstreetmap.josm.gui.PleaseWaitDialog;
23import org.openstreetmap.josm.gui.PleaseWaitRunnable;
24import org.openstreetmap.josm.tools.Utils;
25import org.xml.sax.SAXException;
26
27/**
28 * Asynchronous task for downloading and unpacking arbitrary file lists
29 * Shows progress bar when downloading
30 */
31public class DownloadFileTask extends PleaseWaitRunnable{
32 private final String address;
33 private final File file;
34 private final boolean mkdir;
35 private final boolean unpack;
36
37 /**
38 * Creates the download task
39 *
40 * @param parent the parent component relative to which the {@link PleaseWaitDialog} is displayed
41 * @param address the URL to download
42 * @param file The destination file
43 * @param mkdir {@code true} if the destination directory must be created, {@code false} otherwise
44 * @param unpack {@code true} if zip archives must be unpacked recursively, {@code false} otherwise
45 * @throws IllegalArgumentException if {@code parent} is null
46 */
47 public DownloadFileTask(Component parent, String address, File file, boolean mkdir, boolean unpack) {
48 super(parent, tr("Downloading file"), false);
49 this.address = address;
50 this.file = file;
51 this.mkdir = mkdir;
52 this.unpack = unpack;
53 }
54
55 private static class DownloadException extends Exception {
56 public DownloadException(String msg) {
57 super(msg);
58 }
59 }
60
61 private boolean canceled;
62 private HttpURLConnection downloadConnection;
63
64 private synchronized void closeConnectionIfNeeded() {
65 if (downloadConnection != null) {
66 downloadConnection.disconnect();
67 }
68 downloadConnection = null;
69 }
70
71
72 @Override
73 protected void cancel() {
74 this.canceled = true;
75 closeConnectionIfNeeded();
76 }
77
78 @Override
79 protected void finish() {}
80
81 /**
82 * Performs download.
83 * @throws DownloadException if the URL is invalid or if any I/O error occurs.
84 */
85 public void download() throws DownloadException {
86 try {
87 if (mkdir) {
88 File newDir = file.getParentFile();
89 if (!newDir.exists()) {
90 newDir.mkdirs();
91 }
92 }
93
94 URL url = new URL(address);
95 int size;
96 synchronized(this) {
97 downloadConnection = Utils.openHttpConnection(url);
98 downloadConnection.setRequestProperty("Cache-Control", "no-cache");
99 downloadConnection.connect();
100 size = downloadConnection.getContentLength();
101 }
102
103 progressMonitor.setTicksCount(100);
104 progressMonitor.subTask(tr("Downloading File {0}: {1} bytes...", file.getName(),size));
105
106 try (
107 InputStream in = downloadConnection.getInputStream();
108 OutputStream out = new FileOutputStream(file)
109 ) {
110 byte[] buffer = new byte[32768];
111 int count=0;
112 int p1=0, p2=0;
113 for (int read = in.read(buffer); read != -1; read = in.read(buffer)) {
114 out.write(buffer, 0, read);
115 count+=read;
116 if (canceled) break;
117 p2 = 100 * count / size;
118 if (p2!=p1) {
119 progressMonitor.setTicks(p2);
120 p1=p2;
121 }
122 }
123 }
124 if (!canceled) {
125 Main.info(tr("Download finished"));
126 if (unpack) {
127 Main.info(tr("Unpacking {0} into {1}", file.getAbsolutePath(), file.getParent()));
128 unzipFileRecursively(file, file.getParent());
129 file.delete();
130 }
131 }
132 } catch(MalformedURLException e) {
133 String msg = tr("Cannot download file ''{0}''. Its download link ''{1}'' is not a valid URL. Skipping download.", file.getName(), address);
134 Main.warn(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 }
143 }
144
145 @Override
146 protected void realRun() throws SAXException, IOException {
147 if (canceled) return;
148 try {
149 download();
150 } catch(DownloadException e) {
151 Main.error(e);
152 }
153 }
154
155 /**
156 * Replies true if the task was canceled by the user
157 *
158 * @return {@code true} if the task was canceled by the user, {@code false} otherwise
159 */
160 public boolean isCanceled() {
161 return canceled;
162 }
163
164 /**
165 * Recursive unzipping function
166 * TODO: May be placed somewhere else - Tools.Utils?
167 * @param file
168 * @param dir
169 * @throws IOException
170 */
171 public static void unzipFileRecursively(File file, String dir) throws IOException {
172 try (ZipFile zf = new ZipFile(file, StandardCharsets.UTF_8)) {
173 Enumeration<? extends ZipEntry> es = zf.entries();
174 while (es.hasMoreElements()) {
175 ZipEntry ze = es.nextElement();
176 File newFile = new File(dir, ze.getName());
177 if (ze.isDirectory()) {
178 newFile.mkdirs();
179 } else try (
180 InputStream is = zf.getInputStream(ze);
181 OutputStream os = new BufferedOutputStream(new FileOutputStream(newFile))
182 ) {
183 byte[] buffer = new byte[8192];
184 int read;
185 while ((read = is.read(buffer)) != -1) {
186 os.write(buffer, 0, read);
187 }
188 }
189 }
190 }
191 }
192}
Note: See TracBrowser for help on using the repository browser.