source: josm/src/org/openstreetmap/josm/plugins/PluginInformation.java@ 293

Last change on this file since 293 was 293, checked in by imi, 17 years ago
  • changed the order which directories are searched for images (~/.josm/images goes first)
  • made the crosshair cursor configurable
File size: 7.7 KB
Line 
1package org.openstreetmap.josm.plugins;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.io.File;
6import java.io.FileInputStream;
7import java.io.IOException;
8import java.io.InputStream;
9import java.net.URL;
10import java.util.ArrayList;
11import java.util.Collection;
12import java.util.LinkedList;
13import java.util.List;
14import java.util.Map;
15import java.util.TreeMap;
16import java.util.jar.Attributes;
17import java.util.jar.JarInputStream;
18import java.util.jar.Manifest;
19
20import org.openstreetmap.josm.Main;
21
22/**
23 * Encapsulate general information about a plugin. This information is available
24 * without the need of loading any class from the plugin jar file.
25 *
26 * @author imi
27 */
28public class PluginInformation {
29
30 public final File file;
31 public final String name;
32 public final String className;
33 public final String description;
34 public final boolean early;
35 public final String author;
36 public final int stage;
37 public final String version;
38 public final List<URL> libraries = new LinkedList<URL>();
39
40 public final Map<String, String> attr = new TreeMap<String, String>();
41
42 /**
43 * Used in the Plugin constructor to make the information of the plugin
44 * that is currently initializing available.
45 *
46 * If you think this is hacky, you are probably right. But it is
47 * convinient anyway ;-)
48 */
49 static PluginInformation currentPluginInitialization = null;
50
51 /**
52 * @param file the plugin jar file.
53 */
54 public PluginInformation(File file) {
55 this(file, file.getName().substring(0, file.getName().length()-4), null);
56 }
57
58 public PluginInformation(File file, String name, InputStream manifestStream) {
59 this.name = name;
60 this.file = file;
61 try {
62 Manifest manifest;
63 JarInputStream jar = null;
64 if (file != null) {
65 jar = new JarInputStream(new FileInputStream(file));
66 manifest = jar.getManifest();
67 if (manifest == null)
68 throw new IOException(file+" contains no manifest.");
69 } else {
70 manifest = new Manifest();
71 manifest.read(manifestStream);
72 }
73 if (manifest != null) {
74 Attributes attr = manifest.getMainAttributes();
75 className = attr.getValue("Plugin-Class");
76 description = attr.getValue("Plugin-Description");
77 early = Boolean.parseBoolean(attr.getValue("Plugin-Early"));
78 String stageStr = attr.getValue("Plugin-Stage");
79 stage = stageStr == null ? 50 : Integer.parseInt(stageStr);
80 version = attr.getValue("Plugin-Version");
81 author = attr.getValue("Author");
82
83 String classPath = attr.getValue(Attributes.Name.CLASS_PATH);
84 if (classPath != null) {
85 String[] cp = classPath.split(" ");
86 StringBuilder entry = new StringBuilder();
87 for (String s : cp) {
88 entry.append(s);
89 if (s.endsWith("\\")) {
90 entry.setLength(entry.length()-1);
91 entry.append("%20"); // append the split character " " as html-encode
92 continue;
93 }
94 s = entry.toString();
95 entry = new StringBuilder();
96 if (!s.startsWith("/") && !s.startsWith("\\") && !s.matches("^.\\:") && file != null)
97 s = file.getParent() + File.separator + s;
98 libraries.add(new URL(getURLString(s)));
99 }
100 }
101 for (Object o : attr.keySet())
102 this.attr.put(o.toString(), attr.getValue(o.toString()));
103 } else {
104 // resource-only plugin
105 className = null;
106 description = tr("unknown");
107 early = false;
108 stage = 50;
109 version = null;
110 author = null;
111 }
112 if (file != null)
113 libraries.add(0, new URL(getURLString(file.getAbsolutePath())));
114
115 if (jar != null)
116 jar.close();
117 } catch (IOException e) {
118 throw new PluginException(null, name, e);
119 }
120 }
121
122 /**
123 * Load and instantiate the plugin
124 */
125 public PluginProxy load(Class<?> klass) {
126 try {
127 currentPluginInitialization = this;
128 return new PluginProxy(klass.newInstance(), this);
129 } catch (Exception e) {
130 throw new PluginException(null, name, e);
131 }
132 }
133
134 /**
135 * Load the class of the plugin
136 */
137 public Class<?> loadClass(ClassLoader classLoader) {
138 if (className == null)
139 return null;
140 try {
141 Class<?> realClass = Class.forName(className, true, classLoader);
142 return realClass;
143 } catch (Exception e) {
144 throw new PluginException(null, name, e);
145 }
146 }
147
148 public static String getURLString(String fileName) {
149 if (System.getProperty("os.name").startsWith("Windows"))
150 return "file:/"+fileName;
151 return "file://"+fileName;
152 }
153
154 /**
155 * Try to find a plugin after some criterias. Extract the plugin-information
156 * from the plugin and return it. The plugin is searched in the following way:
157 *
158 *<li>first look after an MANIFEST.MF in the package org.openstreetmap.josm.plugins.<plugin name>
159 * (After removing all fancy characters from the plugin name).
160 * If found, the plugin is loaded using the bootstrap classloader.
161 *<li>If not found, look for a jar file in the user specific plugin directory
162 * (~/.josm/plugins/<plugin name>.jar)
163 *<li>If not found and the environment variable JOSM_RESSOURCES + "/plugins/" exist, look there.
164 *<li>Try for the java property josm.ressources + "/plugins/" (set via java -Djosm.plugins.path=...)
165 *<li>If the environment variable ALLUSERSPROFILE and APPDATA exist, look in
166 * ALLUSERSPROFILE/<the last stuff from APPDATA>/JOSM/plugins.
167 * (*sic* There is no easy way under Windows to get the All User's application
168 * directory)
169 *<li>Finally, look in some typical unix paths:<ul>
170 * <li>/usr/local/share/josm/plugins/
171 * <li>/usr/local/lib/josm/plugins/
172 * <li>/usr/share/josm/plugins/
173 * <li>/usr/lib/josm/plugins/
174 *
175 * If a plugin class or jar file is found earlier in the list but seem not to
176 * be working, an PluginException is thrown rather than continuing the search.
177 * This is so JOSM can detect broken user-provided plugins and do not go silently
178 * ignore them.
179 *
180 * The plugin is not initialized. If the plugin is a .jar file, it is not loaded
181 * (only the manifest is extracted). In the classloader-case, the class is
182 * bootstraped (e.g. static {} - declarations will run. However, nothing else is done.
183 *
184 * @param pluginName The name of the plugin (in all lowercase). E.g. "lang-de"
185 * @return Information about the plugin or <code>null</code>, if the plugin
186 * was nowhere to be found.
187 * @throws PluginException In case of broken plugins.
188 */
189 public static PluginInformation findPlugin(String pluginName) throws PluginException {
190 String name = pluginName;
191 name = name.replaceAll("[-. ]", "");
192 InputStream manifestStream = PluginInformation.class.getResourceAsStream("/org/openstreetmap/josm/plugins/"+name+"/MANIFEST.MF");
193 if (manifestStream != null)
194 return new PluginInformation(null, pluginName, manifestStream);
195
196 Collection<String> locations = getPluginLocations();
197
198 for (String s : locations) {
199 File pluginFile = new File(s+"/"+pluginName+".jar");
200 if (pluginFile.exists()) {
201 PluginInformation info = new PluginInformation(pluginFile);
202 return info;
203 }
204 }
205 return null;
206 }
207
208 public static Collection<String> getPluginLocations() {
209 Collection<String> locations = Main.pref.getAllPossiblePreferenceDirs();
210 Collection<String> all = new ArrayList<String>(locations.size());
211 for (String s : locations)
212 all.add(s+"plugins");
213 return all;
214 }
215
216
217 /**
218 * Return information about a loaded plugin.
219 *
220 * Note that if you call this in your plugins bootstrap, you may get <code>null</code> if
221 * the plugin requested is not loaded yet.
222 *
223 * @return The PluginInformation to a specific plugin, but only if the plugin is loaded.
224 * If it is not loaded, <code>null</code> is returned.
225 */
226 public static PluginInformation getLoaded(String pluginName) {
227 for (PluginProxy p : Main.plugins)
228 if (p.info.name.equals(pluginName))
229 return p.info;
230 return null;
231 }
232}
233
Note: See TracBrowser for help on using the repository browser.