001: // The contents of this file are subject to the Mozilla Public License Version
002: // 1.1
003: //(the "License"); you may not use this file except in compliance with the
004: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
005: //
006: //Software distributed under the License is distributed on an "AS IS" basis,
007: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
008: //for the specific language governing rights and
009: //limitations under the License.
010: //
011: //The Original Code is "The Columba Project"
012: //
013: //The Initial Developers of the Original Code are Frederik Dietz and Timo
014: // Stich.
015: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
016: //
017: //All Rights Reserved.
018: package org.columba.core.plugin;
019:
020: import java.io.BufferedInputStream;
021: import java.io.File;
022: import java.io.FileInputStream;
023: import java.io.FileNotFoundException;
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.net.MalformedURLException;
027: import java.net.URL;
028: import java.util.Enumeration;
029: import java.util.Hashtable;
030: import java.util.Vector;
031: import java.util.logging.Logger;
032:
033: import org.columba.api.plugin.ExtensionHandlerMetadata;
034: import org.columba.api.plugin.ExtensionMetadata;
035: import org.columba.api.plugin.IExtensionHandler;
036: import org.columba.api.plugin.IPluginManager;
037: import org.columba.api.plugin.PluginHandlerNotFoundException;
038: import org.columba.api.plugin.PluginMetadata;
039: import org.columba.core.io.DiskIO;
040:
041: /**
042: * Plugin manager is a singleton registry for all plugins and all extension
043: * handlers.
044: *
045: * @author fdietz
046: *
047: */
048: public class PluginManager implements IPluginManager {
049:
050: private static final Logger LOG = Logger
051: .getLogger("org.columba.core.plugin");
052:
053: private static final String FILENAME_PLUGIN_XML = "plugin.xml";
054:
055: private static final String FILENAME_CONFIG_XML = "config.xml";
056:
057: private static final String FILENAME_EXTENSIONHANDLER_XML = "extensionhandler.xml";
058:
059: private Hashtable<String, IExtensionHandler> handlerMap = new Hashtable<String, IExtensionHandler>();
060:
061: private Hashtable<String, PluginMetadata> pluginMap = new Hashtable<String, PluginMetadata>();
062:
063: private static PluginManager instance = new PluginManager();
064:
065: private File[] pluginFolders;
066:
067: /**
068: *
069: */
070: private PluginManager() {
071: // find all possible plugin directories
072: pluginFolders = PluginFinder.searchPlugins();
073: }
074:
075: /**
076: * @return instance
077: */
078: public static IPluginManager getInstance() {
079: return instance;
080: }
081:
082: /**
083: * @see org.columba.api.plugin.IPluginManager#addExtensionHandler(java.lang.String,
084: * org.columba.api.plugin.IExtensionHandler)
085: */
086: public void addExtensionHandler(String id, IExtensionHandler handler) {
087: if (id == null)
088: throw new IllegalArgumentException("id == null");
089: if (handler == null)
090: throw new IllegalArgumentException("handler == null");
091:
092: LOG.fine("adding extension handler " + id);
093:
094: handlerMap.put(id, handler);
095: }
096:
097: /**
098: * @see org.columba.api.plugin.IPluginManager#getExtensionHandler(java.lang.String)
099: */
100: public IExtensionHandler getExtensionHandler(String id)
101: throws PluginHandlerNotFoundException {
102: if (id == null)
103: throw new IllegalArgumentException("id == null");
104:
105: if (handlerMap.containsKey(id))
106: return (IExtensionHandler) handlerMap.get(id);
107: else
108: throw new PluginHandlerNotFoundException(id);
109: }
110:
111: /**
112: * @see org.columba.api.plugin.IPluginManager#addPlugin(java.io.File)
113: */
114: public String addPlugin(File xmlFile) {
115: Hashtable hashtable = new Hashtable();
116:
117: // parse "/plugin.xml" file
118: BufferedInputStream buf;
119: try {
120: buf = new BufferedInputStream(new FileInputStream(xmlFile));
121: } catch (FileNotFoundException e1) {
122: e1.printStackTrace();
123: // cancel
124: return null;
125: }
126:
127: PluginMetadata pluginMetadata = new ExtensionXMLParser()
128: .parsePlugin(buf, hashtable);
129: pluginMetadata.setDirectory(xmlFile.getParentFile());
130:
131: String id = pluginMetadata.getId();
132: pluginMap.put(id, pluginMetadata);
133:
134: // register all extensions
135: parseExtensions(hashtable, pluginMetadata, false);
136:
137: return id;
138: }
139:
140: /**
141: * @param hashtable
142: * hashtable with String id and Vector of
143: * <code>ExtensionMetadata</code>
144: * @param pluginMetadata
145: */
146: private void parseExtensions(Hashtable hashtable,
147: PluginMetadata pluginMetadata, boolean internal) {
148: // loop through all extensions this plugin uses
149: // -> search the corresponding extension handler
150: // -> register the extension at the extension handler
151: Enumeration e = hashtable.keys();
152: while (e.hasMoreElements()) {
153: String extensionpointId = (String) e.nextElement();
154:
155: Vector extensionVector = (Vector) hashtable
156: .get(extensionpointId);
157:
158: IExtensionHandler handler = null;
159:
160: // we have a plugin-handler for this kind of extension
161: try {
162: handler = getExtensionHandler(extensionpointId);
163: Enumeration e2 = extensionVector.elements();
164: while (e2.hasMoreElements()) {
165: ExtensionMetadata extensionMetadata = (ExtensionMetadata) e2
166: .nextElement();
167: Extension pluginExtension = new Extension(
168: pluginMetadata, extensionMetadata);
169: pluginExtension.setInternal(internal);
170:
171: String extensionId = pluginExtension.getMetadata()
172: .getId();
173: // if extension wasn't already registered
174: if (handler.exists(extensionId) == false)
175: handler.addExtension(extensionId,
176: pluginExtension);
177: }
178: } catch (PluginHandlerNotFoundException e2) {
179: LOG.severe("No suitable extension handler with name "
180: + extensionpointId + " found");
181: }
182: }
183: }
184:
185: /**
186: * @see org.columba.api.plugin.IPluginManager#initExternalPlugins()
187: */
188: public void initExternalPlugins() {
189:
190: // if no plugin directory exists -> return
191: if (pluginFolders == null || pluginFolders.length == 0) {
192: return;
193: }
194:
195: // try to load all plugins
196: for (int i = 0; i < pluginFolders.length; i++) {
197: File folder = pluginFolders[i];
198:
199: File xmlFile = new File(folder, FILENAME_PLUGIN_XML);
200:
201: if (xmlFile == null || !xmlFile.exists()) {
202: // skip if it doesn't exist
203: continue;
204: }
205:
206: LOG.fine("registering plugin: " + folder);
207:
208: addPlugin(xmlFile);
209: }
210: }
211:
212: /**
213: * @see org.columba.api.plugin.IPluginManager#getPluginConfigFile(java.lang.String)
214: */
215: public File getPluginConfigFile(String id) {
216:
217: PluginMetadata metadata = (PluginMetadata) pluginMap.get(id);
218: File directory = metadata.getDirectory();
219: File configFile = new File(directory, FILENAME_CONFIG_XML);
220:
221: return configFile;
222: }
223:
224: /**
225: * @see org.columba.api.plugin.IPluginManager#getPluginMetadata(java.lang.String)
226: */
227: public PluginMetadata getPluginMetadata(String id) {
228: if (id == null)
229: throw new IllegalArgumentException("id == null");
230:
231: PluginMetadata metadata = (PluginMetadata) pluginMap.get(id);
232: return metadata;
233: }
234:
235: /**
236: * @see org.columba.api.plugin.IPluginManager#getInfoURL(java.lang.String)
237: */
238: public URL getInfoURL(String id) {
239: PluginMetadata metadata = (PluginMetadata) pluginMap.get(id);
240: File pluginDirectory = metadata.getDirectory();
241:
242: if (pluginDirectory == null) {
243: return null;
244: }
245:
246: try {
247: // try all possible version of readme files...
248: File infoFile = new File(pluginDirectory, "readme.html");
249:
250: if (!infoFile.exists()) {
251: infoFile = new File(pluginDirectory, "readme.txt");
252: }
253:
254: if (!infoFile.exists()) {
255: infoFile = new File(pluginDirectory, "Readme.html");
256: }
257:
258: if (!infoFile.exists()) {
259: infoFile = new File(pluginDirectory, "Readme.txt");
260: }
261:
262: if (infoFile.exists()) {
263: LOG.fine("infofile-URL=" + infoFile.toURL());
264:
265: return infoFile.toURL();
266: }
267: } catch (MalformedURLException ex) {
268: } // does not occur
269:
270: return null;
271: }
272:
273: /**
274: * @see org.columba.api.plugin.IPluginManager#getPluginMetadataEnumeration()
275: */
276: public Enumeration getPluginMetadataEnumeration() {
277: return pluginMap.elements();
278: }
279:
280: /**
281: * @see org.columba.api.plugin.IPluginManager#addPlugin(java.lang.String)
282: */
283: public String addPlugin(String resourcePath) {
284: if (resourcePath == null)
285: throw new IllegalArgumentException("resourcePath == null");
286:
287: // retrieve inputstream from resource
288: InputStream is;
289: try {
290: is = DiskIO.getResourceStream(resourcePath);
291: } catch (IOException e) {
292: e.printStackTrace();
293: // cancel
294: return null;
295: }
296:
297: // parse plugin metadata
298: Hashtable hashtable = new Hashtable();
299: PluginMetadata pluginMetadata = new ExtensionXMLParser()
300: .parsePlugin(new BufferedInputStream(is), hashtable);
301:
302: String id = pluginMetadata.getId();
303:
304: //
305: // Note: We intentionally don't remember internal plugins, because
306: // we don't want them to appear in the plugin manager currently.
307: //
308: // TODO: improve plugin manager dialog to support internal plugins
309: // which can't be removed, etc.
310:
311: // remember plugin metadata
312: // pluginMap.put(id, pluginMetadata);
313:
314: // register all extensions
315: parseExtensions(hashtable, pluginMetadata, true);
316:
317: return id;
318: }
319:
320: /**
321: * @see org.columba.api.plugin.IPluginManager#initExternalExtensionHandlers()
322: */
323: public void initExternalExtensionHandlers() {
324: // if no plugin directory exists -> return
325: if (pluginFolders == null || pluginFolders.length == 0) {
326: return;
327: }
328:
329: // try to load extensin handlers of all plugins
330: for (int i = 0; i < pluginFolders.length; i++) {
331: File folder = pluginFolders[i];
332:
333: File xmlFile = new File(folder,
334: FILENAME_EXTENSIONHANDLER_XML);
335:
336: if (xmlFile == null || !xmlFile.exists()) {
337: // skip if it doesn't exist
338: continue;
339: }
340:
341: BufferedInputStream buf;
342: try {
343: buf = new BufferedInputStream(new FileInputStream(
344: xmlFile));
345: LOG.fine("registering extension handler: " + folder);
346: addExtensionHandlers(buf);
347: } catch (FileNotFoundException e1) {
348: e1.printStackTrace();
349: // cancel
350: continue;
351: }
352: }
353: }
354:
355: /**
356: * @see org.columba.api.plugin.IPluginManager#addExtensionHandlers(java.io.InputStream)
357: */
358: public void addExtensionHandlers(InputStream is) {
359: Enumeration<ExtensionHandlerMetadata> e = new ExtensionXMLParser()
360: .parseExtensionHandlerList(is);
361: while (e.hasMoreElements()) {
362: ExtensionHandlerMetadata metadata = e.nextElement();
363:
364: IExtensionHandler handler = new ExtensionHandler(metadata
365: .getId(), metadata.getParent());
366:
367: addExtensionHandler(metadata.getId(), handler);
368: }
369: }
370:
371: /**
372: * @see org.columba.api.plugin.IPluginManager#addExtensionHandlers(java.lang.String)
373: */
374: public void addExtensionHandlers(String resourcePath) {
375: // retrieve inputstream from resource
376: InputStream is;
377: try {
378: is = DiskIO.getResourceStream(resourcePath);
379: } catch (IOException e) {
380: e.printStackTrace();
381: // cancel
382: return;
383: }
384:
385: addExtensionHandlers(is);
386: }
387: }
|