Clover Coverage Report - Atlassian Core
Coverage timestamp: Sun Nov 30 2008 18:33:35 CST
20   170   14   2.22
2   87   0.7   3
9     1.56  
3    
 
 
  DuckTypeProxy       Line # 44 7 7 71.4% 0.71428573
  DuckTypeProxy.UnimplementedMethodHandler       Line # 116 0 0 - -1.0
  DuckTypeProxy.DuckTypeInvocationHandler       Line # 124 13 7 100% 1.0
 
  (6)
 
1    package com.atlassian.core.test.util;
2   
3    import java.lang.reflect.*;
4    import java.util.*;
5   
6    /**
7    * Utility for getting a proxy that delegates to a list of delegates in order. The delegates are queried whether they
8    * implement a particular method and if so, it is called and the result returned. If they don't, the next handler is
9    * queried and so forth. If none of the objects implement the interface then the UnimplementedMethodhandler is invoked.
10    * None of the delegates need to actually implement the proxied interface, only have a method with the same signature.
11    * <p>
12    * So for instance, given:
13    *
14    * <pre>
15    * interface MyInterface
16    * {
17    * String getString();
18    *
19    * Long getLong();
20    *
21    * Integer getInteger();
22    * }
23    * </pre>
24    *
25    * you can create a proxy for this interface without needing to implement the whole thing:
26    *
27    * <pre>
28    * Object mocker = new Object()
29    * {
30    * public String myMethod()
31    * {
32    * return &quot;proxied&quot;;
33    * }
34    * }
35    * MyInterface mock = (MyInterface) DuckTypeProxy.getProxy(MyInterface.class, mocker);
36    * System.out.println(mock.getString());
37    * </pre>
38    *
39    * prints "proxied" to the console.
40    * <p>
41    * There are {@link UnimplementedMethodHandler facilities for handling unimplemented methods} either by
42    * {@link #RETURN_NULL returning null} or {@link #THROW throwing exceptions by default}.
43    */
 
44    public class DuckTypeProxy
45    {
46    // -------------------------------------------------------------------------------------------------- static members
47   
48    /**
49    * Return null if the method cannot be found.
50    */
51    public static UnimplementedMethodHandler RETURN_NULL = new UnimplementedMethodHandler()
52    {
 
53  0 toggle public Object methodNotImplemented(Method method, Object[] args)
54    {
55  0 return null;
56    }
57    };
58   
59    /**
60    * Throw an exception if the method cannot be found.
61    */
62    public static UnimplementedMethodHandler THROW = new UnimplementedMethodHandler()
63    {
 
64  1 toggle public Object methodNotImplemented(Method method, Object[] args)
65    {
66  1 throw new UnsupportedOperationException(method.toString());
67    }
68    };
69   
70    // ------------------------------------------------------------------------------------------------- factory methods
71   
72    /**
73    * Get a Proxy that checks each of the enclosed objects and calls them if they have a Method of the same signature.
74    * By default this will {@link #THROW throw an UnsupportedOperationException} if the method is not implemented
75    */
 
76  1 toggle /* <T> */public static/* T */Object getProxy(/* Class<T> */Class implementingClass, List delegates)
77    {
78  1 return getProxy(new Class[] { implementingClass }, delegates);
79    }
80   
81    /**
82    * Get a Proxy that checks each of the enclosed objects and calls them if they have a Method of the same signature.
83    */
 
84  5 toggle /* <T> */public static/* T */Object getProxy(/* Class<T> */Class implementingClass, List delegates,
85    UnimplementedMethodHandler unimplementedMethodHandler)
86    {
87  5 return getProxy(new Class[] { implementingClass }, delegates, unimplementedMethodHandler);
88    }
89   
90    /**
91    * Get a Proxy that checks each of the enclosed objects and calls them if they have a Method of the same signature.
92    * Uses the {@link #THROW} {@link UnimplementedMethodHandler}
93    */
 
94  1 toggle public static Object getProxy(Class[] implementingClasses, List delegates)
95    {
96  1 return getProxy(implementingClasses, delegates, THROW);
97    }
98   
 
99  6 toggle public static Object getProxy(Class[] implementingClasses, List delegates, UnimplementedMethodHandler unimplementedMethodHandler)
100    {
101  6 return Proxy.newProxyInstance(DuckTypeProxy.class.getClassLoader(), implementingClasses, new DuckTypeInvocationHandler(delegates,
102    unimplementedMethodHandler));
103    }
104   
105    /**
106    * Get a Proxy that checks the enclosed object and calls it if it has a Method of the same signature.
107    * By default this will {@link #THROW throw an UnsupportedOperationException} if the method is not implemented
108    */
 
109  0 toggle /* <T> */public static/* T */Object getProxy(/* Class<T> */Class implementingClass, Object delegate)
110    {
111  0 return getProxy(new Class[] { implementingClass }, Arrays.asList(new Object[] {delegate}));
112    }
113   
114    // --------------------------------------------------------------------------------------------------- inner classes
115   
 
116    public interface UnimplementedMethodHandler
117    {
118    Object methodNotImplemented(Method method, Object[] args);
119    }
120   
121    /**
122    * The invocation handler that keeps the references to the delegate objects.
123    */
 
124    private static class DuckTypeInvocationHandler implements InvocationHandler
125    {
126    private final List delegates;
127    private final UnimplementedMethodHandler unimplementedMethodHandler;
128   
 
129  6 toggle DuckTypeInvocationHandler(List handlers, UnimplementedMethodHandler unimplementedMethodHandler)
130    {
131  6 this.delegates = Collections.unmodifiableList(new ArrayList(handlers));
132  6 this.unimplementedMethodHandler = unimplementedMethodHandler;
133    }
134   
 
135  6 toggle public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
136    {
137  8 for (Iterator it = delegates.iterator(); it.hasNext();)
138    {
139  7 Object handler = it.next();
140  7 Method duckTypeMethod;
141  7 try
142    {
143  7 duckTypeMethod = handler.getClass().getMethod(method.getName(), method.getParameterTypes());
144    }
145    catch (NoSuchMethodException ignoreAndTryNext)
146    {
147  2 continue;
148    }
149  5 try
150    {
151  5 duckTypeMethod.setAccessible(true);
152  5 return duckTypeMethod.invoke(handler, args);
153    }
154    catch (IllegalArgumentException ignoreAndContinue)
155    {
156    // ignored
157    }
158    catch (IllegalAccessException ignoreAndContinue)
159    {
160    // ignored
161    }
162    catch (InvocationTargetException e)
163    {
164  1 throw e.getCause();
165    }
166    }
167  1 return unimplementedMethodHandler.methodNotImplemented(method, args);
168    }
169    }
170    }