Main.java revision cab8be0c6e1e9a683402d5a71b037723a6b15bb2
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/**
18 * Class loader test.
19 */
20public class Main {
21    /**
22     * Main entry point.
23     */
24    public static void main(String[] args) {
25        FancyLoader loader;
26
27        loader = new FancyLoader(ClassLoader.getSystemClassLoader());
28
29        /*
30         * This statement has no effect on this program, but it can
31         * change the point where a LinkageException is thrown in
32         * testImplement().  When this is present the "reference
33         * implementation" throws an exception from Class.newInstance(),
34         * when it's absent the exception is deferred until the first time
35         * we call a method that isn't actually implemented.
36         *
37         * This isn't the class that fails -- it's a class with the same
38         * name in the "fancy" class loader --  but the VM thinks it has a
39         * reference to one of these; presumably the difference is that
40         * without this the VM finds itself holding a reference to an
41         * instance of an uninitialized class.
42         */
43        System.out.println("base: " + DoubledImplement.class);
44        System.out.println("base2: " + DoubledImplement2.class);
45
46        /*
47         * Run tests.
48         */
49        testAccess1(loader);
50        testAccess2(loader);
51        testAccess3(loader);
52
53        testExtend(loader);
54        testExtendOkay(loader);
55        testImplement(loader);
56        testIfaceImplement(loader);
57    }
58
59    /**
60     * See if we can load a class that isn't public to us.  We should be
61     * able to load it but not instantiate it.
62     */
63    static void testAccess1(ClassLoader loader) {
64        Class altClass;
65
66        try {
67            altClass = loader.loadClass("Inaccessible1");
68        } catch (ClassNotFoundException cnfe) {
69            System.err.println("loadClass failed");
70            cnfe.printStackTrace();
71            return;
72        }
73
74        /* instantiate */
75        Object obj;
76        try {
77            obj = altClass.newInstance();
78            System.err.println("ERROR: Inaccessible1 was accessible");
79        } catch (InstantiationException ie) {
80            System.err.println("newInstance failed: " + ie);
81            return;
82        } catch (IllegalAccessException iae) {
83            System.out.println("Got expected access exception #1");
84            //System.out.println("+++ " + iae);
85            return;
86        }
87    }
88
89    /**
90     * See if we can load a class whose base class is not accessible to it
91     * (though the base *is* accessible to us).
92     */
93    static void testAccess2(ClassLoader loader) {
94        Class altClass;
95
96        try {
97            altClass = loader.loadClass("Inaccessible2");
98            System.err.println("ERROR: Inaccessible2 was accessible");
99        } catch (ClassNotFoundException cnfe) {
100            Throwable cause = cnfe.getCause();
101            if (cause instanceof IllegalAccessError) {
102                System.out.println("Got expected CNFE/IAE #2");
103            } else {
104                System.err.println("Got unexpected CNFE/IAE #2");
105                cnfe.printStackTrace();
106            }
107        }
108    }
109
110    /**
111     * See if we can load a class with an inaccessible interface.
112     */
113    static void testAccess3(ClassLoader loader) {
114        Class altClass;
115
116        try {
117            altClass = loader.loadClass("Inaccessible3");
118            System.err.println("ERROR: Inaccessible3 was accessible");
119        } catch (ClassNotFoundException cnfe) {
120            Throwable cause = cnfe.getCause();
121            if (cause instanceof IllegalAccessError) {
122                System.out.println("Got expected CNFE/IAE #3");
123            } else {
124                System.err.println("Got unexpected CNFE/IAE #3");
125                cnfe.printStackTrace();
126            }
127        }
128    }
129
130    /**
131     * Test a doubled class that extends the base class.
132     */
133    static void testExtend(ClassLoader loader) {
134        Class doubledExtendClass;
135        Object obj;
136
137        /* get the "alternate" version of DoubledExtend */
138        try {
139            doubledExtendClass = loader.loadClass("DoubledExtend");
140            //System.out.println("+++ DoubledExtend is " + doubledExtendClass
141            //    + " in " + doubledExtendClass.getClassLoader());
142        } catch (ClassNotFoundException cnfe) {
143            System.err.println("loadClass failed: " + cnfe);
144            return;
145        }
146
147        /* instantiate */
148        try {
149            obj = doubledExtendClass.newInstance();
150        } catch (InstantiationException ie) {
151            System.err.println("newInstance failed: " + ie);
152            return;
153        } catch (IllegalAccessException iae) {
154            System.err.println("newInstance failed: " + iae);
155            return;
156        } catch (LinkageError le) {
157            System.out.println("Got expected LinkageError on DE");
158            return;
159        }
160
161        /* use the base class reference to get a CL-specific instance */
162        Base baseRef = (Base) obj;
163        DoubledExtend de = baseRef.getExtended();
164
165        /* try to call through it */
166        try {
167            String result;
168
169            result = Base.doStuff(de);
170            System.err.println("ERROR: did not get LinkageError on DE");
171            System.err.println("(result=" + result + ")");
172        } catch (LinkageError le) {
173            System.out.println("Got expected LinkageError on DE");
174            return;
175        }
176    }
177
178    /**
179     * Test a doubled class that extends the base class, but is okay since
180     * it doesn't override the base class method.
181     */
182    static void testExtendOkay(ClassLoader loader) {
183        Class doubledExtendOkayClass;
184        Object obj;
185
186        /* get the "alternate" version of DoubledExtendOkay */
187        try {
188            doubledExtendOkayClass = loader.loadClass("DoubledExtendOkay");
189        } catch (ClassNotFoundException cnfe) {
190            System.err.println("loadClass failed: " + cnfe);
191            return;
192        }
193
194        /* instantiate */
195        try {
196            obj = doubledExtendOkayClass.newInstance();
197        } catch (InstantiationException ie) {
198            System.err.println("newInstance failed: " + ie);
199            return;
200        } catch (IllegalAccessException iae) {
201            System.err.println("newInstance failed: " + iae);
202            return;
203        } catch (LinkageError le) {
204            System.err.println("Got unexpected LinkageError on DEO");
205            le.printStackTrace();
206            return;
207        }
208
209        /* use the base class reference to get a CL-specific instance */
210        BaseOkay baseRef = (BaseOkay) obj;
211        DoubledExtendOkay de = baseRef.getExtended();
212
213        /* try to call through it */
214        try {
215            String result;
216
217            result = BaseOkay.doStuff(de);
218            System.out.println("Got DEO result " + result);
219        } catch (LinkageError le) {
220            System.err.println("Got unexpected LinkageError on DEO");
221            le.printStackTrace();
222            return;
223        }
224    }
225
226    /**
227     * Test a doubled class that implements a common interface.
228     */
229    static void testImplement(ClassLoader loader) {
230        Class doubledImplementClass;
231        Object obj;
232
233        useImplement(new DoubledImplement(), true);
234
235        /* get the "alternate" version of DoubledImplement */
236        try {
237            doubledImplementClass = loader.loadClass("DoubledImplement");
238        } catch (ClassNotFoundException cnfe) {
239            System.err.println("loadClass failed: " + cnfe);
240            return;
241        }
242
243        /* instantiate */
244        try {
245            obj = doubledImplementClass.newInstance();
246        } catch (InstantiationException ie) {
247            System.err.println("newInstance failed: " + ie);
248            return;
249        } catch (IllegalAccessException iae) {
250            System.err.println("newInstance failed: " + iae);
251            return;
252        } catch (LinkageError le) {
253            System.out.println("Got LinkageError on DI (early)");
254            return;
255        }
256
257        /* if we lived this long, try to do something with it */
258        ICommon icommon = (ICommon) obj;
259        useImplement(icommon.getDoubledInstance(), false);
260    }
261
262    /**
263     * Do something with a DoubledImplement instance.
264     */
265    static void useImplement(DoubledImplement di, boolean isOne) {
266        //System.out.println("useObject: " + di.toString() + " -- "
267        //    + di.getClass().getClassLoader());
268        try {
269            di.one();
270            if (!isOne) {
271                System.err.println("ERROR: did not get LinkageError on DI");
272            }
273        } catch (LinkageError le) {
274            if (!isOne) {
275                System.out.println("Got LinkageError on DI (late)");
276            } else {
277                throw le;
278            }
279        }
280    }
281
282
283    /**
284     * Test a class that implements an interface with a super-interface
285     * that refers to a doubled class.
286     */
287    static void testIfaceImplement(ClassLoader loader) {
288        Class ifaceImplClass;
289        Object obj;
290
291        /*
292         * Create an instance of IfaceImpl.  We also pull in
293         * DoubledImplement2 from the other class loader; without this
294         * we don't fail in some implementations.
295         */
296        try {
297            ifaceImplClass = loader.loadClass("IfaceImpl");
298            ifaceImplClass = loader.loadClass("DoubledImplement2");
299        } catch (ClassNotFoundException cnfe) {
300            System.err.println("loadClass failed: " + cnfe);
301            return;
302        }
303
304        /* instantiate */
305        try {
306            obj = ifaceImplClass.newInstance();
307        } catch (InstantiationException ie) {
308            System.err.println("newInstance failed: " + ie);
309            return;
310        } catch (IllegalAccessException iae) {
311            System.err.println("newInstance failed: " + iae);
312            return;
313        } catch (LinkageError le) {
314            System.out.println("Got LinkageError on IDI (early)");
315            //System.out.println(le);
316            return;
317        }
318
319        /*
320         * Without the pre-load of FancyLoader->DoubledImplement2, some
321         * implementations will happily execute through this part.  "obj"
322         * comes from FancyLoader, but the di2 returned from ifaceSuper
323         * comes from the application class loader.
324         */
325        IfaceSuper ifaceSuper = (IfaceSuper) obj;
326        DoubledImplement2 di2 = ifaceSuper.getDoubledInstance2();
327        di2.one();
328    }
329}
330
331