2 * Copyright 2005-2010 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.wamblee.general;
18 import java.lang.reflect.InvocationHandler;
19 import java.lang.reflect.Proxy;
23 * Thread-specific proxy is used to create implementations of interfaces that
24 * delegate to a thread-specific implementation of the service.
28 * It can be used for instance to create a contextual reference to an entity
29 * manager that delegates to a thread-specific instance.
33 * The {@link #set(Object)} method sets the current service instance for the
34 * current thread. The {@link #get()} method gets the current service instance
35 * for the current thread. The {@link #getProxy()} method gets a proxy that will
36 * delegate at runtime to the thread-specific instance. The result from this
37 * method can be passed at construction of an object that will be used by
42 * This class is mostly used by infrastructure code (utilities) and test tools.
46 * Care has been taken so that the invocation handler is serializable. However,
47 * it is only serializable within one virtual machine. It cannot be used in a
48 * distributed context where it can be sent to another JVM.
52 * This class currently does not do any cleanup. So it should not be used in production code
53 * but only in test utilities.
58 * @author Erik Brakkee
61 public class ThreadSpecificProxyFactory<T> {
64 * Optional callback invoked to create the thread-specific object when there
65 * is no object yet associated with the current thread.
67 * @author Erik Brakkee
70 public static interface CreationCallback<T> {
79 private ThreadLocal<T> svc;
84 * Constructs the factory.
87 * Interface class of the service to proxy.
89 public ThreadSpecificProxyFactory(Class<T> aClass) {
94 * Constructs the factory with a callback to create thread-specific objects
98 * Interface class of the service to proxy.
100 * Callback to create the object if it does not exist. When null,
101 * then no initialization is done.
103 public ThreadSpecificProxyFactory(Class<T> aClass,
104 final CreationCallback<T> aCallback) {
105 if (!aClass.isInterface()) {
106 throw new IllegalArgumentException("Class " + aClass.getName() +
107 " is not an interface");
109 svc = new ThreadLocal<T>() {
111 protected T initialValue() {
112 if (aCallback != null) {
113 return aCallback.create();
119 proxy = createProxy();
124 * Sets the thread-specific service.
127 * Service, use null value to reset.
129 public void set(T aService) {
134 * Gets the current thread-specific service. To get a contextual reference
135 * that can be used by any thread but delegates to a thread-specific
136 * instance, use {@link #getProxy()}.
145 * Gets the proxy that delegates to the thread-specific instance set by
146 * {@link #set(Object)}
150 public T getProxy() {
154 private T createProxy() {
155 InvocationHandler handler = new ThreadSpecificInvocationHandler(svc,
157 Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(),
158 new Class[] { clazz });
161 proxyObj = (T) proxyClass.getConstructor(
162 new Class[] { InvocationHandler.class }).newInstance(
163 new Object[] { handler });
165 } catch (Exception e) {
166 throw new RuntimeException("Could not create proxy for " +