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 }