1 16 package com.google.gwt.dev; 17 18 import com.google.gwt.core.ext.TreeLogger; 19 import com.google.gwt.core.ext.UnableToCompleteException; 20 import com.google.gwt.core.ext.TreeLogger.Type; 21 import com.google.gwt.core.ext.typeinfo.TypeOracle; 22 import com.google.gwt.dev.cfg.ModuleDef; 23 import com.google.gwt.dev.cfg.ModuleDefLoader; 24 import com.google.gwt.dev.shell.BrowserWidget; 25 import com.google.gwt.dev.shell.BrowserWidgetHost; 26 import com.google.gwt.dev.shell.BrowserWidgetHostChecker; 27 import com.google.gwt.dev.shell.LowLevel; 28 import com.google.gwt.dev.shell.ModuleSpaceHost; 29 import com.google.gwt.dev.shell.PlatformSpecific; 30 import com.google.gwt.dev.shell.ShellMainWindow; 31 import com.google.gwt.dev.shell.ShellModuleSpaceHost; 32 import com.google.gwt.dev.shell.tomcat.EmbeddedTomcatServer; 33 import com.google.gwt.dev.util.arg.ArgHandlerGenDir; 34 import com.google.gwt.dev.util.arg.ArgHandlerLogLevel; 35 import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle; 36 import com.google.gwt.dev.util.log.AbstractTreeLogger; 37 import com.google.gwt.util.tools.ArgHandlerExtra; 38 import com.google.gwt.util.tools.ArgHandlerFlag; 39 import com.google.gwt.util.tools.ArgHandlerOutDir; 40 import com.google.gwt.util.tools.ArgHandlerString; 41 import com.google.gwt.util.tools.ToolBase; 42 43 import org.eclipse.swt.SWT; 44 import org.eclipse.swt.events.DisposeEvent; 45 import org.eclipse.swt.events.DisposeListener; 46 import org.eclipse.swt.graphics.Cursor; 47 import org.eclipse.swt.graphics.Image; 48 import org.eclipse.swt.graphics.Rectangle; 49 import org.eclipse.swt.internal.Library; 50 import org.eclipse.swt.layout.FillLayout; 51 import org.eclipse.swt.widgets.Display; 52 import org.eclipse.swt.widgets.Shell; 53 54 import java.io.File ; 55 import java.util.ArrayList ; 56 import java.util.Iterator ; 57 import java.util.List ; 58 import java.util.Set ; 59 60 63 public class GWTShell extends ToolBase { 64 65 68 protected class ArgHandlerBlacklist extends ArgHandlerString { 69 70 public String [] getDefaultArgs() { 71 return new String [] {"-blacklist", ""}; 72 } 73 74 public String getPurpose() { 75 return "Prevents the user browsing URLs that match the specified regexes (comma or space separated)"; 76 } 77 78 public String getTag() { 79 return "-blacklist"; 80 } 81 82 public String [] getTagArgs() { 83 return new String [] {"blacklist-string"}; 84 } 85 86 public boolean setString(String blacklistStr) { 87 return BrowserWidgetHostChecker.blacklistRegexes(blacklistStr); 88 } 89 } 90 91 94 protected class ArgHandlerNoServerFlag extends ArgHandlerFlag { 95 public String getPurpose() { 96 return "Prevents the embedded Tomcat server from running, even if a port is specified"; 97 } 98 99 public String getTag() { 100 return "-noserver"; 101 } 102 103 public boolean setFlag() { 104 runTomcat = false; 105 return true; 106 } 107 } 108 109 112 protected class ArgHandlerPort extends ArgHandlerString { 113 114 public String [] getDefaultArgs() { 115 return new String [] {"-port", "8888"}; 116 } 117 118 public String getPurpose() { 119 return "Runs an embedded Tomcat instance on the specified port (defaults to 8888)"; 120 } 121 122 public String getTag() { 123 return "-port"; 124 } 125 126 public String [] getTagArgs() { 127 return new String [] {"port-number | \"auto\""}; 128 } 129 130 public boolean setString(String value) { 131 if (value.equals("auto")) { 132 port = 0; 133 } else { 134 try { 135 port = Integer.parseInt(value); 136 } catch (NumberFormatException e) { 137 String msg = "A port must be an integer or \"auto\""; 138 getTopLogger().log(TreeLogger.ERROR, msg, null); 139 return false; 140 } 141 } 142 return true; 143 } 144 } 145 146 149 protected class ArgHandlerStartupURLs extends ArgHandlerExtra { 150 151 public boolean addExtraArg(String arg) { 152 addStartupURL(arg); 153 return true; 154 } 155 156 public String getPurpose() { 157 return "Automatically launches the specified URL"; 158 } 159 160 public String [] getTagArgs() { 161 return new String [] {"url"}; 162 } 163 } 164 165 168 protected class ArgHandlerWhitelist extends ArgHandlerString { 169 170 public String [] getDefaultArgs() { 171 return new String [] {"-whitelist", ""}; 172 } 173 174 public String getPurpose() { 175 return "Allows the user to browse URLs that match the specified regexes (comma or space separated)"; 176 } 177 178 public String getTag() { 179 return "-whitelist"; 180 } 181 182 public String [] getTagArgs() { 183 return new String [] {"whitelist-string"}; 184 } 185 186 public boolean setString(String whitelistStr) { 187 return BrowserWidgetHostChecker.whitelistRegexes(whitelistStr); 188 } 189 } 190 191 private class BrowserWidgetHostImpl implements BrowserWidgetHost { 192 public BrowserWidgetHostImpl() { 193 } 194 195 public void compile(String [] moduleNames) throws UnableToCompleteException { 196 for (int i = 0; i < moduleNames.length; i++) { 197 String moduleName = moduleNames[i]; 198 ModuleDef moduleDef = loadModule(moduleName, getLogger()); 199 GWTShell.this.compile(getLogger(), moduleDef); 200 } 201 } 202 203 public ModuleSpaceHost createModuleSpaceHost(BrowserWidget widget, 204 final String moduleName) throws UnableToCompleteException { 205 TreeLogger logger = getLogger(); 206 207 Shell widgetShell = widget.getShell(); 210 try { 211 Cursor waitCursor = display.getSystemCursor(SWT.CURSOR_WAIT); 212 widgetShell.setCursor(waitCursor); 213 214 ModuleDef moduleDef = loadModule(moduleName, logger); 217 assert (moduleDef != null); 218 219 TypeOracle typeOracle = moduleDef.getTypeOracle(logger); 222 ShellModuleSpaceHost host = doCreateShellModuleSpaceHost(logger, 223 typeOracle, moduleDef, genDir, outDir); 224 return host; 225 } finally { 226 Cursor normalCursor = display.getSystemCursor(SWT.CURSOR_ARROW); 227 widgetShell.setCursor(normalCursor); 228 } 229 } 230 231 public TreeLogger getLogger() { 232 return getTopLogger(); 233 } 234 235 public String normalizeURL(String whatTheUserTyped) { 236 return GWTShell.this.normalizeURL(whatTheUserTyped); 237 } 238 239 public BrowserWidget openNewBrowserWindow() 240 throws UnableToCompleteException { 241 return GWTShell.this.openNewBrowserWindow(); 242 } 243 244 252 private ModuleDef loadModule(final String moduleName, TreeLogger logger) 253 throws UnableToCompleteException { 254 ModuleDef moduleDef = doLoadModule(logger, moduleName); 255 assert (moduleDef != null) : "Required module state is absent"; 256 return moduleDef; 257 } 258 } 259 260 private static Image[] icons; 261 262 static { 263 Display.setAppName("GWT"); 265 } 266 267 public static String checkHost(String hostUnderConsideration, Set hosts) { 268 hostUnderConsideration = hostUnderConsideration.toLowerCase(); 269 for (Iterator i = hosts.iterator(); i.hasNext();) { 270 String rule = i.next().toString().toLowerCase(); 271 if (hostUnderConsideration.matches(".*" + rule + ".*")) { 273 return rule; 274 } 275 } 276 return null; 277 } 278 279 public static String computeHostRegex(String url) { 280 String raw = url.split("(?<![:/])/")[0]; 282 return "^" + raw.replaceAll("[.]", "[.]"); 284 } 285 286 public static String formatRules(Set invalidHttpHosts) { 287 StringBuffer out = new StringBuffer (); 288 for (Iterator i = invalidHttpHosts.iterator(); i.hasNext();) { 289 String rule = (String ) i.next(); 290 out.append(rule); 291 out.append(" "); 292 } 293 return out.toString(); 294 } 295 296 299 public static Image[] getIcons() { 300 if (icons == null) { 303 icons = new Image[] { 304 LowLevel.loadImage("icon16.png"), LowLevel.loadImage("icon24.png"), 305 LowLevel.loadImage("icon32.png"), LowLevel.loadImage("icon48.png"), 306 LowLevel.loadImage("icon128.png")}; 307 } 308 return icons; 309 } 310 311 public static void main(String [] args) { 312 318 BootStrapPlatform.go(); 319 GWTShell shellMain = new GWTShell(); 320 if (shellMain.processArgs(args)) { 321 shellMain.run(); 322 } 323 System.exit(0); 324 } 325 326 330 protected final Display display = Display.getDefault(); 331 332 protected File outDir; 333 334 private BrowserWidgetHostImpl browserHost = new BrowserWidgetHostImpl(); 335 336 private ShellMainWindow mainWnd; 337 338 private boolean runTomcat = true; 339 340 private final List browserShells = new ArrayList (); 341 342 private final List startupUrls = new ArrayList (); 343 344 private File genDir; 345 346 private boolean headlessMode = false; 347 348 private TreeLogger.Type logLevel; 349 350 private boolean obfuscate; 351 352 private int port; 353 354 private boolean prettyNames; 355 356 private boolean started; 357 358 public GWTShell() { 359 this(false, false); 360 } 361 362 protected GWTShell(boolean forceServer, boolean noURLs) { 363 registerHandler(getArgHandlerPort()); 364 365 if (!forceServer) { 366 registerHandler(new ArgHandlerNoServerFlag()); 367 } 368 369 registerHandler(new ArgHandlerWhitelist()); 370 registerHandler(new ArgHandlerBlacklist()); 371 372 registerHandler(new ArgHandlerLogLevel() { 373 public String [] getDefaultArgs() { 374 return new String [] {getTag(), doGetDefaultLogLevel()}; 375 } 376 377 public void setLogLevel(Type level) { 378 logLevel = level; 379 } 380 }); 381 382 registerHandler(new ArgHandlerGenDir() { 383 public void setDir(File dir) { 384 genDir = dir; 385 } 386 }); 387 388 if (!noURLs) { 389 registerHandler(new ArgHandlerStartupURLs()); 390 } 391 392 registerHandler(new ArgHandlerOutDir() { 393 public void setDir(File dir) { 394 outDir = dir; 395 } 396 }); 397 398 registerHandler(new ArgHandlerScriptStyle() { 399 public void setStyleDetailed() { 400 obfuscate = false; 401 prettyNames = false; 402 } 403 404 public void setStyleObfuscated() { 405 obfuscate = true; 406 } 407 408 public void setStylePretty() { 409 obfuscate = false; 410 prettyNames = true; 411 } 412 }); 413 } 414 415 public void addStartupURL(String url) { 416 startupUrls.add(url); 417 } 418 419 public void closeAllBrowserWindows() { 420 while (!browserShells.isEmpty()) { 421 ((Shell) browserShells.get(0)).dispose(); 422 } 423 } 424 425 public File getGenDir() { 426 return genDir; 427 } 428 429 public Type getLogLevel() { 430 return logLevel; 431 } 432 433 public File getOutDir() { 434 return outDir; 435 } 436 437 public int getPort() { 438 return port; 439 } 440 441 public TreeLogger getTopLogger() { 442 return mainWnd.getLogger(); 443 } 444 445 public boolean hasBrowserWindowsOpen() { 446 if (browserShells.isEmpty()) { 447 return false; 448 } else { 449 return true; 450 } 451 } 452 453 456 public void launchStartupUrls(final TreeLogger logger) { 457 if (startupUrls != null) { 458 String startupURL = ""; 461 try { 462 for (Iterator iter = startupUrls.iterator(); iter.hasNext();) { 463 startupURL = normalizeURL((String ) iter.next()); 464 logger.log(TreeLogger.TRACE, "Starting URL: " + startupURL, null); 465 BrowserWidget bw = openNewBrowserWindow(); 466 bw.go(startupURL); 467 } 468 } catch (UnableToCompleteException e) { 469 logger.log(TreeLogger.ERROR, 470 "Unable to open new window for startup URL: " + startupURL, null); 471 } 472 } 473 } 474 475 public String normalizeURL(String unknownUrlText) { 476 if (unknownUrlText.indexOf(":") != -1) { 477 return unknownUrlText; 479 } 480 481 if (unknownUrlText.length() > 0 && unknownUrlText.charAt(0) == '/') { 484 unknownUrlText = unknownUrlText.substring(1); 485 } 486 487 int prt = getPort(); 488 if (prt != 80 && prt != 0) { 489 return "http://localhost:" + prt + "/" + unknownUrlText; 491 } else { 493 return "http://localhost/" + unknownUrlText; 494 } 495 } 496 497 500 public BrowserWidget openNewBrowserWindow() throws UnableToCompleteException { 501 boolean succeeded = false; 502 Shell s = createTrackedBrowserShell(); 503 try { 504 BrowserWidget bw = PlatformSpecific.createBrowserWidget(getTopLogger(), 505 s, browserHost); 506 507 if (mainWnd != null) { 508 Rectangle r = mainWnd.getShell().getBounds(); 509 int n = browserShells.size() + 1; 510 s.setBounds(r.x + n * 50, r.y + n * 50, 800, 600); 511 } else { 512 s.setSize(800, 600); 513 } 514 515 if (!isHeadless()) { 516 s.open(); 517 } 518 519 bw.onFirstShown(); 520 succeeded = true; 521 return bw; 522 } finally { 523 if (!succeeded) { 524 s.dispose(); 525 } 526 } 527 } 528 529 534 public void run() { 535 try { 536 BootStrapPlatform.setSystemProperties(); 538 539 if (!startUp()) { 540 return; 542 } 543 544 BootStrapPlatform.maybeInitializeAWT(); 546 547 launchStartupUrls(getTopLogger()); 549 550 pumpEventLoop(); 551 552 shutDown(); 553 554 } catch (Exception e) { 555 e.printStackTrace(); 556 } 557 } 558 559 public void setGenDir(File genDir) { 560 this.genDir = genDir; 561 } 562 563 public void setLogLevel(Type level) { 564 this.logLevel = level; 565 } 566 567 public void setOutDir(File outDir) { 568 this.outDir = outDir; 569 } 570 571 public void setPort(int port) { 572 this.port = port; 573 } 574 575 public void setRunTomcat(boolean run) { 576 runTomcat = run; 577 } 578 579 584 protected void compile(TreeLogger logger, ModuleDef moduleDef) 585 throws UnableToCompleteException { 586 GWTCompiler compiler = new GWTCompiler(moduleDef.getCacheManager()); 587 compiler.setGenDir(genDir); 588 compiler.setOutDir(outDir); 589 compiler.setModuleName(moduleDef.getName()); 590 compiler.setLogLevel(logLevel); 591 if (obfuscate) { 592 compiler.setStyleObfuscated(); 593 } else if (prettyNames) { 594 compiler.setStylePretty(); 595 } else { 596 compiler.setStyleDetailed(); 597 } 598 compiler.distill(logger, moduleDef); 599 } 600 601 612 protected ShellModuleSpaceHost doCreateShellModuleSpaceHost( 613 TreeLogger logger, TypeOracle typeOracle, ModuleDef moduleDef, 614 File genDir, File outDir) { 615 return new ShellModuleSpaceHost(logger, typeOracle, moduleDef, genDir, 616 outDir); 617 } 618 619 623 protected String doGetDefaultLogLevel() { 624 return "INFO"; 625 } 626 627 632 protected ModuleDef doLoadModule(TreeLogger logger, final String moduleName) 633 throws UnableToCompleteException { 634 return ModuleDefLoader.loadFromClassPath(logger, moduleName); 635 } 636 637 640 protected boolean doShouldCheckForUpdates() { 641 return true; 642 } 643 644 647 protected ArgHandlerPort getArgHandlerPort() { 648 return new ArgHandlerPort(); 649 } 650 651 protected BrowserWidgetHost getBrowserHost() { 652 return browserHost; 653 } 654 655 protected void initializeLogger() { 656 final AbstractTreeLogger logger = mainWnd.getLogger(); 657 logger.setMaxDetail(logLevel); 658 } 659 660 665 protected boolean isHeadless() { 666 return headlessMode; 667 } 668 669 protected boolean notDone() { 670 if (!mainWnd.isDisposed()) { 671 return true; 672 } 673 if (!browserShells.isEmpty()) { 674 return true; 675 } 676 return false; 677 } 678 679 682 protected void pumpEventLoop() { 683 TreeLogger logger = getTopLogger(); 684 685 while (notDone()) { 688 try { 689 if (!display.readAndDispatch()) { 690 display.sleep(); 691 } 692 } catch (Throwable e) { 693 String msg = e.getMessage(); 694 msg = (msg != null ? msg : e.getClass().getName()); 695 logger.log(TreeLogger.ERROR, msg, e); 696 } 697 } 698 } 699 700 protected void setHeadless(boolean headlessMode) { 701 this.headlessMode = headlessMode; 702 } 703 704 707 protected void shutDown() { 708 if (!runTomcat) { 709 return; 710 } 711 712 EmbeddedTomcatServer.stop(); 715 } 716 717 protected boolean startUp() { 718 if (started) { 719 throw new IllegalStateException ("Startup code has already been run"); 720 } 721 722 started = true; 723 724 loadRequiredNativeLibs(); 725 726 openAppWindow(); 730 731 initializeLogger(); 734 735 if (runTomcat) { 736 final int serverPort = getPort(); 741 742 String whyFailed = EmbeddedTomcatServer.start(getTopLogger(), serverPort, 743 outDir); 744 if (whyFailed != null) { 745 System.err.println(whyFailed); 746 return false; 747 } 748 749 port = EmbeddedTomcatServer.getPort(); 751 } 752 753 return true; 754 } 755 756 private Shell createTrackedBrowserShell() { 757 final Shell shell = new Shell(display); 758 FillLayout fillLayout = new FillLayout(); 759 fillLayout.marginWidth = 0; 760 fillLayout.marginHeight = 0; 761 shell.setLayout(fillLayout); 762 browserShells.add(shell); 763 shell.addDisposeListener(new DisposeListener() { 764 public void widgetDisposed(DisposeEvent e) { 765 if (e.widget == shell) { 766 browserShells.remove(shell); 767 } 768 } 769 }); 770 771 shell.setImages(getIcons()); 772 773 return shell; 774 } 775 776 private void loadRequiredNativeLibs() { 777 String libName = null; 778 try { 779 libName = "swt"; 780 Library.loadLibrary(libName); 781 } catch (UnsatisfiedLinkError e) { 782 StringBuffer sb = new StringBuffer (); 783 sb.append("Unable to load required native library '" + libName + "'"); 784 sb.append("\n\tPlease specify the JVM startup argument "); 785 sb.append("\"-Djava.library.path\""); 786 throw new RuntimeException (sb.toString(), e); 787 } 788 } 789 790 private void openAppWindow() { 791 final Shell shell = new Shell(display); 792 793 FillLayout fillLayout = new FillLayout(); 794 fillLayout.marginWidth = 0; 795 fillLayout.marginHeight = 0; 796 shell.setLayout(fillLayout); 797 798 shell.setImages(getIcons()); 799 800 boolean checkForUpdates = doShouldCheckForUpdates(); 801 802 mainWnd = new ShellMainWindow(this, shell, runTomcat ? getPort() : 0, 803 checkForUpdates); 804 805 shell.setSize(700, 600); 806 if (!isHeadless()) { 807 shell.open(); 808 } 809 } 810 } 811 | Popular Tags |