1 /* 2 * Copyright (c) 2013, 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 /* 25 * @test 26 * @bug 8002070 8013382 27 * @summary Remove the stack search for a resource bundle Logger to use 28 * @author Jim Gish 29 * @build ResourceBundleSearchTest IndirectlyLoadABundle LoadItUp1 LoadItUp2 TwiceIndirectlyLoadABundle LoadItUp2Invoker 30 * @run main/othervm ResourceBundleSearchTest 31 */ 32 import java.net.URL; 33 import java.net.URLClassLoader; 34 import java.nio.file.Paths; 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.util.Locale; 38 import java.util.MissingResourceException; 39 import java.util.ResourceBundle; 40 import java.util.logging.Logger; 41 42 /** 43 * This class tests various scenarios of loading resource bundles from 44 * java.util.logging. Since jtreg uses the logging system, it is necessary to 45 * run these tests using othervm mode to ensure no interference from logging 46 * initialization by jtreg 47 */ 48 public class ResourceBundleSearchTest { 49 50 private final static boolean DEBUG = false; 51 private final static String LOGGER_PREFIX = "myLogger."; 52 private static int loggerNum = 0; 53 private final static String PROP_RB_NAME = "ClassPathTestBundle"; 54 private final static String TCCL_TEST_BUNDLE = "ContextClassLoaderTestBundle"; 55 56 private static int numPass = 0; 57 private static int numFail = 0; 58 private static List<String> msgs = new ArrayList<>(); 59 60 public static void main(String[] args) throws Throwable { 61 ResourceBundleSearchTest test = new ResourceBundleSearchTest(); 62 test.runTests(); 63 } 64 65 private void runTests() throws Throwable { 66 // ensure we are using en as the default Locale so we can find the resource 67 Locale.setDefault(Locale.ENGLISH); 68 69 ClassLoader myClassLoader = ClassLoader.getSystemClassLoader(); 70 71 // Find out where we are running from so we can setup the URLClassLoader URL 72 String userDir = System.getProperty("user.dir"); 73 String testDir = System.getProperty("test.src", userDir); 74 75 URL[] urls = new URL[1]; 76 77 urls[0] = Paths.get(testDir, "resources").toUri().toURL(); 78 URLClassLoader rbClassLoader = new URLClassLoader(urls); 79 80 // Test 1 - can we find a Logger bundle from doing a stack search? 81 // We shouldn't be able to 82 assertFalse(testGetBundleFromStackSearch(), "1-testGetBundleFromStackSearch"); 83 84 // Test 2 - can we find a Logger bundle off of the Thread context class 85 // loader? We should be able to. 86 assertTrue(testGetBundleFromTCCL(TCCL_TEST_BUNDLE, rbClassLoader), 87 "2-testGetBundleFromTCCL"); 88 89 // Test 3 - Can we find a Logger bundle from the classpath? We should be 90 // able to. We'll first check to make sure the setup is correct and 91 // it actually is on the classpath before checking whether logging 92 // can see it there. 93 if (isOnClassPath(PROP_RB_NAME, myClassLoader)) { 94 debug("We should be able to see " + PROP_RB_NAME + " on the classpath"); 95 assertTrue(testGetBundleFromSystemClassLoader(PROP_RB_NAME), 96 "3-testGetBundleFromSystemClassLoader"); 97 } else { 98 throw new Exception("TEST SETUP FAILURE: Cannot see " + PROP_RB_NAME 99 + " on the classpath"); 100 } 101 102 // Test 4 - we should be able to find a bundle from the caller's 103 // classloader, but only one level up. 104 assertTrue(testGetBundleFromCallersClassLoader(), 105 "4-testGetBundleFromCallersClassLoader"); 106 107 // Test 5 - this ensures that getAnonymousLogger(String rbName) 108 // can find the bundle from the caller's classloader 109 assertTrue(testGetAnonymousLogger(), "5-testGetAnonymousLogger"); 110 111 // Test 6 - first call getLogger("myLogger"). 112 // Then call getLogger("myLogger","bundleName") from a different ClassLoader 113 // Make sure we find the bundle 114 assertTrue(testGetBundleFromSecondCallersClassLoader(), 115 "6-testGetBundleFromSecondCallersClassLoader"); 116 117 report(); 118 } 119 120 private void report() throws Exception { 121 System.out.println("Num passed = " + numPass + " Num failed = " + numFail); 122 if (numFail > 0) { 123 // We only care about the messages if they were errors 124 for (String msg : msgs) { 125 System.out.println(msg); 126 } 127 throw new Exception(numFail + " out of " + (numPass + numFail) 128 + " tests failed."); 129 } 130 } 131 132 public void assertTrue(boolean testResult, String testName) { 133 if (testResult) { 134 numPass++; 135 } else { 136 numFail++; 137 System.out.println("FAILED: " + testName 138 + " was supposed to return true but did NOT!"); 139 } 140 } 141 142 public void assertFalse(boolean testResult, String testName) { 143 if (!testResult) { 144 numPass++; 145 } else { 146 numFail++; 147 System.out.println("FAILED: " + testName 148 + " was supposed to return false but did NOT!"); 149 } 150 } 151 152 public boolean testGetBundleFromStackSearch() throws Throwable { 153 // This should fail. This was the old functionality to search up the 154 // caller's call stack 155 TwiceIndirectlyLoadABundle indirectLoader = new TwiceIndirectlyLoadABundle(); 156 return indirectLoader.loadAndTest(); 157 } 158 159 public boolean testGetBundleFromCallersClassLoader() throws Throwable { 160 // This should pass. This exercises getting the bundle using the 161 // class loader of the caller (one level up) 162 IndirectlyLoadABundle indirectLoader = new IndirectlyLoadABundle(); 163 return indirectLoader.loadAndTest(); 164 } 165 166 public boolean testGetBundleFromTCCL(String bundleName, 167 ClassLoader setOnTCCL) throws InterruptedException { 168 // This should succeed. We should be able to get the bundle from the 169 // thread context class loader 170 debug("Looking for " + bundleName + " using TCCL"); 171 LoggingThread lr = new LoggingThread(bundleName, setOnTCCL); 172 lr.start(); 173 synchronized (lr) { 174 try { 175 lr.wait(); 176 } catch (InterruptedException ex) { 177 throw ex; 178 } 179 } 180 msgs.add(lr.msg); 181 return lr.foundBundle; 182 } 183 184 /* 185 * @param String bundleClass 186 * @param ClassLoader to use for search 187 * @return true iff bundleClass is on system classpath 188 */ 189 public static boolean isOnClassPath(String baseName, ClassLoader cl) { 190 ResourceBundle rb = null; 191 try { 192 rb = ResourceBundle.getBundle(baseName, Locale.getDefault(), cl); 193 System.out.println("INFO: Found bundle " + baseName + " on " + cl); 194 } catch (MissingResourceException e) { 195 System.out.println("INFO: Could not find bundle " + baseName + " on " + cl); 196 return false; 197 } 198 return (rb != null); 199 } 200 201 private static String newLoggerName() { 202 // we need a new logger name every time we attempt to find a bundle via 203 // the Logger.getLogger call, so we'll simply tack on an integer which 204 // we increment each time this is called 205 loggerNum++; 206 return LOGGER_PREFIX + loggerNum; 207 } 208 209 public boolean testGetBundleFromSystemClassLoader(String bundleName) { 210 // this should succeed if the bundle is on the system classpath. 211 try { 212 Logger aLogger = Logger.getLogger(ResourceBundleSearchTest.newLoggerName(), 213 bundleName); 214 } catch (MissingResourceException re) { 215 msgs.add("INFO: testGetBundleFromSystemClassLoader() did not find bundle " 216 + bundleName); 217 return false; 218 } 219 msgs.add("INFO: testGetBundleFromSystemClassLoader() found the bundle " 220 + bundleName); 221 return true; 222 } 223 224 private boolean testGetAnonymousLogger() throws Throwable { 225 // This should pass. This exercises getting the bundle using the 226 // class loader of the caller (one level up) when calling 227 // Logger.getAnonymousLogger(String rbName) 228 IndirectlyLoadABundle indirectLoader = new IndirectlyLoadABundle(); 229 return indirectLoader.testGetAnonymousLogger(); 230 } 231 232 private boolean testGetBundleFromSecondCallersClassLoader() throws Throwable { 233 // This should pass. This exercises getting the bundle using the 234 // class loader of the caller (one level up) 235 IndirectlyLoadABundle indirectLoader = new IndirectlyLoadABundle(); 236 return indirectLoader.testGetLoggerGetLoggerWithBundle(); 237 } 238 239 public static class LoggingThread extends Thread { 240 241 boolean foundBundle = false; 242 String msg = null; 243 ClassLoader clToSetOnTCCL = null; 244 String bundleName = null; 245 246 public LoggingThread(String bundleName) { 247 this.bundleName = bundleName; 248 } 249 250 public LoggingThread(String bundleName, ClassLoader setOnTCCL) { 251 this.clToSetOnTCCL = setOnTCCL; 252 this.bundleName = bundleName; 253 } 254 255 public void run() { 256 boolean setTCCL = false; 257 try { 258 if (clToSetOnTCCL != null) { 259 Thread.currentThread().setContextClassLoader(clToSetOnTCCL); 260 setTCCL = true; 261 } 262 // this should succeed if the bundle is on the system classpath. 263 try { 264 Logger aLogger = Logger.getLogger(ResourceBundleSearchTest.newLoggerName(), 265 bundleName); 266 msg = "INFO: LoggingThread.run() found the bundle " + bundleName 267 + (setTCCL ? " with " : " without ") + "setting the TCCL"; 268 foundBundle = true; 269 } catch (MissingResourceException re) { 270 msg = "INFO: LoggingThread.run() did not find the bundle " + bundleName 271 + (setTCCL ? " with " : " without ") + "setting the TCCL"; 272 foundBundle = false; 273 } 274 } catch (Throwable e) { 275 e.printStackTrace(); 276 System.exit(1); 277 } 278 } 279 } 280 281 private void debug(String msg) { 282 if (DEBUG) { 283 System.out.println(msg); 284 } 285 } 286 }