source: josm/trunk/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java@ 5508

Last change on this file since 5508 was 5266, checked in by bastiK, 12 years ago

fixed majority of javadoc warnings by replacing "{@see" by "{@link"

  • Property svn:eol-style set to native
File size: 14.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.plugins;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.BufferedReader;
7import java.io.ByteArrayInputStream;
8import java.io.File;
9import java.io.FileOutputStream;
10import java.io.FilenameFilter;
11import java.io.IOException;
12import java.io.InputStream;
13import java.io.InputStreamReader;
14import java.io.OutputStream;
15import java.io.OutputStreamWriter;
16import java.io.PrintWriter;
17import java.io.UnsupportedEncodingException;
18import java.net.HttpURLConnection;
19import java.net.MalformedURLException;
20import java.net.URL;
21import java.util.ArrayList;
22import java.util.Arrays;
23import java.util.Collection;
24import java.util.Collections;
25import java.util.HashSet;
26import java.util.LinkedList;
27import java.util.List;
28
29import org.openstreetmap.josm.Main;
30import org.openstreetmap.josm.data.Version;
31import org.openstreetmap.josm.gui.PleaseWaitRunnable;
32import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
33import org.openstreetmap.josm.gui.progress.ProgressMonitor;
34import org.openstreetmap.josm.io.OsmTransferException;
35import org.openstreetmap.josm.tools.ImageProvider;
36import org.openstreetmap.josm.tools.Utils;
37import org.xml.sax.SAXException;
38
39/**
40 * An asynchronous task for downloading plugin lists from the configured plugin download
41 * sites.
42 *
43 */
44public class ReadRemotePluginInformationTask extends PleaseWaitRunnable{
45
46 private Collection<String> sites;
47 private boolean canceled;
48 private HttpURLConnection connection;
49 private List<PluginInformation> availablePlugins;
50
51 protected enum CacheType {PLUGIN_LIST, ICON_LIST}
52
53 protected void init(Collection<String> sites){
54 this.sites = sites;
55 if (sites == null) {
56 this.sites = Collections.emptySet();
57 }
58 availablePlugins = new LinkedList<PluginInformation>();
59
60 }
61 /**
62 * Creates the task
63 *
64 * @param sites the collection of download sites. Defaults to the empty collection if null.
65 */
66 public ReadRemotePluginInformationTask(Collection<String> sites) {
67 super(tr("Download plugin list..."), false /* don't ignore exceptions */);
68 init(sites);
69 }
70
71 /**
72 * Creates the task
73 *
74 * @param monitor the progress monitor. Defaults to {@link NullProgressMonitor#INSTANCE} if null
75 * @param sites the collection of download sites. Defaults to the empty collection if null.
76 */
77 public ReadRemotePluginInformationTask(ProgressMonitor monitor, Collection<String> sites) {
78 super(tr("Download plugin list..."), monitor == null ? NullProgressMonitor.INSTANCE: monitor, false /* don't ignore exceptions */);
79 init(sites);
80 }
81
82
83 @Override
84 protected void cancel() {
85 canceled = true;
86 synchronized(this) {
87 if (connection != null) {
88 connection.disconnect();
89 }
90 }
91 }
92
93 @Override
94 protected void finish() {}
95
96 /**
97 * Creates the file name for the cached plugin list and the icon cache
98 * file.
99 *
100 * @param site the name of the site
101 * @param type icon cache or plugin list cache
102 * @return the file name for the cache file
103 */
104 protected File createSiteCacheFile(File pluginDir, String site, CacheType type) {
105 String name;
106 try {
107 site = site.replaceAll("%<(.*)>", "");
108 URL url = new URL(site);
109 StringBuilder sb = new StringBuilder();
110 sb.append("site-");
111 sb.append(url.getHost()).append("-");
112 if (url.getPort() != -1) {
113 sb.append(url.getPort()).append("-");
114 }
115 String path = url.getPath();
116 for (int i =0;i<path.length(); i++) {
117 char c = path.charAt(i);
118 if (Character.isLetterOrDigit(c)) {
119 sb.append(c);
120 } else {
121 sb.append("_");
122 }
123 }
124 switch (type) {
125 case PLUGIN_LIST:
126 sb.append(".txt");
127 break;
128 case ICON_LIST:
129 sb.append("-icons.zip");
130 break;
131 }
132 name = sb.toString();
133 } catch(MalformedURLException e) {
134 name = "site-unknown.txt";
135 }
136 return new File(pluginDir, name);
137 }
138
139 /**
140 * Downloads the list from a remote location
141 *
142 * @param site the site URL
143 * @param monitor a progress monitor
144 * @return the downloaded list
145 */
146 protected String downloadPluginList(String site, ProgressMonitor monitor) {
147 BufferedReader in = null;
148 StringBuilder sb = new StringBuilder();
149 try {
150 /* replace %<x> with empty string or x=plugins (separated with comma) */
151 String pl = Utils.join(",", Main.pref.getCollection("plugins"));
152 String printsite = site.replaceAll("%<(.*)>", "");
153 if(pl != null && pl.length() != 0) {
154 site = site.replaceAll("%<(.*)>", "$1"+pl);
155 } else {
156 site = printsite;
157 }
158
159 monitor.beginTask("");
160 monitor.indeterminateSubTask(tr("Downloading plugin list from ''{0}''", printsite));
161
162 URL url = new URL(site);
163 synchronized(this) {
164 connection = (HttpURLConnection)url.openConnection();
165 connection.setRequestProperty("Cache-Control", "no-cache");
166 connection.setRequestProperty("User-Agent",Version.getInstance().getAgentString());
167 connection.setRequestProperty("Host", url.getHost());
168 connection.setRequestProperty("Accept-Charset", "utf-8");
169 }
170 in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
171 String line;
172 while((line = in.readLine()) != null) {
173 sb.append(line).append("\n");
174 }
175 return sb.toString();
176 } catch(MalformedURLException e) {
177 if (canceled) return null;
178 e.printStackTrace();
179 return null;
180 } catch(IOException e) {
181 if (canceled) return null;
182 e.printStackTrace();
183 return null;
184 } finally {
185 synchronized(this) {
186 if (connection != null) {
187 connection.disconnect();
188 }
189 connection = null;
190 }
191 Utils.close(in);
192 monitor.finishTask();
193 }
194 }
195
196 /**
197 * Downloads the icon archive from a remote location
198 *
199 * @param site the site URL
200 * @param monitor a progress monitor
201 */
202 protected void downloadPluginIcons(String site, File destFile, ProgressMonitor monitor) {
203 InputStream in = null;
204 OutputStream out = null;
205 try {
206 site = site.replaceAll("%<(.*)>", "");
207
208 monitor.beginTask("");
209 monitor.indeterminateSubTask(tr("Downloading plugin list from ''{0}''", site));
210
211 URL url = new URL(site);
212 synchronized(this) {
213 connection = (HttpURLConnection)url.openConnection();
214 connection.setRequestProperty("Cache-Control", "no-cache");
215 connection.setRequestProperty("User-Agent",Version.getInstance().getAgentString());
216 connection.setRequestProperty("Host", url.getHost());
217 }
218 in = connection.getInputStream();
219 out = new FileOutputStream(destFile);
220 byte[] buffer = new byte[8192];
221 for (int read = in.read(buffer); read != -1; read = in.read(buffer)) {
222 out.write(buffer, 0, read);
223 }
224 out.close();
225 in.close();
226 } catch(MalformedURLException e) {
227 if (canceled) return;
228 e.printStackTrace();
229 return;
230 } catch(IOException e) {
231 if (canceled) return;
232 e.printStackTrace();
233 return;
234 } finally {
235 synchronized(this) {
236 if (connection != null) {
237 connection.disconnect();
238 }
239 connection = null;
240 }
241 Utils.close(in);
242 monitor.finishTask();
243 }
244 for (PluginInformation pi : availablePlugins) {
245 if (pi.icon == null && pi.iconPath != null) {
246 pi.icon = new ImageProvider(pi.name+".jar/"+pi.iconPath)
247 .setArchive(destFile)
248 .setMaxWidth(24)
249 .setMaxHeight(24)
250 .setOptional(true).get();
251 }
252 }
253 }
254
255 /**
256 * Writes the list of plugins to a cache file
257 *
258 * @param site the site from where the list was downloaded
259 * @param list the downloaded list
260 */
261 protected void cachePluginList(String site, String list) {
262 PrintWriter writer = null;
263 try {
264 File pluginDir = Main.pref.getPluginsDirectory();
265 if (!pluginDir.exists()) {
266 if (! pluginDir.mkdirs()) {
267 System.err.println(tr("Warning: failed to create plugin directory ''{0}''. Cannot cache plugin list from plugin site ''{1}''.", pluginDir.toString(), site));
268 }
269 }
270 File cacheFile = createSiteCacheFile(pluginDir, site, CacheType.PLUGIN_LIST);
271 getProgressMonitor().subTask(tr("Writing plugin list to local cache ''{0}''", cacheFile.toString()));
272 writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(cacheFile), "utf-8"));
273 writer.write(list);
274 } catch(IOException e) {
275 // just failed to write the cache file. No big deal, but log the exception anyway
276 e.printStackTrace();
277 } finally {
278 if (writer != null) {
279 writer.flush();
280 writer.close();
281 }
282 }
283 }
284
285 /**
286 * Filter information about deprecated plugins from the list of downloaded
287 * plugins
288 *
289 * @param plugins the plugin informations
290 * @return the plugin informations, without deprecated plugins
291 */
292 protected List<PluginInformation> filterDeprecatedPlugins(List<PluginInformation> plugins) {
293 List<PluginInformation> ret = new ArrayList<PluginInformation>(plugins.size());
294 HashSet<String> deprecatedPluginNames = new HashSet<String>();
295 for (PluginHandler.DeprecatedPlugin p : PluginHandler.DEPRECATED_PLUGINS) {
296 deprecatedPluginNames.add(p.name);
297 }
298 for (PluginInformation plugin: plugins) {
299 if (deprecatedPluginNames.contains(plugin.name)) {
300 continue;
301 }
302 ret.add(plugin);
303 }
304 return ret;
305 }
306
307 /**
308 * Parses the plugin list
309 *
310 * @param site the site from where the list was downloaded
311 * @param doc the document with the plugin list
312 */
313 protected void parsePluginListDocument(String site, String doc) {
314 try {
315 getProgressMonitor().subTask(tr("Parsing plugin list from site ''{0}''", site));
316 InputStream in = new ByteArrayInputStream(doc.getBytes("UTF-8"));
317 List<PluginInformation> pis = new PluginListParser().parse(in);
318 availablePlugins.addAll(filterDeprecatedPlugins(pis));
319 } catch(UnsupportedEncodingException e) {
320 System.err.println(tr("Failed to parse plugin list document from site ''{0}''. Skipping site. Exception was: {1}", site, e.toString()));
321 e.printStackTrace();
322 } catch(PluginListParseException e) {
323 System.err.println(tr("Failed to parse plugin list document from site ''{0}''. Skipping site. Exception was: {1}", site, e.toString()));
324 e.printStackTrace();
325 }
326 }
327
328 @Override
329 protected void realRun() throws SAXException, IOException, OsmTransferException {
330 if (sites == null) return;
331 getProgressMonitor().setTicksCount(sites.size() * 3);
332 File pluginDir = Main.pref.getPluginsDirectory();
333
334 // collect old cache files and remove if no longer in use
335 List<File> siteCacheFiles = new LinkedList<File>();
336 for (String location : PluginInformation.getPluginLocations()) {
337 File [] f = new File(location).listFiles(
338 new FilenameFilter() {
339 public boolean accept(File dir, String name) {
340 return name.matches("^([0-9]+-)?site.*\\.txt$") ||
341 name.matches("^([0-9]+-)?site.*-icons\\.zip$");
342 }
343 }
344 );
345 if(f != null && f.length > 0) {
346 siteCacheFiles.addAll(Arrays.asList(f));
347 }
348 }
349
350 for (String site: sites) {
351 String printsite = site.replaceAll("%<(.*)>", "");
352 getProgressMonitor().subTask(tr("Processing plugin list from site ''{0}''", printsite));
353 String list = downloadPluginList(site, getProgressMonitor().createSubTaskMonitor(0, false));
354 if (canceled) return;
355 siteCacheFiles.remove(createSiteCacheFile(pluginDir, site, CacheType.PLUGIN_LIST));
356 siteCacheFiles.remove(createSiteCacheFile(pluginDir, site, CacheType.ICON_LIST));
357 if(list != null)
358 {
359 getProgressMonitor().worked(1);
360 cachePluginList(site, list);
361 if (canceled) return;
362 getProgressMonitor().worked(1);
363 parsePluginListDocument(site, list);
364 if (canceled) return;
365 getProgressMonitor().worked(1);
366 if (canceled) return;
367 }
368 downloadPluginIcons(site+"-icons.zip", createSiteCacheFile(pluginDir, site, CacheType.ICON_LIST), getProgressMonitor().createSubTaskMonitor(0, false));
369 }
370 for (File file: siteCacheFiles) /* remove old stuff or whole update process is broken */
371 {
372 file.delete();
373 }
374 }
375
376 /**
377 * Replies true if the task was canceled
378 * @return
379 */
380 public boolean isCanceled() {
381 return canceled;
382 }
383
384 /**
385 * Replies the list of plugins described in the downloaded plugin lists
386 *
387 * @return the list of plugins
388 */
389 public List<PluginInformation> getAvailabePlugins() {
390 return availablePlugins;
391 }
392}
Note: See TracBrowser for help on using the repository browser.