[jbosscache-commits] JBoss Cache SVN: r4872 - in core/trunk/src: main/java/org/jboss/cache/config and 12 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Tue Dec 18 14:58:11 EST 2007


Author: manik.surtani at jboss.com
Date: 2007-12-18 14:58:10 -0500 (Tue, 18 Dec 2007)
New Revision: 4872

Added:
   core/trunk/src/main/java/org/jboss/cache/util/reflect/
   core/trunk/src/main/java/org/jboss/cache/util/reflect/ClasspathScanner.java
   core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java
   core/trunk/src/test/java/org/jboss/cache/factories/ComponentRegistryFunctionalTest.java
   core/trunk/src/test/java/org/jboss/cache/factories/ComponentRegistryUnitTest.java
   core/trunk/src/test/java/org/jboss/cache/factories/DependencyGraphTest.java
   core/trunk/src/test/java/org/jboss/cache/util/reflect/
   core/trunk/src/test/java/org/jboss/cache/util/reflect/ClasspathScannerTest.java
Removed:
   core/trunk/src/test/java/org/jboss/cache/factories/annotations/
Modified:
   core/trunk/src/main/java/org/jboss/cache/CacheImpl.java
   core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java
   core/trunk/src/main/java/org/jboss/cache/config/ConfigurationComponent.java
   core/trunk/src/main/java/org/jboss/cache/factories/CacheMarshallerFactory.java
   core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
   core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
   core/trunk/src/test/java/org/jboss/cache/interceptors/EvictionInterceptorTest.java
   core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java
   core/trunk/src/test/java/org/jboss/cache/loader/UnnecessaryLoadingTest.java
   core/trunk/src/test/java/org/jboss/cache/misc/TestingUtil.java
   core/trunk/src/test/java/org/jboss/cache/passivation/PassivationToDummyInMemoryCacheLoaderTest.java
Log:
Updated injection framework and component registry internals and bootstrap

Modified: core/trunk/src/main/java/org/jboss/cache/CacheImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheImpl.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/main/java/org/jboss/cache/CacheImpl.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -502,6 +502,8 @@
       // Include our clusterName in our log category
       configureLogCategory();
 
+      componentRegistry.wire();
+
       // initialise the node factory and set this in the runtime.
 //      NodeFactory nf;
 //      if ((nf = configuration.getRuntimeConfig().getNodeFactory()) == null)
@@ -617,9 +619,11 @@
       // remove the Interceptor.class component though, since it may pertain to an old config
       componentRegistry.unregisterComponent(Interceptor.class);
 
+      // re-do the bootstrap sequence
       componentRegistry.registerComponent(configuration);
       componentRegistry.registerComponent(this);
-      componentRegistry.registerComponent(CacheSPI.class, spi);
+      componentRegistry.registerComponent(CacheSPI.class.getName(), spi);
+      componentRegistry.registerComponent(Cache.class.getName(), spi);
       componentRegistry.registerComponent(componentRegistry);
 
       componentRegistry.updateDependencies();
@@ -628,7 +632,7 @@
       cacheStatus = CacheStatus.STARTING;
 
       // start all internal components
-      componentRegistry.startComponents();
+      componentRegistry.start();
 
       correctRootNodeType();
 
@@ -873,7 +877,7 @@
    {
       cacheStatus = CacheStatus.STOPPING;
 
-      componentRegistry.stopComponents();
+      componentRegistry.stop();
 
       // before closing the channel stop the buddy manager
 //      if (buddyManager != null && buddyManager.isEnabled())
@@ -3773,7 +3777,7 @@
 
    private void setInterceptorChain(Interceptor startOfNewChain)
    {
-      componentRegistry.registerComponent(Interceptor.class, startOfNewChain);
+      componentRegistry.registerComponent(Interceptor.class.getName(), startOfNewChain);
       componentRegistry.updateDependencies();
    }
 
@@ -3781,21 +3785,22 @@
    {
       List<Interceptor> interceptors = getInterceptors();
 
-      InterceptorChainFactory factory = InterceptorChainFactory.getInstance();
+      InterceptorChainFactory factory = componentRegistry.getComponent(InterceptorChainFactory.class);
 
       interceptors.add(position, i);
 
       // now correct the chaining of interceptors...
-      Interceptor linkedChain = factory.correctInterceptorChaining(interceptors, configuration, componentRegistry);
+      Interceptor linkedChain = factory.correctInterceptorChaining(interceptors);
 
       setInterceptorChain(linkedChain);
    }
 
    public synchronized void removeInterceptor(int position)
    {
+      InterceptorChainFactory factory = componentRegistry.getComponent(InterceptorChainFactory.class);
       List<Interceptor> i = getInterceptors();
       i.remove(position);
-      setInterceptorChain(InterceptorChainFactory.getInstance().correctInterceptorChaining(i, configuration, componentRegistry));
+      setInterceptorChain(factory.correctInterceptorChaining(i));
    }
 
    public RPCManager getRPCManager()

Modified: core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -11,7 +11,6 @@
 import org.jboss.cache.factories.ComponentFactory;
 import org.jboss.cache.factories.ComponentRegistry;
 import org.jboss.cache.factories.XmlConfigurationParser;
-import org.jboss.cache.factories.annotations.DefaultFactoryFor;
 import org.jboss.cache.invocation.CacheInvocationDelegate;
 
 import java.io.InputStream;
@@ -23,34 +22,27 @@
  * This is a special instance of a {@link ComponentFactory} which contains bootstrap information for the
  * {@link ComponentRegistry}.
  * <p/>
- * E.g., {@link #bootstrap()} is used to create a cache, a {@link ComponentRegistry}, and then wire dependencies as needed.
+ * E.g., {@link #bootstrap(CacheImpl, CacheSPI, org.jboss.cache.config.Configuration)} is used to create a cache, a {@link ComponentRegistry}, and then wire dependencies as needed.
  *
  * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
  * @see org.jboss.cache.factories.ComponentFactory
  */
- at DefaultFactoryFor(classes = {CacheSPI.class})
+//@DefaultFactoryFor(classes = {CacheSPI.class})
 public class DefaultCacheFactory<K, V> extends ComponentFactory implements CacheFactory<K, V>
 {
    private volatile static CacheFactory<?, ?> singleton = new DefaultCacheFactory();
 
-   protected DefaultCacheFactory()
-   {
-   }
-
    /**
-    * @return a singleton instance of this class.
+    * Note - this method used to return a singleton instance, and since 2.1.0 returns a new instance.  The method is
+    * deprecated and you should use the no-arg constructor to create a new instance of this factory.
+    *
+    * @return a NEW instance of this class.
     */
    @SuppressWarnings("unchecked")
+   @Deprecated
    public static <K, V> CacheFactory<K, V> getInstance()
    {
-      if (singleton == null)
-      {
-         synchronized (DefaultCacheFactory.class)
-         {
-            if (singleton == null) singleton = new DefaultCacheFactory();
-         }
-      }
-      return (CacheFactory<K, V>) singleton;
+      return new DefaultCacheFactory();
    }
 
    public Cache<K, V> createCache() throws ConfigurationException
@@ -124,11 +116,7 @@
 
       bootstrap(cache, spi, configuration);
 
-      // wire dependencies into cache
-      componentRegistry.wireDependencies(cache);
-      // wire dependencies into SPI delegate
-      componentRegistry.wireDependencies(spi);
-
+      componentRegistry.wire();
       return spi;
    }
 
@@ -143,17 +131,18 @@
       // injection bootstrap stuff
       componentRegistry = cache.getComponentRegistry();
 
-      // make sure we set the CacheImpl and CacheSPI instance in the component registry.
-      componentRegistry.registerComponent(cache);
-      componentRegistry.registerComponent(spi);
-
       // and the configuration
       componentRegistry.registerComponent(configuration);
       this.configuration = configuration;
-      componentRegistry.wireDependencies(configuration);
+
       // and the component registry itself.  This bit of recursiveness is needed for factories that are also components.
       // See NodeFactory for example, which is created by an EmptyConstructorFactory
       componentRegistry.registerComponent(componentRegistry);
+
+      // make sure we set the CacheImpl and CacheSPI instance in the component registry.
+      componentRegistry.registerComponent(cache);
+      componentRegistry.registerComponent(CacheSPI.class.getName(), spi);
+      componentRegistry.registerComponent(Cache.class.getName(), spi);
    }
 
    public Cache<K, V> createCache(InputStream is) throws ConfigurationException

Modified: core/trunk/src/main/java/org/jboss/cache/config/ConfigurationComponent.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/ConfigurationComponent.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/main/java/org/jboss/cache/config/ConfigurationComponent.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -10,7 +10,9 @@
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.CacheSPI;
 import org.jboss.cache.CacheStatus;
+import org.jboss.cache.factories.ComponentRegistry;
 import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
 
 import java.io.Serializable;
 import java.util.Collection;
@@ -34,6 +36,7 @@
    private transient CacheSPI cache; // back-reference to test whether the cache is running.
    private final Set<ConfigurationComponent> children =
          Collections.synchronizedSet(new HashSet<ConfigurationComponent>());
+   private ComponentRegistry cr;
 
    protected ConfigurationComponent()
    {
@@ -117,7 +120,6 @@
     *
     * @param cache
     */
-   @Inject
    public void setCache(CacheSPI cache)
    {
       this.cache = cache;
@@ -130,6 +132,18 @@
       }
    }
 
+   @Inject
+   private void injectDependencies(ComponentRegistry cr)
+   {
+      this.cr = cr;
+   }
+
+   @Start
+   private void start()
+   {
+      setCache(cr.getComponent(CacheSPI.class));
+   }
+
    public ConfigurationComponent clone() throws CloneNotSupportedException
    {
       ConfigurationComponent c = (ConfigurationComponent) super.clone();

Modified: core/trunk/src/main/java/org/jboss/cache/factories/CacheMarshallerFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/CacheMarshallerFactory.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/main/java/org/jboss/cache/factories/CacheMarshallerFactory.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -42,7 +42,7 @@
          throw new ConfigurationException("Unable to instantiate marshaller of type " + marshallerClass, e);
       }
 
-      componentRegistry.wireDependencies(m);
+      //componentRegistry.wireDependencies(m);
 
       if (log.isDebugEnabled()) log.debug("Instantiated " + marshallerClass + "; wrapping in a VersionAwareMarshaller");
 

Modified: core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -2,23 +2,25 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.Cache;
+import org.jboss.cache.CacheImpl;
+import org.jboss.cache.CacheSPI;
 import org.jboss.cache.config.Configuration;
 import org.jboss.cache.config.ConfigurationException;
 import org.jboss.cache.config.RuntimeConfig;
-import org.jboss.cache.factories.annotations.ClasspathScanner;
+import static org.jboss.cache.factories.ComponentRegistry.State.*;
 import org.jboss.cache.factories.annotations.ComponentName;
 import org.jboss.cache.factories.annotations.DefaultFactoryFor;
 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.util.BeanUtils;
+import org.jboss.cache.util.reflect.ClasspathScanner;
+import org.jboss.cache.util.reflect.ReflectionUtil;
 
 import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -34,17 +36,36 @@
  * 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 at jboss.org">manik at jboss.org</a>)
  * @since 2.1.0
  */
 public class ComponentRegistry
 {
+   State overallState = CONSTRUCTED;
+
    /**
-    * Can contain either unnamed singletons (in which case the key is the class of the instance) or named singletons, keyed by a
-    * String representing the name of the instance.
+    * The registry of components.  Components are stored under their name.
     */
-   Map<Object, Object> registry = new HashMap<Object, Object>();
+   Map<String, Component> componentLookup = new HashMap<String, Component>();
+
    /**
     * Contains class definitions of component factories that can be used to construct certain components
     */
@@ -52,6 +73,11 @@
 
    private static Log log = LogFactory.getLog(ComponentRegistry.class);
 
+   /**
+    * Creates an instance of the component registry.  The configuration passed in is automatically registered.
+    *
+    * @param configuration
+    */
    public ComponentRegistry(Configuration configuration)
    {
       // bootstrap.
@@ -61,72 +87,50 @@
    /**
     * 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(Class, Object)}
+    * implements an interface or extends an abstract class, it may make more sense to use {@link #registerComponent(String, Object)}
+    * <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)
    {
-      registerComponent(component.getClass(), component);
+      registerComponent(component.getClass().getName(), component);
    }
 
    /**
-    * Adds a singleton instance to the registry.  Note that if an instance of this component already exists in the
-    * registry it is overwritten.
-    *
-    * @param componentType the type to register the component under.
-    * @param component     component to add to the registry.
-    */
-   public void registerComponent(Class componentType, Object component)
-   {
-      registry.put(componentType, component);
-   }
-
-   /**
     * 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)
    {
-      registry.put(name, component);
+      // this will make sure all dependent components are stopped or set to CONSTRUCTED so they can be re-wired later.
+      unregisterComponent(name);
+
+      Component c = new Component(name, component);
+      componentLookup.put(name, c);
+      // build any dependent components if necessary
+      for (Dependency d : c.dependencies)
+      {
+         getOrCreateComponent(d.name, d.type);
+      }
+      c.changeState(overallState);
    }
 
-   /**
-    * Retrieves a singleton 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(Class<T> c)
    {
-      if (c == null)
-      {
-         log.error("Scanning for component null!!  This is a bug!!", new Throwable());
-         return null;
-      }
-
-      //if (log.isTraceEnabled()) log.trace("Scanning registry for an instance that can be assigned to class " + c);
-      T component = (T) registry.get(c);
-
-      if (component == null)
-      {
-         // search for subclasses.
-         for (Object object : registry.keySet())
-         {
-            if (object instanceof Class)
-            {
-               if (c.isAssignableFrom((Class) object)) component = (T) registry.get(object);
-            }
-
-         }
-      }
-
-      return component;
+      return getComponent(c.getName(), c);
    }
 
    /**
@@ -139,8 +143,11 @@
    @SuppressWarnings("unchecked")
    public <T> T getComponent(String name, Class<T> c)
    {
-      T component = (T) registry.get(name);
-      if (component == null) return null;
+      Component wrapper = componentLookup.get(name);
+      if (wrapper == null) return null;
+
+      T component = (T) wrapper.instance;
+
       if (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);
@@ -160,6 +167,29 @@
     * 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.
@@ -167,14 +197,14 @@
     */
    public <T> T getOrCreateComponent(String componentName, Class<T> componentClass)
    {
-      T component = (componentName == null) ? getComponent(componentClass) : getComponent(componentName, componentClass);
+      T component = getComponent(componentName == null ? componentClass.getName() : componentName, componentClass);
 
       if (component == null)
       {
          // first see if this has been injected externally.
          component = getFromConfiguration(componentClass);
 
-         if (component == null)
+         if (component == null && isNonBootstrap(componentClass))
          {
             // create this component and add it to the registry
             ComponentFactory factory = getFactory(componentClass);
@@ -184,9 +214,9 @@
          if (component != null)
          {
             // wire dependencies
-            wireDependencies(component);
+//            wireDependencies(component);
             if (componentName == null)
-               registerComponent(componentClass, component);
+               registerComponent(componentClass.getName(), component);
             else
                registerComponent(componentName, component);
          }
@@ -194,8 +224,14 @@
       return component;
    }
 
+   private boolean isNonBootstrap(Class<?> componentClass)
+   {
+      return !(componentClass.equals(CacheSPI.class) || componentClass.equals(CacheImpl.class) || componentClass.equals(Cache.class)
+            || componentClass.equals(ComponentRegistry.class));
+   }
+
    @SuppressWarnings("unchecked")
-   private <T> T getFromConfiguration(Class<T> componentClass)
+         <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);
@@ -243,12 +279,9 @@
     */
    public void updateDependencies()
    {
-      // make sure we work off a copy of the values set since wireDependencies may add components to the registry
-      // and this may otherwise end up in a CME.
-
-      Set<Object> components = new HashSet<Object>(registry.values());
-
-      for (Object component : components) wireDependencies(component);
+      State originalState = overallState;
+      moveComponentsToState(overallState == STARTED ? CONSTRUCTED : STOPPED);
+      moveComponentsToState(originalState);
    }
 
    /**
@@ -259,7 +292,7 @@
     */
    public void unregisterComponent(Class<?> clazz)
    {
-      registry.remove(clazz);
+      unregisterComponent(clazz.getName());
    }
 
    /**
@@ -270,13 +303,14 @@
     */
    public void unregisterComponent(String name)
    {
-      registry.remove(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}.
+    * {@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
@@ -286,7 +320,7 @@
       //if (log.isTraceEnabled()) log.trace("Inspecting class " + target.getClass());
       try
       {
-         List<Method> methods = getAllMethods(target.getClass(), Inject.class);
+         List<Method> methods = ReflectionUtil.getAllMethods(target.getClass(), Inject.class);
          //if (log.isTraceEnabled()) log.trace("Found method set containing " + methods.size() + " methods that need injection: " + methods);
 
          // search for anything we need to inject
@@ -316,14 +350,13 @@
    private <T> void performInjection(Method method, T target) throws IllegalAccessException, InvocationTargetException
    {
       Class[] parameterTypes = method.getParameterTypes();
-      Annotation[][] annotationsOnParams = method.getParameterAnnotations();
+      List<Dependency> componentsToInject = getDeclaredDependencies(method);
 
       Object[] parameters = new Object[parameterTypes.length];
 
       for (int i = 0; i < parameterTypes.length; i++)
       {
-         String componentName = extractComponentName(annotationsOnParams[i]);
-         parameters[i] = getOrCreateComponent(componentName, parameterTypes[i]);
+         parameters[i] = getComponent(componentsToInject.get(i).name, parameterTypes[i]);
       }
 
       // make sure we set this method to be accessible, so we can call private, package and protected
@@ -347,53 +380,23 @@
       return null;
    }
 
-   /**
-    * Returns a set of Methods that require components injected.  This includes all public, protected, package and private
-    * methods, as well as those of superclasses.  Note that this does *not* include overridden methods.
-    * <p/>
-    * Includes all methods annotated with &amp;Inject as well as methods that are <i>not</i> annotated, but instead
-    * have parameters annotated accordingly.
-    *
-    * @param c              class to inspect
-    * @param annotationType the type of annotation to look for
-    * @return Set of Method objects that require injection.
-    */
-   private List<Method> getAllMethods(Class c, Class<? extends Annotation> annotationType)
+   private List<Dependency> getDeclaredDependencies(Method method)
    {
-      List<Method> annotated = new LinkedList<Method>();
-      inspectRecursively(c, annotated, annotationType);
-      return annotated;
-   }
-
-   private void inspectRecursively(Class c, List<Method> s, Class<? extends Annotation> annotationType)
-   {
-      // Superclass first
-      if (!c.equals(Object.class)) inspectRecursively(c.getSuperclass(), s, annotationType);
-
-      for (Method m : c.getDeclaredMethods())
+      List<Dependency> dependencies = new LinkedList<Dependency>();
+      Class[] parameterTypes = method.getParameterTypes();
+      Annotation[][] annotationsOnParams = method.getParameterAnnotations();
+      for (int i = 0; i < parameterTypes.length; i++)
       {
-         // don't bother if this method has already been overridden by a subclass
-         if (!alreadyFound(m, s) && m.isAnnotationPresent(annotationType))
-         {
-            s.add(m);
-         }
+         String componentName = extractComponentName(annotationsOnParams[i]);
+         Dependency d = new Dependency(componentName == null ? parameterTypes[i].getName() : componentName, parameterTypes[i]);
+         dependencies.add(d);
       }
+      return dependencies;
    }
 
-   private boolean alreadyFound(Method m, Collection<Method> s)
-   {
-      for (Method found : s)
-      {
-         if (m.getName().equals(found.getName()) &&
-               Arrays.equals(m.getParameterTypes(), found.getParameterTypes()))
-            return true;
-      }
-      return false;
-   }
-
-
    /**
-    * Retrieves a component factory instance capable of constructing components of a specified type.
+    * 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
@@ -412,15 +415,19 @@
          cf = instantiateFactory(cfClass);
          if (cf != null)
          {
-            // wire factory deps
-            wireDependencies(cf);
-            // register this factory
+            // we simply register this factory.  Registration will take care of constructing any dependencies.
             registerComponent(cf);
          }
       }
 
       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;
    }
 
@@ -445,111 +452,339 @@
 
    /**
     * No such thing as a meta factory yet.  Factories are created using this method which attempts to use an empty public
-    * constructor, or a "getInstance" method.
+    * constructor.
     *
     * @param factory class of factory to be created
     * @return factory instance
     */
    ComponentFactory instantiateFactory(Class<? extends ComponentFactory> factory)
    {
-      Constructor ctor = null;
-      Method singletonAccessor = null;
       try
       {
-         ctor = factory.getConstructor();
+         return factory.newInstance();
       }
-      catch (NoSuchMethodException e)
+      catch (Exception e)
       {
-         log.trace("No default, public constructor on " + factory);
-         // perhaps this factory is a singleton.
-         try
-         {
-            singletonAccessor = factory.getMethod("getInstance");
-         }
-         catch (NoSuchMethodException e1)
-         {
-            log.trace("No getInstance() method on " + factory);
-         }
+         // unable to get a hold of an instance!!
+         throw new ConfigurationException("Unable to instantiate factory " + factory, e);
       }
+   }
 
-      if (ctor == null && singletonAccessor == null)
+   /**
+    * Wipes everything in the registry.  Use with care.
+    */
+   public void reset()
+   {
+      componentLookup.clear();
+      overallState = CONSTRUCTED;
+   }
+
+   /**
+    * Starts all components that contain the {@link Start} annotation.
+    */
+   public void start()
+   {
+      moveComponentsToState(STARTED);
+   }
+
+   /**
+    * 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)
+   {
+      for (Component c : componentLookup.values())
       {
-         // unable to get a hold of an instance!!
-         throw new ConfigurationException("Unable to instantiate factory " + factory + ": no public, default constructor or getInstance() static method!");
+         c.changeState(state);
       }
+      overallState = state;
+   }
 
-      ComponentFactory instance;
-      try
+   /**
+    * Represents the state of a component
+    */
+   enum State
+   {
+      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)
       {
-         if (ctor == null)
-         {
-            instance = (ComponentFactory) singletonAccessor.invoke(null);
-         }
-         else
-         {
-            instance = (ComponentFactory) ctor.newInstance();
-         }
+         return this.ordinal() > other.ordinal();
       }
-      catch (Exception e)
+
+      /**
+       * 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)
       {
-         throw new ConfigurationException("Unable to instantiate factory " + factory, e);
+         return this.ordinal() < other.ordinal();
       }
 
-      return instance;
+      /**
+       * @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());
+      }
    }
 
    /**
-    * Wipes everything in the registry.  Use with care.
+    * Represents a potentially unconstructed dependency.  A simple wrapper around a name and type pair.
     */
-   public void reset()
+   class Dependency
    {
-      registry.clear();
+      String name;
+      Class<?> type;
+
+      public Dependency(String name, Class type)
+      {
+         this.name = name;
+         this.type = type;
+      }
+
+      public int hashCode()
+      {
+         return 31 * name.hashCode();
+      }
+
+      public boolean equals(Object other)
+      {
+         return other instanceof Dependency && name.equals(((Dependency) other).name);
+      }
+
+      public String toString()
+      {
+         return "Dependency (name = " + name + ")";
+      }
    }
 
    /**
-    * Starts all components that contain the {@link Start} annotation.
+    * Represents a component in the registry, along with state and dependencies.
     */
-   public void startComponents()
+   class Component
    {
-      for (Object component : registry.values())
+      Object instance;
+      String name;
+      State state = CONSTRUCTED;
+      Set<Dependency> dependencies = new HashSet<Dependency>(3);
+      Set<Dependency> dependencyFor = new HashSet<Dependency>(3);
+      Dependency me;
+      boolean deepRecursionDetector = false;
+
+      /**
+       * 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)
       {
-         List<Method> methods = getAllMethods(component.getClass(), Start.class);
-         for (Method m : methods)
+         this.instance = instance;
+         this.name = name;
+
+         // now scan the instance for all dependencies.
+         List<Method> injectionMethods = ReflectionUtil.getAllMethods(instance.getClass(), Inject.class);
+
+         // now for each injection method, get dependencies
+         for (Method m : injectionMethods) dependencies.addAll(getDeclaredDependencies(m));
+
+         // backward-chaining - make sure I know about components that depend on me.
+         me = asDependency();
+         for (Dependency d : dependencies)
          {
-            try
+            Component c = componentLookup.get(d.name);
+            if (c != null) c.dependencyFor.add(me);
+         }
+      }
+
+      /**
+       * @return a {@link org.jboss.cache.factories.ComponentRegistry.Dependency} object that represents the current component
+       */
+      Dependency asDependency()
+      {
+         if (me == null) me = new Dependency(name, null);
+         return me;
+      }
+
+      /**
+       * 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)
             {
-               m.setAccessible(true);
-               m.invoke(component);
+               changeState(State.values()[state.ordinal() + (increase ? 1 : -1)]);
+               numSteps = newState.absoluteDifference(state);
             }
-            catch (Exception e)
+
+            // now we update the state of dependent components accordingly.
+            Set<Dependency> dependentComponents = new HashSet<Dependency>();
+            Set<Component> shallowCyclic = new HashSet<Component>();
+
+            if (increase)
             {
-               log.warn("Unable to invoke @Start annotated method " + m, e);
+               // 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 (Dependency d : dependentComponents)
+            {
+               Component c = componentLookup.get(d.name);
+               if (c != null)
+               {
+                  if (isShallowCyclic(c))
+                  {
+                     // don't process shallow cyclic deps here - shoud do that after we set our state.
+                     shallowCyclic.add(c);
+                  }
+                  else
+                  {
+                     // 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);
+
+                  }
+               }
+            }
+
+            // NOW we update our state.
+            switch (newState)
+            {
+               case STOPPED:
+                  stop();
+                  break;
+               case WIRED:
+                  wire();
+                  break;
+               case STARTED:
+                  start();
+                  break;
+               case CONSTRUCTED:
+                  // nothing to do here.
+            }
+
+            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;
          }
       }
-   }
 
-   /**
-    * Stops all components that contain the {@link Stop} annotation.
-    */
-   public void stopComponents()
-   {
-      for (Object component : registry.values())
+      /**
+       * 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)
       {
-         List<Method> methods = getAllMethods(component.getClass(), Stop.class);
+         return (dependencies.contains(c.asDependency()) && c.dependencies.contains(asDependency()));
+      }
+
+      /**
+       * Used to wire dependencies into this component instance.
+       */
+      void wire()
+      {
+         try
+         {
+            List<Method> methods = ReflectionUtil.getAllMethods(instance.getClass(), Inject.class);
+
+            // search for anything we need to inject
+            for (Method 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);
+      }
+
+      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(component);
+               m.invoke(instance);
             }
             catch (Exception e)
             {
-               log.warn("Unable to invoke @Stop annotated method " + m, e);
+               log.warn("Unable to invoke annotated method " + m, e);
             }
          }
       }
+
+      public String toString()
+      {
+         return "Component (name = " + name + ", state = " + state + ")";
+      }
    }
-
-}
+}
\ No newline at end of file

Modified: core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -58,7 +58,7 @@
       if (i == null)
       {
          i = clazz.newInstance();
-         componentRegistry.wireDependencies(i);
+//         componentRegistry.wireDependencies(i);
          // add this interceptor as a NAMED component into the registry
          componentRegistry.registerComponent(clazz.getName(), i);
       }
@@ -584,41 +584,37 @@
    }
 
    /**
-    * The same as {@link #correctInterceptorChaining(java.util.List, org.jboss.cache.config.Configuration, ComponentRegistry)}
+    * The same as {@link #correctInterceptorChaining(java.util.List)}
     * except that it takes in the first interceptor in the chain instead of a list of interceptors, and traverses the chain to
     * generate a list.  Identical to calling
     * <pre>
     *    InterceptorChainFactory.correctInterceptorChaining( InterceptorChainFactory.asList(first), configuration, componentRegistry );
     * </pre>
     *
-    * @param first             first interceptor in the chain to correct.
-    * @param configuration     cache configuration
-    * @param componentRegistry component registry
+    * @param first first interceptor in the chain to correct.
     * @return the first interceptor in the chain.
     */
-   public Interceptor correctInterceptorChaining(Interceptor first, Configuration configuration, ComponentRegistry componentRegistry)
+   public Interceptor correctInterceptorChaining(Interceptor first)
    {
-      return correctInterceptorChaining(asList(first), configuration, componentRegistry);
+      return correctInterceptorChaining(asList(first));
    }
 
    /**
     * "Fixes" the next() and last() pointers for each interceptor, based on the order presented in the list passed in, and
     * also re-assesses dependencies for each interceptor, injecting dependencies accordingingly.
     *
-    * @param interceptors      interceptor chain to correct
-    * @param configuration     cache configuration
-    * @param componentRegistry component registry
+    * @param interceptors interceptor chain to correct
     * @return the first interceptor in the chain.
     */
-   public Interceptor correctInterceptorChaining(List<Interceptor> interceptors, Configuration configuration, ComponentRegistry componentRegistry)
+   public Interceptor correctInterceptorChaining(List<Interceptor> interceptors)
    {
+      // re-wire
+      componentRegistry.updateDependencies();
+
       Interceptor first = null, last = null;
 
       for (Interceptor next : interceptors)
       {
-         // re-wire
-         componentRegistry.wireDependencies(next);
-
          if (first == null)
          {
             first = last = next;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -316,6 +316,7 @@
 
       if (node != null && node.isChildrenLoaded())
       {
+         log.trace("Children already loaded!");
          return;
       }
       Set children_names = loader.getChildrenNames(fqn);

Modified: core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -414,7 +414,6 @@
 
    public Node getNode(Fqn<?> fqn)
    {
-      GlobalTransaction tx = cache.getCurrentTransaction();
       MethodCall m = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal, fqn);
       return (Node) invoke(m);
    }

Copied: core/trunk/src/main/java/org/jboss/cache/util/reflect/ClasspathScanner.java (from rev 4871, core/trunk/src/main/java/org/jboss/cache/factories/annotations/ClasspathScanner.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/reflect/ClasspathScanner.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/reflect/ClasspathScanner.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -0,0 +1,171 @@
+package org.jboss.cache.util.reflect;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * Class for scanning archives and classpaths in the current JBoss Cache classpath for classes annotated with a given annotation.  Inspired by a similar class in
+ * JBoss SEAM.
+ *
+ * @author Manik Surtani
+ */
+public class ClasspathScanner
+{
+   private Log log = LogFactory.getLog(ClasspathScanner.class);
+   private URLClassLoader classLoader;
+
+   /**
+    * Constructor with the type of annotation to scan for.
+    */
+   public ClasspathScanner()
+   {
+      classLoader = (URLClassLoader) ClasspathScanner.class.getClassLoader();
+   }
+
+   /**
+    * Scans the class path element that contains JBoss Cache for all classes that contain the annotation type this class is
+    * initialised with.  Note that this only scans CLASSES for the annotation; not methods, etc.
+    *
+    * @param annotationType the type of annotation to scan for.
+    * @param classType      the type of class to scan for.  Subclasses will be scanned, others will not.
+    * @return a set of Classes that contain the specified annotation on the class.
+    */
+   public <T> Set<Class<? extends T>> scan(Class<? extends Annotation> annotationType, Class<T> classType)
+   {
+      Set<Class<? extends T>> classes = Collections.emptySet();
+
+      try
+      {
+         // only scan the current ClassPath location that contains this file.  Could be a directory or a JAR file.
+         URL url = getURLPathFromClassLoader();
+         String urlPath = url.getFile();
+         if (urlPath.endsWith("/"))
+         {
+            urlPath = urlPath.substring(0, urlPath.length() - 1);
+         }
+
+         if (log.isDebugEnabled()) log.debug("scanning: " + urlPath);
+         File file = new File(urlPath);
+         if (file.isDirectory())
+         {
+            classes = handleDirectory(file, null, classType, annotationType);
+         }
+         else
+         {
+            classes = handleArchive(file, classType, annotationType);
+         }
+      }
+      catch (IOException ioe)
+      {
+         log.warn("could not read entries", ioe);
+      }
+      catch (ClassNotFoundException e)
+      {
+         log.warn("Unable to load class", e);
+      }
+
+      return classes;
+   }
+
+   private URL getURLPathFromClassLoader() throws MalformedURLException
+   {
+      URL u2 = classLoader.findResource("org/jboss/cache/Version.class");
+
+      for (URL u : classLoader.getURLs())
+      {
+         String urlString = u.toString().replaceAll("\\/\\.\\/", "/");
+         if (u2.toString().startsWith(urlString))
+         {
+            return new URL(urlString);
+         }
+      }
+
+      return null;
+   }
+
+
+   private <T> Set<Class<? extends T>> handleArchive(File file, Class<T> classType, Class<? extends Annotation> annotationType) throws IOException, ClassNotFoundException
+   {
+      Set<Class<? extends T>> classesWithAnnotations = new HashSet<Class<? extends T>>();
+      ZipFile zip = new ZipFile(file);
+      Enumeration<? extends ZipEntry> entries = zip.entries();
+      while (entries.hasMoreElements())
+      {
+         ZipEntry entry = entries.nextElement();
+         String name = entry.getName();
+         Class<? extends T> c = handleItem(name, classType, annotationType);
+         if (c != null) classesWithAnnotations.add(c);
+      }
+
+      return classesWithAnnotations;
+   }
+
+   private <T> Set<Class<? extends T>> handleDirectory(File file, String path, Class<T> classType, Class<? extends Annotation> annotationType) throws IOException, ClassNotFoundException
+   {
+      Set<Class<? extends T>> classesWithAnnotations = new HashSet<Class<? extends T>>();
+      for (File child : file.listFiles())
+      {
+         String newPath = path == null ? child.getName() : path + '/' + child.getName();
+         if (child.isDirectory())
+         {
+            classesWithAnnotations.addAll(handleDirectory(child, newPath, classType, annotationType));
+         }
+         else
+         {
+            Class<? extends T> c = handleItem(newPath, classType, annotationType);
+            if (c != null)
+            {
+               classesWithAnnotations.add(c);
+            }
+         }
+      }
+
+      return classesWithAnnotations;
+   }
+
+   private <T> Class<? extends T> handleItem(String name, Class<T> classType, Class<? extends Annotation> annotationType) throws IOException, ClassNotFoundException
+   {
+      if (!name.endsWith(".class")) return null;
+
+      Class<? extends T> c = getClassFile(filenameToClassname(name), classType);
+      if (c != null && hasAnnotation(c, annotationType))
+      {
+         return c;
+      }
+      else
+      {
+         return null;
+      }
+   }
+
+   private <T> Class<? extends T> getClassFile(String name, Class<T> classType) throws IOException, ClassNotFoundException
+   {
+      Class c = classLoader.loadClass(name);
+      if (c != null && classType.isAssignableFrom(c)) return c;
+      else return null;
+   }
+
+   private boolean hasAnnotation(Class clazz, Class<? extends Annotation> annotationType)
+   {
+      return (clazz.isAnnotationPresent(annotationType));
+   }
+
+   private static String filenameToClassname(String filename)
+   {
+      return filename.substring(0, filename.lastIndexOf(".class")).replace('/', '.').replace('\\', '.');
+   }
+
+}

Added: core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -0,0 +1,73 @@
+package org.jboss.cache.util.reflect;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Basic reflection utilities to enhance what the JDK provides.
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 2.1.0
+ */
+public class ReflectionUtil
+{
+   /**
+    * Returns a set of Methods that contain the given method annotation.  This includes all public, protected, package and private
+    * methods, as well as those of superclasses.  Note that this does *not* include overridden methods.
+    *
+    * @param c              class to inspect
+    * @param annotationType the type of annotation to look for
+    * @return List of Method objects that require injection.
+    */
+   public static List<Method> getAllMethods(Class c, Class<? extends Annotation> annotationType)
+   {
+      List<Method> annotated = new LinkedList<Method>();
+      inspectRecursively(c, annotated, annotationType);
+      return annotated;
+   }
+
+   /**
+    * Inspects a class and it's superclasses (all the way to {@link Object} for method instances that contain a given annotation.
+    * This even identifies private, package and protected methods, not just public ones.
+    *
+    * @param c
+    * @param s
+    * @param annotationType
+    */
+   private static void inspectRecursively(Class c, List<Method> s, Class<? extends Annotation> annotationType)
+   {
+      // Superclass first
+      if (!c.equals(Object.class)) inspectRecursively(c.getSuperclass(), s, annotationType);
+
+      for (Method m : c.getDeclaredMethods())
+      {
+         // don't bother if this method has already been overridden by a subclass
+         if (!alreadyFound(m, s) && m.isAnnotationPresent(annotationType))
+         {
+            s.add(m);
+         }
+      }
+   }
+
+   /**
+    * Tests whether a method has already been found, i.e., overridden.
+    *
+    * @param m method to inspect
+    * @param s collection of methods found
+    * @return true a method with the same signature already exists.
+    */
+   private static boolean alreadyFound(Method m, Collection<Method> s)
+   {
+      for (Method found : s)
+      {
+         if (m.getName().equals(found.getName()) &&
+               Arrays.equals(m.getParameterTypes(), found.getParameterTypes()))
+            return true;
+      }
+      return false;
+   }
+}

Copied: core/trunk/src/test/java/org/jboss/cache/factories/ComponentRegistryFunctionalTest.java (from rev 4851, core/trunk/src/test/java/org/jboss/cache/factories/ComponentRegistryTest.java)
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/factories/ComponentRegistryFunctionalTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/factories/ComponentRegistryFunctionalTest.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -0,0 +1,227 @@
+package org.jboss.cache.factories;
+
+import org.jboss.cache.CacheImpl;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.RPCManager;
+import org.jboss.cache.RegionManager;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.buddyreplication.NextMemberBuddyLocator;
+import org.jboss.cache.config.BuddyReplicationConfig;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.invocation.CacheInvocationDelegate;
+import org.jboss.cache.marshall.CacheMarshaller200;
+import org.jboss.cache.marshall.CacheMarshaller210;
+import org.jboss.cache.marshall.Marshaller;
+import org.jboss.cache.marshall.VersionAwareMarshaller;
+import org.jboss.cache.misc.TestingUtil;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.statetransfer.StateTransferManager;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 2.1.0
+ */
+ at Test(groups = {"functional"})
+public class ComponentRegistryFunctionalTest
+{
+   private ComponentFactory cf;
+   private ComponentRegistry cr;
+   private Configuration configuration;
+
+   @BeforeMethod
+   public void setUp() throws Exception
+   {
+      cf = (ComponentFactory) DefaultCacheFactory.getInstance();
+
+      CacheSPI spi = new CacheInvocationDelegate();
+      Constructor ctor = CacheImpl.class.getDeclaredConstructor();
+      ctor.setAccessible(true);
+      CacheImpl ci = (CacheImpl) ctor.newInstance();
+
+      configuration = ci.getConfiguration();
+      cr = TestingUtil.extractComponentRegistry(ci);
+
+      cf.componentRegistry = cr;
+      cf.configuration = configuration;
+
+      cr.registerComponent(cr); // register self
+      cr.registerComponent(ci);
+      cr.registerComponent(spi);
+      cr.registerComponent(configuration);
+
+      cr.wire();
+   }
+
+   public void testDefaultFactoryScanning()
+   {
+      cr.scanDefaultFactories();
+
+      assert cr.defaultFactories != null : "Should be populated";
+
+      // at very least, expecting a Marshaller factory and a DefaultCacheFactory.
+      assert cr.defaultFactories.containsKey(Marshaller.class);
+      assert cr.defaultFactories.get(Marshaller.class).equals(CacheMarshallerFactory.class);
+      assert cr.defaultFactories.containsKey(Notifier.class);
+      assert cr.defaultFactories.get(Notifier.class).equals(EmptyConstructorFactory.class);
+
+   }
+
+   public void testNamedComponents()
+   {
+      cr.registerComponent("blah", new Object());
+      Object namedComponent1 = cr.getOrCreateComponent("blah", Object.class);
+      Object namedComponent2 = cr.getOrCreateComponent("blah", Object.class);
+
+      assert namedComponent1 == namedComponent2;
+   }
+
+   /**
+    * Case 1:
+    * nothing injected, nothing specified in Configuration.  Should use default factory.
+    */
+   public void testConstructionOrder1()
+   {
+      Class<Marshaller> componentToTest = Marshaller.class;
+      Marshaller m = cr.getOrCreateComponent(null, componentToTest);
+      assert m instanceof VersionAwareMarshaller;
+      VersionAwareMarshaller vam = (VersionAwareMarshaller) m;
+      m = (Marshaller) TestingUtil.extractField(vam, "defaultMarshaller");
+      assert m instanceof CacheMarshaller210;
+   }
+
+   /**
+    * Case 2:
+    * instance injected, class specified in Configuration.  Should use injected.
+    */
+   public void testConstructionOrder2()
+   {
+      Class<Marshaller> componentToTest = Marshaller.class;
+      configuration.setMarshallerClass(CacheMarshaller200.class.getName());
+      Marshaller instance = new CacheMarshaller210(null, false, false);
+      configuration.setCacheMarshaller(instance);
+
+      // the setup() would have wired the default marshaller.  Need to update deps.
+      cr.unregisterComponent(Marshaller.class);
+      cr.updateDependencies();
+
+      Marshaller m = cr.getOrCreateComponent(null, componentToTest);
+      assert m == instance : "m is " + m + " but expected " + instance;
+   }
+
+   /**
+    * Case 3:
+    * instance injected, no class specified in Configuration.  Should use injected.
+    */
+   public void testConstructionOrder3()
+   {
+      Class<Marshaller> componentToTest = Marshaller.class;
+      Marshaller instance = new CacheMarshaller210(null, false, false);
+      configuration.setCacheMarshaller(instance);
+
+      // the setup() would have wired the default marshaller.  Need to update deps.
+      cr.unregisterComponent(Marshaller.class);
+      cr.updateDependencies();
+
+      Marshaller m = cr.getOrCreateComponent(null, componentToTest);
+      assert m == instance : "m is " + m + " but expected " + instance;
+   }
+
+   /**
+    * Case 4:
+    * nothing injected, class specified in Configuration.  Should use class specified.
+    */
+   public void testConstructionOrder4()
+   {
+      Class<Marshaller> componentToTest = Marshaller.class;
+      configuration.setMarshallerClass(CacheMarshaller200.class.getName());
+      Marshaller m = cr.getOrCreateComponent(null, componentToTest);
+      assert m instanceof VersionAwareMarshaller;
+      VersionAwareMarshaller vam = (VersionAwareMarshaller) m;
+      m = (Marshaller) TestingUtil.extractField(vam, "defaultMarshaller");
+      assert m instanceof CacheMarshaller200;
+   }
+
+   public void testTransitiveDependencies()
+   {
+      Class<BuddyManager> componentToTest = BuddyManager.class;
+
+      // configure the cfg to use BR
+      BuddyReplicationConfig brc = new BuddyReplicationConfig();
+      brc.setEnabled(true);
+      BuddyReplicationConfig.BuddyLocatorConfig blc = new BuddyReplicationConfig.BuddyLocatorConfig();
+      blc.setBuddyLocatorClass(NextMemberBuddyLocator.class.getName());
+      brc.setBuddyLocatorConfig(blc);
+      configuration.setBuddyReplicationConfig(brc);
+
+      BuddyManager bm = cr.getOrCreateComponent(null, componentToTest);
+      assert bm != null;
+
+      StateTransferManager stm = (StateTransferManager) TestingUtil.extractField(bm, "stateTransferManager");
+      assert stm != null;
+
+      RPCManager rpcm = (RPCManager) TestingUtil.extractField(bm, "rpcManager");
+      assert rpcm != null;
+
+      RegionManager rm = (RegionManager) TestingUtil.extractField(bm, "regionManager");
+      assert rm != null;
+
+      Configuration cfg = (Configuration) TestingUtil.extractField(bm, "configuration");
+      assert cfg == configuration;
+   }
+
+   public void testInjectionOrder()
+   {
+      // injection should only occur after dependent components have been fully wired.
+
+      // E.g. Test1 depends on Test2 and Test2 depends on Test3.
+      //cr.reset();
+
+      // DefaultFactoryFor annotation won't work since tests are compiled into a separate classpath
+      cr.defaultFactories.put(Test1.class, EmptyConstructorFactory.class);
+      cr.defaultFactories.put(Test2.class, EmptyConstructorFactory.class);
+      cr.defaultFactories.put(Test3.class, EmptyConstructorFactory.class);
+
+      Test1 t1 = cr.getOrCreateComponent(null, Test1.class);
+
+      assert t1 != null;
+      assert t1.test2 != null;
+      assert t1.test2.test3 != null;
+      assert t1.someValue == t1.test2.test3.someValue;
+   }
+
+   public static class Test1
+   {
+      private Test2 test2;
+      private boolean someValue = false;
+
+      @Inject
+      public void setTest2(Test2 test2)
+      {
+         this.test2 = test2;
+         someValue = test2.test3.someValue;
+      }
+   }
+
+   public static class Test2
+   {
+      private Test3 test3;
+
+      @Inject
+      public void setTest3(Test3 test3)
+      {
+         this.test3 = test3;
+      }
+   }
+
+   public static class Test3
+   {
+      private boolean someValue = true;
+   }
+}
+

Added: core/trunk/src/test/java/org/jboss/cache/factories/ComponentRegistryUnitTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/factories/ComponentRegistryUnitTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/factories/ComponentRegistryUnitTest.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -0,0 +1,107 @@
+package org.jboss.cache.factories;
+
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.factories.annotations.ComponentName;
+import org.jboss.cache.factories.annotations.Inject;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 2.1.0
+ */
+ at Test(groups = "functional")
+public class ComponentRegistryUnitTest
+{
+   ComponentRegistry cr;
+   Configuration cfg;
+
+   @BeforeMethod
+   public void setUp()
+   {
+      cr = new ComponentRegistry(new Configuration());
+      cfg = cr.getConfiguration();
+   }
+
+   public void testChangingComponentState()
+   {
+      cr.registerComponent("c2", new C2());
+      cr.registerComponent("c1", new C1());
+      cr.registerComponent("c3", new C3());
+
+      ComponentRegistry.Component c1 = cr.componentLookup.get("c1");
+      ComponentRegistry.Component c2 = cr.componentLookup.get("c2");
+      ComponentRegistry.Component c3 = cr.componentLookup.get("c3");
+
+      // add some dependencies
+      ComponentRegistry.Dependency d1 = cr.new Dependency("c1", null);
+      ComponentRegistry.Dependency d2 = cr.new Dependency("c2", null);
+      ComponentRegistry.Dependency d3 = cr.new Dependency("c3", null);
+
+      // c1 depends on c2
+      // c3 depends on c1
+
+      // test dependency and dependencyFor
+
+      assert c2.dependencies.isEmpty();
+      assert c1.dependencies.contains(d2);
+      assert c1.dependencies.size() == 1;
+      assert c3.dependencies.contains(d1);
+      assert c3.dependencies.size() == 1;
+
+      assert c2.dependencyFor.contains(d1);
+      assert c2.dependencyFor.size() == 1;
+      assert c1.dependencyFor.contains(d3);
+      assert c1.dependencyFor.size() == 1;
+      assert c3.dependencyFor.isEmpty();
+
+      assert c1.state == ComponentRegistry.State.CONSTRUCTED;
+      assert c2.state == ComponentRegistry.State.CONSTRUCTED;
+      assert c3.state == ComponentRegistry.State.CONSTRUCTED;
+
+      c1.changeState(ComponentRegistry.State.WIRED);
+
+      assert c1.state == ComponentRegistry.State.WIRED;
+      assert c2.state == ComponentRegistry.State.WIRED;
+      assert c3.state == ComponentRegistry.State.CONSTRUCTED;
+
+      c3.changeState(ComponentRegistry.State.STARTED);
+
+      assert c1.state == ComponentRegistry.State.STARTED;
+      assert c2.state == ComponentRegistry.State.STARTED;
+      assert c3.state == ComponentRegistry.State.STARTED;
+
+      c1.changeState(ComponentRegistry.State.CONSTRUCTED);
+
+      assert c1.state == ComponentRegistry.State.CONSTRUCTED;
+      assert c2.state == ComponentRegistry.State.STARTED;
+      assert c3.state == ComponentRegistry.State.CONSTRUCTED;
+   }
+
+   public static class C1
+   {
+      C2 c2;
+
+      @Inject
+      private void inject(@ComponentName("c2")C2 c2)
+      {
+         this.c2 = c2;
+      }
+   }
+
+   public static class C2
+   {
+
+   }
+
+   public static class C3
+   {
+      C1 c1;
+
+      @Inject
+      private void inject(@ComponentName("c1")C1 c1)
+      {
+         this.c1 = c1;
+      }
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/factories/DependencyGraphTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/factories/DependencyGraphTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/factories/DependencyGraphTest.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -0,0 +1,78 @@
+package org.jboss.cache.factories;
+
+import org.jboss.cache.factories.annotations.Inject;
+import org.testng.annotations.Test;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 2.1.0
+ */
+ at Test(groups = "functional")
+public class DependencyGraphTest
+{
+   public void testDependencies()
+   {
+      Map<Object, Object> components = new HashMap<Object, Object>();
+      components.put(Test1.class, new Test1());
+      components.put(Test2.class, new Test2());
+      components.put(Test3.class, new Test3());
+      components.put(Test4.class, new Test4());
+
+      // expected order - Test4, Test3, Test2, Test1
+      DependencyGraph dg = new DependencyGraph(components);
+      List<Object> ordered = dg.getOrderedComponentKeys();
+
+      assert ordered.size() == 4;
+
+      System.out.println(ordered);
+
+      int n = 0;
+      assert ordered.get(n++) == Test4.class;
+      assert ordered.get(n++) == Test3.class;
+      assert ordered.get(n++) == Test2.class;
+      assert ordered.get(n) == Test1.class;
+   }
+
+   public static class Test1
+   {
+      private Test2 test2;
+
+      @Inject
+      private void inject(Test2 test2)
+      {
+         this.test2 = test2;
+      }
+   }
+
+   public static class Test2
+   {
+      private Test3 test3;
+      private Test4 test4;
+
+      @Inject
+      private void inject(Test3 test3, Test4 test4)
+      {
+         this.test3 = test3;
+         this.test4 = test4;
+      }
+   }
+
+   public static class Test3
+   {
+      private Test4 test4;
+
+      @Inject
+      private void inject(Test4 test4)
+      {
+         this.test4 = test4;
+      }
+   }
+
+   public static class Test4
+   {
+   }
+}

Modified: core/trunk/src/test/java/org/jboss/cache/interceptors/EvictionInterceptorTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/interceptors/EvictionInterceptorTest.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/test/java/org/jboss/cache/interceptors/EvictionInterceptorTest.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -17,6 +17,7 @@
 import org.jboss.cache.eviction.DummyEvictionConfiguration;
 import org.jboss.cache.eviction.EvictedEventNode;
 import org.jboss.cache.eviction.NodeEventType;
+import org.jboss.cache.factories.ComponentRegistry;
 import org.jboss.cache.factories.InterceptorChainFactory;
 import org.jboss.cache.lock.IsolationLevel;
 import org.jboss.cache.marshall.MethodCall;
@@ -88,10 +89,12 @@
       CallInterceptor ci = new CallInterceptor();
       ei.setNext(ci);
 
-      InterceptorChainFactory.getInstance().correctInterceptorChaining(interceptor, cache.getConfiguration(), TestingUtil.extractComponentRegistry(cache));
-
       cache.getConfiguration().setCacheMode("LOCAL");
       cache.start();
+
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+
+      cr.getComponent(InterceptorChainFactory.class).correctInterceptorChaining(interceptor);
    }
 
    @AfterMethod(alwaysRun = true)

Modified: core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -44,7 +44,6 @@
 @Test(groups = {"functional"})
 abstract public class CacheLoaderTestsBase extends AbstractCacheLoaderTestBase
 {
-
    private static final Log log = LogFactory.getLog(CacheLoaderTestsBase.class);
    CacheSPI<Object, Object> cache;
    CacheLoader loader = null;
@@ -80,6 +79,7 @@
    @AfterMethod(alwaysRun = true)
    public void tearDown() throws Exception
    {
+      log.warn("********* Starting tearDown()");
       cleanup();
       try
       {
@@ -755,7 +755,11 @@
          cache.evict(Fqn.fromString("/a"));
 
          // now load the children - this set childrenLoaded in /a/b to true
-         cache.getNode("/a/b").getChildrenNames();
+//         cache.getNode("/a/b").getChildrenNames();
+
+         NodeSPI n = (NodeSPI) cache.getNode("/a/b");
+         assert !n.isChildrenLoaded();
+
          children = cache.getNode("/a/b").getChildrenNames();
          assertEquals(3, children.size());
 

Modified: core/trunk/src/test/java/org/jboss/cache/loader/UnnecessaryLoadingTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/loader/UnnecessaryLoadingTest.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/test/java/org/jboss/cache/loader/UnnecessaryLoadingTest.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -48,7 +48,7 @@
 
       cache.getCacheLoaderManager().setCacheLoader(mockCacheLoader);
       // re-set the cache so that the mock CL is registered with the inerceptors.
-      InterceptorChainFactory.getInstance().correctInterceptorChaining(cache.getInterceptorChain(), cache.getConfiguration(), TestingUtil.extractComponentRegistry(cache));
+      TestingUtil.extractComponentRegistry(cache).getComponent(InterceptorChainFactory.class).correctInterceptorChaining(cache.getInterceptorChain());
 
       // lifecycle stuff
       mockCacheLoader.stop();

Modified: core/trunk/src/test/java/org/jboss/cache/misc/TestingUtil.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/misc/TestingUtil.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/test/java/org/jboss/cache/misc/TestingUtil.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -94,7 +94,7 @@
       System.out.println("Old interceptor chain: " + CachePrinter.printCacheInterceptors(cache));
       // make sure the new interceptor is wired
       ComponentRegistry cr = extractComponentRegistry(cache);
-      cr.wireDependencies(interceptorToInject);
+      cr.registerComponent(interceptorToInject);
       interceptorToInject.setCache(cache);
       int index = -1;
       for (Interceptor i : cache.getInterceptorChain())
@@ -527,13 +527,15 @@
       ComponentRegistry cr = extractComponentRegistry(cache);
 
       // This will replace the previous interceptor chain in the component registry
-      cr.registerComponent(Interceptor.class, interceptor);
+      cr.registerComponent(Interceptor.class.getName(), interceptor);
 
       // update all component dependencies
       cr.updateDependencies();
 
+      InterceptorChainFactory factory = cr.getComponent(InterceptorChainFactory.class);
+
       // make sure the new interceptors have their deps satisfied.
-      InterceptorChainFactory.getInstance().correctInterceptorChaining(interceptor, cache.getConfiguration(), cr);
+      factory.correctInterceptorChaining(interceptor);
    }
 
    /**

Modified: core/trunk/src/test/java/org/jboss/cache/passivation/PassivationToDummyInMemoryCacheLoaderTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/passivation/PassivationToDummyInMemoryCacheLoaderTest.java	2007-12-18 15:03:42 UTC (rev 4871)
+++ core/trunk/src/test/java/org/jboss/cache/passivation/PassivationToDummyInMemoryCacheLoaderTest.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -2,7 +2,9 @@
 
 import org.jboss.cache.config.CacheLoaderConfig;
 import org.jboss.cache.loader.DummyInMemoryCacheLoader;
+import org.testng.annotations.Test;
 
+ at Test(groups = {"functional"})
 public class PassivationToDummyInMemoryCacheLoaderTest extends PassivationTestsBase
 {
    protected void configureCache() throws Exception

Copied: core/trunk/src/test/java/org/jboss/cache/util/reflect/ClasspathScannerTest.java (from rev 4836, core/trunk/src/test/java/org/jboss/cache/factories/annotations/ClasspathScannerTest.java)
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/util/reflect/ClasspathScannerTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/util/reflect/ClasspathScannerTest.java	2007-12-18 19:58:10 UTC (rev 4872)
@@ -0,0 +1,27 @@
+package org.jboss.cache.util.reflect;
+
+import org.jboss.cache.factories.CacheMarshallerFactory;
+import org.jboss.cache.factories.ComponentFactory;
+import org.jboss.cache.factories.TransactionManagerFactory;
+import org.jboss.cache.factories.annotations.DefaultFactoryFor;
+import org.testng.annotations.Test;
+
+import java.util.Set;
+
+/**
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 2.1.0
+ */
+ at Test(groups = {"functional"})
+public class ClasspathScannerTest
+{
+   public void testScanning()
+   {
+      ClasspathScanner cs = new ClasspathScanner();
+      Set<Class<? extends ComponentFactory>> sc = cs.scan(DefaultFactoryFor.class, ComponentFactory.class);
+
+      // should at least contain these 2.
+      assert sc.contains(TransactionManagerFactory.class);
+      assert sc.contains(CacheMarshallerFactory.class);
+   }
+}




More information about the jbosscache-commits mailing list