]> source.dussan.org Git - pf4j.git/commitdiff
try to resolve issue #20
authorDecebal Suiu <decebal.suiu@gmail.com>
Tue, 15 Jul 2014 19:43:52 +0000 (22:43 +0300)
committerDecebal Suiu <decebal.suiu@gmail.com>
Tue, 15 Jul 2014 19:43:52 +0000 (22:43 +0300)
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFactory.java [new file with mode: 0644]
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginFactory.java [new file with mode: 0644]
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionDescriptor.java [new file with mode: 0644]
pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFactory.java [new file with mode: 0644]
pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionWrapper.java
pf4j/src/main/java/ro/fortsoft/pf4j/PluginFactory.java [new file with mode: 0644]
pf4j/src/main/java/ro/fortsoft/pf4j/PluginWrapper.java

diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFactory.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFactory.java
new file mode 100644 (file)
index 0000000..5824e88
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The default implementation for ExtensionFactory.
+ * It uses Class.newInstance() method.
+ *
+ * @author Decebal Suiu
+ */
+public class DefaultExtensionFactory implements ExtensionFactory {
+
+    private static final Logger log = LoggerFactory.getLogger(DefaultExtensionFactory.class);
+
+    /**
+     * Creates an extension instance. If an error occurs than that error is logged and the method returns null.
+     * @param extensionClass
+     * @return
+     */
+    @Override
+    public Object create(Class<?> extensionClass) {
+        log.debug("Create instance for extension '{}'", extensionClass.getName());
+        try {
+            return extensionClass.newInstance();
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+
+        return null;
+    }
+
+}
index 0f04ed7a72acc5840d11fb4c9e4dc2cb8b176100..ab726584968b5a5ae203c44e148e5bd3ac11d4df 100644 (file)
@@ -36,9 +36,9 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
        private ExtensionFactory extensionFactory;
     private volatile Map<String, Set<String>> entries; // cache by pluginId
 
-       public DefaultExtensionFinder(PluginManager pluginManager) {
+       public DefaultExtensionFinder(PluginManager pluginManager, ExtensionFactory extensionFactory) {
         this.pluginManager = pluginManager;
-               this.extensionFactory = createExtensionFactory();
+               this.extensionFactory = extensionFactory;
        }
 
     @Override
@@ -68,23 +68,26 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
 
             for (String className : extensionClassNames) {
                 try {
-                    Class<?> extensionType;
+                    Class<?> extensionClass;
                     if (pluginId != null) {
-                        extensionType = pluginManager.getPluginClassLoader(pluginId).loadClass(className);
+                        extensionClass = pluginManager.getPluginClassLoader(pluginId).loadClass(className);
                     } else {
-                        extensionType = getClass().getClassLoader().loadClass(className);
+                        extensionClass = getClass().getClassLoader().loadClass(className);
                     }
 
-                    log.debug("Checking extension type '{}'", extensionType.getName());
-                    if (type.isAssignableFrom(extensionType)) {
-                        Object instance = extensionFactory.create(extensionType);
-                        if (instance != null) {
-                            Extension extension = extensionType.getAnnotation(Extension.class);
-                            log.debug("Added extension '{}' with ordinal {}", extensionType.getName(), extension.ordinal());
-                            result.add(new ExtensionWrapper<T>(type.cast(instance), extension.ordinal()));
-                        }
+                    log.debug("Checking extension type '{}'", className);
+                    if (type.isAssignableFrom(extensionClass) && extensionClass.isAnnotationPresent(Extension.class)) {
+                        Extension extension = extensionClass.getAnnotation(Extension.class);
+                        ExtensionDescriptor descriptor = new ExtensionDescriptor();
+                        descriptor.setOrdinal(extension.ordinal());
+                        descriptor.setExtensionClass(extensionClass);
+
+                        ExtensionWrapper extensionWrapper = new ExtensionWrapper<T>(descriptor);
+                        extensionWrapper.setExtensionFactory(extensionFactory);
+                        result.add(extensionWrapper);
+                        log.debug("Added extension '{}' with ordinal {}", className, extension.ordinal());
                     } else {
-                        log.debug("'{}' is not an extension for extension point '{}'", extensionType.getName(), type.getName());
+                        log.debug("'{}' is not an extension for extension point '{}'", className, type.getName());
                     }
                 } catch (ClassNotFoundException e) {
                     log.error(e.getMessage(), e);
@@ -117,31 +120,6 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
         entries = null;
     }
 
-    /**
-     * Add the possibility to override the ExtensionFactory.
-     * The default implementation uses Class.newInstance() method.
-     */
-       protected ExtensionFactory createExtensionFactory() {
-               return new ExtensionFactory() {
-
-                       @Override
-                       public Object create(Class<?> extensionType) {
-                               log.debug("Create instance for extension '{}'", extensionType.getName());
-
-                               try {
-                                       return extensionType.newInstance();
-                               } catch (InstantiationException e) {
-                                       log.error(e.getMessage(), e);
-                               } catch (IllegalAccessException e) {
-                                       log.error(e.getMessage(), e);
-                               }
-
-                               return null;
-                       }
-
-               };
-       }
-
     private Map<String, Set<String>> readIndexFiles() {
         // checking cache
         if (entries != null) {
@@ -219,13 +197,4 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
         return ExtensionPoint.class.isAssignableFrom(type);
     }
 
-       /**
-        * Creates an extension instance.
-        */
-       public static interface ExtensionFactory {
-
-               public Object create(Class<?> extensionType);
-
-       }
-
 }
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginFactory.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginFactory.java
new file mode 100644 (file)
index 0000000..6c4dc4f
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+
+/**
+ * The default implementation for PluginFactory.
+ * It uses Class.newInstance() method.
+ *
+ * @author Decebal Suiu
+ */
+public class DefaultPluginFactory implements PluginFactory {
+
+    private static final Logger log = LoggerFactory.getLogger(DefaultExtensionFactory.class);
+
+    /**
+     * Creates a plugin instance. If an error occurs than that error is logged and the method returns null.
+     * @param pluginWrapper
+     * @return
+     */
+    @Override
+    public Plugin create(final PluginWrapper pluginWrapper) {
+        String pluginClassName = pluginWrapper.getDescriptor().getPluginClass();
+        log.debug("Create instance for plugin '{}'", pluginClassName);
+
+        Class<?> pluginClass;
+        try {
+            pluginClass = pluginWrapper.getPluginClassLoader().loadClass(pluginClassName);
+        } catch (ClassNotFoundException e) {
+            log.error(e.getMessage(), e);
+            return null;
+        }
+
+        // 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))) {
+            log.error("The plugin class '{}' is not valid", pluginClassName);
+            return null;
+        }
+
+        // create the plugin instance
+        try {
+            Constructor<?> constructor = pluginClass.getConstructor(new Class[] { PluginWrapper.class });
+            return (Plugin) constructor.newInstance(new Object[] { pluginWrapper });
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+
+        return null;
+    }
+
+}
index 339c06307149476a960c09b47e69359747efbe1a..d2fcd3bc91fb4dd277f5ed34f2e50dd25d069cdd 100644 (file)
@@ -94,6 +94,9 @@ public class DefaultPluginManager implements PluginManager {
      */
     private Version systemVersion = Version.ZERO;
 
+    private PluginFactory pluginFactory;
+    private ExtensionFactory extensionFactory;
+
     /**
      * The plugins directory is supplied by System.getProperty("pf4j.pluginsDir", "plugins").
      */
@@ -168,6 +171,8 @@ public class DefaultPluginManager implements PluginManager {
                        throw new IllegalArgumentException(String.format("Specified plugin %s does not exist!", pluginArchiveFile));
                }
 
+        log.debug("Loading plugin from '{}'", pluginArchiveFile);
+
                File pluginDirectory = null;
                try {
                        pluginDirectory = expandPluginArchive(pluginArchiveFile);
@@ -361,7 +366,7 @@ public class DefaultPluginManager implements PluginManager {
         if (directories == null) {
                directories = new File[0];
         }
-        log.debug("Found possible {} plugins: {}", directories.length, directories);
+        log.debug("Found {} possible plugins: {}", directories.length, directories);
         if (directories.length == 0) {
                log.info("No plugins");
                return;
@@ -554,7 +559,7 @@ public class DefaultPluginManager implements PluginManager {
                List<ExtensionWrapper<T>> extensionsWrapper = extensionFinder.find(type);
                List<T> extensions = new ArrayList<T>(extensionsWrapper.size());
                for (ExtensionWrapper<T> extensionWrapper : extensionsWrapper) {
-                       extensions.add(extensionWrapper.getInstance());
+                       extensions.add(extensionWrapper.getExtension());
                }
 
                return extensions;
@@ -633,7 +638,7 @@ public class DefaultPluginManager implements PluginManager {
      * Add the possibility to override the ExtensionFinder.
      */
     protected ExtensionFinder createExtensionFinder() {
-       DefaultExtensionFinder extensionFinder = new DefaultExtensionFinder(this);
+       DefaultExtensionFinder extensionFinder = new DefaultExtensionFinder(this, extensionFactory);
         addPluginStateListener(extensionFinder);
 
         return extensionFinder;
@@ -702,7 +707,21 @@ public class DefaultPluginManager implements PluginManager {
        return new File(pluginsDir);
     }
 
-       private void initialize() {
+    /**
+     * Add the possibility to override the PluginFactory..
+     */
+    protected PluginFactory createPluginFactory() {
+        return new DefaultPluginFactory();
+    }
+
+    /**
+     * Add the possibility to override the ExtensionFactory.
+     */
+    protected ExtensionFactory createExtensionFactory() {
+        return new DefaultExtensionFactory();
+    }
+
+    private void initialize() {
                plugins = new HashMap<String, PluginWrapper>();
         pluginClassLoaders = new HashMap<String, PluginClassLoader>();
         pathToIdMap = new HashMap<String, String>();
@@ -716,6 +735,8 @@ public class DefaultPluginManager implements PluginManager {
         log.info("PF4J version {} in '{}' mode", getVersion(), getRuntimeMode());
 
         pluginClasspath = createPluginClasspath();
+        pluginFactory = createPluginFactory();
+        extensionFactory = createExtensionFactory();
         pluginDescriptorFinder = createPluginDescriptorFinder();
         extensionFinder = createExtensionFinder();
 
@@ -760,6 +781,7 @@ public class DefaultPluginManager implements PluginManager {
         // create the plugin wrapper
         log.debug("Creating wrapper for plugin '{}'", pluginPath);
         PluginWrapper pluginWrapper = new PluginWrapper(pluginDescriptor, pluginPath, pluginLoader.getPluginClassLoader());
+        pluginWrapper.setPluginFactory(pluginFactory);
         pluginWrapper.setRuntimeMode(getRuntimeMode());
 
         // test for disabled plugin
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionDescriptor.java b/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionDescriptor.java
new file mode 100644 (file)
index 0000000..32a5225
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * @author Decebal Suiu
+ */
+public class ExtensionDescriptor {
+
+    private int ordinal;
+    private Class<?> extensionClass;
+
+    public Class<?> getExtensionClass() {
+        return extensionClass;
+    }
+
+    public int getOrdinal() {
+        return ordinal;
+    }
+
+    void setExtensionClass(Class<?> extensionClass) {
+        this.extensionClass = extensionClass;
+    }
+
+    void setOrdinal(int ordinal) {
+        this.ordinal = ordinal;
+    }
+
+}
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFactory.java b/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFactory.java
new file mode 100644 (file)
index 0000000..fd7c56b
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+/**
+ * Creates an extension instance.
+ */
+public interface ExtensionFactory {
+
+    public Object create(Class<?> extensionClass);
+
+}
index 2f147c029700f06d410f75af823085e4d723306c..d6ac74db4e8a8c9b00f9fec9aeca3965a0c523ca 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * Copyright 2012 Decebal Suiu
- * 
+ * 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;
 
 /**
+ * A wrapper over extension instance.
+ *
  * @author Decebal Suiu
  */
 public class ExtensionWrapper<T> implements Comparable<ExtensionWrapper<T>> {
 
-       private final T instance;
-       private final int ordinal;
-       
-       public ExtensionWrapper(T instance, int ordinal) {
-               this.instance = instance;
-               this.ordinal = ordinal;
+    ExtensionDescriptor descriptor;
+    ExtensionFactory extensionFactory;
+    T extension; // cache
+
+       public ExtensionWrapper(ExtensionDescriptor descriptor) {
+        this.descriptor = descriptor;
        }
 
-       public T getInstance() {
-               return instance;
+       public T getExtension() {
+        if (extension == null) {
+            extension = (T) extensionFactory.create(descriptor.getExtensionClass());
+        }
+
+        return extension;
        }
 
-       public int getOrdinal() {
-               return ordinal;
+    public ExtensionDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    public int getOrdinal() {
+               return descriptor.getOrdinal();
        }
 
        @Override
        public int compareTo(ExtensionWrapper<T> o) {
-               return (ordinal - o.getOrdinal());
+               return (getOrdinal() - o.getOrdinal());
        }
 
+    void setExtensionFactory(ExtensionFactory extensionFactory) {
+        this.extensionFactory = extensionFactory;
+    }
+
 }
\ No newline at end of file
diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginFactory.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginFactory.java
new file mode 100644 (file)
index 0000000..b9ece11
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+/**
+ * Creates a plugin instance.
+ */
+public interface PluginFactory {
+
+    public Plugin create(PluginWrapper pluginWrapper);
+
+}
index f8bf716c3bb0d69e0512d3befc4323254f0cad6d..3c3b6e14b2cb94d3cfa92a4ab87d5efa4ecf154d 100644 (file)
@@ -12,9 +12,6 @@
  */
 package ro.fortsoft.pf4j;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
-
 /**
  * A wrapper over plugin instance.
  *
@@ -25,22 +22,16 @@ public class PluginWrapper {
        PluginDescriptor descriptor;
        String pluginPath;
        PluginClassLoader pluginClassLoader;
-       Plugin plugin;
+       PluginFactory pluginFactory;
        PluginState pluginState;
        RuntimeMode runtimeMode;
+    Plugin plugin; // cache
 
        public PluginWrapper(PluginDescriptor descriptor, String pluginPath, PluginClassLoader pluginClassLoader) {
                this.descriptor = descriptor;
                this.pluginPath = pluginPath;
                this.pluginClassLoader = pluginClassLoader;
 
-               // TODO
-               try {
-                       plugin = createPluginInstance();
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
-
                pluginState = PluginState.CREATED;
        }
 
@@ -68,7 +59,11 @@ public class PluginWrapper {
     }
 
     public Plugin getPlugin() {
-               return plugin;
+        if (plugin == null) {
+            plugin = pluginFactory.create(this);
+        }
+
+        return plugin;
        }
 
        public PluginState getPluginState() {
@@ -130,23 +125,8 @@ public class PluginWrapper {
                this.runtimeMode = runtimeMode;
        }
 
-       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 valid.");
-        }
-
-        // create the plugin instance
-        Constructor<?> constructor = pluginClass.getConstructor(new Class[] { PluginWrapper.class });
-        Plugin plugin = (Plugin) constructor.newInstance(new Object[] { this });
-
-        return plugin;
+    void setPluginFactory(PluginFactory pluginFactory) {
+        this.pluginFactory = pluginFactory;
     }
 
 }