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