1 /* 2 * $Id$ 3 * 4 * Copyright (c) 1996, 2016, 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.tool; 28 29 import java.awt.EventQueue; 30 import java.io.File; 31 import java.io.IOException; 32 import java.io.PrintWriter; 33 import java.text.MessageFormat; 34 import java.util.Map; 35 import java.util.Set; 36 37 import com.sun.javatest.Harness; 38 import com.sun.javatest.InterviewParameters; 39 import com.sun.javatest.JavaTestError; 40 import com.sun.javatest.JavaTestSecurityManager; 41 import com.sun.javatest.ProductInfo; 42 import com.sun.javatest.Status; 43 import com.sun.javatest.services.ServiceManager; 44 import com.sun.javatest.util.Debug; 45 import com.sun.javatest.util.ExitCount; 46 import com.sun.javatest.util.I18NResourceBundle; 47 48 /** 49 * The main program class for JT Harness. 50 */ 51 public class Main 52 { 53 54 /** 55 * Thrown when a bad command line argument is encountered. 56 */ 57 public static class Fault extends Exception 58 { 59 /** 60 * Create a BadArgs exception. 61 * @param i18n A resource bundle in which to find the detail message. 62 * @param key The key for the detail message. 63 */ 64 public Fault(I18NResourceBundle i18n, String key) { 65 super(i18n.getString(key)); 66 } 67 68 /** 69 * Create a BadArgs exception. 70 * @param i18n A resource bundle in which to find the detail message. 71 * @param key The key for the detail message. 72 * @param arg An argument to be formatted with the detail message by 73 * {@link java.text.MessageFormat#format} 74 */ 75 public Fault(I18NResourceBundle i18n, String key, Object arg) { 76 super(i18n.getString(key, arg)); 77 } 78 79 /** 80 * Create a BadArgs exception. 81 * @param i18n A resource bundle in which to find the detail message. 82 * @param key The key for the detail message. 83 * @param args An array of arguments to be formatted with the detail message by 84 * {@link java.text.MessageFormat#format} 85 */ 86 public Fault(I18NResourceBundle i18n, String key, Object[] args) { 87 super(i18n.getString(key, args)); 88 } 89 } 90 91 92 /** 93 * Run JT Harness with command-line args. 94 * @param args Arguments, per the command-line spec 95 */ 96 public static void main(String[] args) { 97 tracing = Boolean.getBoolean("javatest.trace.startup"); 98 99 if (tracing) 100 traceStartTime = System.currentTimeMillis(); 101 102 if (Boolean.getBoolean("javatest.trace.printargs")) { 103 StringBuilder fullCmd = new StringBuilder(); 104 StringBuilder incrementalCmd = new StringBuilder(); 105 106 for (String a : args) { 107 fullCmd.append(a); 108 fullCmd.append(" "); 109 110 incrementalCmd.append("// "); 111 incrementalCmd.append(a); 112 incrementalCmd.append("\n"); 113 } // for 114 115 System.out.println(fullCmd.toString().trim()); 116 System.out.println(incrementalCmd.toString()); 117 } 118 119 String javaVersion = System.getProperty("java.version"); 120 if (javaVersion != null) { 121 String[] oldVersions = {"1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6"}; 122 for (int i = 0; i < oldVersions.length; i++) { 123 if (javaVersion.startsWith(oldVersions[i])) { 124 // I18N? 125 System.err.println("Please use Java(TM) Standard Edition, Version 7.0 or better to run the JT Harness(TM) harness."); 126 System.exit(1); 127 } 128 } 129 } 130 131 main0(args); 132 } 133 134 private static void main0(String[] args) { 135 Debug.setProperties(System.getProperties()); 136 137 PrintWriter out = new PrintWriter(System.err) { 138 public void close() { 139 flush(); 140 } 141 }; 142 143 if (tracing) 144 traceOut = out; 145 146 try { 147 ExitCount.inc(); 148 Main m = new Main(); 149 150 CommandContext ctx = new CommandContext(out); 151 m.run(args, ctx); 152 153 if (tracing) 154 trace("Main.run complete"); 155 156 out.flush(); // flush now in case ExitCount exits 157 158 int[] stats = ctx.getTestStats(); 159 int rc = (stats[Status.ERROR] > 0 ? RC_BATCH_TESTS_ERROR 160 : stats[Status.FAILED] > 0 ? RC_BATCH_TESTS_FAILED 161 : RC_OK); 162 163 ExitCount.dec(true, rc); 164 165 // all initialization is done; this thread has nothing left to do, so... 166 boolean preload = 167 System.getProperty("javatest.preload.classes", "true").equals("true"); 168 169 if (preload) { 170 if (tracing) 171 trace("preloading classes..."); 172 173 preloadUsefulClasses(); 174 175 if (tracing) 176 trace("preloaded classes"); 177 } 178 179 out.flush(); 180 } 181 catch (Command.Fault e) { 182 // occurs when executing default commands at end of command line 183 out.println(CommandContext.TRACE_PREFIX + e.getCommand().toString()); 184 out.println(e.getMessage()); 185 out.flush(); 186 exit(RC_USER_ERROR); 187 } 188 catch (CommandContext.Fault e) { 189 // occurs when executing commands on command line or in command file 190 Throwable t = e.getCause(); 191 if (t instanceof Command.Fault) { 192 CommandContext ctx = e.getContext(); 193 boolean verboseCommands = 194 ctx.getVerboseOptionValue(CommandContext.VERBOSE_COMMANDS); 195 if (!verboseCommands) { 196 Command.Fault ce = (Command.Fault) t; 197 Command c = ce.getCommand(); 198 out.println(CommandContext.TRACE_PREFIX + c.toString()); 199 } 200 } 201 out.println(e.getMessage()); 202 out.flush(); 203 exit(RC_USER_ERROR); 204 } 205 catch (CommandParser.Fault e) { 206 // occurs when parsing commands on command line or in command file 207 Throwable t = e.getCause(); 208 if (t instanceof Command.Fault) { 209 Command.Fault ce = (Command.Fault) t; 210 Command c = ce.getCommand(); 211 out.println(CommandParser.TRACE_PREFIX + c.toString()); 212 } 213 out.println(e.getMessage()); 214 out.flush(); 215 exit(RC_USER_ERROR); 216 } 217 catch (Fault e) { 218 out.println(e.getMessage()); 219 out.flush(); 220 exit(RC_INTERNAL_ERROR); 221 } 222 catch (Error e) { 223 e.printStackTrace(out); 224 out.flush(); 225 exit(RC_INTERNAL_ERROR); 226 } 227 catch (RuntimeException e) { 228 e.printStackTrace(out); 229 out.flush(); 230 exit(RC_INTERNAL_ERROR); 231 } 232 } 233 234 /** 235 * The main routine to run JT Harness. 236 * @param args Arguments for JT Harness, per the command-line spec. 237 * @param out A stream to which to write standard messages, such as 238 * command-line help, version info etc. Some error messages will 239 * still be sent to System.err. 240 * @throws Main.Fault if there is a problem initializing the harness 241 * @throws Command.Fault if there is a problem with a command's arguments 242 * @throws CommandContext.Fault if there is a problem executing a command 243 * @throws CommandParser.Fault if there is a problem parsing the args 244 */ 245 public final void run(String[] args, PrintWriter out) 246 throws Fault, Command.Fault, CommandContext.Fault, CommandParser.Fault 247 { 248 run(args, new CommandContext(out)); 249 } 250 251 /** 252 * A routine to run JT Harness. 253 * @param args Arguments for JT Harness, per the command-line spec. 254 * @param ctx A context to use to execute the commands in the args 255 * @throws Main.Fault if there is a problem initializing the harness 256 * @throws Command.Fault if there is a problem with a command's arguments 257 * @throws CommandContext.Fault if there is a problem executing a command 258 * @throws CommandParser.Fault if there is a problem parsing the args 259 */ 260 public final void run(String[] args, final CommandContext ctx) 261 throws Fault, Command.Fault, CommandContext.Fault, CommandParser.Fault 262 { 263 if (commandManagers == null) { 264 desktopManager = new DesktopManager(); 265 helpManager = new HelpManager(); 266 serviceManager = new ServiceManager.ServiceCommandManager(); 267 try { 268 ManagerLoader ml = new ManagerLoader(CommandManager.class, System.err); 269 Set<Object> mgrs = ml.loadManagers(CMDMGRLIST); 270 mgrs.add(desktopManager); 271 mgrs.add(helpManager); 272 mgrs.add(serviceManager); 273 commandManagers = mgrs.toArray(new CommandManager[mgrs.size()]); 274 helpManager.setCommandManagers(commandManagers); 275 } 276 catch (IOException e) { 277 throw new Fault(i18n, "main.cantAccessResource", new Object[] { CMDMGRLIST, e }); 278 } 279 } 280 281 CommandParser p = new CommandParser(commandManagers); 282 boolean urlEncoded = Boolean.getBoolean("javatest.command.urlEncoded"); 283 p.parse(args, urlEncoded, ctx); 284 285 if (!initialized) { 286 File classDir = ProductInfo.getJavaTestClassDir(); 287 Harness.setClassDir(classDir); 288 289 // Install our own security manager. This is primarily for self-defense 290 // against sameJVM tests, and not to prevent access outside the sandbox. 291 // Moan to stderr if it can't be installed. 292 JavaTestSecurityManager.install(); 293 294 // mark initialization done 295 initialized = true; 296 } 297 298 final Command[] cmds = ctx.getCommands(); 299 300 // special case, when user requested info 301 boolean helpInfoRequired = helpManager.isInfoRequired(); 302 if (helpInfoRequired) { 303 helpManager.showRequiredInfo(ctx.getLogWriter(), ctx); 304 if (cmds.length == 0) 305 return; 306 } 307 308 final Desktop desktop; 309 boolean needDesktop = ctx.isDesktopRequired(); 310 311 if (needDesktop) { 312 if (tracing) 313 trace("creating desktop..."); 314 315 // should really be on event thread 316 desktop = desktopManager.createDesktop(ctx); 317 318 /* 319 // show splash screen, using event thread 320 Runnable task = new Runnable() { 321 public void run() { 322 if (tracing) 323 trace("creating splash screen..."); 324 Startup su = null; 325 // lots of GUI construction caused by the few lines below 326 for (int i = 0; i < cmds.length; i++) { 327 URL ss = cmds[i].getCustomSplash(); 328 if (ss != null) { 329 su = new Startup(ss); 330 break; 331 } 332 } // for 333 334 if (su == null) 335 su = new Startup(); 336 337 final Startup splashScreen = su; 338 339 Thread splashTimer = new Thread() { 340 public void run() { 341 // pause for 15 seconds before displaying desktop and 342 // hiding splash screen; if the desktop is made ready sooner, 343 // it will be displayed sooner 344 int splashSecs = 345 Integer.getInteger("javatest.splashScreen.time", 15).intValue(); 346 try { 347 Thread.currentThread().sleep(splashSecs*1000); 348 } 349 catch (InterruptedException e) { 350 } 351 if (tracing) 352 trace("splash timer done: showing desktop..."); 353 354 Runnable task2 = new Runnable() { 355 public void run() { 356 desktop.setVisible(true); 357 splashScreen.disposeLater(); 358 } 359 }; 360 361 try { 362 EventQueue.invokeAndWait(task2); 363 } catch (InterruptedException e) { 364 if (tracing) 365 e.printStackTrace(); 366 } catch (java.lang.reflect.InvocationTargetException e) { 367 if (tracing) 368 e.printStackTrace(); 369 } 370 371 } 372 }; 373 splashTimer.setDaemon(true); 374 splashTimer.start(); 375 } // run() 376 }; // runnable 377 378 try { 379 EventQueue.invokeAndWait(task); 380 } catch (InterruptedException e) { 381 if (tracing) 382 e.printStackTrace(); 383 } catch (java.lang.reflect.InvocationTargetException e) { 384 if (tracing) 385 e.printStackTrace(); 386 } 387 */ 388 389 desktop.setVisible(true); 390 ctx.setDesktop(desktop); 391 // set context log to display in a log tool 392 } 393 else 394 desktop = null; 395 396 // execute the commands on the command line 397 if (tracing) 398 trace("executing command line..."); 399 400 if (desktop != null) { 401 desktop.setVisible(true); 402 } 403 404 ctx.runCommands(); 405 406 if (tracing) 407 trace("command line done"); 408 409 if (desktop != null) { 410 if (ctx.isCloseDesktopWhenDoneEnabled() 411 && desktop.isOKToAutoExit()) { 412 Runnable task = new Runnable() { 413 public void run() { 414 desktop.setVisible(false); 415 desktop.dispose(); 416 } 417 }; 418 try { 419 EventQueue.invokeAndWait(task); 420 } catch (InterruptedException e) { 421 if (tracing) 422 e.printStackTrace(); 423 } catch (java.lang.reflect.InvocationTargetException e) { 424 if (tracing) 425 e.printStackTrace(); 426 } 427 } 428 else { 429 InterviewParameters ip_tmp = null; 430 if (desktop.isEmpty() && ctx.hasConfig()) { 431 try { 432 ip_tmp = ctx.getConfig(); 433 } catch (CommandContext.Fault e) { 434 System.err.println(i18n.getString("main.cantGetConfig", e.getMessage())); 435 } 436 } 437 final InterviewParameters ip = ip_tmp; 438 439 Runnable task = new Runnable() { 440 public void run() { 441 // if a desktop has been started, make sure it is not empty 442 if (desktop.isEmpty()) { 443 if (ctx.hasConfig() && ip != null) { 444 if (tracing) { 445 trace("show specified test suite"); 446 } 447 desktop.restoreHistory(); 448 Tool tool = desktop.addDefaultTool(ip); 449 Map<String, String> data = ctx.getDesktopData(); 450 if (data != null) { 451 tool.restore(data); 452 } 453 } 454 else if (desktop.isFirstTime()) { 455 if (tracing) 456 trace("show default"); 457 desktop.addDefaultTool(); 458 } 459 else { 460 if (tracing) 461 trace("restore desktop"); 462 desktop.restore(); 463 } 464 } 465 if (tracing) 466 trace("set desktop visible"); 467 desktop.setVisible(true); 468 } // run() 469 }; // Runnable 470 471 try { 472 EventQueue.invokeAndWait(task); 473 } catch (InterruptedException e) { 474 if (tracing) 475 e.printStackTrace(); 476 } catch (java.lang.reflect.InvocationTargetException e) { 477 if (tracing) 478 e.printStackTrace(); 479 } 480 481 } 482 } 483 ctx.dispose(); 484 } 485 486 private CommandManager[] commandManagers; 487 private HelpManager helpManager; 488 private DesktopManager desktopManager; 489 private ServiceManager.ServiceCommandManager serviceManager; 490 491 private static void preloadUsefulClasses() { 492 //System.err.println("\n\n\n>>>>> preloading classes\n\n\n"); 493 new javax.swing.text.html.HTMLEditorKit().createDefaultDocument(); 494 com.sun.interview.Interview i = new com.sun.interview.Interview("dummy") { 495 com.sun.interview.Question qEnd = new com.sun.interview.FinalQuestion(this); 496 { setFirstQuestion(qEnd); } 497 }; 498 new com.sun.interview.wizard.WizPane(i); 499 //System.err.println("\n\n\n>>>>> preloading classes done\n\n\n"); 500 } 501 502 private static void trace(String msg) { 503 long now = System.currentTimeMillis(); 504 traceOut.println(MessageFormat.format("{0,number,[##0.0]} {1}", 505 new Float((now - traceStartTime)/1000f), msg)); 506 traceOut.flush(); 507 } 508 509 510 /** 511 * Call System.exit, taking care to get permission from the 512 * JavaTestSecurityManager, if it is installed. 513 * @param exitCode an exit code to be passed to System.exit 514 */ 515 private static final void exit(int exitCode) { 516 // If our security manager is installed, it won't allow a call of 517 // System.exit unless we ask it nicely, pretty please, thank you. 518 SecurityManager sc = System.getSecurityManager(); 519 if (sc instanceof JavaTestSecurityManager) 520 ((JavaTestSecurityManager) sc).setAllowExit(true); 521 System.exit(exitCode); 522 throw new JavaTestError(i18n, "main.cannotExit.err"); 523 } 524 525 private static boolean tracing; 526 private static long traceStartTime; 527 private static PrintWriter traceOut; 528 private static boolean initialized = false; 529 private static final String CMDMGRLIST = "META-INF/services/com.sun.javatest.tool.CommandManager.lst"; 530 531 private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(Main.class); 532 533 private static final int RC_GUI_ACTIVE = -1; 534 private static final int RC_OK = 0; 535 private static final int RC_BATCH_TESTS_FAILED = 1; 536 private static final int RC_BATCH_TESTS_ERROR = 2; 537 private static final int RC_USER_ERROR = 3; 538 private static final int RC_INTERNAL_ERROR = 4; 539 }