    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     * Original code by Centerline Computers, Inc.                               *
    009     *****************************************************************************/
    010    package org.picocontainer.gems.adapters;
    011
    012    import java.lang.reflect.Type;
    013
    014    import org.picocontainer.ComponentAdapter;
    015    import org.picocontainer.ComponentMonitor;
    016    import org.picocontainer.PicoCompositionException;
    017    import org.picocontainer.PicoContainer;
    018    import org.picocontainer.PicoVisitor;
    019    import org.picocontainer.gems.util.DelegateMethod;
    020
    021    /**
    022     * Object construction is sometimes expensive, especially when it is seldom used
    023     * object. The goal of this adapter is to use the
    024     * {@link org.picocontainer.gems.util.DelegateMethod} type to allow delayed
    025     * construction of objects.
    026     * <p>
    027     * For example, in a web application, to be able to have classes that depend on
    028     * the HttpSession object, you would have to call
    029     * HttpServletRequest.getSession(true). This is fine unless you don't want to
    030     * create a session until you absolutely have to.
    031     * </p>
    032     * <p>
    033     * Enter DelegateMethodAdapter:
    034     * </p>
    035     *
    036     * <pre>
    037     * //Assumed Variables: request == HttpServletRequest.
    038     * //Typical PicoContainer
    039     * MutablePicoContainer pico = new PicoBuilder().withLifecycle().withCaching()
    040     *              .build();
    041     *
    042     * //Create a delegate method that will invoke HttpServletRequest.getSession(true) when invoke() is called.
    043     * DelegateMethod delegateMethod = new DelegateMethod(HttpServletRequest.class,
    044     *              &quot;getSession&quot;, true);
    045     *
    046     * //Create the Adapter wrapping the delegate method.
    047     * DelegateMethodAdapter methodAdapter = new DelegateMethodAdapter(
    048     *              HttpSession.class, request, delegateMethod);
    049     * pico.addAdapter(methodAdapter);
    050     *
    051     * //If only executing this code, the HttpSession should not be created yet.
    052     * assertNull(request.getSession(false));
    053     *
    054     * //Will get the session object by having the delegate method call HttpServletRequest.getSession(true)
    055     * HttpSession session = pico.getComponent(HttpSession.class);
    056     * assertNotNull(session);
    057     *
    058     * //Should demonstrate that the session has now been created.
    059     * assertNotNull(request.getSession(false));
    060     * </pre>
    061     *
    062     * <p>
    063     * With an adapter like this, you can write classes like:
    064     * </p>
    065     *
    066     * <pre>
    067     * public class SessionUser {
    068     *      public SessionUser(HttpSession session) {
    069     *              //.....
    070     *      }
    071     * }
    072     * </pre>
    073     *
    074     * <p>
    075     * With impunity, and are guaranteed that the session would not be created
    076     * unless the SessionUser object was constructed.
    077     * </p>
    078     *
    079     * @author Michael Rimov
    080     */
    081    public class DelegateMethodAdapter<T> implements ComponentAdapter<T> {
    082
    083            /**
    084             * The delegate method instance that will ultimately invoke via reflection some method
    085             * on targetInstance.
    086             */
    087            private final DelegateMethod factoryMethod;
    088
    089            /**
    090             * The target instance on which the delegate method's invoke() call will operate.
    091             */
    092            private final Object targetInstance;
    093
    094            /**
    095             * Object key.
    096             */
    097            private final Object key;
    098
    099            /**
    100             * @param componentKey
    101             * @param Component
    102             *            Implementation will be the expected return type of the factory
    103             *            method.
    104             */
    105            public DelegateMethodAdapter(final Object componentKey,
    106                            final Object targetInstance, final DelegateMethod factoryMethod) {
    107                    this.factoryMethod = factoryMethod;
    108                    this.targetInstance = targetInstance;
    109                    this.key = componentKey;
    110            }
    111
    112            /**
    113             * @param componentKey
    114             * @param componentImplementation
    115             * @param monitor
    116             */
    117            public DelegateMethodAdapter(final Object componentKey,
    118                            final ComponentMonitor monitor, final Object targetInstance,
    119                            final DelegateMethod factoryMethod) {
    120                    this.factoryMethod = factoryMethod;
    121                    this.targetInstance = targetInstance;
    122                    this.key = componentKey;
    123            }
    124
    125            /**
    126             * Returns the
    127             */
    128            public T getComponentInstance(final PicoContainer container, final Type into)
    129                            throws PicoCompositionException {
    130                    try {
    131                            return (T) factoryMethod.invoke(targetInstance);
    132                    } catch (RuntimeException e) {
    133                            throw new PicoCompositionException(
    134                                            "Error invoking delegate for object construction", e);
    135                    }
    136            }
    137
    138            /**
    139             * {@inheritDoc}
    140             *
    141             * @see org.picocontainer.ComponentAdapter#getDescriptor()
    142             */
    143            public String getDescriptor() {
    144                    return "Delegate Adapter.  Delegate: " + this.factoryMethod.toString();
    145            }
    146
    147            /** {@inheritDoc} **/
    148            public void verify(final PicoContainer container)
    149                            throws PicoCompositionException {
    150                    // Currently does nothing.
    151            }
    152
    153            /** {@inheritDoc} **/
    154            public void accept(final PicoVisitor visitor) {
    155                    visitor.visitComponentAdapter(this);
    156            }
    157
    158            /** {@inheritDoc} **/
    159            public ComponentAdapter<T> findAdapterOfType(final Class adapterType) {
    160                    if (adapterType == null) {
    161                            return null;
    162                    }
    163
    164                    if (DelegateMethodAdapter.class.isAssignableFrom(adapterType)) {
    165                            return this;
    166                    }
    167
    168                    return null;
    169            }
    170
    171            /** {@inheritDoc} **/
    172            @SuppressWarnings("unchecked")
    173            public Class<T> getComponentImplementation() {
    174                    return this.factoryMethod.getReturnType();
    175            }
    176
    177            /** {@inheritDoc} **/
    178            @Deprecated
    179            public T getComponentInstance(final PicoContainer container)
    180                            throws PicoCompositionException {
    181                    return getComponentInstance(container, null);
    182            }
    183
    184            /** {@inheritDoc} **/
    185            public Object getComponentKey() {
    186                    return key;
    187            }
    188
    189            /**
    190             * No delegates.
    191             */
    192            public ComponentAdapter<T> getDelegate() {
    193                    return null;
    194            }
    195
    196    }