Author: manik.surtani(a)jboss.com
Date: 2008-05-08 05:04:25 -0400 (Thu, 08 May 2008)
New Revision: 5804
Removed:
core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
Log:
Deleted: core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java 2008-05-08
08:50:28 UTC (rev 5803)
+++ core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java 2008-05-08
09:04:25 UTC (rev 5804)
@@ -1,1016 +0,0 @@
-package org.jboss.cache.factories;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.Cache;
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.LifecycleManager;
-import org.jboss.cache.config.Configuration;
-import org.jboss.cache.config.ConfigurationException;
-import org.jboss.cache.config.RuntimeConfig;
-import static org.jboss.cache.factories.ComponentRegistry.State.*;
-import org.jboss.cache.factories.annotations.CacheInjectionMethods;
-import org.jboss.cache.factories.annotations.ComponentName;
-import org.jboss.cache.factories.annotations.DefaultFactoryFor;
-import org.jboss.cache.factories.annotations.Destroy;
-import org.jboss.cache.factories.annotations.Inject;
-import org.jboss.cache.factories.annotations.Start;
-import org.jboss.cache.factories.annotations.Stop;
-import org.jboss.cache.interceptors.InterceptorChain;
-import org.jboss.cache.util.BeanUtils;
-import org.jboss.cache.util.reflect.CachedMethod;
-import org.jboss.cache.util.reflect.ReflectionUtil;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A registry where components which have been created are stored. Components are stored
as singletons, registered under
- * a specific name. When retrieving components from the registry, callers may specify a
component name or just the type
- * of component needed (in which case the fully qualified class name is used as the
component name).
- * <p/>
- * Components can be retrieved from the registry using {@link #getComponent(Class)}, or
they can be constructed using
- * {@link #getOrCreateComponent(String, Class)} which will scan for default factories and
attempt to use such
- * factpries to create the component if needed.
- * <p/>
- * Default factories are treated as components too and will need to be wired and started
before being used.
- * <p/>
- * Components can exist in one of 4 states, as defined by the {@link State} enumeration.
The component registry also
- * has a state for the overall component set. While some components may move to the
{@link org.jboss.cache.factories.ComponentRegistry.State#STARTED}
- * state before others (such as factories to create other components) the
ComponentRegistry's overall state depicts the lowest
- * possible form for all components.
- * <p/>
- * In terms of the cache, overall state changes in the following manner:
- * <ul>
- * <li>CONSTRUCTED - when created using the DefaultCacheFactory</li>
- * <li>WIRED - when {@link org.jboss.cache.Cache#create()} is called</li>
- * <li>STARTED - when {@link org.jboss.cache.Cache#start()} is called</li>
- * <li>STOPPED - when {@link org.jboss.cache.Cache#stop()} is called</li>
- * </ul>
- * <p/>
- * Cache configuration can only be changed and will only be reinjected if the cache is
not in the {@link org.jboss.cache.CacheStatus#STARTED} state.
- *
- * @author Manik Surtani (<a
href="mailto:manik@jboss.org">manik@jboss.org</a>)
- * @since 2.1.0
- */
-public class ComponentRegistry
-{
- // TODO: 2.2.0: Needs refactoring
- //TODO: 2.2.x+ @Start annotation bug: BaseClass.start() and ChildrenClass.start() are
annotated with @Start then only base class method is being called
- static final Object NULL_COMPONENT = new Object();
-
- State overallState = CONSTRUCTED;
-
- /**
- * The registry of components. Components are stored under their name.
- */
- final Map<String, Component> componentLookup = new HashMap<String,
Component>();
-
- /**
- * Contains class definitions of component factories that can be used to construct
certain components
- */
- Map<Class, Class<? extends ComponentFactory>> defaultFactories = null;
-
- private static final Log log = LogFactory.getLog(ComponentRegistry.class);
- private static final boolean trace = log.isTraceEnabled();
- private Bootstrap bootstrap;
-
- // cache of reflection methods to call during injections. These will be emptied when
start() is called.
- Map<Class, List<CachedMethod>> shortTermMethodCache = null;
- // these will hang around longer - for components that are frequently created during
normal operation.
- Map<Class, List<CachedMethod>> longTermMethodCache = null;
-
- /**
- * Creates an instance of the component registry. The configuration passed in is
automatically registered.
- *
- * @param configuration
- */
- public ComponentRegistry(Configuration configuration)
- {
- // bootstrap.
- registerDefaultClassLoader(null);
- registerComponent(this, ComponentRegistry.class);
- registerComponent(configuration, Configuration.class);
- }
-
- /**
- * Registers the default class loader. This method *must* be called before any other
components are registered,
- * typically called by bootstrap code. Defensively, it is called in the constructor
of ComponentRegistry with a null
- * parameter.
- *
- * @param loader a class loader to use by default. If this is null, the class loader
used to load this instance of ComponentRegistry is used.
- */
- public void registerDefaultClassLoader(ClassLoader loader)
- {
- registerComponent("deployerClassLoader", loader == null ?
getClass().getClassLoader() : loader, ClassLoader.class);
- }
-
-
- public State getOverallState()
- {
- return overallState;
- }
-
- /**
- * This is hard coded for now, since scanning the classpath for factories annotated
with {@link org.jboss.cache.factories.annotations.DefaultFactoryFor}
- * does not work with all class loaders. This is a temporary solution until a more
elegant one can be designed.
- * <p/>
- * BE SURE TO ADD ANY NEW FACTORY TYPES ANNOTATED WITH DefaultFactoryFor TO THIS
SET!!
- * <p/>
- *
- * @return set of known factory types.
- */
- private Set<Class<? extends ComponentFactory>> getHardcodedFactories()
- {
- Set<Class<? extends ComponentFactory>> s = new HashSet<Class<?
extends ComponentFactory>>();
- s.add(BuddyManagerFactory.class);
- s.add(EmptyConstructorFactory.class);
- s.add(InterceptorChainFactory.class);
- s.add(RuntimeConfigAwareFactory.class);
- s.add(TransactionManagerFactory.class);
- s.add(ReplicationQueueFactory.class);
- return s;
- }
-
-
- /**
- * Adds a singleton instance to the registry. Note that if an instance of this
component already exists in the
- * registry it is overwritten. The instance is registered under type
<tt>component.getClass()</tt>. If the component
- * implements an interface or extends an abstract class, it may make more sense to use
{@link #registerComponent(String, Object, Class)}
- * <p/>
- * The status of the component is updated th the overall state of the registry, which
may involve calling of methods annotated
- * with {@link org.jboss.cache.factories.annotations.Inject}, {@link
org.jboss.cache.factories.annotations.Start} or
- * {@link org.jboss.cache.factories.annotations.Stop}.
- * <p/>
- *
- * @param component component to add to the registry.
- */
- public void registerComponent(Object component, Class type)
- {
- registerComponent(type.getName(), component, type);
- }
-
- /**
- * Adds an instance component to the registry, registering the component under the
given name. If an instance already
- * exists in the registry under the given name, it will be overwritten.
- * <p/>
- * The status of the component is updated th the overall state of the registry, which
may involve calling of methods annotated
- * with {@link org.jboss.cache.factories.annotations.Inject}, {@link
org.jboss.cache.factories.annotations.Start} or
- * {@link org.jboss.cache.factories.annotations.Stop}.
- * <p/>
- *
- * @param name name of the instance
- * @param component component to add
- */
- public void registerComponent(String name, Object component, Class type)
- {
- // this will make sure all dependent components are stopped or set to CONSTRUCTED
so they can be re-wired later.
- Component c = new Component(name, component, type);
- Component old = componentLookup.get(name);
- if (trace)
- log.trace("Registering component " + c + " under name " +
name + " replacing old component " + old);
- if (old != null)
- {
- // if they are equal don't bother
- if (old.instance.equals(component))
- {
- if (trace)
- log.trace("Attempting to register a component equal to one that
already exists under the same name (" + name + "). Not doing anything.");
- return;
- }
- // unregister the old component so that components that depend on it can be
stopped if necessary
- unregisterComponent(name);
- // components that depended on the old component should now depend on the new
one.
- c.dependencyFor.addAll(old.dependencyFor);
- }
- componentLookup.put(name, c);
-
- addComponentDependencies(c, old == null);
-
- State stateToMoveTo = overallState == null ? CONSTRUCTED : overallState;
- c.changeState(stateToMoveTo);
-
- // make sure any other omponents that have inadvertently been stopped are now
restarted.
- if (old != null)
- {
- for (Component comp : old.dependencyFor)
- {
- if (comp.state != stateToMoveTo) comp.changeState(stateToMoveTo);
- }
- }
- }
-
- protected void addComponentDependencies(Component c, boolean firstTimeAdded)
- {
- // build any dependent components if necessary
- for (Component d : c.dependencies)
- {
- getOrCreateComponent(d.name, d.type);
- Component dependencyComponent = componentLookup.get(d.name);
- if (dependencyComponent != null) dependencyComponent.dependencyFor.add(c);
- }
-
- if (firstTimeAdded)
- {
- // loop through all other components already registered and make sure the
current component's dependencyFor map is accurate
- for (Component other : componentLookup.values())
- {
- if (other.dependencies.contains(c)) c.dependencyFor.add(other);
- }
- }
-
- }
-
- public <T> T getComponent(Class<T> c)
- {
- return getComponent(c.getName(), c);
- }
-
- /**
- * Retrieves a named component which can be assigned to the type passed in. Will
return a null if no such component
- * is registered
- *
- * @param c type to be able to assign component to.
- * @return component, if found, or a null otherwise.
- */
- @SuppressWarnings("unchecked")
- public <T> T getComponent(String name, Class<T> c)
- {
- Component wrapper = componentLookup.get(name);
- if (wrapper == null) return null;
-
- T component = (T) (wrapper.instance == NULL_COMPONENT ? null : wrapper.instance);
-
- if (component == null || c.isAssignableFrom(component.getClass())) return
component;
- else
- throw new ConfigurationException("Component registered under " + name
+ " is of type " + component.getClass() + " and cannot be assigned to
" + c);
- }
-
- /**
- * Retrieves a named component if one exists, and if not, attempts to find a factory
capable of constructing the component
- * (factories annotated with the {@link
org.jboss.cache.factories.annotations.DefaultFactoryFor} annotation that is capable
- * of creating the component class).
- * <p/>
- * If an instance needs to be constructed, dependencies are then automatically wired
into the instance, based on methods
- * on the component type annotated with {@link
org.jboss.cache.factories.annotations.Inject}.
- * <p/>
- * Summing it up, component retrieval happens in the following order:<br />
- * 1. Look for an appropriate component that exists in the {@link Configuration} that
may be injected from an external system.
- * 2. Look for a class definition passed in to the {@link
org.jboss.cache.config.Configuration} - such as an EvictionPolicy implementation
- * 3. Attempt to create it by looking for an appropriate factory (annotated with
{@link org.jboss.cache.factories.annotations.DefaultFactoryFor})
- * <p/>
- *
- * @param componentClass type of component to be retrieved. Should not be null.
- * @return a fully wired component instance, or null if one cannot be found or
constructed.
- * @throws ConfigurationException if there is a problem with consructing or wiring the
instance.
- */
- public <T> T getOrCreateComponent(Class<T> componentClass)
- {
- return getOrCreateComponent(null, componentClass);
- }
-
- /**
- * Retrieves a named component if one exists, and if not, attempts to find a factory
capable of constructing the component
- * (factories annotated with the {@link
org.jboss.cache.factories.annotations.DefaultFactoryFor} annotation that is capable
- * of creating the component class).
- * <p/>
- * If an instance needs to be constructed, dependencies are then automatically wired
into the instance, based on methods
- * on the component type annotated with {@link
org.jboss.cache.factories.annotations.Inject}.
- * <p/>
- * Summing it up, component retrieval happens in the following order:<br />
- * 1. Look for an appropriate component that exists in the {@link Configuration} that
may be injected from an external system.
- * 2. Look for a class definition passed in to the {@link
org.jboss.cache.config.Configuration} - such as an EvictionPolicy implementation
- * 3. Attempt to create it by looking for an appropriate factory (annotated with
{@link org.jboss.cache.factories.annotations.DefaultFactoryFor})
- * <p/>
- *
- * @param componentName name of component to be created. If null, uses the fully
qualified class name as component name.
- * @param componentClass type of component to be retrieved. Should not be null.
- * @return a fully wired component instance, or null if one cannot be found or
constructed.
- * @throws ConfigurationException if there is a problem with consructing or wiring the
instance.
- */
- public <T> T getOrCreateComponent(String componentName, Class<T>
componentClass)
- {
- T component = getComponent(componentName == null ? componentClass.getName() :
componentName, componentClass);
-
- if (component == null)
- {
- // first see if this has been injected externally.
- component = getFromConfiguration(componentClass);
- boolean attemptedFactoryConstruction = false;
-
- if (component == null && isNonBootstrapClass(componentClass))
- {
- // create this component and add it to the registry
- ComponentFactory factory = getFactory(componentClass);
- component = factory.construct(componentName, componentClass);
- attemptedFactoryConstruction = true;
-
- }
-
- String componentNameToUse = componentName == null ? componentClass.getName() :
componentName;
-
- if (component != null)
- {
- registerComponent(componentNameToUse, component, componentClass);
- }
- else if (attemptedFactoryConstruction)
- {
- if (trace) log.trace("Registering a null for component " +
componentNameToUse);
- registerNullComponent(componentNameToUse, componentClass);
- }
- }
-
- return component;
- }
-
- // registers a special "null" component that has no dependencies.
- void registerNullComponent(String componentName, Class type)
- {
- registerComponent(componentName, NULL_COMPONENT, type);
- }
-
- private boolean isNonBootstrapClass(Class<?> componentClass)
- {
- return !(componentClass.equals(CacheSPI.class) ||
componentClass.equals(LifecycleManager.class) ||
- componentClass.equals(Cache.class) ||
componentClass.equals(ComponentRegistry.class) ||
- componentClass.equals(Configuration.class));
- }
-
- @SuppressWarnings("unchecked")
- <T> T getFromConfiguration(Class<T> componentClass)
- {
- if (log.isDebugEnabled())
- log.debug("Looking in configuration for an instance of " +
componentClass + " that may have been injected from an external source.");
- Method getter = BeanUtils.getterMethod(Configuration.class, componentClass);
- T returnValue = null;
-
- if (getter != null)
- {
- try
- {
- returnValue = (T) getter.invoke(getConfiguration());
- }
- catch (Exception e)
- {
- log.warn("Unable to invoke getter " + getter + " on
Configuration.class!", e);
- }
- }
-
- // now try the RuntimeConfig - a legacy "registry" of sorts.
- if (returnValue == null)
- {
- getter = BeanUtils.getterMethod(RuntimeConfig.class, componentClass);
- if (getter != null)
- {
- try
- {
- returnValue = (T) getter.invoke(getConfiguration().getRuntimeConfig());
- }
- catch (Exception e)
- {
- log.warn("Unable to invoke getter " + getter + " on
RuntimeConfig.class!", e);
- }
- }
- }
- return returnValue;
- }
-
- Configuration getConfiguration()
- {
- // this is assumed to always be present as a part of the bootstrap/construction of
a ComponentRegistry.
- return getComponent(Configuration.class);
- }
-
- /**
- * Updates (re-injects) any dependencies needed by all components already in the
registry.
- */
- public void updateDependencies()
- {
- State originalState = overallState;
- moveComponentsToState(overallState == STARTED ? STOPPED : CONSTRUCTED);
- moveComponentsToState(originalState);
- // re- add a few key components - this is a hack for now
- LifecycleManager clm = getComponent(LifecycleManager.class);
- CacheSPI spi = getComponent(CacheSPI.class.getName(), CacheSPI.class);
- CommandsFactory commandsFactory = getComponent(CommandsFactory.class.getName(),
CommandsFactory.class);
-
- unregisterComponent(LifecycleManager.class);
- unregisterComponent(CacheSPI.class);
- unregisterComponent(CommandsFactory.class);
-
- overallState = CONSTRUCTED;
-
- registerComponent(LifecycleManager.class.getName(), clm, LifecycleManager.class);
- registerComponent(CacheSPI.class.getName(), spi, CacheSPI.class);
- registerComponent(CommandsFactory.class.getName(), commandsFactory,
CommandsFactory.class);
-
- overallState = originalState;
- moveComponentsToState(overallState);
- }
-
- /**
- * Removes a component from the registry. If the component has already been injected
into other components, you should
- * call {@link #updateDependencies()} to ensure dependencies are updated.
- *
- * @param clazz class of component to remove.
- */
- public void unregisterComponent(Class<?> clazz)
- {
- unregisterComponent(clazz.getName());
- }
-
- /**
- * Removes a component from the registry. If the component has already been injected
into other components, you should
- * call {@link #updateDependencies()} to ensure dependencies are updated.
- *
- * @param name name of the component to remove.
- */
- public void unregisterComponent(String name)
- {
- Component c = componentLookup.remove(name);
- if (c != null) c.changeState(c.state == STARTED ? STOPPED : CONSTRUCTED);
- }
-
- /**
- * Wires an object instance with dependencies annotated with the {@link
org.jboss.cache.factories.annotations.Inject} annotation, creating more components
- * as needed based on the Configuration passed in if these additional components
don't exist in the
- * {@link ComponentRegistry}. Strictly for components that don't otherwise live
in the registry and have a lifecycle, such as Nodes.
- *
- * @param target object to wire
- * @throws ConfigurationException if there is a problem wiring the instance
- */
- public void wireDependencies(Object target) throws ConfigurationException
- {
- //if (trace) log.trace("Inspecting class " + target.getClass());
- try
- {
- // look in caches first
- List<CachedMethod> methods = lookupInjectionMethods(target.getClass());
- //if (trace) log.trace("Found method set containing " + methods.size()
+ " methods that need injection: " + methods);
-
- // search for anything we need to inject
- for (CachedMethod method : methods)
- {
- //if (trace) log.trace("Method " + method + " needs some other
components injected!");
- performInjection(method, target);
- }
- }
- catch (Exception e)
- {
- throw new ConfigurationException("Unable to configure component (type:
" + target.getClass() + ", instance " + target + ")", e);
- }
- }
-
- private List<CachedMethod> lookupInjectionMethods(Class type)
- {
- if (longTermMethodCache != null && longTermMethodCache.containsKey(type))
return longTermMethodCache.get(type);
- if (shortTermMethodCache != null && shortTermMethodCache.containsKey(type))
return shortTermMethodCache.get(type);
-
- List<CachedMethod> methods = ReflectionUtil.getAllCachedMethods(type,
Inject.class);
- if (type.isAnnotationPresent(CacheInjectionMethods.class))
- {
- if (longTermMethodCache == null) longTermMethodCache = new HashMap<Class,
List<CachedMethod>>();
- longTermMethodCache.put(type, methods);
- }
- else
- {
- if (shortTermMethodCache == null) shortTermMethodCache = new HashMap<Class,
List<CachedMethod>>();
- shortTermMethodCache.put(type, methods);
- }
-
- return methods;
- }
-
- /**
- * Looks through the parameter list of the given method, attempts to locate parameters
that fit the types that may
- * exist in the {@link ComponentRegistry}, and then calls the method on the target
object with the necessary parameters.
- *
- * @param method Method to call
- * @param target Instance on which to call the method
- * @throws IllegalAccessException if the method cannot be called
- * @throws java.lang.reflect.InvocationTargetException
- * if the method cannot be called
- */
- @SuppressWarnings("unchecked")
- private <T> void performInjection(CachedMethod method, T target) throws
IllegalAccessException, InvocationTargetException
- {
- Class[] parameterTypes = method.getParameterTypes();
- List<Component> componentsToInject = getDeclaredDependencies(method);
-
- Object[] parameters = new Object[parameterTypes.length];
-
- for (int i = 0; i < parameterTypes.length; i++)
- {
- parameters[i] = getOrCreateComponent(componentsToInject.get(i).name,
parameterTypes[i]);
- }
-
- Method reflectMethod = method.getMethod();
- // make sure we set this method to be accessible, so we can call private, package
and protected
- // methods rather than just public ones.
- reflectMethod.setAccessible(true);
-
- // invoke the method with the parameters we've worked out.
- reflectMethod.invoke(target, parameters);
- }
-
- private String extractComponentName(Annotation[] annotationsOnParameter)
- {
- for (Annotation a : annotationsOnParameter)
- {
- if (a instanceof ComponentName)
- {
- ComponentName cn = (ComponentName) a;
- return cn.value();
- }
- }
- return null;
- }
-
- private List<Component> getDeclaredDependencies(CachedMethod method)
- {
- List<Component> dependencies = new LinkedList<Component>();
- Class[] parameterTypes = method.getParameterTypes();
- Annotation[][] annotationsOnParams = method.getParameterAnnotations();
- for (int i = 0; i < parameterTypes.length; i++)
- {
- String componentName = extractComponentName(annotationsOnParams[i]);
- String componentNameToUse = componentName == null ? parameterTypes[i].getName()
: componentName;
- // if the component exists in the lookup, use it. Otherwise use a placeholder
which will be constructed later, on demand.
- Component d = componentLookup.containsKey(componentNameToUse) ?
componentLookup.get(componentNameToUse) : new Component(componentNameToUse,
parameterTypes[i]);
- dependencies.add(d);
- }
- return dependencies;
- }
-
- /**
- * Retrieves a component factory instance capable of constructing components of a
specified type. If the factory doesn't
- * exist in the registry, one is created. Always changes the state of any factory to
{@link State#STARTED} before returning.
- *
- * @param componentClass type of component to construct
- * @return component factory capable of constructing such components
- */
- protected ComponentFactory getFactory(Class componentClass)
- {
- if (defaultFactories == null) scanDefaultFactories();
- Class<? extends ComponentFactory> cfClass =
defaultFactories.get(componentClass);
- if (cfClass == null)
- throw new ConfigurationException("No registered default factory for
component " + componentClass + " found!");
- // a component factory is a component too! See if one has been created and exists
in the registry
- ComponentFactory cf = getComponent(cfClass);
- if (cf == null)
- {
- // hasn't yet been created. Create and put in registry
- cf = instantiateFactory(cfClass);
- if (cf != null)
- {
- // we simply register this factory. Registration will take care of
constructing any dependencies.
- registerComponent(cf, cfClass);
- }
- }
-
- if (cf == null)
- throw new ConfigurationException("Unable to locate component factory for
component " + componentClass);
-
- // ensure the component factory is in the STARTED state!
- Component c = componentLookup.get(cfClass.getName());
- if (c.instance != cf)
- throw new ConfigurationException("Component factory " + cfClass +
" incorrectly registered!");
- c.changeState(STARTED);
- return cf;
- }
-
- /**
- * Scans the class path for classes annotated with {@link
org.jboss.cache.factories.annotations.DefaultFactoryFor}, and
- * analyses which components can be created by such factories.
- */
- void scanDefaultFactories()
- {
- defaultFactories = new HashMap<Class, Class<? extends
ComponentFactory>>();
-
- Set<Class<? extends ComponentFactory>> factories =
getHardcodedFactories();
-
- for (Class<? extends ComponentFactory> factory : factories)
- {
- DefaultFactoryFor dFFAnnotation =
factory.getAnnotation(DefaultFactoryFor.class);
- for (Class targetClass : dFFAnnotation.classes())
defaultFactories.put(targetClass, factory);
- }
- }
-
- /**
- * No such thing as a meta factory yet. Factories are created using this method which
attempts to use an empty public
- * constructor.
- *
- * @param factory class of factory to be created
- * @return factory instance
- */
- ComponentFactory instantiateFactory(Class<? extends ComponentFactory> factory)
- {
- try
- {
- return factory.newInstance();
- }
- catch (Exception e)
- {
- // unable to get a hold of an instance!!
- throw new ConfigurationException("Unable to instantiate factory " +
factory, e);
- }
- }
-
- /**
- * Wipes everything in the registry. Use with care.
- */
- public void reset()
- {
- // the bootstrap classes
- Component deployerClassLoader =
componentLookup.get("deployerClassLoader");
- Component spi = componentLookup.get(CacheSPI.class.getName());
- Component interceptorChain =
componentLookup.get(InterceptorChain.class.getName());
- Component lifeCycleManager =
componentLookup.get(LifecycleManager.class.getName());
- Component dataContainer = componentLookup.get(DataContainer.class.getName());
- Component conf = componentLookup.get(Configuration.class.getName());
- Component cr = componentLookup.get(ComponentRegistry.class.getName());
-
- // destroy all components to clean up resources
- for (Component c : componentLookup.values()) c.changeState(DESTROYED);
-
- // remove from componentLookup
- componentLookup.clear();
-
- // bootstrap components
- deployerClassLoader.changeState(CONSTRUCTED);
- spi.changeState(CONSTRUCTED);
- interceptorChain.changeState(CONSTRUCTED);
- lifeCycleManager.changeState(CONSTRUCTED);
- dataContainer.changeState(CONSTRUCTED);
- conf.changeState(CONSTRUCTED);
- cr.changeState(CONSTRUCTED);
-
- bootstrap = new Bootstrap((ClassLoader) deployerClassLoader.instance,
(InterceptorChain) interceptorChain.instance,
- (LifecycleManager) lifeCycleManager.instance, (DataContainer)
dataContainer.instance, (CacheSPI) spi.instance,
- (ComponentRegistry) cr.instance, (Configuration) conf.instance);
-
- overallState = null;
- }
-
- /**
- * Starts all components that contain the {@link Start} annotation.
- */
- public void start()
- {
- moveComponentsToState(STARTED);
- shortTermMethodCache = null;
- }
-
- /**
- * Stops all components that contain the {@link Stop} annotation.
- */
- public void stop()
- {
- moveComponentsToState(STOPPED);
- }
-
- /**
- * Injects dependencies to all components that require injection.
- */
- public void wire()
- {
- moveComponentsToState(WIRED);
- }
-
- void moveComponentsToState(State state)
- {
- if (overallState == null && bootstrap != null &&
!bootstrap.isBootstrapped())
- {
- // we have been destroyed! Need to bootstrap again.
- bootstrap.bootstrap();
- }
-
- // copy the component lookup CHM to prevent concurrent modification exceptions
later on, if components need to be
- // constructed and added to the system on the fly.
- Set<Component> components = new
HashSet<Component>(componentLookup.values());
- for (Component c : components) c.changeState(state);
-
- overallState = state;
- }
-
- /**
- * Represents the state of a component
- */
- public enum State
- {
- DESTROYED, STOPPED, CONSTRUCTED, WIRED, STARTED;
-
- /**
- * Tests whether the current state is "greater" than the state passed in
- *
- * @param other state to compare with
- * @return true if the current state is "greater" than the state passed
in
- */
- boolean isGreaterThan(State other)
- {
- return this.ordinal() > other.ordinal();
- }
-
- /**
- * Tests whether the current state is "less" than the state passed in
- *
- * @param other state to compare with
- * @return true if the current state is "less" than the state passed in
- */
- boolean isLessThan(State other)
- {
- return this.ordinal() < other.ordinal();
- }
-
- /**
- * @param other state to compare with
- * @return the absolute difference in ordinal places between 2 states
- */
- int absoluteDifference(State other)
- {
- return Math.abs(this.ordinal() - other.ordinal());
- }
- }
-
- /**
- * Represents a component in the registry, along with state and dependencies.
- */
- class Component
- {
- Object instance;
- final String name;
- final Class type;
- State state = CONSTRUCTED;
- final Set<Component> dependencies = new HashSet<Component>(3);
- final Set<Component> dependencyFor = new HashSet<Component>(3);
- boolean deepRecursionDetector = false;
-
- public Component(String name, Class type)
- {
- this.name = name;
- this.type = type;
- }
-
- /**
- * Constructs a Component out of an instance and a name. Scans instance for
dependencies and populates
- * the "dependencies" and "dependencyFor" collections.
- *
- * @param name name of component
- * @param instance component instance
- */
- public Component(String name, Object instance, Class type)
- {
- this(name, type);
- this.instance = instance;
-
- // now scan the instance for all dependencies.
- List<CachedMethod> injectionMethods =
lookupInjectionMethods(instance.getClass());
-
- // now for each injection method, get dependencies
- for (CachedMethod m : injectionMethods)
dependencies.addAll(getDeclaredDependencies(m));
- }
-
- /**
- * Changes the state of a component - along with all dependent components - to a
new state. This method is recursion
- * and cyclic dependency safe.
- *
- * @param newState new state to move component to
- */
- void changeState(State newState)
- {
- // Deep recursion is when this component depends on another component which in
turn may depend on this component again.
- // if this is encountered then break out of the recursive loop.
- if (state != newState && !deepRecursionDetector)
- {
- // Step by step. If the new state is > 1 step away from the current
state, change state gradually.
- boolean increase = newState.isGreaterThan(state);
- int numSteps = newState.absoluteDifference(state);
-
- while (numSteps > 1)
- {
- changeState(State.values()[state.ordinal() + (increase ? 1 : -1)]);
- numSteps = newState.absoluteDifference(state);
- }
-
- // now we update the state of dependent components accordingly.
- Set<Component> dependentComponents = new HashSet<Component>();
- Set<Component> shallowCyclic = new HashSet<Component>();
-
- if (increase)
- {
- // if I am moving to a "higher" state make sure all components
that I depend on have moved to that state as well.
- dependentComponents.addAll(dependencies);
- }
- else
- {
- // if I am moving to a "lower" state make sure all components
depend on me have moved to that state as well.
- dependentComponents.addAll(dependencyFor);
- }
-
- // switch on the deep recursion detector
- deepRecursionDetector = true;
- for (Component d : dependentComponents)
- {
- if (d != null)
- {
- // always look up again in the component lookup. The dependencies and
dependenciesFor sets are just
- // used as references. The actual component instances may be out of
date.
- d = componentLookup.get(d.name);
-
- if (d != null)
- {
- if (isShallowCyclic(d))
- {
- // don't invoke shallow cyclic deps here - shoud do that
after we set our state.
- shallowCyclic.add(d);
- }
- else
- {
- // of we are "moving up" - only do this if the
component is lower than what is needed.
- if ((increase && newState.isGreaterThan(d.state)) ||
(!increase && newState.isLessThan(d.state)))
- {
- d.changeState(newState);
- }
- }
- }
- }
- }
-
- // NOW we update our state.
- switch (newState)
- {
- case STOPPED:
- stop();
- break;
- case WIRED:
- if (increase) wire();
- break;
- case STARTED:
- start();
- break;
- case DESTROYED:
- destroy();
- break;
- case CONSTRUCTED:
- // do nothing
- }
-
- state = newState;
-
- // now process the shallow cyclic deps
- for (Component c : shallowCyclic)
- {
- // of we are "moving up" - only do this if the component is
lower than what is needed.
- if ((increase && newState.isGreaterThan(c.state)) || (!increase
&& newState.isLessThan(c.state)))
- c.changeState(newState);
- }
-
- // make sure we switch off the deep recursion detector now.
- deepRecursionDetector = false;
- }
- }
-
- /**
- * Tests whether there is an immediate cyclic dependency (i.e., both components
depend on each other) between the current component and another one.
- *
- * @param c other component to test with
- * @return true if there is an immediate cyclic dependency between the 2
components
- */
- private boolean isShallowCyclic(Component c)
- {
- return dependencies.contains(c) && c.dependencies.contains(this);
- }
-
- /**
- * Used to wire dependencies into this component instance.
- */
- void wire()
- {
- try
- {
- List<CachedMethod> methods =
lookupInjectionMethods(instance.getClass());
-
- // search for anything we need to inject
- for (CachedMethod method : methods) performInjection(method, instance);
- }
- catch (Exception e)
- {
- throw new ConfigurationException("Unable to configure component (type:
" + instance.getClass() + ", instance " + instance + ")", e);
- }
- }
-
- /**
- * Used to call all methods annotated with {@link Start} on component instance
- */
- void start()
- {
- invokeMethods(Start.class);
- }
-
- /**
- * Used to call all methods annotated with {@link Stop} on component instance
- */
- void stop()
- {
- invokeMethods(Stop.class);
- }
-
- /**
- * Used to call all methods annotated with {@link
org.jboss.cache.factories.annotations.Destroy} on component instance
- */
- void destroy()
- {
- invokeMethods(Destroy.class);
- }
-
- private void invokeMethods(Class<? extends Annotation> annotation)
- {
- List<Method> methods = ReflectionUtil.getAllMethods(instance.getClass(),
annotation);
- for (Method m : methods)
- {
- try
- {
- m.setAccessible(true);
- m.invoke(instance);
- }
- catch (Exception e)
- {
- log.warn("Unable to invoke annotated method " + m, e);
- }
- }
- }
-
- @Override
- public String toString()
- {
- return "Component (name = " + name + ", state = " + state +
")";
- }
-
- @Override
- public int hashCode()
- {
- return 31 * name.hashCode();
- }
-
- @Override
- public boolean equals(Object other)
- {
- return other instanceof Component && name.equals(((Component)
other).name);
- }
-
- }
-
- class Bootstrap
- {
- final InterceptorChain interceptorChain;
- final LifecycleManager lifecycleManager;
- final DataContainer dataContainer;
- final CacheSPI cacheSPI;
- final ComponentRegistry componentRegistry;
- final Configuration configuration;
- private final ClassLoader deployerClassLoader;
-
- Bootstrap(ClassLoader deployerClassLoader, InterceptorChain interceptorChain,
LifecycleManager lifecycleManager,
- DataContainer dataContainer, CacheSPI cacheSPI, ComponentRegistry
componentRegistry, Configuration configuration)
- {
- this.deployerClassLoader = deployerClassLoader;
- this.lifecycleManager = lifecycleManager;
- this.dataContainer = dataContainer;
- this.interceptorChain = interceptorChain;
- this.cacheSPI = cacheSPI;
- this.componentRegistry = componentRegistry;
- this.configuration = configuration;
- }
-
- boolean isBootstrapped()
- {
- return componentLookup.containsKey(Configuration.class.getName()) &&
- componentLookup.containsKey(LifecycleManager.class.getName()) &&
- componentLookup.containsKey(InterceptorChain.class.getName()) &&
- componentLookup.containsKey(DataContainer.class.getName()) &&
- componentLookup.containsKey(CacheSPI.class.getName()) &&
- componentLookup.containsKey(ComponentRegistry.class.getName()) &&
- componentLookup.containsKey("deployerClassLoader");
- }
-
- void bootstrap()
- {
- overallState = CONSTRUCTED;
- registerComponent("deployerClassLoader", deployerClassLoader,
ClassLoader.class);
- registerComponent(Configuration.class.getName(), configuration,
Configuration.class);
- registerComponent(ComponentRegistry.class.getName(), componentRegistry,
ComponentRegistry.class);
- registerComponent(InterceptorChain.class.getName(), interceptorChain,
InterceptorChain.class);
- registerComponent(LifecycleManager.class.getName(), lifecycleManager,
LifecycleManager.class);
- registerComponent(DataContainer.class.getName(), dataContainer,
DataContainer.class);
- registerComponent(CacheSPI.class.getName(), cacheSPI, CacheSPI.class);
- }
- }
-}
\ No newline at end of file