1277f5d84e
Reviewed-by: darcy, joehw, iris
316 lines
12 KiB
Java
316 lines
12 KiB
Java
/*
|
|
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
/*
|
|
@test 1.3 99/02/15
|
|
@summary test Resource Bundle for bug 4179766
|
|
@build Bug4179766Class Bug4179766Resource Bug4179766Getter
|
|
@run main TestBug4179766
|
|
@bug 4179766
|
|
*/
|
|
/*
|
|
* This file is available under and governed by the GNU General Public
|
|
* License version 2 only, as published by the Free Software Foundation.
|
|
* However, the following notice accompanied the original version of this
|
|
* file and, per its terms, should not be removed:
|
|
*
|
|
* (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
|
|
*
|
|
* Portions copyright (c) 2007 Sun Microsystems, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* The original version of this source code and documentation
|
|
* is copyrighted and owned by Taligent, Inc., a wholly-owned
|
|
* subsidiary of IBM. These materials are provided under terms
|
|
* of a License Agreement between Taligent and Sun. This technology
|
|
* is protected by multiple US and International patents.
|
|
*
|
|
* This notice and attribution to Taligent may not be removed.
|
|
* Taligent is a registered trademark of Taligent, Inc.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software
|
|
* and its documentation for NON-COMMERCIAL purposes and without
|
|
* fee is hereby granted provided that this copyright notice
|
|
* appears in all copies. Please refer to the file "copyright.html"
|
|
* for further important copyright and licensing information.
|
|
*
|
|
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
|
|
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
|
|
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
|
|
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
|
|
*
|
|
*/
|
|
|
|
import java.util.Hashtable;
|
|
import java.util.ResourceBundle;
|
|
import java.util.MissingResourceException;
|
|
import java.util.Hashtable;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
|
|
/**
|
|
* This class tests the behavior of the ResourceBundle cache with
|
|
* respect to ClassLoaders. The same resource loaded by different
|
|
* loaders should be cached as separate objects, one for each loader.
|
|
* In order to test this behavior, this test constructs a custom
|
|
* class loader to load its resources. It does not delegate resource
|
|
* loading to the system loader to load the class files, but loads
|
|
* them from the current directory instead. This is so that the
|
|
* defining class loader for the resources is different. If it
|
|
* delegated to the system loader to load the resources, the
|
|
* defining ClassLoader would be the same even though the initiating
|
|
* loader differered, and the resource would only be cached once.
|
|
*/
|
|
public class TestBug4179766 extends RBTestFmwk {
|
|
//hash code used by class loaders when sameHash is true
|
|
private static final int SAME_HASH_CODE = 0;
|
|
//the next unique hash code
|
|
private static int nextHashCode = SAME_HASH_CODE + 1;
|
|
//suffix on class files
|
|
private static final String CLASS_SUFFIX = ".class";
|
|
|
|
//generate a unique hashcode for a class loader
|
|
private static synchronized int getNextHashCode() {
|
|
return nextHashCode++;
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
//static links so all needed classes get compiled
|
|
Object o1 = new Bug4179766Class();
|
|
Object o2 = new Bug4179766Resource();
|
|
new TestBug4179766().run(args);
|
|
}
|
|
|
|
/**
|
|
* Ensure the resource cache is working correctly for a single
|
|
* resource from a single loader. If we get the same resource
|
|
* from the same loader twice, we should get the same resource.
|
|
*/
|
|
public void testCache() throws Exception {
|
|
Loader loader = new Loader(false);
|
|
ResourceBundle b1 = getResourceBundle(loader, "Bug4179766Resource");
|
|
if (b1 == null) {
|
|
errln("Resource not found: Bug4179766Resource");
|
|
}
|
|
ResourceBundle b2 = getResourceBundle(loader, "Bug4179766Resource");
|
|
if (b2 == null) {
|
|
errln("Resource not found: Bug4179766Resource");
|
|
}
|
|
printIDInfo("[bundle1]",b1);
|
|
printIDInfo("[bundle2]",b2);
|
|
if (b1 != b2) {
|
|
errln("Different objects returned by same ClassLoader");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that loaders with the same hash key still
|
|
* cache resources seperately
|
|
*/
|
|
public void testSameHash() throws Exception {
|
|
doTest(true);
|
|
}
|
|
|
|
/**
|
|
* Test that loaders with different hash keys
|
|
* cache resources seperately
|
|
*/
|
|
public void testDifferentHash() throws Exception {
|
|
doTest(false);
|
|
}
|
|
|
|
/**
|
|
* Ensure that cached resources for different ClassLoaders
|
|
* are cached seperately
|
|
*/
|
|
private void doTest(boolean sameHash) throws Exception {
|
|
ResourceBundle b1 = getResourceBundle(new Loader(sameHash), "Bug4179766Resource");
|
|
if (b1 == null) {
|
|
errln("Resource not found: Bug4179766Resource");
|
|
}
|
|
ResourceBundle b2 = getResourceBundle(new Loader(sameHash), "Bug4179766Resource");
|
|
if (b2 == null) {
|
|
errln("Resource not found: Bug4179766Resource");
|
|
}
|
|
printIDInfo("[bundle1]",b1);
|
|
printIDInfo("[bundle2]",b2);
|
|
if (b1 == b2) {
|
|
errln("Same object returned by different ClassLoaders");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a resource using a specified class loader to load the resource
|
|
*/
|
|
private ResourceBundle getResourceBundle(Loader loader, String name) throws Exception {
|
|
try {
|
|
Class c = loader.loadClass("Bug4179766Class");
|
|
Bug4179766Getter test = (Bug4179766Getter)c.newInstance();
|
|
return test.getResourceBundle(name);
|
|
} catch (ClassNotFoundException e) {
|
|
errln("Class not found by custom class loader: "+name);
|
|
throw e;
|
|
} catch (InstantiationException e) {
|
|
errln("Error instantiating: "+name);
|
|
throw e;
|
|
} catch (IllegalAccessException e) {
|
|
errln("IllegalAccessException instantiating: "+name);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print information about an object
|
|
* [message][object's identity][object's class][object's loader][loaders hash][loaders identity]
|
|
*/
|
|
private void printIDInfo(String message, Object o) {
|
|
if (o == null) {
|
|
return;
|
|
}
|
|
Class c = o.getClass();
|
|
ClassLoader l = c.getClassLoader();
|
|
int hash = -1;
|
|
if (l != null) {
|
|
hash = l.hashCode();
|
|
}
|
|
logln(message + System.identityHashCode(o) + " Class: " + c
|
|
+ " ClassLoader: " + l + " loaderHash: " + hash
|
|
+ " loaderPrimHash: " + System.identityHashCode(l));
|
|
}
|
|
|
|
/**
|
|
* A simple class loader that loads classes from the current
|
|
* working directory. The hash code of the loader can be
|
|
* set to be either the loaders identity or 0, allowing several
|
|
* loaders to have the same hashCode value.
|
|
*/
|
|
public class Loader extends ClassLoader {
|
|
private int thisHashCode;
|
|
|
|
/**
|
|
* Create a new loader
|
|
*/
|
|
public Loader(boolean sameHash) {
|
|
super(Loader.class.getClassLoader());
|
|
if (sameHash) {
|
|
thisHashCode = SAME_HASH_CODE;
|
|
} else {
|
|
thisHashCode = getNextHashCode();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the hash code for this loader.
|
|
*/
|
|
public int hashCode() {
|
|
return thisHashCode;
|
|
}
|
|
|
|
/**
|
|
* Get the data from the class file for the specified class. If
|
|
* the file can't be found, or the class is not one of the
|
|
* special ones listed below, return null.
|
|
* Bug4179766Class
|
|
* Bug4179766Resource
|
|
*/
|
|
private byte[] getClassData(String className) {
|
|
boolean shouldLoad = className.equals("Bug4179766Class");
|
|
shouldLoad = shouldLoad || className.equals("Bug4179766Resource");
|
|
|
|
if (shouldLoad) {
|
|
try {
|
|
File file = new File(System.getProperty("test.classes", "."), className+CLASS_SUFFIX);
|
|
FileInputStream fi = new FileInputStream(file);
|
|
byte[] result = new byte[fi.available()];
|
|
fi.read(result);
|
|
return result;
|
|
} catch (Exception e) {
|
|
return null;
|
|
}
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load a class. Files we can load take preference over ones the system
|
|
* can load.
|
|
*/
|
|
public synchronized Class loadClass(String className, boolean resolveIt)
|
|
throws ClassNotFoundException {
|
|
|
|
Class result = findLoadedClass(className);
|
|
if (result != null) {
|
|
printInfo(" ***Returning cached class: "+className, result);
|
|
return result;
|
|
}
|
|
|
|
byte[] classData = getClassData(className);
|
|
if (classData == null) {
|
|
//we don't have a local copy of this one
|
|
return loadFromSystem(className);
|
|
}
|
|
|
|
result = defineClass(classData, 0, classData.length);
|
|
if (result == null) {
|
|
//there was an error defining the class
|
|
return loadFromSystem(className);
|
|
}
|
|
|
|
if (resolveIt) {
|
|
resolveClass(result);
|
|
}
|
|
|
|
printInfo(" ***Loaded local class: "+className, result);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Delegate loading to the system loader
|
|
*/
|
|
private Class loadFromSystem(String className) throws ClassNotFoundException {
|
|
try {
|
|
Class result = getParent().loadClass(className);
|
|
printInfo(" ***Returning system class: "+className, result);
|
|
return result;
|
|
} catch (ClassNotFoundException e) {
|
|
printInfo(" ***Class not found: "+className, null);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print information about a class that was loaded
|
|
* [loader identity][message][class identity]
|
|
*/
|
|
private void printInfo(String message, Class c) {
|
|
if (c != null) {
|
|
logln(""+System.identityHashCode(this)+" "+message+" "+System.identityHashCode(c));
|
|
} else {
|
|
logln(""+System.identityHashCode(this)+" "+message);
|
|
}
|
|
}
|
|
}
|
|
}
|