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 }