source: josm/trunk/src/org/openstreetmap/josm/plugins/ReadLocalPluginInformationTask.java@ 13502

Last change on this file since 13502 was 13204, checked in by Don-vip, 6 years ago

enable new PMD rule AvoidFileStream - see https://pmd.github.io/pmd-6.0.0/pmd_rules_java_performance.html#avoidfilestream / https://bugs.openjdk.java.net/browse/JDK-8080225 for details

  • Property svn:eol-style set to native
File size: 8.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.File;
7import java.io.FilenameFilter;
8import java.io.IOException;
9import java.io.InputStream;
10import java.nio.file.Files;
11import java.nio.file.InvalidPathException;
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.HashMap;
15import java.util.List;
16import java.util.Map;
17
18import org.openstreetmap.josm.gui.PleaseWaitRunnable;
19import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
20import org.openstreetmap.josm.gui.progress.ProgressMonitor;
21import org.openstreetmap.josm.io.OsmTransferException;
22import org.openstreetmap.josm.tools.Logging;
23import org.xml.sax.SAXException;
24
25/**
26 * This is an asynchronous task for reading plugin information from the files
27 * in the local plugin repositories.
28 *
29 * It scans the files in the local plugins repository (see {@link org.openstreetmap.josm.data.Preferences#getPluginsDirectory()}
30 * and extracts plugin information from three kind of files:
31 * <ul>
32 * <li>.jar files, assuming that they represent plugin jars</li>
33 * <li>.jar.new files, assuming that these are downloaded but not yet installed plugins</li>
34 * <li>cached lists of available plugins, downloaded for instance from
35 * <a href="https://josm.openstreetmap.de/pluginicons">https://josm.openstreetmap.de/pluginicons</a></li>
36 * </ul>
37 *
38 */
39public class ReadLocalPluginInformationTask extends PleaseWaitRunnable {
40 private final Map<String, PluginInformation> availablePlugins;
41 private boolean canceled;
42
43 /**
44 * Constructs a new {@code ReadLocalPluginInformationTask}.
45 */
46 public ReadLocalPluginInformationTask() {
47 super(tr("Reading local plugin information.."), false);
48 availablePlugins = new HashMap<>();
49 }
50
51 /**
52 * Constructs a new {@code ReadLocalPluginInformationTask}.
53 * @param monitor progress monitor
54 */
55 public ReadLocalPluginInformationTask(ProgressMonitor monitor) {
56 super(tr("Reading local plugin information.."), monitor, false);
57 availablePlugins = new HashMap<>();
58 }
59
60 @Override
61 protected void cancel() {
62 canceled = true;
63 }
64
65 @Override
66 protected void finish() {
67 // Do nothing
68 }
69
70 protected void processJarFile(File f, String pluginName) throws PluginException {
71 PluginInformation info = new PluginInformation(
72 f,
73 pluginName
74 );
75 if (!availablePlugins.containsKey(info.getName())) {
76 info.updateLocalInfo(info);
77 availablePlugins.put(info.getName(), info);
78 } else {
79 PluginInformation current = availablePlugins.get(info.getName());
80 current.updateFromJar(info);
81 }
82 }
83
84 private static File[] listFiles(File pluginsDirectory, final String regex) {
85 return pluginsDirectory.listFiles((FilenameFilter) (dir, name) -> name.matches(regex));
86 }
87
88 protected void scanSiteCacheFiles(ProgressMonitor monitor, File pluginsDirectory) {
89 File[] siteCacheFiles = listFiles(pluginsDirectory, "^([0-9]+-)?site.*\\.txt$");
90 if (siteCacheFiles == null || siteCacheFiles.length == 0)
91 return;
92 monitor.subTask(tr("Processing plugin site cache files..."));
93 monitor.setTicksCount(siteCacheFiles.length);
94 for (File f: siteCacheFiles) {
95 String fname = f.getName();
96 monitor.setCustomText(tr("Processing file ''{0}''", fname));
97 try {
98 processLocalPluginInformationFile(f);
99 } catch (PluginListParseException e) {
100 Logging.warn(tr("Failed to scan file ''{0}'' for plugin information. Skipping.", fname));
101 Logging.error(e);
102 }
103 monitor.worked(1);
104 }
105 }
106
107 protected void scanPluginFiles(ProgressMonitor monitor, File pluginsDirectory) {
108 File[] pluginFiles = pluginsDirectory.listFiles(
109 (FilenameFilter) (dir, name) -> name.endsWith(".jar") || name.endsWith(".jar.new")
110 );
111 if (pluginFiles == null || pluginFiles.length == 0)
112 return;
113 monitor.subTask(tr("Processing plugin files..."));
114 monitor.setTicksCount(pluginFiles.length);
115 for (File f: pluginFiles) {
116 String fname = f.getName();
117 monitor.setCustomText(tr("Processing file ''{0}''", fname));
118 try {
119 if (fname.endsWith(".jar")) {
120 String pluginName = fname.substring(0, fname.length() - 4);
121 processJarFile(f, pluginName);
122 } else if (fname.endsWith(".jar.new")) {
123 String pluginName = fname.substring(0, fname.length() - 8);
124 processJarFile(f, pluginName);
125 }
126 } catch (PluginException e) {
127 Logging.log(Logging.LEVEL_WARN, "PluginException: ", e);
128 Logging.warn(tr("Failed to scan file ''{0}'' for plugin information. Skipping.", fname));
129 }
130 monitor.worked(1);
131 }
132 }
133
134 protected void scanLocalPluginRepository(ProgressMonitor progressMonitor, File pluginsDirectory) {
135 if (pluginsDirectory == null)
136 return;
137 ProgressMonitor monitor = progressMonitor != null ? progressMonitor : NullProgressMonitor.INSTANCE;
138 try {
139 monitor.beginTask("");
140 scanSiteCacheFiles(monitor, pluginsDirectory);
141 scanPluginFiles(monitor, pluginsDirectory);
142 } finally {
143 monitor.setCustomText("");
144 monitor.finishTask();
145 }
146 }
147
148 protected void processLocalPluginInformationFile(File file) throws PluginListParseException {
149 try (InputStream fin = Files.newInputStream(file.toPath())) {
150 List<PluginInformation> pis = new PluginListParser().parse(fin);
151 for (PluginInformation pi : pis) {
152 // we always keep plugin information from a plugin site because it
153 // includes information not available in the plugin jars Manifest, i.e.
154 // the download link or localized descriptions
155 //
156 availablePlugins.put(pi.name, pi);
157 }
158 } catch (IOException | InvalidPathException e) {
159 throw new PluginListParseException(e);
160 }
161 }
162
163 protected void analyseInProcessPlugins() {
164 for (PluginProxy proxy : PluginHandler.pluginList) {
165 PluginInformation info = proxy.getPluginInformation();
166 if (canceled) return;
167 if (!availablePlugins.containsKey(info.name)) {
168 availablePlugins.put(info.name, info);
169 } else {
170 availablePlugins.get(info.name).localversion = info.localversion;
171 }
172 }
173 }
174
175 protected void filterOldPlugins() {
176 for (PluginHandler.DeprecatedPlugin p : PluginHandler.DEPRECATED_PLUGINS) {
177 if (canceled) return;
178 if (availablePlugins.containsKey(p.name)) {
179 availablePlugins.remove(p.name);
180 }
181 }
182 }
183
184 @Override
185 protected void realRun() throws SAXException, IOException, OsmTransferException {
186 Collection<String> pluginLocations = PluginInformation.getPluginLocations();
187 getProgressMonitor().setTicksCount(pluginLocations.size() + 2);
188 if (canceled) return;
189 for (String location : pluginLocations) {
190 scanLocalPluginRepository(
191 getProgressMonitor().createSubTaskMonitor(1, false),
192 new File(location)
193 );
194 getProgressMonitor().worked(1);
195 if (canceled) return;
196 }
197 analyseInProcessPlugins();
198 getProgressMonitor().worked(1);
199 if (canceled) return;
200 filterOldPlugins();
201 getProgressMonitor().worked(1);
202 }
203
204 /**
205 * Replies information about available plugins detected by this task.
206 *
207 * @return information about available plugins detected by this task.
208 */
209 public List<PluginInformation> getAvailablePlugins() {
210 return new ArrayList<>(availablePlugins.values());
211 }
212
213 /**
214 * Replies true if the task was canceled by the user
215 *
216 * @return true if the task was canceled by the user
217 */
218 public boolean isCanceled() {
219 return canceled;
220 }
221}
Note: See TracBrowser for help on using the repository browser.