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    }