code style improvements.
[utils] / test / enterprise / src / main / java / org / wamblee / test / jndi / JndiProxyFactory.java
1 /*
2  * Copyright 2005-2010 the original author or authors.
3  * 
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
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
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.
15  */
16 package org.wamblee.test.jndi;
17
18 import java.lang.reflect.InvocationHandler;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.lang.reflect.Proxy;
22
23 import javax.naming.InitialContext;
24 import javax.naming.NamingException;
25
26 /**
27  * Proxy factory that can provide contextual references to objects retrieved
28  * from JNDI.
29  * 
30  * NOTE: This class is probably better suited as a production class, not a test support class. 
31  * It needs to find a new home in a Java EE production utilities library. 
32  * 
33  * @param T
34  *            Interface to proxy.
35  * @author Erik Brakkee
36  * 
37  */
38 public class JndiProxyFactory<T> {
39     /**
40      * Exception thrown in case an object cannot be retrieved from JNDI. 
41      * 
42      * @author Erik Brakkee
43      */
44     public static class JndiWiringException extends RuntimeException {
45         public JndiWiringException(String aMsg, Throwable aCause) {
46             super(aMsg, aCause);
47         }
48
49         public JndiWiringException(String aMsg) {
50             super(aMsg);
51         }
52     }
53
54     /**
55      * Invocation handler that does a lookup in JNDI and invokes the method on the 
56      * object it found. 
57      * 
58      * @author Erik Brakkee
59      */
60     private class JndiInvocationHandler implements InvocationHandler {
61
62         @Override
63         /**
64          * @throws JndiWiringException in case the object could not be retrieved from JNDI. 
65          */
66         public Object invoke(Object aProxy, Method aMethod, Object[] aArgs)
67             throws Throwable {
68             Object svcObj = null;
69             try {
70                 InitialContext ctx = new InitialContext();
71                 svcObj = ctx.lookup(jndi);
72             } catch (NamingException e) {
73                 throw new JndiWiringException(
74                     "Error looking up object in JNDI at '" + jndi + "'", e);
75             }
76             if (svcObj == null) {
77                 throw new JndiWiringException("Object at '" + jndi +
78                     "' is null");
79             }
80             if (!clazz.isInstance(svcObj)) {
81                 throw new JndiWiringException("Object in JNDI tree at '" +
82                     jndi + "' not of type " + clazz.getName() +
83                     " but of type " + svcObj.getClass().getName());
84             }
85             T svc = (T) svcObj;
86             try {
87                 return aMethod.invoke(svc, aArgs);
88             } catch (InvocationTargetException e) {
89                 throw e.getCause();
90             }
91         }
92     }
93
94     private String jndi;
95     private Class clazz;
96
97     /**
98      * Constructs the factory.
99      * 
100      * @param aClass
101      *            Interface class of the service to proxy.
102      * @param aJndi JNDI name of the object to lookup. 
103      * 
104      */
105     public JndiProxyFactory(Class<T> aClass, String aJndi) {
106         if (!aClass.isInterface()) {
107             throw new IllegalArgumentException("Class " + aClass.getName() +
108                 " is not an interface");
109         }
110         clazz = aClass;
111         jndi = aJndi; 
112     }
113
114     /**
115      * Gets the proxy that delegates to the thread-specific instance set by
116      * {@link #set(Object)}
117      * 
118      * When at runtime the proxy cannot find lookup the object in JNDI, it 
119      * throws {@link JndiWiringException}. 
120      * 
121      * @return Proxy.
122      */
123     public T getProxy() {
124         InvocationHandler handler = new JndiInvocationHandler();
125         Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(),
126             new Class[] { clazz });
127         T proxy;
128         try {
129             proxy = (T) proxyClass.getConstructor(
130                 new Class[] { InvocationHandler.class }).newInstance(
131                 new Object[] { handler });
132             return proxy;
133         } catch (Exception e) {
134             throw new RuntimeException("Could not create proxy for " +
135                 clazz.getName(), e);
136         }
137     }
138 }