< prev index next >

src/com/sun/javatest/TestSuite.java

Print this page
rev 145 : 7902237: Fixing raw use of parameterized class
Reviewed-by: jjg


 199         try {
 200             canonRoot = root.getCanonicalFile();
 201         }
 202         catch (IOException e) {
 203             throw new Fault(i18n, "ts.cantCanonicalize",
 204                             new Object[] {root.getPath(), e.toString()});
 205         }
 206 
 207         File canonRootDir;
 208         if (canonRoot.isDirectory())
 209             canonRootDir = canonRoot;
 210         else {
 211             if (canonRoot.getName().equalsIgnoreCase(TESTSUITE_HTML))
 212                 canonRootDir = canonRoot.getParentFile();
 213             else
 214                 throw new NotTestSuiteFault(i18n, "ts.notTestSuiteFile", canonRoot);
 215         }
 216 
 217         File f = new File(canonRootDir, TESTSUITE_JTT);
 218         if (isReadableFile(f)) {
 219             try {
 220                 Properties p = new Properties();
 221                 InputStream in = new BufferedInputStream(new FileInputStream(f));
 222                 p.load(in);
 223                 in.close();
 224                 return open(canonRoot, p);
 225             }
 226             catch (IOException e) {
 227                 throw new Fault(i18n, "ts.cantReadTestSuiteFile", e.toString());
 228             }
 229         }
 230         else {
 231             // check for old style test suite
 232             File ts_html = new File(canonRootDir, TESTSUITE_HTML);
 233             File parentDir = canonRootDir.getParentFile();
 234             File parent_jtt = (parentDir == null ? null : new File(parentDir, TESTSUITE_JTT));
 235             if (isReadableFile(ts_html) && (parent_jtt == null || !parent_jtt.exists()))
 236                 return open(canonRoot, new HashMap());
 237             else
 238                 throw new NotTestSuiteFault(i18n, "ts.notTestSuiteFile", canonRoot);
 239         }
 240     }
 241 
 242     /**
 243      * Open a test suite.
 244      * @param root A file identifying the root of the test suite.
 245      * @param tsInfo Test Suite properties read from the test suite properties file.
 246      * @return A TestSuite object for the test suite in question.
 247      * @throws TestSuite.Fault if any problems occur while opening the test suite
 248      */
 249     private static TestSuite open(File root, Map tsInfo) throws Fault {
 250         synchronized (dirMap) {
 251             TestSuite ts;
 252 
 253             // if this test suite has already been opened, return that
 254             WeakReference<TestSuite> ref = dirMap.get(root);
 255             if (ref != null) {
 256                 ts = ref.get();
 257                 if (ts != null) {
 258                     return ts;
 259                 }
 260             }
 261 
 262             // otherwise, open it for real
 263             ts = open0(root, tsInfo);
 264 
 265             // save reference in case opened again
 266             dirMap.put(root, new WeakReference<>(ts));
 267             return ts;
 268         }
 269     }
 270 
 271     private static TestSuite open0(File root, Map tsInfo) throws Fault {
 272         String[] classPath = StringArray.split((String) (tsInfo.get("classpath")));
 273 
 274         ClassLoader cl;
 275         if (classPath.length == 0)
 276             cl = null;
 277         else {
 278             try {
 279                 File rootDir = (root.isDirectory() ? root : root.getParentFile());
 280                 URL[] p = new URL[classPath.length];
 281                 for (int i = 0; i < classPath.length; i++) {
 282                     String cpi = classPath[i];
 283                     if (cpi.toLowerCase().startsWith("http:"))
 284                         p[i] = new URL(cpi);
 285                     else {
 286                         File f = new File(cpi);
 287                         if (!f.isAbsolute())
 288                             f = new File(rootDir, cpi);
 289                         p[i] = f.toURI().toURL();
 290                     }
 291                 }
 292                 cl = new URLClassLoader(p, TestSuite.class.getClassLoader());
 293             }
 294             catch (MalformedURLException e) {
 295                 throw new Fault(i18n, "ts.badClassPath",
 296                                 new Object[] {root, e.getMessage()});
 297             }
 298         }
 299 
 300         String[] tsClassAndArgs = StringArray.split((String) (tsInfo.get("testsuite")));
 301 
 302         TestSuite testSuite;
 303         if (tsClassAndArgs.length == 0)
 304             testSuite = new TestSuite(root, tsInfo, cl);
 305         else {
 306             String className = tsClassAndArgs[0];
 307 
 308             try {
 309                 Class c = loadClass(className, cl);
 310                 Class[] tsArgTypes = {File.class, Map.class, ClassLoader.class};
 311                 Object[] tsArgs = {root, tsInfo, cl};
 312                 testSuite = (TestSuite)(newInstance(c, tsArgTypes, tsArgs));
 313             }
 314             catch (ClassCastException e) {
 315                 throw new Fault(i18n, "ts.notASubtype",
 316                                 new Object[] {className, "testsuite", TestSuite.class.getName()});
 317             }
 318             catch (UnsupportedClassVersionError uce){
 319                 throw new Fault(i18n, "ts.compiledRecentVersion",
 320                         new Object[] {System.getProperty("java.version"), root.getPath()});
 321             }
 322 
 323             String[] args = new String[tsClassAndArgs.length - 1];
 324             System.arraycopy(tsClassAndArgs, 1, args, 0, args.length);
 325             testSuite.init(args);
 326         }
 327 
 328         // initialize test finder
 329         testSuite.setTestFinder(new TestFinderDecorator(testSuite.createTestFinder()));
 330 


 348         if (ref != null) {
 349             TestSuite ts = (TestSuite)(ref.get());
 350             if (ts != null) {
 351                 return ts;
 352             }
 353         }
 354 
 355         return null;
 356     }
 357      */
 358 
 359     /**
 360      * Create a TestSuite object.
 361      * @param root The root file for this test suite.
 362      * @param tsInfo Test suite properties, typically read from the test suite properties file
 363      * in the root directory of the test suite.
 364      * @param cl A class loader to be used to load additional classes as required,
 365      * typically using a class path defined in the test suite properties file.
 366      * @throws TestSuite.Fault if a problem occurs while creating this test suite.
 367      */
 368     public TestSuite(File root, Map tsInfo, ClassLoader cl) throws Fault {
 369         this.root = root;
 370         this.tsInfo = tsInfo;
 371         this.loader = cl;
 372 
 373         String kw = (tsInfo == null ? null : (String) (tsInfo.get("keywords")));
 374         keywords = (kw == null ? null : StringArray.split(kw));
 375     }
 376 
 377 
 378     /**
 379      * Create a TestSuite object, with no additional test suite properties and no
 380      * class loader.
 381      * @param root The root file for this test suite.
 382      */
 383     public TestSuite(File root) {
 384         this.root = root;
 385     }
 386 
 387     /**
 388      * Initialize this test suite, with args typically read from a .jtt file.
 389      * The default implementation does not recognize any arguments and always
 390      * throws an exception.
 391      * @param args an array of strings to initialize this test suite object
 392      * @throws TestSuite.Fault if there are any problems initializing the
 393      * test suite from the specified arguments.


 423     public File getRootDir() {
 424         return (root.isDirectory() ? root : new File(root.getParent()));
 425     }
 426 
 427     /**
 428      * Get the directory in the test suite that contains the tests.
 429      * By default, the following are checked:
 430      * <ol>
 431      * <li>The <code>tests</code> property in the test suite properties file.
 432      * If this entry is found, it must either identify an absolute filename, or
 433      * a directory relative to the test suite root directory, using '/' to
 434      * separate the components of the path.
 435      * <li>If the file <em>root</em><code>/tests/testsuite.html</code> exists,
 436      * the result is the directory <em>root</em><code>/tests</code>. This is
 437      * for compatibility with standard TCK layout.
 438      * <li>Otherwise, the result is the root directory of the test suite.
 439      * </ol>
 440      * @return the directory that contains the tests
 441      */
 442     public File getTestsDir() {
 443         String t = (String) (tsInfo == null ? null : tsInfo.get("tests"));
 444         if (t == null || t.length() == 0) {
 445             File rootDir = getRootDir();
 446             File testsDir = new File(rootDir, "tests");
 447             if (testsDir.isDirectory()) {
 448                 // if the tests directory exists, and there is no overriding
 449                 // testsuite.jtt entry, assume the tests dir is "tests/".
 450                 return testsDir;
 451             }
 452             // default
 453             return rootDir;
 454         }
 455         else {
 456             File f = new File(t);
 457             if (f.isAbsolute())
 458                 return f;
 459             else
 460                 return new File(getRootDir(), t.replace('/', File.separatorChar));
 461         }
 462     }
 463 


 534      * loader specified when the test suite was opened, if one was given;
 535      * otherwise, the system class loader will be used.
 536      *
 537      * The default implementation attempts to use a file <tt>testsuite.jtd</tt>
 538      * in the tests directory.  If found, a BinaryTestFinder will be created
 539      * using this file.  If it is not found, then it searches for a property
 540      * named <tt>finder</tt> in the test suite properties and will attempt to
 541      * instantiate that.  If no entry is found or it is blank, an
 542      * HTMLTestFinder is used, using whatever a basic settings HTMLTestFinder
 543      * initializes to.
 544      * @return a test finder to be used to read the tests in the test suite
 545      * @throws TestSuite.Fault if there is a problem creating the test finder
 546      * @see #getTestFinder
 547      * @see #setTestFinder
 548      * @see #getTestsDir
 549      */
 550     protected TestFinder createTestFinder() throws Fault {
 551         File testsDir = getTestsDir();
 552 
 553         // no BTF file; look for a finder=class args... entry
 554         String[] finderCmd = StringArray.split((String) (tsInfo.get("finder")));
 555         String finderClassName;
 556         String[] finderArgs = new String[0];
 557 
 558         if (finderCmd == null || finderCmd.length == 0) {
 559             //finderCmd = new String[] {HTMLTestFinder.class.getName()};
 560             finderCmd = null;   // ensure null for later use
 561             finderClassName = HTMLTestFinder.class.getName();
 562         }
 563         else {
 564             finderClassName = finderCmd[0];
 565 
 566             if (finderCmd.length > 1) {
 567                 finderArgs = new String[finderCmd.length - 1];
 568                 System.arraycopy(finderCmd, 1, finderArgs, 0, finderArgs.length);
 569             }
 570             else {
 571                 // finderArgs should remain empty array
 572             }
 573         }
 574 
 575         // first, try looking for testsuite.jtd
 576         String jtd = (String) (tsInfo.get("testsuite.jtd"));
 577         File jtdFile = (jtd == null ? new File(testsDir, "testsuite.jtd") : new File(root, jtd));
 578         if (jtdFile.exists()) {
 579             try {
 580                 // found a file for BinaryTestFinder
 581                 // only pass the finder class if it was not defaulted to HTMLTestFinder
 582                 return createBinaryTestFinder((finderCmd == null ? null : finderClassName),
 583                         finderArgs, testsDir, jtdFile);
 584             }
 585             catch (TestFinder.Fault e) {
 586                 // ignore, try to continue with normal finder
 587             }
 588             catch (Fault f) {
 589                 // ignore, try to continue with normal finder
 590             }
 591         }
 592 
 593         try {
 594             Class c = loadClass(finderClassName);
 595             TestFinder tf = (TestFinder) (newInstance(c));
 596             // called old deprecated entry till we know no-one cares
 597             //tf.init(finderArgs, testsRoot, null, null, tsInfo/*pass in env?*/);
 598             // this likely kills ExpandTestFinder, finally
 599             tf.init(finderArgs, testsDir, null, null, null/*pass in env?*/);
 600             return tf;
 601         }
 602         catch (ClassCastException e) {
 603             throw new Fault(i18n, "ts.notASubtype",
 604                             new Object[] {finderClassName, "finder", TestFinder.class.getName()});
 605         }
 606         catch (TestFinder.Fault e) {
 607             throw new Fault(i18n, "ts.errorInitFinder",
 608                             new Object[] {finderClassName, e.getMessage()});
 609         }
 610     }
 611 
 612     /**
 613      * In the case where a JTD file is found, attempt to load a binary test finder.
 614      * The default implementation attempts to use the finder property in the
 615      * test suite properties if it is a BinaryTestFinder subclass.
 616      *
 617      * @param finderClassName Finder class name to attempt to use as a BTF.  Null if
 618      *      the default BTF class should be used.
 619      * @param finderArgs Arguments to finder given from the test suite property.
 620      * @param testsDir Reference location to pass to finder.
 621      * @param jtdFile Location of the JTD file to give to the BTF.
 622      * @return The binary test finder which was created.
 623      * @throws com.sun.javatest.TestSuite.Fault
 624      * @throws com.sun.javatest.TestFinder.Fault
 625      * @see com.sun.javatest.TestFinder
 626      * @see com.sun.javatest.finder.BinaryTestFinder
 627      */
 628     protected TestFinder createBinaryTestFinder(String finderClassName,
 629             String finderArgs[], File testsDir, File jtdFile) throws Fault, TestFinder.Fault {
 630         try {
 631             TestFinder tf = null;
 632 
 633             if (finderClassName != null) {
 634                 Class c = loadClass(finderClassName);
 635                 tf = (TestFinder) (newInstance(c));
 636             }
 637 
 638             if (tf instanceof BinaryTestFinder) {
 639                 tf.init(finderArgs, testsDir, null, null, null);
 640                 return tf;
 641             }
 642             else {
 643                 return new BinaryTestFinder(testsDir, jtdFile);
 644             }
 645         }
 646         catch (ClassCastException e) {
 647             throw new Fault(i18n, "ts.notASubtype",
 648                             new Object[] {finderClassName, "finder", TestFinder.class.getName()});
 649         }
 650         catch (TestFinder.Fault e) {
 651             throw new Fault(i18n, "ts.errorInitFinder",
 652                             new Object[] {finderClassName, e.getMessage()});
 653         }
 654 


 680      * that is created.
 681      *
 682      * Note that the name of this method is "create", it is not recommended
 683      * that the value returned ever be re-used or cached for subsequent requests
 684      * to this method.
 685      * @param td The test description for the test to be executed.
 686      * @param exclTestCases Any test cases within the test that should not be executed.
 687      * @param scriptEnv Configuration data to be given to the test as necessary.
 688      * @param workDir A work directory in which to store the results of the test.
 689      * @param backupPolicy A policy object used to control how to backup any files that
 690      * might be overwritten.
 691      * @return a script to be used to execute the given test
 692      * @throws TestSuite.Fault if any errors occur while creating the script
 693      */
 694     public Script createScript(TestDescription td, String[] exclTestCases, TestEnvironment scriptEnv,
 695                                WorkDirectory workDir,
 696                                BackupPolicy backupPolicy) throws Fault {
 697         if (scriptClass == null) {
 698             String[] script = envLookup(scriptEnv, "script");
 699             if (script.length == 0)
 700                 script = StringArray.split((String) tsInfo.get("script"));
 701             if (script.length > 0) {
 702                 scriptClass = loadClass(script[0]);
 703                 if (!Script.class.isAssignableFrom(scriptClass)) {
 704                     throw new Fault(i18n, "ts.notASubtype",
 705                                     new Object[] {script[0], "script", Script.class.getName()});
 706                 }
 707                 scriptArgs = new String[script.length - 1];
 708                 System.arraycopy(script, 1, scriptArgs, 0, scriptArgs.length);
 709             }
 710             else {
 711                 // for backwards compatibility,
 712                 // see if KeywordScript is a reasonable default
 713                 boolean keywordScriptOK = false;
 714                 for (Iterator i = scriptEnv.keys().iterator(); i.hasNext() && !keywordScriptOK; ) {
 715                     String key = (String)(i.next());
 716                     keywordScriptOK = key.startsWith("script.");
 717                 }
 718                 if (keywordScriptOK) {
 719                     scriptClass = KeywordScript.class;
 720                     scriptArgs = new String[] { };
 721                 }
 722                 else {
 723                     throw new Fault(i18n, "ts.noScript");
 724                 }
 725             }
 726         }
 727 
 728         Script s = (Script)(newInstance(scriptClass));
 729         s.initArgs(scriptArgs);
 730         s.initTestDescription(td);
 731         s.initExcludedTestCases(exclTestCases);
 732         s.initTestEnvironment(scriptEnv);
 733         s.initWorkDir(workDir);
 734         s.initBackupPolicy(backupPolicy);
 735         s.initClassLoader(loader);


 741      * data for a test run.
 742      * <p>The default implementation returns a {@link LegacyParameters default}
 743      * interview suitable for use with test suites built with earlier versions
 744      * of the JT Harness: it provides questions equivalent to the fields in
 745      * the GUI Parameter Editor or command-line -params option. As such, much of the
 746      * necessary configuration data is provided indirectly via environment (.jte) files
 747      * which must be created and updated separately.
 748      * <p>Individual test suites should provide their own interview, with questions
 749      * customized to the configuration data they require.
 750      *
 751      * Note that the name of this method is "create", the harness may instantiate
 752      * multiple copies for temporary use, resetting data or transferring data.
 753      * Do not override this method with an implementation which caches the
 754      * return value.
 755      * @return A configuration interview to collect the configuration data for a test run.
 756      * @throws TestSuite.Fault if a problem occurs while creating the interview
 757      */
 758     public InterviewParameters createInterview()
 759         throws Fault
 760     {
 761         String[] classNameAndArgs = StringArray.split((String) (tsInfo.get("interview")));
 762         if (classNameAndArgs == null || classNameAndArgs.length == 0) {
 763             try {
 764                 return new LegacyParameters(this);
 765             }
 766             catch (InterviewParameters.Fault e) {
 767                 throw new Fault(i18n, "ts.errorInitDefaultInterview",
 768                                 e.getMessage());
 769             }
 770         }
 771 
 772 
 773         String className = classNameAndArgs[0];
 774         String[] args = new String[classNameAndArgs.length - 1];
 775         System.arraycopy(classNameAndArgs, 1, args, 0, args.length);
 776 
 777         try {
 778             Class c = loadClass(className);
 779             InterviewParameters p = (InterviewParameters) (newInstance(c));
 780             p.init(args);
 781             p.setTestSuite(this);
 782             return p;
 783         }
 784         catch (ClassCastException e) {
 785             throw new Fault(i18n, "ts.notASubtype",
 786                             new Object[] {className, "interview", InterviewParameters.class.getName()});
 787         }
 788         catch (InterviewParameters.Fault e) {
 789             //e.printStackTrace();
 790             throw new Fault(i18n, "ts.errorInitInterview",
 791                             new Object[] {className, e.getMessage()});
 792         }
 793 
 794     }
 795 
 796     /**
 797      * Create a configuration interview based on specified map of template values
 798      * @return A configuration interview to collect the configuration data for a test run.


 825                          template.getAbsolutePath());
 826                 ip.setTemplatePath(template.getAbsolutePath());
 827                 return loadInterviewFromTemplate(stringProps, ip);
 828             } else {
 829                 // XXX should probably return ip
 830                 //     or throw Fault
 831                 return null;
 832             }
 833         }
 834     }
 835 
 836 
 837     /**
 838      * Get a string containing a unique ID identifying this test suite,
 839      * or null if not available.  The default is taken from the "id" entry
 840      * in the .jtt file.
 841      * @return a unique ID identifying the test suite, or null if not specified.
 842      * @see #getName
 843      */
 844     public String getID() {
 845         return (tsInfo == null ? null : (String) (tsInfo.get("id")));
 846     }
 847 
 848     /**
 849      * Get a string identifying this test suite, or null if not available.
 850      * The default is taken from the "name" entry in the .jtt file.
 851      * This string is for presentation to the user, and may be localized
 852      * if appropriate.
 853      * @return a string identifying the test suite, or null if not specified.
 854      * @see #getID
 855      */
 856     public String getName() {
 857         return (tsInfo == null ? null : (String) (tsInfo.get("name")));
 858     }
 859 
 860     /**
 861      * Get the estimated number of tests in the test suite.
 862      * The default is to use the value of the "testCount" property from the
 863      * testsuite.jtt file.
 864      *
 865      * @return The estimated number of tests, or -1 if this number is not available.
 866      */
 867     public int getEstimatedTestCount() {
 868         try {
 869             if (tsInfo != null) {
 870                 String s = (String) (tsInfo.get("testCount"));
 871                 if (s != null)
 872                     return Integer.parseInt(s);
 873             }
 874         }
 875         catch (NumberFormatException e) {
 876             // ignore
 877         }
 878         return -1; // unknown
 879     }
 880 
 881     /**
 882      * Get the file name of the initial exclude list associated with the test suite.
 883      * The default is to use the value of the "initial.jtx" property from the
 884      * testsuite.jtt file. If the value is a relative filename, it will be made absolute
 885      * by evaluating it relative to the test suite root directory.
 886      * @return the name of the default exclude list, or null if none specified.
 887      */
 888     public File getInitialExcludeList() {
 889         String s = (tsInfo == null ? null : (String) (tsInfo.get("initial.jtx")));
 890         if (s == null)
 891             return null;
 892 
 893         File f = new File(s.replace('/', File.separatorChar));
 894         if (!f.isAbsolute())
 895             f = new File(getRootDir(), f.getPath());
 896         return f;
 897     }
 898 
 899     /**
 900      * Check if the test suite has an initial exclude list.
 901      * The default is to use getInitialExcludeList, and if that returns
 902      * a non-null result, check whether that file exists or not.
 903      * @return true if the test suite has an initial exclude list,
 904      * and false otherwise
 905      */
 906     public boolean hasInitialExcludeList() {
 907         File f = getInitialExcludeList();
 908         return (f == null ? false : f.exists());
 909     }
 910 
 911     /**
 912      * Get the URL for the latest exclude list associated with the test suite.
 913      * The default is to use the value of the "latest.jtx" property from the
 914      * testsuite.jtt file., which (if present) must be a fully qualified URL
 915      * identifying the latest exclude list for this test suite.
 916      * @return the name of the latest exclude list, or null if none specified.
 917      */
 918     public URL getLatestExcludeList() {
 919         try {
 920             String s = (tsInfo == null ? null : (String) (tsInfo.get("latest.jtx")));
 921             return (s == null ? null : new URL(s));
 922         }
 923         catch (MalformedURLException e) {
 924             // ignore
 925             return null;
 926         }
 927     }
 928 
 929     /**
 930      * Check if the test suite has a latest exclude list.
 931      * The default is to use getLatestExcludeList, and to
 932      * check whether that return a non-null result. The URL is not
 933      * itself checked for validity.
 934      * @return true if the test suite has a latest exclude list,
 935      * and false otherwise
 936      */
 937     public boolean hasLatestExcludeList() {
 938         URL u = getLatestExcludeList();
 939         return (u != null);
 940     }
 941 
 942     /**
 943      * Get the names of any helpsets containing related documents for this
 944      * test suite. The names should identify JavaHelp helpset files, as
 945      * used by javax.help.HelpSet.findHelpSet(ClassLoader, String).
 946      * Thus the names should identify resources of helpsets on the classpath.
 947      * This means you will typically need to put the directory or jar file
 948      * containing the help set on the classpath as well.
 949      * By default, the names will be looked up under the name "additionalDocs"
 950      * in the testsuite.jtt file.
 951      * @return an array of names identifying helpsets that contain related
 952      * documents for this testsuite. The result may be null if there are no
 953      * such documents.
 954      */
 955     public String[] getAdditionalDocNames() {
 956         return (tsInfo == null
 957                 ? null
 958                 : StringArray.split((String) (tsInfo.get("additionalDocs"))));
 959     }
 960 
 961     /**
 962      * Get the set of valid keywords for this test suite.
 963      * By default, the keywords will be looked up under the name "keywords"
 964      * in the testsuite.jtt file.
 965      * @return the set of valid keywords for this test suite, or null
 966      * if not known.
 967      */
 968     public String[] getKeywords() {
 969         return keywords;
 970     }
 971 
 972     /**
 973      * Get a list of associated files for a specified test description.
 974      * Normally, this will include the file containing the test description,
 975      * and any source files used by the test.  By default, the source files
 976      * are determined from the test description's "source" entry.
 977      * @see TestDescription#getSourceURLs()
 978      * @param td The test description for which the associated files are required


 993     public URL[] getDocsForFolder(String path) {
 994         return null;
 995     }
 996 
 997     /**
 998      * This method should be overridden in subclasses
 999      * @param td TestDescription for currently selected test case. This shouldn't be null.
1000      * @return array of files with documentation for test case, determined td.
1001      * null means there no documentation for this test case
1002      */
1003     public URL[] getDocsForTest(TestDescription td) {
1004         return null;
1005     }
1006 
1007     /**
1008      * Get A URL identifying a logo for this test suite, or null if none available.
1009      * @return a URL for a logo for the testsuite, or null if not available
1010      */
1011     public URL getLogo() {
1012         try {
1013             String s = (tsInfo == null ? null : (String) (tsInfo.get("logo")));
1014             return (s == null ? null : new URL(getRootDir().toURL(), s));
1015         }
1016         catch (MalformedURLException e) {
1017             // ignore
1018             return null;
1019         }
1020     }
1021 
1022     private static String[] envLookup(TestEnvironment env, String name) throws Fault {
1023         try {
1024             return env.lookup(name);
1025         }
1026         catch (TestEnvironment.Fault e) {
1027             throw new Fault(i18n, "ts.cantFindNameInEnv",
1028                             new Object[] {name, e.getMessage()});
1029         }
1030     }
1031 
1032     /**
1033      * Create a new instance of a class, translating any exceptions that may arise
1034      * into Fault.
1035      * @param c the class to be instantiated
1036      * @return an instance of the specified class
1037      * @throws TestSuite.Fault if any errors arise while trying to instantiate
1038      * the class.
1039      */
1040     protected static Object newInstance(Class c) throws Fault {
1041         try {
1042             return c.newInstance();
1043         }
1044         catch (InstantiationException e) {
1045             throw new Fault(i18n, "ts.cantInstantiate",
1046                             new Object[] { c.getName(), e });
1047         }
1048         catch (IllegalAccessException e) {
1049             throw new Fault(i18n, "ts.illegalAccess",
1050                             new Object[] { c.getName(), e });
1051         }
1052     }
1053 
1054 
1055     /**
1056      * Create a new instance of a class using a non-default constructor,
1057      * translating any exceptions that may arise into Fault.
1058      * @param c the class to be instantiated
1059      * @param argTypes the types of the argument to be passed to the constructor,
1060      * (thus implying the constructor to be used.)
1061      * @param args the arguments to be passed to the constructor
1062      * @return an instance of the specified class
1063      * @throws TestSuite.Fault if any errors arise while trying to instantiate
1064      * the class.
1065      */
1066     protected static Object newInstance(Class<?> c, Class[] argTypes, Object[] args)
1067         throws Fault
1068     {
1069         try {
1070             return c.getConstructor(argTypes).newInstance(args);
1071         }
1072         catch (IllegalAccessException e) {
1073             throw new Fault(i18n, "ts.illegalAccess",
1074                             new Object[] { c.getName(), e });
1075         }
1076         catch (InstantiationException e) {
1077             throw new Fault(i18n, "ts.cantInstantiate",
1078                             new Object[] { c.getName(), e });
1079         }
1080         catch (InvocationTargetException e) {
1081             Throwable te = e.getTargetException();
1082             if (te instanceof Fault)
1083                 throw (Fault) te;
1084             else
1085                 throw new Fault(i18n, "ts.cantInit", new Object[] { c.getName(), te });
1086         }
1087         catch (NoSuchMethodException e) {
1088             // don't recurse past the use of a single arg constructor
1089             if (argTypes.length > 1 && Boolean.getBoolean(FIND_LEGACY_CONSTRUCTOR)) {
1090                 return newInstance(c, new Class[] {File.class}, new Object[] {args[0]});
1091             }
1092 
1093             throw new Fault(i18n, "ts.cantFindConstructor",
1094                             new Object[] { c.getName(), e });
1095         }
1096     }
1097 
1098     /**
1099      * Load a class using the class loader provided when this test suite was created.
1100      * @param className the name of the class to be loaded
1101      * @return the class that was loaded
1102      * @throws TestSuite.Fault if there was a problem loading the specified class
1103      */
1104     public Class loadClass(String className) throws Fault {
1105         return loadClass(className, loader);
1106     }
1107 
1108     /**
1109      * Load a class using a specified loader, translating any errors that may arise
1110      * into Fault.
1111      * @param className the name of the class to be loaded
1112      * @param cl the class loader to use to load the specified class
1113      * @return the class that was loaded
1114      * @throws TestSuite.Fault if there was a problem loading the specified class
1115      */
1116     protected static Class loadClass(String className, ClassLoader cl) throws Fault {
1117         try {
1118             if (cl == null)
1119                 return Class.forName(className);
1120             else
1121                 return cl.loadClass(className);
1122         }
1123         catch (ClassNotFoundException e) {
1124             throw new Fault(i18n, "ts.classNotFound",
1125                             new Object[] { className, e });
1126         }
1127         catch (IllegalArgumentException e) {
1128             throw new Fault(i18n, "ts.badClassName",
1129                             new Object[] { className });
1130         }
1131     }
1132 
1133     /**
1134      * Get the class loader specified when this test suite object was created.
1135      * @return the class loader specified when this test suite object was created
1136      */


1152 
1153     /**
1154      * Checks if serviceReader is active and file with service description does
1155      * exist.
1156      * @return true, if it's needed to start services, false otherwise.
1157      */
1158     public boolean needServices() {
1159         ServiceReader sr = getServiceReader();
1160         if (sr == null) {
1161             return false;
1162         }
1163 
1164         /*
1165          * Since jt4.5 the ServiceReader has been extended with a new method.
1166          * To preserve ability to use new javatest with old test suites
1167          * the extra check is performed: check if the newly introduced method
1168          * is abstract or not.
1169          */
1170         boolean isLegacy = false;
1171         try {
1172             Method m = sr.getClass().getMethod("getServiceDescriptorFileName", new Class[0]);
1173             if (Modifier.isAbstract(m.getModifiers())) {
1174                 isLegacy = true;
1175             }
1176         } catch (NoSuchMethodException e) {
1177              isLegacy = true;
1178         }
1179         File descrFile = isLegacy ?
1180             new File(getRootDir(), File.separator + "lib" + File.separator + "services.xml") :
1181             new File(getRootDir(), sr.getServiceDescriptorFileName());
1182 
1183         return descrFile.exists();
1184     }
1185     /**
1186      * Returns a test suite specific ServiceReader, used to read Service
1187      * definitions.
1188      *
1189      * @return ServiceReader instance. Default is PropertyServiceReader
1190      */
1191     public ServiceReader getServiceReader() {
1192         if (serviceReader != null) {
1193             return serviceReader;
1194         }
1195 
1196         String servInfo = (String)tsInfo.get("serviceReader");
1197         if (servInfo != null) {
1198             String[] args = servInfo.split(" ");
1199             try {
1200                 Class c = loadClass(args[0]);
1201                 serviceReader = (ServiceReader) (newInstance(c));
1202                 if (args.length > 1) {
1203                     // problem with java1.5, which has no Arrays.copyOfRange();
1204                     String[] copy = new String[args.length - 1];
1205                     for (int i = 1; i < args.length; i++) {
1206                         copy[i-1] = args[i];
1207                     }
1208 
1209                     serviceReader.init(this, copy);
1210                 }
1211                 else {
1212                     serviceReader.init(this, null);
1213                 }
1214             }
1215             catch (TestSuite.Fault e) {
1216             }
1217         }
1218         else {
1219             serviceReader = new PropertyServiceReader();
1220             serviceReader.init(this, null);
1221         }
1222 
1223         return serviceReader;
1224     }
1225 
1226     /**
1227      * Get a map containing the test suite data in the .jtt file.
1228      * @return a map containing the test suite data in the .jtt file
1229      */
1230     protected Map getTestSuiteInfo() {
1231         return tsInfo;
1232     }
1233 
1234     /**
1235      * Get an entry from the data in the .jtt file.
1236      * @param name The name of the entry to get from the info in the .jtt file
1237      * @return the value of the specified entry, or null if not found.
1238      */
1239     public String getTestSuiteInfo(String name) {
1240         if (tsInfo == null)
1241             return null;
1242         else
1243             return (String) (tsInfo.get(name));
1244     }
1245 
1246     /**
1247      * Get the requested behavior for dealing with conflicts between
1248      * which tests are in the test suite vs those in the work directory.
1249      * @see #DELETE_NONTEST_RESULTS
1250      * @see #REFRESH_ON_RUN
1251      * @see #CLEAR_CHANGED_TEST
1252      */
1253     public boolean getTestRefreshBehavior(int event) {
1254         switch (event) {
1255         case DELETE_NONTEST_RESULTS:
1256             return Boolean.valueOf(getTestSuiteInfo("deleteNonExistTests")).booleanValue();
1257         case REFRESH_ON_RUN:
1258             return Boolean.valueOf( getTestSuiteInfo("refreshTestsOnRun") ).booleanValue();
1259         case CLEAR_CHANGED_TEST:
1260             return Boolean.valueOf( getTestSuiteInfo("clearChangedTests")).booleanValue();
1261         default:
1262             return false;
1263         }


1466                     } else {
1467                         targets[i].publish(record);
1468                     }
1469                 }
1470             }
1471         }
1472 
1473         private String getLogFileName() {
1474             return logFileName;
1475         }
1476 
1477         private String logFileName;
1478     }
1479 
1480 
1481     private static final String TESTSUITE_HTML = "testsuite.html";
1482     private static final String TESTSUITE_JTT  = "testsuite.jtt";
1483     private static final String FIND_LEGACY_CONSTRUCTOR = "com.sun.javatest.ts.findLegacyCtor";
1484 
1485     private File root;
1486     private Map tsInfo;
1487     private ClassLoader loader;
1488     private TestFinder finder;
1489 
1490     // the following are used by the default impl of createScript
1491     private Class scriptClass;
1492     private String[] scriptArgs;
1493 
1494     private String[] keywords;
1495 
1496     private ServiceReader serviceReader;
1497     private ServiceManager serviceManager;
1498 
1499     private static Map<File, WeakReference<TestSuite>> dirMap = new HashMap<>(2);
1500 
1501     private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(TestSuite.class);
1502     private static String notificationLogName = i18n.getString("notification.logname");
1503 
1504     static Map<String, WorkDirLogHandler> handlersMap = new HashMap<>();
1505     private static Vector<GeneralPurposeLogger> gpls;
1506     private static Map<String, File> observedFiles;
1507 
1508     private final NotificationLogger notifLogger = new NotificationLogger(null);
1509 
1510     public static final String TM_CONTEXT_NAME = "tmcontext";
1511 


 199         try {
 200             canonRoot = root.getCanonicalFile();
 201         }
 202         catch (IOException e) {
 203             throw new Fault(i18n, "ts.cantCanonicalize",
 204                             new Object[] {root.getPath(), e.toString()});
 205         }
 206 
 207         File canonRootDir;
 208         if (canonRoot.isDirectory())
 209             canonRootDir = canonRoot;
 210         else {
 211             if (canonRoot.getName().equalsIgnoreCase(TESTSUITE_HTML))
 212                 canonRootDir = canonRoot.getParentFile();
 213             else
 214                 throw new NotTestSuiteFault(i18n, "ts.notTestSuiteFile", canonRoot);
 215         }
 216 
 217         File f = new File(canonRootDir, TESTSUITE_JTT);
 218         if (isReadableFile(f)) {
 219             try (InputStream in = new BufferedInputStream(new FileInputStream(f))) {
 220                 Map<String, String> p = com.sun.javatest.util.Properties.load(in);



 221                 return open(canonRoot, p);
 222             }
 223             catch (IOException e) {
 224                 throw new Fault(i18n, "ts.cantReadTestSuiteFile", e.toString());
 225             }
 226         }
 227         else {
 228             // check for old style test suite
 229             File ts_html = new File(canonRootDir, TESTSUITE_HTML);
 230             File parentDir = canonRootDir.getParentFile();
 231             File parent_jtt = (parentDir == null ? null : new File(parentDir, TESTSUITE_JTT));
 232             if (isReadableFile(ts_html) && (parent_jtt == null || !parent_jtt.exists()))
 233                 return open(canonRoot, new HashMap<String, String>());
 234             else
 235                 throw new NotTestSuiteFault(i18n, "ts.notTestSuiteFile", canonRoot);
 236         }
 237     }
 238 
 239     /**
 240      * Open a test suite.
 241      * @param root A file identifying the root of the test suite.
 242      * @param tsInfo Test Suite properties read from the test suite properties file.
 243      * @return A TestSuite object for the test suite in question.
 244      * @throws TestSuite.Fault if any problems occur while opening the test suite
 245      */
 246     private static TestSuite open(File root, Map<String, String> tsInfo) throws Fault {
 247         synchronized (dirMap) {
 248             TestSuite ts;
 249 
 250             // if this test suite has already been opened, return that
 251             WeakReference<TestSuite> ref = dirMap.get(root);
 252             if (ref != null) {
 253                 ts = ref.get();
 254                 if (ts != null) {
 255                     return ts;
 256                 }
 257             }
 258 
 259             // otherwise, open it for real
 260             ts = open0(root, tsInfo);
 261 
 262             // save reference in case opened again
 263             dirMap.put(root, new WeakReference<>(ts));
 264             return ts;
 265         }
 266     }
 267 
 268     private static TestSuite open0(File root, Map<String, String> tsInfo) throws Fault {
 269         String[] classPath = StringArray.split(tsInfo.get("classpath"));
 270 
 271         ClassLoader cl;
 272         if (classPath.length == 0)
 273             cl = null;
 274         else {
 275             try {
 276                 File rootDir = (root.isDirectory() ? root : root.getParentFile());
 277                 URL[] p = new URL[classPath.length];
 278                 for (int i = 0; i < classPath.length; i++) {
 279                     String cpi = classPath[i];
 280                     if (cpi.toLowerCase().startsWith("http:"))
 281                         p[i] = new URL(cpi);
 282                     else {
 283                         File f = new File(cpi);
 284                         if (!f.isAbsolute())
 285                             f = new File(rootDir, cpi);
 286                         p[i] = f.toURI().toURL();
 287                     }
 288                 }
 289                 cl = new URLClassLoader(p, TestSuite.class.getClassLoader());
 290             }
 291             catch (MalformedURLException e) {
 292                 throw new Fault(i18n, "ts.badClassPath",
 293                                 new Object[] {root, e.getMessage()});
 294             }
 295         }
 296 
 297         String[] tsClassAndArgs = StringArray.split(tsInfo.get("testsuite"));
 298 
 299         TestSuite testSuite;
 300         if (tsClassAndArgs.length == 0)
 301             testSuite = new TestSuite(root, tsInfo, cl);
 302         else {
 303             String className = tsClassAndArgs[0];
 304 
 305             try {
 306                 Class<?> c = loadClass(className, cl);
 307                 Class<?>[] tsArgTypes = {File.class, Map.class, ClassLoader.class};
 308                 Object[] tsArgs = {root, tsInfo, cl};
 309                 testSuite = (TestSuite)(newInstance(c, tsArgTypes, tsArgs));
 310             }
 311             catch (ClassCastException e) {
 312                 throw new Fault(i18n, "ts.notASubtype",
 313                                 new Object[] {className, "testsuite", TestSuite.class.getName()});
 314             }
 315             catch (UnsupportedClassVersionError uce){
 316                 throw new Fault(i18n, "ts.compiledRecentVersion",
 317                         new Object[] {System.getProperty("java.version"), root.getPath()});
 318             }
 319 
 320             String[] args = new String[tsClassAndArgs.length - 1];
 321             System.arraycopy(tsClassAndArgs, 1, args, 0, args.length);
 322             testSuite.init(args);
 323         }
 324 
 325         // initialize test finder
 326         testSuite.setTestFinder(new TestFinderDecorator(testSuite.createTestFinder()));
 327 


 345         if (ref != null) {
 346             TestSuite ts = (TestSuite)(ref.get());
 347             if (ts != null) {
 348                 return ts;
 349             }
 350         }
 351 
 352         return null;
 353     }
 354      */
 355 
 356     /**
 357      * Create a TestSuite object.
 358      * @param root The root file for this test suite.
 359      * @param tsInfo Test suite properties, typically read from the test suite properties file
 360      * in the root directory of the test suite.
 361      * @param cl A class loader to be used to load additional classes as required,
 362      * typically using a class path defined in the test suite properties file.
 363      * @throws TestSuite.Fault if a problem occurs while creating this test suite.
 364      */
 365     public TestSuite(File root, Map<String, String> tsInfo, ClassLoader cl) throws Fault {
 366         this.root = root;
 367         this.tsInfo = tsInfo;
 368         this.loader = cl;
 369 
 370         String kw = (tsInfo == null ? null : tsInfo.get("keywords"));
 371         keywords = (kw == null ? null : StringArray.split(kw));
 372     }
 373 
 374 
 375     /**
 376      * Create a TestSuite object, with no additional test suite properties and no
 377      * class loader.
 378      * @param root The root file for this test suite.
 379      */
 380     public TestSuite(File root) {
 381         this.root = root;
 382     }
 383 
 384     /**
 385      * Initialize this test suite, with args typically read from a .jtt file.
 386      * The default implementation does not recognize any arguments and always
 387      * throws an exception.
 388      * @param args an array of strings to initialize this test suite object
 389      * @throws TestSuite.Fault if there are any problems initializing the
 390      * test suite from the specified arguments.


 420     public File getRootDir() {
 421         return (root.isDirectory() ? root : new File(root.getParent()));
 422     }
 423 
 424     /**
 425      * Get the directory in the test suite that contains the tests.
 426      * By default, the following are checked:
 427      * <ol>
 428      * <li>The <code>tests</code> property in the test suite properties file.
 429      * If this entry is found, it must either identify an absolute filename, or
 430      * a directory relative to the test suite root directory, using '/' to
 431      * separate the components of the path.
 432      * <li>If the file <em>root</em><code>/tests/testsuite.html</code> exists,
 433      * the result is the directory <em>root</em><code>/tests</code>. This is
 434      * for compatibility with standard TCK layout.
 435      * <li>Otherwise, the result is the root directory of the test suite.
 436      * </ol>
 437      * @return the directory that contains the tests
 438      */
 439     public File getTestsDir() {
 440         String t = (tsInfo == null ? null : tsInfo.get("tests"));
 441         if (t == null || t.length() == 0) {
 442             File rootDir = getRootDir();
 443             File testsDir = new File(rootDir, "tests");
 444             if (testsDir.isDirectory()) {
 445                 // if the tests directory exists, and there is no overriding
 446                 // testsuite.jtt entry, assume the tests dir is "tests/".
 447                 return testsDir;
 448             }
 449             // default
 450             return rootDir;
 451         }
 452         else {
 453             File f = new File(t);
 454             if (f.isAbsolute())
 455                 return f;
 456             else
 457                 return new File(getRootDir(), t.replace('/', File.separatorChar));
 458         }
 459     }
 460 


 531      * loader specified when the test suite was opened, if one was given;
 532      * otherwise, the system class loader will be used.
 533      *
 534      * The default implementation attempts to use a file <tt>testsuite.jtd</tt>
 535      * in the tests directory.  If found, a BinaryTestFinder will be created
 536      * using this file.  If it is not found, then it searches for a property
 537      * named <tt>finder</tt> in the test suite properties and will attempt to
 538      * instantiate that.  If no entry is found or it is blank, an
 539      * HTMLTestFinder is used, using whatever a basic settings HTMLTestFinder
 540      * initializes to.
 541      * @return a test finder to be used to read the tests in the test suite
 542      * @throws TestSuite.Fault if there is a problem creating the test finder
 543      * @see #getTestFinder
 544      * @see #setTestFinder
 545      * @see #getTestsDir
 546      */
 547     protected TestFinder createTestFinder() throws Fault {
 548         File testsDir = getTestsDir();
 549 
 550         // no BTF file; look for a finder=class args... entry
 551         String[] finderCmd = StringArray.split((tsInfo.get("finder")));
 552         String finderClassName;
 553         String[] finderArgs = new String[0];
 554 
 555         if (finderCmd == null || finderCmd.length == 0) {
 556             //finderCmd = new String[] {HTMLTestFinder.class.getName()};
 557             finderCmd = null;   // ensure null for later use
 558             finderClassName = HTMLTestFinder.class.getName();
 559         }
 560         else {
 561             finderClassName = finderCmd[0];
 562 
 563             if (finderCmd.length > 1) {
 564                 finderArgs = new String[finderCmd.length - 1];
 565                 System.arraycopy(finderCmd, 1, finderArgs, 0, finderArgs.length);
 566             }
 567             else {
 568                 // finderArgs should remain empty array
 569             }
 570         }
 571 
 572         // first, try looking for testsuite.jtd
 573         String jtd = tsInfo.get("testsuite.jtd");
 574         File jtdFile = (jtd == null ? new File(testsDir, "testsuite.jtd") : new File(root, jtd));
 575         if (jtdFile.exists()) {
 576             try {
 577                 // found a file for BinaryTestFinder
 578                 // only pass the finder class if it was not defaulted to HTMLTestFinder
 579                 return createBinaryTestFinder((finderCmd == null ? null : finderClassName),
 580                         finderArgs, testsDir, jtdFile);
 581             }
 582             catch (TestFinder.Fault e) {
 583                 // ignore, try to continue with normal finder
 584             }
 585             catch (Fault f) {
 586                 // ignore, try to continue with normal finder
 587             }
 588         }
 589 
 590         try {
 591             Class<?> c = loadClass(finderClassName);
 592             TestFinder tf = (TestFinder) (newInstance(c));
 593             // called old deprecated entry till we know no-one cares
 594             //tf.init(finderArgs, testsRoot, null, null, tsInfo/*pass in env?*/);
 595             // this likely kills ExpandTestFinder, finally
 596             tf.init(finderArgs, testsDir, null, null, null/*pass in env?*/);
 597             return tf;
 598         }
 599         catch (ClassCastException e) {
 600             throw new Fault(i18n, "ts.notASubtype",
 601                             new Object[] {finderClassName, "finder", TestFinder.class.getName()});
 602         }
 603         catch (TestFinder.Fault e) {
 604             throw new Fault(i18n, "ts.errorInitFinder",
 605                             new Object[] {finderClassName, e.getMessage()});
 606         }
 607     }
 608 
 609     /**
 610      * In the case where a JTD file is found, attempt to load a binary test finder.
 611      * The default implementation attempts to use the finder property in the
 612      * test suite properties if it is a BinaryTestFinder subclass.
 613      *
 614      * @param finderClassName Finder class name to attempt to use as a BTF.  Null if
 615      *      the default BTF class should be used.
 616      * @param finderArgs Arguments to finder given from the test suite property.
 617      * @param testsDir Reference location to pass to finder.
 618      * @param jtdFile Location of the JTD file to give to the BTF.
 619      * @return The binary test finder which was created.
 620      * @throws com.sun.javatest.TestSuite.Fault
 621      * @throws com.sun.javatest.TestFinder.Fault
 622      * @see com.sun.javatest.TestFinder
 623      * @see com.sun.javatest.finder.BinaryTestFinder
 624      */
 625     protected TestFinder createBinaryTestFinder(String finderClassName,
 626             String finderArgs[], File testsDir, File jtdFile) throws Fault, TestFinder.Fault {
 627         try {
 628             TestFinder tf = null;
 629 
 630             if (finderClassName != null) {
 631                 Class<?> c = loadClass(finderClassName);
 632                 tf = (TestFinder) (newInstance(c));
 633             }
 634 
 635             if (tf instanceof BinaryTestFinder) {
 636                 tf.init(finderArgs, testsDir, null, null, null);
 637                 return tf;
 638             }
 639             else {
 640                 return new BinaryTestFinder(testsDir, jtdFile);
 641             }
 642         }
 643         catch (ClassCastException e) {
 644             throw new Fault(i18n, "ts.notASubtype",
 645                             new Object[] {finderClassName, "finder", TestFinder.class.getName()});
 646         }
 647         catch (TestFinder.Fault e) {
 648             throw new Fault(i18n, "ts.errorInitFinder",
 649                             new Object[] {finderClassName, e.getMessage()});
 650         }
 651 


 677      * that is created.
 678      *
 679      * Note that the name of this method is "create", it is not recommended
 680      * that the value returned ever be re-used or cached for subsequent requests
 681      * to this method.
 682      * @param td The test description for the test to be executed.
 683      * @param exclTestCases Any test cases within the test that should not be executed.
 684      * @param scriptEnv Configuration data to be given to the test as necessary.
 685      * @param workDir A work directory in which to store the results of the test.
 686      * @param backupPolicy A policy object used to control how to backup any files that
 687      * might be overwritten.
 688      * @return a script to be used to execute the given test
 689      * @throws TestSuite.Fault if any errors occur while creating the script
 690      */
 691     public Script createScript(TestDescription td, String[] exclTestCases, TestEnvironment scriptEnv,
 692                                WorkDirectory workDir,
 693                                BackupPolicy backupPolicy) throws Fault {
 694         if (scriptClass == null) {
 695             String[] script = envLookup(scriptEnv, "script");
 696             if (script.length == 0)
 697                 script = StringArray.split(tsInfo.get("script"));
 698             if (script.length > 0) {
 699                 scriptClass = loadClass(script[0]);
 700                 if (!Script.class.isAssignableFrom(scriptClass)) {
 701                     throw new Fault(i18n, "ts.notASubtype",
 702                                     new Object[] {script[0], "script", Script.class.getName()});
 703                 }
 704                 scriptArgs = new String[script.length - 1];
 705                 System.arraycopy(script, 1, scriptArgs, 0, scriptArgs.length);
 706             }
 707             else {
 708                 // for backwards compatibility,
 709                 // see if KeywordScript is a reasonable default
 710                 boolean keywordScriptOK = false;
 711                 for (Iterator<String> i = scriptEnv.keys().iterator(); i.hasNext() && !keywordScriptOK; ) {
 712                     String key = i.next();
 713                     keywordScriptOK = key.startsWith("script.");
 714                 }
 715                 if (keywordScriptOK) {
 716                     scriptClass = KeywordScript.class;
 717                     scriptArgs = new String[] { };
 718                 }
 719                 else {
 720                     throw new Fault(i18n, "ts.noScript");
 721                 }
 722             }
 723         }
 724 
 725         Script s = (Script)(newInstance(scriptClass));
 726         s.initArgs(scriptArgs);
 727         s.initTestDescription(td);
 728         s.initExcludedTestCases(exclTestCases);
 729         s.initTestEnvironment(scriptEnv);
 730         s.initWorkDir(workDir);
 731         s.initBackupPolicy(backupPolicy);
 732         s.initClassLoader(loader);


 738      * data for a test run.
 739      * <p>The default implementation returns a {@link LegacyParameters default}
 740      * interview suitable for use with test suites built with earlier versions
 741      * of the JT Harness: it provides questions equivalent to the fields in
 742      * the GUI Parameter Editor or command-line -params option. As such, much of the
 743      * necessary configuration data is provided indirectly via environment (.jte) files
 744      * which must be created and updated separately.
 745      * <p>Individual test suites should provide their own interview, with questions
 746      * customized to the configuration data they require.
 747      *
 748      * Note that the name of this method is "create", the harness may instantiate
 749      * multiple copies for temporary use, resetting data or transferring data.
 750      * Do not override this method with an implementation which caches the
 751      * return value.
 752      * @return A configuration interview to collect the configuration data for a test run.
 753      * @throws TestSuite.Fault if a problem occurs while creating the interview
 754      */
 755     public InterviewParameters createInterview()
 756         throws Fault
 757     {
 758         String[] classNameAndArgs = StringArray.split((tsInfo.get("interview")));
 759         if (classNameAndArgs == null || classNameAndArgs.length == 0) {
 760             try {
 761                 return new LegacyParameters(this);
 762             }
 763             catch (InterviewParameters.Fault e) {
 764                 throw new Fault(i18n, "ts.errorInitDefaultInterview",
 765                                 e.getMessage());
 766             }
 767         }
 768 
 769 
 770         String className = classNameAndArgs[0];
 771         String[] args = new String[classNameAndArgs.length - 1];
 772         System.arraycopy(classNameAndArgs, 1, args, 0, args.length);
 773 
 774         try {
 775             Class<?> c = loadClass(className);
 776             InterviewParameters p = (InterviewParameters) (newInstance(c));
 777             p.init(args);
 778             p.setTestSuite(this);
 779             return p;
 780         }
 781         catch (ClassCastException e) {
 782             throw new Fault(i18n, "ts.notASubtype",
 783                             new Object[] {className, "interview", InterviewParameters.class.getName()});
 784         }
 785         catch (InterviewParameters.Fault e) {
 786             //e.printStackTrace();
 787             throw new Fault(i18n, "ts.errorInitInterview",
 788                             new Object[] {className, e.getMessage()});
 789         }
 790 
 791     }
 792 
 793     /**
 794      * Create a configuration interview based on specified map of template values
 795      * @return A configuration interview to collect the configuration data for a test run.


 822                          template.getAbsolutePath());
 823                 ip.setTemplatePath(template.getAbsolutePath());
 824                 return loadInterviewFromTemplate(stringProps, ip);
 825             } else {
 826                 // XXX should probably return ip
 827                 //     or throw Fault
 828                 return null;
 829             }
 830         }
 831     }
 832 
 833 
 834     /**
 835      * Get a string containing a unique ID identifying this test suite,
 836      * or null if not available.  The default is taken from the "id" entry
 837      * in the .jtt file.
 838      * @return a unique ID identifying the test suite, or null if not specified.
 839      * @see #getName
 840      */
 841     public String getID() {
 842         return (tsInfo == null ? null : tsInfo.get("id"));
 843     }
 844 
 845     /**
 846      * Get a string identifying this test suite, or null if not available.
 847      * The default is taken from the "name" entry in the .jtt file.
 848      * This string is for presentation to the user, and may be localized
 849      * if appropriate.
 850      * @return a string identifying the test suite, or null if not specified.
 851      * @see #getID
 852      */
 853     public String getName() {
 854         return (tsInfo == null ? null : tsInfo.get("name"));
 855     }
 856 
 857     /**
 858      * Get the estimated number of tests in the test suite.
 859      * The default is to use the value of the "testCount" property from the
 860      * testsuite.jtt file.
 861      *
 862      * @return The estimated number of tests, or -1 if this number is not available.
 863      */
 864     public int getEstimatedTestCount() {
 865         try {
 866             if (tsInfo != null) {
 867                 String s = tsInfo.get("testCount");
 868                 if (s != null)
 869                     return Integer.parseInt(s);
 870             }
 871         }
 872         catch (NumberFormatException e) {
 873             // ignore
 874         }
 875         return -1; // unknown
 876     }
 877 
 878     /**
 879      * Get the file name of the initial exclude list associated with the test suite.
 880      * The default is to use the value of the "initial.jtx" property from the
 881      * testsuite.jtt file. If the value is a relative filename, it will be made absolute
 882      * by evaluating it relative to the test suite root directory.
 883      * @return the name of the default exclude list, or null if none specified.
 884      */
 885     public File getInitialExcludeList() {
 886         String s = (tsInfo == null ? null : tsInfo.get("initial.jtx"));
 887         if (s == null)
 888             return null;
 889 
 890         File f = new File(s.replace('/', File.separatorChar));
 891         if (!f.isAbsolute())
 892             f = new File(getRootDir(), f.getPath());
 893         return f;
 894     }
 895 
 896     /**
 897      * Check if the test suite has an initial exclude list.
 898      * The default is to use getInitialExcludeList, and if that returns
 899      * a non-null result, check whether that file exists or not.
 900      * @return true if the test suite has an initial exclude list,
 901      * and false otherwise
 902      */
 903     public boolean hasInitialExcludeList() {
 904         File f = getInitialExcludeList();
 905         return (f == null ? false : f.exists());
 906     }
 907 
 908     /**
 909      * Get the URL for the latest exclude list associated with the test suite.
 910      * The default is to use the value of the "latest.jtx" property from the
 911      * testsuite.jtt file., which (if present) must be a fully qualified URL
 912      * identifying the latest exclude list for this test suite.
 913      * @return the name of the latest exclude list, or null if none specified.
 914      */
 915     public URL getLatestExcludeList() {
 916         try {
 917             String s = (tsInfo == null ? null : tsInfo.get("latest.jtx"));
 918             return (s == null ? null : new URL(s));
 919         }
 920         catch (MalformedURLException e) {
 921             // ignore
 922             return null;
 923         }
 924     }
 925 
 926     /**
 927      * Check if the test suite has a latest exclude list.
 928      * The default is to use getLatestExcludeList, and to
 929      * check whether that return a non-null result. The URL is not
 930      * itself checked for validity.
 931      * @return true if the test suite has a latest exclude list,
 932      * and false otherwise
 933      */
 934     public boolean hasLatestExcludeList() {
 935         URL u = getLatestExcludeList();
 936         return (u != null);
 937     }
 938 
 939     /**
 940      * Get the names of any helpsets containing related documents for this
 941      * test suite. The names should identify JavaHelp helpset files, as
 942      * used by javax.help.HelpSet.findHelpSet(ClassLoader, String).
 943      * Thus the names should identify resources of helpsets on the classpath.
 944      * This means you will typically need to put the directory or jar file
 945      * containing the help set on the classpath as well.
 946      * By default, the names will be looked up under the name "additionalDocs"
 947      * in the testsuite.jtt file.
 948      * @return an array of names identifying helpsets that contain related
 949      * documents for this testsuite. The result may be null if there are no
 950      * such documents.
 951      */
 952     public String[] getAdditionalDocNames() {
 953         return (tsInfo == null
 954                 ? null
 955                 : StringArray.split((tsInfo.get("additionalDocs"))));
 956     }
 957 
 958     /**
 959      * Get the set of valid keywords for this test suite.
 960      * By default, the keywords will be looked up under the name "keywords"
 961      * in the testsuite.jtt file.
 962      * @return the set of valid keywords for this test suite, or null
 963      * if not known.
 964      */
 965     public String[] getKeywords() {
 966         return keywords;
 967     }
 968 
 969     /**
 970      * Get a list of associated files for a specified test description.
 971      * Normally, this will include the file containing the test description,
 972      * and any source files used by the test.  By default, the source files
 973      * are determined from the test description's "source" entry.
 974      * @see TestDescription#getSourceURLs()
 975      * @param td The test description for which the associated files are required


 990     public URL[] getDocsForFolder(String path) {
 991         return null;
 992     }
 993 
 994     /**
 995      * This method should be overridden in subclasses
 996      * @param td TestDescription for currently selected test case. This shouldn't be null.
 997      * @return array of files with documentation for test case, determined td.
 998      * null means there no documentation for this test case
 999      */
1000     public URL[] getDocsForTest(TestDescription td) {
1001         return null;
1002     }
1003 
1004     /**
1005      * Get A URL identifying a logo for this test suite, or null if none available.
1006      * @return a URL for a logo for the testsuite, or null if not available
1007      */
1008     public URL getLogo() {
1009         try {
1010             String s = (tsInfo == null ? null : tsInfo.get("logo"));
1011             return (s == null ? null : new URL(getRootDir().toURL(), s));
1012         }
1013         catch (MalformedURLException e) {
1014             // ignore
1015             return null;
1016         }
1017     }
1018 
1019     private static String[] envLookup(TestEnvironment env, String name) throws Fault {
1020         try {
1021             return env.lookup(name);
1022         }
1023         catch (TestEnvironment.Fault e) {
1024             throw new Fault(i18n, "ts.cantFindNameInEnv",
1025                             new Object[] {name, e.getMessage()});
1026         }
1027     }
1028 
1029     /**
1030      * Create a new instance of a class, translating any exceptions that may arise
1031      * into Fault.
1032      * @param c the class to be instantiated
1033      * @return an instance of the specified class
1034      * @throws TestSuite.Fault if any errors arise while trying to instantiate
1035      * the class.
1036      */
1037     protected static Object newInstance(Class<?> c) throws Fault {
1038         try {
1039             return c.newInstance();
1040         }
1041         catch (InstantiationException e) {
1042             throw new Fault(i18n, "ts.cantInstantiate",
1043                             new Object[] { c.getName(), e });
1044         }
1045         catch (IllegalAccessException e) {
1046             throw new Fault(i18n, "ts.illegalAccess",
1047                             new Object[] { c.getName(), e });
1048         }
1049     }
1050 
1051 
1052     /**
1053      * Create a new instance of a class using a non-default constructor,
1054      * translating any exceptions that may arise into Fault.
1055      * @param c the class to be instantiated
1056      * @param argTypes the types of the argument to be passed to the constructor,
1057      * (thus implying the constructor to be used.)
1058      * @param args the arguments to be passed to the constructor
1059      * @return an instance of the specified class
1060      * @throws TestSuite.Fault if any errors arise while trying to instantiate
1061      * the class.
1062      */
1063     protected static Object newInstance(Class<?> c, Class<?>[] argTypes, Object[] args)
1064         throws Fault
1065     {
1066         try {
1067             return c.getConstructor(argTypes).newInstance(args);
1068         }
1069         catch (IllegalAccessException e) {
1070             throw new Fault(i18n, "ts.illegalAccess",
1071                             new Object[] { c.getName(), e });
1072         }
1073         catch (InstantiationException e) {
1074             throw new Fault(i18n, "ts.cantInstantiate",
1075                             new Object[] { c.getName(), e });
1076         }
1077         catch (InvocationTargetException e) {
1078             Throwable te = e.getTargetException();
1079             if (te instanceof Fault)
1080                 throw (Fault) te;
1081             else
1082                 throw new Fault(i18n, "ts.cantInit", new Object[] { c.getName(), te });
1083         }
1084         catch (NoSuchMethodException e) {
1085             // don't recurse past the use of a single arg constructor
1086             if (argTypes.length > 1 && Boolean.getBoolean(FIND_LEGACY_CONSTRUCTOR)) {
1087                 return newInstance(c, new Class<?>[] {File.class}, new Object[] {args[0]});
1088             }
1089 
1090             throw new Fault(i18n, "ts.cantFindConstructor",
1091                             new Object[] { c.getName(), e });
1092         }
1093     }
1094 
1095     /**
1096      * Load a class using the class loader provided when this test suite was created.
1097      * @param className the name of the class to be loaded
1098      * @return the class that was loaded
1099      * @throws TestSuite.Fault if there was a problem loading the specified class
1100      */
1101     public Class<?> loadClass(String className) throws Fault {
1102         return loadClass(className, loader);
1103     }
1104 
1105     /**
1106      * Load a class using a specified loader, translating any errors that may arise
1107      * into Fault.
1108      * @param className the name of the class to be loaded
1109      * @param cl the class loader to use to load the specified class
1110      * @return the class that was loaded
1111      * @throws TestSuite.Fault if there was a problem loading the specified class
1112      */
1113     protected static Class<?> loadClass(String className, ClassLoader cl) throws Fault {
1114         try {
1115             if (cl == null)
1116                 return Class.forName(className);
1117             else
1118                 return cl.loadClass(className);
1119         }
1120         catch (ClassNotFoundException e) {
1121             throw new Fault(i18n, "ts.classNotFound",
1122                             new Object[] { className, e });
1123         }
1124         catch (IllegalArgumentException e) {
1125             throw new Fault(i18n, "ts.badClassName",
1126                             new Object[] { className });
1127         }
1128     }
1129 
1130     /**
1131      * Get the class loader specified when this test suite object was created.
1132      * @return the class loader specified when this test suite object was created
1133      */


1149 
1150     /**
1151      * Checks if serviceReader is active and file with service description does
1152      * exist.
1153      * @return true, if it's needed to start services, false otherwise.
1154      */
1155     public boolean needServices() {
1156         ServiceReader sr = getServiceReader();
1157         if (sr == null) {
1158             return false;
1159         }
1160 
1161         /*
1162          * Since jt4.5 the ServiceReader has been extended with a new method.
1163          * To preserve ability to use new javatest with old test suites
1164          * the extra check is performed: check if the newly introduced method
1165          * is abstract or not.
1166          */
1167         boolean isLegacy = false;
1168         try {
1169             Method m = sr.getClass().getMethod("getServiceDescriptorFileName", new Class<?>[0]);
1170             if (Modifier.isAbstract(m.getModifiers())) {
1171                 isLegacy = true;
1172             }
1173         } catch (NoSuchMethodException e) {
1174              isLegacy = true;
1175         }
1176         File descrFile = isLegacy ?
1177             new File(getRootDir(), File.separator + "lib" + File.separator + "services.xml") :
1178             new File(getRootDir(), sr.getServiceDescriptorFileName());
1179 
1180         return descrFile.exists();
1181     }
1182     /**
1183      * Returns a test suite specific ServiceReader, used to read Service
1184      * definitions.
1185      *
1186      * @return ServiceReader instance. Default is PropertyServiceReader
1187      */
1188     public ServiceReader getServiceReader() {
1189         if (serviceReader != null) {
1190             return serviceReader;
1191         }
1192 
1193         String servInfo = tsInfo.get("serviceReader");
1194         if (servInfo != null) {
1195             String[] args = servInfo.split(" ");
1196             try {
1197                 Class<?> c = loadClass(args[0]);
1198                 serviceReader = (ServiceReader) (newInstance(c));
1199                 if (args.length > 1) {
1200                     // problem with java1.5, which has no Arrays.copyOfRange();
1201                     String[] copy = new String[args.length - 1];
1202                     for (int i = 1; i < args.length; i++) {
1203                         copy[i-1] = args[i];
1204                     }
1205 
1206                     serviceReader.init(this, copy);
1207                 }
1208                 else {
1209                     serviceReader.init(this, null);
1210                 }
1211             }
1212             catch (TestSuite.Fault e) {
1213             }
1214         }
1215         else {
1216             serviceReader = new PropertyServiceReader();
1217             serviceReader.init(this, null);
1218         }
1219 
1220         return serviceReader;
1221     }
1222 
1223     /**
1224      * Get a map containing the test suite data in the .jtt file.
1225      * @return a map containing the test suite data in the .jtt file
1226      */
1227     protected Map<String, String> getTestSuiteInfo() {
1228         return tsInfo;
1229     }
1230 
1231     /**
1232      * Get an entry from the data in the .jtt file.
1233      * @param name The name of the entry to get from the info in the .jtt file
1234      * @return the value of the specified entry, or null if not found.
1235      */
1236     public String getTestSuiteInfo(String name) {
1237         if (tsInfo == null)
1238             return null;
1239         else
1240             return (tsInfo.get(name));
1241     }
1242 
1243     /**
1244      * Get the requested behavior for dealing with conflicts between
1245      * which tests are in the test suite vs those in the work directory.
1246      * @see #DELETE_NONTEST_RESULTS
1247      * @see #REFRESH_ON_RUN
1248      * @see #CLEAR_CHANGED_TEST
1249      */
1250     public boolean getTestRefreshBehavior(int event) {
1251         switch (event) {
1252         case DELETE_NONTEST_RESULTS:
1253             return Boolean.valueOf(getTestSuiteInfo("deleteNonExistTests")).booleanValue();
1254         case REFRESH_ON_RUN:
1255             return Boolean.valueOf( getTestSuiteInfo("refreshTestsOnRun") ).booleanValue();
1256         case CLEAR_CHANGED_TEST:
1257             return Boolean.valueOf( getTestSuiteInfo("clearChangedTests")).booleanValue();
1258         default:
1259             return false;
1260         }


1463                     } else {
1464                         targets[i].publish(record);
1465                     }
1466                 }
1467             }
1468         }
1469 
1470         private String getLogFileName() {
1471             return logFileName;
1472         }
1473 
1474         private String logFileName;
1475     }
1476 
1477 
1478     private static final String TESTSUITE_HTML = "testsuite.html";
1479     private static final String TESTSUITE_JTT  = "testsuite.jtt";
1480     private static final String FIND_LEGACY_CONSTRUCTOR = "com.sun.javatest.ts.findLegacyCtor";
1481 
1482     private File root;
1483     private Map<String, String> tsInfo;
1484     private ClassLoader loader;
1485     private TestFinder finder;
1486 
1487     // the following are used by the default impl of createScript
1488     private Class<?> scriptClass;
1489     private String[] scriptArgs;
1490 
1491     private String[] keywords;
1492 
1493     private ServiceReader serviceReader;
1494     private ServiceManager serviceManager;
1495 
1496     private static Map<File, WeakReference<TestSuite>> dirMap = new HashMap<>(2);
1497 
1498     private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(TestSuite.class);
1499     private static String notificationLogName = i18n.getString("notification.logname");
1500 
1501     static Map<String, WorkDirLogHandler> handlersMap = new HashMap<>();
1502     private static Vector<GeneralPurposeLogger> gpls;
1503     private static Map<String, File> observedFiles;
1504 
1505     private final NotificationLogger notifLogger = new NotificationLogger(null);
1506 
1507     public static final String TM_CONTEXT_NAME = "tmcontext";
1508 
< prev index next >