Browse Source

Merge pull request #108 from decebals/extensions_per_plugin

Return a list of all extensions from a plugin and optional for an ension point
pull/111/head
Decebal Suiu 8 years ago committed by GitHub
parent
commit
59fed935fb
  1. 31
      demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java
  2. 178
      pf4j/src/main/java/ro/fortsoft/pf4j/AbstractExtensionFinder.java
  3. 21
      pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
  4. 23
      pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
  5. 10
      pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java
  6. 3
      pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionWrapper.java
  7. 18
      pf4j/src/main/java/ro/fortsoft/pf4j/LegacyExtensionFinder.java
  8. 4
      pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java
  9. 57
      pf4j/src/main/java/ro/fortsoft/pf4j/ServiceProviderExtensionFinder.java

31
demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java

@ -56,13 +56,13 @@ public class Boot {
} }
// print extensions from classpath (non plugin) // print extensions from classpath (non plugin)
System.out.println(String.format("Extensions added by classpath:")); System.out.println("Extensions added by classpath:");
Set<String> extensionClassNames = pluginManager.getExtensionClassNames(null); Set<String> extensionClassNames = pluginManager.getExtensionClassNames(null);
for (String extension : extensionClassNames) { for (String extension : extensionClassNames) {
System.out.println(" " + extension); System.out.println(" " + extension);
} }
// print extensions for each started plugin // print extensions ids for each started plugin
List<PluginWrapper> startedPlugins = pluginManager.getStartedPlugins(); List<PluginWrapper> startedPlugins = pluginManager.getStartedPlugins();
for (PluginWrapper plugin : startedPlugins) { for (PluginWrapper plugin : startedPlugins) {
String pluginId = plugin.getDescriptor().getPluginId(); 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<Greeting> 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 // stop the plugins
pluginManager.stopPlugins(); pluginManager.stopPlugins();
/* /*

178
pf4j/src/main/java/ro/fortsoft/pf4j/AbstractExtensionFinder.java

@ -48,67 +48,131 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin
public <T> List<ExtensionWrapper<T>> find(Class<T> type) { public <T> List<ExtensionWrapper<T>> find(Class<T> type) {
log.debug("Finding extensions of extension point '{}'", type.getName()); log.debug("Finding extensions of extension point '{}'", type.getName());
Map<String, Set<String>> entries = getEntries(); Map<String, Set<String>> entries = getEntries();
List<ExtensionWrapper<T>> result = new ArrayList<>();
// add extensions found in classpath
List<ExtensionWrapper<T>> classpathExtensions = find(type, null);
result.addAll(classpathExtensions);
// add extensions found in each plugin
for (String pluginId : entries.keySet()) {
List<ExtensionWrapper<T>> 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 <T> List<ExtensionWrapper<T>> find(Class<T> type, String pluginId) {
log.debug("Finding extensions of extension point '{}' for plugin '{}'", type.getName(), pluginId);
List<ExtensionWrapper<T>> result = new ArrayList<>(); List<ExtensionWrapper<T>> result = new ArrayList<>();
for (Map.Entry<String, Set<String>> entry : entries.entrySet()) {
if (entry.getValue().isEmpty()) { Set<String> classNames = findClassNames(pluginId);
continue; 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();
for (String className : classNames) {
try {
log.debug("Loading class '{}' using class loader '{}'", className, classLoader);
Class<?> extensionClass = classLoader.loadClass(className);
if (pluginId != null) { log.debug("Checking extension type '{}'", className);
PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginId); if (type.isAssignableFrom(extensionClass)) {
if (PluginState.STARTED != pluginWrapper.getPluginState()) { ExtensionWrapper extensionWrapper = createExtensionWrapper(extensionClass);
continue; 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);
}
}
log.trace("Checking extensions from plugin '{}'", pluginId); if (result.isEmpty()) {
} else { log.debug("No extensions found for extension point '{}'", type.getName());
log.trace("Checking extensions from classpath"); } else {
log.debug("Found {} extensions for extension point '{}'", result.size(), type.getName());
}
// sort by "ordinal" property
Collections.sort(result);
return result;
}
@Override
public List<ExtensionWrapper> find(String pluginId) {
log.debug("Finding extensions from plugin '{}'", pluginId);
List<ExtensionWrapper> result = new ArrayList<>();
Set<String> 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(); log.trace("Checking extensions from plugin '{}'", pluginId);
} else {
for (String className : entry.getValue()) { log.trace("Checking extensions from classpath");
try { }
log.debug("Loading class '{}' using class loader '{}'", className, classLoader);
Class<?> extensionClass = classLoader.loadClass(className); ClassLoader classLoader = (pluginId != null) ? pluginManager.getPluginClassLoader(pluginId) : getClass().getClassLoader();
log.debug("Checking extension type '{}'", className); for (String className : classNames) {
if (type.isAssignableFrom(extensionClass)) { try {
ExtensionDescriptor descriptor = new ExtensionDescriptor(); log.debug("Loading class '{}' using class loader '{}'", className, classLoader);
int ordinal = 0; Class<?> extensionClass = classLoader.loadClass(className);
if (extensionClass.isAnnotationPresent(Extension.class)) {
ordinal = extensionClass.getAnnotation(Extension.class).ordinal(); ExtensionWrapper extensionWrapper = createExtensionWrapper(extensionClass);
} result.add(extensionWrapper);
descriptor.setOrdinal(ordinal); log.debug("Added extension '{}' with ordinal {}", className, extensionWrapper.getOrdinal());
descriptor.setExtensionClass(extensionClass); } catch (ClassNotFoundException e) {
log.error(e.getMessage(), e);
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);
}
} }
} }
if (entries.isEmpty()) { if (result.isEmpty()) {
log.debug("No extensions found for extension point '{}'", type.getName()); log.debug("No extensions found for plugin '{}'", pluginId);
} else { } 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 // sort by "ordinal" property
Collections.sort(result); Collections.sort(result);
return result; return result;
} }
@Override @Override
public Set<String> findClassNames(String pluginId) { public Set<String> findClassNames(String pluginId) {
@ -122,6 +186,19 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin
entries = null; entries = null;
} }
protected void debugExtensions(Set<String> extensions) {
if (log.isDebugEnabled()) {
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<String, Set<String>> readStorages() { private Map<String, Set<String>> readStorages() {
Map<String, Set<String>> result = new LinkedHashMap<>(); Map<String, Set<String>> result = new LinkedHashMap<>();
@ -139,4 +216,19 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin
return entries; 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;
}
} }

21
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java

@ -50,6 +50,27 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
return extensions; return extensions;
} }
@Override
public <T> List<ExtensionWrapper<T>> find(Class<T> type, String pluginId) {
List<ExtensionWrapper<T>> extensions = new ArrayList<>();
for (ExtensionFinder finder : finders) {
extensions.addAll(finder.find(type, pluginId));
}
return extensions;
}
@Override
public List<ExtensionWrapper> find(String pluginId) {
List<ExtensionWrapper> extensions = new ArrayList<>();
for (ExtensionFinder finder : finders) {
extensions.addAll(finder.find(pluginId));
}
return extensions;
}
@Override @Override
public Set<String> findClassNames(String pluginId) { public Set<String> findClassNames(String pluginId) {
Set<String> classNames = new HashSet<>(); Set<String> classNames = new HashSet<>();

23
pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java

@ -561,6 +561,29 @@ public class DefaultPluginManager implements PluginManager {
return extensions; return extensions;
} }
@Override
public <T> List<T> getExtensions(Class<T> type, String pluginId) {
List<ExtensionWrapper<T>> extensionsWrapper = extensionFinder.find(type, pluginId);
List<T> extensions = new ArrayList<>(extensionsWrapper.size());
for (ExtensionWrapper<T> extensionWrapper : extensionsWrapper) {
extensions.add(extensionWrapper.getExtension());
}
return extensions;
}
@Override
@SuppressWarnings("unchecked")
public List getExtensions(String pluginId) {
List<ExtensionWrapper> extensionsWrapper = extensionFinder.find(pluginId);
List extensions = new ArrayList<>(extensionsWrapper.size());
for (ExtensionWrapper extensionWrapper : extensionsWrapper) {
extensions.add(extensionWrapper.getExtension());
}
return extensions;
}
@Override @Override
public Set<String> getExtensionClassNames(String pluginId) { public Set<String> getExtensionClassNames(String pluginId) {
return extensionFinder.findClassNames(pluginId); return extensionFinder.findClassNames(pluginId);

10
pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java

@ -28,6 +28,16 @@ public interface ExtensionFinder {
*/ */
<T> List<ExtensionWrapper<T>> find(Class<T> type); <T> List<ExtensionWrapper<T>> find(Class<T> type);
/**
* Retrieves a list with all extensions found for an extension point and a plugin.
*/
<T> List<ExtensionWrapper<T>> find(Class<T> type, String pluginId);
/**
* Retrieves a list with all extensions found for a plugin
*/
List<ExtensionWrapper> find(String pluginId);
/** /**
* Retrieves a list with all extension class names found for a plugin. * Retrieves a list with all extension class names found for a plugin.
*/ */

3
pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionWrapper.java

@ -30,7 +30,8 @@ public class ExtensionWrapper<T> implements Comparable<ExtensionWrapper<T>> {
this.descriptor = descriptor; this.descriptor = descriptor;
} }
public T getExtension() { @SuppressWarnings("unchecked")
public T getExtension() {
if (extension == null) { if (extension == null) {
extension = (T) extensionFactory.create(descriptor.getExtensionClass()); extension = (T) extensionFactory.create(descriptor.getExtensionClass());
} }

18
pf4j/src/main/java/ro/fortsoft/pf4j/LegacyExtensionFinder.java

@ -59,14 +59,7 @@ public class LegacyExtensionFinder extends AbstractExtensionFinder {
LegacyExtensionStorage.read(reader, bucket); LegacyExtensionStorage.read(reader, bucket);
} }
if (bucket.isEmpty()) { debugExtensions(bucket);
log.debug("No extensions found");
} else {
log.debug("Found possible {} extensions:", bucket.size());
for (String entry : bucket) {
log.debug(" " + entry);
}
}
result.put(null, bucket); result.put(null, bucket);
} catch (IOException e) { } catch (IOException e) {
@ -97,14 +90,7 @@ public class LegacyExtensionFinder extends AbstractExtensionFinder {
log.debug("Cannot find '{}'", getExtensionsResource()); log.debug("Cannot find '{}'", getExtensionsResource());
} }
if (bucket.isEmpty()) { debugExtensions(bucket);
log.debug("No extensions found");
} else {
log.debug("Found possible {} extensions:", bucket.size());
for (String entry : bucket) {
log.debug(" " + entry);
}
}
result.put(pluginId, bucket); result.put(pluginId, bucket);
} catch (IOException e) { } catch (IOException e) {

4
pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java

@ -134,6 +134,10 @@ public interface PluginManager {
<T> List<T> getExtensions(Class<T> type); <T> List<T> getExtensions(Class<T> type);
<T> List<T> getExtensions(Class<T> type, String pluginId);
List getExtensions(String pluginId);
Set<String> getExtensionClassNames(String pluginId); Set<String> getExtensionClassNames(String pluginId);
ExtensionFactory getExtensionFactory(); ExtensionFactory getExtensionFactory();

57
pf4j/src/main/java/ro/fortsoft/pf4j/ServiceProviderExtensionFinder.java

@ -70,27 +70,11 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder {
} else { } else {
extensionPath = Paths.get(url.toURI()); extensionPath = Paths.get(url.toURI());
} }
Files.walkFileTree(extensionPath, Collections.<FileVisitOption>emptySet(), 1, new SimpleFileVisitor<Path>() {
@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()) { debugExtensions(bucket);
log.debug("No extensions found");
} else {
log.debug("Found possible {} extensions:", bucket.size());
for (String entry : bucket) {
log.debug(" " + entry);
}
}
result.put(null, bucket); result.put(null, bucket);
} catch (IOException | URISyntaxException e) { } catch (IOException | URISyntaxException e) {
@ -121,29 +105,13 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder {
} else { } else {
extensionPath = Paths.get(url.toURI()); extensionPath = Paths.get(url.toURI());
} }
Files.walkFileTree(extensionPath, Collections.<FileVisitOption>emptySet(), 1, new SimpleFileVisitor<Path>() {
@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 { } else {
log.debug("Cannot find '{}'", getExtensionsResource()); log.debug("Cannot find '{}'", getExtensionsResource());
} }
if (bucket.isEmpty()) { debugExtensions(bucket);
log.debug("No extensions found");
} else {
log.debug("Found possible {} extensions:", bucket.size());
for (String entry : bucket) {
log.debug(" " + entry);
}
}
result.put(pluginId, bucket); result.put(pluginId, bucket);
} catch (IOException | URISyntaxException e) { } catch (IOException | URISyntaxException e) {
@ -158,4 +126,21 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder {
return ServiceProviderExtensionStorage.EXTENSIONS_RESOURCE; return ServiceProviderExtensionStorage.EXTENSIONS_RESOURCE;
} }
private Set<String> readExtensions(Path extensionPath) throws IOException {
final Set<String> result = new HashSet<>();
Files.walkFileTree(extensionPath, Collections.<FileVisitOption>emptySet(), 1, new SimpleFileVisitor<Path>() {
@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;
}
} }

Loading…
Cancel
Save