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

Last change on this file since 626 was 504, checked in by gebner, 16 years ago

Don't do hacky string mangling to get a URL from a File.

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