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: *****************************************************************************/package org.picocontainer.gems.adapters;
010:
011: import com.thoughtworks.proxy.ProxyFactory;
012: import com.thoughtworks.proxy.factory.StandardProxyFactory;
013:
014: import org.picocontainer.ComponentAdapter;
015: import org.picocontainer.Parameter;
016: import org.picocontainer.PicoCompositionException;
017: import org.picocontainer.ComponentMonitor;
018: import org.picocontainer.behaviors.Cached;
019: import org.picocontainer.behaviors.AbstractBehaviorFactory;
020: import org.picocontainer.ComponentFactory;
021: import org.picocontainer.LifecycleStrategy;
022: import org.picocontainer.references.ThreadLocalReference;
023:
024: import java.util.Properties;
025:
026: /**
027: * A {@link ComponentFactory} 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 ThreadLocalized}. 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 Cached} 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 addComponent
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 final class ThreadLocalizing extends AbstractBehaviorFactory {
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 final ProxyFactory proxyFactory;
070:
071: /**
072: * Constructs a wrapping ThreadLocalizing, that ensures the usage of the ThreadLocal. The Proxy
073: * instances are generated by the JDK.
074: */
075: public ThreadLocalizing() {
076: this (new StandardProxyFactory());
077: }
078:
079: /**
080: * Constructs a wrapping ThreadLocalizing, that ensures the usage of the ThreadLocal.
081: * @param proxyFactory The {@link ProxyFactory} to use.
082: */
083: public ThreadLocalizing(final ProxyFactory proxyFactory) {
084: this (ENSURE_THREAD_LOCALITY, proxyFactory);
085: }
086:
087: /**
088: * Constructs a wrapping ThreadLocalizing.
089: * @param ensure {@link #ENSURE_THREAD_LOCALITY} or {@link #THREAD_ENSURES_LOCALITY}.
090: */
091: public ThreadLocalizing(final boolean ensure) {
092: this (ensure, new StandardProxyFactory());
093: }
094:
095: /**
096: * Constructs a wrapping ThreadLocalizing.
097: * @param ensure {@link #ENSURE_THREAD_LOCALITY} or {@link #THREAD_ENSURES_LOCALITY}.
098: * @param factory The {@link ProxyFactory} to use.
099: */
100: protected ThreadLocalizing(final boolean ensure,
101: final ProxyFactory factory) {
102: ensureThreadLocal = ensure;
103: proxyFactory = factory;
104: }
105:
106: public ComponentAdapter createComponentAdapter(
107: ComponentMonitor componentMonitor,
108: LifecycleStrategy lifecycleStrategy,
109: Properties componentProperties, Object componentKey,
110: Class componentImplementation, Parameter... parameters)
111: throws PicoCompositionException {
112: final ComponentAdapter componentAdapter;
113: if (ensureThreadLocal) {
114: componentAdapter = new ThreadLocalized(super
115: .createComponentAdapter(componentMonitor,
116: lifecycleStrategy, componentProperties,
117: componentKey, componentImplementation,
118: parameters), proxyFactory);
119: } else {
120: componentAdapter = new Cached(super .createComponentAdapter(
121: componentMonitor, lifecycleStrategy,
122: componentProperties, componentKey,
123: componentImplementation, parameters),
124: new ThreadLocalReference());
125: }
126: return componentAdapter;
127: }
128:
129: public ComponentAdapter addComponentAdapter(
130: ComponentMonitor componentMonitor,
131: LifecycleStrategy lifecycleStrategy,
132: Properties componentProperties, ComponentAdapter adapter) {
133: if (ensureThreadLocal) {
134: return new ThreadLocalized(super .addComponentAdapter(
135: componentMonitor, lifecycleStrategy,
136: componentProperties, adapter), proxyFactory);
137: } else {
138: return new Cached(super .addComponentAdapter(
139: componentMonitor, lifecycleStrategy,
140: componentProperties, adapter),
141: new ThreadLocalReference());
142: }
143:
144: }
145: }
|