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