001/**
002 * 
003 */
004package org.picocontainer.gems.adapters;
005
006import java.util.Properties;
007
008import org.picocontainer.ComponentAdapter;
009import org.picocontainer.ComponentMonitor;
010import org.picocontainer.LifecycleStrategy;
011import org.picocontainer.Parameter;
012import org.picocontainer.PicoCompositionException;
013import org.picocontainer.gems.util.DelegateMethod;
014import org.picocontainer.injectors.AbstractInjectionFactory;
015
016/**
017 * Mirrored AdaptorFactory for handling delegate methods.
018 * @author Michael Rimov
019 */
020@SuppressWarnings("serial")
021public class DelegateAdaptorFactory extends AbstractInjectionFactory {
022
023    
024        /**
025         * DelegateMethod instance key.
026         */
027    private static final String DELEGATE = "delegateInstance";
028    
029    
030    /**
031     * Delegate target instance key.
032     */
033    private static final String INSTANCE = "targetInstance";
034    
035        /**
036         * Default constructor.
037         */
038        public DelegateAdaptorFactory() {
039                super();
040        }
041
042
043        /**
044         * {@inheritDoc}
045         * 
046         */
047        public <T> ComponentAdapter<T> createComponentAdapter(
048                        final ComponentMonitor componentMonitor,
049                        final LifecycleStrategy lifecycleStrategy,
050                        final Properties componentProperties, final Object componentKey,
051                        final Class<T> componentImplementation, final Parameter... parameters)
052                        throws PicoCompositionException {
053                
054                DelegateMethod<?, T> method =  cast(componentProperties.remove(DELEGATE));
055                
056                //TODO: what to do since if there is no method, the delegate adapter won't work.
057                if (method == null) {
058                        throw new IllegalArgumentException("Component properties must have a "
059                                        +"org.picocontainer.gems.util.DelegateMethod object stored as delegateInstance");
060                }
061
062                Object instance = componentProperties.remove(INSTANCE);
063                if (instance == null) {
064                        throw new IllegalArgumentException("Property 'instance' must exist.");
065                }
066
067                
068
069                return new DelegateMethodAdapter<T>(componentKey, componentMonitor, instance, method);
070        }
071
072
073        /**
074         * Takes care of generic warnings.
075         * @param <T>
076         * @param source
077         * @return an appropriately cast object.
078         */
079        @SuppressWarnings("unchecked")
080        private <T> T cast(final Object source) {
081                return (T) source;
082        }
083
084        /**
085         * Use this static factory method as a way of creating all the necessary properties that are required by the adapter.
086         * <p>Example:</p>
087         * <pre>
088         *              DelegateAdapterFactory factory = new DelegateAdapterFactory();
089         *              HttpServletRequest request = .....;
090         * 
091         *      //When object is instantiated will lazily call:   request.getSession(false);
092         *              Properties props = createDelegateProperties(request, &quot;getSession&quot;, false);
093         * 
094         *              DelegateMethodAdapter adapter = createComponentAdapter(new ConsoleComponentMonitor(), new DefaultLifecycleStrategy(),
095         *                               props, HttpSession.class, HttpSession.class);
096         * </pre>
097         * @param targetObject the object to be operated on.
098         * @param methodName the name of the method to invoke.
099         * @param parameters the parameters to supply upon invocation. (Also used to find matching argument).
100         * @return the appropriate properties that can be used with createComponentAdapter().
101         */
102        public static Properties createDelegateProprties(final Object targetObject, final String methodName, final Object... parameters) {
103                Properties props = new Properties();
104                props.put(INSTANCE, targetObject);
105                props.put(DELEGATE, createDelegate(targetObject.getClass(), methodName, parameters));
106                
107                return props;
108        }
109        
110        /**
111         * Generic-friendly instantiation.  If you have control of your own code, you can also just use the DelegateMethod constructors.
112         * @param <INSTANCE>
113         * @param <RETURN_TYPE>
114         * @param targetType the type of object being instantiated.
115         * @param methodName the method name to invoke when called.
116         * @param parameters the method paramters to use.
117         * @return DelegateMethod instance.
118         */
119        public static <INSTANCE,RETURN_TYPE> DelegateMethod<INSTANCE, RETURN_TYPE> createDelegate(final Class<INSTANCE> targetType, final String methodName, final Object... parameters) {
120                return new DelegateMethod<INSTANCE,RETURN_TYPE>(targetType, methodName, parameters);
121        }
122}