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 * "getSession", 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 }