1 /* 2 * Copyright (c) 1998, 2012, 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 * 26 * 27 * @author Adrian Colley 28 * @author Laird Dornin 29 * @author Peter Jones 30 * @author Ann Wollrath 31 * 32 * The rmi library directory contains a set of simple utiltity classes 33 * for use in rmi regression tests. 34 * 35 * NOTE: The JavaTest group has recommended that regression tests do 36 * not make use of packages. 37 */ 38 39 import java.io.ByteArrayOutputStream; 40 import java.io.File; 41 import java.io.FileInputStream; 42 import java.io.FileOutputStream; 43 import java.io.IOException; 44 import java.io.PrintStream; 45 import java.net.MalformedURLException; 46 import java.net.ServerSocket; 47 import java.net.URL; 48 import java.rmi.NoSuchObjectException; 49 import java.rmi.Remote; 50 import java.rmi.RemoteException; 51 import java.rmi.registry.LocateRegistry; 52 import java.rmi.registry.Registry; 53 import java.rmi.server.ExportException; 54 import java.rmi.server.RemoteRef; 55 import java.rmi.server.UnicastRemoteObject; 56 import java.util.Enumeration; 57 import java.util.Properties; 58 import sun.rmi.registry.RegistryImpl; 59 import sun.rmi.server.UnicastServerRef; 60 import sun.rmi.transport.Endpoint; 61 import sun.rmi.transport.LiveRef; 62 import sun.rmi.transport.tcp.TCPEndpoint; 63 64 /** 65 * Class of utility/library methods (i.e. procedures) that assist with 66 * the writing and maintainance of rmi regression tests. 67 */ 68 public class TestLibrary { 69 /** 70 * IMPORTANT! 71 * 72 * RMI tests are run concurrently and port conflicts result when a single 73 * port number is used by multiple tests. When needing a port, use 74 * getUnusedRandomPort() wherever possible. If getUnusedRandomPort() cannot 75 * be used, reserve and specify a port to use for your test here. This 76 * will ensure there are no port conflicts amongst the RMI tests. The 77 * port numbers specified here may also be specified in the respective 78 * tests. Do not change the reserved port numbers here without also 79 * changing the port numbers in the respective tests. 80 * 81 * When needing an instance of the RMIRegistry, use 82 * createRegistryOnUnusedPort wherever possible to prevent port conflicts. 83 * 84 * Reserved port range: FIXED_PORT_MIN to FIXED_PORT_MAX (inclusive) for 85 * tests which cannot use a random port. If new fixed ports are added below 86 * FIXED_PORT_MIN or above FIXED_PORT_MAX, then adjust 87 * FIXED_PORT_MIN/MAX appropriately. 88 */ 89 public final static int FIXED_PORT_MIN = 64001; 90 public final static int FIXED_PORT_MAX = 64010; 91 public final static int RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT = 64001; 92 public final static int RMIDVIAINHERITEDCHANNEL_REGISTRY_PORT = 64002; 93 public final static int INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT = 64003; 94 public final static int INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT = 64004; 95 public final static int READTEST_REGISTRY_PORT = 64005; 96 97 static void mesg(Object mesg) { 98 System.err.println("TEST_LIBRARY: " + mesg.toString()); 99 } 100 101 /** 102 * Routines that enable rmi tests to fail in a uniformly 103 * informative fashion. 104 */ 105 public static void bomb(String message, Exception e) { 106 String testFailed = "TEST FAILED: "; 107 108 if ((message == null) && (e == null)) { 109 testFailed += " No relevant information"; 110 } else if (e == null) { 111 testFailed += message; 112 } 113 114 System.err.println(testFailed); 115 if (e != null) { 116 System.err.println("Test failed with: " + 117 e.getMessage()); 118 e.printStackTrace(System.err); 119 } 120 throw new TestFailedException(testFailed, e); 121 } 122 public static void bomb(String message) { 123 bomb(message, null); 124 } 125 public static void bomb(Exception e) { 126 bomb(null, e); 127 } 128 129 /** 130 * Property accessors 131 */ 132 private static boolean getBoolean(String name) { 133 return (new Boolean(getProperty(name, "false")).booleanValue()); 134 } 135 private static Integer getInteger(String name) { 136 int val = 0; 137 Integer value = null; 138 139 String propVal = getProperty(name, null); 140 if (propVal == null) { 141 return null; 142 } 143 144 try { 145 value = new Integer(Integer.parseInt(propVal)); 146 } catch (NumberFormatException nfe) { 147 } 148 return value; 149 } 150 public static String getProperty(String property, String defaultVal) { 151 final String prop = property; 152 final String def = defaultVal; 153 return ((String) java.security.AccessController.doPrivileged 154 (new java.security.PrivilegedAction() { 155 public Object run() { 156 return System.getProperty(prop, def); 157 } 158 })); 159 } 160 161 /** 162 * Property mutators 163 */ 164 public static void setBoolean(String property, boolean value) { 165 setProperty(property, (new Boolean(value)).toString()); 166 } 167 public static void setInteger(String property, int value) { 168 setProperty(property, Integer.toString(value)); 169 } 170 public static void setProperty(String property, String value) { 171 final String prop = property; 172 final String val = value; 173 java.security.AccessController.doPrivileged 174 (new java.security.PrivilegedAction() { 175 public Object run() { 176 System.setProperty(prop, val); 177 return null; 178 } 179 }); 180 } 181 182 /** 183 * Routines to print out a test's properties environment. 184 */ 185 public static void printEnvironment() { 186 printEnvironment(System.err); 187 } 188 public static void printEnvironment(PrintStream out) { 189 out.println("-------------------Test environment----------" + 190 "---------"); 191 192 for(Enumeration keys = System.getProperties().keys(); 193 keys.hasMoreElements();) { 194 195 String property = (String) keys.nextElement(); 196 out.println(property + " = " + getProperty(property, null)); 197 } 198 out.println("---------------------------------------------" + 199 "---------"); 200 } 201 202 /** 203 * Routine that "works-around" a limitation in jtreg. 204 * Currently it is not possible for a test to specify that the 205 * test harness should build a given source file and install the 206 * resulting class in a location that is not accessible from the 207 * test's classpath. This method enables a test to move a 208 * compiled test class file from the test's class directory into a 209 * given "codebase" directory. As a result the test can only 210 * access the class file for <code>className</code>if the test loads 211 * it from a classloader (e.g. RMIClassLoader). 212 * 213 * Tests that use this routine must have the following permissions 214 * granted to them: 215 * 216 * getProperty user.dir 217 * getProperty etc. 218 */ 219 public static URL installClassInCodebase(String className, 220 String codebase) 221 throws MalformedURLException 222 { 223 return installClassInCodebase(className, codebase, true); 224 } 225 226 public static URL installClassInCodebase(String className, 227 String codebase, 228 boolean delete) 229 throws MalformedURLException 230 { 231 /* 232 * NOTES/LIMITATIONS: The class must not be in a named package, 233 * and the codebase must be a relative path (it's created relative 234 * to the working directory). 235 */ 236 String classFileName = className + ".class"; 237 238 /* 239 * Specify the file to contain the class definition. Make sure 240 * that the codebase directory exists (underneath the working 241 * directory). 242 */ 243 File dstDir = (new File(getProperty("user.dir", "."), codebase)); 244 245 if (!dstDir.exists()) { 246 if (!dstDir.mkdir()) { 247 throw new RuntimeException( 248 "could not create codebase directory"); 249 } 250 } 251 File dstFile = new File(dstDir, classFileName); 252 253 /* 254 * Obtain the URL for the codebase. 255 */ 256 URL codebaseURL = dstDir.toURL(); 257 258 /* 259 * Specify where we will copy the class definition from, if 260 * necessary. After the test is built, the class file can be 261 * found in the "test.classes" directory. 262 */ 263 File srcDir = new File(getProperty("test.classes", ".")); 264 File srcFile = new File(srcDir, classFileName); 265 266 mesg(srcFile); 267 mesg(dstFile); 268 269 /* 270 * If the class definition is not already located at the codebase, 271 * copy it there from the test build area. 272 */ 273 if (!dstFile.exists()) { 274 if (!srcFile.exists()) { 275 throw new RuntimeException( 276 "could not find class file to install in codebase " + 277 "(try rebuilding the test): " + srcFile); 278 } 279 280 try { 281 copyFile(srcFile, dstFile); 282 } catch (IOException e) { 283 throw new RuntimeException( 284 "could not install class file in codebase"); 285 } 286 287 mesg("Installed class \"" + className + 288 "\" in codebase " + codebaseURL); 289 } 290 291 /* 292 * After the class definition is successfully installed at the 293 * codebase, delete it from the test's CLASSPATH, so that it will 294 * not be found there first before the codebase is searched. 295 */ 296 if (srcFile.exists()) { 297 if (delete && !srcFile.delete()) { 298 throw new RuntimeException( 299 "could not delete duplicate class file in CLASSPATH"); 300 } 301 } 302 303 return codebaseURL; 304 } 305 306 public static void copyFile(File srcFile, File dstFile) 307 throws IOException 308 { 309 FileInputStream src = new FileInputStream(srcFile); 310 FileOutputStream dst = new FileOutputStream(dstFile); 311 312 byte[] buf = new byte[32768]; 313 while (true) { 314 int count = src.read(buf); 315 if (count < 0) { 316 break; 317 } 318 dst.write(buf, 0, count); 319 } 320 321 dst.close(); 322 src.close(); 323 } 324 325 /** routine to unexport an object */ 326 public static void unexport(Remote obj) { 327 if (obj != null) { 328 try { 329 mesg("unexporting object..."); 330 UnicastRemoteObject.unexportObject(obj, true); 331 } catch (NoSuchObjectException munch) { 332 } catch (Exception e) { 333 e.getMessage(); 334 e.printStackTrace(); 335 } 336 } 337 } 338 339 /** 340 * Allow test framework to control the security manager set in 341 * each test. 342 * 343 * @param managerClassName The class name of the security manager 344 * to be instantiated and set if no security 345 * manager has already been set. 346 */ 347 public static void suggestSecurityManager(String managerClassName) { 348 SecurityManager manager = null; 349 350 if (System.getSecurityManager() == null) { 351 try { 352 if (managerClassName == null) { 353 managerClassName = TestParams.defaultSecurityManager; 354 } 355 manager = ((SecurityManager) Class. 356 forName(managerClassName).newInstance()); 357 } catch (ClassNotFoundException cnfe) { 358 bomb("Security manager could not be found: " + 359 managerClassName, cnfe); 360 } catch (Exception e) { 361 bomb("Error creating security manager. ", e); 362 } 363 364 System.setSecurityManager(manager); 365 } 366 } 367 368 /** 369 * Creates an RMI {@link Registry} on a random port. 370 * 371 * @returns an RMI Registry, using a random port. 372 * @throws RemoteException if there was a problem creating a Registry. 373 */ 374 public static Registry createRegistryOnUnusedPort() throws RemoteException { 375 Registry registry = null; 376 377 try { 378 registry = LocateRegistry.createRegistry(0); 379 } catch (ExportException ee) { 380 // If we have an ExportException, it's becuase there's already a 381 // registry which was created using 382 // LocateRegistry.createRegistry(0) running in this VM. Try 383 // getting a random port and creating the registry using the 384 // random port instead. 385 int port = getUnusedRandomPort(); 386 387 try { 388 registry = LocateRegistry.createRegistry(port); 389 } catch(RemoteException re) { 390 throw new RemoteException("Could not create registry."); 391 } 392 } catch (Exception ex) { 393 throw new RemoteException("Could not create registry."); 394 } 395 396 return registry; 397 } 398 399 /** 400 * Returns the port number the RMI {@link Registry} is running on. 401 * 402 * @param registry the registry to find the port of. 403 * @return the port number the registry is using. 404 * @throws NullPointerException if registry is {@code null}. 405 * @throws RuntimeException if there was a problem getting the port number. 406 */ 407 public static int getRegistryPort(Registry registry) { 408 int port = -1; 409 410 try { 411 RemoteRef remoteRef = ((RegistryImpl)registry).getRef(); 412 LiveRef liveRef = ((UnicastServerRef)remoteRef).getLiveRef(); 413 Endpoint endpoint = liveRef.getChannel().getEndpoint(); 414 TCPEndpoint tcpEndpoint = (TCPEndpoint) endpoint; 415 port = tcpEndpoint.getPort(); 416 } catch (Exception ex) { 417 throw new RuntimeException("Error getting registry port."); 418 } 419 420 return port; 421 } 422 423 /** 424 * Returns an unused random port number less than FIXED_PORT_MIN and greater 425 * than FIXED_PORT_MAX. Will try up to 10 times to get a random port before 426 * giving up and throwing a RuntimeException. 427 * 428 * @return an unused random port number. 429 * @throws RuntimeException if there was a problem getting a port. 430 */ 431 public static int getUnusedRandomPort() { 432 int numTries = 0; 433 int unusedRandomPort = FIXED_PORT_MIN; 434 435 while ((numTries++ < 10) && ((unusedRandomPort >= FIXED_PORT_MIN) && 436 (unusedRandomPort <= FIXED_PORT_MAX))) 437 { 438 try (ServerSocket ss = new ServerSocket(0)) { 439 unusedRandomPort = ss.getLocalPort(); 440 } catch (Exception e) { 441 // Do nothing 442 } 443 } 444 445 if ((unusedRandomPort >= FIXED_PORT_MIN) && 446 (unusedRandomPort <= FIXED_PORT_MAX)) 447 { 448 throw new RuntimeException("Error getting unused random port."); 449 } 450 451 return unusedRandomPort; 452 } 453 454 /** 455 * Method to capture the stack trace of an exception and return it 456 * as a string. 457 */ 458 public String stackTraceToString(Exception e) { 459 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 460 PrintStream ps = new PrintStream(bos); 461 462 e.printStackTrace(ps); 463 return bos.toString(); 464 } 465 466 /** extra properties */ 467 private static Properties props; 468 469 /** 470 * Returns extra test properties. Looks for the file "../../test.props" 471 * and reads it in as a Properties file. Assuming the working directory 472 * is "<path>/JTwork/scratch", this will find "<path>/test.props". 473 */ 474 private static synchronized Properties getExtraProperties() { 475 if (props != null) { 476 return props; 477 } 478 props = new Properties(); 479 File f = new File(".." + File.separator + ".." + File.separator + 480 "test.props"); 481 if (!f.exists()) { 482 return props; 483 } 484 try { 485 FileInputStream in = new FileInputStream(f); 486 try { 487 props.load(in); 488 } finally { 489 in.close(); 490 } 491 } catch (IOException e) { 492 e.printStackTrace(); 493 throw new RuntimeException("extra property setup failed", e); 494 } 495 return props; 496 } 497 498 /** 499 * Returns an extra test property. Looks for the file "../../test.props" 500 * and reads it in as a Properties file. Assuming the working directory 501 * is "<path>/JTwork/scratch", this will find "<path>/test.props". 502 * If the property isn't found, defaultVal is returned. 503 */ 504 public static String getExtraProperty(String property, String defaultVal) { 505 return getExtraProperties().getProperty(property, defaultVal); 506 } 507 }