Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return a list of all extensions from a plugin and optional for an extension point #108

Merged
merged 2 commits into from
Aug 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 29 additions & 2 deletions demo/app/src/main/java/ro/fortsoft/pf4j/demo/Boot.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ public static void main(String[] args) {
}

// 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);
for (String extension : extensionClassNames) {
System.out.println(" " + extension);
}

// print extensions for each started plugin
// print extensions ids for each started plugin
List<PluginWrapper> startedPlugins = pluginManager.getStartedPlugins();
for (PluginWrapper plugin : startedPlugins) {
String pluginId = plugin.getDescriptor().getPluginId();
Expand All @@ -73,6 +73,33 @@ public static void main(String[] args) {
}
}

// 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
pluginManager.stopPlugins();
/*
Expand Down
178 changes: 135 additions & 43 deletions pf4j/src/main/java/ro/fortsoft/pf4j/AbstractExtensionFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,67 +48,131 @@ public AbstractExtensionFinder(PluginManager pluginManager) {
public <T> List<ExtensionWrapper<T>> find(Class<T> type) {
log.debug("Finding extensions of extension point '{}'", type.getName());
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<>();
for (Map.Entry<String, Set<String>> entry : entries.entrySet()) {
if (entry.getValue().isEmpty()) {
continue;

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;
}

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) {
PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginId);
if (PluginState.STARTED != pluginWrapper.getPluginState()) {
continue;
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);
}
}

log.trace("Checking extensions from plugin '{}'", pluginId);
} else {
log.trace("Checking extensions from classpath");
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());
}

// 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();

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<String> findClassNames(String pluginId) {
Expand All @@ -122,6 +186,19 @@ public void pluginStateChanged(PluginStateEvent event) {
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() {
Map<String, Set<String>> result = new LinkedHashMap<>();

Expand All @@ -139,4 +216,19 @@ private Map<String, Set<String>> getEntries() {
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 changes: 21 additions & 0 deletions pf4j/src/main/java/ro/fortsoft/pf4j/DefaultExtensionFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ public <T> List<ExtensionWrapper<T>> find(Class<T> type) {
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
public Set<String> findClassNames(String pluginId) {
Set<String> classNames = new HashSet<>();
Expand Down
23 changes: 23 additions & 0 deletions pf4j/src/main/java/ro/fortsoft/pf4j/DefaultPluginManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,29 @@ public <T> List<T> getExtensions(Class<T> type) {
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
public Set<String> getExtensionClassNames(String pluginId) {
return extensionFinder.findClassNames(pluginId);
Expand Down
10 changes: 10 additions & 0 deletions pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ public interface ExtensionFinder {
*/
<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.
*/
Expand Down
3 changes: 2 additions & 1 deletion pf4j/src/main/java/ro/fortsoft/pf4j/ExtensionWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public ExtensionWrapper(ExtensionDescriptor descriptor) {
this.descriptor = descriptor;
}

public T getExtension() {
@SuppressWarnings("unchecked")
public T getExtension() {
if (extension == null) {
extension = (T) extensionFactory.create(descriptor.getExtensionClass());
}
Expand Down
18 changes: 2 additions & 16 deletions pf4j/src/main/java/ro/fortsoft/pf4j/LegacyExtensionFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,7 @@ public Map<String, Set<String>> readClasspathStorages() {
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);
}
}
debugExtensions(bucket);

result.put(null, bucket);
} catch (IOException e) {
Expand Down Expand Up @@ -97,14 +90,7 @@ public Map<String, Set<String>> readPluginsStorages() {
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);
}
}
debugExtensions(bucket);

result.put(pluginId, bucket);
} catch (IOException e) {
Expand Down
4 changes: 4 additions & 0 deletions pf4j/src/main/java/ro/fortsoft/pf4j/PluginManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ public interface PluginManager {

<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);

ExtensionFactory getExtensionFactory();
Expand Down