    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    }