]> source.dussan.org Git - pf4j.git/commitdiff
added PluginState
authorDecebal Suiu <decebal.suiu@gmail.com>
Mon, 19 Nov 2012 11:38:03 +0000 (13:38 +0200)
committerDecebal Suiu <decebal.suiu@gmail.com>
Mon, 19 Nov 2012 11:38:03 +0000 (13:38 +0200)
README.md
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
pf4j/src/main/java/ro/fortsoft/pf4j/PluginDescriptor.java
pf4j/src/main/java/ro/fortsoft/pf4j/PluginState.java [new file with mode: 0644]
pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java
pf4j/src/main/java/ro/fortsoft/pf4j/util/CompoundClassLoader.java [new file with mode: 0644]
pf4j/src/main/java/ro/fortsoft/pf4j/util/UberClassLoader.java [deleted file]

index dc4e01e6e49c894dc3e0396e729101208a6d8c55..1914775c188d8372d4dff8ffa20412c8e2e161d4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@ declared by application or other plugins. Also a plugin can define extension poi
 
 Components
 -------------------
+
 - **Plugin** is the base class for all plugins types. Each plugin is loaded into a separate class loader to avoid conflicts.
 - **PluginManager** is used for all aspects of plugins management (loading, starting, stopping).
 - **ExtensionPoint** is a point in the application where custom code can be invoked. It's a java interface marker.   
@@ -14,6 +15,7 @@ Any java interface or abstract class can be marked as an extension point (implem
 
 Artifacts
 -------------------
+
 - PF4J `pf4j` (jar)
 - PF4J Demo `pf4j-demo` (executable jar)
 
@@ -34,6 +36,7 @@ where ${pf4j.version} is the last pf4j version.
 
 How to use
 -------------------
+
 It's very simple to add pf4j in your application:
 
     public static void main(String[] args) {
index 1081526db28bcc3a98bb47b9d2e472ff3186827f..750e334e357cee3130cadcc10e787fcbbf1e8de9 100644 (file)
@@ -24,8 +24,8 @@ import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import ro.fortsoft.pf4j.util.CompoundClassLoader;
 import ro.fortsoft.pf4j.util.DirectoryFilter;
-import ro.fortsoft.pf4j.util.UberClassLoader;
 import ro.fortsoft.pf4j.util.Unzip;
 import ro.fortsoft.pf4j.util.ZipFilter;
 
@@ -82,8 +82,11 @@ public class DefaultPluginManager implements PluginManager {
      */
     private List<PluginWrapper> startedPlugins;
     
-    private UberClassLoader uberClassLoader;
-
+    /**
+     * A compound class loader of resolved plugins. 
+     */
+    private CompoundClassLoader compoundClassLoader;
+    
     /**
      * Th plugins directory is supplied by System.getProperty("pf4j.pluginsDir", "plugins").
      */
@@ -108,16 +111,18 @@ public class DefaultPluginManager implements PluginManager {
         disabledPlugins = new ArrayList<PluginWrapper>();
         startedPlugins = new ArrayList<PluginWrapper>();
         pluginDescriptorFinder = new DefaultPluginDescriptorFinder();
-        uberClassLoader = new UberClassLoader();
-        extensionFinder = new DefaultExtensionFinder(uberClassLoader);
+        compoundClassLoader = new CompoundClassLoader();
+        extensionFinder = new DefaultExtensionFinder(compoundClassLoader);
         
         System.setProperty("pf4j.pluginsDir", pluginsDirectory.getAbsolutePath());
     }
 
+    @Override
     public List<PluginWrapper> getPlugins() {
         return new ArrayList<PluginWrapper>(plugins.values());
     }
 
+    @Override
        public List<PluginWrapper> getResolvedPlugins() {
                return resolvedPlugins;
        }
@@ -126,6 +131,7 @@ public class DefaultPluginManager implements PluginManager {
                return plugins.get(pluginId);
        }
 
+       @Override
     public List<PluginWrapper> getUnresolvedPlugins() {
                return unresolvedPlugins;
        }
@@ -134,6 +140,7 @@ public class DefaultPluginManager implements PluginManager {
                return disabledPlugins;
        }
 
+       @Override
        public List<PluginWrapper> getStartedPlugins() {
                return startedPlugins;
        }
@@ -141,11 +148,13 @@ public class DefaultPluginManager implements PluginManager {
     /**
      * Start all active plugins.
      */
+       @Override
     public void startPlugins() {
         for (PluginWrapper pluginWrapper : resolvedPlugins) {
             try {
                LOG.info("Start plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'");
                                pluginWrapper.getPlugin().start();
+                               pluginWrapper.setPluginState(PluginState.STARTED);
                                startedPlugins.add(pluginWrapper);
                        } catch (PluginException e) {
                                LOG.error(e.getMessage(), e);
@@ -156,6 +165,7 @@ public class DefaultPluginManager implements PluginManager {
     /**
      * Stop all active plugins.
      */
+    @Override
     public void stopPlugins() {
        // stop started plugins in reverse order
        Collections.reverse(startedPlugins);
@@ -163,6 +173,7 @@ public class DefaultPluginManager implements PluginManager {
             try {
                LOG.info("Stop plugin '" + pluginWrapper.getDescriptor().getPluginId() + "'");
                pluginWrapper.getPlugin().stop();
+               pluginWrapper.setPluginState(PluginState.STOPPED);
                        } catch (PluginException e) {
                                LOG.error(e.getMessage(), e);
                        }
@@ -172,6 +183,7 @@ public class DefaultPluginManager implements PluginManager {
     /**
      * Load plugins.
      */
+    @Override
     public void loadPlugins() {
        // check for plugins directory
         if (!pluginsDirectory.exists() || !pluginsDirectory.isDirectory()) {
@@ -218,10 +230,12 @@ public class DefaultPluginManager implements PluginManager {
     /**
      * Get plugin class loader for this path.
      */
+    @Override
     public PluginClassLoader getPluginClassLoader(String pluginId) {
        return pluginClassLoaders.get(pluginId);
     }
 
+    @Override
        public <T> List<T> getExtensions(Class<T> type) {
                List<ExtensionWrapper<T>> extensionsWrapper = extensionFinder.find(type);
                List<T> extensions = new ArrayList<T>(extensionsWrapper.size());
@@ -232,13 +246,27 @@ public class DefaultPluginManager implements PluginManager {
                return extensions;
        }
        
+    /**
+     * Retrieves the {@link PluginWrapper} that loaded the given class 'clazz'.
+     */
+    public PluginWrapper whichPlugin(Class<?> clazz) {
+        ClassLoader classLoader = clazz.getClassLoader();
+        for (PluginWrapper plugin : resolvedPlugins) {
+            if (plugin.getPluginClassLoader() == classLoader) {
+               return plugin;
+            }
+        }
+        
+        return null;
+    }
+
        private void loadPlugin(String fileName) throws PluginException {
         // test for plugin directory
         File pluginDirectory = new File(pluginsDirectory, fileName);
         if (!pluginDirectory.isDirectory()) {
             return;
         }
-
+        
         // try to load the plugin
         String pluginPath = "/".concat(fileName);
 
@@ -247,7 +275,7 @@ public class DefaultPluginManager implements PluginManager {
             return;
         }
 
-        // it's a new plugin
+        // test for plugin duplication
         if (plugins.get(pathToIdMap.get(pluginPath)) != null) {
             return;
         }
@@ -278,7 +306,6 @@ public class DefaultPluginManager implements PluginManager {
 
         // add plugin class loader to the list with class loaders
         PluginClassLoader pluginClassLoader = pluginLoader.getPluginClassLoader();
-        pluginDescriptor.setPluginClassLoader(pluginClassLoader);
         pluginClassLoaders.put(pluginId, pluginClassLoader);
     }
 
@@ -288,7 +315,7 @@ public class DefaultPluginManager implements PluginManager {
         String pluginName = fileName.substring(0, fileName.length() - 4);
         File pluginDirectory = new File(pluginsDirectory, pluginName);
         // check if exists directory or the '.zip' file is "newer" than directory
-        if (!pluginDirectory.exists() || pluginArchiveDate > pluginDirectory.lastModified()) {
+        if (!pluginDirectory.exists() || (pluginArchiveDate > pluginDirectory.lastModified())) {
                LOG.debug("Expand plugin archive '" + pluginArchiveFile + "' in '" + pluginDirectory + "'");
             // create directorie for plugin
             pluginDirectory.mkdirs();
@@ -310,7 +337,7 @@ public class DefaultPluginManager implements PluginManager {
                resolvedPlugins = dependencyResolver.getSortedPlugins();
         for (PluginWrapper pluginWrapper : resolvedPlugins) {
                unresolvedPlugins.remove(pluginWrapper);
-               uberClassLoader.addLoader(pluginWrapper.getPluginClassLoader());
+               compoundClassLoader.addLoader(pluginWrapper.getPluginClassLoader());
                LOG.info("Plugin '" + pluginWrapper.getDescriptor().getPluginId() + "' resolved");
         }
        }
index e6006d27db6a85d0a9c28a059d46280c9792512f..546f0036c86bb495c7e05ad1d8e82ce86e11b91a 100644 (file)
@@ -29,7 +29,6 @@ public class PluginDescriptor {
     private PluginVersion version;
     private String provider;
     private List<PluginDependency> dependencies;
-    private PluginClassLoader pluginClassLoader;
 
     public PluginDescriptor() {
         dependencies = new ArrayList<PluginDependency>();
@@ -71,21 +70,12 @@ public class PluginDescriptor {
         return dependencies;
     }
 
-    /**
-     * Returns the plugin class loader used to load classes and resources
-        * for this plug-in. The class loader can be used to directly access
-        * plug-in resources and classes.
-        */
-    public PluginClassLoader getPluginClassLoader() {
-       return pluginClassLoader;
-    }
-
     @Override
        public String toString() {
                return "PluginDescriptor [pluginId=" + pluginId + ", pluginClass="
                                + pluginClass + ", version=" + version + ", provider="
                                + provider + ", dependencies=" + dependencies
-                               + ", pluginClassLoader=" + pluginClassLoader + "]";
+                               + "]";
        }
 
        void setPluginId(String pluginId) {
@@ -127,8 +117,4 @@ public class PluginDescriptor {
        }
     }
 
-       void setPluginClassLoader(PluginClassLoader pluginClassLoader) {
-               this.pluginClassLoader = pluginClassLoader;
-       }
-
 }
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginState.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginState.java
new file mode 100644 (file)
index 0000000..3727087
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Decebal Suiu
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with
+ * the License. You may obtain a copy of the License in the LICENSE file, or at:
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package ro.fortsoft.pf4j;
+
+/**
+ * @author Decebal Suiu
+ */
+public class PluginState {
+
+       public static final PluginState CREATED = new PluginState("CREATED");
+       public static final PluginState INITIALIZED = new PluginState("INITIALIZED");   
+       public static final PluginState STARTED = new PluginState("STARTED");
+       public static final PluginState STOPPED = new PluginState("STOPPED");
+       public static final PluginState DESTROYED = new PluginState("DESTROYED");
+       public static final PluginState FAILED = new PluginState("FAILED");
+
+       private String status;
+       
+       private PluginState(String status) {
+               this.status = status;
+       }
+
+       @Override
+       public String toString() {
+               return status;
+       }
+
+}
index c960ec1db47371e104c2f5b9ced7b6886000b7ca..4dd18d1d77b83a86c30401929f23699596a7f61a 100644 (file)
@@ -26,6 +26,7 @@ public class PluginWrapper {
        String pluginPath;
        PluginClassLoader pluginClassLoader;
        Plugin plugin;
+       PluginState pluginState;
        
        public PluginWrapper(PluginDescriptor descriptor, String pluginPath, PluginClassLoader pluginClassLoader) {
                this.descriptor = descriptor;
@@ -38,6 +39,8 @@ public class PluginWrapper {
                } catch (Exception e) {
                        e.printStackTrace();
                }
+               
+               pluginState = PluginState.CREATED;
        }
        
     /**
@@ -67,25 +70,9 @@ public class PluginWrapper {
                return plugin;
        }
 
-       private Plugin createPluginInstance() throws Exception {
-       String pluginClassName = descriptor.getPluginClass();
-        Class<?> pluginClass = pluginClassLoader.loadClass(pluginClassName);
-
-        // once we have the class, we can do some checks on it to ensure
-        // that it is a valid implementation of a plugin.
-        int modifiers = pluginClass.getModifiers();
-        if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers)
-                || (!Plugin.class.isAssignableFrom(pluginClass))) {
-            throw new PluginException("The plugin class '" + pluginClassName + "' is not compatible.");
-        }
-
-        // create the plugin instance
-        Constructor<?> constructor = pluginClass.getConstructor(new Class[] { PluginWrapper.class });
-        Plugin plugin = (Plugin) constructor.newInstance(new Object[] { this });
-
-        return plugin;
-    }
-
+       public PluginState getPluginState() {
+               return pluginState;
+       }
 
        @Override
        public int hashCode() {
@@ -124,4 +111,27 @@ public class PluginWrapper {
                                + pluginPath + "]";
        }
 
+       void setPluginState(PluginState pluginState) {
+               this.pluginState = pluginState;
+       }
+
+       private Plugin createPluginInstance() throws Exception {
+       String pluginClassName = descriptor.getPluginClass();
+        Class<?> pluginClass = pluginClassLoader.loadClass(pluginClassName);
+
+        // once we have the class, we can do some checks on it to ensure
+        // that it is a valid implementation of a plugin.
+        int modifiers = pluginClass.getModifiers();
+        if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers)
+                || (!Plugin.class.isAssignableFrom(pluginClass))) {
+            throw new PluginException("The plugin class '" + pluginClassName + "' is not compatible.");
+        }
+
+        // create the plugin instance
+        Constructor<?> constructor = pluginClass.getConstructor(new Class[] { PluginWrapper.class });
+        Plugin plugin = (Plugin) constructor.newInstance(new Object[] { this });
+
+        return plugin;
+    }
+
 }
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/CompoundClassLoader.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/CompoundClassLoader.java
new file mode 100644 (file)
index 0000000..f5c5df4
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012 Decebal Suiu
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with
+ * the License. You may obtain a copy of the License in the LICENSE file, or at:
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package ro.fortsoft.pf4j.util;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A class loader that has multiple loaders and uses them for loading classes and resources.
+ * 
+ * @author Decebal Suiu
+ */
+public class CompoundClassLoader extends ClassLoader {
+
+       private Set<ClassLoader> loaders = new HashSet<ClassLoader>();
+
+       public void addLoader(ClassLoader loader) {
+               loaders.add(loader);
+       }
+
+       @Override
+       public Class<?> findClass(String name) throws ClassNotFoundException {
+               for (ClassLoader loader : loaders) {
+                       try {
+                               return loader.loadClass(name);
+                       } catch (ClassNotFoundException e) {
+                               // try next
+                       }
+               }
+               
+               throw new ClassNotFoundException(name);
+       }
+
+       @Override
+       public URL findResource(String name) {
+               for (ClassLoader loader : loaders) {
+                       URL url = loader.getResource(name);
+                       if (url != null) {
+                               return url;
+                       }
+               }
+               
+               return null;
+       }
+
+       @Override
+       protected Enumeration<URL> findResources(String name) throws IOException {
+               List<URL> resources = new ArrayList<URL>();
+               for (ClassLoader loader : loaders) {
+                       resources.addAll(Collections.list(loader.getResources(name)));
+               }
+               
+               return Collections.enumeration(resources);
+       }
+       
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/util/UberClassLoader.java b/pf4j/src/main/java/ro/fortsoft/pf4j/util/UberClassLoader.java
deleted file mode 100644 (file)
index 013c2a1..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2012 Decebal Suiu
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with
- * the License. You may obtain a copy of the License in the LICENSE file, or at:
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
- * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package ro.fortsoft.pf4j.util;
-
-import java.io.IOException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * A class loader that has multiple loaders and uses them for loading classes and resources.
- * 
- * @author Decebal Suiu
- */
-public class UberClassLoader extends ClassLoader {
-
-       private Set<ClassLoader> loaders = new HashSet<ClassLoader>();
-
-       public void addLoader(ClassLoader loader) {
-               loaders.add(loader);
-       }
-
-       @Override
-       public Class<?> findClass(String name) throws ClassNotFoundException {
-               for (ClassLoader loader : loaders) {
-                       try {
-                               return loader.loadClass(name);
-                       } catch (ClassNotFoundException e) {
-                               // try next
-                       }
-               }
-               
-               throw new ClassNotFoundException(name);
-       }
-
-       @Override
-       public URL findResource(String name) {
-               for (ClassLoader loader : loaders) {
-                       URL url = loader.getResource(name);
-                       if (url != null) {
-                               return url;
-                       }
-               }
-               
-               return null;
-       }
-
-       @Override
-       protected Enumeration<URL> findResources(String name) throws IOException {
-               List<URL> resources = new ArrayList<URL>();
-               for (ClassLoader loader : loaders) {
-                       resources.addAll(Collections.list(loader.getResources(name)));
-               }
-               
-               return Collections.enumeration(resources);
-       }
-       
-}