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

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