Revision: 6283 Author: j...@google.com Date: Thu Oct 1 17:01:51 2009 Log: Checkpoint work on abstracting out develmode UI.
http://code.google.com/p/google-web-toolkit/source/detail?r=6283 Added: /changes/jat/abstractui/dev/core/src/com/google/gwt/dev/SwingUI.java Deleted: /changes/jat/abstractui/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java Modified: /changes/jat/abstractui/dev/core/src/com/google/gwt/dev/HostedModeBase.java /changes/jat/abstractui/dev/oophm/overlay/com/google/gwt/dev/GWTShell.java /changes/jat/abstractui/dev/oophm/overlay/com/google/gwt/dev/HostedMode.java /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/OophmHostedModeBase.java /changes/jat/abstractui/user/src/com/google/gwt/junit/JUnitShell.java ======================================= --- /dev/null +++ /changes/jat/abstractui/dev/core/src/com/google/gwt/dev/SwingUI.java Thu Oct 1 17:01:51 2009 @@ -0,0 +1,243 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.TreeLogger.Type; +import com.google.gwt.dev.HostedModeBase.DevelopmentModeUI; +import com.google.gwt.dev.OophmHostedModeBase.TabPanelCollection; +import com.google.gwt.dev.WebServerPanel.RestartAction; +import com.google.gwt.dev.shell.ShellMainWindow; +import com.google.gwt.dev.util.collect.HashMap; + +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.net.URL; +import java.util.IdentityHashMap; +import java.util.Map; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JTabbedPane; +import javax.swing.WindowConstants; + +/** + * Implements the Swing UI for development mode. + */ +public class SwingUI extends DevelopmentModeUI { + + private final Map<ModuleHandle, ModulePanel> moduleTabs = new IdentityHashMap<ModuleHandle, ModulePanel>(); + private final Map<DevelModeTabKey, ModuleTabPanel> tabPanels = new HashMap<DevelModeTabKey, ModuleTabPanel>(); + + public class SwingModuleHandle implements ModuleHandle { + + public TreeLogger getLogger() { + // TODO(jat) Auto-generated method stub + return null; + } + + } + + private final HostedModeBase hostedModeBase; + private JFrame frame; + private JTabbedPane tabs; + private ShellMainWindow mainWnd; + private WebServerPanel webServerLog; + + public SwingUI(HostedModeBase hostedModeBase) { + this.hostedModeBase = hostedModeBase; + } + + @Override + public void initialize() { + if (hostedModeBase.isHeadless()) { + return; + } + ImageIcon gwtIcon = loadImageIcon("icon24.png"); + frame = new JFrame("GWT Development Mode"); + tabs = new JTabbedPane(); + if (hostedModeBase.options.alsoLogToFile()) { + hostedModeBase.options.getLogDir().mkdirs(); + } + mainWnd = new ShellMainWindow(hostedModeBase.options.getLogLevel(), + hostedModeBase.options.getLogFile("main.log")); + tabs.addTab("Development Mode", gwtIcon, mainWnd, "GWT Development mode"); + frame.getContentPane().add(tabs); + frame.setSize(950, 700); + frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + callback(DONE, null); + } + }); + frame.setIconImage(loadImageIcon("icon16.png").getImage()); + frame.setVisible(true); + } + + protected static final String PACKAGE_PATH = SwingUI.class.getPackage( + ).getName().replace('.', '/').concat("/shell/"); + + /** + * Loads an image from the classpath in this package. + */ + static ImageIcon loadImageIcon(String name) { + return loadImageIcon(name, true); + } + + /** + * Loads an image from the classpath, optionally prepending this package. + * + * @param name name of an image file. + * @param prependPackage true if {...@link #PACKAGE_PATH} should be prepended to + * this name. + */ + static ImageIcon loadImageIcon(String name, boolean prependPackage) { + ClassLoader cl = OophmHostedModeBase.class.getClassLoader(); + if (prependPackage) { + name = PACKAGE_PATH + name; + } + + URL url = (name == null) ? null : cl.getResource(name); + if (url != null) { + ImageIcon image = new ImageIcon(url); + return image; + } else { + // Bad image. + return new ImageIcon(); + } + } + + @Override + public TreeLogger getTopLogger(Type logLevel) { + return mainWnd == null ? null : mainWnd.getLogger(); + } + + @Override + public TreeLogger getWebServerLogger(String serverName, String iconName) { + if (webServerLog == null) { + webServerLog = new WebServerPanel(hostedModeBase.getPort(), + hostedModeBase.options.getLogLevel(), + hostedModeBase.options.getLogFile("webserver.log"), + new RestartAction() { + public void restartServer(TreeLogger logger) { + callback(RESTART_SERVER, logger); + } + }); + Icon serverIcon = null; + tabs.insertTab(serverName, serverIcon, webServerLog, null, 1); + } + return webServerLog.getLogger(); + } + + @Override + public ModuleHandle loadModule(String userAgent, String remoteSocket, + String url, String tabKey, String moduleName, String sessionKey, + String agentTag, TreeLogger.Type logLevel) { + ModuleTabPanel tabPanel = null; + ModulePanel tab = null; + if (!hostedModeBase.isHeadless()) { + tabPanel = findModuleTab(userAgent, remoteSocket, url, tabKey, + moduleName); + tab = tabPanel.addModuleSession(logLevel, moduleName, sessionKey, + hostedModeBase.options.getLogFile(String.format("%s-%s-%d.log", moduleName, + agentTag, getNextSessionCounter( + hostedModeBase.options.getLogDir())))); + TreeLogger logger = tab.getLogger(); + TreeLogger branch = logger.branch(TreeLogger.INFO, "Loading module " + + moduleName); + if (url != null) { + branch.log(TreeLogger.INFO, "Top URL: " + url); + } + branch.log(TreeLogger.INFO, "User agent: " + userAgent); + branch.log(TreeLogger.TRACE, "Remote socket: " + remoteSocket); + if (tabKey != null) { + branch.log(TreeLogger.DEBUG, "Tab key: " + tabKey); + } + if (sessionKey != null) { + branch.log(TreeLogger.DEBUG, "Session key: " + sessionKey); + } + + // TODO: Switch to a wait cursor? + + SwingModuleHandle module = new SwingModuleHandle(); + moduleTabs.put(module, tab); + } + return null; + } + + private static int sessionCounter = 0; + + protected int getNextSessionCounter(File logdir) { + if (sessionCounter == 0 && logdir != null) { + // first time only, figure out the "last" session count already in use + for (String filename : logdir.list()) { + if (filename.matches("^[A-Za-z0-9_$]*-[a-z]*-[0-9]*.log$")) { + String substring = filename.substring(filename.lastIndexOf('-') + 1, + filename.length() - 4); + int number = Integer.parseInt(substring); + if (number > sessionCounter) { + sessionCounter = number; + } + } + } + } + return ++sessionCounter; + } + + @Override + public void unloadModule(ModuleHandle module) { + SwingModuleHandle handle = (SwingModuleHandle) module; + Disconnectable tab = moduleTabs.remove(handle); + if (tab != null) { + tab.disconnect(); + } + } + + private ModuleTabPanel findModuleTab(String userAgent, String remoteSocket, + String url, String tabKey, String moduleName) { + int hostEnd = remoteSocket.indexOf(':'); + if (hostEnd < 0) { + hostEnd = remoteSocket.length(); + } + String remoteHost = remoteSocket.substring(0, hostEnd); + final DevelModeTabKey key = new DevelModeTabKey(userAgent, url, tabKey, + remoteHost); + ModuleTabPanel moduleTabPanel = tabPanels.get(key); + if (moduleTabPanel == null) { + moduleTabPanel = new ModuleTabPanel(userAgent, remoteSocket, url, + new TabPanelCollection() { + public void addTab(ModuleTabPanel tabPanel, ImageIcon icon, + String title, String tooltip) { + synchronized (tabs) { + tabs.addTab(title, icon, tabPanel, tooltip); + tabPanels.put(key, tabPanel); + } + } + + public void removeTab(ModuleTabPanel tabPanel) { + synchronized (tabs) { + tabs.remove(tabPanel); + tabPanels.remove(key); + } + } + }, moduleName); + } + return moduleTabPanel; + } +} ======================================= --- /changes/jat/abstractui/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java Sun Sep 20 12:33:31 2009 +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.dev.shell; - -import com.google.gwt.core.ext.TreeLogger; -import com.google.gwt.core.ext.UnableToCompleteException; - -/** - * Interface to the browser window controller. - */ -public interface BrowserWindowController { - /** - * Whether to display server control(s). - */ - enum WebServerRestart { - DISABLED, ENABLED, NONE - } - - void closeAllBrowserWindows(); - - boolean hasBrowserWindowsOpen(); - - WebServerRestart hasWebServer(); - - String normalizeURL(String string); - - void restartServer(TreeLogger logger) throws UnableToCompleteException; -} ======================================= --- /changes/jat/abstractui/dev/core/src/com/google/gwt/dev/HostedModeBase.java Sun Sep 20 13:03:25 2009 +++ /changes/jat/abstractui/dev/core/src/com/google/gwt/dev/HostedModeBase.java Thu Oct 1 17:01:51 2009 @@ -17,17 +17,22 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.TreeLogger.Type; import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.dev.HostedModeBase.DevelopmentModeUI.ModuleHandle; import com.google.gwt.dev.Precompile.PrecompileOptionsImpl; import com.google.gwt.dev.cfg.ModuleDef; import com.google.gwt.dev.cfg.ModuleDefLoader; import com.google.gwt.dev.jjs.JJSOptions; import com.google.gwt.dev.shell.ArtifactAcceptor; +import com.google.gwt.dev.shell.BrowserListener; import com.google.gwt.dev.shell.BrowserWidgetHost; import com.google.gwt.dev.shell.BrowserWidgetHostChecker; -import com.google.gwt.dev.shell.BrowserWindowController; import com.google.gwt.dev.shell.CheckForUpdates; +import com.google.gwt.dev.shell.ModuleSpaceHost; +import com.google.gwt.dev.shell.OophmSessionHandler; import com.google.gwt.dev.shell.ShellModuleSpaceHost; +import com.google.gwt.dev.util.BrowserInfo; import com.google.gwt.dev.util.Util; import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization; import com.google.gwt.dev.util.arg.ArgHandlerDisableCastChecking; @@ -39,15 +44,22 @@ import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle; import com.google.gwt.dev.util.arg.OptionGenDir; import com.google.gwt.dev.util.arg.OptionLogLevel; +import com.google.gwt.dev.util.log.PrintWriterTreeLogger; import com.google.gwt.util.tools.ArgHandlerFlag; import com.google.gwt.util.tools.ArgHandlerString; import java.io.File; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.List; +import java.util.Map; +import java.util.Random; import java.util.Set; +import java.util.concurrent.Semaphore; /** * The main executable class for the hosted mode shell. This class must not have @@ -56,7 +68,123 @@ * TODO: remove BrowserWidget references (which reference SWT via inheritance, * though it doesn't appear to cause any harm currently. */ -abstract class HostedModeBase implements BrowserWindowController { +abstract class HostedModeBase { + + private final Map<ModuleSpaceHost, ModuleHandle> loadedModules = new IdentityHashMap<ModuleSpaceHost, ModuleHandle>(); + + public class UiBrowserWidgetHostImpl extends BrowserWidgetHostImpl { + + private ModuleHandle module; + + public ModuleSpaceHost createModuleSpaceHost(TreeLogger mainLogger, + String moduleName, String userAgent, String url, String tabKey, + String sessionKey, String remoteSocket) + throws UnableToCompleteException { + if (sessionKey == null) { + // if we don't have a unique session key, make one up + sessionKey = randomString(); + } + TreeLogger logger = mainLogger; + TreeLogger.Type maxLevel = options.getLogLevel(); + String agentTag = BrowserInfo.getShortName(userAgent).toLowerCase(); + module = ui.loadModule(userAgent, remoteSocket, url, tabKey, moduleName, + sessionKey, agentTag, maxLevel); + logger = module.getLogger(); + try { + // Try to find an existing loaded version of the module def. + ModuleDef moduleDef = loadModule(logger, moduleName, true); + assert (moduleDef != null); + + // Create a sandbox for the module. + // TODO(jat): consider multiple instances of the same module open at + // once + TypeOracle typeOracle = moduleDef.getTypeOracle(logger); + ShellModuleSpaceHost host = doCreateShellModuleSpaceHost(logger, + typeOracle, moduleDef); + + loadedModules.put(host, module); + return host; + } catch (RuntimeException e) { + logger.log(TreeLogger.ERROR, "Exception initializing module", e); + ui.unloadModule(module); + throw e; + } + } + + public void unloadModule(ModuleSpaceHost moduleSpaceHost) { + ModuleHandle module = loadedModules.remove(moduleSpaceHost); + if (module != null) { + ui.unloadModule(module); + } + } + + } + + private static final Random RNG = new Random(); + + /** + * Produce a random string that has low probability of collisions. + * + * <p>In this case, we use 16 characters, each drawn from a pool of 94, + * so the number of possible values is 94^16, leading to an expected number + * of values used before a collision occurs as sqrt(pi/2) * 94^8 (treated the + * same as a birthday attack), or a little under 10^16. + * + * <p>This algorithm is also implemented in hosted.html, though it is not + * technically important that they match. + * + * @return a random string + */ + protected static String randomString() { + StringBuilder buf = new StringBuilder(16); + for (int i = 0; i < 16; ++i) { + buf.append((char) RNG.nextInt('~' - '!' + 1) + '!'); + } + return buf.toString(); + } + + public abstract static class DevelopmentModeUI { + + public static final String DONE = "done"; + public static final String RESTART_SERVER = "restart-server"; + + public interface ModuleHandle { + + TreeLogger getLogger(); + } + + public interface Callback { + // TODO: typesafe callbacks + public void callback(String event, Object callbackData); + } + + private final Map<String, Callback> callbacks = new HashMap<String, Callback>(); + + public abstract void initialize(); + + public void setCallback(String event, Callback callback) { + callbacks.put(event, callback); + } + + protected void callback(String event, Object callbackData) { + Callback callback = callbacks.get(event); + if (callback != null) { + callback(event, callbackData); + } + } + + public abstract TreeLogger getTopLogger(TreeLogger.Type logLevel); + + // TODO: How to pass icon? + public abstract TreeLogger getWebServerLogger(String serverName, + String iconName); + + public abstract ModuleHandle loadModule(String userAgent, + String remoteSocket, String url, String tabKey, String moduleName, + String sessionKey, String agentTag, Type logLevel); + + public abstract void unloadModule(ModuleHandle module); + } /** * Handles the -blacklist command line argument. @@ -251,10 +379,64 @@ return HostedModeBase.this.normalizeURL(whatTheUserTyped); } } + + + /** + * Handles the -portHosted command line flag. + */ + protected static class ArgHandlerPortHosted extends ArgHandlerString { + + private final OptionPortHosted options; + + public ArgHandlerPortHosted(OptionPortHosted options) { + this.options = options; + } + + @Override + public String[] getDefaultArgs() { + return new String[] {"-portHosted", "9997"}; + } + + @Override + public String getPurpose() { + return "Listens on the specified port for hosted mode connections"; + } + + @Override + public String getTag() { + return "-portHosted"; + } + + @Override + public String[] getTagArgs() { + return new String[] {"port-number | \"auto\""}; + } + + @Override + public boolean setString(String value) { + if (value.equals("auto")) { + options.setPortHosted(0); + } else { + try { + options.setPortHosted(Integer.parseInt(value)); + } catch (NumberFormatException e) { + System.err.println("A port must be an integer or \"auto\""); + return false; + } + } + return true; + } + } + + protected interface OptionPortHosted { + int getPortHosted(); + + void setPortHosted(int portHosted); + } protected interface HostedModeBaseOptions extends JJSOptions, OptionLogDir, OptionLogLevel, OptionGenDir, OptionNoServer, OptionPort, - OptionStartupURLs { + OptionPortHosted, OptionStartupURLs { /** * The base shell work directory. @@ -272,7 +454,15 @@ private File logDir; private int port; private final List<String> startupURLs = new ArrayList<String>(); - + private int portHosted; + + public int getPortHosted() { + return portHosted; + } + + public void setPortHosted(int port) { + portHosted = port; + } public void addStartupURL(String url) { startupURLs.add(url); } @@ -380,6 +570,7 @@ registerHandler(new ArgHandlerDisableClassMetadata(options)); registerHandler(new ArgHandlerDisableCastChecking(options)); registerHandler(new ArgHandlerDraftCompile(options)); + registerHandler(new ArgHandlerPortHosted(options)); } } @@ -416,8 +607,12 @@ private boolean headlessMode = false; + private TreeLogger topLogger; + private boolean started; + protected DevelopmentModeUI ui; + public HostedModeBase() { // Set any platform specific system properties. BootStrapPlatform.initHostedMode(); @@ -428,16 +623,14 @@ public final void addStartupURL(String url) { options.addStartupURL(url); } - - public abstract void closeAllBrowserWindows(); public final int getPort() { return options.getPort(); } - public abstract TreeLogger getTopLogger(); - - public abstract boolean hasBrowserWindowsOpen(); + public TreeLogger getTopLogger() { + return topLogger; + } /** * Launch the arguments as Urls in separate windows. @@ -448,28 +641,53 @@ return normalizeURL(unknownUrlText, getPort(), getHost()); } + private final Semaphore blockUntilDone = new Semaphore(0); + /** * Sets up all the major aspects of running the shell graphically, including * creating the main window and optionally starting the embedded Tomcat * server. */ public final void run() { + if (ui == null) { + ui = new SwingUI(this); + } try { if (startUp()) { // Eager AWT init for OS X to ensure safe coexistence with SWT. BootStrapPlatform.initGui(); - // Tomcat's running now, so launch browsers for startup urls now. + // The web server is running now, so launch browsers for startup urls. launchStartupUrls(getTopLogger()); } - pumpEventLoop(); + blockUntilDone.acquire(); } catch (Exception e) { e.printStackTrace(); } finally { shutDown(); } } + + protected final void setDone() { + blockUntilDone.release(); + } + + protected abstract void restartServer(); + + public class Callback implements DevelopmentModeUI.Callback { + + public void callback(String event, Object callbackData) { + if (DevelopmentModeUI.DONE.equals(event)) { + setDone(); + return; + } else if (DevelopmentModeUI.RESTART_SERVER.equals(event)) { + restartServer(); + return; + } + // TODO: unexpected event? + } + } public final void setPort(int port) { options.setPort(port); @@ -528,10 +746,9 @@ protected boolean doStartup() { // Create the main app window. - openAppWindow(); + ui.initialize(); // Initialize the logger. - // initializeLogger(); // Check for updates @@ -549,8 +766,33 @@ checkerThread.setDaemon(true); checkerThread.start(); } + + // Accept connections from OOPHM clients + ensureOophmListener(); + return true; } + + protected int codeServerPort; + + protected BrowserListener listener; + + private BrowserWidgetHostImpl browserHost = new UiBrowserWidgetHostImpl(); + + protected void ensureOophmListener() { + if (listener == null) { + codeServerPort = options.getPortHosted(); + listener = new BrowserListener(getTopLogger(), codeServerPort, + new OophmSessionHandler(browserHost)); + listener.start(); + try { + // save the port we actually used if it was auto + codeServerPort = listener.getSocketPort(); + } catch (UnableToCompleteException e) { + // ignore errors listening, we will catch them later + } + } + } protected abstract int doStartUpServer(); @@ -558,7 +800,17 @@ return "localhost"; } - protected abstract void initializeLogger(); + private void initializeLogger() { + Type logLevel = options.getLogLevel(); + if (headlessMode) { + PrintWriterTreeLogger logger = new PrintWriterTreeLogger( + new PrintWriter(System.out)); + logger.setMaxDetail(logLevel); + topLogger = logger; + } else { + topLogger = ui.getTopLogger(logLevel); + } + } /** * Called from a selection script as it begins to load in hosted mode. This @@ -570,7 +822,15 @@ * will trigger a full-page refresh by the calling (out of date) * selection script */ - protected abstract boolean initModule(String moduleName); + protected boolean initModule(String moduleName) { + /* + * Not used in legacy mode due to GWTShellServlet playing this role. + * + * TODO: something smarter here and actually make GWTShellServlet less + * magic? + */ + return false; + } /** * By default we will open the application window. @@ -599,28 +859,6 @@ assert (moduleDef != null) : "Required module state is absent"; return moduleDef; } - - protected abstract boolean notDone(); - - protected abstract void openAppWindow(); - - protected abstract void processEvents() throws Exception; - - protected final void pumpEventLoop() { - TreeLogger logger = getTopLogger(); - - // Run the event loop. When there are no open shells, quit. - // - while (notDone()) { - try { - processEvents(); - } catch (Throwable e) { - String msg = e.getMessage(); - msg = (msg != null ? msg : e.getClass().getName()); - logger.log(TreeLogger.ERROR, msg, e); - } - } - } protected final void setHeadless(boolean headlessMode) { this.headlessMode = headlessMode; ======================================= --- /changes/jat/abstractui/dev/oophm/overlay/com/google/gwt/dev/GWTShell.java Wed Sep 23 11:22:27 2009 +++ /changes/jat/abstractui/dev/oophm/overlay/com/google/gwt/dev/GWTShell.java Thu Oct 1 17:01:51 2009 @@ -38,7 +38,7 @@ */ @SuppressWarnings("deprecation") @Deprecated -public class GWTShell extends OophmHostedModeBase { +public class GWTShell extends HostedModeBase { /** * Handles the list of startup urls that can be passed at the end of the @@ -248,9 +248,10 @@ @Override protected int doStartUpServer() { + TreeLogger logger = ui.getWebServerLogger("Tomcat", null); // TODO(bruce): make tomcat work in terms of the modular launcher String whyFailed = EmbeddedTomcatServer.start(isHeadless() ? getTopLogger() - : webServerLog.getLogger(), getPort(), options); + : logger, getPort(), options); if (whyFailed != null) { getTopLogger().log(TreeLogger.ERROR, "Starting Tomcat: " + whyFailed); @@ -258,14 +259,4 @@ } return EmbeddedTomcatServer.getPort(); } - - @Override - protected ImageIcon getWebServerIcon() { - return null; - } - - @Override - protected String getWebServerName() { - return "Tomcat"; - } -} +} ======================================= --- /changes/jat/abstractui/dev/oophm/overlay/com/google/gwt/dev/HostedMode.java Sat Aug 22 16:01:38 2009 +++ /changes/jat/abstractui/dev/oophm/overlay/com/google/gwt/dev/HostedMode.java Thu Oct 1 17:01:51 2009 @@ -41,14 +41,12 @@ import java.util.HashMap; import java.util.Map; -import javax.swing.ImageIcon; - /** * The main executable class for the hosted mode shell. NOTE: the public API for * this class is to be determined. Consider this class as having <b>no</b> * public API other than {...@link #main(String[])}. */ -public class HostedMode extends OophmHostedModeBase { +public class HostedMode extends HostedModeBase { /** * Handles the -server command line flag. @@ -165,7 +163,7 @@ } } - interface HostedModeOptions extends OophmHostedModeBaseOptions, + interface HostedModeOptions extends HostedModeBaseOptions, CompilerOptions { ServletContainerLauncher getServletContainerLauncher(); @@ -175,7 +173,7 @@ /** * Concrete class to implement all hosted mode options. */ - static class HostedModeOptionsImpl extends OophmHostedModeBaseOptionsImpl + static class HostedModeOptionsImpl extends HostedModeBaseOptionsImpl implements HostedModeOptions { private File extraDir; private int localWorkers; @@ -286,12 +284,7 @@ HostedMode() { } - public WebServerRestart hasWebServer() { - return options.isNoServer() ? WebServerRestart.DISABLED - : WebServerRestart.ENABLED; - } - - public void restartServer(TreeLogger logger) throws UnableToCompleteException { + protected void restartServer(TreeLogger logger) throws UnableToCompleteException { server.refresh(); } @@ -382,7 +375,7 @@ @Override protected int doStartUpServer() { try { - TreeLogger serverLogger = webServerLog.getLogger(); + TreeLogger serverLogger = ui.getWebServerLogger(getWebServerName(), null); serverLogger.log(TreeLogger.INFO, "Starting HTTP on port " + getPort(), null); server = options.getServletContainerLauncher().start(serverLogger, @@ -408,13 +401,6 @@ return super.getHost(); } - @Override - protected ImageIcon getWebServerIcon() { - return loadImageIcon(options.getServletContainerLauncher().getIconPath(), - false); - } - - @Override protected String getWebServerName() { return options.getServletContainerLauncher().getName(); } ======================================= --- /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/OophmHostedModeBase.java Sun Sep 20 13:03:25 2009 +++ /changes/jat/abstractui/dev/oophm/src/com/google/gwt/dev/OophmHostedModeBase.java Thu Oct 1 17:01:51 2009 @@ -18,7 +18,6 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.TypeOracle; -import com.google.gwt.dev.WebServerPanel.RestartAction; import com.google.gwt.dev.cfg.ModuleDef; import com.google.gwt.dev.shell.BrowserListener; import com.google.gwt.dev.shell.BrowserWidgetHost; @@ -29,14 +28,10 @@ import com.google.gwt.dev.util.BrowserInfo; import com.google.gwt.dev.util.collect.HashMap; import com.google.gwt.dev.util.log.AbstractTreeLogger; -import com.google.gwt.dev.util.log.PrintWriterTreeLogger; import com.google.gwt.util.tools.ArgHandlerString; import java.awt.Cursor; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; import java.io.File; -import java.io.PrintWriter; import java.net.MalformedURLException; import java.net.URL; import java.util.IdentityHashMap; @@ -46,7 +41,6 @@ import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JTabbedPane; -import javax.swing.WindowConstants; /** * Base class for OOPHM hosted mode shells. @@ -77,85 +71,6 @@ void removeTab(ModuleTabPanel tabPanel); } - /** - * Handles the -portHosted command line flag. - */ - protected static class ArgHandlerPortHosted extends ArgHandlerString { - - private final OptionPortHosted options; - - public ArgHandlerPortHosted(OptionPortHosted options) { - this.options = options; - } - - @Override - public String[] getDefaultArgs() { - return new String[] {"-portHosted", "9997"}; - } - - @Override - public String getPurpose() { - return "Listens on the specified port for hosted mode connections"; - } - - @Override - public String getTag() { - return "-portHosted"; - } - - @Override - public String[] getTagArgs() { - return new String[] {"port-number | \"auto\""}; - } - - @Override - public boolean setString(String value) { - if (value.equals("auto")) { - options.setPortHosted(0); - } else { - try { - options.setPortHosted(Integer.parseInt(value)); - } catch (NumberFormatException e) { - System.err.println("A port must be an integer or \"auto\""); - return false; - } - } - return true; - } - } - - protected interface OptionPortHosted { - int getPortHosted(); - - void setPortHosted(int portHosted); - } - - abstract static class ArgProcessor extends HostedModeBase.ArgProcessor { - public ArgProcessor(OophmHostedModeBaseOptions options, boolean forceServer) { - super(options, forceServer); - registerHandler(new ArgHandlerPortHosted(options)); - } - } - - interface OophmHostedModeBaseOptions extends HostedModeBaseOptions, - OptionPortHosted { - } - - /** - * Concrete class to implement all shell options. - */ - static class OophmHostedModeBaseOptionsImpl extends HostedModeBaseOptionsImpl - implements OophmHostedModeBaseOptions { - private int portHosted; - - public int getPortHosted() { - return portHosted; - } - - public void setPortHosted(int port) { - portHosted = port; - } - } private class OophmBrowserWidgetHostImpl extends BrowserWidgetHostImpl { private final Map<ModuleSpaceHost, ModulePanel> moduleTabs = new IdentityHashMap<ModuleSpaceHost, ModulePanel>(); @@ -234,111 +149,6 @@ tab.disconnect(); } } - - private ModuleTabPanel findModuleTab(String userAgent, String remoteSocket, - String url, String tabKey, String moduleName) { - int hostEnd = remoteSocket.indexOf(':'); - if (hostEnd < 0) { - hostEnd = remoteSocket.length(); - } - String remoteHost = remoteSocket.substring(0, hostEnd); - final DevelModeTabKey key = new DevelModeTabKey(userAgent, url, tabKey, - remoteHost); - ModuleTabPanel moduleTabPanel = tabPanels.get(key); - if (moduleTabPanel == null) { - moduleTabPanel = new ModuleTabPanel(userAgent, remoteSocket, url, - new TabPanelCollection() { - public void addTab(ModuleTabPanel tabPanel, ImageIcon icon, - String title, String tooltip) { - synchronized (tabs) { - tabs.addTab(title, icon, tabPanel, tooltip); - tabPanels.put(key, tabPanel); - } - } - - public void removeTab(ModuleTabPanel tabPanel) { - synchronized (tabs) { - tabs.remove(tabPanel); - tabPanels.remove(key); - } - } - }, moduleName); - } - return moduleTabPanel; - } - } - - protected static final String PACKAGE_PATH = OophmHostedModeBase.class.getPackage().getName().replace( - '.', '/').concat("/shell/"); - - private static final Random RNG = new Random(); - - private static int sessionCounter = 0; - - /** - * Produce a random string that has low probability of collisions. - * - * <p>In this case, we use 16 characters, each drawn from a pool of 94, - * so the number of possible values is 94^16, leading to an expected number - * of values used before a collision occurs as sqrt(pi/2) * 94^8 (treated the - * same as a birthday attack), or a little under 10^16. - * - * <p>This algorithm is also implemented in hosted.html, though it is not - * technically important that they match. - * - * @return a random string - */ - protected static String randomString() { - StringBuilder buf = new StringBuilder(16); - for (int i = 0; i < 16; ++i) { - buf.append((char) RNG.nextInt('~' - '!' + 1) + '!'); - } - return buf.toString(); - } - - /** - * Loads an image from the classpath in this package. - */ - static ImageIcon loadImageIcon(String name) { - return loadImageIcon(name, true); - } - - /** - * Loads an image from the classpath, optionally prepending this package. - * - * @param name name of an image file. - * @param prependPackage true if {...@link #PACKAGE_PATH} should be prepended to - * this name. - */ - static ImageIcon loadImageIcon(String name, boolean prependPackage) { - ClassLoader cl = OophmHostedModeBase.class.getClassLoader(); - if (prependPackage) { - name = PACKAGE_PATH + name; - } - - URL url = (name == null) ? null : cl.getResource(name); - if (url != null) { - ImageIcon image = new ImageIcon(url); - return image; - } else { - // Bad image. - return new ImageIcon(); - } - } - - protected int codeServerPort; - - protected BrowserListener listener; - - /** - * Hiding super field because it's actually the same object, just with a - * stronger type. - */ - @SuppressWarnings("hiding") - protected final OophmHostedModeBaseOptionsImpl options = (OophmHostedModeBaseOptionsImpl) super.options; - - // TODO(jat): clean up access to this field - protected WebServerPanel webServerLog; private BrowserWidgetHostImpl browserHost = new OophmBrowserWidgetHostImpl(); @@ -352,24 +162,6 @@ private AbstractTreeLogger topLogger; - public OophmHostedModeBase() { - super(); - } - - @Override - public void closeAllBrowserWindows() { - } - - @Override - public TreeLogger getTopLogger() { - return topLogger; - } - - @Override - public boolean hasBrowserWindowsOpen() { - return false; - } - /** * Launch the arguments as Urls in separate windows. */ @@ -430,61 +222,10 @@ protected void compile(TreeLogger logger) throws UnableToCompleteException { throw new UnsupportedOperationException(); } - - @Override - protected boolean doStartup() { - if (super.doStartup()) { - // Accept connections from OOPHM clients - ensureOophmListener(); - return true; - } - return false; - } protected final BrowserWidgetHost getBrowserHost() { return browserHost; } - - protected int getNextSessionCounter(File logdir) { - if (sessionCounter == 0 && logdir != null) { - // first time only, figure out the "last" session count already in use - for (String filename : logdir.list()) { - if (filename.matches("^[A-Za-z0-9_$]*-[a-z]*-[0-9]*.log$")) { - String substring = filename.substring(filename.lastIndexOf('-') + 1, - filename.length() - 4); - int number = Integer.parseInt(substring); - if (number > sessionCounter) { - sessionCounter = number; - } - } - } - } - return ++sessionCounter; - } - - /** - * @return the icon to use for the web server tab - */ - protected ImageIcon getWebServerIcon() { - return null; - } - - /** - * @return the name of the web server tab - */ - protected String getWebServerName() { - return "Server"; - } - - @Override - protected void initializeLogger() { - if (mainWnd != null) { - topLogger = mainWnd.getLogger(); - } else { - topLogger = new PrintWriterTreeLogger(new PrintWriter(System.out)); - } - topLogger.setMaxDetail(options.getLogLevel()); - } @Override protected boolean initModule(String moduleName) { @@ -496,57 +237,6 @@ */ return false; } - - @Override - protected synchronized boolean notDone() { - return !mainWindowClosed; - } - - @Override - protected void openAppWindow() { - if (isHeadless()) { - return; - } - ImageIcon gwtIcon = loadImageIcon("icon24.png"); - frame = new JFrame("GWT Development Mode"); - tabs = new JTabbedPane(); - if (options.alsoLogToFile()) { - options.getLogDir().mkdirs(); - } - mainWnd = new ShellMainWindow(options.getLogLevel(), - options.getLogFile("main.log")); - tabs.addTab("Development Mode", gwtIcon, mainWnd, "GWT Development mode"); - if (!options.isNoServer()) { - webServerLog = new WebServerPanel(getPort(), options.getLogLevel(), - options.getLogFile("webserver.log"), - new RestartAction() { - public void restartServer(TreeLogger logger) { - try { - OophmHostedModeBase.this.restartServer(logger); - } catch (UnableToCompleteException e) { - // Already logged why it failed - } - } - }); - tabs.addTab(getWebServerName(), getWebServerIcon(), webServerLog); - } - frame.getContentPane().add(tabs); - frame.setSize(950, 700); - frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - frame.addWindowListener(new WindowAdapter() { - @Override - public void windowClosed(WindowEvent e) { - setMainWindowClosed(); - } - }); - frame.setIconImage(loadImageIcon("icon16.png").getImage()); - frame.setVisible(true); - } - - @Override - protected void processEvents() throws Exception { - Thread.sleep(10); - } protected synchronized void setMainWindowClosed() { mainWindowClosed = true; ======================================= --- /changes/jat/abstractui/user/src/com/google/gwt/junit/JUnitShell.java Wed Sep 30 17:53:07 2009 +++ /changes/jat/abstractui/user/src/com/google/gwt/junit/JUnitShell.java Thu Oct 1 17:01:51 2009 @@ -396,34 +396,19 @@ * @return the list of remote user agents */ public static String[] getRemoteUserAgents() { - if (unitTestShell == null) { - return null; - } - return unitTestShell.remoteUserAgents; + return getUnitTestShell().remoteUserAgents; } /** * Checks if a testCase should not be executed. Currently, a test is either * executed on all clients (mentioned in this test) or on no clients. * - * @param testInfo the test info to check + * @param testCase current testCase. * @return true iff the test should not be executed on any of the specified * clients. */ - public static boolean mustNotExecuteTest(TestInfo testInfo) { - if (unitTestShell == null) { - throw new IllegalStateException( - "mustNotExecuteTest cannot be called before runTest()"); - } - try { - Class<?> testClass = TestCase.class.getClassLoader().loadClass( - testInfo.getTestClass()); - return unitTestShell.mustNotExecuteTest(getBannedPlatforms(testClass, - testInfo.getTestMethod())); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Could not load test class: " - + testInfo.getTestClass()); - } + public static boolean mustNotExecuteTest(TestCase testCase) { + return getUnitTestShell().mustNotExecuteTest(getBannedPlatforms(testCase)); } /** @@ -503,19 +488,16 @@ } /** - * Returns the set of banned {...@code Platform} for a test method. - * - * @param testClass the testClass - * @param methodName the name of the test method + * returns the set of banned {...@code Platform} for a test method. */ - private static Set<Platform> getBannedPlatforms(Class<?> testClass, - String methodName) { + private static Set<Platform> getBannedPlatforms(TestCase testCase) { + Class<?> testClass = testCase.getClass(); Set<Platform> bannedSet = EnumSet.noneOf(Platform.class); if (testClass.isAnnotationPresent(DoNotRunWith.class)) { bannedSet.addAll(Arrays.asList(testClass.getAnnotation(DoNotRunWith.class).value())); } try { - Method testMethod = testClass.getMethod(methodName); + Method testMethod = testClass.getMethod(testCase.getName()); if (testMethod.isAnnotationPresent(DoNotRunWith.class)) { bannedSet.addAll(Arrays.asList(testMethod.getAnnotation( DoNotRunWith.class).value())); @@ -554,10 +536,6 @@ // TODO: install a shutdown hook? Not necessary with GWTShell. unitTestShell.lastLaunchFailed = false; } - if (unitTestShell.thread != Thread.currentThread()) { - throw new IllegalThreadStateException( - "JUnitShell can only be accessed from the thread that created it."); - } return unitTestShell; } @@ -662,17 +640,11 @@ */ private long testMethodTimeout; - /** - * The thread that created the JUnitShell. - */ - private Thread thread; - /** * Enforce the singleton pattern. The call to {...@link GWTShell}'s ctor forces * server mode and disables processing extra arguments as URLs to be shown. */ private JUnitShell() { - thread = Thread.currentThread(); setRunTomcat(true); setHeadless(true); } @@ -692,15 +664,6 @@ throw new RuntimeException("Unable to determine my ip address", e); } } - - @Override - public TreeLogger getTopLogger() { - if (consoleLogger != null) { - return consoleLogger; - } else { - return super.getTopLogger(); - } - } /** * Check for updates once a minute. @@ -724,16 +687,6 @@ } return true; } - - @Override - protected void initializeLogger() { - if (isHeadless()) { - consoleLogger = new PrintWriterTreeLogger(); - consoleLogger.setMaxDetail(options.getLogLevel()); - } else { - super.initializeLogger(); - } - } /** * Overrides {...@link GWTShell#notDone()} to wait for the currently-running test @@ -928,8 +881,7 @@ private void runTestImpl(GWTTestCase testCase, TestResult testResult) throws UnableToCompleteException { - if (mustNotExecuteTest(getBannedPlatforms(testCase.getClass(), - testCase.getName()))) { + if (mustNotExecuteTest(testCase)) { return; } --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---