source: josm/trunk/src/org/openstreetmap/josm/plugins/PluginListParser.java

Last change on this file was 18796, checked in by taylor.smock, 9 months ago

Fix #23097: Significantly reduce allocations during startup in XmlObjectParser, PluginListParser, and ReadLocalPluginInformationTask

With the Name Suggestion Index preset added to JOSM, the following methods are
relatively expensive during startup (mem old -> mem new, cpu old -> cpu new):

  • XmlObjectParser$Entry.getField (124 MB -> 8.1 MB, 501ms -> 99ms)
  • XmlObjectParser$Entry.getMethod (126 MB -> 452 kB, 292ms -> 45ms)

The gains are almost entirely from getting rid of copy calls to Method and Field
(done when calling Class.getMethods() and Class.getFields()). There are
further gains in JVM methods (like GC), but those can be a bit ticklish to
profile correctly. It does look like a 20% improvement there though
(32,653ms -> 26,075ms).

This additionally reduces pattern compilation from PluginListParser.parse and
ReadLocalPluginInformationTask.listFiles.

  • Property svn:eol-style set to native
File size: 4.4 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.IOException;
8import java.io.InputStream;
9import java.io.InputStreamReader;
10import java.nio.charset.StandardCharsets;
11import java.util.LinkedList;
12import java.util.List;
13import java.util.jar.Attributes;
14import java.util.regex.Matcher;
15import java.util.regex.Pattern;
16
17import org.openstreetmap.josm.tools.Logging;
18
19/**
20 * A parser for the plugin list provided by a JOSM Plugin Download Site.
21 *
22 * See <a href="https://josm.openstreetmap.de/plugin">https://josm.openstreetmap.de/plugin</a>
23 * for a sample of the document. The format is a custom format, kind of mix of CSV and RFC822 style
24 * name/value-pairs.
25 *
26 */
27public class PluginListParser {
28
29 /**
30 * Creates the plugin information object
31 *
32 * @param name the plugin name
33 * @param url the plugin download url
34 * @param manifest the plugin manifest attributes
35 * @return a plugin information object
36 * @throws PluginListParseException if plugin manifest cannot be parsed
37 */
38 public static PluginInformation createInfo(String name, String url, Attributes manifest) throws PluginListParseException {
39 try {
40 return new PluginInformation(
41 manifest,
42 name.substring(0, name.length() - 4),
43 url
44 );
45 } catch (PluginException e) {
46 throw new PluginListParseException(tr("Failed to create plugin information from manifest for plugin ''{0}''", name), e);
47 }
48 }
49
50 /**
51 * Parses a plugin information document and replies a list of plugin information objects.
52 *
53 * See <a href="https://josm.openstreetmap.de/plugin">https://josm.openstreetmap.de/plugin</a>
54 * for a sample of the document. The format is a custom format, kind of mix of CSV and RFC822 style
55 * name/value-pairs.
56 *
57 * @param in the input stream from which to parse
58 * @return the list of plugin information objects
59 * @throws PluginListParseException if something goes wrong while parsing
60 */
61 public List<PluginInformation> parse(InputStream in) throws PluginListParseException {
62 List<PluginInformation> ret = new LinkedList<>();
63 try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
64 String name = null;
65 String url = null;
66 Attributes manifest = new Attributes();
67 final Pattern spaceColonSpace = Pattern.compile("\\s*:\\s*", Pattern.UNICODE_CHARACTER_CLASS);
68 final Matcher matcher = spaceColonSpace.matcher("");
69 for (String line = r.readLine(); line != null; line = r.readLine()) {
70 if (line.startsWith("\t")) {
71 matcher.reset(line);
72 if (matcher.find() && matcher.start() > 0 && matcher.end() < line.length()) {
73 final String key = line.substring(1, matcher.start());
74 final String value = line.substring(matcher.end());
75 manifest.put(new Attributes.Name(key), value);
76 }
77 continue;
78 }
79 addPluginInformation(ret, name, url, manifest);
80 String[] x = line.split(";", -1);
81 if (x.length != 2)
82 throw new IOException(tr("Illegal entry in plugin list.") + " " + line);
83 name = x[0];
84 url = x[1];
85 manifest = new Attributes();
86 }
87 addPluginInformation(ret, name, url, manifest);
88 return ret;
89 } catch (IOException e) {
90 throw new PluginListParseException(e);
91 }
92 }
93
94 private static void addPluginInformation(List<PluginInformation> ret, String name, String url, Attributes manifest) {
95 try {
96 if (name != null) {
97 PluginInformation info = createInfo(name, url, manifest);
98 for (PluginProxy plugin : PluginHandler.pluginList) {
99 if (plugin.getPluginInformation().name.equals(info.getName())) {
100 info.localversion = plugin.getPluginInformation().localversion;
101 }
102 }
103 ret.add(info);
104 }
105 } catch (PluginListParseException ex) {
106 Logging.error(ex);
107 }
108 }
109
110}
Note: See TracBrowser for help on using the repository browser.