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

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

findbugs - DB_DUPLICATE_SWITCH_CLAUSES + REC_CATCH_EXCEPTION + UC_USELESS_CONDITION + OS_OPEN_STREAM_EXCEPTION_PATH + ICAST_INTEGER_MULTIPLY_CAST_TO_LONG

  • Property svn:eol-style set to native
File size: 6.7 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.File;
8import java.io.FileOutputStream;
9import java.io.IOException;
10import java.io.InputStream;
11import java.io.OutputStream;
12import java.net.MalformedURLException;
13import java.net.URL;
14import java.nio.charset.StandardCharsets;
15import java.nio.file.Files;
16import java.nio.file.StandardCopyOption;
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.HttpClient;
25import org.openstreetmap.josm.tools.Utils;
26import org.xml.sax.SAXException;
27
28/**
29 * Asynchronous task for downloading and unpacking arbitrary file lists
30 * Shows progress bar when downloading
31 */
32public class DownloadFileTask extends PleaseWaitRunnable {
33 private final String address;
34 private final File file;
35 private final boolean mkdir;
36 private final boolean unpack;
37
38 /**
39 * Creates the download task
40 *
41 * @param parent the parent component relative to which the {@link PleaseWaitDialog} is displayed
42 * @param address the URL to download
43 * @param file The destination file
44 * @param mkdir {@code true} if the destination directory must be created, {@code false} otherwise
45 * @param unpack {@code true} if zip archives must be unpacked recursively, {@code false} otherwise
46 * @throws IllegalArgumentException if {@code parent} is null
47 */
48 public DownloadFileTask(Component parent, String address, File file, boolean mkdir, boolean unpack) {
49 super(parent, tr("Downloading file"), false);
50 this.address = address;
51 this.file = file;
52 this.mkdir = mkdir;
53 this.unpack = unpack;
54 }
55
56 private static class DownloadException extends Exception {
57 /**
58 * Constructs a new {@code DownloadException}.
59 * @param message the detail message. The detail message is saved for
60 * later retrieval by the {@link #getMessage()} method.
61 * @param cause the cause (which is saved for later retrieval by the
62 * {@link #getCause()} method). (A <tt>null</tt> value is
63 * permitted, and indicates that the cause is nonexistent or unknown.)
64 */
65 DownloadException(String message, Throwable cause) {
66 super(message, cause);
67 }
68 }
69
70 private boolean canceled;
71 private HttpClient downloadConnection;
72
73 private synchronized void closeConnectionIfNeeded() {
74 if (downloadConnection != null) {
75 downloadConnection.disconnect();
76 }
77 downloadConnection = null;
78 }
79
80 @Override
81 protected void cancel() {
82 this.canceled = true;
83 closeConnectionIfNeeded();
84 }
85
86 @Override
87 protected void finish() {
88 // Do nothing
89 }
90
91 /**
92 * Performs download.
93 * @throws DownloadException if the URL is invalid or if any I/O error occurs.
94 */
95 public void download() throws DownloadException {
96 try {
97 if (mkdir) {
98 File newDir = file.getParentFile();
99 if (!newDir.exists()) {
100 Utils.mkDirs(newDir);
101 }
102 }
103
104 URL url = new URL(address);
105 long size;
106 synchronized (this) {
107 downloadConnection = HttpClient.create(url).useCache(false);
108 downloadConnection.connect();
109 size = downloadConnection.getResponse().getContentLength();
110 }
111
112 progressMonitor.setTicksCount(100);
113 progressMonitor.subTask(tr("Downloading File {0}: {1} bytes...", file.getName(), size));
114
115 try (
116 InputStream in = downloadConnection.getResponse().getContent();
117 OutputStream out = new FileOutputStream(file)
118 ) {
119 byte[] buffer = new byte[32768];
120 int count = 0;
121 long p1 = 0;
122 long p2;
123 for (int read = in.read(buffer); read != -1; read = in.read(buffer)) {
124 out.write(buffer, 0, read);
125 count += read;
126 if (canceled) break;
127 p2 = 100L * count / size;
128 if (p2 != p1) {
129 progressMonitor.setTicks((int) p2);
130 p1 = p2;
131 }
132 }
133 }
134 if (!canceled) {
135 Main.info(tr("Download finished"));
136 if (unpack) {
137 Main.info(tr("Unpacking {0} into {1}", file.getAbsolutePath(), file.getParent()));
138 unzipFileRecursively(file, file.getParent());
139 Utils.deleteFile(file);
140 }
141 }
142 } catch (MalformedURLException e) {
143 String msg = tr("Cannot download file ''{0}''. Its download link ''{1}'' is not a valid URL. Skipping download.",
144 file.getName(), address);
145 Main.warn(msg);
146 throw new DownloadException(msg, e);
147 } catch (IOException e) {
148 if (canceled)
149 return;
150 throw new DownloadException(e.getMessage(), e);
151 } finally {
152 closeConnectionIfNeeded();
153 }
154 }
155
156 @Override
157 protected void realRun() throws SAXException, IOException {
158 if (canceled) return;
159 try {
160 download();
161 } catch (DownloadException e) {
162 Main.error(e);
163 }
164 }
165
166 /**
167 * Replies true if the task was canceled by the user
168 *
169 * @return {@code true} if the task was canceled by the user, {@code false} otherwise
170 */
171 public boolean isCanceled() {
172 return canceled;
173 }
174
175 /**
176 * Recursive unzipping function
177 * TODO: May be placed somewhere else - Tools.Utils?
178 * @param file zip file
179 * @param dir output directory
180 * @throws IOException if any I/O error occurs
181 */
182 public static void unzipFileRecursively(File file, String dir) throws IOException {
183 try (ZipFile zf = new ZipFile(file, StandardCharsets.UTF_8)) {
184 Enumeration<? extends ZipEntry> es = zf.entries();
185 while (es.hasMoreElements()) {
186 ZipEntry ze = es.nextElement();
187 File newFile = new File(dir, ze.getName());
188 if (ze.isDirectory()) {
189 Utils.mkDirs(newFile);
190 } else try (InputStream is = zf.getInputStream(ze)) {
191 Files.copy(is, newFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
192 }
193 }
194 }
195 }
196}
Note: See TracBrowser for help on using the repository browser.