    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&ouml;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    }