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 }