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 }