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.Invoker;
012: import com.thoughtworks.proxy.ProxyFactory;
013: import com.thoughtworks.proxy.factory.StandardProxyFactory;
014: import com.thoughtworks.proxy.kit.ReflectionUtils;
015:
016: import org.picocontainer.ComponentAdapter;
017: import org.picocontainer.PicoContainer;
018: import org.picocontainer.PicoCompositionException;
019: import org.picocontainer.references.ThreadLocalReference;
020: import org.picocontainer.behaviors.Cached;
021: import org.picocontainer.behaviors.AbstractBehavior;
022:
023: import java.lang.reflect.InvocationTargetException;
024: import java.lang.reflect.Method;
025: import java.lang.reflect.Proxy;
026: import java.util.Set;
027:
028: /**
029: * A {@link ComponentAdapter} that realizes a {@link ThreadLocal} component instance.
030: * <p>
031: * The adapter creates proxy instances, that will create the necessary instances on-the-fly invoking the methods of the
032: * instance. Use this adapter, if you are instantiating your components in a single thread, but should be different when
033: * accessed from different threads. See {@link ThreadLocalizing} for details.
034: * </p>
035: * <p>
036: * Note: Because this implementation uses a {@link Proxy}, you can only access the methods exposed by the implemented
037: * interfaces of your component.
038: * </p>
039: *
040: * @author Jörg Schaible
041: */
042: public final class ThreadLocalized extends AbstractBehavior {
043:
044: private transient Class[] interfaces;
045: private final ProxyFactory proxyFactory;
046:
047: /**
048: * Construct a ThreadLocalized.
049: *
050: * @param delegate The {@link ComponentAdapter} to delegate.
051: * @param proxyFactory The {@link ProxyFactory} to use.
052: * @throws PicoCompositionException Thrown if the component does not implement any interface.
053: */
054: public ThreadLocalized(final ComponentAdapter delegate,
055: final ProxyFactory proxyFactory)
056: throws PicoCompositionException {
057: super (new Cached(delegate, new ThreadLocalReference()));
058: this .proxyFactory = proxyFactory;
059: interfaces = getInterfaces();
060: }
061:
062: /**
063: * Construct a ThreadLocalized using {@link Proxy} instances.
064: *
065: * @param delegate The {@link ComponentAdapter} to delegate.
066: * @throws PicoCompositionException Thrown if the component does not implement any interface.
067: */
068: public ThreadLocalized(final ComponentAdapter delegate)
069: throws PicoCompositionException {
070: this (new Cached(delegate, new ThreadLocalReference()),
071: new StandardProxyFactory());
072: }
073:
074: public Object getComponentInstance(final PicoContainer pico)
075: throws PicoCompositionException {
076:
077: if (interfaces == null) {
078: interfaces = getInterfaces();
079: }
080:
081: final Invoker invoker = new ThreadLocalInvoker(pico,
082: getDelegate());
083: return proxyFactory.createProxy(interfaces, invoker);
084: }
085:
086: private Class[] getInterfaces() {
087: final Object componentKey = getComponentKey();
088: final Class[] interfaces;
089: if (componentKey instanceof Class
090: && ((Class) componentKey).isInterface()) {
091: interfaces = new Class[] { (Class) componentKey };
092: } else {
093: final Set allInterfaces = ReflectionUtils
094: .getAllInterfaces(getComponentImplementation());
095: interfaces = (Class[]) allInterfaces
096: .toArray(new Class[allInterfaces.size()]);
097: }
098: if (interfaces.length == 0) {
099: throw new PicoCompositionException(
100: "Can't proxy implementation for "
101: + getComponentImplementation().getName()
102: + ". It does not implement any interfaces.");
103: }
104: return interfaces;
105: }
106:
107: public String getDescriptor() {
108: return "ThreadLocal";
109: }
110:
111: final static private class ThreadLocalInvoker implements Invoker {
112:
113: private final PicoContainer pico;
114: private final ComponentAdapter delegate;
115:
116: private ThreadLocalInvoker(final PicoContainer pico,
117: final ComponentAdapter delegate) {
118: this .pico = pico;
119: this .delegate = delegate;
120: }
121:
122: public Object invoke(final Object proxy, final Method method,
123: final Object[] args) throws Throwable {
124: final Object delegatedInstance = delegate
125: .getComponentInstance(pico);
126: if (method.equals(ReflectionUtils.equals)) { // necessary for JDK 1.3
127: return args[0] != null
128: && args[0].equals(delegatedInstance);
129: } else {
130: try {
131: return method.invoke(delegatedInstance, args);
132: } catch (final InvocationTargetException e) {
133: throw e.getTargetException();
134: }
135: }
136: }
137: }
138: }
|