]> source.dussan.org Git - pf4j.git/commitdiff
add listeners to plugin state changes
authorDecebal Suiu <decebal.suiu@gmail.com>
Wed, 9 Apr 2014 14:33:58 +0000 (17:33 +0300)
committerDecebal Suiu <decebal.suiu@gmail.com>
Wed, 9 Apr 2014 14:33:58 +0000 (17:33 +0300)
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java
pf4j/src/main/java/ro/fortsoft/pf4j/PluginLoader.java
pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java
pf4j/src/main/java/ro/fortsoft/pf4j/PluginStateEvent.java [new file with mode: 0644]
pf4j/src/main/java/ro/fortsoft/pf4j/PluginStateListener.java [new file with mode: 0644]
pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java

index c31f5d3ff90d4e51323d4be543a120d53326d6b1..295d5c8ec3a52c4146c259fca3256953e348c468 100644 (file)
@@ -28,7 +28,7 @@ import org.slf4j.LoggerFactory;
  *
  * @author Decebal Suiu
  */
-public class DefaultExtensionFinder implements ExtensionFinder {
+public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListener {
 
        private static final Logger log = LoggerFactory.getLogger(DefaultExtensionFinder.class);
 
@@ -95,8 +95,8 @@ public class DefaultExtensionFinder implements ExtensionFinder {
         return entries.get(pluginId);
     }
 
-    @Override
-    public void reset() {
+    public void pluginStateChanged(PluginStateEvent event) {
+        // TODO optimize (do only for some transitions)
         // clear cache
         entries = null;
     }
index cf020459e216f6070fe80295d77219b3a39ed68a..47dce71033c55a28c8225338e1e42aa74fa2a4dc 100644 (file)
@@ -77,6 +77,11 @@ public class DefaultPluginManager implements PluginManager {
     private List<String> enabledPlugins;
     private List<String> disabledPlugins;
 
+    /**
+     * The registered {@link PluginStateListener}s.
+     */
+    private List<PluginStateListener> pluginStateListeners;
+
     /**
      * Cache value for the runtime mode. No need to re-read it because it wont change at
         * runtime.
@@ -143,7 +148,7 @@ public class DefaultPluginManager implements PluginManager {
 
        @Override
        public String loadPlugin(File pluginArchiveFile) {
-               if (pluginArchiveFile == null || !pluginArchiveFile.exists()) {
+               if ((pluginArchiveFile == null) || !pluginArchiveFile.exists()) {
                        throw new IllegalArgumentException(String.format("Specified plugin %s does not exist!", pluginArchiveFile));
                }
 
@@ -153,7 +158,7 @@ public class DefaultPluginManager implements PluginManager {
                } catch (IOException e) {
                        log.error(e.getMessage(), e);
                }
-               if (pluginDirectory == null || !pluginDirectory.exists()) {
+               if ((pluginDirectory == null) || !pluginDirectory.exists()) {
                        throw new IllegalArgumentException(String.format("Failed to expand %s", pluginArchiveFile));
                }
 
@@ -162,7 +167,9 @@ public class DefaultPluginManager implements PluginManager {
                        // TODO uninstalled plugin dependencies?
                unresolvedPlugins.remove(pluginWrapper);
                resolvedPlugins.add(pluginWrapper);
-               extensionFinder.reset();
+
+            firePluginStateEvent(new PluginStateEvent(this, pluginWrapper, null));
+
                        return pluginWrapper.getDescriptor().getPluginId();
                } catch (PluginException e) {
                        log.error(e.getMessage(), e);
@@ -185,6 +192,8 @@ public class DefaultPluginManager implements PluginManager {
                     pluginWrapper.getPlugin().start();
                     pluginWrapper.setPluginState(PluginState.STARTED);
                     startedPlugins.add(pluginWrapper);
+
+                    firePluginStateEvent(new PluginStateEvent(this, pluginWrapper, pluginState));
                 } catch (PluginException e) {
                     log.error(e.getMessage(), e);
                 }
@@ -201,17 +210,18 @@ public class DefaultPluginManager implements PluginManager {
                throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
        }
 
-       PluginWrapper pluginWrapper = plugins.get(pluginId);
+       PluginWrapper pluginWrapper = getPlugin(pluginId);
        PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
-       if (PluginState.STARTED == pluginWrapper.getPluginState()) {
+        PluginState pluginState = pluginWrapper.getPluginState();
+       if (PluginState.STARTED == pluginState) {
                log.debug("Already started plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
                return PluginState.STARTED;
        }
 
-        if (PluginState.DISABLED == pluginWrapper.getPluginState()) {
+        if (PluginState.DISABLED == pluginState) {
             // automatically enable plugin on manual plugin start
             if (!enablePlugin(pluginId)) {
-                return pluginWrapper.getPluginState();
+                return pluginState;
             }
         }
 
@@ -224,7 +234,9 @@ public class DefaultPluginManager implements PluginManager {
                pluginWrapper.getPlugin().start();
                pluginWrapper.setPluginState(PluginState.STARTED);
                startedPlugins.add(pluginWrapper);
-       } catch (PluginException e) {
+
+            firePluginStateEvent(new PluginStateEvent(this, pluginWrapper, pluginState));
+        } catch (PluginException e) {
                log.error(e.getMessage(), e);
        }
 
@@ -241,13 +253,16 @@ public class DefaultPluginManager implements PluginManager {
        Iterator<PluginWrapper> itr = startedPlugins.iterator();
         while (itr.hasNext()) {
                PluginWrapper pluginWrapper = itr.next();
-            if (PluginState.STARTED == pluginWrapper.getPluginState()) {
+            PluginState pluginState = pluginWrapper.getPluginState();
+            if (PluginState.STARTED == pluginState) {
                 try {
                     PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
                     log.info("Stop plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
                     pluginWrapper.getPlugin().stop();
                     pluginWrapper.setPluginState(PluginState.STOPPED);
                     itr.remove();
+
+                    firePluginStateEvent(new PluginStateEvent(this, pluginWrapper, pluginState));
                 } catch (PluginException e) {
                     log.error(e.getMessage(), e);
                 }
@@ -264,17 +279,18 @@ public class DefaultPluginManager implements PluginManager {
                throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
        }
 
-       PluginWrapper pluginWrapper = plugins.get(pluginId);
+       PluginWrapper pluginWrapper = getPlugin(pluginId);
        PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
-       if (PluginState.STOPPED == pluginWrapper.getPluginState()) {
+        PluginState pluginState = pluginWrapper.getPluginState();
+       if (PluginState.STOPPED == pluginState) {
                log.debug("Already stopped plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
                return PluginState.STOPPED;
        }
 
         // test for disabled plugin
-        if (PluginState.DISABLED == pluginWrapper.getPluginState()) {
+        if (PluginState.DISABLED == pluginState) {
             // do nothing
-            return pluginWrapper.getPluginState();
+            return pluginState;
         }
 
        for (PluginDependency dependency : pluginDescriptor.getDependencies()) {
@@ -286,6 +302,8 @@ public class DefaultPluginManager implements PluginManager {
                pluginWrapper.getPlugin().stop();
                pluginWrapper.setPluginState(PluginState.STOPPED);
                startedPlugins.remove(pluginWrapper);
+
+            firePluginStateEvent(new PluginStateEvent(this, pluginWrapper, pluginState));
        } catch (PluginException e) {
                log.error(e.getMessage(), e);
        }
@@ -353,12 +371,12 @@ public class DefaultPluginManager implements PluginManager {
     @Override
     public boolean unloadPlugin(String pluginId) {
        try {
-               PluginState state = stopPlugin(pluginId);
-               if (PluginState.STOPPED != state) {
+               PluginState pluginState = stopPlugin(pluginId);
+               if (PluginState.STOPPED != pluginState) {
                        return false;
                }
 
-               PluginWrapper pluginWrapper = plugins.get(pluginId);
+               PluginWrapper pluginWrapper = getPlugin(pluginId);
                PluginDescriptor descriptor = pluginWrapper.getDescriptor();
                List<PluginDependency> dependencies = descriptor.getDependencies();
                for (PluginDependency dependency : dependencies) {
@@ -371,7 +389,8 @@ public class DefaultPluginManager implements PluginManager {
                plugins.remove(pluginId);
                resolvedPlugins.remove(pluginWrapper);
                pathToIdMap.remove(pluginWrapper.getPluginPath());
-               extensionFinder.reset();
+
+            firePluginStateEvent(new PluginStateEvent(this, pluginWrapper, pluginState));
 
                // remove the classloader
                if (pluginClassLoaders.containsKey(pluginId)) {
@@ -398,17 +417,18 @@ public class DefaultPluginManager implements PluginManager {
         }
 
 
-        PluginWrapper pluginWrapper = plugins.get(pluginId);
+        PluginWrapper pluginWrapper = getPlugin(pluginId);
         PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
-
-        if (PluginState.DISABLED == getPlugin(pluginId).getPluginState()) {
+        PluginState pluginState = pluginWrapper.getPluginState();
+        if (PluginState.DISABLED == pluginState) {
                log.debug("Already disabled plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
                return true;
         }
 
         if (PluginState.STOPPED == stopPlugin(pluginId)) {
-            getPlugin(pluginId).setPluginState(PluginState.DISABLED);
-            extensionFinder.reset();
+            pluginWrapper.setPluginState(PluginState.DISABLED);
+
+            firePluginStateEvent(new PluginStateEvent(this, pluginWrapper, PluginState.STOPPED));
 
             if (disabledPlugins.add(pluginId)) {
                 try {
@@ -432,10 +452,10 @@ public class DefaultPluginManager implements PluginManager {
             throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
         }
 
-        PluginWrapper pluginWrapper = plugins.get(pluginId);
+        PluginWrapper pluginWrapper = getPlugin(pluginId);
         PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor();
-
-        if (PluginState.DISABLED != getPlugin(pluginId).getPluginState()) {
+        PluginState pluginState = pluginWrapper.getPluginState();
+        if (PluginState.DISABLED != pluginState) {
             log.debug("Plugin plugin '{}:{}' is not disabled", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
             return true;
         }
@@ -449,8 +469,9 @@ public class DefaultPluginManager implements PluginManager {
             return false;
         }
 
-        getPlugin(pluginId).setPluginState(PluginState.CREATED);
-        extensionFinder.reset();
+        pluginWrapper.setPluginState(PluginState.CREATED);
+
+        firePluginStateEvent(new PluginStateEvent(this, pluginWrapper, pluginState));
 
         log.info("Enabled plugin '{}:{}'", pluginDescriptor.getPluginId(), pluginDescriptor.getVersion());
 
@@ -462,10 +483,10 @@ public class DefaultPluginManager implements PluginManager {
        if (!plugins.containsKey(pluginId)) {
                throw new IllegalArgumentException(String.format("Unknown pluginId %s", pluginId));
        }
-               PluginWrapper pw = getPlugin(pluginId);
-               PluginState state = stopPlugin(pluginId);
 
-               if (PluginState.STOPPED != state) {
+               PluginWrapper pluginWrapper = getPlugin(pluginId);
+               PluginState pluginState = stopPlugin(pluginId);
+               if (PluginState.STOPPED != pluginState) {
                        log.error("Failed to stop plugin {} on delete", pluginId);
                        return false;
                }
@@ -475,14 +496,14 @@ public class DefaultPluginManager implements PluginManager {
                        return false;
                }
 
-               File pluginFolder = new File(pluginsDirectory, pw.getPluginPath());
+               File pluginFolder = new File(pluginsDirectory, pluginWrapper.getPluginPath());
                File pluginZip = null;
 
                FileFilter zipFilter = new ZipFileFilter();
         File[] zipFiles = pluginsDirectory.listFiles(zipFilter);
         if (zipFiles != null) {
                // strip prepended / from the plugin path
-               String dirName = pw.getPluginPath().substring(1);
+               String dirName = pluginWrapper.getPluginPath().substring(1);
                // find the zip file that matches the plugin path
                for (File zipFile : zipFiles) {
                        String name = zipFile.getName().substring(0, zipFile.getName().lastIndexOf('.'));
@@ -499,6 +520,7 @@ public class DefaultPluginManager implements PluginManager {
                if (pluginZip != null && pluginZip.exists()) {
                        FileUtils.delete(pluginZip);
                }
+
                return true;
        }
 
@@ -551,10 +573,21 @@ public class DefaultPluginManager implements PluginManager {
             }
         }
         log.warn("Failed to find the plugin for {}", clazz);
+
         return null;
     }
 
-       /**
+    @Override
+    public synchronized void addPluginStateListener(PluginStateListener listener) {
+        pluginStateListeners.add(listener);
+    }
+
+    @Override
+    public synchronized void removePluginStateListener(PluginStateListener listener) {
+        pluginStateListeners.remove(listener);
+    }
+
+    /**
         * Add the possibility to override the PluginDescriptorFinder.
         * By default if getRuntimeMode() returns RuntimeMode.DEVELOPMENT than a
         * PropertiesPluginDescriptorFinder is returned else this method returns
@@ -572,7 +605,10 @@ public class DefaultPluginManager implements PluginManager {
      * Add the possibility to override the ExtensionFinder.
      */
     protected ExtensionFinder createExtensionFinder() {
-       return new DefaultExtensionFinder(this);
+       DefaultExtensionFinder extensionFinder = new DefaultExtensionFinder(this);
+        addPluginStateListener(extensionFinder);
+
+        return extensionFinder;
     }
 
     /**
@@ -632,6 +668,8 @@ public class DefaultPluginManager implements PluginManager {
         startedPlugins = new ArrayList<PluginWrapper>();
         disabledPlugins = new ArrayList<String>();
 
+        pluginStateListeners = new ArrayList<PluginStateListener>();
+
         pluginClasspath = createPluginClasspath();
         pluginDescriptorFinder = createPluginDescriptorFinder();
         extensionFinder = createExtensionFinder();
@@ -739,4 +777,11 @@ public class DefaultPluginManager implements PluginManager {
         }
        }
 
+    private synchronized void firePluginStateEvent(PluginStateEvent event) {
+        for (PluginStateListener listener : pluginStateListeners) {
+            log.debug("Fire '{}' to '{}'", event, listener);
+            listener.pluginStateChanged(event);
+        }
+    }
+
 }
index c518566ffd76d7cab40eed448cf0f7dac1245331..7236b4983b5e04aa2ffb1c55aadefc0233f426b0 100644 (file)
@@ -30,6 +30,4 @@ public interface ExtensionFinder {
      */
     public Set<String> findClassNames(String pluginId);
 
-    public void reset();
-
 }
index 8bd2daa8630124f65439f946b1fabad7501d6c76..03e7683293d4bb22e0ad5f2ac71f3582902487c7 100644 (file)
@@ -1,11 +1,11 @@
 /*
  * 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.
@@ -46,10 +46,11 @@ class PluginLoader {
 
     public PluginLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, File pluginRepository, PluginClasspath pluginClasspath) {
         this.pluginRepository = pluginRepository;
-        this.pluginClasspath = pluginClasspath; 
-        ClassLoader parent = getClass().getClassLoader(); 
-        pluginClassLoader = new PluginClassLoader(pluginManager, pluginDescriptor, parent);        
-        log.debug("Created class loader {}", pluginClassLoader);
+        this.pluginClasspath = pluginClasspath;
+
+        ClassLoader parent = getClass().getClassLoader();
+        pluginClassLoader = new PluginClassLoader(pluginManager, pluginDescriptor, parent);
+        log.debug("Created class loader '{}'", pluginClassLoader);
     }
 
     public File getPluginRepository() {
@@ -70,15 +71,15 @@ class PluginLoader {
 
     private boolean loadClasses() {
        List<String> classesDirectories = pluginClasspath.getClassesDirectories();
-       
+
        // add each classes directory to plugin class loader
        for (String classesDirectory : classesDirectories) {
                // make 'classesDirectory' absolute
                File file = new File(pluginRepository, classesDirectory).getAbsoluteFile();
-       
+
                if (file.exists() && file.isDirectory()) {
                    log.debug("Found '{}' directory", file.getPath());
-       
+
                    try {
                        pluginClassLoader.addURL(file.toURI().toURL());
                        log.debug("Added '{}' to the class loader path", file);
@@ -98,12 +99,12 @@ class PluginLoader {
      */
     private boolean loadJars() {
        List<String> libDirectories = pluginClasspath.getLibDirectories();
-       
+
        // add each jars directory to plugin class loader
        for (String libDirectory : libDirectories) {
                // make 'libDirectory' absolute
                File file = new File(pluginRepository, libDirectory).getAbsoluteFile();
-       
+
                // collect all jars from current lib directory in jars variable
                Vector<File> jars = new Vector<File>();
                getJars(jars, file);
index f6563139ca62aa1e5df57965c0d0075e664a0916..daf6fbf40f5375903f9c9e06ef2082f3353d0193 100644 (file)
@@ -137,4 +137,8 @@ public interface PluginManager {
         */
        public RuntimeMode getRuntimeMode();
 
+    public void addPluginStateListener(PluginStateListener listener);
+
+    public void removePluginStateListener(PluginStateListener listener);
+
 }
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginStateEvent.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginStateEvent.java
new file mode 100644 (file)
index 0000000..bea202e
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 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;
+
+import java.util.EventObject;
+
+/**
+ * @author Decebal Suiu
+ */
+public class PluginStateEvent extends EventObject {
+
+    private PluginWrapper plugin;
+    private PluginState oldState;
+
+    public PluginStateEvent(PluginManager source, PluginWrapper plugin, PluginState oldState) {
+        super(source);
+
+        this.plugin = plugin;
+        this.oldState = oldState;
+    }
+
+    @Override
+    public PluginManager getSource() {
+        return (PluginManager) super.getSource();
+    }
+
+    public PluginWrapper getPlugin() {
+        return plugin;
+    }
+
+    public PluginState getPluginState() {
+        return plugin.getPluginState();
+    }
+
+    public PluginState getOldState() {
+        return oldState;
+    }
+
+    @Override
+    public String toString() {
+        return "PluginStateEvent [plugin=" + plugin.getPluginId() +
+                ", newState=" + getPluginState() +
+                ", oldState=" + oldState +
+                ']';
+    }
+
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginStateListener.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginStateListener.java
new file mode 100644 (file)
index 0000000..4af2e91
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 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;
+
+import java.util.EventListener;
+
+/**
+ * PluginStateListener defines the interface for an object that listens to plugin state changes.
+ *
+ * @author Decebal Suiu
+ */
+public interface PluginStateListener extends EventListener {
+
+    /**
+     * Invoked when a plugin's state (for example DISABLED, STARTED) is changed.
+     */
+    public void pluginStateChanged(PluginStateEvent event);
+
+}
index b2ab37d746412419df6cb48b7fd16631025cd03b..da9908a8d7f96fbce76763475e2a13a6338f2d58 100644 (file)
@@ -119,8 +119,7 @@ public class PluginWrapper {
 
        @Override
        public String toString() {
-               return "PluginWrapper [descriptor=" + descriptor + ", pluginPath="
-                               + pluginPath + "]";
+               return "PluginWrapper [descriptor=" + descriptor + ", pluginPath=" + pluginPath + "]";
        }
 
        void setPluginState(PluginState pluginState) {