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

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

see #7027 - internal structures for preferences (expect some problems next few days)

  • Property svn:eol-style set to native
File size: 14.1 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 {@see 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 = ImageProvider.getIfAvailable(null, null, null, pi.name+".jar/"+pi.iconPath, destFile);
247 }
248 }
249 }
250
251 /**
252 * Writes the list of plugins to a cache file
253 *
254 * @param site the site from where the list was downloaded
255 * @param list the downloaded list
256 */
257 protected void cachePluginList(String site, String list) {
258 PrintWriter writer = null;
259 try {
260 File pluginDir = Main.pref.getPluginsDirectory();
261 if (!pluginDir.exists()) {
262 if (! pluginDir.mkdirs()) {
263 System.err.println(tr("Warning: failed to create plugin directory ''{0}''. Cannot cache plugin list from plugin site ''{1}''.", pluginDir.toString(), site));
264 }
265 }
266 File cacheFile = createSiteCacheFile(pluginDir, site, CacheType.PLUGIN_LIST);
267 getProgressMonitor().subTask(tr("Writing plugin list to local cache ''{0}''", cacheFile.toString()));
268 writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(cacheFile), "utf-8"));
269 writer.write(list);
270 } catch(IOException e) {
271 // just failed to write the cache file. No big deal, but log the exception anyway
272 e.printStackTrace();
273 } finally {
274 if (writer != null) {
275 writer.flush();
276 writer.close();
277 }
278 }
279 }
280
281 /**
282 * Filter information about deprecated plugins from the list of downloaded
283 * plugins
284 *
285 * @param plugins the plugin informations
286 * @return the plugin informations, without deprecated plugins
287 */
288 protected List<PluginInformation> filterDeprecatedPlugins(List<PluginInformation> plugins) {
289 List<PluginInformation> ret = new ArrayList<PluginInformation>(plugins.size());
290 HashSet<String> deprecatedPluginNames = new HashSet<String>();
291 for (PluginHandler.DeprecatedPlugin p : PluginHandler.DEPRECATED_PLUGINS) {
292 deprecatedPluginNames.add(p.name);
293 }
294 for (PluginInformation plugin: plugins) {
295 if (deprecatedPluginNames.contains(plugin.name)) {
296 continue;
297 }
298 ret.add(plugin);
299 }
300 return ret;
301 }
302
303 /**
304 * Parses the plugin list
305 *
306 * @param site the site from where the list was downloaded
307 * @param doc the document with the plugin list
308 */
309 protected void parsePluginListDocument(String site, String doc) {
310 try {
311 getProgressMonitor().subTask(tr("Parsing plugin list from site ''{0}''", site));
312 InputStream in = new ByteArrayInputStream(doc.getBytes("UTF-8"));
313 List<PluginInformation> pis = new PluginListParser().parse(in);
314 availablePlugins.addAll(filterDeprecatedPlugins(pis));
315 } catch(UnsupportedEncodingException e) {
316 System.err.println(tr("Failed to parse plugin list document from site ''{0}''. Skipping site. Exception was: {1}", site, e.toString()));
317 e.printStackTrace();
318 } catch(PluginListParseException e) {
319 System.err.println(tr("Failed to parse plugin list document from site ''{0}''. Skipping site. Exception was: {1}", site, e.toString()));
320 e.printStackTrace();
321 }
322 }
323
324 @Override
325 protected void realRun() throws SAXException, IOException, OsmTransferException {
326 if (sites == null) return;
327 getProgressMonitor().setTicksCount(sites.size() * 3);
328 File pluginDir = Main.pref.getPluginsDirectory();
329
330 // collect old cache files and remove if no longer in use
331 List<File> siteCacheFiles = new LinkedList<File>();
332 for (String location : PluginInformation.getPluginLocations()) {
333 File [] f = new File(location).listFiles(
334 new FilenameFilter() {
335 public boolean accept(File dir, String name) {
336 return name.matches("^([0-9]+-)?site.*\\.txt$") ||
337 name.matches("^([0-9]+-)?site.*-icons\\.zip$");
338 }
339 }
340 );
341 if(f != null && f.length > 0) {
342 siteCacheFiles.addAll(Arrays.asList(f));
343 }
344 }
345
346 for (String site: sites) {
347 String printsite = site.replaceAll("%<(.*)>", "");
348 getProgressMonitor().subTask(tr("Processing plugin list from site ''{0}''", printsite));
349 String list = downloadPluginList(site, getProgressMonitor().createSubTaskMonitor(0, false));
350 if (canceled) return;
351 siteCacheFiles.remove(createSiteCacheFile(pluginDir, site, CacheType.PLUGIN_LIST));
352 siteCacheFiles.remove(createSiteCacheFile(pluginDir, site, CacheType.ICON_LIST));
353 if(list != null)
354 {
355 getProgressMonitor().worked(1);
356 cachePluginList(site, list);
357 if (canceled) return;
358 getProgressMonitor().worked(1);
359 parsePluginListDocument(site, list);
360 if (canceled) return;
361 getProgressMonitor().worked(1);
362 if (canceled) return;
363 }
364 downloadPluginIcons(site+"-icons.zip", createSiteCacheFile(pluginDir, site, CacheType.ICON_LIST), getProgressMonitor().createSubTaskMonitor(0, false));
365 }
366 for (File file: siteCacheFiles) /* remove old stuff or whole update process is broken */
367 {
368 file.delete();
369 }
370 }
371
372 /**
373 * Replies true if the task was canceled
374 * @return
375 */
376 public boolean isCanceled() {
377 return canceled;
378 }
379
380 /**
381 * Replies the list of plugins described in the downloaded plugin lists
382 *
383 * @return the list of plugins
384 */
385 public List<PluginInformation> getAvailabePlugins() {
386 return availablePlugins;
387 }
388}
Note: See TracBrowser for help on using the repository browser.