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.PicoContainer;
012    import org.picocontainer.ComponentMonitor;
013    import org.picocontainer.ComponentMonitorStrategy;
014    import org.picocontainer.InjectionFactory;
015    import org.picocontainer.lifecycle.NullLifecycleStrategy;
016    import org.picocontainer.monitors.NullComponentMonitor;
017    
018    import java.lang.reflect.Method;
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 (key and impl are the same)
066         * @param reinjectionFactory the InjectionFactory to use for reinjection.
067         * @return the result of the reinjection-method invocation.
068         */
069        public Object reinject(Class<?> key, InjectionFactory reinjectionFactory) {
070            Object o = reinject(key, key, parent.getComponent(key), NO_PROPERTIES, reinjectionFactory);
071            return o;
072        }
073    
074        /**
075         * Reinjecting into a method.
076         * @param key the component-key from the parent set of components to inject into
077         * @param implementation the implementation of the component that is going to result.
078         * @param reinjectionFactory the InjectionFactory to use for reinjection.
079         * @return
080         */
081        public Object reinject(Class<?> key, Class<?> impl, InjectionFactory reinjectionFactory) {
082            return reinject(key, impl, parent.getComponent(key), NO_PROPERTIES, reinjectionFactory);
083        }
084    
085        /**
086         * Reinjecting into a method.
087         * @param key the component-key from the parent set of components to inject into
088         * @param implementation the implementation of the component that is going to result.
089         * @param instance the object that has the provider method to be invoked
090         * @param reinjectionFactory the InjectionFactory to use for reinjection.
091         * @return the result of the reinjection-method invocation.
092         */
093        public Object reinject(Class<?> key, Class implementation, Object instance, InjectionFactory reinjectionFactory) {
094            return reinject(key, implementation, instance, NO_PROPERTIES, reinjectionFactory);
095        }
096    
097        /**
098         * Reinjecting into a method.
099         * @param key the component-key from the parent set of components to inject into
100         * @param implementation the implementation of the component that is going to result.
101         * @param instance the object that has the provider method to be invoked
102         * @param properties for reinjection
103         * @param reinjectionFactory the InjectionFactory to use for reinjection.
104         * @return the result of the reinjection-method invocation.
105         */
106        public Object reinject(Class<?> key, Class implementation, Object instance, Properties properties,
107                               InjectionFactory reinjectionFactory) {
108            Reinjection reinjection = new Reinjection(reinjectionFactory, parent);
109            org.picocontainer.Injector injector = (org.picocontainer.Injector) reinjection.createComponentAdapter(
110                    monitor, NO_LIFECYCLE, properties, key, implementation, null);
111            return injector.decorateComponentInstance(parent, null, instance);
112        }
113    
114    }