Revision: 7027 Author: j...@google.com Date: Thu Nov 19 12:24:42 2009 Log: Rearrange how module logging is handled.
Patch by: jat Review by: rdayal http://code.google.com/p/google-web-toolkit/source/detail?r=7027 Added: /trunk/dev/core/src/com/google/gwt/dev/ModuleHandle.java Modified: /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java /trunk/dev/core/src/com/google/gwt/dev/HeadlessUI.java /trunk/dev/core/src/com/google/gwt/dev/SwingUI.java /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java /trunk/dev/core/src/com/google/gwt/dev/shell/HtmlUnitSessionHandler.java /trunk/dev/core/src/com/google/gwt/dev/shell/OophmSessionHandler.java /trunk/dev/core/src/com/google/gwt/dev/shell/remoteui/RemoteUI.java /trunk/dev/core/src/com/google/gwt/dev/ui/CloseModuleCallback.java /trunk/dev/core/src/com/google/gwt/dev/ui/DevModeUI.java /trunk/dev/core/test/com/google/gwt/dev/shell/BrowserChannelServerTest.java ======================================= --- /dev/null +++ /trunk/dev/core/src/com/google/gwt/dev/ModuleHandle.java Thu Nov 19 12:24:42 2009 @@ -0,0 +1,35 @@ +/* + * 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; + +/** + * Opaque handle to a module instance - external code can only get a logger or + * notify the module handle it is no longer needed. + */ +public interface ModuleHandle { + + /** + * @return the logger for this module. + */ + TreeLogger getLogger(); + + /** + * Mark the module instance associated with this handle as unloaded. + */ + void unload(); +} ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java Wed Nov 18 15:02:16 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java Thu Nov 19 12:24:42 2009 @@ -17,7 +17,6 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; -import com.google.gwt.core.ext.TreeLogger.HelpInfo; import com.google.gwt.core.ext.linker.ArtifactSet; import com.google.gwt.core.ext.linker.impl.StandardLinkerContext; import com.google.gwt.dev.Precompile.PrecompileOptionsImpl; @@ -38,7 +37,6 @@ import com.google.gwt.dev.ui.DevModeUI; import com.google.gwt.dev.ui.DoneCallback; import com.google.gwt.dev.ui.DoneEvent; -import com.google.gwt.dev.ui.DevModeUI.ModuleHandle; import com.google.gwt.dev.util.BrowserInfo; import com.google.gwt.dev.util.Util; import com.google.gwt.dev.util.arg.ArgHandlerGenDir; @@ -57,7 +55,6 @@ 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; @@ -77,22 +74,25 @@ */ public class UiBrowserWidgetHostImpl implements BrowserWidgetHost { - public ModuleSpaceHost createModuleSpaceHost(TreeLogger mainLogger, - String moduleName, String userAgent, String url, String tabKey, - String sessionKey, BrowserChannelServer serverChannel, - byte[] userAgentIcon) throws UnableToCompleteException { + public ModuleHandle createModuleLogger(String moduleName, String userAgent, + String url, String tabKey, String sessionKey, + BrowserChannelServer serverChannel, byte[] userAgentIcon) { 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); String remoteSocket = serverChannel.getRemoteEndpoint(); - ModuleHandle module = ui.loadModule(userAgent, remoteSocket, url, tabKey, - moduleName, sessionKey, agentTag, userAgentIcon, maxLevel); + ModuleHandle module = ui.getModuleLogger(userAgent, remoteSocket, url, + tabKey, moduleName, sessionKey, agentTag, userAgentIcon, maxLevel); + return module; + } + + public ModuleSpaceHost createModuleSpaceHost(ModuleHandle module, + String moduleName) throws UnableToCompleteException { // TODO(jat): add support for closing an active module - logger = module.getLogger(); + TreeLogger logger = module.getLogger(); try { // Try to find an existing loaded version of the module def. ModuleDef moduleDef = loadModule(logger, moduleName, true); @@ -102,26 +102,13 @@ ShellModuleSpaceHost host = doCreateShellModuleSpaceHost(logger, moduleDef.getCompilationState(logger), moduleDef); - - loadedModules.put(host, module); return host; } catch (RuntimeException e) { logger.log(TreeLogger.ERROR, "Exception initializing module", e); - ui.unloadModule(module); + module.unload(); throw e; } } - - public TreeLogger getLogger() { - return getTopLogger(); - } - - public void unloadModule(ModuleSpaceHost moduleSpaceHost) { - ModuleHandle module = loadedModules.remove(moduleSpaceHost); - if (module != null) { - ui.unloadModule(module); - } - } } /** @@ -589,7 +576,8 @@ private static final AtomicLong uniqueId = new AtomicLong(); - public static String normalizeURL(String unknownUrlText, int port, String host) { + public static String normalizeURL(String unknownUrlText, int port, + String host) { if (unknownUrlText.indexOf(":") != -1) { // Assume it's a full url. return unknownUrlText; @@ -676,8 +664,6 @@ private boolean headlessMode = false; - private final Map<ModuleSpaceHost, ModuleHandle> loadedModules = new IdentityHashMap<ModuleSpaceHost, ModuleHandle>(); - private boolean started; private TreeLogger topLogger; @@ -709,16 +695,19 @@ public void launchStartupUrls(final TreeLogger logger) { ensureCodeServerListener(); String startupURL = ""; - try { - for (String prenormalized : options.getStartupURLs()) { - startupURL = normalizeURL(prenormalized, getPort(), getHost()); - logger.log(TreeLogger.TRACE, "Starting URL: " + startupURL, null); - launchURL(startupURL); - } - } catch (UnableToCompleteException e) { - logger.log(TreeLogger.ERROR, - "Unable to open new window for startup URL: " + startupURL, null); - } + Map<String, URL> startupUrls = new HashMap<String, URL>(); + for (String prenormalized : options.getStartupURLs()) { + startupURL = normalizeURL(prenormalized, getPort(), getHost()); + logger.log(TreeLogger.TRACE, "Starting URL: " + startupURL, null); + try { + URL url = processUrl(startupURL); + startupUrls.put(prenormalized, url); + } catch (UnableToCompleteException e) { + logger.log(TreeLogger.ERROR, + "Unable to process startup URL " + startupURL, null); + } + } + ui.setStartupUrls(startupUrls); } /** @@ -737,7 +726,7 @@ // Eager AWT init for OS X to ensure safe coexistence with SWT. BootStrapPlatform.initGui(); - if (startUp() && !options.useRemoteUI()) { + if (startUp()) { // The web server is running now, so launch browsers for startup urls. launchStartupUrls(getTopLogger()); } @@ -838,7 +827,7 @@ if (listener == null) { codeServerPort = options.getCodeServerPort(); listener = new BrowserListener(getTopLogger(), codeServerPort, - new OophmSessionHandler(browserHost)); + new OophmSessionHandler(getTopLogger(), browserHost)); listener.start(); try { // save the port we actually used if it was auto @@ -861,55 +850,6 @@ protected final boolean isHeadless() { return headlessMode; } - - protected void launchURL(String url) throws UnableToCompleteException { - /* - * TODO(jat): properly support launching arbitrary browsers -- need some UI - * API tweaks to support that. - */ - URL parsedUrl = null; - try { - parsedUrl = new URL(url); - String path = parsedUrl.getPath(); - String query = parsedUrl.getQuery(); - String hash = parsedUrl.getRef(); - String hostedParam = BrowserListener.getDevModeURLParams(listener.getEndpointIdentifier()); - if (query == null) { - query = hostedParam; - } else { - query += '&' + hostedParam; - } - path += '?' + query; - if (hash != null) { - path += '#' + hash; - } - parsedUrl = new URL(parsedUrl.getProtocol(), parsedUrl.getHost(), - parsedUrl.getPort(), path); - url = parsedUrl.toExternalForm(); - } catch (MalformedURLException e) { - getTopLogger().log(TreeLogger.ERROR, "Invalid URL " + url, e); - throw new UnableToCompleteException(); - } - - final URL helpInfoUrl = parsedUrl; - getTopLogger().log(TreeLogger.INFO, - "Waiting for browser connection to " + url, null, new HelpInfo() { - @Override - public String getAnchorText() { - return "Launch default browser"; - } - - @Override - public String getPrefix() { - return ""; - } - - @Override - public URL getURL() { - return helpInfoUrl; - } - }); - } /** * Perform an initial hosted mode link, without overwriting newer or @@ -950,6 +890,37 @@ assert (moduleDef != null) : "Required module state is absent"; return moduleDef; } + + protected URL processUrl(String url) throws UnableToCompleteException { + /* + * TODO(jat): properly support launching arbitrary browsers -- need some UI + * API tweaks to support that. + */ + URL parsedUrl = null; + try { + parsedUrl = new URL(url); + String path = parsedUrl.getPath(); + String query = parsedUrl.getQuery(); + String hash = parsedUrl.getRef(); + String hostedParam = BrowserListener.getDevModeURLParams(listener.getEndpointIdentifier()); + if (query == null) { + query = hostedParam; + } else { + query += '&' + hostedParam; + } + path += '?' + query; + if (hash != null) { + path += '#' + hash; + } + parsedUrl = new URL(parsedUrl.getProtocol(), parsedUrl.getHost(), + parsedUrl.getPort(), path); + url = parsedUrl.toExternalForm(); + } catch (MalformedURLException e) { + getTopLogger().log(TreeLogger.ERROR, "Invalid URL " + url, e); + throw new UnableToCompleteException(); + } + return parsedUrl; + } protected abstract void produceOutput(TreeLogger logger, StandardLinkerContext linkerStack, ArtifactSet artifacts, ModuleDef module) @@ -990,8 +961,8 @@ return false; } options.setPort(resultPort); - getTopLogger().log(TreeLogger.TRACE, - "Started web server on port " + resultPort); + getTopLogger().log(TreeLogger.TRACE, "Started web server on port " + + resultPort); } return true; ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/HeadlessUI.java Fri Oct 16 20:22:17 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/HeadlessUI.java Thu Nov 19 12:24:42 2009 @@ -34,17 +34,16 @@ } @Override - public ModuleHandle loadModule(String userAgent, String remoteSocket, + public ModuleHandle getModuleLogger(String userAgent, String remoteSocket, String url, String tabKey, String moduleName, String sessionKey, String agentTag, byte[] agentIcon, Type logLevel) { return new ModuleHandle() { public TreeLogger getLogger() { return getConsoleLogger(); } - }; - } - - @Override - public void unloadModule(ModuleHandle module) { + + public void unload() { + } + }; } } ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/SwingUI.java Wed Nov 18 08:54:53 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/SwingUI.java Thu Nov 19 12:24:42 2009 @@ -16,6 +16,7 @@ package com.google.gwt.dev; import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.TreeLogger.HelpInfo; import com.google.gwt.core.ext.TreeLogger.Type; import com.google.gwt.dev.DevModeBase.HostedModeBaseOptions; import com.google.gwt.dev.WebServerPanel.RestartAction; @@ -35,6 +36,7 @@ import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -78,6 +80,12 @@ public ModulePanel getTab() { return tab; } + + public void unload() { + if (tab != null) { + tab.disconnect(); + } + } } /** @@ -162,6 +170,36 @@ public SwingUI(HostedModeBaseOptions options) { this.options = options; } + + @Override + public ModuleHandle getModuleLogger(String userAgent, String remoteSocket, + String url, String tabKey, String moduleName, String sessionKey, + String agentTag, byte[] agentIcon, TreeLogger.Type logLevel) { + // TODO(jat): add support for closing an active module + ModuleTabPanel tabPanel = null; + ModulePanel tab = null; + tabPanel = findModuleTab(userAgent, remoteSocket, url, tabKey, + moduleName, agentIcon); + tab = tabPanel.addModuleSession(logLevel, moduleName, sessionKey, + options.getLogFile(String.format("%s-%s-%d.log", moduleName, agentTag, + getNextSessionCounter(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? + return new SwingModuleHandle(logger, tab); + } @Override public TreeLogger getTopLogger() { @@ -229,41 +267,30 @@ } @Override - public ModuleHandle loadModule(String userAgent, String remoteSocket, - String url, String tabKey, String moduleName, String sessionKey, - String agentTag, byte[] agentIcon, TreeLogger.Type logLevel) { - // TODO(jat): add support for closing an active module - ModuleTabPanel tabPanel = null; - ModulePanel tab = null; - tabPanel = findModuleTab(userAgent, remoteSocket, url, tabKey, - moduleName, agentIcon); - tab = tabPanel.addModuleSession(logLevel, moduleName, sessionKey, - options.getLogFile(String.format("%s-%s-%d.log", moduleName, agentTag, - getNextSessionCounter(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? - return new SwingModuleHandle(logger, tab); - } - - @Override - public void unloadModule(ModuleHandle module) { - SwingModuleHandle handle = (SwingModuleHandle) module; - Disconnectable tab = handle.getTab(); - if (tab != null) { - tab.disconnect(); + public void setStartupUrls(Map<String, URL> urls) { + // TODO(jat): provide UI for selecting URLs and launching + ArrayList<String> keys = new ArrayList<String>(urls.keySet()); + Collections.sort(keys); + for (String url : keys) { + final URL helpInfoUrl = urls.get(url); + getTopLogger().log(TreeLogger.INFO, "Waiting for browser connection to " + + helpInfoUrl.toExternalForm(), null, + new HelpInfo() { + @Override + public String getAnchorText() { + return "Launch default browser"; + } + + @Override + public String getPrefix() { + return ""; + } + + @Override + public URL getURL() { + return helpInfoUrl; + } + }); } } ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java Mon Oct 26 14:02:26 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java Thu Nov 19 12:24:42 2009 @@ -254,8 +254,7 @@ /** * Load a new instance of a module. - * - * @param logger + * * @param channel * @param moduleName * @param userAgent @@ -267,9 +266,9 @@ * 24x24) representing the user agent or null if unavailable * @return a TreeLogger to use for the module's logs */ - public abstract TreeLogger loadModule(TreeLogger logger, - BrowserChannel channel, String moduleName, String userAgent, String url, - String tabKey, String sessionKey, byte[] userAgentIcon); + public abstract TreeLogger loadModule(BrowserChannel channel, + String moduleName, String userAgent, String url, String tabKey, + String sessionKey, byte[] userAgentIcon); public abstract ExceptionOrReturnValue setProperty(BrowserChannel channel, int refId, int dispId, Value newValue); ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java Thu Nov 19 10:58:27 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java Thu Nov 19 12:24:42 2009 @@ -373,7 +373,7 @@ Thread.currentThread().setName( "Code server for " + moduleName + " from " + userAgent + " on " + url + " @ " + sessionKey); - logger = handler.loadModule(logger, this, moduleName, userAgent, url, + logger = handler.loadModule(this, moduleName, userAgent, url, tabKey, sessionKey, iconBytes); try { // send LoadModule response ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java Thu Nov 5 10:42:40 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java Thu Nov 19 12:24:42 2009 @@ -15,8 +15,8 @@ */ package com.google.gwt.dev.shell; -import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.dev.ModuleHandle; /** * Interface that unifies access to the <code>BrowserWidget</code>, @@ -25,9 +25,8 @@ public interface BrowserWidgetHost { /** - * For OOPHM. + * Create a logger for a module instance. * - * @param logger * @param moduleName * @param userAgent * @param url URL of top-level window, may be null for old browser plugins @@ -37,16 +36,22 @@ * @param serverChannel connection from the client * @param userAgentIcon byte array containing an icon (which fits in 24x24) * for this user agent or null if unavailable + * @return ModuleHandle instance -- caller is responsible for calling + * {...@link ModuleHandle#unload()} on it when done */ - ModuleSpaceHost createModuleSpaceHost(TreeLogger logger, String moduleName, - String userAgent, String url, String tabKey, String sessionKey, - BrowserChannelServer serverChannel, byte[] userAgentIcon) - throws UnableToCompleteException; - - TreeLogger getLogger(); + ModuleHandle createModuleLogger(String moduleName, String userAgent, + String url, String tabKey, String sessionKey, + BrowserChannelServer serverChannel, byte[] userAgentIcon); /** - * For OOPHM. + * Create a ModuleSpaceHost for the specified module. + * + * @param module ModuleHandle returned from a previous createModuleLogger + * call. + * @param moduleName name of module to create + * @return ModuleSpaceHost instance + * @throws UnableToCompleteException */ - void unloadModule(ModuleSpaceHost moduleSpaceHost); -} + ModuleSpaceHost createModuleSpaceHost(ModuleHandle module, String moduleName) + throws UnableToCompleteException; +} ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/shell/HtmlUnitSessionHandler.java Wed Oct 28 17:37:45 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/shell/HtmlUnitSessionHandler.java Thu Nov 19 12:24:42 2009 @@ -250,9 +250,9 @@ } @Override - public TreeLogger loadModule(TreeLogger logger, BrowserChannel channel, - String moduleName, String userAgent, String url, String tabKey, - String sessionKey, byte[] userAgentIcon) { + public TreeLogger loadModule(BrowserChannel channel, String moduleName, + String userAgent, String url, String tabKey, String sessionKey, + byte[] userAgentIcon) { throw new UnsupportedOperationException("loadModule must not be called"); } ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/shell/OophmSessionHandler.java Thu Nov 12 14:37:28 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/shell/OophmSessionHandler.java Thu Nov 19 12:24:42 2009 @@ -16,6 +16,7 @@ package com.google.gwt.dev.shell; import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.dev.ModuleHandle; import com.google.gwt.dev.shell.BrowserChannel.SessionHandler; import com.google.gwt.dev.shell.BrowserChannel.Value; import com.google.gwt.dev.shell.JsValue.DispatchMethod; @@ -34,16 +35,20 @@ private BrowserWidgetHost host; - private TreeLogger logger; - private Map<BrowserChannelServer, ModuleSpace> moduleMap = Collections.synchronizedMap(new HashMap<BrowserChannelServer, ModuleSpace>()); + private Map<BrowserChannelServer, ModuleHandle> moduleHandleMap = Collections.synchronizedMap(new HashMap<BrowserChannelServer, ModuleHandle>()); + + private final TreeLogger topLogger; + /** * Listens for new connections from browsers. + * @param topLogger logger to use for non-module-related messages + * @param host BrowserWidgetHost instance */ - public OophmSessionHandler(BrowserWidgetHost host) { + public OophmSessionHandler(TreeLogger topLogger, BrowserWidgetHost host) { this.host = host; - logger = host.getLogger(); + this.topLogger = topLogger; } @Override @@ -60,7 +65,9 @@ int dispId) { BrowserChannelServer serverChannel = (BrowserChannelServer) channel; ModuleSpace moduleSpace = moduleMap.get(serverChannel); - assert moduleSpace != null; + ModuleHandle moduleHandle = moduleHandleMap.get(serverChannel); + assert moduleSpace != null && moduleHandle != null; + TreeLogger logger = moduleHandle.getLogger(); ServerObjectsTable localObjects = serverChannel.getJavaObjectsExposedInBrowser(); try { JsValueOOPHM obj = new JsValueOOPHM(); @@ -94,7 +101,9 @@ BrowserChannelServer serverChannel = (BrowserChannelServer) channel; ServerObjectsTable localObjects = serverChannel.getJavaObjectsExposedInBrowser(); ModuleSpace moduleSpace = moduleMap.get(serverChannel); - assert moduleSpace != null; + ModuleHandle moduleHandle = moduleHandleMap.get(serverChannel); + assert moduleSpace != null && moduleHandle != null; + TreeLogger logger = moduleHandle.getLogger(); CompilingClassLoader cl = moduleSpace.getIsolatedClassLoader(); // Treat dispatch id 0 as toString() @@ -155,21 +164,21 @@ } @Override - public synchronized TreeLogger loadModule(TreeLogger loadModuleLogger, - BrowserChannel channel, String moduleName, String userAgent, String url, - String tabKey, String sessionKey, byte[] userAgentIcon) { - logger = loadModuleLogger; + public synchronized TreeLogger loadModule(BrowserChannel channel, + String moduleName, String userAgent, String url, String tabKey, + String sessionKey, byte[] userAgentIcon) { + PerfLogger.start("OophmSessionHandler.loadModule " + moduleName); + BrowserChannelServer serverChannel = (BrowserChannelServer) channel; + ModuleHandle moduleHandle = host.createModuleLogger(moduleName, userAgent, + url, tabKey, sessionKey, serverChannel, userAgentIcon); + TreeLogger logger = moduleHandle.getLogger(); + moduleHandleMap.put(serverChannel, moduleHandle); + ModuleSpace moduleSpace = null; try { - PerfLogger.start("OophmSessionHandler.loadModule " + moduleName); // Attach a new ModuleSpace to make it programmable. - // - BrowserChannelServer serverChannel = (BrowserChannelServer) channel; - ModuleSpaceHost msh = host.createModuleSpaceHost(loadModuleLogger, - moduleName, userAgent, url, tabKey, sessionKey, serverChannel, - userAgentIcon); - logger = msh.getLogger(); - ModuleSpace moduleSpace = new ModuleSpaceOOPHM(msh, moduleName, - serverChannel); + ModuleSpaceHost msh = host.createModuleSpaceHost(moduleHandle, + moduleName); + moduleSpace = new ModuleSpaceOOPHM(msh, moduleName, serverChannel); moduleMap.put(serverChannel, moduleSpace); PerfLogger.start("ModuleSpace.onLoad"); moduleSpace.onLoad(logger); @@ -178,14 +187,20 @@ // that can go wrong trying to load a module, including Error-derived // things like NoClassDefFoundError. // - this.logger.log(TreeLogger.ERROR, "Failed to load module '" + moduleName - + "' from user agent '" + userAgent + "' at " + moduleHandle.getLogger().log(TreeLogger.ERROR, "Failed to load module '" + + moduleName + "' from user agent '" + userAgent + "' at " + channel.getRemoteEndpoint(), e); + if (moduleSpace != null) { + moduleSpace.dispose(); + } + moduleHandle.unload(); + moduleMap.remove(serverChannel); + moduleHandleMap.remove(serverChannel); } finally { PerfLogger.end(); PerfLogger.end(); } - return this.logger; + return moduleHandle.getLogger(); } @Override @@ -193,7 +208,9 @@ int dispId, Value newValue) { BrowserChannelServer serverChannel = (BrowserChannelServer) channel; ModuleSpace moduleSpace = moduleMap.get(serverChannel); - assert moduleSpace != null; + ModuleHandle moduleHandle = moduleHandleMap.get(serverChannel); + assert moduleSpace != null && moduleHandle != null; + TreeLogger logger = moduleHandle.getLogger(); ServerObjectsTable localObjects = serverChannel.getJavaObjectsExposedInBrowser(); try { JsValueOOPHM obj = new JsValueOOPHM(); @@ -220,16 +237,18 @@ @Override public void unloadModule(BrowserChannel channel, String moduleName) { BrowserChannelServer serverChannel = (BrowserChannelServer) channel; + ModuleHandle moduleHandle = moduleHandleMap.get(serverChannel); ModuleSpace moduleSpace = moduleMap.get(serverChannel); - if (moduleSpace == null) { - logger.log(TreeLogger.ERROR, "Unload request without a module loaded", + if (moduleSpace == null || moduleHandle == null) { + topLogger.log(TreeLogger.ERROR, "Unload request without a module loaded", null); return; } - logger.log(TreeLogger.INFO, "Unloading module " + moduleHandle.getLogger().log(TreeLogger.INFO, "Unloading module " + moduleSpace.getModuleName() + " (" + moduleName + ")", null); - host.unloadModule(moduleSpace.host); moduleSpace.dispose(); + moduleHandle.unload(); moduleMap.remove(serverChannel); + moduleHandleMap.remove(serverChannel); } } ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/shell/remoteui/RemoteUI.java Wed Nov 18 13:50:42 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/shell/remoteui/RemoteUI.java Thu Nov 19 12:24:42 2009 @@ -17,6 +17,7 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.TreeLogger.Type; +import com.google.gwt.dev.ModuleHandle; import com.google.gwt.dev.shell.BrowserListener; import com.google.gwt.dev.ui.DevModeUI; import com.google.gwt.dev.ui.DoneCallback; @@ -85,7 +86,7 @@ } @Override - public ModuleHandle loadModule(String userAgent, String remoteSocket, + public ModuleHandle getModuleLogger(String userAgent, String remoteSocket, String url, String tabKey, String moduleName, String sessionKey, String agentTag, byte[] agentIcon, Type logLevel) { @@ -100,6 +101,24 @@ public TreeLogger getLogger() { return moduleLogger; } + + public void unload() { + synchronized (modulesLock) { + if (!modules.contains(this)) { + return; + } + } + + ViewerServiceTreeLogger moduleLogger = (ViewerServiceTreeLogger) (getLogger()); + + try { + viewerServiceClient.disconnectLog(moduleLogger.getLogHandle()); + } finally { + synchronized (modulesLock) { + modules.remove(this); + } + } + } }; synchronized (modulesLock) { modules.add(handle); @@ -154,23 +173,4 @@ public boolean supportsRestartWebServer() { return hasCallback(RestartServerEvent.getType()); } - - @Override - public void unloadModule(ModuleHandle module) { - synchronized (modulesLock) { - if (!modules.contains(module)) { - return; - } - } - - ViewerServiceTreeLogger moduleLogger = (ViewerServiceTreeLogger) (module.getLogger()); - - try { - viewerServiceClient.disconnectLog(moduleLogger.getLogHandle()); - } finally { - synchronized (modulesLock) { - modules.remove(module); - } - } - } -} +} ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/ui/CloseModuleCallback.java Tue Oct 13 16:57:19 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/ui/CloseModuleCallback.java Thu Nov 19 12:24:42 2009 @@ -15,7 +15,7 @@ */ package com.google.gwt.dev.ui; -import com.google.gwt.dev.ui.DevModeUI.ModuleHandle; +import com.google.gwt.dev.ModuleHandle; /** * Callback for a request to close an active module from the UI. @@ -28,7 +28,7 @@ * the UI), there will be separate calls for each one. * * @param moduleHandle module handle returned from - * {...@link DevModeUI#loadModule}. + * {...@link DevModeUI#getModuleLogger}. */ void onCloseModule(ModuleHandle moduleHandle); } ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/ui/DevModeUI.java Tue Oct 13 16:57:19 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/ui/DevModeUI.java Thu Nov 19 12:24:42 2009 @@ -17,8 +17,10 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.TreeLogger.Type; +import com.google.gwt.dev.ModuleHandle; import com.google.gwt.dev.util.log.PrintWriterTreeLogger; +import java.net.URL; import java.util.HashMap; import java.util.Map; @@ -27,19 +29,6 @@ * alternate UIs can be implemented. */ public abstract class DevModeUI { - - /** - * Opaque handle to a module - it is returned from loadModule and the client - * can only pass it to unloadModule or get a logger for messages about that - * module. - */ - public interface ModuleHandle { - - /** - * @return the logger for this module. - */ - TreeLogger getLogger(); - } /** * Map of callbacks. @@ -57,6 +46,31 @@ */ private Type logLevel; + /** + * Show that a module is loaded in the UI. + * + * <p>Note that the {...@link CloseModuleEvent} should already have a callback + * registered when this is called if needed -- the UI is not required to + * change the UI if it is registered later. + * + * @param userAgent full user agent name + * @param remoteSocket name of remote socket endpoint in host:port format + * @param url URL of top-level window + * @param tabKey stable browser tab identifier, or the empty string if no + * such identifier is available + * @param moduleName the name of the module loaded + * @param sessionKey a unique session key + * @param agentTag short-form user agent identifier, suitable for use in + * a label for this connection + * @param agentIcon icon to use for the user agent (fits inside 24x24) or + * null if unavailable + * @param logLevel logging detail requested + * @return a handle to the module + */ + public abstract ModuleHandle getModuleLogger(String userAgent, + String remoteSocket, String url, String tabKey, String moduleName, + String sessionKey, String agentTag, byte[] agentIcon, Type logLevel); + /** * Create a top-level logger for messages which are not associated with the * web server or any module. Defaults to logging to stdout. @@ -66,7 +80,7 @@ public TreeLogger getTopLogger() { return getConsoleLogger(); } - + /** * Create the web server portion of the UI if not already created, and * return its TreeLogger instance. @@ -83,7 +97,7 @@ */ public abstract TreeLogger getWebServerLogger(String serverName, byte[] serverIcon); - + /** * Initialize the UI - must be called exactly once and before any other method * on this class. @@ -95,31 +109,6 @@ public void initialize(Type logLevel) { this.logLevel = logLevel; } - - /** - * Show that a module is loaded in the UI. - * - * <p>Note that the {...@link CloseModuleEvent} should already have a callback - * registered when this is called if needed -- the UI is not required to - * change the UI if it is registered later. - * - * @param userAgent full user agent name - * @param remoteSocket name of remote socket endpoint in host:port format - * @param url URL of top-level window - * @param tabKey stable browser tab identifier, or the empty string if no - * such identifier is available - * @param moduleName the name of the module loaded - * @param sessionKey a unique session key - * @param agentTag short-form user agent identifier, suitable for use in - * a label for this connection - * @param agentIcon icon to use for the user agent (fits inside 24x24) or - * null if unavailable - * @param logLevel logging detail requested - * @return a handle to the module - */ - public abstract ModuleHandle loadModule(String userAgent, - String remoteSocket, String url, String tabKey, String moduleName, - String sessionKey, String agentTag, byte[] agentIcon, Type logLevel); /** * Sets the callback for a given event type.. @@ -135,13 +124,15 @@ } /** - * Show that a previously loaded module has been unloaded. + * Set the URLs that should be available to start. * - * @param module ModuleHandle instance returned from loadModule on this UI - * instance + * @param urls map of URLs -- the key is the name supplied with -startupUrls, + * and the value is the mapped URL with all parameters included */ - public abstract void unloadModule(ModuleHandle module); - + public void setStartupUrls(Map<String, URL> urls) { + // do nothing by default + } + /** * Call callback for a given event. * ======================================= --- /trunk/dev/core/test/com/google/gwt/dev/shell/BrowserChannelServerTest.java Tue Oct 13 16:57:19 2009 +++ /trunk/dev/core/test/com/google/gwt/dev/shell/BrowserChannelServerTest.java Thu Nov 19 12:24:42 2009 @@ -156,9 +156,9 @@ } @Override - public TreeLogger loadModule(TreeLogger logger, BrowserChannel channel, - String moduleName, String userAgent, String url, String tabKey, - String sessionKey, byte[] userAgentIcon) { + public TreeLogger loadModule(BrowserChannel channel, String moduleName, + String userAgent, String url, String tabKey, String sessionKey, + byte[] userAgentIcon) { loadedModule = moduleName; this.moduleName = moduleName; this.userAgent = userAgent; @@ -166,7 +166,7 @@ this.tabKey = tabKey; this.sessionKey = sessionKey; this.userAgentIcon = userAgentIcon; - return logger; + return new FailErrorLogger(); } @Override -- http://groups.google.com/group/Google-Web-Toolkit-Contributors