From f07884740605cfc19ccb411cb65224792c9185bb Mon Sep 17 00:00:00 2001 From: erik Date: Wed, 21 Jul 2010 12:12:04 +0000 Subject: [PATCH] Now the thread-specific proxies are serializable. --- .../general/ThreadSpecificProxyFactory.java | 40 +++++++++++++++++-- .../ThreadSpecificProxyFactoryTest.java | 5 +++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/support/general/src/main/java/org/wamblee/general/ThreadSpecificProxyFactory.java b/support/general/src/main/java/org/wamblee/general/ThreadSpecificProxyFactory.java index a5a1cebb..036a6828 100644 --- a/support/general/src/main/java/org/wamblee/general/ThreadSpecificProxyFactory.java +++ b/support/general/src/main/java/org/wamblee/general/ThreadSpecificProxyFactory.java @@ -15,10 +15,14 @@ */ package org.wamblee.general; +import java.io.Serializable; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; /** * Thread-specific proxy is used to create implementations of interfaces that @@ -41,13 +45,36 @@ import java.lang.reflect.Proxy; * */ public class ThreadSpecificProxyFactory { - private class ThreadSpecificInvocationHandler implements InvocationHandler { + + /** + * We store a map of unique ids of invocation handlers to thread local storage of the + * service. In this way, serialiability of the generated proxy is obtained (required by + * framweorks such as wicket). Also, different factories will still be separate and never + * use the same threadlocal storage. + */ + private static Map STORAGE = + initializeThreadLocal(); + + private static class ThreadSpecificInvocationHandler implements InvocationHandler, Serializable { + + private String id; + private Class clazz; + + public ThreadSpecificInvocationHandler(String aId, Class aClass) { + id = aId; + clazz = aClass; + } @Override public Object invoke(Object aProxy, Method aMethod, Object[] aArgs) throws Throwable { + ThreadLocal local = STORAGE.get(id); + T actualSvc = local.get(); + if ( aMethod.getName().equals("toString") && actualSvc == null) { + return "Thread-specific proxy for '" + clazz.getName() + "'"; + } try { - return aMethod.invoke(svc.get(), aArgs); + return aMethod.invoke(actualSvc, aArgs); } catch (InvocationTargetException e) { throw e.getCause(); } @@ -74,6 +101,11 @@ public class ThreadSpecificProxyFactory { proxy = createProxy(); } + private static Map initializeThreadLocal() { + Map map = new HashMap(); + return map; + } + /** * Sets the thread-specific service. * @@ -105,7 +137,9 @@ public class ThreadSpecificProxyFactory { } private T createProxy() { - InvocationHandler handler = new ThreadSpecificInvocationHandler(); + String id = UUID.randomUUID().toString(); + STORAGE.put(id, svc); + InvocationHandler handler = new ThreadSpecificInvocationHandler(id, clazz); Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(), new Class[] { clazz }); T proxyObj; diff --git a/support/general/src/test/java/org/wamblee/general/ThreadSpecificProxyFactoryTest.java b/support/general/src/test/java/org/wamblee/general/ThreadSpecificProxyFactoryTest.java index 310e47a7..9b52817e 100644 --- a/support/general/src/test/java/org/wamblee/general/ThreadSpecificProxyFactoryTest.java +++ b/support/general/src/test/java/org/wamblee/general/ThreadSpecificProxyFactoryTest.java @@ -104,4 +104,9 @@ public class ThreadSpecificProxyFactoryTest { public void testNotAnInterface() { ThreadSpecificProxyFactory f = new ThreadSpecificProxyFactory(String.class); } + + @Test + public void testProxyToStringWhileUninitialized() { + String val = proxy.toString(); + } } -- 2.31.1