/** * Copyright (C) 2013 Kametic <epo.jemba@kametic.com> * * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3, 29 June 2007; * or any later version * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.gnu.org/licenses/lgpl-3.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.nuunframework.kernel; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.collections.iterators.ArrayIterator; import org.nuunframework.kernel.commons.graph.Graph; import org.nuunframework.kernel.context.Context; import org.nuunframework.kernel.context.InitContext; import org.nuunframework.kernel.context.InitContextInternal; import org.nuunframework.kernel.internal.InternalKernelGuiceModule; import org.nuunframework.kernel.plugin.InitState; import org.nuunframework.kernel.plugin.Plugin; import org.nuunframework.kernel.plugin.RoundEnvironementInternal; import org.nuunframework.kernel.plugin.provider.DependencyInjectionProvider; import org.nuunframework.kernel.plugin.request.BindingRequest; import org.nuunframework.kernel.plugin.request.ClasspathScanRequest; import org.nuunframework.kernel.plugin.request.KernelParamsRequest; import org.nuunframework.kernel.plugin.request.KernelParamsRequestType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Strings; import com.google.common.collect.Sets; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.Stage; import com.google.inject.util.Modules; /** * @author Epo Jemba */ public final class Kernel { public static final String NUUN_ROOT_PACKAGE = "nuun.root.package"; public static final String NUUN_NUM_CP_PATH = "nuun.num.classpath.path"; public static final String NUUN_CP_PATH_PREFIX = "nuun.classpath.path.prefix-"; public static final String NUUN_CP_STRATEGY_NAME = "nuun.classpath.strategy.name"; public static final String NUUN_CP_STRATEGY_ADD = "nuun.classpath.strategy.additional"; public static final String KERNEL_PREFIX_NAME = "Kernel-"; private final int MAXIMAL_ROUND_NUMBER = 50; private final Logger logger; private static ConcurrentHashMap<String, Kernel> kernels = new ConcurrentHashMap<String, Kernel>(); private final String name; private final String NUUN_PROPERTIES_PREFIX = "nuun-"; private ServiceLoader<Plugin> pluginLoader; private boolean spiPluginEnabled = true; private Map<String, Plugin> plugins = Collections.synchronizedMap(new HashMap<String, Plugin>()); // private Map<String, Plugin> pluginsToAdd = Collections.synchronizedMap(new HashMap<String, Plugin>()); // private final InitContextInternal initContext; private Injector mainInjector; private final AliasMap kernelParamsAndAlias; private boolean started = false; private boolean initialized = false; private Context context; private Collection<DependencyInjectionProvider> dependencyInjectionProviders; private Object containerContext; private ArrayList<Plugin> orderedPlugins; private Collection<DependencyInjectionProvider> globalDependencyInjectionProviders; private List<Iterator<Plugin>> pluginIterators; private List<Plugin> fetchedPlugins; private Set<URL> globalAdditionalClasspath; private RoundEnvironementInternal roundEnv; private Kernel(String... keyValues) { name = KERNEL_PREFIX_NAME+kernels.size(); logger = LoggerFactory.getLogger( Kernel.class.getPackage().getName() +'.' + name()); kernelParamsAndAlias = new AliasMap(); @SuppressWarnings("unchecked") Iterator<String> it = new ArrayIterator(keyValues); while (it.hasNext()) { String key = it.next(); String value = ""; if (it.hasNext()) value = it.next(); logger.info("Adding {} = {} as param to kernel", key, value); kernelParamsAndAlias.put(key, value); } this.initContext = new InitContextInternal(NUUN_PROPERTIES_PREFIX, kernelParamsAndAlias); } public String name() { return name; } public boolean isStarted() { return started; } public boolean isInitialized() { return initialized; } /** * * */ public synchronized void init() { if (!initialized) { fetchPlugins(); computeAliases(); initRoundEnvironment(); checkPlugins(); fetchGlobalParametersFromPlugins(); initPlugins(); initialized = true; } else { throw new KernelException("Kernel is already initialized"); } } private void initRoundEnvironment() { // we initialize plugins roundEnv = new RoundEnvironementInternal(); for (Plugin plugin : fetchedPlugins) { // we pass the roundEnvironment plugin.provideRoundEnvironment(roundEnv); } } private void fetchGlobalParametersFromPlugins() { globalDependencyInjectionProviders = new HashSet<DependencyInjectionProvider>(); globalAdditionalClasspath = Sets.newHashSet(); // Constants from plugin outside rounds // We pass the container context object for plugin for (Plugin plugin : plugins.values()) { plugin.provideContainerContext(containerContext); String name = plugin.name(); logger.info("Get additional classpath to scan from Plugin {}.", name); Set<URL> computeAdditionalClasspathScan = plugin.computeAdditionalClasspathScan(); if (computeAdditionalClasspathScan != null && computeAdditionalClasspathScan.size() > 0) { logger.info("Adding from Plugin {} start.", name); for (URL url : computeAdditionalClasspathScan) { if (url != null) { globalAdditionalClasspath.add(url); logger.debug(url.toExternalForm()); } } logger.info("Adding from Plugin {} end. {} elements.", name, "" + computeAdditionalClasspathScan.size()); } // Convert dependency manager classes to instances // DependencyInjectionProvider iocProvider = plugin.dependencyInjectionProvider(); if (iocProvider != null) { globalDependencyInjectionProviders.add(iocProvider); } } } @SuppressWarnings("unchecked") private void fetchPlugins() { // plugin from kernel call api Iterator<Plugin> iterator1 = pluginsToAdd.values().iterator(); // TODO add unit and test integration test for this if (spiPluginEnabled) { pluginLoader = ServiceLoader.load(Plugin.class, Thread.currentThread().getContextClassLoader()); // plugin from service loader Iterator<Plugin> iterator2 = pluginLoader.iterator(); pluginIterators = Arrays.asList(iterator2, iterator1); } else { pluginIterators = Arrays.asList(iterator1); } fetchedPlugins = new LinkedList<Plugin>(); for (Iterator<Plugin> iterator : pluginIterators) { Plugin plugin; while (iterator.hasNext()) { plugin = iterator.next(); fetchedPlugins.add(plugin); } } } private void computeAliases() { // Compute alias for (Plugin plugin : fetchedPlugins) { Map<String, String> pluginKernelParametersAliases = plugin.kernelParametersAliases(); for (Entry<String, String> entry : pluginKernelParametersAliases.entrySet()) { // entry.getValue() is the alias to give // entry.getKey() is the key to alias logger.info("Adding alias parameter \"{}\" to key \"{}\"." , entry.getKey() , entry.getValue()); kernelParamsAndAlias.putAlias(entry.getKey() , entry.getValue()); } } // if (kernelParamsAndAlias.containsKey(NUUN_ROOT_PACKAGE)) { String tmp = kernelParamsAndAlias.get(NUUN_ROOT_PACKAGE); fillPackagesRoot(tmp); } } // String getKernelParam(String key) // { // // } /** * */ private void checkPlugins() { logger.info("Plugins initialisation "); plugins.clear(); List<Class<? extends Plugin>> pluginClasses = new ArrayList<Class<? extends Plugin>>(); for (Plugin plugin : fetchedPlugins) { String pluginName = plugin.name(); logger.info("checking Plugin {}.", pluginName); if (!Strings.isNullOrEmpty(pluginName)) { Object ok = plugins.put(pluginName, plugin); if (ok == null) { // Check for required param // ======================== Collection<KernelParamsRequest> kernelParamsRequests = plugin.kernelParamsRequests(); Collection<String> computedMandatoryParams = new HashSet<String>(); for (KernelParamsRequest kernelParamsRequest : kernelParamsRequests) { if (kernelParamsRequest.requestType == KernelParamsRequestType.MANDATORY) { computedMandatoryParams.add(kernelParamsRequest.keyRequested); } } if (kernelParamsAndAlias.containsAllKeys(computedMandatoryParams)) // if (kernelParams.keySet().containsAll(computedMandatoryParams)) { pluginClasses.add(plugin.getClass()); } else { logger.error("plugin {} miss parameter/s : {}", pluginName, kernelParamsRequests.toString()); throw new KernelException("plugin " + pluginName + " miss parameter/s : " + kernelParamsRequests.toString()); } } else { logger.error("Can not have 2 Plugin {} of the same type {}. please fix this before the kernel can start.", pluginName, plugin.getClass() .getName()); throw new KernelException( "Can not have 2 Plugin %s of the same type %s. please fix this before the kernel can start.", pluginName, plugin.getClass() .getName()); } } else { logger.warn("Plugin {} has no correct name it won't be installed.", plugin.getClass()); throw new KernelException("Plugin %s has no correct name it won't be installed.", pluginName); } } // Check for required and dependent plugins for (Plugin plugin : plugins.values()) { { Collection<Class<? extends Plugin>> pluginDependenciesRequired = plugin.requiredPlugins(); if (pluginDependenciesRequired != null && !pluginDependenciesRequired.isEmpty() && !pluginClasses.containsAll(pluginDependenciesRequired)) { logger.error("plugin {} misses the following plugin/s as dependency/ies {}", plugin.name(), pluginDependenciesRequired.toString()); throw new KernelException("plugin %s misses the following plugin/s as dependency/ies %s", plugin.name(), pluginDependenciesRequired.toString()); } } { Collection<Class<? extends Plugin>> dependentPlugin = plugin.dependentPlugins(); if (dependentPlugin != null && !dependentPlugin.isEmpty() && !pluginClasses.containsAll(dependentPlugin)) { logger.error("plugin {} misses the following plugin/s as dependee/s {}", plugin.name(), dependentPlugin.toString()); throw new KernelException("plugin %s misses the following plugin/s as dependee/s %s", plugin.name(), dependentPlugin.toString()); } } } } public synchronized void preStart() { } public synchronized void start() { if (initialized) { // All bindings will be computed InternalKernelGuiceModule internalKernelGuiceModule = new InternalKernelGuiceModule(initContext); InternalKernelGuiceModule internalKernelGuiceModuleOverriding = new InternalKernelGuiceModule(initContext).overriding(); Module mainFinalModule = Modules.override(internalKernelGuiceModule).with(internalKernelGuiceModuleOverriding); mainInjector = Guice.createInjector( Stage.PRODUCTION , mainFinalModule); // Here we can pass the mainInjector to the non guice modules context = mainInjector.getInstance(Context.class); // 1) inject plugins via injector // 2) inject context via injector // 2) start them for (Plugin plugin : orderedPlugins) { mainInjector.injectMembers(plugin); plugin.start(context); } started = true; } else { throw new KernelException("Kernel is not initialized."); } } public Injector getMainInjector() { return mainInjector; } public void stop() { // 1) stop plugins // for (Plugin plugin : plugins.values()) { plugin.stop(); } } /** * */ @SuppressWarnings("unchecked") private void initPlugins() { // We reset the resettable element of initcontext this.initContext.reset(); // Get plugins requests // ==================== Collection<Plugin> globalPlugins = plugins.values(); // first round all plugins // We sort them ArrayList<Plugin> unOrderedPlugins = new ArrayList<Plugin>(globalPlugins); logger.info("unordered plugins: (" + unOrderedPlugins.size() + ") " + unOrderedPlugins); orderedPlugins = sortPlugins(unOrderedPlugins); logger.info("ordered plugins: (" + orderedPlugins.size() + ") " + orderedPlugins); Map<String,InitState> states = new HashMap<String, InitState>(); ArrayList<Plugin> roundOrderedPlugins = new ArrayList<Plugin>(orderedPlugins); do { // ROUND ITERATIONS // we update the number of initialization round. this.initContext.roundNumber(roundEnv.roundNumber()); logger.info("ROUND " + roundEnv.roundNumber() + " of the kernel initialisation."); for (Plugin plugin : roundOrderedPlugins) { // Configure properties prefixes String pluginPropertiesPrefix = plugin.pluginPropertiesPrefix(); if (!Strings.isNullOrEmpty(pluginPropertiesPrefix)) { this.initContext.addPropertiesPrefix(pluginPropertiesPrefix); } // Configure package root String pluginPackageRoot = plugin.pluginPackageRoot(); fillPackagesRoot(pluginPackageRoot); Collection<ClasspathScanRequest> classpathScanRequests = plugin.classpathScanRequests(); if (classpathScanRequests != null && classpathScanRequests.size() > 0) { for (ClasspathScanRequest request : classpathScanRequests) { switch (request.requestType) { case ANNOTATION_TYPE: this.initContext.addAnnotationTypesToScan((Class<? extends Annotation>) request.objectRequested); break; case ANNOTATION_REGEX_MATCH: this.initContext.addAnnotationRegexesToScan((String) request.objectRequested); break; // case META_ANNOTATION_TYPE: // this.initContext.addAnnotationTypesToScan((Class<? extends Annotation>) // request.objectRequested); // break; // case META_ANNOTATION_REGEX_MATCH: // this.initContext.addAnnotationRegexesToScan((String) request.objectRequested); // break; case SUBTYPE_OF_BY_CLASS: this.initContext.addParentTypeClassToScan((Class<?>) request.objectRequested); break; case SUBTYPE_OF_BY_TYPE_DEEP: this.initContext.addAncestorTypeClassToScan((Class<?>) request.objectRequested); break; case SUBTYPE_OF_BY_REGEX_MATCH: this.initContext.addParentTypeRegexesToScan((String) request.objectRequested); break; case RESOURCES_REGEX_MATCH: this.initContext.addResourcesRegexToScan((String) request.objectRequested); // this.initContext.addTypeClassToScan((Class<?>) request.objectRequested); break; case TYPE_OF_BY_REGEX_MATCH: this.initContext.addTypeRegexesToScan((String) request.objectRequested); break; case VIA_SPECIFICATION: // pas encore pluggé this.initContext.addSpecificationToScan(request.specification); break; default: logger.warn("{} is not a ClasspathScanRequestType a o_O", request.requestType); break; } } } Collection<BindingRequest> bindingRequests = plugin.bindingRequests(); if (bindingRequests != null && bindingRequests.size() > 0) { for (BindingRequest request : bindingRequests) { switch (request.requestType) { case ANNOTATION_TYPE: this.initContext.addAnnotationTypesToBind((Class<? extends Annotation>) request.requestedObject, request.requestedScope); break; case ANNOTATION_REGEX_MATCH: this.initContext.addAnnotationRegexesToBind((String) request.requestedObject, request.requestedScope); break; case META_ANNOTATION_TYPE: this.initContext.addMetaAnnotationTypesToBind((Class<? extends Annotation>) request.requestedObject, request.requestedScope); break; case META_ANNOTATION_REGEX_MATCH: this.initContext.addMetaAnnotationRegexesToBind((String) request.requestedObject, request.requestedScope); break; case SUBTYPE_OF_BY_CLASS: this.initContext.addParentTypeClassToBind((Class<?>) request.requestedObject, request.requestedScope); break; case SUBTYPE_OF_BY_TYPE_DEEP: this.initContext.addAncestorTypeClassToBind((Class<?>) request.requestedObject, request.requestedScope); break; case SUBTYPE_OF_BY_REGEX_MATCH: this.initContext.addTypeRegexesToBind((String) request.requestedObject, request.requestedScope); break; case VIA_SPECIFICATION: this.initContext.addSpecificationToBind(request.specification, request.requestedScope); break; default: logger.warn("{} is not a BindingRequestType o_O !", request.requestType); break; } } } } // end plugin request for (URL url : globalAdditionalClasspath) { initContext.addClasspathToScan(url); } // We launch classpath scan and store results of requests this.initContext.executeRequests(); // INITIALISATION for (Plugin plugin : roundOrderedPlugins) { InitContext actualInitContext = this.initContext; // TODO : we compute dependencies only in round 0 for first version , no other plugin will be given Collection<Class<? extends Plugin>> requiredPluginsClasses = plugin.requiredPlugins(); Collection<Class<? extends Plugin>> dependentPluginsClasses = plugin.dependentPlugins(); if (roundEnv.roundNumber() == 0 && (requiredPluginsClasses != null && !requiredPluginsClasses.isEmpty()) || (dependentPluginsClasses != null && !dependentPluginsClasses.isEmpty()) ) { Collection<Plugin> requiredPlugins = filterPlugins(globalPlugins, requiredPluginsClasses); Collection<Plugin> dependentPlugins = filterPlugins(globalPlugins, dependentPluginsClasses); actualInitContext = proxyfy(initContext, requiredPlugins,dependentPlugins); } String name = plugin.name(); logger.info("initializing Plugin {}.", name); InitState state = plugin.init(actualInitContext); states.put(name, state); } // After been initialized plugin can give they module // Configure module // ArrayList<Plugin> nextRoundOrderedPlugins = new ArrayList<Plugin>(); for (Plugin plugin : roundOrderedPlugins) { String name = plugin.name(); InitState state = states.get(name); if ( state == InitState.INITIALIZED ) { // Main // ===================================================================== Object pluginDependencyInjectionDef = plugin.dependencyInjectionDef(); if (pluginDependencyInjectionDef != null) { if (pluginDependencyInjectionDef instanceof com.google.inject.Module) { this.initContext.addChildModule(com.google.inject.Module.class.cast(pluginDependencyInjectionDef)); } else { addModuleViaProvider(name, pluginDependencyInjectionDef); } } // // Overrinding definition Object dependencyInjectionOverridingDef = plugin.dependencyInjectionOverridingDef(); if (dependencyInjectionOverridingDef != null) { if (dependencyInjectionOverridingDef instanceof com.google.inject.Module) { this.initContext.addChildOverridingModule(com.google.inject.Module.class.cast(dependencyInjectionOverridingDef)); } else { addModuleViaProvider(name, dependencyInjectionOverridingDef); } } } else { // the plugin is not initialized we add it for a new round logger.info("Plugin " + name + " is not initialized. We set it for a new round"); nextRoundOrderedPlugins.add(plugin); } } roundOrderedPlugins = nextRoundOrderedPlugins; // increment round number roundEnv.incrementRoundNumber(); } while( ! roundOrderedPlugins .isEmpty() && roundEnv.roundNumber() < MAXIMAL_ROUND_NUMBER ); } private void fillPackagesRoot(String pluginPackageRoot) { if (!Strings.isNullOrEmpty(pluginPackageRoot)) { String[] packages = null; packages = pluginPackageRoot.split(","); for (String pack : packages) { logger.info("Adding {} as package root", pack); this.initContext.addPackageRoot(pack.trim()); } } } private void addModuleViaProvider(String name, Object pluginDependencyInjectionDef) { DependencyInjectionProvider provider = findDependencyInjectionProvider(pluginDependencyInjectionDef); if (provider != null) { this.initContext.addChildModule(provider.convert(pluginDependencyInjectionDef)); } else { logger.error("Kernel did not recognize module {} of plugin {}", pluginDependencyInjectionDef, name); throw new KernelException( "Kernel did not recognize module %s of plugin %s. Please provide a DependencyInjectionProvider.", pluginDependencyInjectionDef.toString(), name); } } private DependencyInjectionProvider findDependencyInjectionProvider(Object pluginDependencyInjectionDef) { DependencyInjectionProvider provider = null; providerLoop: for (DependencyInjectionProvider providerIt : globalDependencyInjectionProviders) { if (providerIt.canHandle(pluginDependencyInjectionDef.getClass())) { provider = providerIt; break providerLoop; } } return provider; } private ArrayList<Plugin> sortPlugins(ArrayList<Plugin> unsortedPlugins) { Graph graph = new Graph(unsortedPlugins.size()); ArrayList<Plugin> sorted = new ArrayList<Plugin>(); Map<Integer, Plugin> idxPlug = new HashMap<Integer, Plugin>(); Map<Character, Plugin> charPlug = new HashMap<Character, Plugin>(); Map<Plugin, Integer> plugIdx = new HashMap<Plugin, Integer>(); Map<Class<? extends Plugin>, Integer> classPlugIdx = new HashMap<Class<? extends Plugin>, Integer>(); // Add vertices for (short i = 0; i < unsortedPlugins.size(); i++) { char c = (char) i; Plugin unsortedPlugin = unsortedPlugins.get(i); Integer pluginIndex = graph.addVertex(c); charPlug.put(c, unsortedPlugin); idxPlug.put(pluginIndex, unsortedPlugin); plugIdx.put(unsortedPlugin, pluginIndex); classPlugIdx.put(unsortedPlugin.getClass(), pluginIndex); } // add edges for (Entry<Integer, Plugin> entry : idxPlug.entrySet()) { Plugin source = entry.getValue(); // based on required plugins for (Class<? extends Plugin> dependencyClass : source.requiredPlugins()) { int start = classPlugIdx.get(dependencyClass); int end = plugIdx.get(source); graph.addEdge(start, end); } // based on dependent plugins for (Class<? extends Plugin> dependencyClass : source.dependentPlugins()) { int start = plugIdx.get(source); // we inversed int end = classPlugIdx.get(dependencyClass); graph.addEdge(start, end); } } // launch the algo char[] topologicalSort = graph.topologicalSort(); if (topologicalSort != null) { for (Character c : topologicalSort) { sorted.add(charPlug.get(c)); } } else { throw new KernelException("Error when sorting plugins : either a Cycle in dependencies or another cause."); } return sorted; } private Collection<Plugin> filterPlugins(Collection<Plugin> collection, Collection<Class<? extends Plugin>> pluginDependenciesRequired) { Set<Plugin> filteredSet = new HashSet<Plugin>(); for (Plugin plugin : collection) { if (pluginDependenciesRequired.contains(plugin.getClass())) { filteredSet.add(plugin); } } return filteredSet; } private InitContext proxyfy(final InitContext initContext, final Collection<Plugin> requiredPlugins , final Collection<Plugin> dependentPlugins) { return (InitContext) Proxy.newProxyInstance( // initContext.getClass().getClassLoader(), // new Class[] { InitContext.class }, // new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("pluginsRequired")) { return requiredPlugins; } else if (method.getName().equals("dependentPlugins")) { return dependentPlugins; } else { return method.invoke(initContext, args); } } }); } void createDependencyInjectionProvidersMap(Collection<Class<?>> dependencyInjectionProvidersClasses) { dependencyInjectionProviders = new HashSet<DependencyInjectionProvider>(); for (Class<?> dependencyInjectionProviderClass : dependencyInjectionProvidersClasses) { DependencyInjectionProvider injectionDependencyProvider = newInstance(dependencyInjectionProviderClass); if (injectionDependencyProvider != null) { dependencyInjectionProviders.add(injectionDependencyProvider); } else { throw new KernelException("DependencyInjectionProvider %s can not be instanciated", (Object) dependencyInjectionProviderClass); } } } /** * You have only one chance to get the current kernel. * * @param keyValues * @return */ public synchronized static KernelBuilderWithPluginAndContext createKernel(String... keyValues) { return new KernelBuilderImpl(keyValues); } public static interface KernelBuilder { Kernel build(); } public static interface KernelBuilderWithPluginAndContext extends KernelBuilderWithContainerContext, KernelBuilderWithPlugins { } public static interface KernelBuilderWithContainerContext extends KernelBuilder { KernelBuilderWithPlugins withContainerContext(Object containerContext); } public static interface KernelBuilderWithPlugins extends KernelBuilder { KernelBuilderWithPluginAndContext withPlugins(Class<? extends Plugin>... klass); KernelBuilderWithPluginAndContext withPlugins(Plugin... plugins); KernelBuilderWithPluginAndContext withoutSpiPluginsLoader(); } private static class KernelBuilderImpl implements KernelBuilderWithPluginAndContext { private final Kernel kernel; /** * */ public KernelBuilderImpl(String... keyValues) { kernel = new Kernel(keyValues); } @Override public Kernel build() { if (!kernels.contains(kernel.name)) { kernels.put(kernel.name, kernel); return kernel; } else { throw new KernelException(String.format("A kernel named %s already exists" , kernel.name )); } } @Override public KernelBuilderWithPlugins withContainerContext(Object containerContext) { kernel.addContainerContext(containerContext); return (KernelBuilderWithPlugins) this; } public KernelBuilderWithPluginAndContext withPlugins(java.lang.Class<? extends Plugin>... klass) { kernel.addPlugins(klass); return this; } public KernelBuilderWithPluginAndContext withPlugins(Plugin... plugin) { kernel.addPlugins(plugin); return this; } @Override public KernelBuilderWithPluginAndContext withoutSpiPluginsLoader() { kernel.spiPluginDisabled(); return this; } } @SuppressWarnings("unchecked") private <T> T newInstance(Class<?> klass) { T instance = null; try { instance = (T) klass.newInstance(); } catch (InstantiationException e) { logger.error("Error when instantiating class " + klass, e); } catch (IllegalAccessException e) { logger.error("Error when instantiating class " + klass, e); } return instance; } void addContainerContext(Object containerContext) { this.containerContext = containerContext; } void spiPluginEnabled() { this.spiPluginEnabled = true; } void spiPluginDisabled() { this.spiPluginEnabled = false; } /** * @param klass */ void addPlugins(Class<? extends Plugin>... klass) { for (Class<? extends Plugin> class1 : klass) { Plugin plugin = newInstance(class1); if (plugin == null) { throw new KernelException("Plugin %s can not be instanciated", (Object) klass); } else { addPlugin(plugin); } } } void addPlugins(Plugin... plugins) { for (Plugin plugin : plugins) { addPlugin(plugin); } } void addPlugin(Plugin plugin) { if (!this.started) { pluginsToAdd.put(plugin.name(), plugin); } else { throw new KernelException("Plugin %s can not be added. Kernel already is started", plugin.name()); } } static class AliasMap extends HashMap<String, String> { private static final long serialVersionUID = 1L; Map<String, String> aliases = new HashMap<String, String>(); /** * * * @param key the key to alias. * @param alias the alias to give to the key. * @return */ public String putAlias(String key, String alias) { if (super.containsKey(alias)) throw new IllegalArgumentException("alias "+alias+" already exists in map."); return aliases.put(alias, key); } @Override public String get(Object key) { String keyAlias = aliases.get(key); if (keyAlias == null) { return super.get(key); } else { return super.get(keyAlias); } } public boolean containsAllKeys(Collection<String> computedMandatoryParams) { HashSet<String> allKeys = new HashSet<String>(); allKeys.addAll( this.keySet() ); allKeys.addAll(aliases.values()); Collection<String> trans = new HashSet<String>(); for (String s : computedMandatoryParams) { String string = aliases.get(s); if (string != null) { trans.add(string); } } return allKeys.containsAll(trans); } @Override public boolean containsKey(Object key) { return aliases.containsKey(key) ? true : super.containsKey(key); } } }