001    /**
002     * 
003     */
004    package org.picocontainer.gems.adapters;
005    
006    import java.util.Properties;
007    
008    import org.picocontainer.ComponentAdapter;
009    import org.picocontainer.ComponentMonitor;
010    import org.picocontainer.LifecycleStrategy;
011    import org.picocontainer.Parameter;
012    import org.picocontainer.PicoCompositionException;
013    import org.picocontainer.gems.util.DelegateMethod;
014    import org.picocontainer.injectors.AbstractInjectionFactory;
015    
016    /**
017     * Mirrored AdaptorFactory for handling delegate methods.
018     * @author Michael Rimov
019     */
020    @SuppressWarnings("serial")
021    public 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    }