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

Last change on this file since 9059 was 9059, checked in by Don-vip, 8 years ago

checkstyle

  • Property svn:eol-style set to native
File size: 6.9 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 /**
57 * Constructs a new {@code DownloadException}.
58 * @param message the detail message. The detail message is saved for
59 * later retrieval by the {@link #getMessage()} method.
60 * @param cause the cause (which is saved for later retrieval by the
61 * {@link #getCause()} method). (A <tt>null</tt> value is
62 * permitted, and indicates that the cause is nonexistent or unknown.)
63 */
64 DownloadException(String message, Throwable cause) {
65 super(message, cause);
66 }
67 }
68
69 private boolean canceled;
70 private HttpURLConnection downloadConnection;
71
72 private synchronized void closeConnectionIfNeeded() {
73 if (downloadConnection != null) {
74 downloadConnection.disconnect();
75 }
76 downloadConnection = null;
77 }
78
79 @Override
80 protected void cancel() {
81 this.canceled = true;
82 closeConnectionIfNeeded();
83 }
84
85 @Override
86 protected void finish() {}
87
88 /**
89 * Performs download.
90 * @throws DownloadException if the URL is invalid or if any I/O error occurs.
91 */
92 public void download() throws DownloadException {
93 try {
94 if (mkdir) {
95 File newDir = file.getParentFile();
96 if (!newDir.exists()) {
97 newDir.mkdirs();
98 }
99 }
100
101 URL url = new URL(address);
102 int size;
103 synchronized (this) {
104 downloadConnection = Utils.openHttpConnection(url);
105 downloadConnection.setRequestProperty("Cache-Control", "no-cache");
106 downloadConnection.connect();
107 size = downloadConnection.getContentLength();
108 }
109
110 progressMonitor.setTicksCount(100);
111 progressMonitor.subTask(tr("Downloading File {0}: {1} bytes...", file.getName(), size));
112
113 try (
114 InputStream in = downloadConnection.getInputStream();
115 OutputStream out = new FileOutputStream(file)
116 ) {
117 byte[] buffer = new byte[32768];
118 int count = 0;
119 int p1 = 0, p2 = 0;
120 for (int read = in.read(buffer); read != -1; read = in.read(buffer)) {
121 out.write(buffer, 0, read);
122 count += read;
123 if (canceled) break;
124 p2 = 100 * count / size;
125 if (p2 != p1) {
126 progressMonitor.setTicks(p2);
127 p1 = p2;
128 }
129 }
130 }
131 if (!canceled) {
132 Main.info(tr("Download finished"));
133 if (unpack) {
134 Main.info(tr("Unpacking {0} into {1}", file.getAbsolutePath(), file.getParent()));
135 unzipFileRecursively(file, file.getParent());
136 file.delete();
137 }
138 }
139 } catch (MalformedURLException e) {
140 String msg = tr("Cannot download file ''{0}''. Its download link ''{1}'' is not a valid URL. Skipping download.",
141 file.getName(), address);
142 Main.warn(msg);
143 throw new DownloadException(msg, e);
144 } catch (IOException e) {
145 if (canceled)
146 return;
147 throw new DownloadException(e.getMessage(), e);
148 } finally {
149 closeConnectionIfNeeded();
150 }
151 }
152
153 @Override
154 protected void realRun() throws SAXException, IOException {
155 if (canceled) return;
156 try {
157 download();
158 } catch (DownloadException e) {
159 Main.error(e);
160 }
161 }
162
163 /**
164 * Replies true if the task was canceled by the user
165 *
166 * @return {@code true} if the task was canceled by the user, {@code false} otherwise
167 */
168 public boolean isCanceled() {
169 return canceled;
170 }
171
172 /**
173 * Recursive unzipping function
174 * TODO: May be placed somewhere else - Tools.Utils?
175 * @param file zip file
176 * @param dir output directory
177 * @throws IOException if any I/O error occurs
178 */
179 public static void unzipFileRecursively(File file, String dir) throws IOException {
180 try (ZipFile zf = new ZipFile(file, StandardCharsets.UTF_8)) {
181 Enumeration<? extends ZipEntry> es = zf.entries();
182 while (es.hasMoreElements()) {
183 ZipEntry ze = es.nextElement();
184 File newFile = new File(dir, ze.getName());
185 if (ze.isDirectory()) {
186 newFile.mkdirs();
187 } else try (
188 InputStream is = zf.getInputStream(ze);
189 OutputStream os = new BufferedOutputStream(new FileOutputStream(newFile))
190 ) {
191 byte[] buffer = new byte[8192];
192 int read;
193 while ((read = is.read(buffer)) != -1) {
194 os.write(buffer, 0, read);
195 }
196 }
197 }
198 }
199 }
200}
Note: See TracBrowser for help on using the repository browser.