1/*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23/*
24    @test  1.3 99/02/15
25    @summary test Resource Bundle for bug 4179766
26    @build Bug4179766Class Bug4179766Resource Bug4179766Getter
27    @run main TestBug4179766
28    @bug 4179766
29*/
30/*
31 *
32 *
33 * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
34 *
35 * Portions copyright (c) 2007 Sun Microsystems, Inc.
36 * All Rights Reserved.
37 *
38 * The original version of this source code and documentation
39 * is copyrighted and owned by Taligent, Inc., a wholly-owned
40 * subsidiary of IBM. These materials are provided under terms
41 * of a License Agreement between Taligent and Sun. This technology
42 * is protected by multiple US and International patents.
43 *
44 * This notice and attribution to Taligent may not be removed.
45 * Taligent is a registered trademark of Taligent, Inc.
46 *
47 * Permission to use, copy, modify, and distribute this software
48 * and its documentation for NON-COMMERCIAL purposes and without
49 * fee is hereby granted provided that this copyright notice
50 * appears in all copies. Please refer to the file "copyright.html"
51 * for further important copyright and licensing information.
52 *
53 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
54 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
55 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
56 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
57 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
58 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
59 *
60 */
61
62import java.util.Hashtable;
63import java.util.ResourceBundle;
64import java.util.MissingResourceException;
65import java.util.Hashtable;
66import java.io.File;
67import java.io.FileInputStream;
68
69/**
70 * This class tests the behavior of the ResourceBundle cache with
71 * respect to ClassLoaders.  The same resource loaded by different
72 * loaders should be cached as separate objects, one for each loader.
73 * In order to test this behavior, this test constructs a custom
74 * class loader to load its resources.  It does not delegate resource
75 * loading to the system loader to load the class files, but loads
76 * them from the current directory instead.  This is so that the
77 * defining class loader for the resources is different.  If it
78 * delegated to the system loader to load the resources, the
79 * defining ClassLoader would be the same even though the initiating
80 * loader differered, and the resource would only be cached once.
81 */
82public class TestBug4179766 extends RBTestFmwk {
83    //hash code used by class loaders when sameHash is true
84    private static final int SAME_HASH_CODE = 0;
85    //the next unique hash code
86    private static int nextHashCode = SAME_HASH_CODE + 1;
87    //suffix on class files
88    private static final String CLASS_SUFFIX = ".class";
89
90    //generate a unique hashcode for a class loader
91    private static synchronized int getNextHashCode() {
92        return nextHashCode++;
93    }
94
95    public static void main(String[] args) throws Exception {
96        //static links so all needed classes get compiled
97        Object o1 = new Bug4179766Class();
98        Object o2 = new Bug4179766Resource();
99        new TestBug4179766().run(args);
100    }
101
102    /**
103    * Ensure the resource cache is working correctly for a single
104    * resource from a single loader.  If we get the same resource
105    * from the same loader twice, we should get the same resource.
106    */
107    public void testCache() throws Exception {
108        Loader loader = new Loader(false);
109        ResourceBundle b1 = getResourceBundle(loader, "Bug4179766Resource");
110        if (b1 == null) {
111            errln("Resource not found: Bug4179766Resource");
112        }
113        ResourceBundle b2 = getResourceBundle(loader, "Bug4179766Resource");
114        if (b2 == null) {
115            errln("Resource not found: Bug4179766Resource");
116        }
117        printIDInfo("[bundle1]",b1);
118        printIDInfo("[bundle2]",b2);
119        if (b1 != b2) {
120            errln("Different objects returned by same ClassLoader");
121        }
122    }
123
124    /**
125    * Test that loaders with the same hash key still
126    * cache resources seperately
127    */
128    public void testSameHash() throws Exception {
129        doTest(true);
130    }
131
132    /**
133    * Test that loaders with different hash keys
134    * cache resources seperately
135    */
136    public void testDifferentHash() throws Exception {
137        doTest(false);
138    }
139
140    /**
141     * Ensure that cached resources for different ClassLoaders
142     * are cached seperately
143     */
144    private void doTest(boolean sameHash) throws Exception {
145        ResourceBundle b1 = getResourceBundle(new Loader(sameHash), "Bug4179766Resource");
146        if (b1 == null) {
147           errln("Resource not found: Bug4179766Resource");
148        }
149        ResourceBundle b2 = getResourceBundle(new Loader(sameHash), "Bug4179766Resource");
150        if (b2 == null) {
151           errln("Resource not found: Bug4179766Resource");
152        }
153        printIDInfo("[bundle1]",b1);
154        printIDInfo("[bundle2]",b2);
155        if (b1 == b2) {
156           errln("Same object returned by different ClassLoaders");
157        }
158    }
159
160    /**
161     * Get a resource using a specified class loader to load the resource
162     */
163    private ResourceBundle getResourceBundle(Loader loader, String name) throws Exception {
164        try {
165            Class c = loader.loadClass("Bug4179766Class");
166            Bug4179766Getter test = (Bug4179766Getter)c.newInstance();
167            return test.getResourceBundle(name);
168        } catch (ClassNotFoundException e) {
169            errln("Class not found by custom class loader: "+name);
170            throw e;
171        } catch (InstantiationException e) {
172            errln("Error instantiating: "+name);
173            throw e;
174        } catch (IllegalAccessException e) {
175            errln("IllegalAccessException instantiating: "+name);
176            throw e;
177        }
178    }
179
180    /**
181     * Print information about an object
182     * [message][object's identity][object's class][object's loader][loaders hash][loaders identity]
183     */
184    private void printIDInfo(String message, Object o) {
185        if (o == null) {
186            return;
187        }
188        Class c = o.getClass();
189        ClassLoader l = c.getClassLoader();
190        int hash = -1;
191        if (l != null) {
192            hash = l.hashCode();
193        }
194        logln(message + System.identityHashCode(o) + "  Class: " + c
195                + "  ClassLoader: " + l + "  loaderHash: " + hash
196                + "  loaderPrimHash: " + System.identityHashCode(l));
197    }
198
199    /**
200     * A simple class loader that loads classes from the current
201     * working directory.  The hash code of the loader can be
202     * set to be either the loaders identity or 0, allowing several
203     * loaders to have the same hashCode value.
204     */
205    public class Loader extends ClassLoader {
206        private int thisHashCode;
207
208        /**
209         * Create a new loader
210         */
211        public Loader(boolean sameHash) {
212            super(Loader.class.getClassLoader());
213            if (sameHash) {
214                thisHashCode = SAME_HASH_CODE;
215            } else {
216                thisHashCode = getNextHashCode();
217            }
218        }
219
220        /**
221         * Return the hash code for this loader.
222         */
223        public int hashCode() {
224            return thisHashCode;
225        }
226
227        /**
228         * Get the data from the class file for the specified class.  If
229         * the file can't be found, or the class is not one of the
230         * special ones listed below, return null.
231         *    Bug4179766Class
232         *    Bug4179766Resource
233         */
234        private byte[] getClassData(String className) {
235            boolean shouldLoad = className.equals("Bug4179766Class");
236            shouldLoad = shouldLoad || className.equals("Bug4179766Resource");
237
238            if (shouldLoad) {
239                try {
240                    File file = new File(System.getProperty("test.classes", "."), className+CLASS_SUFFIX);
241                    FileInputStream fi = new FileInputStream(file);
242                    byte[] result = new byte[fi.available()];
243                    fi.read(result);
244                    return result;
245                } catch (Exception e) {
246                    return null;
247                }
248            } else {
249                return null;
250            }
251        }
252
253        /**
254         * Load a class.  Files we can load take preference over ones the system
255         * can load.
256         */
257        public synchronized Class loadClass(String className, boolean resolveIt)
258                throws ClassNotFoundException {
259
260            Class result = findLoadedClass(className);
261            if (result != null) {
262                printInfo("        ***Returning cached class: "+className, result);
263                return result;
264            }
265
266            byte[] classData = getClassData(className);
267            if (classData == null) {
268                //we don't have a local copy of this one
269                return loadFromSystem(className);
270            }
271
272            result = defineClass(classData, 0, classData.length);
273            if (result == null) {
274                //there was an error defining the class
275                return loadFromSystem(className);
276            }
277
278            if (resolveIt) {
279                resolveClass(result);
280            }
281
282            printInfo("        ***Loaded local class: "+className, result);
283            return result;
284        }
285
286        /**
287         * Delegate loading to the system loader
288         */
289        private Class loadFromSystem(String className) throws ClassNotFoundException {
290            try {
291                Class result = getParent().loadClass(className);
292                printInfo("        ***Returning system class: "+className, result);
293                return result;
294            } catch (ClassNotFoundException e) {
295                printInfo("        ***Class not found: "+className, null);
296                throw e;
297            }
298        }
299
300        /**
301         * Print information about a class that was loaded
302         * [loader identity][message][class identity]
303         */
304        private void printInfo(String message, Class c) {
305            if (c != null) {
306                logln(""+System.identityHashCode(this)+"  "+message+"  "+System.identityHashCode(c));
307            } else {
308                logln(""+System.identityHashCode(this)+"  "+message);
309            }
310        }
311    }
312}
313