KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > core > plugin > Extension


1 // The contents of this file are subject to the Mozilla Public License Version
2
// 1.1
3
//(the "License"); you may not use this file except in compliance with the
4
//License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
5
//
6
//Software distributed under the License is distributed on an "AS IS" basis,
7
//WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
8
//for the specific language governing rights and
9
//limitations under the License.
10
//
11
//The Original Code is "The Columba Project"
12
//
13
//The Initial Developers of the Original Code are Frederik Dietz and Timo
14
// Stich.
15
//Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
16
//
17
//All Rights Reserved.
18
package org.columba.core.plugin;
19
20 import java.io.File JavaDoc;
21 import java.lang.reflect.Constructor JavaDoc;
22 import java.net.MalformedURLException JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Vector JavaDoc;
26
27 import org.columba.api.plugin.ExtensionMetadata;
28 import org.columba.api.plugin.IExtension;
29 import org.columba.api.plugin.IExtensionInterface;
30 import org.columba.api.plugin.PluginException;
31 import org.columba.api.plugin.PluginMetadata;
32 import org.columba.core.logging.Logging;
33 import org.columba.core.main.Main;
34
35 /**
36  * An extension providing the metadata of an extension and the runtime context
37  * for instanciation.
38  *
39  * @author fdietz
40  */

41 public class Extension implements IExtension {
42
43     private static final String JavaDoc FILE_PLUGIN_JAR = "plugin.jar";
44
45     private static final java.util.logging.Logger JavaDoc LOG = java.util.logging.Logger
46             .getLogger("org.columba.core.plugin");
47
48     private ExtensionMetadata metadata;
49
50     private PluginMetadata pluginMetadata;
51
52     private boolean internalPlugin;
53
54     private IExtensionInterface cachedInstance;
55
56     /**
57      * Enabled by default. But, in case of an error on instanciation its
58      * disabled.
59      */

60     private boolean enabled = true;
61
62     /**
63      * Constructor used by internal extensions
64      *
65      * @param metadata
66      */

67     public Extension(ExtensionMetadata metadata, boolean internal) {
68         this.metadata = metadata;
69
70         internalPlugin = internal;
71     }
72
73     /**
74      * Constructor used by external extensions.
75      *
76      * @param pluginMetadata
77      * @param metadata
78      */

79     public Extension(PluginMetadata pluginMetadata, ExtensionMetadata metadata) {
80         this.metadata = metadata;
81         this.pluginMetadata = pluginMetadata;
82
83         internalPlugin = false;
84     }
85
86     /**
87      * @see org.columba.api.plugin.IExtension#getMetadata()
88      */

89     public ExtensionMetadata getMetadata() {
90         return metadata;
91     }
92
93     /**
94      * @see org.columba.api.plugin.IExtension#instanciateExtension(java.lang.Object[])
95      */

96     public IExtensionInterface instanciateExtension(Object JavaDoc[] arguments)
97             throws PluginException {
98
99         if (!enabled)
100             throw new PluginException("Extension <" + getMetadata().getId()
101                     + "> was disabled due to a former instanciation error");
102
103         String JavaDoc id = null;
104         File JavaDoc pluginDirectory = null;
105
106         String JavaDoc className = metadata.getClassname();
107
108         if (pluginMetadata != null) {
109             id = pluginMetadata.getId();
110             // if external plugin, we need the directory of it
111
pluginDirectory = pluginMetadata.getDirectory();
112         }
113
114         IExtensionInterface plugin = null;
115
116         // if available, load cached instance
117
if ((metadata.isSingleton()) && (cachedInstance != null)) {
118             plugin = cachedInstance;
119
120         } else {
121
122             try {
123
124                 if (isInternal())
125
126                     // use default Java classlodaer
127
plugin = instanciateJavaClass(className, arguments);
128
129                 else {
130                     //
131
// external plugin
132
//
133

134                     // just in case that someone who developers on a plugin
135
// adds the plugin files to his classpath, we try to
136
// load
137
// them with the default classloader
138

139                     // use default Java classlodaer
140

141                     // try {
142
// plugin = instanciateJavaClass(className, arguments);
143
// if (plugin != null)
144
// return plugin;
145
//
146
// } catch (Exception e) {
147
// //handleException(e);
148
// } catch (Error e) {
149
// //handleException(e);
150
// }
151

152                     // use external Java URL classloader
153
plugin = instanciateExternalJavaClass(arguments,
154                             pluginDirectory, className);
155
156                 }
157
158                 // remember instance
159
if (metadata.isSingleton())
160                     cachedInstance = plugin;
161
162             } catch (Exception JavaDoc e) {
163                 logErrorMessage(e);
164
165                 // disable extension
166
enabled = false;
167
168                 throw new PluginException(this, e);
169             } catch (Error JavaDoc e) {
170                 logErrorMessage(e);
171
172                 // disable extension
173
enabled = false;
174
175                 throw new PluginException(this, e);
176             }
177
178         }
179         return plugin;
180     }
181
182     /**
183      * @param e
184      */

185     private void logErrorMessage(Throwable JavaDoc e) {
186         if (e.getCause() != null) {
187             LOG.severe(e.getCause().getMessage());
188             if (Logging.DEBUG)
189                 e.getCause().printStackTrace();
190         } else {
191             LOG.severe(e.getMessage());
192             if (Logging.DEBUG)
193                 e.printStackTrace();
194         }
195     }
196
197     /**
198      * Instanciate external Java class which is specified using the
199      * <code>plugin.xml</code> descriptor file.
200      * <p>
201      * Currently, this is not used!
202      *
203      * @param arguments
204      * class constructor arguments
205      * @param pluginDirectory
206      * plugin directory
207      * @param className
208      * extension classname
209      * @return extension instance
210      * @throws Exception
211      */

212     private IExtensionInterface instanciateExternalJavaClass(
213             Object JavaDoc[] arguments, File JavaDoc pluginDirectory, String JavaDoc className)
214             throws Exception JavaDoc {
215         IExtensionInterface plugin;
216         URL JavaDoc[] urls = null;
217
218         // all Java plugins package their class-files in "plugin.jar"
219
String JavaDoc jarFilename = Extension.FILE_PLUGIN_JAR;
220
221         try {
222             urls = getURLs(pluginDirectory, jarFilename);
223         } catch (MalformedURLException JavaDoc e) {
224             // should never happen
225
e.printStackTrace();
226         }
227
228         //
229
// @author: fdietz
230
// WORKAROUND:
231
// we simply append URLs to the existing global class loader
232
// and use the same as parent
233
//
234
// Note, that we create a new URL classloader for every class
235
// we instanciate. We might want to support hot-swapping
236
// of changed classes later.
237

238         // append URLs to global classloader
239
Main.mainClassLoader.addURLs(urls);
240
241         //plugin = instanciateJavaClass(className, arguments);
242

243         // create new class loader using the global class loader as parent
244
ExternalClassLoader loader = new ExternalClassLoader(urls,
245                  Main.mainClassLoader);
246          plugin = (IExtensionInterface) loader.instanciate(className,
247          arguments);
248
249         return plugin;
250     }
251
252     private IExtensionInterface instanciateJavaClass(String JavaDoc className,
253             Object JavaDoc[] arguments) throws Exception JavaDoc {
254
255         if (className == null)
256             throw new IllegalArgumentException JavaDoc("className == null");
257
258         IExtensionInterface plugin = null;
259
260         // use our global class loader
261
ClassLoader JavaDoc loader = Main.mainClassLoader;
262         
263         Class JavaDoc actClass;
264
265         actClass = loader.loadClass(className);
266
267         //
268
// we can't just load the first constructor
269
// -> go find the correct constructor based
270
// -> based on the arguments
271
//
272
if ((arguments == null) || (arguments.length == 0)) {
273
274             plugin = (IExtensionInterface) actClass.newInstance();
275
276         } else {
277             Constructor JavaDoc constructor;
278
279             constructor = ClassLoaderHelper
280                     .findConstructor(arguments, actClass);
281
282             // couldn't find correct constructor
283
if (constructor == null) {
284                 LOG.severe("Couldn't find constructor for " + className
285                         + " with matching argument-list: ");
286                 for (int i = 0; i < arguments.length; i++) {
287                     LOG.severe("argument[" + i + "]=" + arguments[i]);
288                 }
289
290                 return null;
291             } else {
292
293                 plugin = (IExtensionInterface) constructor
294                         .newInstance(arguments);
295
296             }
297
298         }
299
300         return plugin;
301     }
302
303     /**
304      * @see org.columba.api.plugin.IExtension#isInternal()
305      */

306     public boolean isInternal() {
307         return internalPlugin;
308     }
309
310     /**
311      * @see java.lang.Object#toString()
312      */

313     public String JavaDoc toString() {
314         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
315         buf.append("id=" + metadata.getId());
316         buf.append("class=" + metadata.getClassname());
317
318         return buf.toString();
319     }
320
321     /**
322      * Generate array of all URLs which are used to prefill the URLClassloader.
323      * <p>
324      * All jar-files in /lib directory are automatically added.
325      *
326      * @param file
327      * plugin directory
328      * @param jarFile
329      * jar-file containing the extension code
330      * @return URL array
331      * @throws MalformedURLException
332      */

333     private URL JavaDoc[] getURLs(File JavaDoc file, String JavaDoc jarFile)
334             throws MalformedURLException JavaDoc {
335         if (file == null)
336             throw new IllegalArgumentException JavaDoc("file == null");
337         if (jarFile == null)
338             throw new IllegalArgumentException JavaDoc("jarFile == null");
339
340         List JavaDoc urlList = new Vector JavaDoc();
341
342         // plugin-directory
343
String JavaDoc path = file.getPath();
344
345         if (jarFile != null) {
346             URL JavaDoc jarURL = new File JavaDoc(file, jarFile).toURL();
347             urlList.add(jarURL);
348         }
349
350         URL JavaDoc newURL = new File JavaDoc(path).toURL();
351         urlList.add(newURL);
352
353         // we add every jar-file in /lib, too
354
// plugin-directory
355

356         File JavaDoc lib = new File JavaDoc(file, "lib");
357
358         if (lib.exists()) {
359             File JavaDoc[] libList = lib.listFiles();
360
361             for (int i = 0; i < libList.length; i++) {
362                 File JavaDoc f = libList[i];
363
364                 if (f.getName().endsWith(".jar")) {
365                     // jar-file found
366
urlList.add(f.toURL());
367                 } else if (f.isDirectory()) {
368                     urlList.add(f.toURL());
369                 }
370             }
371         }
372
373         URL JavaDoc[] url = new URL JavaDoc[urlList.size()];
374
375         for (int i = 0; i < urlList.size(); i++) {
376             url[i] = (URL JavaDoc) urlList.get(i);
377         }
378
379         if (Logging.DEBUG) {
380             for (int i = 0; i < url.length; i++) {
381                 LOG.finest("url[" + i + "]=" + url[i]);
382             }
383         }
384
385         return url;
386     }
387
388     public void setInternal(boolean internal) {
389         this.internalPlugin = internal;
390     }
391
392     /**
393      * Returns enabled by default. But, in case of an error on instanciation its
394      * disabled.
395      *
396      * @return enabled by default. But, in case of an error on instanciation its
397      */

398     public boolean isEnabled() {
399         // TODO Auto-generated method stub
400
return false;
401     }
402
403 }
404
Popular Tags