001 /*****************************************************************************
002 * Copyright (C) PicoContainer Organization. All rights reserved. *
003 * ------------------------------------------------------------------------- *
004 * The software in this package is published under the terms of the BSD *
005 * style license a copy of which has been included with this distribution in *
006 * the LICENSE.txt file. *
007 * *
008 *****************************************************************************/
009 package org.picocontainer.injectors;
010
011 import org.picocontainer.*;
012 import org.picocontainer.lifecycle.NullLifecycleStrategy;
013 import org.picocontainer.monitors.NullComponentMonitor;
014
015 import java.lang.reflect.InvocationTargetException;
016 import java.lang.reflect.Method;
017 import java.security.AccessController;
018 import java.security.PrivilegedAction;
019 import java.util.Properties;
020
021 /**
022 * A Reinjector allows methods on pre-instantiated classes to be invoked,
023 * with appropriately scoped parameters.
024 */
025 public class Reinjector {
026
027 private final PicoContainer parent;
028 private final ComponentMonitor monitor;
029 private static NullLifecycleStrategy NO_LIFECYCLE = new NullLifecycleStrategy();
030 private static Properties NO_PROPERTIES = new Properties();
031
032 /**
033 * Make a reinjector with a parent container from which to pull components to be reinjected to.
034 * With this constructor, a NullComponentMonitor is used.
035 * @param parentContainer the parent container
036 */
037 public Reinjector(PicoContainer parentContainer) {
038 this(parentContainer, parentContainer instanceof ComponentMonitorStrategy
039 ? ((ComponentMonitorStrategy) parentContainer).currentMonitor()
040 : new NullComponentMonitor());
041 }
042
043 /**
044 * Make a reinjector with a parent container from which to pull components to be reinjected to
045 * @param parentContainer the parent container
046 * @param monitor the monitor to use for 'instantiating' events
047 */
048 public Reinjector(PicoContainer parentContainer, ComponentMonitor monitor) {
049 this.parent = parentContainer;
050 this.monitor = monitor;
051 }
052
053 /**
054 * Reinjecting into a method.
055 * @param key the component-key from the parent set of components to inject into
056 * @param reinjectionMethod the reflection method to use for injection.
057 * @return the result of the reinjection-method invocation.
058 */
059 public Object reinject(Class<?> key, Method reinjectionMethod) {
060 return reinject(key, key, parent.getComponent(key), NO_PROPERTIES, new MethodInjection(reinjectionMethod));
061 }
062
063 /**
064 * Reinjecting into a method.
065 * @param key the component-key from the parent set of components to inject into
066 * @param reinjectionMethodEnum the enum for the reflection method to use for injection.
067 * @return the result of the reinjection-method invocation.
068 */
069 public Object reinject(Class<?> key, Enum reinjectionMethodEnum) {
070 return reinject(key, key, parent.getComponent(key), NO_PROPERTIES, new MethodInjection(toMethod(reinjectionMethodEnum)));
071 }
072
073 private Method toMethod(final Enum reinjectionMethodEnum) {
074 Object methodOrException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
075 public Object run() {
076 try {
077 return reinjectionMethodEnum.getClass().getMethod("toMethod").invoke(reinjectionMethodEnum);
078 } catch (IllegalAccessException e) {
079 return new PicoCompositionException("Illegal access to " + reinjectionMethodEnum.name());
080 } catch (InvocationTargetException e) {
081 return new PicoCompositionException("Invocation Target Exception " + reinjectionMethodEnum.name(), e.getCause());
082 } catch (NoSuchMethodException e) {
083 return new PicoCompositionException("Expected generated method toMethod() on enum");
084 }
085 }
086 });
087 if (methodOrException instanceof Method) {
088 return (Method) methodOrException;
089 } else {
090 throw (PicoCompositionException) methodOrException;
091 }
092 }
093
094 /**
095 * Reinjecting into a method.
096 * @param key the component-key from the parent set of components to inject into (key and impl are the same)
097 * @param reinjectionFactory the InjectionFactory to use for reinjection.
098 * @return the result of the reinjection-method invocation.
099 */
100 public Object reinject(Class<?> key, InjectionFactory reinjectionFactory) {
101 Object o = reinject(key, key, parent.getComponent(key), NO_PROPERTIES, reinjectionFactory);
102 return o;
103 }
104
105 /**
106 * Reinjecting into a method.
107 * @param key the component-key from the parent set of components to inject into
108 * @param impl the implementation of the component that is going to result.
109 * @param reinjectionFactory the InjectionFactory to use for reinjection.
110 * @return
111 */
112 public Object reinject(Class<?> key, Class<?> impl, InjectionFactory reinjectionFactory) {
113 return reinject(key, impl, parent.getComponent(key), NO_PROPERTIES, reinjectionFactory);
114 }
115
116 /**
117 * Reinjecting into a method.
118 * @param key the component-key from the parent set of components to inject into
119 * @param implementation the implementation of the component that is going to result.
120 * @param instance the object that has the provider method to be invoked
121 * @param reinjectionFactory the InjectionFactory to use for reinjection.
122 * @return the result of the reinjection-method invocation.
123 */
124 public Object reinject(Class<?> key, Class implementation, Object instance, InjectionFactory reinjectionFactory) {
125 return reinject(key, implementation, instance, NO_PROPERTIES, reinjectionFactory);
126 }
127
128 /**
129 * Reinjecting into a method.
130 * @param key the component-key from the parent set of components to inject into
131 * @param implementation the implementation of the component that is going to result.
132 * @param instance the object that has the provider method to be invoked
133 * @param properties for reinjection
134 * @param reinjectionFactory the InjectionFactory to use for reinjection.
135 * @return the result of the reinjection-method invocation.
136 */
137 public Object reinject(Class<?> key, Class implementation, Object instance, Properties properties,
138 InjectionFactory reinjectionFactory) {
139 Reinjection reinjection = new Reinjection(reinjectionFactory, parent);
140 org.picocontainer.Injector injector = (org.picocontainer.Injector) reinjection.createComponentAdapter(
141 monitor, NO_LIFECYCLE, properties, key, implementation, null);
142 return injector.decorateComponentInstance(parent, null, instance);
143 }
144
145 }