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