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

Last change on this file since 2817 was 2817, checked in by Gubaer, 14 years ago

fixed #3063: Downloading a plugin yields 3 dialogs at the same time: Downloading plugin / You should restart JOSM / Plugin downloaded
fixed #3628: JOSM blocking itself updating broken plugin
fixed #4187: JOSM deleted random files from disk after start (data loss)
fixed #4199: new version - plugins update vs josm start [should be fixed. Be careful if you have two JOSM instances running. Auto-update of plugins in the second instance will fail because plugin files are locked by the first instance]
fixed #4034: JOSM should auto-download plugin list when it hasn't been downloaded before [JOSM now displays a hint]

fixed: splash screen showing again even if plugins are auto-updated
new: progress indication integrated in splash screen
new: cancelable, asynchronous download of plugins from preferences
new: cancelable, asynchronous download of plugin list from plugin download sites
new: asynchronous loading of plugin information, launch of preferences dialog accelerated
refactored: clean up, documentation of plugin management code (PluginHandler)

File size: 8.0 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.FileWriter;
10import java.io.IOException;
11import java.io.InputStream;
12import java.io.InputStreamReader;
13import java.io.PrintWriter;
14import java.io.UnsupportedEncodingException;
15import java.net.HttpURLConnection;
16import java.net.MalformedURLException;
17import java.net.URL;
18import java.util.Collection;
19import java.util.Collections;
20import java.util.LinkedList;
21import java.util.List;
22
23import org.openstreetmap.josm.Main;
24import org.openstreetmap.josm.gui.PleaseWaitRunnable;
25import org.openstreetmap.josm.gui.progress.ProgressMonitor;
26import org.openstreetmap.josm.io.OsmTransferException;
27import org.xml.sax.SAXException;
28
29/**
30 * An asynchronous task for downloading plugin lists from the configured plugin download
31 * sites.
32 *
33 */
34public class ReadRemotePluginInformationTask extends PleaseWaitRunnable{
35
36 private Collection<String> sites;
37 private boolean canceled;
38 private HttpURLConnection connection;
39 private List<PluginInformation> availabePlugins;
40
41 /**
42 * Creates the task
43 *
44 * @param sites the collection of download sites. Defaults to the empty collection if null.
45 */
46 public ReadRemotePluginInformationTask(Collection<String> sites) {
47 super(tr("Download plugin list..."), false /* don't ignore exceptions */);
48 this.sites = sites;
49 if (sites == null) {
50 this.sites = Collections.emptySet();
51 }
52 availabePlugins = new LinkedList<PluginInformation>();
53 }
54
55 @Override
56 protected void cancel() {
57 canceled = true;
58 synchronized(this) {
59 if (connection != null) {
60 connection.disconnect();
61 }
62 }
63 }
64
65 @Override
66 protected void finish() {}
67
68 /**
69 * Creates the file name for the cached plugin list.
70 *
71 * @param site the name of the site
72 * @return the file name for the cache file
73 */
74 protected String createSiteCacheFileName(String site) {
75 try {
76 URL url = new URL(site);
77 StringBuilder sb = new StringBuilder();
78 sb.append("site-");
79 sb.append(url.getHost()).append("-");
80 if (url.getPort() != -1) {
81 sb.append(url.getPort()).append("-");
82 }
83 String path = url.getPath();
84 for (int i =0;i<path.length(); i++) {
85 char c = path.charAt(i);
86 if (Character.isLetterOrDigit(c)) {
87 sb.append(c);
88 } else {
89 sb.append("_");
90 }
91 }
92 sb.append(".txt");
93 return sb.toString();
94 } catch(MalformedURLException e) {
95 return "site-unknown.txt";
96 }
97 }
98
99 /**
100 * Downloads the list from a remote location
101 *
102 * @param site the site URL
103 * @param monitor a progress monitor
104 * @return the downloaded list
105 */
106 protected String downloadPluginList(String site, ProgressMonitor monitor) {
107 BufferedReader in = null;
108 StringBuilder sb = new StringBuilder();
109 try {
110 monitor.beginTask("");
111 monitor.indeterminateSubTask(tr("Downloading plugin list from ''{0}''", site));
112
113 URL url = new URL(site);
114 synchronized(this) {
115 connection = (HttpURLConnection)url.openConnection();
116 }
117 in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
118 String line;
119 while((line = in.readLine()) != null) {
120 sb.append(line).append("\n");
121 }
122 return sb.toString();
123 } catch(MalformedURLException e) {
124 if (canceled) return null;
125 e.printStackTrace();
126 return null;
127 } catch(IOException e) {
128 if (canceled) return null;
129 e.printStackTrace();
130 return null;
131 } finally {
132 synchronized(this) {
133 if (connection != null) {
134 connection.disconnect();
135 }
136 connection = null;
137 }
138 if (in != null) {
139 try {
140 in.close();
141 } catch(IOException e){/* ignore */}
142 }
143 monitor.finishTask();
144 }
145 }
146
147 /**
148 * Writes the list of plugins to a cache file
149 *
150 * @param site the site from where the list was downloaded
151 * @param list the downloaded list
152 */
153 protected void cachePluginList(String site, String list) {
154 PrintWriter writer = null;
155 try {
156 File pluginDir = Main.pref.getPluginsDirectory();
157 if (!pluginDir.exists()) {
158 if (! pluginDir.mkdirs()) {
159 System.err.println(tr("Warning: failed to create plugin directory ''{0}''. Cannot cache plugin list from plugin site ''{1}''.", pluginDir.toString(), site));
160 }
161 }
162 File cacheFile = new File(pluginDir, createSiteCacheFileName(site));
163 getProgressMonitor().subTask(tr("Writing plugin list to local cache ''{0}''", cacheFile.toString()));
164 writer = new PrintWriter(
165 new FileWriter(cacheFile)
166 );
167 writer.print(list);
168 } catch(IOException e) {
169 // just failed to write the cache file. No big deal, but log the exception anyway
170 e.printStackTrace();
171 } finally {
172 if (writer != null) {
173 writer.flush();
174 writer.close();
175 }
176 }
177 }
178
179 /**
180 * Parses the plugin list
181 *
182 * @param site the site from where the list was downloaded
183 * @param doc the document with the plugin list
184 */
185 protected void parsePluginListDocument(String site, String doc) {
186 try {
187 getProgressMonitor().subTask(tr("Parsing plugin list from site ''{0}''", site));
188 InputStream in = new ByteArrayInputStream(doc.getBytes("UTF-8"));
189 List<PluginInformation> pis = new PluginListParser().parse(in);
190 availabePlugins.addAll(pis);
191 } catch(UnsupportedEncodingException e) {
192 System.err.println(tr("Failed to parse plugin list document from site ''{0}''. Skipping site. Exception was: {1}", site, e.toString()));
193 e.printStackTrace();
194 } catch(PluginListParseException e) {
195 System.err.println(tr("Failed to parse plugin list document from site ''{0}''. Skipping site. Exception was: {1}", site, e.toString()));
196 e.printStackTrace();
197 }
198 }
199
200 @Override
201 protected void realRun() throws SAXException, IOException, OsmTransferException {
202 if (sites == null) return;
203 getProgressMonitor().setTicksCount(sites.size() * 3);
204 for (String site: sites) {
205 getProgressMonitor().subTask(tr("Processing plugin list from site ''{0}''", site));
206 String list = downloadPluginList(site, getProgressMonitor().createSubTaskMonitor(0, false));
207 if (canceled) return;
208 getProgressMonitor().worked(1);
209 cachePluginList(site, list);
210 if (canceled) return;
211 getProgressMonitor().worked(1);
212 parsePluginListDocument(site, list);
213 if (canceled) return;
214 getProgressMonitor().worked(1);
215 }
216 }
217
218 /**
219 * Replies true if the task was canceled
220 * @return
221 */
222 public boolean isCanceled() {
223 return canceled;
224 }
225
226 /**
227 * Replies the list of plugins described in the downloaded plugin lists
228 *
229 * @return the list of plugins
230 */
231 public List<PluginInformation> getAvailabePlugins() {
232 return availabePlugins;
233 }
234}
Note: See TracBrowser for help on using the repository browser.