1 /*
   2  * Copyright (c) 1998, 2003, 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.File;
  40 import java.io.FileInputStream;
  41 import java.io.FileOutputStream;
  42 import java.io.IOException;
  43 import java.io.OutputStream;
  44 import java.io.PrintStream;
  45 import java.net.URL;
  46 import java.net.MalformedURLException;
  47 import java.rmi.activation.Activatable;
  48 import java.rmi.activation.ActivationID;
  49 import java.rmi.NoSuchObjectException;
  50 import java.rmi.registry.Registry;
  51 import java.rmi.Remote;
  52 import java.rmi.server.UnicastRemoteObject;
  53 import java.util.Enumeration;
  54 import java.util.Hashtable;
  55 import java.util.Properties;
  56 import java.io.ByteArrayOutputStream;
  57 import java.security.AccessController;
  58 import java.security.PrivilegedAction;
  59 
  60 /**
  61  * Class of utility/library methods (i.e. procedures) that assist with
  62  * the writing and maintainance of rmi regression tests.
  63  */
  64 public class TestLibrary {
  65 
  66     /** standard test port number for registry */
  67     public final static int REGISTRY_PORT = 2006;
  68     /** port for rmid necessary: not used to actually start rmid */
  69     public final static int RMID_PORT = 1098;
  70 
  71     static void mesg(Object mesg) {
  72         System.err.println("TEST_LIBRARY: " + mesg.toString());
  73     }
  74 
  75     /**
  76      * Routines that enable rmi tests to fail in a uniformly
  77      * informative fashion.
  78      */
  79     public static void bomb(String message, Exception e) {
  80         String testFailed = "TEST FAILED: ";
  81 
  82         if ((message == null) && (e == null)) {
  83             testFailed += " No relevant information";
  84         } else if (e == null) {
  85             testFailed += message;
  86         }
  87 
  88         System.err.println(testFailed);
  89         if (e != null) {
  90             System.err.println("Test failed with: " +
  91                                e.getMessage());
  92             e.printStackTrace(System.err);
  93         }
  94         throw new TestFailedException(testFailed, e);
  95     }
  96     public static void bomb(String message) {
  97         bomb(message, null);
  98     }
  99     public static void bomb(Exception e) {
 100         bomb(null, e);
 101     }
 102 
 103     /**
 104      * Property accessors
 105      */
 106     private static boolean getBoolean(String name) {
 107         return (new Boolean(getProperty(name, "false")).booleanValue());
 108     }
 109     private static Integer getInteger(String name) {
 110         int val = 0;
 111         Integer value = null;
 112 
 113         String propVal = getProperty(name, null);
 114         if (propVal == null) {
 115             return null;
 116         }
 117 
 118         try {
 119             value = new Integer(Integer.parseInt(propVal));
 120         } catch (NumberFormatException nfe) {
 121         }
 122         return value;
 123     }
 124     public static String getProperty(String property, String defaultVal) {
 125         final String prop = property;
 126         final String def = defaultVal;
 127         return ((String) java.security.AccessController.doPrivileged
 128             (new java.security.PrivilegedAction() {
 129                 public Object run() {
 130                     return System.getProperty(prop, def);
 131                 }
 132             }));
 133     }
 134 
 135     /**
 136      * Property mutators
 137      */
 138     public static void setBoolean(String property, boolean value) {
 139         setProperty(property, (new Boolean(value)).toString());
 140     }
 141     public static void setInteger(String property, int value) {
 142         setProperty(property, Integer.toString(value));
 143     }
 144     public static void setProperty(String property, String value) {
 145         final String prop = property;
 146         final String val = value;
 147         java.security.AccessController.doPrivileged
 148             (new java.security.PrivilegedAction() {
 149                 public Object run() {
 150                     System.setProperty(prop, val);
 151                     return null;
 152                 }
 153         });
 154     }
 155 
 156     /**
 157      * Routines to print out a test's properties environment.
 158      */
 159     public static void printEnvironment() {
 160         printEnvironment(System.err);
 161     }
 162     public static void printEnvironment(PrintStream out) {
 163         out.println("-------------------Test environment----------" +
 164                     "---------");
 165 
 166         for(Enumeration keys = System.getProperties().keys();
 167             keys.hasMoreElements();) {
 168 
 169             String property = (String) keys.nextElement();
 170             out.println(property + " = " + getProperty(property, null));
 171         }
 172         out.println("---------------------------------------------" +
 173                     "---------");
 174     }
 175 
 176     /**
 177      * Routine that "works-around" a limitation in jtreg.
 178      * Currently it is not possible for a test to specify that the
 179      * test harness should build a given source file and install the
 180      * resulting class in a location that is not accessible from the
 181      * test's classpath.  This method enables a test to move a
 182      * compiled test class file from the test's class directory into a
 183      * given "codebase" directory.  As a result the test can only
 184      * access the class file for <code>className</code>if the test loads
 185      * it from a classloader (e.g. RMIClassLoader).
 186      *
 187      * Tests that use this routine must have the following permissions
 188      * granted to them:
 189      *
 190      *   getProperty user.dir
 191      *   getProperty etc.
 192      */
 193     public static URL installClassInCodebase(String className,
 194                                              String codebase)
 195         throws MalformedURLException
 196     {
 197         return installClassInCodebase(className, codebase, true);
 198     }
 199 
 200     public static URL installClassInCodebase(String className,
 201                                              String codebase,
 202                                              boolean delete)
 203         throws MalformedURLException
 204     {
 205         /*
 206          * NOTES/LIMITATIONS: The class must not be in a named package,
 207          * and the codebase must be a relative path (it's created relative
 208          * to the working directory).
 209          */
 210         String classFileName = className + ".class";
 211 
 212         /*
 213          * Specify the file to contain the class definition.  Make sure
 214          * that the codebase directory exists (underneath the working
 215          * directory).
 216          */
 217         File dstDir = (new File(getProperty("user.dir", "."), codebase));
 218 
 219         if (!dstDir.exists()) {
 220             if (!dstDir.mkdir()) {
 221                 throw new RuntimeException(
 222                     "could not create codebase directory");
 223             }
 224         }
 225         File dstFile = new File(dstDir, classFileName);
 226 
 227         /*
 228          * Obtain the URL for the codebase.
 229          */
 230         URL codebaseURL = dstDir.toURL();
 231 
 232         /*
 233          * Specify where we will copy the class definition from, if
 234          * necessary.  After the test is built, the class file can be
 235          * found in the "test.classes" directory.
 236          */
 237         File srcDir = new File(getProperty("test.classes", "."));
 238         File srcFile = new File(srcDir, classFileName);
 239 
 240         mesg(srcFile);
 241         mesg(dstFile);
 242 
 243         /*
 244          * If the class definition is not already located at the codebase,
 245          * copy it there from the test build area.
 246          */
 247         if (!dstFile.exists()) {
 248             if (!srcFile.exists()) {
 249                 throw new RuntimeException(
 250                     "could not find class file to install in codebase " +
 251                     "(try rebuilding the test): " + srcFile);
 252             }
 253 
 254             try {
 255                 copyFile(srcFile, dstFile);
 256             } catch (IOException e) {
 257                 throw new RuntimeException(
 258                     "could not install class file in codebase");
 259             }
 260 
 261             mesg("Installed class \"" + className +
 262                 "\" in codebase " + codebaseURL);
 263         }
 264 
 265         /*
 266          * After the class definition is successfully installed at the
 267          * codebase, delete it from the test's CLASSPATH, so that it will
 268          * not be found there first before the codebase is searched.
 269          */
 270         if (srcFile.exists()) {
 271             if (delete && !srcFile.delete()) {
 272                 throw new RuntimeException(
 273                     "could not delete duplicate class file in CLASSPATH");
 274             }
 275         }
 276 
 277         return codebaseURL;
 278     }
 279 
 280     public static void copyFile(File srcFile, File dstFile)
 281         throws IOException
 282     {
 283         FileInputStream src = new FileInputStream(srcFile);
 284         FileOutputStream dst = new FileOutputStream(dstFile);
 285 
 286         byte[] buf = new byte[32768];
 287         while (true) {
 288             int count = src.read(buf);
 289             if (count < 0) {
 290                 break;
 291             }
 292             dst.write(buf, 0, count);
 293         }
 294 
 295         dst.close();
 296         src.close();
 297     }
 298 
 299     /** routine to unexport an object */
 300     public static void unexport(Remote obj) {
 301         if (obj != null) {
 302             try {
 303                 mesg("unexporting object...");
 304                 UnicastRemoteObject.unexportObject(obj, true);
 305             } catch (NoSuchObjectException munch) {
 306             } catch (Exception e) {
 307                 e.getMessage();
 308                 e.printStackTrace();
 309             }
 310         }
 311     }
 312 
 313     /**
 314      * Allow test framework to control the security manager set in
 315      * each test.
 316      *
 317      * @param managerClassName The class name of the security manager
 318      *                         to be instantiated and set if no security
 319      *                         manager has already been set.
 320      */
 321     public static void suggestSecurityManager(String managerClassName) {
 322         SecurityManager manager = null;
 323 
 324         if (System.getSecurityManager() == null) {
 325             try {
 326                 if (managerClassName == null) {
 327                     managerClassName = TestParams.defaultSecurityManager;
 328                 }
 329                 manager = ((SecurityManager) Class.
 330                            forName(managerClassName).newInstance());
 331             } catch (ClassNotFoundException cnfe) {
 332                 bomb("Security manager could not be found: " +
 333                      managerClassName, cnfe);
 334             } catch (Exception e) {
 335                 bomb("Error creating security manager. ", e);
 336             }
 337 
 338             System.setSecurityManager(manager);
 339         }
 340     }
 341 
 342     /**
 343      * Method to capture the stack trace of an exception and return it
 344      * as a string.
 345      */
 346     public String stackTraceToString(Exception e) {
 347         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 348         PrintStream ps = new PrintStream(bos);
 349 
 350         e.printStackTrace(ps);
 351         return bos.toString();
 352     }
 353 
 354     /** extra properties */
 355     private static Properties props;
 356 
 357     /**
 358      * Returns extra test properties. Looks for the file "../../test.props"
 359      * and reads it in as a Properties file. Assuming the working directory
 360      * is "<path>/JTwork/scratch", this will find "<path>/test.props".
 361      */
 362     private static synchronized Properties getExtraProperties() {
 363         if (props != null) {
 364             return props;
 365         }
 366         props = new Properties();
 367         File f = new File(".." + File.separator + ".." + File.separator +
 368                           "test.props");
 369         if (!f.exists()) {
 370             return props;
 371         }
 372         try {
 373             FileInputStream in = new FileInputStream(f);
 374             try {
 375                 props.load(in);
 376             } finally {
 377                 in.close();
 378             }
 379         } catch (IOException e) {
 380             e.printStackTrace();
 381             throw new RuntimeException("extra property setup failed", e);
 382         }
 383         return props;
 384     }
 385 
 386     /**
 387      * Returns an extra test property. Looks for the file "../../test.props"
 388      * and reads it in as a Properties file. Assuming the working directory
 389      * is "<path>/JTwork/scratch", this will find "<path>/test.props".
 390      * If the property isn't found, defaultVal is returned.
 391      */
 392     public static String getExtraProperty(String property, String defaultVal) {
 393         return getExtraProperties().getProperty(property, defaultVal);
 394     }
 395 }