1 /* 2 * $Id$ 3 * 4 * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Oracle designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Oracle in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24 * or visit www.oracle.com if you need additional information or have any 25 * questions. 26 */ 27 package com.sun.javatest; 28 29 import java.io.BufferedReader; 30 import java.io.File; 31 import java.io.FileReader; 32 import java.io.IOException; 33 import java.io.PrintStream; 34 import java.io.PrintWriter; 35 import java.io.StreamTokenizer; 36 import java.util.Date; 37 import java.util.Vector; 38 39 import com.sun.javatest.util.BackupPolicy; 40 import com.sun.javatest.util.I18NResourceBundle; 41 import com.sun.javatest.util.StringArray; 42 import com.sun.javatest.util.Timer; 43 44 /** 45 * Script is the abstract base class providing the ability to control 46 * how a test is to be compiled and executed. In addition to the primary method, 47 * <em>run</em>, it has many methods that can be used by subtype classes 48 * to assist them in performing a test. 49 */ 50 public abstract class Script 51 { 52 /** 53 * Initialize any custom args for the script. 54 * @param args custom args for the script 55 */ 56 public void initArgs(String[] args) { 57 scriptArgs = args; 58 } 59 60 /** 61 * Initialize the test description to be run by the script. 62 * In addition, a mutable test result is set up, in which the results of running 63 * the test can be recorded by the script. 64 * @param td the test description for the test to be run 65 */ 66 public void initTestDescription(TestDescription td) { 67 this.td = td; 68 testResult = new TestResult(td); 69 trOut = testResult.getTestCommentWriter(); 70 } 71 72 /** 73 * Initialize the list of test cases to be excluded from the test. 74 * The script is responsible for determining how to instruct the test 75 * not to run these test cases. A recommended convention is to pass the 76 * list of test cases to the test using a -exclude option. 77 * @param excludedTestCases a list of test cases within the test that 78 * should not be run 79 */ 80 public void initExcludedTestCases(String[] excludedTestCases) { 81 this.excludedTestCases = excludedTestCases; 82 } 83 84 /** 85 * Initialize the environment to be used when running the test. 86 * @param env the environment to be used when running the test 87 */ 88 public void initTestEnvironment(TestEnvironment env) { 89 this.env = env; 90 } 91 92 /** 93 * Initialize the work directory to be used to store the results 94 * obtained when running the test, 95 * and to store any temporary files that may be required by the test. 96 * @param workDir the work directory to be used to store the test's results. 97 */ 98 public void initWorkDir(WorkDirectory workDir) { 99 this.workDir = workDir; 100 } 101 102 /** 103 * Initialize the backup policy to be used when creating a test result 104 * file in which to store the results of running this test. 105 * @param backupPolicy A backup policy object to be used when 106 * creating test result files. 107 */ 108 public void initBackupPolicy(BackupPolicy backupPolicy) { 109 this.backupPolicy = backupPolicy; 110 } 111 112 /** 113 * Initialize the class loader for any commands to be loaded. 114 * @param loader a class loader to be used to load any commands or other 115 * user-specified classes that may be required. 116 */ 117 public void initClassLoader(ClassLoader loader) { 118 this.loader = loader; 119 } 120 121 /** 122 * Initialize a delegate script object. This should only be used in 123 * exceptional circumstances, and is mostly provided for historical purposes. 124 * @param s The delegate to be initialized 125 * @param scriptArgs the arguments to be passed to the delegate object 126 */ 127 protected void initDelegate(Script s, String[] scriptArgs) { 128 s.scriptArgs = scriptArgs; 129 // copy rest of values across from self 130 s.td = td; 131 s.env = env; 132 s.workDir = workDir; 133 s.backupPolicy = backupPolicy; 134 s.loader = loader; 135 s.testResult = testResult; 136 s.trOut = trOut; 137 s.jtrIfPassed = jtrIfPassed; 138 } 139 140 /** 141 * Initialize the test result for the result of the script execution. 142 * Normally, a test result is initialized as a side effect of calling 143 * initTestDescription. This method should only be called is special 144 * circumstances, and is mostly provided for historical purposes. 145 * @param tr The test result to set as the result of the script's execution. 146 * @throws IllegalStateException if the test result has already been set. 147 * @see #initTestDescription 148 */ 149 protected void initTestResult(TestResult tr) { 150 if (testResult != null) 151 throw new IllegalStateException(); 152 153 testResult = tr; 154 } 155 156 /** 157 * Run the script, to fill out the test results for the test description 158 * given to <code>init</code>. Most implementations will use the default 159 * implementation of this method, which delegates to a simpler (abstract) 160 * method @link(run(String[],TestDescription, TestEnvironment)). If you 161 * override this method, be aware that this method does insert many of the 162 * standard result properties into the TestResult object - harness info, 163 * start stop times, etc. 164 */ 165 public void run() { 166 if (workDir == null) 167 throw new NullPointerException(i18n.getString("script.noWorkDir")); 168 if (td == null) 169 throw new NullPointerException(i18n.getString("script.noTestDesc")); 170 if (testResult == null) 171 throw new NullPointerException(i18n.getString("script.noTestRslt")); 172 if (env == null) 173 throw new NullPointerException(i18n.getString("script.noTestEnv")); 174 175 Status execStatus = null; 176 177 // "work" has the the work dir for the suite 178 // "testWork" has the work dir for this test 179 File testWork = workDir.getFile(td.getRootRelativeDir().getPath()); 180 181 // synchronize against interference by other scripts 182 synchronized (Script.class) { 183 if (!testWork.exists()) { 184 testWork.mkdirs(); 185 } 186 } 187 188 long startMs = System.currentTimeMillis(); 189 190 String descUrl = td.getFile().toURI().toASCIIString(); 191 String id = td.getId(); 192 if (id != null) 193 descUrl += "#" + id; 194 testResult.putProperty(TestResult.DESCRIPTION, descUrl); 195 testResult.putProperty(TestResult.START, testResult.formatDate(new Date())); 196 testResult.putProperty(TestResult.VERSION, ProductInfo.getVersion()); 197 testResult.putProperty(TestResult.WORK, testWork.getAbsolutePath()); 198 testResult.putProperty(TestResult.ENVIRONMENT, env.getName()); 199 testResult.putProperty(TestResult.VARIETY, ProductInfo.getHarnessVariety()); 200 testResult.putProperty(TestResult.LOADER, ProductInfo.getPackagingType()); 201 202 if (osInfo == null) { 203 String osArch = System.getProperty("os.arch"); 204 String osName = System.getProperty("os.name"); 205 String osVersion = System.getProperty("os.version"); 206 osInfo = osName + " " + osVersion + " (" + osArch + ")"; 207 } 208 testResult.putProperty(TestResult.JAVATEST_OS, osInfo); 209 if (excludedTestCases != null) 210 testResult.putProperty("excludedTestCases", StringArray.join(excludedTestCases)); 211 212 String classDir = td.getParameter("classDir"); 213 File f = (classDir == null ? workDir.getFile(defaultClassDir) : 214 new File(testWork, classDir)); 215 env.putUrlAndFile("testClassDir", f); 216 env.putUrlAndFile("testWorkDir", testWork); 217 env.put("test", td.getFile().getPath()); 218 env.put("testDir", td.getFile().getParent()); 219 env.put("testURL", descUrl); 220 env.put("testPath", td.getRootRelativeURL()); 221 222 int timeout = getTestTimeout(); 223 PrintStream out = System.out; 224 PrintStream err = System.err; 225 226 try { 227 testResult.putProperty(TestResult.TEST, td.getRootRelativeURL()); 228 StringBuilder sb = new StringBuilder(this.getClass().getName()); 229 String args = StringArray.join(scriptArgs); 230 if (args != null && args.length() > 0) { 231 sb.append(" "); 232 sb.append(args); 233 } 234 testResult.putProperty(TestResult.SCRIPT, sb.toString()); 235 236 if (timeout > 0) { 237 testResult.putProperty("timeoutSeconds", Integer.toString(timeout)); 238 setAlarm(timeout*1000); 239 } 240 241 execStatus = run(scriptArgs, td, env); 242 } 243 finally { 244 if (timeout > 0) 245 setAlarm(0); 246 247 try { 248 System.setOut(System.out); 249 System.setErr(System.err); 250 } 251 catch (SecurityException ignore) { 252 } 253 254 if (Thread.interrupted()) // will clear interrupted status of thread, as desired 255 execStatus = Status.error(i18n.getString("script.interrupted")); 256 257 testResult.putProperty(TestResult.END, 258 testResult.formatDate(new Date())); 259 260 if (execStatus == null) { 261 execStatus = Status.error(i18n.getString("script.noStatus")); 262 } 263 else { 264 switch (execStatus.getType()) { 265 case Status.PASSED: 266 case Status.FAILED: 267 case Status.ERROR: 268 break; 269 default: 270 execStatus = Status.error(i18n.getString("script.badTestStatus", execStatus)); 271 } 272 } 273 274 } 275 276 testResult.setEnvironment(env); 277 testResult.putProperty("totalTime", Long.toString(System.currentTimeMillis() - startMs)); 278 testResult.setStatus(execStatus); 279 280 try { 281 if (execStatus.getType() != Status.PASSED || jtrIfPassed) 282 testResult.writeResults(workDir, backupPolicy); 283 } 284 catch (IOException e) { 285 // ignore it; the test will have an error status already 286 //throw new JavaTestError("Unable to write result file! " + e); 287 } 288 } 289 290 /** 291 * The primary method to be provided by Scripts. It is responsible for compiling 292 * and executing the test appropiately. Normally, a script should call `init' and 293 * then decode any script-specific options it is given in `args'. It should then 294 * examine the test description it is given so that it can compile and execute 295 * the test as appropriate. Various convenience routines are provided to 296 * simplify the task of running the compiler, an interpreter or any other commands, 297 * which can be specified in a flexible manner by properties in the TestEnvironment. 298 * 299 * @param args Any script-specific options specified in the script property 300 * @param td The test description for the test to be performed 301 * @param env The test environment giving the details of how to run the test 302 * @return The result of running the script 303 * @see #compileIndividually 304 * @see #compileTogether 305 * @see #execute 306 * @see #invokeCommand 307 */ 308 public abstract Status run(String[] args, TestDescription td, TestEnvironment env); 309 310 /** 311 * Get the test description for the test which this script will run. 312 * @return the test description for the test which this script will run. 313 */ 314 public TestDescription getTestDescription() { 315 return td; 316 } 317 318 /** 319 * Get the test result object to be used for the results of the test run. 320 * @return the test result object to be used for the results of the test run. 321 */ 322 public TestResult getTestResult() { 323 return testResult; 324 } 325 326 /** 327 * Get the flag that indicates whether a result (.jtr) file should be written 328 * even if the test has passed. By default, this is true. 329 * @return the flag that indicates whether a result (.jtr) file should be written 330 * even if the test has passed. 331 * @see #setJTRIfPassed 332 */ 333 public boolean getJTRIfPassed() { 334 return jtrIfPassed; 335 } 336 337 /** 338 * Set the flag that indicates whether a result (.jtr) file should be written 339 * even if the test has passed. By default, this is true. 340 * @param b the flag that indicates whether a result (.jtr) file should be written 341 * even if the test has passed. 342 * @see #getJTRIfPassed 343 */ 344 public void setJTRIfPassed(boolean b) { 345 jtrIfPassed = b; 346 } 347 348 /** 349 * Set an alarm that will interrupt the calling thread after 350 * a specified delay (in milliseconds), and repeatedly thereafter 351 * until cancelled. 352 * Typical usage: 353 * <pre> 354 * try { 355 * setAlarm(delay); 356 * ... 357 * } 358 * finally { 359 * setAlarm(0); 360 * } 361 * </pre> 362 * @param timeout the interval (in milliseconds) after which the calling 363 * thread will be interrupted, if not cancelled in the meantime. 364 */ 365 protected void setAlarm(int timeout) { 366 setAlarm(timeout, Thread.currentThread()); 367 } 368 369 370 /** 371 * Set an alarm that will interrupt a given thread after 372 * a specified delay (in milliseconds), and repeatedly thereafter 373 * until cancelled. 374 * Typical usage: 375 * <pre> 376 * try { 377 * setAlarm(delay); 378 * ... 379 * } 380 * finally { 381 * setAlarm(0); 382 * } 383 * </pre> 384 * @param timeout the interval (in milliseconds) after which the calling 385 * thread will be interrupted, if not cancelled in the meantime. 386 * @param threadToInterrupt which thread to interrupt 387 */ 388 protected void setAlarm(int timeout, Thread threadToInterrupt) { 389 if (alarm != null) { 390 alarm.cancel(); 391 alarm = null; 392 } 393 394 if (timeout > 0) 395 alarm = new Alarm(timeout, threadToInterrupt); 396 } 397 398 /** 399 * Set TimeoutProvider used to control test timeouts. 400 * 401 * @see TimeoutProvider 402 * @see #getTestTimeout() 403 * @see #getTimeoutProvider() 404 * @param provider null to use default test timeout value (10 sec). 405 */ 406 public void setTimeoutProvider(TimeoutProvider provider) { 407 if(provider != this.provider) { 408 this.provider = provider; 409 } 410 } 411 412 /** 413 * Getter for TimeoutProvider. Generates default (10*factor) 414 * provider in case no provider is set 415 * 416 * @return TimeoutProvider set to Script. Returns default 417 * TimeoutProvider in case no TimeoutProvider 418 * is set (or it is set to null). 419 * The default implementation is 10 minutes scaled by 420 * a value found in the environment ("javatestTimeoutFactor"). 421 * @see #setTimeoutProvider(com.sun.javatest.Script.TimeoutProvider) 422 * @see #getTestTimeout() 423 * @see TimeoutProvider 424 */ 425 public TimeoutProvider getTimeoutProvider() { 426 if(provider == null) { 427 provider = new DefaultTimeoutProvider(); 428 } 429 return provider; 430 } 431 432 /** 433 * Get the timeout to be used for a test. 434 * Uses TimeoutProvider to get test timeout value. The default 435 * implementation of TimeoutProvider is 10 minutes scaled by 436 * a value found in the environment ("javatestTimeoutFactor"). 437 * This method can be overriden to provide different behaviors. 438 * A value of zero means no timeout. 439 * @return the number of seconds in which the test is expected to 440 * complete its execution. 441 * @see #getTimeoutProvider() 442 * @see #setTimeoutProvider(com.sun.javatest.Script.TimeoutProvider) 443 * @see TimeoutProvider 444 */ 445 protected int getTestTimeout() { 446 // use "getTimeoutProvider()." instead of "provider." to generate default (10min*factor) timeout provider 447 return getTimeoutProvider().getTestTimeout(); 448 } 449 450 /** 451 * Compile the given source files individually. One at a time, each source file 452 * is passed to <em>compileTogether</em>, until they have all been 453 * successfully compiled, or until one fails to compile. 454 * @param srcs The names of the file to be compiled. 455 * @return The status of the compilation: passed or failed. 456 * @see #compileTogether 457 */ 458 protected Status compileIndividually(String[] srcs) { 459 return compileIndividually(DEFAULT_COMPILE_COMMAND, srcs); 460 } 461 462 /** 463 * Compile the given source files individually. One at a time, each source file 464 * is passed to <em>compileTogether</em>, until they have all been 465 * successfully compiled, or until one fails to compile. 466 * @param command the base name of the command entry in the environment to be used 467 * to compile any necessary sources. The complete entry name will be 468 * <code>command.</code><i>command</i><code>.</code><i>extn</i> 469 * @param srcs The names of the file to be compiled. 470 * @return The status of the compilation: passed or failed. 471 * @see #compileTogether 472 */ 473 protected Status compileIndividually(String command, String[] srcs) { 474 if (srcs.length == 0) 475 return error_noSource; 476 477 for (int i = 0; i < srcs.length; i++) { 478 Status s = compileOne(command, srcs[i]); 479 if (!s.isPassed()) 480 return s; 481 } 482 return pass_compSuccExp; 483 } 484 485 /** 486 * Compile the given source files individually. One at a time, each source file 487 * is passed to <em>compileTogether</em>, until they have all been 488 * successfully compiled, or until one fails to compile. 489 * @param srcs The names of the file to be compiled. 490 * @return The status of the compilation: passed or failed. 491 * @see #compileTogether 492 */ 493 protected Status compileIndividually(File[] srcs) { 494 return compileIndividually(DEFAULT_COMPILE_COMMAND, filesToStrings(srcs)); 495 } 496 497 /** 498 * Compile the given source files individually. One at a time, each source file 499 * is passed to <em>compileTogether</em>, until they have all been 500 * successfully compiled, or until one fails to compile. 501 * @param command the base name of the command entry in the environment to be used 502 * to compile any necessary sources. The complete entry name will be 503 * <code>command.</code><i>command</i><code>.</code><i>extn</i> 504 * @param srcs The names of the file to be compiled. 505 * @return The status of the compilation: passed or failed. 506 * @see #compileTogether 507 */ 508 protected Status compileIndividually(String command, File[] srcs) { 509 return compileIndividually(command, filesToStrings(srcs)); 510 } 511 512 /** 513 * Compile the given source file. 514 * @param src The name of the file to be compiled. 515 * @return The status of the compilation: passed or failed. 516 * @see #compileTogether 517 */ 518 protected Status compileOne(String src) { 519 return compileOne(DEFAULT_COMPILE_COMMAND, src); 520 } 521 522 /** 523 * Compile the given source file. The file is treated as a singleton group 524 * and passed to <em>compileTogether</em>. 525 * @param command the base name of the command entry in the environment to be used 526 * to compile any necessary sources. The complete entry name will be 527 * <code>command.</code><i>command</i><code>.</code><i>extn</i> 528 * @param src The name of the file to be compiled. 529 * @return The status of the compilation: passed or failed. 530 * @see #compileTogether 531 */ 532 protected Status compileOne(String command, String src) { 533 return compileTogether(command, new String[] {src}); 534 } 535 536 /** 537 * Compiles the given source file. 538 * 539 * @param src The name of the file to be compiled. 540 * @return The status of the compilation: passed or failed. 541 * @see #compileTogether 542 */ 543 protected Status compileOne(File src) { 544 return compileOne(DEFAULT_COMPILE_COMMAND, src.getPath()); 545 } 546 547 /** 548 * Compiles the given source file. 549 * 550 * @param command the base name of the command entry in the environment to be used 551 * to compile any necessary sources. The complete entry name will be 552 * <code>command.</code><i>command</i><code>.</code><i>extn</i> 553 * @param src The name of the file to be compiled. 554 * @return The status of the compilation: passed or failed. 555 * @see #compileTogether 556 */ 557 protected Status compileOne(String command, File src) { 558 return compileOne(command, src.getPath()); 559 } 560 561 /** 562 * Compile the given source files together. The compiler and arguments to be used 563 * are identified by the `<code>env.<em>env</em>.compile.<em>extn</em>.*</code>' 564 * properties in the script's environment, where <em>env</em> 565 * is the name of the environment specified to the GUI, and <em>extn</em> is 566 * the extension of the first source file. The names of the files to be compiled 567 * are added to the end of the arguments retrieved from the environment. 568 * @param srcs The names of the file to be compiled. 569 * @return The status of the compilation: passed or failed. 570 * @see #invokeCommand 571 */ 572 protected Status compileTogether(String[] srcs) { 573 return compileTogether(DEFAULT_COMPILE_COMMAND, srcs); 574 } 575 576 /** 577 * Compile the given source files together. The compiler and arguments to be used 578 * are identified by the `<code>env.<em>env</em>.command.<em>command</em>.<em>extn</em>.*</code>' 579 * properties in the script's environment, where <em>env</em> 580 * is the name of the environment specified to the GUI, and <em>extn</em> is 581 * the extension of the first source file. The names of the files to be compiled 582 * are added to the end of the arguments retrieved from the environment. 583 * @param command the base name of the command entry in the environment to be used 584 * to compile any necessary sources. The complete entry name will be 585 * <code>command.</code><i>command</i><code>.</code><i>extn</i> 586 * @param srcs The names of the file to be compiled. 587 * @return The status of the compilation: passed or failed. 588 * @see #invokeCommand 589 */ 590 protected Status compileTogether(String command, String[] srcs) { 591 if (srcs.length == 0) 592 return error_noSource; 593 594 try { 595 String[] classDir = env.lookup("testClassDir"); 596 if (classDir == null || classDir.length != 1) 597 return error_badTestClassDir; 598 File f = new File(classDir[0]); 599 if (!f.exists()) 600 f.mkdirs(); 601 } 602 catch (TestEnvironment.Fault e) { 603 return error_badTestClassDir; 604 } 605 606 String primarySrcFile = srcs[0]; 607 int dot = primarySrcFile.lastIndexOf('.'); 608 if (dot == -1) 609 return error_noExtnInSource; 610 611 String extn = primarySrcFile.substring(dot); 612 613 env.put("testSource", srcs); 614 615 try { 616 boolean ok = sourceTable.acquire(srcs, 10*60*1000); 617 if (!ok) 618 return Status.error(i18n.getString("script.srcLockTimeout")); 619 return invokeCommand(command + extn); 620 } 621 catch (InterruptedException e) { 622 return Status.error(i18n.getString("script.srcLockInterrupted")); 623 } 624 finally { 625 sourceTable.release(srcs); 626 } 627 } 628 629 private static ResourceTable sourceTable = new ResourceTable(); 630 631 /** 632 * Compile the given source files together. The compiler and arguments to be used 633 * are identified by the `<code>env.<em>env</em>.command.compile.<em>extn</em>.*</code>' 634 * properties in the script's environment, where <em>env</em> 635 * is the name of the environment specified to the GUI, and <em>extn</em> is 636 * the extension of the first source file. The names of the files to be compiled 637 * are added to the end of the arguments retrieved from the environment. 638 * @param srcs The names of the file to be compiled. 639 * @return The status of the compilation: passed or failed. 640 * @see #invokeCommand 641 */ 642 protected Status compileTogether(File[] srcs) { 643 return compileTogether(DEFAULT_COMPILE_COMMAND, filesToStrings(srcs)); 644 } 645 646 /** 647 * Compile the given source files together. The compiler and arguments to be used 648 * are identified by the `<code>env.<em>env</em>.command.<em>command</em>.<em>extn</em>.*</code>' 649 * properties in the script's environment, where <em>env</em> 650 * is the name of the environment specified to the GUI, and <em>extn</em> is 651 * the extension of the first source file. The names of the files to be compiled 652 * are added to the end of the arguments retrieved from the environment. 653 * @param command the base name of the command entry in the environment to be used 654 * to compile any necessary sources. The complete entry name will be 655 * <code>command.</code><i>command</i><code>.</code><i>extn</i> 656 * @param srcs The names of the file to be compiled. 657 * @return The status of the compilation: passed or failed. 658 * @see #invokeCommand 659 */ 660 protected Status compileTogether(String command, File[] srcs) { 661 return compileTogether(command, filesToStrings(srcs)); 662 } 663 664 /** 665 * Compile those source files for which the corresponding class file appears to 666 * be out of date. Each source file is scanned to find a package statement to help 667 * determine the main class defined in the source file -- the corresponding class 668 * file in the given class directory is then checked, and if the source file is newer, 669 * it is put on a list to be recompiled. After checking all the source files, if any 670 * need to be recompiled, they will be compiled together, using the default compile 671 * command ("command.compile.extn") entry in the the environment. 672 * @param srcs The names of the source files to be compiled if necessary 673 * @param classDir The class directory in which the corresponding class files 674 * (if any) will be found. 675 * @return The status of the compilation: passed or failed. 676 * @see #compileTogether 677 */ 678 protected Status compileIfNecessary(String[] srcs, String classDir) { 679 return compileIfNecessary(DEFAULT_COMPILE_COMMAND, srcs, classDir); 680 } 681 682 /** 683 * Compile those source files for which the corresponding class file appears to 684 * be out of date. Each source file is scanned to find a package statement to help 685 * determine the main class defined in the source file -- the corresponding class 686 * file in the given class directory is then checked, and if the source file is newer, 687 * it is put on a list to be recompiled. After checking all the source files, if any 688 * need to be recompiled, they will be compiled together, using the specified compile 689 * command entry in the the environment. 690 * @param command the base name of the command entry in the environment to be used 691 * to compile any necessary sources. The complete entry name will be 692 * <code>command.</code><i>command</i><code>.</code><i>extn</i> 693 * @param srcs The names of the source files to be compiled if necessary 694 * @param classDir The class directory in which the corresponding class files 695 * (if any) will be found. 696 * @return The status of the compilation: passed or failed. 697 * @see #compileTogether 698 */ 699 protected Status compileIfNecessary(String command, String[] srcs, String classDir) { 700 if (srcs.length == 0) 701 return error_noSource; 702 703 if (classDir == null) 704 classDir = "$testClassDir"; 705 706 if (classDir.startsWith("$")) { 707 try { 708 String[] cd = env.resolve(classDir); 709 if (cd == null || cd.length != 1) 710 return error_badTestClassDir; 711 classDir = cd[0]; 712 } 713 catch (TestEnvironment.Fault e) { 714 return error_badTestClassDir; 715 } 716 } 717 718 File cdf = new File(classDir); 719 if (!cdf.exists()) 720 cdf.mkdirs(); 721 722 Vector<String> v = new Vector<>(0, srcs.length); 723 724 for (int i = 0; i < srcs.length; i++) { 725 String src = srcs[i]; 726 int x = src.lastIndexOf(File.separatorChar); 727 int y = src.indexOf('.', x+1); 728 String className = src.substring(x+1, (y == -1 ? src.length() : y)); 729 String pkgPrefix; // deliberately unset to have compiler check init in all required cases 730 731 // read the source file to see if a package statement exists 732 // if it does, set pkgPrefix to package directory 733 // if none found, set setPrefix to empty string 734 // if error, report the error, ignore pkgPrefix, and set file to 735 // be unconditionally compiled. 736 try (BufferedReader r = new BufferedReader(new FileReader(src))) { 737 StreamTokenizer tr = new StreamTokenizer(r); 738 tr.ordinaryChar('/'); 739 tr.slashStarComments(true); 740 tr.slashSlashComments(true); 741 tr.wordChars('.', '.'); // package separator 742 int c = tr.nextToken(); 743 if (c == StreamTokenizer.TT_WORD && tr.sval.equals("package")) { 744 // found what looks like a package statement 745 c = tr.nextToken(); 746 if (c == StreamTokenizer.TT_WORD) 747 // yes, it was a valid package statement 748 pkgPrefix = tr.sval.replace('.', File.separatorChar) + File.separatorChar; 749 else { 750 // well, sort of; malformed package statement 751 trOut.println(i18n.getString("script.badPackage")); 752 v.addElement(src); 753 continue; 754 } 755 } 756 else 757 // no package statement 758 pkgPrefix = ""; 759 } 760 catch (IOException e) { 761 trOut.println(i18n.getString("script.badDateStamp", new Object[] { src, e })); 762 v.addElement(src); 763 continue; 764 } 765 766 767 File srcFile = new File(src); 768 File classFile = new File(classDir, pkgPrefix + className + ".class"); 769 //System.out.println("checking " + classFile); 770 //System.out.println("classfile " + classFile.lastModified()); 771 //System.out.println("srcfile " + srcFile.lastModified()); 772 if (classFile.exists() && classFile.lastModified() > srcFile.lastModified()) 773 trOut.println(i18n.getString("script.upToDate", src)); 774 else 775 v.addElement(src); 776 } 777 778 if (v.size() > 0) { 779 String[] necessarySrcs = new String[v.size()]; 780 v.copyInto(necessarySrcs); 781 782 return compileTogether(command, necessarySrcs); 783 } 784 else 785 return Status.passed(i18n.getString("script.allUpToDate")); 786 } 787 788 /** 789 * Compile those source files for which the corresponding class file appears to 790 * be out of date. Each source file is scanned to find a package statement to help 791 * determine the main class defined in the source file -- the corresponding class 792 * file in the given class directory is then checked, and if the source file is newer, 793 * it is put on a list to be recompiled. After checking all the source files, if any 794 * need to be recompiled, they will be compiled together, using the default compile 795 * command ("command.compile.extn") entry in the the environment. 796 * @param srcs The names of the source files to be compiled if necessary 797 * @param classDir The class directory in which the corresponding class files 798 * (if any) will be found. 799 * @return The status of the compilation: passed or failed. 800 * @see #compileTogether 801 */ 802 protected Status compileIfNecessary(File[] srcs, String classDir) { 803 return compileIfNecessary(DEFAULT_COMPILE_COMMAND, filesToStrings(srcs), classDir); 804 } 805 806 /** 807 * Compile those source files for which the corresponding class file appears to 808 * be out of date. Each source file is scanned to find a package statement to help 809 * determine the main class defined in the source file -- the corresponding class 810 * file in the given class directory is then checked, and if the source file is newer, 811 * it is put on a list to be recompiled. After checking all the source files, if any 812 * need to be recompiled, they will be compiled together, using the specified compile 813 * command entry in the the environment. 814 * @param command the base name of the command entry in the environment to be used 815 * to compile any necessary sources. The complete entry name will be 816 * <code>command.</code><i>command</i><code>.</code><i>extn</i> 817 * @param srcs The names of the source files to be compiled if necessary 818 * @param classDir The class directory in which the corresponding class files 819 * (if any) will be found. 820 * @return The status of the compilation: passed or failed. 821 * @see #compileTogether 822 */ 823 protected Status compileIfNecessary(String command, File[] srcs, String classDir) { 824 return compileIfNecessary(command, filesToStrings(srcs), classDir); 825 } 826 827 /** 828 * Execute the given class with the given arguments, which need to be passed 829 * to the environment for $ substitution and for splitting into separate strings. 830 * @param executeClass The name of the class to be executed 831 * @param executeArgs The arguments to be evaluated before passing to 832 * the class to be executed 833 * @return The status of the execution 834 * @see #execute(java.lang.String, java.lang.String, java.lang.String) 835 */ 836 protected Status execute(String executeClass, String executeArgs) { 837 return execute(DEFAULT_EXECUTE_COMMAND, executeClass, executeArgs); 838 } 839 840 /** 841 * Execute the given class with the given arguments, which need to be passed 842 * to the environment for $ substitution and for splitting into separate strings. 843 * @param command The name of the command containing the template to be executed 844 * @param executeClass The name of the class to be executed 845 * @param executeArgs The arguments to be evaluated before passing to 846 * the class to be executed 847 * @return The status of the execution 848 */ 849 protected Status execute(String command, String executeClass, 850 String executeArgs) { 851 try { 852 String[] args = (executeArgs == null ? nullArgs : env.resolve(executeArgs)); 853 if (excludedTestCases != null) 854 args = exclude(args, excludedTestCases); 855 return execute(command, executeClass, args); 856 } 857 catch (TestEnvironment.Fault e) { 858 trOut.println(i18n.getString("script.testEnvFault", 859 new Object[] { executeArgs, e.toString() })); 860 return error_badExecuteArgs; 861 } 862 } 863 864 /** 865 * Execute the given class with the given arguments. The interpreter to be used 866 * and its arguments are identified by the `<code>env.<em>env</em>.execute.*</code>' 867 * properties in the script's environment, where <em>env</em> 868 * is the name of the environment specified to the GUI. The class to be executed and 869 * its arguments are added to the end of the arguments retrieved from the environment. 870 * @param executeClass The name of the class to be executed. 871 * @param executeArgs Any arguments to be passed to the class to be executed. 872 * @return The status of the execution 873 * @see #execute(java.lang.String, java.lang.String, java.lang.String[]) 874 */ 875 protected Status execute(String executeClass, String[] executeArgs) { 876 return execute(DEFAULT_EXECUTE_COMMAND, executeClass, executeArgs); 877 } 878 879 /** 880 * Execute the given class with the given arguments. The interpreter to be used 881 * and its arguments are identified by the `<code>env.<em>env</em>.<em>command</em>.*</code>' 882 * properties in the script's environment, where <em>env</em> 883 * is the name of the environment specified to the GUI. The class to be executed and 884 * its arguments are added to the end of the arguments retrieved from the environment. 885 * @param command The name of the command containing the template to be executed 886 * @param executeClass The name of the class to be executed. 887 * @param executeArgs Any arguments to be passed to the class to be executed. 888 * @return The status of the execution 889 * @see #invokeCommand 890 */ 891 protected Status execute(String command, String executeClass, String[] executeArgs) { 892 if (executeClass == null || executeClass.length() == 0) 893 return error_noExecuteClass; 894 env.put("testExecuteClass", executeClass); 895 env.put("testExecuteArgs", executeArgs); 896 return invokeCommand(command); 897 } 898 899 /** 900 * RMI Compile the given class files. The compiler and arguments to be used 901 * is identified by the `<code>env.<em>env</em>.command.rmic</code>' 902 * property in the script's environment, where <em>env</em> 903 * is the name of the environment specified to the GUI. 904 * The name of the classes to be compiled by rmic is obtained from the 905 * test description. 906 * @param classes The names of the classes to be compiled by rmic. 907 * @return The status of the compilation: passed or failed. 908 * @see #invokeCommand 909 */ 910 protected Status rmiCompile(String[] classes) { 911 return rmiCompile(DEFAULT_RMIC_COMMAND, classes); 912 } 913 914 /** 915 * RMI Compile the given class files. The compiler and arguments to be used 916 * is identified by the `<code>env.<em>env</em>.command.<em>command</em></code>' 917 * property in the script's environment, where <em>env</em> 918 * is the name of the environment specified to the GUI. 919 * The name of the classes to be compiled by rmic is obtained from the 920 * test description. 921 * @param command The name of the command containing the template to be compiled 922 * @param classes The names of the classes to be compiled by rmic. 923 * @return The status of the compilation: passed or failed. 924 * @see #invokeCommand 925 */ 926 protected Status rmiCompile(String command, String[] classes) { 927 try { 928 String[] classDir = env.lookup("testClassDir"); 929 if (classDir == null || classDir.length != 1) 930 return error_badTestClassDir; 931 File f = new File(classDir[0]); 932 if (!f.exists()) 933 f.mkdirs(); 934 } 935 catch (TestEnvironment.Fault e) { 936 return error_badTestClassDir; 937 } 938 939 if (classes == null || classes.length == 0) 940 return error_noRMIClasses; 941 942 env.put("testRmicClasses", classes); 943 // backwards compatibility 944 env.put("testRmicClass", classes); 945 return invokeCommand(command); 946 } 947 948 949 /** 950 * Invoke a command in the environment identified by a given key. 951 * The command is identified by looking up `<code>command.<em>key</em></code>' 952 * property in the environment. The first word of this property identifies 953 * the name of a class that should be an implementation of <code>Command</code>, 954 * and the subsequent words are the arguments to be passed to a fresh instance 955 * of that class, via its <code>run</code> method. 956 * Standard library implementations of <code>Command</code> are available, 957 * such as: 958 * <DL> 959 * <DT>com.sun.javatest.lib.ProcessCommand 960 * <DD>Execute a command in a separate process 961 * <DT>com.sun.javatest.lib.ExecStdTestSameJVMCmd 962 * <DD>Execute a standard test in the same JVM as JT Harness 963 * <DT>com.sun.javatest.agent.PassiveAgentCommand 964 * <DD>Execute a command on a remote machine 965 * </DL> 966 * For full details, the documentation for the various appropriate classes. 967 * 968 * <p> The use of `<code>command.<em>key</em></code>' supercedes an earlier 969 * mechanism involving multiple properties. For backwards compatibility, 970 * if the `<code>command.<em>key</em></code>' property is not found, the 971 * properties for the earlier mechanism are checked as well. 972 * 973 * @param key The tag for the command to be executed 974 * @return A status giving the outcome of the command 975 * 976 * @see Command 977 * 978 */ 979 protected Status invokeCommand(String key) { 980 TestResult.Section section; 981 Status s = null; 982 983 try { 984 String[] command = env.lookup("command." + key); 985 986 if (command.length == 0) 987 return Status.error(i18n.getString("script.noCommand", 988 new Object[] { env.getName(), key })); 989 990 String className = command[0]; 991 String[] args = new String[command.length - 1]; 992 System.arraycopy(command, 1, args, 0, args.length); 993 994 section = testResult.createSection(key); 995 996 section.getMessageWriter().println(i18n.getString("script.command", 997 new Object[] {className, StringArray.join(args) })); 998 999 try (PrintWriter out1 = section.createOutput(cmdOut1Name); 1000 PrintWriter out2 = section.createOutput(cmdOut2Name)) { 1001 1002 s = invokeClass(className, args, out1, out2); 1003 } 1004 1005 section.setStatus(s); 1006 return s; 1007 } 1008 catch (TestEnvironment.Fault e) { 1009 return Status.error(i18n.getString("script.badCommand", 1010 new Object[] { env.getName(), key })); 1011 } 1012 } 1013 1014 /** 1015 * Set the default names of the two default output streams used when executing a 1016 * command. In many cases these may correspond to the UNIX-style standard-out 1017 * and standard-error streams. This API does not define what they are used for 1018 * though, and architects are encouraged to give descriptive names if possible. 1019 * 1020 * @param out1Name Name of the first stream. 1021 * @param out2Name Name of the second stream. 1022 */ 1023 protected void setDefaultCommandStreamNames(String out1Name, String out2Name) { 1024 cmdOut1Name = out1Name; 1025 cmdOut2Name = out2Name; 1026 } 1027 1028 /** 1029 * Create and run a Command object. 1030 * @param className The name of the class to load and instantiate. 1031 * @param args The args to pass to the `run' method of the loaded object. 1032 * @return The result identifies any problems that may occur in trying 1033 * to create and run the specified object, or if it succeeds, 1034 * it returns the result from calling the object's `run' method. 1035 * @see Command 1036 */ 1037 private Status invokeClass(String className, String[] args, 1038 PrintWriter out1, PrintWriter out2) { 1039 // this is the central place where we get to run what the user 1040 // says in the environment file: 1041 Command testCommand; 1042 try { 1043 Class c = (loader == null ? Class.forName(className) : loader.loadClass(className)); 1044 testCommand = (Command)(c.newInstance()); 1045 } 1046 catch (ClassCastException e) { 1047 return Status.error(i18n.getString("script.cantRunClass", 1048 new Object[] { className, Command.class.getName() })); 1049 } 1050 catch (ClassNotFoundException ex) { 1051 return Status.error(i18n.getString("script.cantFindClass", 1052 new Object[] { className, env.getName() })); 1053 } 1054 catch (IllegalAccessException ex) { 1055 return Status.error(i18n.getString("script.cantAccessClass", 1056 new Object[] { className, env.getName() })); 1057 } 1058 catch (IllegalArgumentException ex) { 1059 return Status.error(i18n.getString("script.badClassName", 1060 new Object[] { className, env.getName() })); 1061 } 1062 catch (InstantiationException ex) { 1063 return Status.error(i18n.getString("script.cantCreateClass", 1064 new Object[] { className, env.getName() })); 1065 } 1066 catch (ThreadDeath e) { 1067 throw (ThreadDeath)(e.fillInStackTrace()); 1068 } 1069 catch (Exception e) { 1070 e.printStackTrace(out1); 1071 return Status.error(i18n.getString("script.unexpLoadExc", new Object[] { className, e })); 1072 } 1073 catch (Error e) { 1074 e.printStackTrace(out1); 1075 return Status.error(i18n.getString("script.unexpLoadErr", new Object[] { className, e })); 1076 } 1077 catch (Throwable e) { 1078 e.printStackTrace(out1); 1079 return Status.error(i18n.getString("script.unexpLoadThr", new Object[] { className, e })); 1080 } 1081 1082 try { 1083 testCommand.setClassLoader(loader); 1084 return testCommand.run(args, out1, out2); 1085 } 1086 catch (ThreadDeath e) { 1087 throw (ThreadDeath)(e.fillInStackTrace()); 1088 } 1089 catch (Exception e) { 1090 e.printStackTrace(out1); 1091 // error reduced to failed in following line for benefit of negative tests 1092 return Status.failed(i18n.getString("script.unexpExecExc", new Object[] { className, e })); 1093 } 1094 catch (Error e) { 1095 e.printStackTrace(out1); 1096 // error reduced to failed in following line for benefit of negative tests 1097 return Status.failed(i18n.getString("script.unexpExecErr", new Object[] { className, e })); 1098 } 1099 catch (Throwable e) { 1100 e.printStackTrace(out1); 1101 // error *NOT* reduced to failed in following line for benefit of 1102 // negative tests: test should never throw something which is not 1103 // an Exception or Error 1104 return Status.error(i18n.getString("script.unexpExecThr", new Object[] { className, e })); 1105 } 1106 1107 } 1108 1109 /** 1110 * Modify the args for a test to be executed, according to a set 1111 * of test cases to be excluded. If there are no test cases to be excluded, 1112 * the result will be the original args unchanged; otherwise, the 1113 * result will be the original args prefixed by "-exclude" and a 1114 * comma-separated list of exclude test cases. 1115 * @param args The basic list of args for the test 1116 * @param testCases the set of test cases to be excluded, or null if none 1117 * @return The original list of args, possibly prefixed by "-exclude" 1118 * and a comma-separated list of test cases that should not be executed by 1119 * the test 1120 */ 1121 protected String[] exclude(String[] args, String[] testCases) { 1122 if (testCases == null) 1123 return args; 1124 StringBuffer sb = new StringBuffer(); 1125 for (int i = 0; i < testCases.length; i++) { 1126 if (i > 0) 1127 sb.append(","); 1128 sb.append(testCases[i]); 1129 } 1130 String[] newArgs = new String[args.length + 2]; 1131 newArgs[0] = "-exclude"; 1132 newArgs[1] = sb.toString(); 1133 System.arraycopy(args, 0, newArgs, 2, args.length); 1134 testResult.putProperty("exclude", newArgs[1]); 1135 return newArgs; 1136 } 1137 1138 /** 1139 * Utility routine to convert an array of filenames to a corresponding 1140 * array of strings. 1141 * @param files The filenames to be converted 1142 * @return The corresponding strings 1143 */ 1144 protected static String[] filesToStrings(File[] files) { 1145 String[] strings = new String[files.length]; 1146 for (int i = 0; i < files.length; i++) 1147 strings[i] = files[i].getPath(); 1148 return strings; 1149 } 1150 1151 /** 1152 * The test description for the test being performed. 1153 */ 1154 protected TestDescription td; // required 1155 1156 /** 1157 * The set of test cases to be excluded for this test. 1158 */ 1159 protected String[] excludedTestCases; // optional, may be null 1160 1161 /** 1162 * The test environment for the test being performed. 1163 */ 1164 protected TestEnvironment env; // required 1165 1166 /** 1167 * The initialization args for the script. 1168 */ 1169 protected String[] scriptArgs; // optional 1170 1171 /** 1172 * The work directory for the test run. 1173 */ 1174 protected WorkDirectory workDir; // required 1175 1176 /** 1177 * The default name for the TestResult section used to save the data written to the out1 stream 1178 * for a command. 1179 * @see Command#run 1180 */ 1181 protected String cmdOut1Name = "out1"; 1182 1183 /** 1184 * The default name for the TestResult section used to save the data written to the out2 stream 1185 * for a command. 1186 * @see Command#run 1187 */ 1188 protected String cmdOut2Name = "out2"; 1189 1190 /** 1191 * A backup policy object that specifies how files should be backed up, 1192 * if a file is found to exist when a new one of the same name is to be 1193 * written. 1194 */ 1195 protected BackupPolicy backupPolicy = BackupPolicy.noBackups(); // optional 1196 1197 /** 1198 * The class loader to be used to load additional user-specified classes 1199 * as required in the execution of the script. 1200 */ 1201 protected ClassLoader loader; // optional, may be null 1202 1203 /** 1204 * The reporting channel for the test being performed. 1205 */ 1206 protected PrintWriter trOut; 1207 1208 // have to define this before the definitions that follow 1209 private static final I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(Script.class); 1210 1211 // use getTimeoutProvider and setTimeoutProvider 1212 private TimeoutProvider provider = null; 1213 1214 // convenience definitions 1215 1216 /** 1217 * A status that may be used to indicate problems in the executeArgs field 1218 * of a test description. 1219 */ 1220 protected static final Status 1221 error_badExecuteArgs = Status.error(i18n.getString("script.badExecuteArgs")); 1222 1223 /** 1224 * A status that may be used to indicate a problem with a test's class directory. 1225 */ 1226 protected static final Status 1227 error_badTestClassDir = Status.error(i18n.getString("script.badTestClassDir")); 1228 1229 /** 1230 * A status that may be used to indicate that a compilation failed unexpectedly. 1231 */ 1232 protected static final Status 1233 error_compFailUnexp = Status.error(i18n.getString("script.compFailUnexp")); 1234 1235 /** 1236 * A status that may be used to indicate that no action was specified. 1237 */ 1238 protected static final Status 1239 error_noActionSpecified = Status.error(i18n.getString("script.noAction")); 1240 1241 /** 1242 * A status that may be used to indicate that no execute class was specified in a test description. 1243 */ 1244 protected static final Status 1245 error_noExecuteClass = Status.error(i18n.getString("script.noExecuteClass")); 1246 1247 /** 1248 * A status that may be used to indicate that no extension was found in a source file. 1249 */ 1250 protected static final Status 1251 error_noExtnInSource = Status.error(i18n.getString("script.noExtnInSrc")); 1252 1253 /** 1254 * A status that may be used to indicate that no rmi classes were specified in a test description. 1255 */ 1256 protected static final Status 1257 error_noRMIClasses = Status.error(i18n.getString("script.noRMIClasses")); 1258 1259 /** 1260 * A status that may be used to indicate that no sources were specified in a test description. 1261 */ 1262 protected static final Status 1263 error_noSource = Status.error(i18n.getString("script.noSource")); 1264 1265 /** 1266 * A status that may be used to indicate the a compilation failed unexpectedly. 1267 */ 1268 protected static final Status 1269 fail_compFailUnexp = Status.failed(i18n.getString("script.compFailUnexp")); 1270 1271 /** 1272 * A status that may be used to indicate that a compilation did not fail as was expected. 1273 */ 1274 protected static final Status 1275 fail_compSuccUnexp = Status.failed(i18n.getString("script.compSuccUnexp")); 1276 1277 /** 1278 * A status that may be used to indicate that a test execution step did not fail as wqas expected. 1279 */ 1280 protected static final Status 1281 fail_execSuccUnexp = Status.failed(i18n.getString("script.execSuccUnexp")); 1282 1283 /** 1284 * A status that may be used to indicate that a compilation failed as expected. 1285 */ 1286 protected static final Status 1287 pass_compFailExp = Status.passed(i18n.getString("script.compFailExp")); 1288 1289 /** 1290 * A status that may be used to indicate that a compilation succeeded as expected. 1291 */ 1292 protected static final Status 1293 pass_compSuccExp = Status.passed(i18n.getString("script.compSuccExp")); 1294 1295 /** 1296 * A status that may be used to indicate that an execution step failed, as was expected. 1297 */ 1298 protected static final Status 1299 pass_execFailExp = Status.passed(i18n.getString("script.execFailExp")); 1300 1301 // backwards compatibility 1302 /** 1303 * A status that may be used to indicate that no source files were found in the test description. 1304 */ 1305 protected static final Status noSource = error_noSource; 1306 1307 /** 1308 * A status that may be used to indicate that no extension was found in a source file. 1309 */ 1310 protected static final Status noExtnInSource = error_noExtnInSource; 1311 1312 private static final String[] nullArgs = { }; 1313 private static final String DEFAULT_COMPILE_COMMAND = "compile"; 1314 private static final String DEFAULT_EXECUTE_COMMAND = "execute"; 1315 private static final String DEFAULT_RMIC_COMMAND = "rmic"; 1316 private static final String defaultClassDir = "classes"; 1317 private static String osInfo; 1318 1319 /** 1320 * A timer that may be used to set up timeouts. 1321 */ 1322 protected static final Timer alarmTimer = new Timer(); 1323 1324 private TestResult testResult; 1325 private Alarm alarm; 1326 private boolean jtrIfPassed = 1327 System.getProperty("javatest.script.jtrIfPassed", "true").equals("true"); 1328 1329 /** 1330 * Notifier of starting/finishing tests. 1331 * Initialized only when useNotifer() returns true. 1332 * @see #useNotifier 1333 * @see #setNotifier 1334 * @since 4.2.1 1335 */ 1336 protected Harness.Observer notifier; 1337 1338 /** 1339 * Returns true if the Script uses own way of notifying the Harness 1340 * of starting/finishing test, false otherwise (by default). 1341 * 1342 * Normally the Harness notifies all listeners of an event of 1343 * starting a test when the method run() is invoked and an event of 1344 * finishing the test when the method run() is completed. Those Scripts 1345 * which need to take a control over notifying should override this method 1346 * to return <code>true</code>. In this case the <i>notifier</i> field will 1347 * be initialized and the Harness will no longer notify the listeners when 1348 * a test starts/stops. 1349 * @since 4.2.1 1350 */ 1351 public boolean useNotifier() { 1352 return false; 1353 } 1354 1355 /** 1356 * Sets notifier to be used to inform listeners of events of a test 1357 * starting/finishing. Invoked by the Harness iff useNotifier() 1358 * returns true. 1359 * 1360 * @see #useNotifier 1361 * @since 4.2.1 1362 */ 1363 public void setNotifier(Harness.Observer notifier) { 1364 this.notifier = notifier; 1365 } 1366 1367 /** 1368 * Interface for extended testTimeout control. Use setTimeoutProvider to 1369 * change test timeout value 1370 * @see #setTimeoutProvider(TimeoutProvider) 1371 */ 1372 public static interface TimeoutProvider { 1373 /** 1374 * Implement this method returning desired test timeout value 1375 * 1376 * @return timeout in <b>seconds</b> 1377 */ 1378 public int getTestTimeout(); 1379 } 1380 1381 private class DefaultTimeoutProvider implements TimeoutProvider { 1382 public int getTestTimeout() { 1383 float factor = 1; 1384 try { 1385 String[] jtf = env.lookup("javatestTimeoutFactor"); 1386 if (jtf != null) { 1387 if (jtf.length == 1) 1388 factor = Float.parseFloat(jtf[0]); 1389 else if (jtf.length == 2) 1390 factor = Float.parseFloat(jtf[1]); 1391 } 1392 } 1393 catch (TestEnvironment.Fault e) { 1394 } 1395 return (int) (600 * factor); // 60 * 10 = 600 sec = 10 min 1396 } 1397 } 1398 1399 private class Alarm implements Timer.Timeable { 1400 Alarm(int delay) { 1401 this(delay, Thread.currentThread()); 1402 } 1403 1404 Alarm(int delay, Thread threadToInterrupt) { 1405 if (threadToInterrupt == null) 1406 throw new NullPointerException(); 1407 1408 this.delay = delay; 1409 this.threadToInterrupt = threadToInterrupt; 1410 entry = alarmTimer.requestDelayedCallback(this, delay); 1411 if (debugAlarm) 1412 System.err.println(i18n.getString("script.alarm.started", this)); 1413 } 1414 1415 synchronized void cancel() { 1416 if (debugAlarm) 1417 System.err.println(i18n.getString("script.alarm.cancelled", this)); 1418 alarmTimer.cancel(entry); 1419 } 1420 1421 public synchronized void timeout() { 1422 if (count == 0) 1423 trOut.println(i18n.getString("script.timeout", new Float(delay/1000.f))); 1424 else if (count%100 == 0) { 1425 trOut.println(i18n.getString("script.notResponding", new Integer(count))); 1426 if (count%1000 == 0) 1427 System.err.println(i18n.getString("script.timedOut", 1428 new Object[] { td.getRootRelativeURL(), new Integer(count) })); 1429 } 1430 if (debugAlarm) 1431 System.err.println(i18n.getString("script.alarm.interrupt", new Object[] { this, threadToInterrupt })); 1432 threadToInterrupt.interrupt(); 1433 count++; 1434 entry = alarmTimer.requestDelayedCallback(this, 100); // keep requesting interrupts until cancelled 1435 } 1436 1437 private int delay; 1438 private Thread threadToInterrupt; 1439 private int count; 1440 private Timer.Entry entry; 1441 } 1442 1443 private static boolean debugAlarm = Boolean.getBoolean("debug.com.sun.javatest.Script.Alarm"); 1444 }