All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jerkar.tool.PluginDictionary Maven / Gradle / Ivy

The newest version!
package org.jerkar.tool;

import org.jerkar.api.java.JkClassLoader;
import org.jerkar.api.java.JkUrlClassLoader;
import org.jerkar.api.system.JkException;
import org.jerkar.api.utils.JkUtilsReflect;
import org.jerkar.api.utils.JkUtilsString;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Contains description for all concrete plugins in current classpath.
 * 

* Jerkar offers a very simple, yet powerful, plugin mechanism.
* Basically it offers to discover every classes in the classpath that inherit * to a given class and that respect a certain naming convention.
*

* The naming convention is as follow : The class simple name should be prefixed * with 'JkPlugin'.
* For example, 'my.package.JkPluginXxxxx' will be discovered as a plugin named Xxxxx. * * @author Jerome Angibaud * * @see {@link PluginDescription} */ final class PluginDictionary { private static final Map SHORTNAME_CACHE = new LinkedHashMap<>(); private Set plugins; /** * Returns all the plugins present in classpath for this template class. */ Set getAll() { if (plugins == null) { synchronized (this) { final Set result = loadAllPlugins(); this.plugins = Collections.unmodifiableSet(result); } } return this.plugins; } /** * Returns the plugin having a full name equals to the specified value. If * not found, returns the plugin having a short name equals to the specified * name. Note that the short value is capitalized for you so using * "myPluging" or "MyPlugin" is equal. If not found, returns * null. */ static PluginDescription loadByName(String name) { if (!name.contains(".")) { final PluginDescription result = loadPluginHavingShortName( JkUtilsString.capitalize(name)); if (result != null) { return result; } } return loadPluginsHavingLongName(name); } private static String simpleClassName(String pluginName) { return JkPlugin.class.getSimpleName() + JkUtilsString.capitalize(pluginName); } @Override public String toString() { if (this.plugins == null) { return "Not loaded."; } return this.plugins.toString(); } private static Set loadAllPlugins() { final String nameSuffix = JkPlugin.class.getSimpleName(); return loadPlugins( "**/" + nameSuffix + "*", nameSuffix, "**/*$" + nameSuffix + "*", "*$" + nameSuffix + "*"); } private static PluginDescription loadPluginHavingShortName(String shortName) { PluginDescription result = SHORTNAME_CACHE.get(shortName); if (result != null) { return result; } final String simpleName = simpleClassName(shortName); final Set set = loadPlugins( "**/" + simpleName, simpleName, "**/*$" + simpleName, "*$" + simpleName ); if (set.size() > 1) { throw new JkException("Several plugin have the same short name : '" + shortName + "'. Please disambiguate with using plugin long name (full class value)." + " Following plugins have same shortName : " + set); } if (set.isEmpty()) { return null; } result = set.iterator().next(); SHORTNAME_CACHE.put(shortName, result); return result; } private static PluginDescription loadPluginsHavingLongName(String longName) { final Class pluginClass = JkClassLoader.ofCurrent().loadIfExist(longName); if (pluginClass == null) { return null; } return new PluginDescription(pluginClass); } private static Set loadPlugins(String... patterns) { final Set> matchingClasses = JkUrlClassLoader.ofCurrent().loadClasses(patterns); return toPluginSet(matchingClasses.stream() .filter(clazz -> JkPlugin.class.isAssignableFrom(clazz)) .filter(clazz -> !Modifier.isAbstract(clazz.getModifiers())) .collect(Collectors.toSet())); } @SuppressWarnings("unchecked") private static Set toPluginSet(Iterable> classes) { final Set result = new TreeSet<>(); for (final Class clazz : classes) { result.add(new PluginDescription((Class) clazz)); } return result; } /** * Give the description of a plugin class as its name, its purpose and its * base class. * * @author Jerome Angibaud */ static class PluginDescription implements Comparable { private static String shortName(Class clazz) { return JkUtilsString.uncapitalize(JkUtilsString.substringAfterFirst(clazz.getSimpleName(), JkPlugin.class.getSimpleName())); } private static String longName(Class clazz) { return clazz.getName(); } private final String shortName; private final String fullName; private final Class clazz; public PluginDescription(Class clazz) { super(); this.shortName = shortName(clazz); this.fullName = longName(clazz); this.clazz = clazz; } public List pluginDependencies() { List result = new LinkedList<>(); JkDocPluginDeps pluginDeps = clazz.getAnnotation(JkDocPluginDeps.class); if (pluginDeps == null) { return Collections.emptyList(); } for (Class depClass : pluginDeps.value()) { result.add(depClass.getName()); } return result; } public String shortName() { return this.shortName; } public String fullName() { return this.fullName; } public Class pluginClass() { return clazz; } public List explanation() { if (this.clazz.getAnnotation(JkDoc.class) == null) { return Collections.emptyList(); } return Arrays.asList(this.clazz.getAnnotation(JkDoc.class).value()); } public List activationEffect() { JkDoc doc = JkUtilsReflect.getInheritedAnnotation(clazz, JkDoc.class, "activate"); return doc == null ? Collections.emptyList() : Arrays.asList(doc.value()); } boolean isDecorateRunDefined() { Method decorateRun = JkUtilsReflect.findMethodMethodDeclaration(clazz, "activate"); return decorateRun != null && !decorateRun.getDeclaringClass().equals(JkPlugin.class); } @Override public String toString() { return "name=" + this.shortName + "(" + this.fullName + ")"; } @Override public int compareTo(PluginDescription o) { return this.shortName.compareTo(o.shortName); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy