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 Joerg Schaible * 009 *****************************************************************************/ 010 011 package org.picocontainer.gems.adapters; 012 013 import com.thoughtworks.proxy.ProxyFactory; 014 import com.thoughtworks.proxy.factory.StandardProxyFactory; 015 016 import org.picocontainer.ComponentAdapter; 017 import org.picocontainer.Parameter; 018 import org.picocontainer.PicoIntrospectionException; 019 import org.picocontainer.defaults.AssignabilityRegistrationException; 020 import org.picocontainer.defaults.CachingComponentAdapter; 021 import org.picocontainer.defaults.ComponentAdapterFactory; 022 import org.picocontainer.defaults.DecoratingComponentAdapterFactory; 023 import org.picocontainer.defaults.NotConcreteRegistrationException; 024 025 026 /** 027 * A {@link ComponentAdapterFactory} for components kept in {@link ThreadLocal} instances. 028 * <p> 029 * This factory has two operating modes. By default it ensures, that every thread uses its own component at any time. 030 * This mode ({@link #ENSURE_THREAD_LOCALITY}) makes internal usage of a {@link ThreadLocalComponentAdapter}. If the 031 * application architecture ensures, that the thread that creates the component is always also the thread that is th 032 * only user, you can set the mode {@link #THREAD_ENSURES_LOCALITY}. In this mode the factory uses a simple 033 * {@link CachingComponentAdapter} that uses a {@link ThreadLocalReference} to cache the component. 034 * </p> 035 * <p> 036 * See the use cases for the subtile difference: 037 * </p> 038 * <p> 039 * <code>THREAD_ENSURES_LOCALITY</code> is applicable, if the pico container is requested for a thread local component 040 * from the working thread e.g. in a web application for a request. In this environment it is ensured, that the request 041 * is processed from the same thread and the thread local component is reused, if a previous request was handled in the 042 * same thread. Note that thi scenario fails badly, if the thread local component is created because of another cached 043 * component indirectly by a dependecy. In this case the cached component already have an instance of the thread local 044 * component, that may have been created in another thread, since only the component adapter for the thread local 045 * component can ensure a unique component for each thread. 046 * </p> 047 * <p> 048 * <code>ENSURES_THREAD_LOCALITY</code> solves this problem. In this case the returned component is just a proxy for 049 * the thread local component and this proxy ensures, that a new component is created for each thread. Even if another 050 * cached component has an indirect dependency on the thread local component, the proxy ensures unique instances. This 051 * is vital for a multithreaded application that uses EJBs. 052 * </p> 053 * @author Jörg Schaible 054 */ 055 public class ThreadLocalComponentAdapterFactory extends DecoratingComponentAdapterFactory { 056 057 /** 058 * <code>ENSURE_THREAD_LOCALITY</code> is the constant for created {@link ComponentAdapter} instances, that ensure 059 * unique instances of the component by delivering a proxy for the component. 060 */ 061 public static final boolean ENSURE_THREAD_LOCALITY = true; 062 /** 063 * <code>THREAD_ENSURES_LOCALITY</code> is the constant for created {@link ComponentAdapter} instances, that 064 * create for the current thread a new component. 065 */ 066 public static final boolean THREAD_ENSURES_LOCALITY = false; 067 068 private final boolean ensureThreadLocal; 069 private ProxyFactory proxyFactory; 070 071 /** 072 * Constructs a wrapping ThreadLocalComponentAdapterFactory, that ensures the usage of the ThreadLocal. The Proxy 073 * instances are generated by the JDK. 074 * @param delegate The delegated {@link ComponentAdapterFactory}. 075 */ 076 public ThreadLocalComponentAdapterFactory(final ComponentAdapterFactory delegate) { 077 this(delegate, new StandardProxyFactory()); 078 } 079 080 /** 081 * Constructs a wrapping ThreadLocalComponentAdapterFactory, that ensures the usage of the ThreadLocal. 082 * @param delegate The delegated ComponentAdapterFactory. 083 * @param proxyFactory The {@link ProxyFactory} to use. 084 */ 085 public ThreadLocalComponentAdapterFactory(final ComponentAdapterFactory delegate, final ProxyFactory proxyFactory) { 086 this(delegate, ENSURE_THREAD_LOCALITY, proxyFactory); 087 } 088 089 /** 090 * Constructs a wrapping ThreadLocalComponentAdapterFactory. 091 * @param delegate The delegated ComponentAdapterFactory. 092 * @param ensure {@link #ENSURE_THREAD_LOCALITY} or {@link #THREAD_ENSURES_LOCALITY}. 093 */ 094 public ThreadLocalComponentAdapterFactory(final ComponentAdapterFactory delegate, final boolean ensure) { 095 this(delegate, ensure, new StandardProxyFactory()); 096 } 097 098 /** 099 * Constructs a wrapping ThreadLocalComponentAdapterFactory. 100 * @param delegate The delegated ComponentAdapterFactory. 101 * @param ensure {@link #ENSURE_THREAD_LOCALITY} or {@link #THREAD_ENSURES_LOCALITY}. 102 * @param factory The {@link ProxyFactory} to use. 103 */ 104 protected ThreadLocalComponentAdapterFactory( 105 final ComponentAdapterFactory delegate, final boolean ensure, final ProxyFactory factory) { 106 super(delegate); 107 ensureThreadLocal = ensure; 108 proxyFactory = factory; 109 } 110 111 public ComponentAdapter createComponentAdapter( 112 Object componentKey, Class componentImplementation, Parameter[] parameters) 113 throws PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException { 114 final ComponentAdapter componentAdapter; 115 if (ensureThreadLocal) { 116 componentAdapter = new ThreadLocalComponentAdapter(super.createComponentAdapter( 117 componentKey, componentImplementation, parameters), proxyFactory); 118 } else { 119 componentAdapter = new CachingComponentAdapter(super.createComponentAdapter( 120 componentKey, componentImplementation, parameters), new ThreadLocalReference()); 121 } 122 return componentAdapter; 123 } 124 125 }