From 2367974fc98e6e1775b28958817a0d8ec981b0b8 Mon Sep 17 00:00:00 2001 From: Erik Brakkee Date: Fri, 30 Jul 2010 18:47:05 +0000 Subject: [PATCH] --- .../wamblee/general/LookupProxyFactory.java | 147 ++++++++++++++++++ .../general/LookupProxyFactoryTest.java | 97 ++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 support/general/src/main/java/org/wamblee/general/LookupProxyFactory.java create mode 100644 support/general/src/test/java/org/wamblee/general/LookupProxyFactoryTest.java diff --git a/support/general/src/main/java/org/wamblee/general/LookupProxyFactory.java b/support/general/src/main/java/org/wamblee/general/LookupProxyFactory.java new file mode 100644 index 00000000..53151862 --- /dev/null +++ b/support/general/src/main/java/org/wamblee/general/LookupProxyFactory.java @@ -0,0 +1,147 @@ +/* + * 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.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * Proxy factory that can provide contextual references to objects retrieved + * through a lookup mechanism. + * + * @param T + * Interface to proxy. + * @author Erik Brakkee + * + */ +public class LookupProxyFactory { + + /** + * Interface to lookup the object to delegate to. + * + * @author Erik Brakkee + */ + public static interface Lookup { + /** + * Looks up the object. + * @return Object (non-null) + * @throws Any exception in case the object cannot be found. + */ + Object lookup() throws Exception; + } + + /** + * Exception thrown in case an object cannot be retrieved from JNDI. + * + * @author Erik Brakkee + */ + public static class LookupException extends RuntimeException { + public LookupException(String aMsg, Throwable aCause) { + super(aMsg, aCause); + } + + public LookupException(String aMsg) { + super(aMsg); + } + } + + /** + * Invocation handler that does a lookup in JNDI and invokes the method on the + * object it found. + * + * @author Erik Brakkee + */ + private class LookupInvocationHandler implements InvocationHandler { + + @Override + /** + * @throws JndiWiringException in case the object could not be retrieved from JNDI. + */ + public Object invoke(Object aProxy, Method aMethod, Object[] aArgs) + throws Throwable { + Object svcObj = null; + try { + svcObj = lookup.lookup(); + } catch (Exception e) { + throw new LookupException( + "Error looking up object", e); + } + if (svcObj == null) { + throw new LookupException("Object at is null"); + } + if (!clazz.isInstance(svcObj)) { + throw new LookupException("Object '" + svcObj + "' is not of type " + clazz.getName() + + " but of type " + svcObj.getClass().getName()); + } + T svc = (T) svcObj; + try { + return aMethod.invoke(svc, aArgs); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + } + } + + private Lookup lookup; + private Class clazz; + + /** + * Constructs the factory. + * + * @param aClass + * Interface class of the service to proxy. + * @param aJndi JNDI name of the object to lookup. + * + */ + public LookupProxyFactory(Class aClass, Lookup aLookup) { + if (!aClass.isInterface()) { + throw new IllegalArgumentException("Class " + aClass.getName() + + " is not an interface"); + } + clazz = aClass; + lookup = aLookup; + } + + /** + * Gets the proxy that delegates to the thread-specific instance set by + * {@link #set(Object)} + * + * When at runtime the proxy cannot find lookup the object in JNDI, it + * throws {@link LookupException}. + * + * @return Proxy. + */ + public T getProxy() { + InvocationHandler handler = new LookupInvocationHandler(); + Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(), + new Class[] { clazz }); + T proxy; + try { + proxy = (T) proxyClass.getConstructor( + new Class[] { InvocationHandler.class }).newInstance( + new Object[] { handler }); + return proxy; + } catch (Exception e) { + throw new RuntimeException("Could not create proxy for " + + clazz.getName(), e); + } + } +} diff --git a/support/general/src/test/java/org/wamblee/general/LookupProxyFactoryTest.java b/support/general/src/test/java/org/wamblee/general/LookupProxyFactoryTest.java new file mode 100644 index 00000000..c7650906 --- /dev/null +++ b/support/general/src/test/java/org/wamblee/general/LookupProxyFactoryTest.java @@ -0,0 +1,97 @@ +/* + * 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 static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import javax.naming.InitialContext; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.wamblee.general.LookupProxyFactory; +import org.wamblee.general.LookupProxyFactory.Lookup; +import org.wamblee.general.LookupProxyFactory.LookupException; + +public class LookupProxyFactoryTest { + + private static final String NAA_NA_NA_NAA_NA = "naa, na, na, naa, na"; + + private static interface MyInterface { + int execute(); + } + + private MyInterface intf; + private Lookup lookup; + private MyInterface proxy; + + @Before + public void setUp() throws Exception { + intf = mock(MyInterface.class); + lookup = mock(Lookup.class); + + LookupProxyFactory factory = new LookupProxyFactory( + MyInterface.class, lookup); + proxy = factory.getProxy(); + } + + @After + public void tearDown() throws Exception { + // Empty. + } + + @Test + public void testFound() throws Exception { + when(intf.execute()).thenReturn(1); + when(lookup.lookup()).thenReturn(intf); + + assertEquals(1, proxy.execute()); + + } + + @Test(expected = LookupException.class) + public void testNotFoundAtJndi() throws Exception { + when(lookup.lookup()).thenThrow(new RuntimeException("Object not found")); + proxy.execute(); + } + + @Test(expected = LookupException.class) + public void testWrongTypeAtJndi() throws Exception { + when(lookup.lookup()).thenReturn("my string"); + when(intf.execute()).thenReturn(1); + proxy.execute(); + } + + @Test(expected = LookupException.class) + public void testNullAtJndi() throws Exception { + when(lookup.lookup()).thenReturn(null); + when(intf.execute()).thenReturn(1); + proxy.execute(); + } + + @Test + public void testFoundButInvocationThrowsException() throws Exception { + when(intf.execute()).thenThrow(new RuntimeException(NAA_NA_NA_NAA_NA)); + when(lookup.lookup()).thenReturn(intf); + try { + proxy.execute(); + } catch (RuntimeException e) { + assertEquals(NAA_NA_NA_NAA_NA, e.getMessage()); + } + } + +} -- 2.31.1