KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > messenger > container > PluginManager


1 /**
2  * $RCSfile: PluginManager.java,v $
3  * $Revision: 1.30 $
4  * $Date: 2005/07/29 22:55:32 $
5  *
6  * Copyright (C) 2004 Jive Software. All rights reserved.
7  *
8  * This software is published under the terms of the GNU Public License (GPL),
9  * a copy of which is included in this distribution.
10  */

11
12 package org.jivesoftware.messenger.container;
13
14 import org.dom4j.Attribute;
15 import org.dom4j.Document;
16 import org.dom4j.Element;
17 import org.dom4j.io.SAXReader;
18 import org.jivesoftware.admin.AdminConsole;
19 import org.jivesoftware.messenger.XMPPServer;
20 import org.jivesoftware.util.JiveGlobals;
21 import org.jivesoftware.util.Log;
22 import org.jivesoftware.util.Version;
23
24 import java.io.File JavaDoc;
25 import java.io.FileFilter JavaDoc;
26 import java.io.FileOutputStream JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.util.*;
29 import java.util.concurrent.ScheduledExecutorService JavaDoc;
30 import java.util.concurrent.ScheduledThreadPoolExecutor JavaDoc;
31 import java.util.concurrent.TimeUnit JavaDoc;
32 import java.util.concurrent.ConcurrentHashMap JavaDoc;
33 import java.util.jar.JarEntry JavaDoc;
34 import java.util.jar.JarFile JavaDoc;
35 import java.util.zip.ZipFile JavaDoc;
36
37 /**
38  * Loads and manages plugins. The <tt>plugins</tt> directory is monitored for any
39  * new plugins, and they are dynamically loaded.<p>
40  * <p/>
41  * An instance of this class can be obtained using:
42  * <p/>
43  * <tt>XMPPServer.getInstance().getPluginManager()</tt>
44  *
45  * @author Matt Tucker
46  * @see Plugin
47  * @see org.jivesoftware.messenger.XMPPServer#getPluginManager()
48  */

49 public class PluginManager {
50
51     private File JavaDoc pluginDirectory;
52     private Map JavaDoc<String JavaDoc, Plugin> plugins;
53     private Map JavaDoc<Plugin, PluginClassLoader> classloaders;
54     private Map JavaDoc<Plugin, File JavaDoc> pluginDirs;
55     private boolean setupMode = !(Boolean.valueOf(JiveGlobals.getXMLProperty("setup")).booleanValue());
56     private ScheduledExecutorService JavaDoc executor = null;
57     private Map JavaDoc<Plugin, PluginDevEnvironment> pluginDevelopment;
58     private Map JavaDoc<Plugin, List<String JavaDoc>> parentPluginMap;
59     private Map JavaDoc<Plugin, String JavaDoc> childPluginMap;
60     private Set<String JavaDoc> devPlugins;
61
62     /**
63      * Constructs a new plugin manager.
64      *
65      * @param pluginDir the plugin directory.
66      */

67     public PluginManager(File JavaDoc pluginDir) {
68         this.pluginDirectory = pluginDir;
69         plugins = new ConcurrentHashMap JavaDoc<String JavaDoc, Plugin>();
70         pluginDirs = new HashMap JavaDoc<Plugin, File JavaDoc>();
71         classloaders = new HashMap JavaDoc<Plugin, PluginClassLoader>();
72         pluginDevelopment = new HashMap JavaDoc<Plugin, PluginDevEnvironment>();
73         parentPluginMap = new HashMap JavaDoc<Plugin, List<String JavaDoc>>();
74         childPluginMap = new HashMap JavaDoc<Plugin, String JavaDoc>();
75         devPlugins = new HashSet<String JavaDoc>();
76     }
77
78     /**
79      * Starts plugins and the plugin monitoring service.
80      */

81     public void start() {
82         executor = new ScheduledThreadPoolExecutor JavaDoc(1);
83         executor.scheduleWithFixedDelay(new PluginMonitor(), 0, 15, TimeUnit.SECONDS);
84     }
85
86     /**
87      * Shuts down all running plugins.
88      */

89     public void shutdown() {
90         // Stop the plugin monitoring service.
91
if (executor != null) {
92             executor.shutdown();
93         }
94         // Shutdown all installed plugins.
95
for (Plugin plugin : plugins.values()) {
96             plugin.destroyPlugin();
97         }
98         plugins.clear();
99         pluginDirs.clear();
100         classloaders.clear();
101         pluginDevelopment.clear();
102         childPluginMap.clear();
103     }
104
105     /**
106      * Returns a Collection of all installed plugins.
107      *
108      * @return a Collection of all installed plugins.
109      */

110     public Collection<Plugin> getPlugins() {
111         return Collections.unmodifiableCollection(plugins.values());
112     }
113
114     /**
115      * Returns a plugin by name or <tt>null</tt> if a plugin with that name does not
116      * exist. The name is the name of the directory that the plugin is in such as
117      * "broadcast".
118      *
119      * @param name the name of the plugin.
120      * @return the plugin.
121      */

122     public Plugin getPlugin(String JavaDoc name) {
123         return plugins.get(name);
124     }
125
126     /**
127      * Returns the plugin's directory.
128      *
129      * @param plugin the plugin.
130      * @return the plugin's directory.
131      */

132     public File JavaDoc getPluginDirectory(Plugin plugin) {
133         return pluginDirs.get(plugin);
134     }
135
136     /**
137      * Loads a plug-in module into the container. Loading consists of the
138      * following steps:<ul>
139      * <p/>
140      * <li>Add all jars in the <tt>lib</tt> dir (if it exists) to the class loader</li>
141      * <li>Add all files in <tt>classes</tt> dir (if it exists) to the class loader</li>
142      * <li>Locate and load <tt>module.xml</tt> into the context</li>
143      * <li>For each jive.module entry, load the given class as a module and start it</li>
144      * <p/>
145      * </ul>
146      *
147      * @param pluginDir the plugin directory.
148      */

149     private void loadPlugin(File JavaDoc pluginDir) {
150         // Only load the admin plugin during setup mode.
151
if (setupMode && !(pluginDir.getName().equals("admin"))) {
152             return;
153         }
154         Log.debug("Loading plugin " + pluginDir.getName());
155         Plugin plugin = null;
156         try {
157             File JavaDoc pluginConfig = new File JavaDoc(pluginDir, "plugin.xml");
158             if (pluginConfig.exists()) {
159                 SAXReader saxReader = new SAXReader();
160                 Document pluginXML = saxReader.read(pluginConfig);
161
162                 // See if the plugin specifies a version of Jive Messenger
163
// required to run.
164
Element minServerVersion = (Element)pluginXML.selectSingleNode("/plugin/minServerVersion");
165                 if (minServerVersion != null) {
166                     String JavaDoc requiredVersion = minServerVersion.getTextTrim();
167                     Version version = XMPPServer.getInstance().getServerInfo().getVersion();
168                     String JavaDoc hasVersion = version.getMajor() + "." + version.getMinor() + "." +
169                             version.getMicro();
170                     if (hasVersion.compareTo(requiredVersion) < 0) {
171                         String JavaDoc msg = "Ignoring plugin " + pluginDir.getName() + ": requires " +
172                                 "server version " + requiredVersion;
173                         Log.warn(msg);
174                         System.out.println(msg);
175                         return;
176                     }
177                 }
178
179                 PluginClassLoader pluginLoader;
180
181                 // Check to see if this is a child plugin of another plugin. If it is, we
182
// re-use the parent plugin's class loader so that the plugins can interact.
183
Element parentPluginNode = (Element)pluginXML.selectSingleNode("/plugin/parentPlugin");
184                 if (parentPluginNode != null) {
185                     String JavaDoc parentPlugin = parentPluginNode.getTextTrim();
186                     // See if the parent is already loaded.
187
if (plugins.containsKey(parentPlugin)) {
188                         pluginLoader = classloaders.get(getPlugin(parentPlugin));
189                         pluginLoader.addDirectory(pluginDir);
190                     }
191                     else {
192                         // See if the parent plugin exists but just hasn't been loaded yet.
193
// This can only be the case if this plugin name is alphabetically before
194
// the parent.
195
if (pluginDir.getName().compareTo(parentPlugin) < 0) {
196                             // See if the parent exists.
197
File JavaDoc file = new File JavaDoc(pluginDir.getParentFile(), parentPlugin + ".jar");
198                             if (file.exists()) {
199                                 // Silently return. The child plugin will get loaded up on the next
200
// plugin load run after the parent.
201
return;
202                             }
203                             else {
204                                 file = new File JavaDoc(pluginDir.getParentFile(), parentPlugin + ".war");
205                                 if (file.exists()) {
206                                     // Silently return. The child plugin will get loaded up on the next
207
// plugin load run after the parent.
208
return;
209                                 }
210                                 else {
211                                     String JavaDoc msg = "Ignoring plugin " + pluginDir.getName() + ": parent plugin " +
212                                     parentPlugin + " not present.";
213                                     Log.warn(msg);
214                                     System.out.println(msg);
215                                     return;
216                                 }
217                             }
218                         }
219                         else {
220                             String JavaDoc msg = "Ignoring plugin " + pluginDir.getName() + ": parent plugin " +
221                                 parentPlugin + " not present.";
222                             Log.warn(msg);
223                             System.out.println(msg);
224                             return;
225                         }
226                     }
227                 }
228                 // This is not a child plugin, so create a new class loader.
229
else {
230                     pluginLoader = new PluginClassLoader(pluginDir);
231                 }
232
233                 // Check to see if development mode is turned on for the plugin. If it is,
234
// configure dev mode.
235
Element developmentNode = (Element)pluginXML.selectSingleNode("/plugin/development");
236                 PluginDevEnvironment dev = null;
237                 if (developmentNode != null) {
238                     Element webRoot = (Element)developmentNode.selectSingleNode(
239                             "/plugin/development/webRoot");
240                     Element classesDir = (Element)developmentNode.selectSingleNode(
241                             "/plugin/development/classesDir");
242
243                     dev = new PluginDevEnvironment();
244
245                     String JavaDoc wrd = webRoot.getTextTrim();
246                     File JavaDoc webRootDir = new File JavaDoc(wrd);
247                     if (!webRootDir.exists()) {
248                         // ok, let's try it relative from this plugin dir?
249
webRootDir = new File JavaDoc(pluginDir, wrd);
250                     }
251
252                     if (webRootDir.exists()) {
253                         dev.setWebRoot(webRootDir);
254                     }
255
256                     String JavaDoc cd = classesDir.getTextTrim();
257                     File JavaDoc classes = new File JavaDoc(cd);
258                     if (!classes.exists()) {
259                         // ok, let's try it relative from this plugin dir?
260
classes = new File JavaDoc(pluginDir, cd);
261                     }
262
263                     if (classes.exists()) {
264                         dev.setClassesDir(classes);
265                         pluginLoader.addURL(classes.getAbsoluteFile().toURL());
266                     }
267                 }
268
269                 pluginLoader.initialize();
270
271                 String JavaDoc className = pluginXML.selectSingleNode("/plugin/class").getText();
272                 plugin = (Plugin)pluginLoader.loadClass(className).newInstance();
273                 plugin.initializePlugin(this, pluginDir);
274                 plugins.put(pluginDir.getName(), plugin);
275                 pluginDirs.put(plugin, pluginDir);
276
277                 // If this is a child plugin, register it as such.
278
if (parentPluginNode != null) {
279                     String JavaDoc parentPlugin = parentPluginNode.getTextTrim();
280                     List<String JavaDoc> childrenPlugins = parentPluginMap.get(plugins.get(parentPlugin));
281                     if (childrenPlugins == null) {
282                         childrenPlugins = new ArrayList<String JavaDoc>();
283                         parentPluginMap.put(plugins.get(parentPlugin), childrenPlugins);
284                     }
285                     childrenPlugins.add(pluginDir.getName());
286                     // Also register child to parent relationship.
287
childPluginMap.put(plugin, parentPlugin);
288                 }
289                 else {
290                     // Only register the class loader in the case of this not being
291
// a child plugin.
292
classloaders.put(plugin, pluginLoader);
293                 }
294
295                 // Load any JSP's defined by the plugin.
296
File JavaDoc webXML = new File JavaDoc(pluginDir, "web" + File.separator + "WEB-INF" +
297                         File.separator + "web.xml");
298                 if (webXML.exists()) {
299                     PluginServlet.registerServlets(this, plugin, webXML);
300                 }
301                 // Load any custom-defined servlets.
302
File JavaDoc customWebXML = new File JavaDoc(pluginDir, "web" + File.separator + "WEB-INF" +
303                         File.separator + "web-custom.xml");
304                 if (customWebXML.exists()) {
305                     PluginServlet.registerServlets(this, plugin, customWebXML);
306                 }
307
308                 if (dev != null) {
309                     pluginDevelopment.put(plugin, dev);
310                 }
311
312                 // If there a <adminconsole> section defined, register it.
313
Element adminElement = (Element)pluginXML.selectSingleNode("/plugin/adminconsole");
314                 if (adminElement != null) {
315                     // If global images are specified, override their URL.
316
Element imageEl = (Element)adminElement.selectSingleNode(
317                             "/plugin/adminconsole/global/logo-image");
318                     if (imageEl != null) {
319                         imageEl.setText("plugins/" + pluginDir.getName() + "/" + imageEl.getText());
320                     }
321                     imageEl = (Element)adminElement.selectSingleNode(
322                             "/plugin/adminconsole/global/login-image");
323                     if (imageEl != null) {
324                         imageEl.setText("plugins/" + pluginDir.getName() + "/" + imageEl.getText());
325                     }
326                     // Modify all the URL's in the XML so that they are passed through
327
// the plugin servlet correctly.
328
List urls = adminElement.selectNodes("//@url");
329                     for (int i = 0; i < urls.size(); i++) {
330                         Attribute attr = (Attribute)urls.get(i);
331                         attr.setValue("plugins/" + pluginDir.getName() + "/" + attr.getValue());
332                     }
333                     AdminConsole.addModel(pluginDir.getName(), adminElement);
334                 }
335             }
336             else {
337                 Log.warn("Plugin " + pluginDir + " could not be loaded: no plugin.xml file found");
338             }
339         }
340         catch (Exception JavaDoc e) {
341             Log.error("Error loading plugin", e);
342         }
343     }
344
345     /**
346      * Unloads a plugin. The {@link Plugin#destroyPlugin()} method will be called and then
347      * any resources will be released. The name should be the name of the plugin directory
348      * and not the name as given by the plugin meta-data. This method only removes
349      * the plugin but does not delete the plugin JAR file. Therefore, if the plugin JAR
350      * still exists after this method is called, the plugin will be started again the next
351      * time the plugin monitor process runs. This is useful for "restarting" plugins.<p>
352      * <p/>
353      * This method is called automatically when a plugin's JAR file is deleted.
354      *
355      * @param pluginName the name of the plugin to unload.
356      */

357     public void unloadPlugin(String JavaDoc pluginName) {
358         Log.debug("Unloading plugin " + pluginName);
359
360         Plugin plugin = plugins.get(pluginName);
361         if (plugin == null) {
362             return;
363         }
364
365         // See if any child plugins are defined.
366
if (parentPluginMap.containsKey(plugin)) {
367             for (String JavaDoc childPlugin : parentPluginMap.get(plugin)) {
368                 Log.debug("Unloading child plugin: " + childPlugin);
369                 unloadPlugin(childPlugin);
370             }
371             parentPluginMap.remove(plugin);
372         }
373
374         File JavaDoc webXML = new File JavaDoc(pluginDirectory, pluginName + File.separator + "web" + File.separator + "WEB-INF" +
375                 File.separator + "web.xml");
376         if (webXML.exists()) {
377             AdminConsole.removeModel(pluginName);
378             PluginServlet.unregisterServlets(webXML);
379         }
380         File JavaDoc customWebXML = new File JavaDoc(pluginDirectory, pluginName + File.separator + "web" + File.separator + "WEB-INF" +
381                 File.separator + "web-custom.xml");
382         if (customWebXML.exists()) {
383             PluginServlet.unregisterServlets(customWebXML);
384         }
385
386         plugin.destroyPlugin();
387         PluginClassLoader classLoader = classloaders.get(plugin);
388         // Destroy class loader if defined, which it won't be if this is a child plugin.
389
if (classLoader != null) {
390             classLoader.destroy();
391         }
392         plugins.remove(pluginName);
393         pluginDirs.remove(plugin);
394         classloaders.remove(plugin);
395
396         // See if this is a child plugin. If it is, we should unload
397
// the parent plugin as well.
398
if (childPluginMap.containsKey(plugin)) {
399             unloadPlugin(childPluginMap.get(plugin));
400         }
401         childPluginMap.remove(plugin);
402     }
403
404     /**
405      * Loads a class from the classloader of a plugin.
406      *
407      * @param plugin the plugin.
408      * @param className the name of the class to load.
409      * @return the class.
410      * @throws ClassNotFoundException if the class was not found.
411      * @throws IllegalAccessException if not allowed to access the class.
412      * @throws InstantiationException if the class could not be created.
413      */

414     public Class JavaDoc loadClass(Plugin plugin, String JavaDoc className) throws ClassNotFoundException JavaDoc,
415             IllegalAccessException JavaDoc, InstantiationException JavaDoc
416     {
417         PluginClassLoader loader = classloaders.get(plugin);
418         return loader.loadClass(className);
419     }
420
421     /**
422      * Returns a plugin's dev environment if development mode is enabled for
423      * the plugin.
424      *
425      * @param plugin the plugin.
426      * @return the plugin dev environment, or <tt>null</tt> if development
427      * mode is not enabled for the plugin.
428      */

429     public PluginDevEnvironment getDevEnvironment(Plugin plugin) {
430         return pluginDevelopment.get(plugin);
431     }
432
433     /**
434      * Returns the name of a plugin. The value is retrieved from the plugin.xml file
435      * of the plugin. If the value could not be found, <tt>null</tt> will be returned.
436      * Note that this value is distinct from the name of the plugin directory.
437      *
438      * @param plugin the plugin.
439      * @return the plugin's name.
440      */

441     public String JavaDoc getName(Plugin plugin) {
442         String JavaDoc name = getElementValue(plugin, "/plugin/name");
443         if (name != null) {
444             return name;
445         }
446         else {
447             return pluginDirs.get(plugin).getName();
448         }
449     }
450
451     /**
452      * Returns the description of a plugin. The value is retrieved from the plugin.xml file
453      * of the plugin. If the value could not be found, <tt>null</tt> will be returned.
454      *
455      * @param plugin the plugin.
456      * @return the plugin's description.
457      */

458     public String JavaDoc getDescription(Plugin plugin) {
459         return getElementValue(plugin, "/plugin/description");
460     }
461
462     /**
463      * Returns the author of a plugin. The value is retrieved from the plugin.xml file
464      * of the plugin. If the value could not be found, <tt>null</tt> will be returned.
465      *
466      * @param plugin the plugin.
467      * @return the plugin's author.
468      */

469     public String JavaDoc getAuthor(Plugin plugin) {
470         return getElementValue(plugin, "/plugin/author");
471     }
472
473     /**
474      * Returns the version of a plugin. The value is retrieved from the plugin.xml file
475      * of the plugin. If the value could not be found, <tt>null</tt> will be returned.
476      *
477      * @param plugin the plugin.
478      * @return the plugin's version.
479      */

480     public String JavaDoc getVersion(Plugin plugin) {
481         return getElementValue(plugin, "/plugin/version");
482     }
483
484     /**
485      * Returns the value of an element selected via an xpath expression from
486      * a Plugin's plugin.xml file.
487      *
488      * @param plugin the plugin.
489      * @param xpath the xpath expression.
490      * @return the value of the element selected by the xpath expression.
491      */

492     private String JavaDoc getElementValue(Plugin plugin, String JavaDoc xpath) {
493         File JavaDoc pluginDir = pluginDirs.get(plugin);
494         if (pluginDir == null) {
495             return null;
496         }
497         try {
498             File JavaDoc pluginConfig = new File JavaDoc(pluginDir, "plugin.xml");
499             if (pluginConfig.exists()) {
500                 SAXReader saxReader = new SAXReader();
501                 Document pluginXML = saxReader.read(pluginConfig);
502                 Element element = (Element)pluginXML.selectSingleNode(xpath);
503                 if (element != null) {
504                     return element.getTextTrim();
505                 }
506             }
507         }
508         catch (Exception JavaDoc e) {
509             Log.error(e);
510         }
511         return null;
512     }
513
514     /**
515      * A service that monitors the plugin directory for plugins. It periodically
516      * checks for new plugin JAR files and extracts them if they haven't already
517      * been extracted. Then, any new plugin directories are loaded.
518      */

519     private class PluginMonitor implements Runnable JavaDoc {
520
521         public void run() {
522             try {
523                 // look for plugin directories specified as a system property
524
String JavaDoc pluginDirs = System.getProperty("pluginDirs");
525                 if (pluginDirs != null) {
526                     StringTokenizer st = new StringTokenizer(pluginDirs, ", ");
527                     while (st.hasMoreTokens()) {
528                         String JavaDoc dir = st.nextToken();
529                         if (!devPlugins.contains(dir)) {
530                             loadPlugin(new File JavaDoc(dir));
531                             devPlugins.add(dir);
532                         }
533                     }
534                 }
535
536                 File JavaDoc[] jars = pluginDirectory.listFiles(new FileFilter JavaDoc() {
537                     public boolean accept(File JavaDoc pathname) {
538                         String JavaDoc fileName = pathname.getName().toLowerCase();
539                         return (fileName.endsWith(".jar") || fileName.endsWith(".war"));
540                     }
541                 });
542
543                 for (int i = 0; i < jars.length; i++) {
544                     File JavaDoc jarFile = jars[i];
545                     String JavaDoc pluginName = jarFile.getName().substring(0,
546                             jarFile.getName().length() - 4).toLowerCase();
547                     // See if the JAR has already been exploded.
548
File JavaDoc dir = new File JavaDoc(pluginDirectory, pluginName);
549                     // If the JAR hasn't been exploded, do so.
550
if (!dir.exists()) {
551                         unzipPlugin(pluginName, jarFile, dir);
552                     }
553                     // See if the JAR is newer than the directory. If so, the plugin
554
// needs to be unloaded and then reloaded.
555
else if (jarFile.lastModified() > dir.lastModified()) {
556                         unloadPlugin(pluginName);
557                         // Ask the system to clean up references.
558
System.gc();
559                         int count = 0;
560                         while (!deleteDir(dir) && count < 5) {
561                             Log.error("Error unloading plugin " + pluginName + ". " +
562                                     "Will attempt again momentarily.");
563                             Thread.sleep(5000);
564                             count++;
565                         }
566                         // Now unzip the plugin.
567
unzipPlugin(pluginName, jarFile, dir);
568                     }
569                 }
570
571                 File JavaDoc[] dirs = pluginDirectory.listFiles(new FileFilter JavaDoc() {
572                     public boolean accept(File JavaDoc pathname) {
573                         return pathname.isDirectory();
574                     }
575                 });
576
577                 // Sort the list of directories so that the "admin" plugin is always
578
// first in the list.
579
Arrays.sort(dirs, new Comparator<File JavaDoc>() {
580                     public int compare(File JavaDoc file1, File JavaDoc file2) {
581                         if (file1.getName().equals("admin")) {
582                             return -1;
583                         }
584                         else if (file2.getName().equals("admin")) {
585                             return 1;
586                         }
587                         else
588                             return file1.compareTo(file2);
589                     }
590                 });
591
592                 // See if any currently running plugins need to be unloaded
593
// due to the JAR file being deleted (ignore admin plugin).
594
// Build a list of plugins to delete first so that the plugins
595
// keyset isn't modified as we're iterating through it.
596
List<String JavaDoc> toDelete = new ArrayList<String JavaDoc>();
597                 for (File JavaDoc pluginDir : dirs) {
598                     String JavaDoc pluginName = pluginDir.getName();
599                     if (pluginName.equals("admin")) {
600                         continue;
601                     }
602                     File JavaDoc file = new File JavaDoc(pluginDirectory, pluginName + ".jar");
603                     if (!file.exists()) {
604                         file = new File JavaDoc(pluginDirectory, pluginName + ".war");
605                         if (!file.exists()) {
606                             toDelete.add(pluginName);
607                         }
608                     }
609                 }
610                 for (String JavaDoc pluginName : toDelete) {
611                     unloadPlugin(pluginName);
612                     System.gc();
613                     int count = 0;
614                     File JavaDoc dir = new File JavaDoc(pluginDirectory, pluginName);
615                     while (!deleteDir(dir) && count < 5) {
616                         Log.error("Error unloading plugin " + pluginName + ". " +
617                                 "Will attempt again momentarily.");
618                         Thread.sleep(5000);
619                         count++;
620                     }
621                 }
622
623                 // Load all plugins that need to be loaded.
624
for (int i = 0; i < dirs.length; i++) {
625                     File JavaDoc dirFile = dirs[i];
626                     // If the plugin hasn't already been started, start it.
627
if (dirFile.exists() && !plugins.containsKey(dirFile.getName())) {
628                         loadPlugin(dirFile);
629                     }
630                 }
631             }
632             catch (Exception JavaDoc e) {
633                 Log.error(e);
634             }
635         }
636
637         /**
638          * Unzips a plugin from a JAR file into a directory. If the JAR file
639          * isn't a plugin, this method will do nothing.
640          *
641          * @param pluginName the name of the plugin.
642          * @param file the JAR file
643          * @param dir the directory to extract the plugin to.
644          */

645         private void unzipPlugin(String JavaDoc pluginName, File JavaDoc file, File JavaDoc dir) {
646             try {
647                 ZipFile JavaDoc zipFile = new JarFile JavaDoc(file);
648                 // Ensure that this JAR is a plugin.
649
if (zipFile.getEntry("plugin.xml") == null) {
650                     return;
651                 }
652                 dir.mkdir();
653                 Log.debug("Extracting plugin: " + pluginName);
654                 for (Enumeration e = zipFile.entries(); e.hasMoreElements();) {
655                     JarEntry JavaDoc entry = (JarEntry JavaDoc)e.nextElement();
656                     File JavaDoc entryFile = new File JavaDoc(dir, entry.getName());
657                     // Ignore any manifest.mf entries.
658
if (entry.getName().toLowerCase().endsWith("manifest.mf")) {
659                         continue;
660                     }
661                     if (!entry.isDirectory()) {
662                         entryFile.getParentFile().mkdirs();
663                         FileOutputStream JavaDoc out = new FileOutputStream JavaDoc(entryFile);
664                         InputStream JavaDoc zin = zipFile.getInputStream(entry);
665                         byte[] b = new byte[512];
666                         int len = 0;
667                         while ((len = zin.read(b)) != -1) {
668                             out.write(b, 0, len);
669                         }
670                         out.flush();
671                         out.close();
672                         zin.close();
673                     }
674                 }
675                 zipFile.close();
676                 zipFile = null;
677             }
678             catch (Exception JavaDoc e) {
679                 Log.error(e);
680             }
681         }
682
683         /**
684          * Deletes a directory.
685          */

686         public boolean deleteDir(File JavaDoc dir) {
687             if (dir.isDirectory()) {
688                 String JavaDoc[] children = dir.list();
689                 for (int i = 0; i < children.length; i++) {
690                     boolean success = deleteDir(new File JavaDoc(dir, children[i]));
691                     if (!success) {
692                         return false;
693                     }
694                 }
695             }
696             return dir.delete();
697         }
698     }
699 }
Popular Tags