1 /*
2  * Copyright (C) 2008 The Android Open Source Project
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 
17 import java.lang.annotation.Annotation;
18 import java.lang.reflect.InvocationHandler;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Proxy;
24 import java.util.Arrays;
25 
26 /**
27  * Do some basic tests.
28  */
29 public class BasicTest {
30 
main(String[] args)31     public static void main(String[] args) {
32         Mix proxyMe = new Mix();
33         Object proxy = createProxy(proxyMe);
34 
35         if (!Proxy.isProxyClass(proxy.getClass()))
36             System.out.println("not a proxy class?");
37         if (Proxy.getInvocationHandler(proxy) == null)
38             System.out.println("ERROR: Proxy.getInvocationHandler is null");
39 
40         /* take it for a spin; verifies instanceof constraint */
41         Shapes shapes = (Shapes) proxy;
42         shapes.circle(3);
43         shapes.rectangle(10, 20);
44         shapes.blob();
45         Quads quads = (Quads) proxy;
46         quads.rectangle(15, 25);
47         quads.trapezoid(6, 81.18, 4);
48         Colors colors = (Colors) proxy;
49         colors.red(1.0f);
50         colors.blue(777);
51         colors.mauve("sorry");
52         colors.blob();
53         Trace trace = (Trace) proxy;
54         trace.getTrace();
55 
56         // Test the proxy spec: These Object functions are supposed to be given to the handler.
57         int unusedHashCode = ((Object)trace).hashCode();
58         boolean unusedEquals = ((Object)trace).equals(trace);
59         String unusedString = ((Object)trace).toString();
60 
61         try {
62             shapes.upChuck();
63             System.out.println("Didn't get expected exception");
64         } catch (IndexOutOfBoundsException ioobe) {
65             System.out.println("Got expected ioobe");
66         }
67         try {
68             shapes.upCheck();
69             System.out.println("Didn't get expected exception");
70         } catch (InterruptedException ie) {
71             System.out.println("Got expected ie");
72         }
73 
74         /*
75          * Exercise annotations on Proxy classes.  This is mostly to ensure
76          * that annotation calls work correctly on generated classes.
77          */
78         System.out.println("");
79         Method[] methods = proxy.getClass().getDeclaredMethods();
80         Arrays.sort(methods, new MethodComparator());
81         System.out.println("Proxy interfaces: " +
82             Arrays.deepToString(proxy.getClass().getInterfaces()));
83         System.out.println("Proxy methods: " +
84             Main.replaceProxyClassNamesForOutput(Arrays.deepToString(methods)));
85         Method meth = methods[methods.length -1];
86         System.out.println("Decl annos: " + Arrays.deepToString(meth.getDeclaredAnnotations()));
87         Annotation[][] paramAnnos = meth.getParameterAnnotations();
88         System.out.println("Param annos (" + paramAnnos.length + ") : "
89             + Arrays.deepToString(paramAnnos));
90         System.out.println("Modifiers: " + meth.getModifiers());
91     }
92 
createProxy(Object proxyMe)93     static Object createProxy(Object proxyMe) {
94         /* declare an object that will handle the method calls */
95         InvocationHandler handler = new MyInvocationHandler(proxyMe);
96 
97         /* create the proxy class */
98         Class<?> proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(),
99                 Quads.class, Colors.class, Trace.class);
100         Main.registerProxyClassName(proxyClass.getCanonicalName());
101 
102         /* create a proxy object, passing the handler object in */
103         Object proxy = null;
104         try {
105             Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class);
106             //System.out.println("Constructor is " + cons);
107             proxy = cons.newInstance(handler);
108         } catch (NoSuchMethodException nsme) {
109             System.out.println("failed: " + nsme);
110         } catch (InstantiationException ie) {
111             System.out.println("failed: " + ie);
112         } catch (IllegalAccessException ie) {
113             System.out.println("failed: " + ie);
114         } catch (InvocationTargetException ite) {
115             System.out.println("failed: " + ite);
116         }
117 
118         return proxy;
119     }
120 }
121 
122 /*
123  * Some interfaces.
124  */
125 interface Shapes {
circle(int r)126     public void circle(int r);
rectangle(int x, int y)127     public int rectangle(int x, int y);
128 
blob()129     public String blob();
130 
checkMe()131     public R0base checkMe();
upChuck()132     public void upChuck();
upCheck()133     public void upCheck() throws InterruptedException;
134 }
135 
136 interface Quads extends Shapes {
rectangle(int x, int y)137     public int rectangle(int x, int y);
square(int x, int y)138     public int square(int x, int y);
trapezoid(int x, double off, int y)139     public int trapezoid(int x, double off, int y);
140 
checkMe()141     public R0a checkMe();
142 }
143 
144 /*
145  * More interfaces.
146  */
147 interface Colors {
red(float howRed)148     public int red(float howRed);
green(double howGreen)149     public int green(double howGreen);
blue(int howBlue)150     public double blue(int howBlue);
mauve(String apology)151     public int mauve(String apology);
152 
blob()153     public String blob();
154 
checkMe()155     public R0aa checkMe();
156 }
157 
158 interface Trace {
getTrace()159     public void getTrace();
160 }
161 
162 /*
163  * Some return types.
164  */
165 class R0base { int mBlah;  }
166 class R0a extends R0base { int mBlah_a;  }
167 class R0aa extends R0a { int mBlah_aa;  }
168 
169 
170 /*
171  * A class that implements them all.
172  */
173 class Mix implements Quads, Colors {
circle(int r)174     public void circle(int r) {
175         System.out.println("--- circle " + r);
176     }
rectangle(int x, int y)177     public int rectangle(int x, int y) {
178         System.out.println("--- rectangle " + x + "," + y);
179         return 4;
180     }
square(int x, int y)181     public int square(int x, int y) {
182         System.out.println("--- square " + x + "," + y);
183         return 4;
184     }
trapezoid(int x, double off, int y)185     public int trapezoid(int x, double off, int y) {
186         System.out.println("--- trap " + x + "," + y + "," + off);
187         return 8;
188     }
blob()189     public String blob() {
190         System.out.println("--- blob");
191         return "mix";
192     }
193 
red(float howRed)194     public int red(float howRed) {
195         System.out.println("--- red " + howRed);
196         return 0;
197     }
green(double howGreen)198     public int green(double howGreen) {
199         System.out.println("--- green " + howGreen);
200         return 1;
201     }
blue(int howBlue)202     public double blue(int howBlue) {
203         System.out.println("--- blue " + howBlue);
204         return 2.54;
205     }
mauve(String apology)206     public int mauve(String apology) {
207         System.out.println("--- mauve " + apology);
208         return 3;
209     }
210 
checkMe()211     public R0aa checkMe() {
212         return null;
213     }
upChuck()214     public void upChuck() {
215         throw new IndexOutOfBoundsException("upchuck");
216     }
upCheck()217     public void upCheck() throws InterruptedException {
218         throw new InterruptedException("upcheck");
219     }
220 }
221 
222 /*
223  * Invocation handler, defining the implementation of the proxy functions.
224  */
225 class MyInvocationHandler implements InvocationHandler {
226     Object mObj;
227 
MyInvocationHandler(Object obj)228     public MyInvocationHandler(Object obj) {
229         mObj = obj;
230     }
231 
232     /*
233      * This is called when anything gets invoked in the proxy object.
234      */
invoke(Object proxy, Method method, Object[] args)235     public Object invoke(Object proxy, Method method, Object[] args)
236         throws Throwable {
237 
238         System.out.println("Invoke " + method);
239 
240         Object result = null;
241 
242         // Trap Object calls.  This is important here to avoid a recursive
243         // invocation of toString() in the print statements below.
244         if (method.getDeclaringClass() == java.lang.Object.class) {
245             //System.out.println("!!! object " + method.getName());
246             if (method.getName().equals("toString")) {
247                 return super.toString();
248             } else if (method.getName().equals("hashCode")) {
249                 return Integer.valueOf(super.hashCode());
250             } else if (method.getName().equals("equals")) {
251                 return Boolean.valueOf(super.equals(args[0]));
252             } else {
253                 throw new RuntimeException("huh?");
254             }
255         }
256 
257         if (method.getDeclaringClass() == Trace.class) {
258           if (method.getName().equals("getTrace")) {
259             StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
260             for (int i = 0; i < stackTrace.length; i++) {
261                 StackTraceElement ste = stackTrace[i];
262                 if (ste.getMethodName().equals("getTrace")) {
263                   String outputClassName = Main.replaceProxyClassNamesForOutput(ste.getClassName());
264                   System.out.println(outputClassName + "." + ste.getMethodName() + " " +
265                                      ste.getFileName() + ":" + ste.getLineNumber());
266                 }
267             }
268             return null;
269           }
270         }
271 
272         if (method.getDeclaringClass() == Trace.class) {
273           if (method.getName().equals("getTrace")) {
274             StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
275             for (int i = 0; i < stackTrace.length; i++) {
276                 StackTraceElement ste = stackTrace[i];
277                 if (ste.getMethodName().equals("getTrace")) {
278                   String outputClassName = Main.replaceProxyClassNamesForOutput(ste.getClassName());
279                   System.out.println(outputClassName + "." + ste.getMethodName() + " " +
280                                      ste.getFileName() + ":" + ste.getLineNumber());
281                 }
282             }
283             return null;
284           }
285         }
286 
287         if (args == null || args.length == 0) {
288             System.out.println(" (no args)");
289         } else {
290             for (int i = 0; i < args.length; i++)
291                 System.out.println(" " + i + ": " + args[i]);
292         }
293 
294         try {
295             if (true) {
296                 result = method.invoke(mObj, args);
297             } else {
298                 result = -1;
299             }
300             System.out.println("Success: method " + method.getName()
301                 + " res=" + result);
302         } catch (InvocationTargetException ite) {
303             throw ite.getTargetException();
304         } catch (IllegalAccessException iae) {
305             throw new RuntimeException(iae);
306         }
307         return result;
308     }
309 }
310