(no commit message)
authorerik <erik@77661180-640e-0410-b3a8-9f9b13e6d0e0>
Thu, 22 Jul 2010 08:47:42 +0000 (08:47 +0000)
committererik <erik@77661180-640e-0410-b3a8-9f9b13e6d0e0>
Thu, 22 Jul 2010 08:47:42 +0000 (08:47 +0000)
support/general/src/main/java/org/wamblee/general/ThreadSpecificInvocationHandler.java [new file with mode: 0644]
support/general/src/main/java/org/wamblee/general/ThreadSpecificProxyFactory.java
support/general/src/main/java/org/wamblee/reflection/AnnotationUtils.java

diff --git a/support/general/src/main/java/org/wamblee/general/ThreadSpecificInvocationHandler.java b/support/general/src/main/java/org/wamblee/general/ThreadSpecificInvocationHandler.java
new file mode 100644 (file)
index 0000000..49c2e17
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Invocation handler for thread-specific proxies. 
+ * 
+ * @author Erik Brakkee
+ *
+ * @param <T>
+ */
+class ThreadSpecificInvocationHandler<T> implements InvocationHandler, Serializable {
+    
+    /**
+     * 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<Integer,ThreadLocal> STORAGE = initializeThreadLocal();
+    
+    private static AtomicInteger COUNTER = new AtomicInteger();
+    
+    private static Map<Integer, ThreadLocal> initializeThreadLocal() {
+        Map<Integer,ThreadLocal> map = new ConcurrentHashMap<Integer,ThreadLocal>();
+        return map;
+    }
+
+    
+    private int id; 
+    private Class clazz; 
+    
+    /**
+     * Constructs the handler. 
+     * @param aSvc Thread local for the service. 
+     * @param aClass Service interface class. 
+     */
+    public ThreadSpecificInvocationHandler(ThreadLocal aSvc, Class aClass) { 
+        id = COUNTER.incrementAndGet();
+        clazz = aClass;
+        STORAGE.put(id, aSvc);
+    }
+
+    @Override
+    public Object invoke(Object aProxy, Method aMethod, Object[] aArgs)
+        throws Throwable {
+
+        ThreadLocal<T> local = STORAGE.get(id);
+        T actualSvc = local.get();
+        if ( aMethod.getName().equals("toString") && actualSvc == null) { 
+            return "Thread-specific proxy for '" + clazz.getName() + "' id = " + id;
+        }
+        try {
+            return aMethod.invoke(actualSvc, aArgs);
+        } catch (InvocationTargetException e) {
+            throw e.getCause();
+        }
+    }
+}
\ No newline at end of file
index 036a6828648b2cd25153d8ecb6edcd8c517b7e73..e3b687df15777ac1fd07003c9d04ed272b925d66 100644 (file)
  */
 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
@@ -39,48 +33,18 @@ import java.util.UUID;
  * 
  * This class is mostly used by infrastructure code (utilities) and test tools.
  * 
+ * Care has been taken so that the invocation handler is serializable.
+ * However, it is only serializable within one virtual machine. It cannot be used in a distributed context
+ * where it can be sent to another JVM. 
+ * 
  * @param T
  *            Interface to proxy.
  * @author Erik Brakkee
  * 
  */
 public class ThreadSpecificProxyFactory<T> {
+   
     
-    /**
-     * 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<String,ThreadLocal> STORAGE = 
-        initializeThreadLocal();
-    
-    private static class ThreadSpecificInvocationHandler<T> 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<T> 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(actualSvc, aArgs);
-            } catch (InvocationTargetException e) {
-                throw e.getCause();
-            }
-        }
-    }
-
     private ThreadLocal<T> svc;
     private Class clazz;
     private T proxy; 
@@ -99,11 +63,7 @@ public class ThreadSpecificProxyFactory<T> {
         svc = new ThreadLocal<T>();
         clazz = aClass;
         proxy = createProxy(); 
-    }
-
-    private static Map<String, ThreadLocal> initializeThreadLocal() {
-        Map<String,ThreadLocal> map = new HashMap<String,ThreadLocal>();
-        return map;
+        
     }
 
     /**
@@ -137,9 +97,7 @@ public class ThreadSpecificProxyFactory<T> {
     }
 
     private T createProxy() {
-        String id = UUID.randomUUID().toString();
-        STORAGE.put(id, svc);
-        InvocationHandler handler = new ThreadSpecificInvocationHandler(id, clazz);
+        InvocationHandler handler = new ThreadSpecificInvocationHandler(svc, clazz);
         Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(),
             new Class[] { clazz });
         T proxyObj;
index 5ea776b3217dac607e939adcfcc49025c2eeb8df..dad07b5ffae13621a1e74f3be347528d15d52b98 100644 (file)
@@ -38,7 +38,6 @@ public class AnnotationUtils {
      *            Annotation that must be present.
      * @return List of accessors. Empty list is returned if no match is found. 
      */
-    // TODO move generic analysis part to the reflection package.
     public static List<Accessor> analyse(Class aClass,
         Class<? extends Annotation> aAnnotation) {
         List<Accessor> result = new ArrayList<Accessor>();