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 // This test has been falling in timeout - so we're adding some 61 // time stamp here and there to help diagnose whether it's a 62 // simple system slowness or whether there's a deeper issue, 63 // like a deadlock. The timeout issue should be fixed now, 64 // but we leave the time stamps in case it reappears. 65 // 66 static final long stamp = System.currentTimeMillis(); 67 private static String newDate(long time) { 68 long delta = time - stamp; 69 long min = delta/60000; 70 long sec = (delta - min * 60000) / 10000; 71 long msec = delta - min * 60000 - sec * 1000; 72 return (min == 0 ? "" : (min + " min. ")) + 73 (sec == 0 ? "" : (sec + " sec. ")) + 74 (msec == 0 ? "" : (msec + "ms.")); 75 } 76 77 public static void main(String[] args) throws Throwable { 78 System.out.println("ResourceBundleSearchTest starting: "+newDate(System.currentTimeMillis())); 79 ResourceBundleSearchTest test = new ResourceBundleSearchTest(); 80 try { 81 test.runTests(); 82 } finally { 83 System.out.println("ResourceBundleSearchTest terminated: "+newDate(System.currentTimeMillis())); 84 } 85 } 86 87 private void runTests() throws Throwable { 88 // ensure we are using en as the default Locale so we can find the resource 89 Locale.setDefault(Locale.ENGLISH); 90 91 ClassLoader myClassLoader = ClassLoader.getSystemClassLoader(); 92 93 // Find out where we are running from so we can setup the URLClassLoader URL 94 String userDir = System.getProperty("user.dir"); 95 String testDir = System.getProperty("test.src", userDir); 96 97 URL[] urls = new URL[1]; 98 99 urls[0] = Paths.get(testDir, "resources").toUri().toURL(); 100 URLClassLoader rbClassLoader = new URLClassLoader(urls); 101 102 int testnb = 1; 103 System.out.println("ResourceBundleSearchTest starting test #"+(testnb++)+": "+newDate(System.currentTimeMillis())); 104 // Test 1 - can we find a Logger bundle from doing a stack search? 105 // We shouldn't be able to 106 assertFalse(testGetBundleFromStackSearch(), "1-testGetBundleFromStackSearch"); 107 108 System.out.println("ResourceBundleSearchTest starting test #"+(testnb++)+": "+newDate(System.currentTimeMillis())); 109 // Test 2 - can we find a Logger bundle off of the Thread context class 110 // loader? We should be able to. 111 assertTrue(testGetBundleFromTCCL(TCCL_TEST_BUNDLE, rbClassLoader), 112 "2-testGetBundleFromTCCL"); 113 114 System.out.println("ResourceBundleSearchTest starting test #"+(testnb++)+": "+newDate(System.currentTimeMillis())); 115 // Test 3 - Can we find a Logger bundle from the classpath? We should be 116 // able to. We'll first check to make sure the setup is correct and 117 // it actually is on the classpath before checking whether logging 118 // can see it there. 119 if (isOnClassPath(PROP_RB_NAME, myClassLoader)) { 120 debug("We should be able to see " + PROP_RB_NAME + " on the classpath"); 121 assertTrue(testGetBundleFromSystemClassLoader(PROP_RB_NAME), 122 "3-testGetBundleFromSystemClassLoader"); 123 } else { 124 throw new Exception("TEST SETUP FAILURE: Cannot see " + PROP_RB_NAME 125 + " on the classpath"); 126 } 127 128 System.out.println("ResourceBundleSearchTest starting test #"+(testnb++)+": "+newDate(System.currentTimeMillis())); 129 // Test 4 - we should be able to find a bundle from the caller's 130 // classloader, but only one level up. 131 assertTrue(testGetBundleFromCallersClassLoader(), 132 "4-testGetBundleFromCallersClassLoader"); 133 134 System.out.println("ResourceBundleSearchTest starting test #"+(testnb++)+": "+newDate(System.currentTimeMillis())); 135 // Test 5 - this ensures that getAnonymousLogger(String rbName) 136 // can find the bundle from the caller's classloader 137 assertTrue(testGetAnonymousLogger(), "5-testGetAnonymousLogger"); 138 139 System.out.println("ResourceBundleSearchTest starting test #"+(testnb++)+": "+newDate(System.currentTimeMillis())); 140 // Test 6 - first call getLogger("myLogger"). 141 // Then call getLogger("myLogger","bundleName") from a different ClassLoader 142 // Make sure we find the bundle 143 assertTrue(testGetBundleFromSecondCallersClassLoader(), 144 "6-testGetBundleFromSecondCallersClassLoader"); 145 146 System.out.println("ResourceBundleSearchTest generating report"); 147 report(); 148 } 149 150 private void report() throws Exception { 151 System.out.println("Num passed = " + numPass + " Num failed = " + numFail); 152 if (numFail > 0) { 153 // We only care about the messages if they were errors 154 for (String msg : msgs) { 155 System.out.println(msg); 156 } 157 throw new Exception(numFail + " out of " + (numPass + numFail) 158 + " tests failed."); 159 } 160 } 161 162 public void assertTrue(boolean testResult, String testName) { 163 if (testResult) { 164 numPass++; 165 System.out.println("PASSED: " + testName); 166 } else { 167 numFail++; 168 System.out.println("FAILED: " + testName 169 + " was supposed to return true but did NOT!"); 170 } 171 } 172 173 public void assertFalse(boolean testResult, String testName) { 174 if (!testResult) { 175 numPass++; 176 System.out.println("PASSED: " + testName); 177 } else { 178 numFail++; 179 System.out.println("FAILED: " + testName 180 + " was supposed to return false but did NOT!"); 181 } 182 } 183 184 public boolean testGetBundleFromStackSearch() throws Throwable { 185 // This should fail. This was the old functionality to search up the 186 // caller's call stack 187 TwiceIndirectlyLoadABundle indirectLoader = new TwiceIndirectlyLoadABundle(); 188 return indirectLoader.loadAndTest(); 189 } 190 191 public boolean testGetBundleFromCallersClassLoader() throws Throwable { 192 // This should pass. This exercises getting the bundle using the 193 // class loader of the caller (one level up) 194 IndirectlyLoadABundle indirectLoader = new IndirectlyLoadABundle(); 195 return indirectLoader.loadAndTest(); 196 } 197 198 public boolean testGetBundleFromTCCL(String bundleName, 199 ClassLoader setOnTCCL) throws InterruptedException { 200 // This should succeed. We should be able to get the bundle from the 201 // thread context class loader 202 debug("Looking for " + bundleName + " using TCCL"); 203 LoggingThread lr = new LoggingThread(bundleName, setOnTCCL); 204 lr.start(); 205 try { 206 lr.join(); 207 } catch (InterruptedException ex) { 208 throw ex; 209 } 210 msgs.add(lr.msg); 211 return lr.foundBundle; 212 } 213 214 /* 215 * @param String bundleClass 216 * @param ClassLoader to use for search 217 * @return true iff bundleClass is on system classpath 218 */ 219 public static boolean isOnClassPath(String baseName, ClassLoader cl) { 220 ResourceBundle rb = null; 221 try { 222 rb = ResourceBundle.getBundle(baseName, Locale.getDefault(), cl); 223 System.out.println("INFO: Found bundle " + baseName + " on " + cl); 224 } catch (MissingResourceException e) { 225 System.out.println("INFO: Could not find bundle " + baseName + " on " + cl); 226 return false; 227 } 228 return (rb != null); 229 } 230 231 private static String newLoggerName() { 232 // we need a new logger name every time we attempt to find a bundle via 233 // the Logger.getLogger call, so we'll simply tack on an integer which 234 // we increment each time this is called 235 loggerNum++; 236 return LOGGER_PREFIX + loggerNum; 237 } 238 239 public boolean testGetBundleFromSystemClassLoader(String bundleName) { 240 // this should succeed if the bundle is on the system classpath. 241 try { 242 Logger aLogger = Logger.getLogger(ResourceBundleSearchTest.newLoggerName(), 243 bundleName); 244 } catch (MissingResourceException re) { 245 msgs.add("INFO: testGetBundleFromSystemClassLoader() did not find bundle " 246 + bundleName); 247 return false; 248 } 249 msgs.add("INFO: testGetBundleFromSystemClassLoader() found the bundle " 250 + bundleName); 251 return true; 252 } 253 254 private boolean testGetAnonymousLogger() throws Throwable { 255 // This should pass. This exercises getting the bundle using the 256 // class loader of the caller (one level up) when calling 257 // Logger.getAnonymousLogger(String rbName) 258 IndirectlyLoadABundle indirectLoader = new IndirectlyLoadABundle(); 259 return indirectLoader.testGetAnonymousLogger(); 260 } 261 262 private boolean testGetBundleFromSecondCallersClassLoader() throws Throwable { 263 // This should pass. This exercises getting the bundle using the 264 // class loader of the caller (one level up) 265 IndirectlyLoadABundle indirectLoader = new IndirectlyLoadABundle(); 266 return indirectLoader.testGetLoggerGetLoggerWithBundle(); 267 } 268 269 public static class LoggingThread extends Thread { 270 271 boolean foundBundle = false; 272 String msg = null; 273 ClassLoader clToSetOnTCCL = null; 274 String bundleName = null; 275 276 public LoggingThread(String bundleName) { 277 this.bundleName = bundleName; 278 } 279 280 public LoggingThread(String bundleName, ClassLoader setOnTCCL) { 281 this.clToSetOnTCCL = setOnTCCL; 282 this.bundleName = bundleName; 283 } 284 285 public void run() { 286 boolean setTCCL = false; 287 try { 288 if (clToSetOnTCCL != null) { 289 Thread.currentThread().setContextClassLoader(clToSetOnTCCL); 290 setTCCL = true; 291 } 292 // this should succeed if the bundle is on the system classpath. 293 try { 294 Logger aLogger = Logger.getLogger(ResourceBundleSearchTest.newLoggerName(), 295 bundleName); 296 msg = "INFO: LoggingThread.run() found the bundle " + bundleName 297 + (setTCCL ? " with " : " without ") + "setting the TCCL"; 298 foundBundle = true; 299 } catch (MissingResourceException re) { 300 msg = "INFO: LoggingThread.run() did not find the bundle " + bundleName 301 + (setTCCL ? " with " : " without ") + "setting the TCCL"; 302 foundBundle = false; 303 } 304 } catch (Throwable e) { 305 e.printStackTrace(); 306 System.exit(1); 307 } 308 } 309 } 310 311 private void debug(String msg) { 312 if (DEBUG) { 313 System.out.println(msg); 314 } 315 } 316 }