struts-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rgie...@apache.org
Subject svn commit: r1294413 - /struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java
Date Tue, 28 Feb 2012 00:28:57 GMT
Author: rgielen
Date: Tue Feb 28 00:28:57 2012
New Revision: 1294413

URL: http://svn.apache.org/viewvc?rev=1294413&view=rev
Log:
Simple code reformatting, no actual change.

Modified:
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java

Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java?rev=1294413&r1=1294412&r2=1294413&view=diff
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java
(original)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java
Tue Feb 28 00:28:57 2012
@@ -28,594 +28,602 @@ import java.security.AccessControlExcept
 /**
  * Default {@link Container} implementation.
  *
- * @see ContainerBuilder
  * @author crazybob@google.com (Bob Lee)
+ * @see ContainerBuilder
  */
 class ContainerImpl implements Container {
 
-  final Map<Key<?>, InternalFactory<?>> factories;
-  final Map<Class<?>,Set<String>> factoryNamesByType;
+	final Map<Key<?>, InternalFactory<?>> factories;
+	final Map<Class<?>, Set<String>> factoryNamesByType;
 
-  ContainerImpl(Map<Key<?>, InternalFactory<?>> factories) {
-    this.factories = factories;
-    Map<Class<?>,Set<String>> map = new HashMap<Class<?>,Set<String>>();
-    for (Key<?> key : factories.keySet()) {
-      Set<String> names = map.get(key.getType());
-      if (names == null) {
-        names = new HashSet<String>();
-        map.put(key.getType(), names);
-      }
-      names.add(key.getName());
-    }
-    
-    for (Entry<Class<?>,Set<String>> entry : map.entrySet()) {
-      entry.setValue(Collections.unmodifiableSet(entry.getValue()));
-    }
-    
-    this.factoryNamesByType = Collections.unmodifiableMap(map);
-  }
-
-  @SuppressWarnings("unchecked")
-  <T> InternalFactory<? extends T> getFactory(Key<T> key) {
-    return (InternalFactory<T>) factories.get(key);
-  }
-
-  /**
-   * Field and method injectors.
-   */
-  final Map<Class<?>, List<Injector>> injectors =
-      new ReferenceCache<Class<?>, List<Injector>>() {
-        @Override
-        protected List<Injector> create(Class<?> key) {
-          List<Injector> injectors = new ArrayList<Injector>();
-          addInjectors(key, injectors);
-          return injectors;
-        }
-      };
-
-  /**
-   * Recursively adds injectors for fields and methods from the given class to
-   * the given list. Injects parent classes before sub classes.
-   */
-  void addInjectors(Class clazz, List<Injector> injectors) {
-    if (clazz == Object.class) {
-      return;
-    }
-
-    // Add injectors for superclass first.
-    addInjectors(clazz.getSuperclass(), injectors);
-
-    // TODO (crazybob): Filter out overridden members.
-    addInjectorsForFields(clazz.getDeclaredFields(), false, injectors);
-    addInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors);
-  }
-
-  void injectStatics(List<Class<?>> staticInjections) {
-    final List<Injector> injectors = new ArrayList<Injector>();
-
-    for (Class<?> clazz : staticInjections) {
-      addInjectorsForFields(clazz.getDeclaredFields(), true, injectors);
-      addInjectorsForMethods(clazz.getDeclaredMethods(), true, injectors);
-    }
-
-    callInContext(new ContextualCallable<Void>() {
-      public Void call(InternalContext context) {
-        for (Injector injector : injectors) {
-          injector.inject(context, null);
-        }
-        return null;
-      }
-    });
-  }
-
-  void addInjectorsForMethods(Method[] methods, boolean statics,
-      List<Injector> injectors) {
-    addInjectorsForMembers(Arrays.asList(methods), statics, injectors,
-        new InjectorFactory<Method>() {
-          public Injector create(ContainerImpl container, Method method,
-              String name) throws MissingDependencyException {
-            return new MethodInjector(container, method, name);
-          }
-        });
-  }
-
-  void addInjectorsForFields(Field[] fields, boolean statics,
-      List<Injector> injectors) {
-    addInjectorsForMembers(Arrays.asList(fields), statics, injectors,
-        new InjectorFactory<Field>() {
-          public Injector create(ContainerImpl container, Field field,
-              String name) throws MissingDependencyException {
-            return new FieldInjector(container, field, name);
-          }
-        });
-  }
-
-  <M extends Member & AnnotatedElement> void addInjectorsForMembers(
-      List<M> members, boolean statics, List<Injector> injectors,
-      InjectorFactory<M> injectorFactory) {
-    for (M member : members) {
-      if (isStatic(member) == statics) {
-        Inject inject = member.getAnnotation(Inject.class);
-        if (inject != null) {
-          try {
-            injectors.add(injectorFactory.create(this, member, inject.value()));
-          } catch (MissingDependencyException e) {
-            if (inject.required()) {
-              throw new DependencyException(e);
-            }
-          }
-        }
-      }
-    }
-  }
-
-  interface InjectorFactory<M extends Member & AnnotatedElement> {
-    Injector create(ContainerImpl container, M member, String name)
-        throws MissingDependencyException;
-  }
-
-  private boolean isStatic(Member member) {
-    return Modifier.isStatic(member.getModifiers());
-  }
-
-  static class FieldInjector implements Injector {
-
-    final Field field;
-    final InternalFactory<?> factory;
-    final ExternalContext<?> externalContext;
-
-    public FieldInjector(ContainerImpl container, Field field, String name)
-        throws MissingDependencyException {
-      this.field = field;
-        if (!field.isAccessible()) {
-            SecurityManager sm = System.getSecurityManager();
-            try {
-                if (sm != null) sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
-                field.setAccessible(true);
-            } catch(AccessControlException e) {
-                throw new DependencyException("Security manager in use, could not access
field: "
-                        + field.getDeclaringClass().getName() + "(" + field.getName() + ")",
e);
-            }
-        }
-
-      Key<?> key = Key.newInstance(field.getType(), name);
-      factory = container.getFactory(key);
-      if (factory == null) {
-        throw new MissingDependencyException(
-            "No mapping found for dependency " + key + " in " + field + ".");
-      }
-
-      this.externalContext = ExternalContext.newInstance(field, key, container);
-    }
-
-    public void inject(InternalContext context, Object o) {
-      ExternalContext<?> previous = context.getExternalContext();
-      context.setExternalContext(externalContext);
-      try {
-        field.set(o, factory.create(context));
-      } catch (IllegalAccessException e) {
-        throw new AssertionError(e);
-      } finally {
-        context.setExternalContext(previous);
-      }
-    }
-  }
-
-  /**
-   * Gets parameter injectors.
-   *
-   * @param member to which the parameters belong
-   * @param annotations on the parameters
-   * @param parameterTypes parameter types
-   * @return injections
-   */
-  <M extends AccessibleObject & Member> ParameterInjector<?>[]
-      getParametersInjectors(M member,
-      Annotation[][] annotations, Class[] parameterTypes, String defaultName)
-      throws MissingDependencyException {
-    List<ParameterInjector<?>> parameterInjectors =
-        new ArrayList<ParameterInjector<?>>();
-
-    Iterator<Annotation[]> annotationsIterator =
-        Arrays.asList(annotations).iterator();
-    for (Class<?> parameterType : parameterTypes) {
-      Inject annotation = findInject(annotationsIterator.next());
-      String name = annotation == null ? defaultName : annotation.value();
-      Key<?> key = Key.newInstance(parameterType, name);
-      parameterInjectors.add(createParameterInjector(key, member));
-    }
-
-    return toArray(parameterInjectors);
-  }
-
-  <T> ParameterInjector<T> createParameterInjector(
-      Key<T> key, Member member) throws MissingDependencyException {
-    InternalFactory<? extends T> factory = getFactory(key);
-    if (factory == null) {
-      throw new MissingDependencyException(
-          "No mapping found for dependency " + key + " in " + member + ".");
-    }
-
-    ExternalContext<T> externalContext =
-        ExternalContext.newInstance(member, key, this);
-    return new ParameterInjector<T>(externalContext, factory);
-  }
-
-  @SuppressWarnings("unchecked")
-  private ParameterInjector<?>[] toArray(
-      List<ParameterInjector<?>> parameterInjections) {
-    return parameterInjections.toArray(
-        new ParameterInjector[parameterInjections.size()]);
-  }
-
-  /**
-   * Finds the {@link Inject} annotation in an array of annotations.
-   */
-  Inject findInject(Annotation[] annotations) {
-    for (Annotation annotation : annotations) {
-      if (annotation.annotationType() == Inject.class) {
-        return Inject.class.cast(annotation);
-      }
-    }
-    return null;
-  }
-
-  static class MethodInjector implements Injector {
-
-    final Method method;
-    final ParameterInjector<?>[] parameterInjectors;
-
-    public MethodInjector(ContainerImpl container, Method method, String name)
-        throws MissingDependencyException {
-      this.method = method;
-        if (!method.isAccessible()) {
-            SecurityManager sm = System.getSecurityManager();
-            try {
-                if (sm != null) sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
-                method.setAccessible(true);
-            } catch(AccessControlException e) {
-                throw new DependencyException("Security manager in use, could not access
method: "
-                        + name + "(" + method.getName() + ")", e);
-            }
-        }
-
-      Class<?>[] parameterTypes = method.getParameterTypes();
-      if (parameterTypes.length == 0) {
-        throw new DependencyException(
-            method + " has no parameters to inject.");
-      }
-      parameterInjectors = container.getParametersInjectors(
-          method, method.getParameterAnnotations(), parameterTypes, name);
-    }
-
-    public void inject(InternalContext context, Object o) {
-      try {
-        method.invoke(o, getParameters(method, context, parameterInjectors));
-      } catch (Exception e) {
-        throw new RuntimeException(e);
-      }
-    }
-  }
-
-  Map<Class<?>, ConstructorInjector> constructors =
-      new ReferenceCache<Class<?>, ConstructorInjector>() {
-        @Override
-        @SuppressWarnings("unchecked")
-        protected ConstructorInjector<?> create(Class<?> implementation) {
-          return new ConstructorInjector(ContainerImpl.this, implementation);
-        }
-      };
-
-  static class ConstructorInjector<T> {
-
-    final Class<T> implementation;
-    final List<Injector> injectors;
-    final Constructor<T> constructor;
-    final ParameterInjector<?>[] parameterInjectors;
-
-    ConstructorInjector(ContainerImpl container, Class<T> implementation) {
-      this.implementation = implementation;
-
-      constructor = findConstructorIn(implementation);
-        if (!constructor.isAccessible()) {
-            SecurityManager sm = System.getSecurityManager();
-            try {
-                if (sm != null) sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
-                constructor.setAccessible(true);
-            } catch(AccessControlException e) {
-                throw new DependencyException("Security manager in use, could not access
constructor: "
-                        + implementation.getName() + "(" + constructor.getName() + ")", e);
-            }
-        }
-
-      MissingDependencyException exception = null;
-      Inject inject = null;
-      ParameterInjector<?>[] parameters = null;
-        
-      try {
-        inject = constructor.getAnnotation(Inject.class);
-        parameters = constructParameterInjector(inject, container, constructor);
-      } catch (MissingDependencyException e) {
-        exception = e;
-      }
-      parameterInjectors = parameters;
-
-      if ( exception != null) {
-        if ( inject != null && inject.required()) {
-          throw new DependencyException(exception);
-        }
-      }
-      injectors = container.injectors.get(implementation);
-    }
-
-    ParameterInjector<?>[] constructParameterInjector(
-    Inject inject, ContainerImpl container, Constructor<T> constructor) throws MissingDependencyException{
-    return constructor.getParameterTypes().length == 0
-      ? null // default constructor.
-      : container.getParametersInjectors(
-        constructor,
-        constructor.getParameterAnnotations(),
-        constructor.getParameterTypes(),
-        inject.value()
-      );
-    }
-
-    @SuppressWarnings("unchecked")
-    private Constructor<T> findConstructorIn(Class<T> implementation) {
-      Constructor<T> found = null;
-      Constructor<T>[] declaredConstructors = (Constructor<T>[]) implementation
-                    .getDeclaredConstructors();
-      for(Constructor<T> constructor :  declaredConstructors) {
-        if (constructor.getAnnotation(Inject.class) != null) {
-          if (found != null) {
-            throw new DependencyException("More than one constructor annotated"
-              + " with @Inject found in " + implementation + ".");
-          }
-          found = constructor;
-        }
-      }
-      if (found != null) {
-        return found;
-      }
-
-      // If no annotated constructor is found, look for a no-arg constructor
-      // instead.
-      try {
-        return implementation.getDeclaredConstructor();
-      } catch (NoSuchMethodException e) {
-        throw new DependencyException("Could not find a suitable constructor"
-            + " in " + implementation.getName() + ".");
-      }
-    }
-
-    /**
-     * Construct an instance. Returns {@code Object} instead of {@code T}
-     * because it may return a proxy.
-     */
-    Object construct(InternalContext context, Class<? super T> expectedType) {
-      ConstructionContext<T> constructionContext =
-          context.getConstructionContext(this);
-
-      // We have a circular reference between constructors. Return a proxy.
-      if (constructionContext.isConstructing()) {
-        // TODO (crazybob): if we can't proxy this object, can we proxy the
-        // other object?
-        return constructionContext.createProxy(expectedType);
-      }
-
-      // If we're re-entering this factory while injecting fields or methods,
-      // return the same instance. This prevents infinite loops.
-      T t = constructionContext.getCurrentReference();
-      if (t != null) {
-        return t;
-      }
-
-      try {
-        // First time through...
-        constructionContext.startConstruction();
-        try {
-          Object[] parameters =
-              getParameters(constructor, context, parameterInjectors);
-          t = constructor.newInstance(parameters);
-          constructionContext.setProxyDelegates(t);
-        } finally {
-          constructionContext.finishConstruction();
-        }
-
-        // Store reference. If an injector re-enters this factory, they'll
-        // get the same reference.
-        constructionContext.setCurrentReference(t);
-
-        // Inject fields and methods.
-        for (Injector injector : injectors) {
-          injector.inject(context, t);
-        }
-
-        return t;
-      } catch (InstantiationException e) {
-        throw new RuntimeException(e);
-      } catch (IllegalAccessException e) {
-        throw new RuntimeException(e);
-      } catch (InvocationTargetException e) {
-        throw new RuntimeException(e);
-      } finally {
-        constructionContext.removeCurrentReference();
-      }
-    }
-  }
-
-  static class ParameterInjector<T> {
-
-    final ExternalContext<T> externalContext;
-    final InternalFactory<? extends T> factory;
-
-    public ParameterInjector(ExternalContext<T> externalContext,
-        InternalFactory<? extends T> factory) {
-      this.externalContext = externalContext;
-      this.factory = factory;
-    }
-
-    T inject(Member member, InternalContext context) {
-      ExternalContext<?> previous = context.getExternalContext();
-      context.setExternalContext(externalContext);
-      try {
-        return factory.create(context);
-      } finally {
-        context.setExternalContext(previous);
-      }
-    }
-  }
-
-  private static Object[] getParameters(Member member, InternalContext context,
-      ParameterInjector[] parameterInjectors) {
-    if (parameterInjectors == null) {
-      return null;
-    }
-
-    Object[] parameters = new Object[parameterInjectors.length];
-    for (int i = 0; i < parameters.length; i++) {
-      parameters[i] = parameterInjectors[i].inject(member, context);
-    }
-    return parameters;
-  }
-
-  void inject(Object o, InternalContext context) {
-    List<Injector> injectors = this.injectors.get(o.getClass());
-    for (Injector injector : injectors) {
-      injector.inject(context, o);
-    }
-  }
-
-  <T> T inject(Class<T> implementation, InternalContext context) {
-    try {
-      ConstructorInjector<T> constructor = getConstructor(implementation);
-      return implementation.cast(
-          constructor.construct(context, implementation));
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  @SuppressWarnings("unchecked")
-  <T> T getInstance(Class<T> type, String name, InternalContext context) {
-    ExternalContext<?> previous = context.getExternalContext();
-    Key<T> key = Key.newInstance(type, name);
-    context.setExternalContext(ExternalContext.newInstance(null, key, this));
-    try {
-      InternalFactory o = getFactory(key);
-      if (o != null) {
-          return getFactory(key).create(context);
-      } else {
-          return null;
-      }
-    } finally {
-      context.setExternalContext(previous);
-    }
-  }
-
-  <T> T getInstance(Class<T> type, InternalContext context) {
-    return getInstance(type, DEFAULT_NAME, context);
-  }
-
-  public void inject(final Object o) {
-    callInContext(new ContextualCallable<Void>() {
-      public Void call(InternalContext context) {
-        inject(o, context);
-        return null;
-      }
-    });
-  }
-
-  public <T> T inject(final Class<T> implementation) {
-    return callInContext(new ContextualCallable<T>() {
-      public T call(InternalContext context) {
-        return inject(implementation, context);
-      }
-    });
-  }
-
-  public <T> T getInstance(final Class<T> type, final String name) {
-    return callInContext(new ContextualCallable<T>() {
-      public T call(InternalContext context) {
-        return getInstance(type, name, context);
-      }
-    });
-  }
-
-  public <T> T getInstance(final Class<T> type) {
-    return callInContext(new ContextualCallable<T>() {
-      public T call(InternalContext context) {
-        return getInstance(type, context);
-      }
-    });
-  }
-  
-  public Set<String> getInstanceNames(final Class<?> type) {
-    return factoryNamesByType.get(type);
-  }
-
-  ThreadLocal<Object[]> localContext =
-      new ThreadLocal<Object[]>() {
-        @Override
-        protected Object[] initialValue() {
-          return new Object[1];
-        }
-      };
-
-  /**
-   * Looks up thread local context. Creates (and removes) a new context if
-   * necessary.
-   */
-  <T> T callInContext(ContextualCallable<T> callable) {
-    Object[] reference = localContext.get();
-    if (reference[0] == null) {
-      reference[0] = new InternalContext(this);
-      try {
-        return callable.call((InternalContext)reference[0]);
-      } finally {
-        // Only remove the context if this call created it.
-        reference[0] = null;
-      }
-    } else {
-      // Someone else will clean up this context.
-      return callable.call((InternalContext)reference[0]);
-    }
-  }
-
-  interface ContextualCallable<T> {
-    T call(InternalContext context);
-  }
-
-  /**
-   * Gets a constructor function for a given implementation class.
-   */
-  @SuppressWarnings("unchecked")
-  <T> ConstructorInjector<T> getConstructor(Class<T> implementation) {
-    return constructors.get(implementation);
-  }
-
-  final ThreadLocal<Object> localScopeStrategy =
-      new ThreadLocal<Object>();
-
-  public void setScopeStrategy(Scope.Strategy scopeStrategy) {
-    this.localScopeStrategy.set(scopeStrategy);
-  }
-
-  public void removeScopeStrategy() {
-    this.localScopeStrategy.remove();
-  }
-
-  /**
-   * Injects a field or method in a given object.
-   */
-  interface Injector extends Serializable {
-    void inject(InternalContext context, Object o);
-  }
-
-  static class MissingDependencyException extends Exception {
-
-    MissingDependencyException(String message) {
-      super(message);
-    }
-  }
+	ContainerImpl( Map<Key<?>, InternalFactory<?>> factories ) {
+		this.factories = factories;
+		Map<Class<?>, Set<String>> map = new HashMap<Class<?>, Set<String>>();
+		for ( Key<?> key : factories.keySet() ) {
+			Set<String> names = map.get(key.getType());
+			if (names == null) {
+				names = new HashSet<String>();
+				map.put(key.getType(), names);
+			}
+			names.add(key.getName());
+		}
+
+		for ( Entry<Class<?>, Set<String>> entry : map.entrySet() ) {
+			entry.setValue(Collections.unmodifiableSet(entry.getValue()));
+		}
+
+		this.factoryNamesByType = Collections.unmodifiableMap(map);
+	}
+
+	@SuppressWarnings("unchecked")
+	<T> InternalFactory<? extends T> getFactory( Key<T> key ) {
+		return (InternalFactory<T>) factories.get(key);
+	}
+
+	/**
+	 * Field and method injectors.
+	 */
+	final Map<Class<?>, List<Injector>> injectors =
+			new ReferenceCache<Class<?>, List<Injector>>() {
+				@Override
+				protected List<Injector> create( Class<?> key ) {
+					List<Injector> injectors = new ArrayList<Injector>();
+					addInjectors(key, injectors);
+					return injectors;
+				}
+			};
+
+	/**
+	 * Recursively adds injectors for fields and methods from the given class to the given list.
Injects parent classes
+	 * before sub classes.
+	 */
+	void addInjectors( Class clazz, List<Injector> injectors ) {
+		if (clazz == Object.class) {
+			return;
+		}
+
+		// Add injectors for superclass first.
+		addInjectors(clazz.getSuperclass(), injectors);
+
+		// TODO (crazybob): Filter out overridden members.
+		addInjectorsForFields(clazz.getDeclaredFields(), false, injectors);
+		addInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors);
+	}
+
+	void injectStatics( List<Class<?>> staticInjections ) {
+		final List<Injector> injectors = new ArrayList<Injector>();
+
+		for ( Class<?> clazz : staticInjections ) {
+			addInjectorsForFields(clazz.getDeclaredFields(), true, injectors);
+			addInjectorsForMethods(clazz.getDeclaredMethods(), true, injectors);
+		}
+
+		callInContext(new ContextualCallable<Void>() {
+			public Void call( InternalContext context ) {
+				for ( Injector injector : injectors ) {
+					injector.inject(context, null);
+				}
+				return null;
+			}
+		});
+	}
+
+	void addInjectorsForMethods( Method[] methods, boolean statics,
+								 List<Injector> injectors ) {
+		addInjectorsForMembers(Arrays.asList(methods), statics, injectors,
+				new InjectorFactory<Method>() {
+					public Injector create( ContainerImpl container, Method method,
+											String name ) throws MissingDependencyException {
+						return new MethodInjector(container, method, name);
+					}
+				});
+	}
+
+	void addInjectorsForFields( Field[] fields, boolean statics,
+								List<Injector> injectors ) {
+		addInjectorsForMembers(Arrays.asList(fields), statics, injectors,
+				new InjectorFactory<Field>() {
+					public Injector create( ContainerImpl container, Field field,
+											String name ) throws MissingDependencyException {
+						return new FieldInjector(container, field, name);
+					}
+				});
+	}
+
+	<M extends Member & AnnotatedElement> void addInjectorsForMembers(
+			List<M> members, boolean statics, List<Injector> injectors,
+			InjectorFactory<M> injectorFactory ) {
+		for ( M member : members ) {
+			if (isStatic(member) == statics) {
+				Inject inject = member.getAnnotation(Inject.class);
+				if (inject != null) {
+					try {
+						injectors.add(injectorFactory.create(this, member, inject.value()));
+					} catch ( MissingDependencyException e ) {
+						if (inject.required()) {
+							throw new DependencyException(e);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	interface InjectorFactory<M extends Member & AnnotatedElement> {
+
+		Injector create( ContainerImpl container, M member, String name )
+				throws MissingDependencyException;
+	}
+
+	private boolean isStatic( Member member ) {
+		return Modifier.isStatic(member.getModifiers());
+	}
+
+	static class FieldInjector implements Injector {
+
+		final Field field;
+		final InternalFactory<?> factory;
+		final ExternalContext<?> externalContext;
+
+		public FieldInjector( ContainerImpl container, Field field, String name )
+				throws MissingDependencyException {
+			this.field = field;
+			if (!field.isAccessible()) {
+				SecurityManager sm = System.getSecurityManager();
+				try {
+					if (sm != null) {
+						sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
+					}
+					field.setAccessible(true);
+				} catch ( AccessControlException e ) {
+					throw new DependencyException("Security manager in use, could not access field: "
+							+ field.getDeclaringClass().getName() + "(" + field.getName() + ")", e);
+				}
+			}
+
+			Key<?> key = Key.newInstance(field.getType(), name);
+			factory = container.getFactory(key);
+			if (factory == null) {
+				throw new MissingDependencyException(
+						"No mapping found for dependency " + key + " in " + field + ".");
+			}
+
+			this.externalContext = ExternalContext.newInstance(field, key, container);
+		}
+
+		public void inject( InternalContext context, Object o ) {
+			ExternalContext<?> previous = context.getExternalContext();
+			context.setExternalContext(externalContext);
+			try {
+				field.set(o, factory.create(context));
+			} catch ( IllegalAccessException e ) {
+				throw new AssertionError(e);
+			} finally {
+				context.setExternalContext(previous);
+			}
+		}
+	}
+
+	/**
+	 * Gets parameter injectors.
+	 *
+	 * @param member		 to which the parameters belong
+	 * @param annotations	on the parameters
+	 * @param parameterTypes parameter types
+	 *
+	 * @return injections
+	 */
+	<M extends AccessibleObject & Member> ParameterInjector<?>[]
+	getParametersInjectors( M member,
+							Annotation[][] annotations, Class[] parameterTypes, String defaultName )
+			throws MissingDependencyException {
+		List<ParameterInjector<?>> parameterInjectors =
+				new ArrayList<ParameterInjector<?>>();
+
+		Iterator<Annotation[]> annotationsIterator =
+				Arrays.asList(annotations).iterator();
+		for ( Class<?> parameterType : parameterTypes ) {
+			Inject annotation = findInject(annotationsIterator.next());
+			String name = annotation == null ? defaultName : annotation.value();
+			Key<?> key = Key.newInstance(parameterType, name);
+			parameterInjectors.add(createParameterInjector(key, member));
+		}
+
+		return toArray(parameterInjectors);
+	}
+
+	<T> ParameterInjector<T> createParameterInjector(
+			Key<T> key, Member member ) throws MissingDependencyException {
+		InternalFactory<? extends T> factory = getFactory(key);
+		if (factory == null) {
+			throw new MissingDependencyException(
+					"No mapping found for dependency " + key + " in " + member + ".");
+		}
+
+		ExternalContext<T> externalContext =
+				ExternalContext.newInstance(member, key, this);
+		return new ParameterInjector<T>(externalContext, factory);
+	}
+
+	@SuppressWarnings("unchecked")
+	private ParameterInjector<?>[] toArray(
+			List<ParameterInjector<?>> parameterInjections ) {
+		return parameterInjections.toArray(
+				new ParameterInjector[parameterInjections.size()]);
+	}
+
+	/**
+	 * Finds the {@link Inject} annotation in an array of annotations.
+	 */
+	Inject findInject( Annotation[] annotations ) {
+		for ( Annotation annotation : annotations ) {
+			if (annotation.annotationType() == Inject.class) {
+				return Inject.class.cast(annotation);
+			}
+		}
+		return null;
+	}
+
+	static class MethodInjector implements Injector {
+
+		final Method method;
+		final ParameterInjector<?>[] parameterInjectors;
+
+		public MethodInjector( ContainerImpl container, Method method, String name )
+				throws MissingDependencyException {
+			this.method = method;
+			if (!method.isAccessible()) {
+				SecurityManager sm = System.getSecurityManager();
+				try {
+					if (sm != null) {
+						sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
+					}
+					method.setAccessible(true);
+				} catch ( AccessControlException e ) {
+					throw new DependencyException("Security manager in use, could not access method: "
+							+ name + "(" + method.getName() + ")", e);
+				}
+			}
+
+			Class<?>[] parameterTypes = method.getParameterTypes();
+			if (parameterTypes.length == 0) {
+				throw new DependencyException(
+						method + " has no parameters to inject.");
+			}
+			parameterInjectors = container.getParametersInjectors(
+					method, method.getParameterAnnotations(), parameterTypes, name);
+		}
+
+		public void inject( InternalContext context, Object o ) {
+			try {
+				method.invoke(o, getParameters(method, context, parameterInjectors));
+			} catch ( Exception e ) {
+				throw new RuntimeException(e);
+			}
+		}
+	}
+
+	Map<Class<?>, ConstructorInjector> constructors =
+			new ReferenceCache<Class<?>, ConstructorInjector>() {
+				@Override
+				@SuppressWarnings("unchecked")
+				protected ConstructorInjector<?> create( Class<?> implementation ) {
+					return new ConstructorInjector(ContainerImpl.this, implementation);
+				}
+			};
+
+	static class ConstructorInjector<T> {
+
+		final Class<T> implementation;
+		final List<Injector> injectors;
+		final Constructor<T> constructor;
+		final ParameterInjector<?>[] parameterInjectors;
+
+		ConstructorInjector( ContainerImpl container, Class<T> implementation ) {
+			this.implementation = implementation;
+
+			constructor = findConstructorIn(implementation);
+			if (!constructor.isAccessible()) {
+				SecurityManager sm = System.getSecurityManager();
+				try {
+					if (sm != null) {
+						sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
+					}
+					constructor.setAccessible(true);
+				} catch ( AccessControlException e ) {
+					throw new DependencyException("Security manager in use, could not access constructor:
"
+							+ implementation.getName() + "(" + constructor.getName() + ")", e);
+				}
+			}
+
+			MissingDependencyException exception = null;
+			Inject inject = null;
+			ParameterInjector<?>[] parameters = null;
+
+			try {
+				inject = constructor.getAnnotation(Inject.class);
+				parameters = constructParameterInjector(inject, container, constructor);
+			} catch ( MissingDependencyException e ) {
+				exception = e;
+			}
+			parameterInjectors = parameters;
+
+			if (exception != null) {
+				if (inject != null && inject.required()) {
+					throw new DependencyException(exception);
+				}
+			}
+			injectors = container.injectors.get(implementation);
+		}
+
+		ParameterInjector<?>[] constructParameterInjector(
+				Inject inject, ContainerImpl container, Constructor<T> constructor ) throws MissingDependencyException
{
+			return constructor.getParameterTypes().length == 0
+					? null // default constructor.
+					: container.getParametersInjectors(
+					constructor,
+					constructor.getParameterAnnotations(),
+					constructor.getParameterTypes(),
+					inject.value()
+			);
+		}
+
+		@SuppressWarnings("unchecked")
+		private Constructor<T> findConstructorIn( Class<T> implementation ) {
+			Constructor<T> found = null;
+			Constructor<T>[] declaredConstructors = (Constructor<T>[]) implementation
+					.getDeclaredConstructors();
+			for ( Constructor<T> constructor : declaredConstructors ) {
+				if (constructor.getAnnotation(Inject.class) != null) {
+					if (found != null) {
+						throw new DependencyException("More than one constructor annotated"
+								+ " with @Inject found in " + implementation + ".");
+					}
+					found = constructor;
+				}
+			}
+			if (found != null) {
+				return found;
+			}
+
+			// If no annotated constructor is found, look for a no-arg constructor
+			// instead.
+			try {
+				return implementation.getDeclaredConstructor();
+			} catch ( NoSuchMethodException e ) {
+				throw new DependencyException("Could not find a suitable constructor"
+						+ " in " + implementation.getName() + ".");
+			}
+		}
+
+		/**
+		 * Construct an instance. Returns {@code Object} instead of {@code T} because it may return
a proxy.
+		 */
+		Object construct( InternalContext context, Class<? super T> expectedType ) {
+			ConstructionContext<T> constructionContext =
+					context.getConstructionContext(this);
+
+			// We have a circular reference between constructors. Return a proxy.
+			if (constructionContext.isConstructing()) {
+				// TODO (crazybob): if we can't proxy this object, can we proxy the
+				// other object?
+				return constructionContext.createProxy(expectedType);
+			}
+
+			// If we're re-entering this factory while injecting fields or methods,
+			// return the same instance. This prevents infinite loops.
+			T t = constructionContext.getCurrentReference();
+			if (t != null) {
+				return t;
+			}
+
+			try {
+				// First time through...
+				constructionContext.startConstruction();
+				try {
+					Object[] parameters =
+							getParameters(constructor, context, parameterInjectors);
+					t = constructor.newInstance(parameters);
+					constructionContext.setProxyDelegates(t);
+				} finally {
+					constructionContext.finishConstruction();
+				}
+
+				// Store reference. If an injector re-enters this factory, they'll
+				// get the same reference.
+				constructionContext.setCurrentReference(t);
+
+				// Inject fields and methods.
+				for ( Injector injector : injectors ) {
+					injector.inject(context, t);
+				}
+
+				return t;
+			} catch ( InstantiationException e ) {
+				throw new RuntimeException(e);
+			} catch ( IllegalAccessException e ) {
+				throw new RuntimeException(e);
+			} catch ( InvocationTargetException e ) {
+				throw new RuntimeException(e);
+			} finally {
+				constructionContext.removeCurrentReference();
+			}
+		}
+	}
+
+	static class ParameterInjector<T> {
+
+		final ExternalContext<T> externalContext;
+		final InternalFactory<? extends T> factory;
+
+		public ParameterInjector( ExternalContext<T> externalContext,
+								  InternalFactory<? extends T> factory ) {
+			this.externalContext = externalContext;
+			this.factory = factory;
+		}
+
+		T inject( Member member, InternalContext context ) {
+			ExternalContext<?> previous = context.getExternalContext();
+			context.setExternalContext(externalContext);
+			try {
+				return factory.create(context);
+			} finally {
+				context.setExternalContext(previous);
+			}
+		}
+	}
+
+	private static Object[] getParameters( Member member, InternalContext context,
+										   ParameterInjector[] parameterInjectors ) {
+		if (parameterInjectors == null) {
+			return null;
+		}
+
+		Object[] parameters = new Object[parameterInjectors.length];
+		for ( int i = 0; i < parameters.length; i++ ) {
+			parameters[i] = parameterInjectors[i].inject(member, context);
+		}
+		return parameters;
+	}
+
+	void inject( Object o, InternalContext context ) {
+		List<Injector> injectors = this.injectors.get(o.getClass());
+		for ( Injector injector : injectors ) {
+			injector.inject(context, o);
+		}
+	}
+
+	<T> T inject( Class<T> implementation, InternalContext context ) {
+		try {
+			ConstructorInjector<T> constructor = getConstructor(implementation);
+			return implementation.cast(
+					constructor.construct(context, implementation));
+		} catch ( Exception e ) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	<T> T getInstance( Class<T> type, String name, InternalContext context ) {
+		ExternalContext<?> previous = context.getExternalContext();
+		Key<T> key = Key.newInstance(type, name);
+		context.setExternalContext(ExternalContext.newInstance(null, key, this));
+		try {
+			InternalFactory o = getFactory(key);
+			if (o != null) {
+				return getFactory(key).create(context);
+			} else {
+				return null;
+			}
+		} finally {
+			context.setExternalContext(previous);
+		}
+	}
+
+	<T> T getInstance( Class<T> type, InternalContext context ) {
+		return getInstance(type, DEFAULT_NAME, context);
+	}
+
+	public void inject( final Object o ) {
+		callInContext(new ContextualCallable<Void>() {
+			public Void call( InternalContext context ) {
+				inject(o, context);
+				return null;
+			}
+		});
+	}
+
+	public <T> T inject( final Class<T> implementation ) {
+		return callInContext(new ContextualCallable<T>() {
+			public T call( InternalContext context ) {
+				return inject(implementation, context);
+			}
+		});
+	}
+
+	public <T> T getInstance( final Class<T> type, final String name ) {
+		return callInContext(new ContextualCallable<T>() {
+			public T call( InternalContext context ) {
+				return getInstance(type, name, context);
+			}
+		});
+	}
+
+	public <T> T getInstance( final Class<T> type ) {
+		return callInContext(new ContextualCallable<T>() {
+			public T call( InternalContext context ) {
+				return getInstance(type, context);
+			}
+		});
+	}
+
+	public Set<String> getInstanceNames( final Class<?> type ) {
+		return factoryNamesByType.get(type);
+	}
+
+	ThreadLocal<Object[]> localContext =
+			new ThreadLocal<Object[]>() {
+				@Override
+				protected Object[] initialValue() {
+					return new Object[1];
+				}
+			};
+
+	/**
+	 * Looks up thread local context. Creates (and removes) a new context if necessary.
+	 */
+	<T> T callInContext( ContextualCallable<T> callable ) {
+		Object[] reference = localContext.get();
+		if (reference[0] == null) {
+			reference[0] = new InternalContext(this);
+			try {
+				return callable.call((InternalContext) reference[0]);
+			} finally {
+				// Only remove the context if this call created it.
+				reference[0] = null;
+			}
+		} else {
+			// Someone else will clean up this context.
+			return callable.call((InternalContext) reference[0]);
+		}
+	}
+
+	interface ContextualCallable<T> {
+
+		T call( InternalContext context );
+	}
+
+	/**
+	 * Gets a constructor function for a given implementation class.
+	 */
+	@SuppressWarnings("unchecked")
+	<T> ConstructorInjector<T> getConstructor( Class<T> implementation ) {
+		return constructors.get(implementation);
+	}
+
+	final ThreadLocal<Object> localScopeStrategy =
+			new ThreadLocal<Object>();
+
+	public void setScopeStrategy( Scope.Strategy scopeStrategy ) {
+		this.localScopeStrategy.set(scopeStrategy);
+	}
+
+	public void removeScopeStrategy() {
+		this.localScopeStrategy.remove();
+	}
+
+	/**
+	 * Injects a field or method in a given object.
+	 */
+	interface Injector extends Serializable {
+
+		void inject( InternalContext context, Object o );
+	}
+
+	static class MissingDependencyException extends Exception {
+
+		MissingDependencyException( String message ) {
+			super(message);
+		}
+	}
 }



Mime
View raw message