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

Last change on this file since 3734 was 3730, checked in by bastiK, 13 years ago

improve migration when remotecontrol plugin is removed (set remotecontol.enabled=yes) (see also #5748)

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