diff --git a/demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java b/demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java index 2394761..fa779e2 100644 --- a/demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java +++ b/demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java @@ -56,13 +56,13 @@ public class Boot { } // print extensions from classpath (non plugin) - System.out.println(String.format("Extensions added by classpath:")); + System.out.println("Extensions added by classpath:"); Set extensionClassNames = pluginManager.getExtensionClassNames(null); for (String extension : extensionClassNames) { System.out.println(" " + extension); } - // print extensions for each started plugin + // print extensions ids for each started plugin List startedPlugins = pluginManager.getStartedPlugins(); for (PluginWrapper plugin : startedPlugins) { String pluginId = plugin.getDescriptor().getPluginId(); @@ -73,6 +73,33 @@ public class Boot { } } + // print the extensions instances for Greeting extension point for each started plugin + for (PluginWrapper plugin : startedPlugins) { + String pluginId = plugin.getDescriptor().getPluginId(); + System.out.println(String.format("Extensions instances added by plugin '%s' for extension point '%s':", pluginId, Greeting.class.getName())); + List extensions = pluginManager.getExtensions(Greeting.class, pluginId); + for (Object extension : extensions) { + System.out.println(" " + extension); + } + } + + // print extensions instances from classpath (non plugin) + System.out.println("Extensions instances added by classpath:"); + List extensions = pluginManager.getExtensions((String) null); + for (Object extension : extensions) { + System.out.println(" " + extension); + } + + // print extensions instances for each started plugin + for (PluginWrapper plugin : startedPlugins) { + String pluginId = plugin.getDescriptor().getPluginId(); + System.out.println(String.format("Extensions instances added by plugin '%s':", pluginId)); + extensions = pluginManager.getExtensions(pluginId); + for (Object extension : extensions) { + System.out.println(" " + extension); + } + } + // stop the plugins pluginManager.stopPlugins(); /* diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/AbstractExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/AbstractExtensionFinder.java index f54a2ab..cdfeb38 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/AbstractExtensionFinder.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/AbstractExtensionFinder.java @@ -48,67 +48,131 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin public List> find(Class type) { log.debug("Finding extensions of extension point '{}'", type.getName()); Map> entries = getEntries(); + List> result = new ArrayList<>(); + + // add extensions found in classpath + List> classpathExtensions = find(type, null); + result.addAll(classpathExtensions); + + // add extensions found in each plugin + for (String pluginId : entries.keySet()) { + List> pluginExtensions = find(type, pluginId); + result.addAll(pluginExtensions); + } + + if (entries.isEmpty()) { + log.debug("No extensions found for extension point '{}'", type.getName()); + } else { + log.debug("Found {} extensions for extension point '{}'", result.size(), type.getName()); + } + + // sort by "ordinal" property + Collections.sort(result); + + return result; + } + @Override + @SuppressWarnings("unchecked") + public List> find(Class type, String pluginId) { + log.debug("Finding extensions of extension point '{}' for plugin '{}'", type.getName(), pluginId); List> result = new ArrayList<>(); - for (Map.Entry> entry : entries.entrySet()) { - if (entry.getValue().isEmpty()) { - continue; + + Set classNames = findClassNames(pluginId); + if (classNames.isEmpty()) { + return result; + } + + if (pluginId != null) { + PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginId); + if (PluginState.STARTED != pluginWrapper.getPluginState()) { + return result; } - String pluginId = entry.getKey(); + log.trace("Checking extensions from plugin '{}'", pluginId); + } else { + log.trace("Checking extensions from classpath"); + } + + ClassLoader classLoader = (pluginId != null) ? pluginManager.getPluginClassLoader(pluginId) : getClass().getClassLoader(); - if (pluginId != null) { - PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginId); - if (PluginState.STARTED != pluginWrapper.getPluginState()) { - continue; + for (String className : classNames) { + try { + log.debug("Loading class '{}' using class loader '{}'", className, classLoader); + Class extensionClass = classLoader.loadClass(className); + + log.debug("Checking extension type '{}'", className); + if (type.isAssignableFrom(extensionClass)) { + ExtensionWrapper extensionWrapper = createExtensionWrapper(extensionClass); + result.add(extensionWrapper); + log.debug("Added extension '{}' with ordinal {}", className, extensionWrapper.getOrdinal()); + } else { + log.trace("'{}' is not an extension for extension point '{}'", className, type.getName()); } + } catch (ClassNotFoundException e) { + log.error(e.getMessage(), e); + } + } + + if (result.isEmpty()) { + log.debug("No extensions found for extension point '{}'", type.getName()); + } else { + log.debug("Found {} extensions for extension point '{}'", result.size(), type.getName()); + } - log.trace("Checking extensions from plugin '{}'", pluginId); - } else { - log.trace("Checking extensions from classpath"); + // sort by "ordinal" property + Collections.sort(result); + + return result; + } + + @Override + public List find(String pluginId) { + log.debug("Finding extensions from plugin '{}'", pluginId); + List result = new ArrayList<>(); + + Set classNames = findClassNames(pluginId); + if (classNames.isEmpty()) { + return result; + } + + if (pluginId != null) { + PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginId); + if (PluginState.STARTED != pluginWrapper.getPluginState()) { + return result; } - ClassLoader classLoader = (pluginId != null) ? pluginManager.getPluginClassLoader(pluginId) : getClass().getClassLoader(); - - for (String className : entry.getValue()) { - try { - log.debug("Loading class '{}' using class loader '{}'", className, classLoader); - Class extensionClass = classLoader.loadClass(className); - - log.debug("Checking extension type '{}'", className); - if (type.isAssignableFrom(extensionClass)) { - ExtensionDescriptor descriptor = new ExtensionDescriptor(); - int ordinal = 0; - if (extensionClass.isAnnotationPresent(Extension.class)) { - ordinal = extensionClass.getAnnotation(Extension.class).ordinal(); - } - descriptor.setOrdinal(ordinal); - descriptor.setExtensionClass(extensionClass); - - ExtensionWrapper extensionWrapper = new ExtensionWrapper<>(descriptor); - extensionWrapper.setExtensionFactory(pluginManager.getExtensionFactory()); - result.add(extensionWrapper); - log.debug("Added extension '{}' with ordinal {}", className, ordinal); - } else { - log.trace("'{}' is not an extension for extension point '{}'", className, type.getName()); - } - } catch (ClassNotFoundException e) { - log.error(e.getMessage(), e); - } + log.trace("Checking extensions from plugin '{}'", pluginId); + } else { + log.trace("Checking extensions from classpath"); + } + + ClassLoader classLoader = (pluginId != null) ? pluginManager.getPluginClassLoader(pluginId) : getClass().getClassLoader(); + + for (String className : classNames) { + try { + log.debug("Loading class '{}' using class loader '{}'", className, classLoader); + Class extensionClass = classLoader.loadClass(className); + + ExtensionWrapper extensionWrapper = createExtensionWrapper(extensionClass); + result.add(extensionWrapper); + log.debug("Added extension '{}' with ordinal {}", className, extensionWrapper.getOrdinal()); + } catch (ClassNotFoundException e) { + log.error(e.getMessage(), e); } } - if (entries.isEmpty()) { - log.debug("No extensions found for extension point '{}'", type.getName()); + if (result.isEmpty()) { + log.debug("No extensions found for plugin '{}'", pluginId); } else { - log.debug("Found {} extensions for extension point '{}'", result.size(), type.getName()); + log.debug("Found {} extensions for plugin '{}'", result.size(), pluginId); } // sort by "ordinal" property Collections.sort(result); - return result; - } + return result; + } @Override public Set findClassNames(String pluginId) { @@ -122,6 +186,17 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin entries = null; } + protected void logExtensions(Set extensions) { + if (extensions.isEmpty()) { + log.debug("No extensions found"); + } else { + log.debug("Found possible {} extensions:", extensions.size()); + for (String extension : extensions) { + log.debug(" " + extension); + } + } + } + private Map> readStorages() { Map> result = new LinkedHashMap<>(); @@ -139,4 +214,19 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin return entries; } + private ExtensionWrapper createExtensionWrapper(Class extensionClass) { + ExtensionDescriptor descriptor = new ExtensionDescriptor(); + int ordinal = 0; + if (extensionClass.isAnnotationPresent(Extension.class)) { + ordinal = extensionClass.getAnnotation(Extension.class).ordinal(); + } + descriptor.setOrdinal(ordinal); + descriptor.setExtensionClass(extensionClass); + + ExtensionWrapper extensionWrapper = new ExtensionWrapper<>(descriptor); + extensionWrapper.setExtensionFactory(pluginManager.getExtensionFactory()); + + return extensionWrapper; + } + } diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java index 66fb952..952f6d4 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java @@ -50,6 +50,27 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe return extensions; } + @Override + public List> find(Class type, String pluginId) { + List> extensions = new ArrayList<>(); + for (ExtensionFinder finder : finders) { + extensions.addAll(finder.find(type, pluginId)); + } + + return extensions; + } + + @Override + public List find(String pluginId) { + List extensions = new ArrayList<>(); + for (ExtensionFinder finder : finders) { + extensions.addAll(finder.find(pluginId)); + } + + return extensions; + } + + @Override public Set findClassNames(String pluginId) { Set classNames = new HashSet<>(); diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java index af85f1f..60b09e8 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java @@ -561,6 +561,29 @@ public class DefaultPluginManager implements PluginManager { return extensions; } + @Override + public List getExtensions(Class type, String pluginId) { + List> extensionsWrapper = extensionFinder.find(type, pluginId); + List extensions = new ArrayList<>(extensionsWrapper.size()); + for (ExtensionWrapper extensionWrapper : extensionsWrapper) { + extensions.add(extensionWrapper.getExtension()); + } + + return extensions; + } + + @Override + @SuppressWarnings("unchecked") + public List getExtensions(String pluginId) { + List extensionsWrapper = extensionFinder.find(pluginId); + List extensions = new ArrayList<>(extensionsWrapper.size()); + for (ExtensionWrapper extensionWrapper : extensionsWrapper) { + extensions.add(extensionWrapper.getExtension()); + } + + return extensions; + } + @Override public Set getExtensionClassNames(String pluginId) { return extensionFinder.findClassNames(pluginId); diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java index 3dc5149..d00e838 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java @@ -28,6 +28,16 @@ public interface ExtensionFinder { */ List> find(Class type); + /** + * Retrieves a list with all extensions found for an extension point and a plugin. + */ + List> find(Class type, String pluginId); + + /** + * Retrieves a list with all extensions found for a plugin + */ + List find(String pluginId); + /** * Retrieves a list with all extension class names found for a plugin. */ diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionWrapper.java b/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionWrapper.java index 8ee99c7..f150c0d 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionWrapper.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionWrapper.java @@ -30,7 +30,8 @@ public class ExtensionWrapper implements Comparable> { this.descriptor = descriptor; } - public T getExtension() { + @SuppressWarnings("unchecked") + public T getExtension() { if (extension == null) { extension = (T) extensionFactory.create(descriptor.getExtensionClass()); } diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/LegacyExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/LegacyExtensionFinder.java index 1e6e5db..dc47d0e 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/LegacyExtensionFinder.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/LegacyExtensionFinder.java @@ -59,14 +59,7 @@ public class LegacyExtensionFinder extends AbstractExtensionFinder { LegacyExtensionStorage.read(reader, bucket); } - if (bucket.isEmpty()) { - log.debug("No extensions found"); - } else { - log.debug("Found possible {} extensions:", bucket.size()); - for (String entry : bucket) { - log.debug(" " + entry); - } - } + logExtensions(bucket); result.put(null, bucket); } catch (IOException e) { @@ -97,14 +90,7 @@ public class LegacyExtensionFinder extends AbstractExtensionFinder { log.debug("Cannot find '{}'", getExtensionsResource()); } - if (bucket.isEmpty()) { - log.debug("No extensions found"); - } else { - log.debug("Found possible {} extensions:", bucket.size()); - for (String entry : bucket) { - log.debug(" " + entry); - } - } + logExtensions(bucket); result.put(pluginId, bucket); } catch (IOException e) { diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java index d079a64..5f23e5c 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java @@ -134,6 +134,10 @@ public interface PluginManager { List getExtensions(Class type); + List getExtensions(Class type, String pluginId); + + List getExtensions(String pluginId); + Set getExtensionClassNames(String pluginId); ExtensionFactory getExtensionFactory(); diff --git a/pf4j/src/main/java/ro/fortsoft/pf4j/ServiceProviderExtensionFinder.java b/pf4j/src/main/java/ro/fortsoft/pf4j/ServiceProviderExtensionFinder.java index 2a32c55..1794f69 100644 --- a/pf4j/src/main/java/ro/fortsoft/pf4j/ServiceProviderExtensionFinder.java +++ b/pf4j/src/main/java/ro/fortsoft/pf4j/ServiceProviderExtensionFinder.java @@ -70,27 +70,11 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder { } else { extensionPath = Paths.get(url.toURI()); } - Files.walkFileTree(extensionPath, Collections.emptySet(), 1, new SimpleFileVisitor() { - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - log.debug("Read '{}'", file); - Reader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8); - ServiceProviderExtensionStorage.read(reader, bucket); - return FileVisitResult.CONTINUE; - } - }); + bucket.addAll(readExtensions(extensionPath)); } - if (bucket.isEmpty()) { - log.debug("No extensions found"); - } else { - log.debug("Found possible {} extensions:", bucket.size()); - for (String entry : bucket) { - log.debug(" " + entry); - } - } + logExtensions(bucket); result.put(null, bucket); } catch (IOException | URISyntaxException e) { @@ -121,29 +105,13 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder { } else { extensionPath = Paths.get(url.toURI()); } - Files.walkFileTree(extensionPath, Collections.emptySet(), 1, new SimpleFileVisitor() { - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - log.debug("Read '{}'", file); - Reader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8); - ServiceProviderExtensionStorage.read(reader, bucket); - return FileVisitResult.CONTINUE; - } - }); + bucket.addAll(readExtensions(extensionPath)); } else { log.debug("Cannot find '{}'", getExtensionsResource()); } - if (bucket.isEmpty()) { - log.debug("No extensions found"); - } else { - log.debug("Found possible {} extensions:", bucket.size()); - for (String entry : bucket) { - log.debug(" " + entry); - } - } + logExtensions(bucket); result.put(pluginId, bucket); } catch (IOException | URISyntaxException e) { @@ -158,4 +126,21 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder { return ServiceProviderExtensionStorage.EXTENSIONS_RESOURCE; } + private Set readExtensions(Path extensionPath) throws IOException { + final Set result = new HashSet<>(); + Files.walkFileTree(extensionPath, Collections.emptySet(), 1, new SimpleFileVisitor() { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + log.debug("Read '{}'", file); + Reader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8); + ServiceProviderExtensionStorage.read(reader, result); + return FileVisitResult.CONTINUE; + } + + }); + + return result; + } + }