@@ -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<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(); | |||
@@ -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 | |||
pluginManager.stopPlugins(); | |||
/* |
@@ -48,67 +48,131 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin | |||
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(); | |||
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<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) { | |||
@@ -122,6 +186,17 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin | |||
entries = null; | |||
} | |||
protected void logExtensions(Set<String> 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<String, Set<String>> readStorages() { | |||
Map<String, Set<String>> 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; | |||
} | |||
} |
@@ -50,6 +50,27 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe | |||
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<>(); |
@@ -561,6 +561,29 @@ public class DefaultPluginManager implements PluginManager { | |||
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); |
@@ -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. | |||
*/ |
@@ -30,7 +30,8 @@ public class ExtensionWrapper<T> implements Comparable<ExtensionWrapper<T>> { | |||
this.descriptor = descriptor; | |||
} | |||
public T getExtension() { | |||
@SuppressWarnings("unchecked") | |||
public T getExtension() { | |||
if (extension == null) { | |||
extension = (T) extensionFactory.create(descriptor.getExtensionClass()); | |||
} |
@@ -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) { |
@@ -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(); |
@@ -70,27 +70,11 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder { | |||
} else { | |||
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()) { | |||
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.<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 { | |||
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<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; | |||
} | |||
} |