Second round of changes to implement WAR design.
http://code.google.com/p/google-web-toolkit/wiki/WAR_Design_1_6
Review by: bobv
git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4302 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/LinkerContext.java b/dev/core/src/com/google/gwt/core/ext/LinkerContext.java
index 120de31..7f1d37f 100644
--- a/dev/core/src/com/google/gwt/core/ext/LinkerContext.java
+++ b/dev/core/src/com/google/gwt/core/ext/LinkerContext.java
@@ -40,6 +40,13 @@
String getModuleFunctionName();
/**
+ * Returns the time at which the module being compiled was last modified. Can
+ * be used to set an appropriate timestamp on artifacts which depend solely on
+ * the module definition.
+ */
+ long getModuleLastModified();
+
+ /**
* Returns the name of the module being compiled.
*/
String getModuleName();
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/AbstractLinker.java b/dev/core/src/com/google/gwt/core/ext/linker/AbstractLinker.java
index f2b3cd3..9f009e4 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/AbstractLinker.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/AbstractLinker.java
@@ -36,12 +36,29 @@
* @return an artifact that contains the given data
* @throws UnableToCompleteException
*/
+ @SuppressWarnings("unused")
protected final SyntheticArtifact emitBytes(TreeLogger logger, byte[] what,
String partialPath) throws UnableToCompleteException {
return new SyntheticArtifact(getClass(), partialPath, what);
}
/**
+ * A helper method to create an artifact from an array of bytes.
+ *
+ * @param logger a TreeLogger
+ * @param what the data to emit
+ * @param partialPath the partial path of the resource
+ * @return an artifact that contains the given data
+ * @param lastModified the last modified time of the new artifact
+ * @throws UnableToCompleteException
+ */
+ @SuppressWarnings("unused")
+ protected final SyntheticArtifact emitBytes(TreeLogger logger, byte[] what,
+ String partialPath, long lastModified) throws UnableToCompleteException {
+ return new SyntheticArtifact(getClass(), partialPath, what, lastModified);
+ }
+
+ /**
* A helper method to create an artifact to emit the contents of an
* InputStream.
*
@@ -54,7 +71,25 @@
InputStream what, String partialPath) throws UnableToCompleteException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Util.copy(logger, what, out);
- return new SyntheticArtifact(getClass(), partialPath, out.toByteArray());
+ return emitBytes(logger, out.toByteArray(), partialPath);
+ }
+
+ /**
+ * A helper method to create an artifact to emit the contents of an
+ * InputStream.
+ *
+ * @param logger a TreeLogger
+ * @param what the source InputStream
+ * @param partialPath the partial path of the emitted resource
+ * @param lastModified the last modified time of the new artifact
+ * @return an artifact that contains the contents of the InputStream
+ */
+ protected final SyntheticArtifact emitInputStream(TreeLogger logger,
+ InputStream what, String partialPath, long lastModified)
+ throws UnableToCompleteException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ Util.copy(logger, what, out);
+ return emitBytes(logger, out.toByteArray(), partialPath, lastModified);
}
/**
@@ -71,6 +106,20 @@
}
/**
+ * A helper method to create an artifact to emit a String.
+ *
+ * @param logger a TreeLogger
+ * @param what the contents of the Artifact to emit
+ * @param partialPath the partial path of the emitted resource
+ * @param lastModified the last modified time of the new artifact
+ * @return an artifact that contains the contents of the given String
+ */
+ protected final SyntheticArtifact emitString(TreeLogger logger, String what,
+ String partialPath, long lastModified) throws UnableToCompleteException {
+ return emitBytes(logger, Util.getBytes(what), partialPath, lastModified);
+ }
+
+ /**
* A helper method to create an artifact from an array of bytes with a strong
* name.
*
@@ -88,4 +137,24 @@
String strongName = prefix + Util.computeStrongName(what) + suffix;
return emitBytes(logger, what, strongName);
}
+
+ /**
+ * A helper method to create an artifact from an array of bytes with a strong
+ * name.
+ *
+ * @param logger a TreeLogger
+ * @param what the data to emit
+ * @param prefix a non-null string to prepend to the hash to determine the
+ * Artifact's partial path
+ * @param suffix a non-null string to append to the hash to determine the
+ * Artifact's partial path
+ * @param lastModified the last modified time of the new artifact
+ * @return an artifact that contains the given data
+ */
+ protected final SyntheticArtifact emitWithStrongName(TreeLogger logger,
+ byte[] what, String prefix, String suffix, long lastModified)
+ throws UnableToCompleteException {
+ String strongName = prefix + Util.computeStrongName(what) + suffix;
+ return emitBytes(logger, what, strongName, lastModified);
+ }
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/SyntheticArtifact.java b/dev/core/src/com/google/gwt/core/ext/linker/SyntheticArtifact.java
index dd9bafd..d9283d0 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/SyntheticArtifact.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/SyntheticArtifact.java
@@ -27,13 +27,19 @@
*/
public class SyntheticArtifact extends EmittedArtifact {
private final byte[] data;
- private final long lastModified = System.currentTimeMillis();
+ private final long lastModified;
SyntheticArtifact(Class<? extends Linker> linkerType, String partialPath,
byte[] data) {
+ this(linkerType, partialPath, data, System.currentTimeMillis());
+ }
+
+ SyntheticArtifact(Class<? extends Linker> linkerType, String partialPath,
+ byte[] data, long lastModified) {
super(linkerType, partialPath);
assert data != null;
this.data = data;
+ this.lastModified = lastModified;
}
@Override
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java
index 71d941b..e475f84 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/SelectionScriptLinker.java
@@ -117,10 +117,23 @@
LinkerContext context, ArtifactSet artifacts)
throws UnableToCompleteException {
String selectionScript = generateSelectionScript(logger, context, artifacts);
- byte[] selectionScriptBytes = Util.getBytes(context.optimizeJavaScript(
- logger, selectionScript));
- return emitBytes(logger, selectionScriptBytes, context.getModuleName()
- + ".nocache.js");
+ selectionScript = context.optimizeJavaScript(logger, selectionScript);
+
+ /*
+ * Last modified is important to keep hosted mode refreses from clobbering
+ * web mode compiles. We set the timestamp on the hosted mode selection
+ * script to the same mod time as the module (to allow updates). For web
+ * mode, we just set it to now.
+ */
+ long lastModified;
+ if (artifacts.find(CompilationResult.class).size() == 0) {
+ lastModified = context.getModuleLastModified();
+ } else {
+ lastModified = System.currentTimeMillis();
+ }
+
+ return emitString(logger, selectionScript, context.getModuleName()
+ + ".nocache.js", lastModified);
}
protected String generatePropertyProvider(SelectionProperty prop) {
@@ -223,9 +236,10 @@
if (startPos != -1) {
StringBuffer text = new StringBuffer();
if (compilations.size() == 0) {
- // We'll see this when running in Hosted Mode. The way the selection
- // templates are structured is such that this line won't be executed
- text.append("strongName = null;");
+ // Hosted mode link.
+ text.append("alert('This module needs to be (re)compiled, "
+ + "please run a compile or use the Compile/Browse button in hosted mode');");
+ text.append("return;");
} else if (compilations.size() == 1) {
// Just one distinct compilation; no need to evaluate properties
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java
index 04719cb..df24b42 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java
@@ -109,6 +109,7 @@
private final Map<Class<? extends Linker>, String> linkerShortNames = new HashMap<Class<? extends Linker>, String>();
private final String moduleFunctionName;
+ private final long moduleLastModified;
private final String moduleName;
private final Map<String, StandardSelectionProperty> propertiesByName = new HashMap<String, StandardSelectionProperty>();
@@ -125,6 +126,7 @@
this.jjsOptions = jjsOptions;
this.moduleFunctionName = module.getFunctionName();
this.moduleName = module.getName();
+ this.moduleLastModified = module.lastModified();
// Sort the linkers into the order they should actually run.
List<Class<? extends Linker>> sortedLinkers = new ArrayList<Class<? extends Linker>>();
@@ -295,6 +297,10 @@
return moduleFunctionName;
}
+ public long getModuleLastModified() {
+ return moduleLastModified;
+ }
+
public String getModuleName() {
return moduleName;
}
@@ -442,11 +448,11 @@
outFile = new File(outputPath, artifact.getPartialPath());
}
- // TODO(scottb): figure out how to do a clean.
- // assert !outFile.exists() : "Attempted to overwrite " +
- // outFile.getPath();
- Util.copy(artifactLogger, artifact.getContents(artifactLogger), outFile);
- outFile.setLastModified(artifact.getLastModified());
+ if (!outFile.exists()
+ || (outFile.lastModified() <= artifact.getLastModified())) {
+ Util.copy(artifactLogger, artifact.getContents(artifactLogger), outFile);
+ outFile.setLastModified(artifact.getLastModified());
+ }
}
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html b/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
index d02be07..aeec95e 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
@@ -17,7 +17,7 @@
function gwtOnLoad(errFn, modName, modBase){
$moduleName = modName;
$moduleBase = modBase;
- if (!external.gwtOnLoad(window, modName, "1.5")) {
+ if (!external.gwtOnLoad(window, modName, "1.6")) {
if (errFn) {
errFn(modName);
}
@@ -29,7 +29,7 @@
};
window.onunload = function() {
- external.gwtOnLoad(window, null, "1.5");
+ external.gwtOnLoad(window, null, "1.6");
};
window.__gwt_module_id = 0;
diff --git a/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java b/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java
index 89517d8..838093e 100644
--- a/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java
@@ -19,15 +19,18 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
+import com.google.gwt.core.ext.linker.EmittedArtifact;
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
+import com.google.gwt.core.ext.linker.impl.HostedModeLinker;
import com.google.gwt.core.ext.linker.impl.SelectionScriptLinker;
import com.google.gwt.dev.About;
import com.google.gwt.dev.util.DefaultTextOutput;
-import com.google.gwt.dev.util.Util;
-import com.google.gwt.util.tools.Utility;
import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
/**
* Implements the canonical GWT bootstrap sequence that loads the GWT module in
@@ -48,8 +51,34 @@
try {
// Add hosted mode iframe contents
// TODO move this into own impl package if HostedModeLinker goes away
- String hostedHtml = Utility.getFileFromClassPath("com/google/gwt/core/ext/linker/impl/hosted.html");
- toReturn.add(emitBytes(logger, Util.getBytes(hostedHtml), "hosted.html"));
+ URL resource = HostedModeLinker.class.getResource("hosted.html");
+ if (resource == null) {
+ logger.log(TreeLogger.ERROR,
+ "Unable to find support resource 'hosted.html'");
+ throw new UnableToCompleteException();
+ }
+
+ final URLConnection connection = resource.openConnection();
+ // TODO: extract URLArtifact class?
+ EmittedArtifact hostedHtml = new EmittedArtifact(IFrameLinker.class,
+ "hosted.html") {
+ @Override
+ public InputStream getContents(TreeLogger logger)
+ throws UnableToCompleteException {
+ try {
+ return connection.getInputStream();
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Unable to copy support resource", e);
+ throw new UnableToCompleteException();
+ }
+ }
+
+ @Override
+ public long getLastModified() {
+ return connection.getLastModified();
+ }
+ };
+ toReturn.add(hostedHtml);
} catch (IOException e) {
logger.log(TreeLogger.ERROR, "Unable to copy support resource", e);
throw new UnableToCompleteException();
diff --git a/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js b/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js
index 1f35a26..d98c012 100644
--- a/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js
+++ b/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js
@@ -65,14 +65,16 @@
// --------------- INTERNAL FUNCTIONS ---------------
function isHostedMode() {
+ var result = false;
try {
- return ($wnd.external && $wnd.external.gwtOnLoad &&
+ result = ($wnd.external && $wnd.external.gwtOnLoad &&
($wnd.location.search.indexOf('gwt.hybrid') == -1));
} catch (e) {
// Defensive: some versions of IE7 reportedly can throw an exception
// evaluating "external.gwtOnLoad".
- return false;
}
+ isHostedMode = function() { return result; };
+ return result;
}
// Called by onScriptLoad(), onInjectionDone(), and onload(). It causes
@@ -338,6 +340,17 @@
// do it early for compile/browse rebasing
computeScriptBase();
+
+ var strongName;
+ if (isHostedMode()) {
+ if ($wnd.external.initModule && $wnd.external.initModule('__MODULE_NAME__')) {
+ // Refresh the page to update this selection script!
+ $wnd.location.reload();
+ return;
+ }
+ strongName = "hosted.html?__MODULE_FUNC__";
+ }
+
processMetas();
// --------------- WINDOW ONLOAD HOOK ---------------
@@ -350,10 +363,7 @@
type: 'selectingPermutation'
});
- var strongName;
- if (isHostedMode()) {
- strongName = "hosted.html?__MODULE_FUNC__";
- } else {
+ if (!strongName) {
try {
// __PERMUTATIONS_BEGIN__
// Permutation logic
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index 93d16ab..b6e2646 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -33,7 +33,10 @@
/**
* The main executable entry point for the GWT Java to JavaScript compiler.
+ *
+ * @deprecated use {@link Compiler} instead
*/
+@Deprecated
public class GWTCompiler {
static final class ArgProcessor extends Precompile.ArgProcessor {
@@ -91,6 +94,9 @@
}
public static void main(String[] args) {
+ System.err.println("WARNING: '" + GWTCompiler.class.getName()
+ + "' is deprecated and will be removed in a future release.");
+ System.err.println("Use '" + Compiler.class.getName() + "' instead.");
/*
* NOTE: main always exits with a call to System.exit to terminate any
* non-daemon threads that were started in Generators. Typically, this is to
@@ -119,7 +125,23 @@
this.options = new GWTCompilerOptionsImpl(options);
}
+ /**
+ * Compiles the set of modules specified in the options.
+ */
public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ ModuleDef[] modules = new ModuleDef[options.getModuleNames().size()];
+ int i = 0;
+ for (String moduleName : options.getModuleNames()) {
+ modules[i++] = ModuleDefLoader.loadFromClassPath(logger, moduleName);
+ }
+ return run(logger, modules);
+ }
+
+ /**
+ * Compiles a specific set of modules.
+ */
+ public boolean run(TreeLogger logger, ModuleDef... modules)
+ throws UnableToCompleteException {
PerfLogger.start("compile");
boolean tempWorkDir = false;
try {
@@ -128,8 +150,8 @@
tempWorkDir = true;
}
- for (String moduleName : options.getModuleNames()) {
- ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, moduleName);
+ for (ModuleDef module : modules) {
+ String moduleName = module.getName();
File compilerWorkDir = options.getCompilerWorkDir(moduleName);
if (options.isValidateOnly()) {
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index a83f85d..63c70b2 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -32,7 +32,10 @@
/**
* The main executable class for the hosted mode shell.
+ *
+ * @deprecated use {@link HostedMode} instead
*/
+@Deprecated
public class GWTShell extends HostedModeBase {
/**
@@ -103,6 +106,9 @@
}
public static void main(String[] args) {
+ System.err.println("WARNING: '" + GWTShell.class.getName()
+ + "' is deprecated and will be removed in a future release.");
+ System.err.println("Use '" + HostedMode.class.getName() + "' instead.");
/*
* NOTE: main always exits with a call to System.exit to terminate any
* non-daemon threads that were started in Generators. Typically, this is to
@@ -134,16 +140,21 @@
this.options.copyFrom(options);
}
+ @Override
+ protected void compile(TreeLogger logger) throws UnableToCompleteException {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Compiles a logical module def. The caller can modify the specified module
* def programmatically in some cases (this is needed for JUnit support, for
* example).
*/
+ @Override
protected void compile(TreeLogger logger, ModuleDef moduleDef)
throws UnableToCompleteException {
LegacyCompilerOptions newOptions = new GWTCompilerOptionsImpl(options);
- newOptions.addModuleName(moduleDef.getName());
- new GWTCompiler(newOptions).run(logger);
+ new GWTCompiler(newOptions).run(logger, moduleDef);
}
@Override
@@ -172,6 +183,17 @@
}
@Override
+ 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;
+ }
+
+ @Override
protected void shutDownServer() {
// Stop the HTTP server.
//
diff --git a/dev/core/src/com/google/gwt/dev/HostedMode.java b/dev/core/src/com/google/gwt/dev/HostedMode.java
index f19bf27..351e10b 100644
--- a/dev/core/src/com/google/gwt/dev/HostedMode.java
+++ b/dev/core/src/com/google/gwt/dev/HostedMode.java
@@ -18,11 +18,9 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
-import com.google.gwt.core.ext.linker.EmittedArtifact;
import com.google.gwt.core.ext.linker.impl.StandardLinkerContext;
import com.google.gwt.dev.Compiler.CompilerOptionsImpl;
import com.google.gwt.dev.cfg.ModuleDef;
-import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.shell.ArtifactAcceptor;
import com.google.gwt.dev.shell.ServletContainer;
import com.google.gwt.dev.shell.ServletContainerLauncher;
@@ -40,7 +38,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.net.BindException;
-import java.util.IdentityHashMap;
+import java.util.HashMap;
import java.util.Map;
/**
@@ -109,18 +107,13 @@
registerHandler(new ArgHandlerStartupURLs());
registerHandler(new ArgHandlerWarDir(options));
registerHandler(new ArgHandlerExtraDir(options));
- registerHandler(new ArgHandlerWorkDirOptional(options) {
- @Override
- public String[] getDefaultArgs() {
- return new String[] {"-workDir", "work"};
- }
- });
+ registerHandler(new ArgHandlerWorkDirOptional(options));
registerHandler(new ArgHandlerModuleName(options));
}
@Override
protected String getName() {
- return GWTShell.class.getName();
+ return HostedMode.class.getName();
}
}
@@ -141,8 +134,9 @@
* shutdown AWT related threads, since the contract for their termination is
* still implementation-dependent.
*/
- HostedMode shellMain = new HostedMode();
- if (shellMain.new ArgProcessor().processArgs(args)) {
+ HostedMode hostedMode = new HostedMode();
+ if (hostedMode.new ArgProcessor().processArgs(args)) {
+ hostedMode.run();
// Exit w/ success code.
System.exit(0);
}
@@ -165,7 +159,16 @@
*/
private ServletContainerLauncher launcher = new JettyLauncher();
- private final Map<ModuleDef, StandardLinkerContext> linkerMap = new IdentityHashMap<ModuleDef, StandardLinkerContext>();
+ /**
+ * Maps each active linker stack by module.
+ */
+ private final Map<String, StandardLinkerContext> linkerStacks = new HashMap<String, StandardLinkerContext>();
+
+ /**
+ * The set of specified modules by name; the keys represent the renamed name
+ * of each module rather than the canonical name.
+ */
+ private Map<String, ModuleDef> modulesByName = new HashMap<String, ModuleDef>();
/**
* The server that was started.
@@ -203,11 +206,15 @@
return false;
}
+ @Override
+ protected void compile(TreeLogger logger) throws UnableToCompleteException {
+ CompilerOptions newOptions = new CompilerOptionsImpl(options);
+ new Compiler(newOptions).run(logger);
+ }
+
protected void compile(TreeLogger logger, ModuleDef moduleDef)
throws UnableToCompleteException {
- CompilerOptions newOptions = new CompilerOptionsImpl(options);
- newOptions.addModuleName(moduleDef.getName());
- new Compiler(newOptions).run(logger);
+ throw new UnsupportedOperationException();
}
@Override
@@ -217,21 +224,51 @@
@Override
protected ArtifactAcceptor doCreateArtifactAcceptor(final ModuleDef module) {
- final File moduleOutDir = new File(options.getWarDir(), module.getName());
return new ArtifactAcceptor() {
public void accept(TreeLogger logger, ArtifactSet newlyGeneratedArtifacts)
throws UnableToCompleteException {
- StandardLinkerContext linkerStack = linkerMap.get(module);
- ArtifactSet artifacts = linkerStack.invokeRelink(logger,
- newlyGeneratedArtifacts);
- // TODO: extras
- linkerStack.produceOutputDirectory(logger, artifacts, moduleOutDir,
- null);
+ relink(logger, module, newlyGeneratedArtifacts);
}
};
}
@Override
+ protected boolean initModule(String moduleName) {
+ ModuleDef module = modulesByName.get(moduleName);
+ if (module == null) {
+ getTopLogger().log(
+ TreeLogger.WARN,
+ "Unknown module requested '"
+ + moduleName
+ + "'; all active GWT modules must be specified in the command line arguments");
+ return false;
+ }
+ try {
+ boolean shouldRefreshPage = false;
+ if (module.isGwtXmlFileStale()) {
+ shouldRefreshPage = true;
+ module = loadModule(getTopLogger(), module.getCanonicalName(), false);
+ }
+ link(getTopLogger(), module, true);
+ return shouldRefreshPage;
+ } catch (UnableToCompleteException e) {
+ // Already logged.
+ return false;
+ }
+ }
+
+ /*
+ * Overridden to keep our map up to date.
+ */
+ @Override
+ protected ModuleDef loadModule(TreeLogger logger, String moduleName,
+ boolean refresh) throws UnableToCompleteException {
+ ModuleDef module = super.loadModule(logger, moduleName, refresh);
+ modulesByName.put(module.getName(), module);
+ return module;
+ }
+
+ @Override
protected void shutDownServer() {
if (server != null) {
try {
@@ -261,40 +298,20 @@
}
for (String moduleName : options.getModuleNames()) {
- TreeLogger linkLogger = getTopLogger().branch(TreeLogger.DEBUG,
- "Prelinking module " + moduleName);
+ TreeLogger loadLogger = getTopLogger().branch(TreeLogger.DEBUG,
+ "Loading module " + moduleName);
try {
- ModuleDef module = ModuleDefLoader.loadFromClassPath(linkLogger,
- moduleName);
+ ModuleDef module = loadModule(loadLogger, moduleName, false);
// TODO: Validate servlet tags.
String[] servletPaths = module.getServletPaths();
if (servletPaths.length > 0) {
- linkLogger.log(TreeLogger.WARN,
+ loadLogger.log(TreeLogger.WARN,
"Ignoring legacy <servlet> tag(s) in module '" + moduleName
+ "'; add servlet tags to your web.xml instead");
}
- File moduleOutDir = new File(options.getWarDir(), moduleName);
- StandardLinkerContext linkerStack = new StandardLinkerContext(
- linkLogger, module, options);
- linkerMap.put(module, linkerStack);
-
- // TODO: remove all public files initially, only conditionally emit.
- ArtifactSet artifacts = linkerStack.invokeLink(linkLogger);
- for (EmittedArtifact artifact : artifacts.find(EmittedArtifact.class)) {
- TreeLogger artifactLogger = linkLogger.branch(TreeLogger.DEBUG,
- "Emitting resource " + artifact.getPartialPath(), null);
-
- if (!artifact.isPrivate()) {
- File outFile = new File(moduleOutDir, artifact.getPartialPath());
- // if (!outFile.exists()) {
- Util.copy(artifactLogger, artifact.getContents(artifactLogger),
- outFile);
- outFile.setLastModified(artifact.getLastModified());
- // }
- }
- }
+ link(loadLogger, module, false);
} catch (UnableToCompleteException e) {
// Already logged.
return -1;
@@ -317,4 +334,61 @@
}
return -1;
}
+
+ /**
+ * Perform an initial hosted mode link, without overwriting newer or
+ * unmodified files in the output folder.
+ *
+ * @param logger the logger to use
+ * @param module the module to link
+ * @param includePublicFiles if <code>true</code>, include public files in
+ * the link, otherwise do not include them
+ * @throws UnableToCompleteException
+ */
+ private void link(TreeLogger logger, ModuleDef module,
+ boolean includePublicFiles) throws UnableToCompleteException {
+ // TODO: move the module-specific computations to a helper function.
+ File moduleOutDir = new File(options.getWarDir(), module.getName());
+ File moduleExtraDir = (options.getExtraDir() == null) ? null : new File(
+ options.getExtraDir(), module.getName());
+
+ // Create a new active linker stack for the fresh link.
+ StandardLinkerContext linkerStack = new StandardLinkerContext(logger,
+ module, options);
+ linkerStacks.put(module.getName(), linkerStack);
+
+ if (!includePublicFiles) {
+ linkerStack.getArtifacts().clear();
+ }
+
+ ArtifactSet artifacts = linkerStack.invokeLink(logger);
+ linkerStack.produceOutputDirectory(logger, artifacts, moduleOutDir,
+ moduleExtraDir);
+ }
+
+ /**
+ * Perform hosted mode relink when new artifacts are generated, without
+ * overwriting newer or unmodified files in the output folder.
+ *
+ * @param logger the logger to use
+ * @param module the module to link
+ * @param newlyGeneratedArtifacts the set of new artifacts
+ * @throws UnableToCompleteException
+ */
+ private void relink(TreeLogger logger, ModuleDef module,
+ ArtifactSet newlyGeneratedArtifacts) throws UnableToCompleteException {
+ // TODO: move the module-specific computations to a helper function.
+ File moduleOutDir = new File(options.getWarDir(), module.getName());
+ File moduleExtraDir = (options.getExtraDir() == null) ? null : new File(
+ options.getExtraDir(), module.getName());
+
+ // Find the existing linker stack.
+ StandardLinkerContext linkerStack = linkerStacks.get(module.getName());
+ assert linkerStack != null;
+
+ ArtifactSet artifacts = linkerStack.invokeRelink(logger,
+ newlyGeneratedArtifacts);
+ linkerStack.produceOutputDirectory(logger, artifacts, moduleOutDir,
+ moduleExtraDir);
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/HostedModeBase.java b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
index f351ff8..1c5f4d4 100644
--- a/dev/core/src/com/google/gwt/dev/HostedModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
@@ -226,18 +226,22 @@
}
private class BrowserWidgetHostImpl implements BrowserWidgetHost {
- public BrowserWidgetHostImpl() {
- }
- public void compile(ModuleDef moduleDef) throws UnableToCompleteException {
- HostedModeBase.this.compile(getLogger(), moduleDef);
+ public void compile() throws UnableToCompleteException {
+ if (isLegacyMode()) {
+ throw new UnsupportedOperationException();
+ }
+ HostedModeBase.this.compile(getLogger());
}
public void compile(String[] moduleNames) throws UnableToCompleteException {
+ if (!isLegacyMode()) {
+ throw new UnsupportedOperationException();
+ }
for (int i = 0; i < moduleNames.length; i++) {
String moduleName = moduleNames[i];
- ModuleDef moduleDef = loadModule(moduleName, getLogger());
- compile(moduleDef);
+ ModuleDef moduleDef = loadModule(getLogger(), moduleName, true);
+ HostedModeBase.this.compile(getLogger(), moduleDef);
}
}
@@ -254,7 +258,7 @@
// Try to find an existing loaded version of the module def.
//
- ModuleDef moduleDef = loadModule(moduleName, logger);
+ ModuleDef moduleDef = loadModule(logger, moduleName, true);
assert (moduleDef != null);
TypeOracle typeOracle = moduleDef.getTypeOracle(logger);
@@ -271,6 +275,14 @@
return getTopLogger();
}
+ public boolean initModule(String moduleName) {
+ return HostedModeBase.this.initModule(moduleName);
+ }
+
+ public boolean isLegacyMode() {
+ return HostedModeBase.this instanceof GWTShell;
+ }
+
public String normalizeURL(String whatTheUserTyped) {
return HostedModeBase.this.normalizeURL(whatTheUserTyped);
}
@@ -279,24 +291,6 @@
throws UnableToCompleteException {
return HostedModeBase.this.openNewBrowserWindow();
}
-
- /**
- * Load a module.
- *
- * @param moduleName name of the module to load
- * @param logger TreeLogger to use
- * @return the loaded module
- * @throws UnableToCompleteException
- */
- private ModuleDef loadModule(String moduleName, TreeLogger logger)
- throws UnableToCompleteException {
- boolean assumeFresh = !alreadySeenModules.contains(moduleName);
- ModuleDef moduleDef = ModuleDefLoader.loadFromClassPath(logger,
- moduleName, !assumeFresh);
- alreadySeenModules.add(moduleName);
- assert (moduleDef != null) : "Required module state is absent";
- return moduleDef;
- }
}
static {
@@ -485,11 +479,18 @@
}
/**
- * Compiles a module.
+ * Compiles a module (legacy only).
*/
+ @Deprecated
protected abstract void compile(TreeLogger logger, ModuleDef moduleDef)
throws UnableToCompleteException;
+ /**
+ * Compiles all modules.
+ */
+ protected abstract void compile(TreeLogger logger)
+ throws UnableToCompleteException;
+
protected abstract HostedModeBaseOptions createOptions();
protected abstract ArtifactAcceptor doCreateArtifactAcceptor(ModuleDef module);
@@ -546,6 +547,18 @@
}
/**
+ * Called from a selection script as it begins to load in hosted mode. This
+ * triggers a hosted mode link, which might actually update the running
+ * selection script.
+ *
+ * @param moduleName the module to link
+ * @return <code>true</code> if the selection script was overwritten; this
+ * will trigger a full-page refresh by the calling (out of date)
+ * selection script
+ */
+ protected abstract boolean initModule(String moduleName);
+
+ /**
* By default we will open the application window.
*
* @return true if we are running in headless mode
@@ -554,6 +567,25 @@
return headlessMode;
}
+ /**
+ * Load a module.
+ *
+ * @param moduleName name of the module to load
+ * @param logger TreeLogger to use
+ * @param refresh if <code>true</code>, refresh the module from disk
+ * @return the loaded module
+ * @throws UnableToCompleteException
+ */
+ protected ModuleDef loadModule(TreeLogger logger, String moduleName,
+ boolean refresh) throws UnableToCompleteException {
+ refresh &= alreadySeenModules.contains(moduleName);
+ ModuleDef moduleDef = ModuleDefLoader.loadFromClassPath(logger, moduleName,
+ refresh);
+ alreadySeenModules.add(moduleName);
+ assert (moduleDef != null) : "Required module state is absent";
+ return moduleDef;
+ }
+
protected boolean notDone() {
if (!mainWnd.isDisposed()) {
return true;
diff --git a/dev/core/src/com/google/gwt/dev/Link.java b/dev/core/src/com/google/gwt/dev/Link.java
index a255423..1436f7f 100644
--- a/dev/core/src/com/google/gwt/dev/Link.java
+++ b/dev/core/src/com/google/gwt/dev/Link.java
@@ -189,6 +189,7 @@
private static void doProduceOutput(TreeLogger logger, ArtifactSet artifacts,
StandardLinkerContext linkerContext, ModuleDef module, File outDir,
File extraDir) throws UnableToCompleteException {
+ // TODO: move the module-specific computations to a helper function.
File moduleOutDir = new File(outDir, module.getName());
File moduleExtraDir = (extraDir == null) ? null : new File(extraDir,
module.getName());
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
index 8f66eaf..7c9fb94 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -351,14 +351,18 @@
}
public boolean isGwtXmlFileStale() {
+ return lastModified() > moduleDefCreationTime;
+ }
+
+ public long lastModified() {
+ long lastModified = moduleDefCreationTime;
for (Iterator<File> iter = gwtXmlFiles.iterator(); iter.hasNext();) {
File xmlFile = iter.next();
- if ((!xmlFile.exists())
- || (xmlFile.lastModified() > moduleDefCreationTime)) {
- return true;
+ if (xmlFile.exists()) {
+ lastModified = Math.min(lastModified, xmlFile.lastModified());
}
}
- return false;
+ return lastModified;
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserWidget.java b/dev/core/src/com/google/gwt/dev/shell/BrowserWidget.java
index 7d4b788..8ac02f1 100644
--- a/dev/core/src/com/google/gwt/dev/shell/BrowserWidget.java
+++ b/dev/core/src/com/google/gwt/dev/shell/BrowserWidget.java
@@ -93,7 +93,18 @@
openWebModeButton = newItem("new-web-mode-window.gif", "&Compile/Browse",
"Compiles and opens the current URL in the system browser");
openWebModeButton.addSelectionListener(this);
- openWebModeButton.setEnabled(false);
+ updateWebMode();
+ }
+
+ @Deprecated
+ public void updateWebMode() {
+ if (!openWebModeButton.isDisposed()) {
+ if (getHost().isLegacyMode()) {
+ openWebModeButton.setEnabled(!loadedModules.isEmpty());
+ } else {
+ openWebModeButton.setEnabled(true);
+ }
+ }
}
public void widgetDefaultSelected(SelectionEvent e) {
@@ -114,22 +125,26 @@
browser.stop();
} else if (evt.widget == openWebModeButton) {
// first, compile
- Set<String> keySet = new HashSet<String>();
- for (Map.Entry<?, ModuleSpace> entry : loadedModules.entrySet()) {
- ModuleSpace module = entry.getValue();
- keySet.add(module.getModuleName());
- }
- String[] moduleNames = Util.toStringArray(keySet);
- if (moduleNames.length == 0) {
- // A latent problem with a module.
- //
- openWebModeButton.setEnabled(false);
- return;
- }
try {
Cursor waitCursor = getDisplay().getSystemCursor(SWT.CURSOR_WAIT);
getShell().setCursor(waitCursor);
- getHost().compile(moduleNames);
+ if (getHost().isLegacyMode()) {
+ Set<String> keySet = new HashSet<String>();
+ for (Map.Entry<?, ModuleSpace> entry : loadedModules.entrySet()) {
+ ModuleSpace module = entry.getValue();
+ keySet.add(module.getModuleName());
+ }
+ String[] moduleNames = Util.toStringArray(keySet);
+ if (moduleNames.length == 0) {
+ // A latent problem with a module.
+ //
+ openWebModeButton.setEnabled(false);
+ return;
+ }
+ getHost().compile(moduleNames);
+ } else {
+ getHost().compile();
+ }
} catch (UnableToCompleteException e) {
// Already logged by callee.
//
@@ -154,9 +169,10 @@
}
/**
- * The version number that should be passed into gwtOnLoad.
+ * The version number that should be passed into gwtOnLoad. Must match the
+ * version in hosted.html.
*/
- private static final String EXPECTED_GWT_ONLOAD_VERSION = "1.5";
+ private static final String EXPECTED_GWT_ONLOAD_VERSION = "1.6";
public static void launchExternalBrowser(TreeLogger logger, String location) {
// check GWT_EXTERNAL_BROWSER first, it overrides everything else
@@ -330,7 +346,7 @@
// Enable the compile button since we successfully loaded.
//
- toolbar.openWebModeButton.setEnabled(true);
+ toolbar.updateWebMode();
}
/**
@@ -356,27 +372,19 @@
loadedModules.remove(key);
}
}
- if (loadedModules.isEmpty()) {
- if (!toolbar.openWebModeButton.isDisposed()) {
- // Disable the compile button.
- //
- toolbar.openWebModeButton.setEnabled(false);
- }
- }
+ toolbar.updateWebMode();
}
/**
- * Report that gwtOnLoad was called with the wrong number of
+ * Report that an external method was called with the wrong number of
* arguments.
- *
- * @param numArgs number of arguments supplied
*/
- protected void reportIncorrectGwtOnLoadInvocation(int numArgs) {
+ protected void reportIncorrectInvocation(String name, int expectedArgs,
+ int actualArgs) {
getHost().getLogger().log(
TreeLogger.ERROR,
- "Not enough arguments ("
- + numArgs
- + ") passed to external.gwtOnLoad(), expected (3); "
+ "Not enough arguments (" + actualArgs + ") passed to external." + name
+ + "(), expected (" + expectedArgs + "); "
+ "your hosted mode bootstrap file may be out of date; "
+ "if you are using -noserver try recompiling and redeploying "
+ "your app");
@@ -398,8 +406,8 @@
/**
* Validate that the supplied hosted.html version matches.
*
- * This is to detect cases where users upgrade to a new version
- * but forget to update the generated hosted.html file.
+ * This is to detect cases where users upgrade to a new version but forget to
+ * update the generated hosted.html file.
*
* @param version version supplied by hosted.html file
* @return true if the version is valid, false otherwise
@@ -408,8 +416,7 @@
if (!EXPECTED_GWT_ONLOAD_VERSION.equals(version)) {
getHost().getLogger().log(
TreeLogger.ERROR,
- "Invalid version number \""
- + version
+ "Invalid version number \"" + version
+ "\" passed to external.gwtOnLoad(), expected \""
+ EXPECTED_GWT_ONLOAD_VERSION
+ "\"; your hosted mode bootstrap file may be out of date; "
diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java b/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java
index 8c557e0..74c2175 100644
--- a/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java
+++ b/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java
@@ -17,16 +17,29 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.cfg.ModuleDef;
/**
* Interface that unifies access to the <code>BrowserWidget</code>,
* <code>ModuleSpaceHost</code>, and the compiler.
*/
public interface BrowserWidgetHost {
- void compile(String[] modules) throws UnableToCompleteException;
+ /**
+ * Perform a web-mode compile on the user-specified set of modules. Used in
+ * non-legacy mode.
+ *
+ * @throws UnableToCompleteException
+ */
+ void compile() throws UnableToCompleteException;
- void compile(ModuleDef module) throws UnableToCompleteException;
+ /**
+ * Compile the specified set of modules, used in legacy mode.
+ *
+ * @param modules the names of the modules to compile
+ * @throws UnableToCompleteException
+ * @deprecated will be removed when legacy shell mode is removed
+ */
+ @Deprecated
+ void compile(String[] modules) throws UnableToCompleteException;
// Factor this out if BrowserWidget becomes decoupled from hosted mode
ModuleSpaceHost createModuleSpaceHost(BrowserWidget widget, String moduleName)
@@ -34,6 +47,26 @@
TreeLogger getLogger();
+ /**
+ * Called from a selection script as it begins to load in hosted mode. This
+ * triggers a hosted mode link, which might actually update the running
+ * selection script.
+ *
+ * @param moduleName the module to link
+ * @return <code>true</code> if the selection script was overwritten; this
+ * will trigger a full-page refresh by the calling (out of date)
+ * selection script
+ */
+ boolean initModule(String moduleName);
+
+ /**
+ * Returns <code>true</code> if running in legacy mode.
+ *
+ * @deprecated will be removed when legacy shell mode is removed
+ */
+ @Deprecated
+ boolean isLegacyMode();
+
String normalizeURL(String whatTheUserTyped);
BrowserWidget openNewBrowserWindow() throws UnableToCompleteException;
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/BrowserWidgetMoz.java b/dev/linux/src/com/google/gwt/dev/shell/moz/BrowserWidgetMoz.java
index f0cbe8c..e1f8aef 100644
--- a/dev/linux/src/com/google/gwt/dev/shell/moz/BrowserWidgetMoz.java
+++ b/dev/linux/src/com/google/gwt/dev/shell/moz/BrowserWidgetMoz.java
@@ -70,6 +70,17 @@
}
/**
+ * Causes a link to occur for the specified module.
+ *
+ * @param moduleName the module name to link
+ * @return <code>true</code> if this module is stale and should be
+ * reloaded
+ */
+ public boolean initModule(String moduleName) {
+ return getHost().initModule(moduleName);
+ }
+
+ /**
* Unload one or more modules.
*
* @param scriptObject window to unload, 0 if all
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java b/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java
index 1606f78..2b89c2e 100644
--- a/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java
+++ b/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java
@@ -75,6 +75,8 @@
* Safari.
*/
interface ExternalObject {
+ boolean initModule(String moduleName);
+
boolean gwtOnLoad(int scriptGlobalObject, String moduleName, String version);
}
diff --git a/dev/mac/src/com/google/gwt/dev/shell/mac/BrowserWidgetSaf.java b/dev/mac/src/com/google/gwt/dev/shell/mac/BrowserWidgetSaf.java
index 439cae7..3d0fe1a 100644
--- a/dev/mac/src/com/google/gwt/dev/shell/mac/BrowserWidgetSaf.java
+++ b/dev/mac/src/com/google/gwt/dev/shell/mac/BrowserWidgetSaf.java
@@ -39,6 +39,9 @@
if ("gwtonload".equalsIgnoreCase(name)) {
return LowLevelSaf.wrapDispatchMethod(jsContext, "gwtOnload",
new GwtOnLoad());
+ } else if ("initmodule".equalsIgnoreCase(name)) {
+ return LowLevelSaf.wrapDispatchMethod(jsContext, "initModule",
+ new InitModule());
}
// Native code eats the same ref it gave us.
return LowLevelSaf.getJsUndefined(jsContext);
@@ -88,6 +91,17 @@
}
}
+ /**
+ * Causes a link to occur for the specified module.
+ *
+ * @param moduleName the module name to link
+ * @return <code>true</code> if this module is stale and should be
+ * reloaded
+ */
+ public boolean initModule(String moduleName) {
+ return getHost().initModule(moduleName);
+ }
+
public void setField(int jsContext, String name, int value) {
try {
// TODO (knorton): This should produce an error. The SetProperty
@@ -127,8 +141,8 @@
return jsFalse;
}
- if (jsargs.length < 2) {
- reportIncorrectGwtOnLoadInvocation(jsargs.length);
+ if (jsargs.length < 3) {
+ reportIncorrectInvocation("gwtOnLoad", 3, jsargs.length);
return jsFalse;
}
@@ -141,16 +155,10 @@
}
String moduleName = LowLevelSaf.toString(jsContext, jsargs[1]);
- /*
- * gwtOnLoad may or may not be called with a third argument indicating
- * which version of GWT the JavaScript bootstrap sequence assumes that
- * its talking to.
- */
- String version = null;
- if (jsargs.length == 3 && !LowLevelSaf.isJsNull(jsContext, jsargs[2])
- && LowLevelSaf.isJsString(jsContext, jsargs[2])) {
- version = LowLevelSaf.toString(jsContext, jsargs[2]);
+ if (!LowLevelSaf.isJsString(jsContext, jsargs[2])) {
+ return jsFalse;
}
+ String version = LowLevelSaf.toString(jsContext, jsargs[2]);
boolean result = ((ExternalObject) thisObj).gwtOnLoad(jsargs[0],
moduleName, version);
@@ -168,6 +176,46 @@
}
}
+ private final class InitModule implements DispatchMethod {
+
+ public int invoke(int jsContext, int jsthis, int[] jsargs, int[] exception) {
+ int jsFalse = LowLevelSaf.toJsBoolean(jsContext, false);
+ LowLevelSaf.pushJsContext(jsContext);
+ try {
+ if (!LowLevelSaf.isDispatchObject(jsContext, jsthis)) {
+ return jsFalse;
+ }
+
+ Object thisObj = LowLevelSaf.unwrapDispatchObject(jsContext, jsthis);
+ if (!(thisObj instanceof ExternalObject)) {
+ return jsFalse;
+ }
+
+ if (jsargs.length < 1) {
+ reportIncorrectInvocation("initModule", 1, jsargs.length);
+ return jsFalse;
+ }
+
+ if (!LowLevelSaf.isJsString(jsContext, jsargs[0])) {
+ return jsFalse;
+ }
+ String moduleName = LowLevelSaf.toString(jsContext, jsargs[0]);
+
+ boolean result = ((ExternalObject) thisObj).initModule(moduleName);
+ // Native code eats the same ref it gave us.
+ return LowLevelSaf.toJsBoolean(jsContext, result);
+ } catch (Throwable e) {
+ return jsFalse;
+ } finally {
+ for (int jsarg : jsargs) {
+ LowLevelSaf.gcUnprotect(jsContext, jsarg);
+ }
+ LowLevelSaf.gcUnprotect(jsContext, jsthis);
+ LowLevelSaf.popJsContext(jsContext);
+ }
+ }
+ }
+
private static final int REDRAW_PERIOD = 250;
static {
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/BrowserWidgetIE6.java b/dev/windows/src/com/google/gwt/dev/shell/ie/BrowserWidgetIE6.java
index 2303df1..6e3aa62 100644
--- a/dev/windows/src/com/google/gwt/dev/shell/ie/BrowserWidgetIE6.java
+++ b/dev/windows/src/com/google/gwt/dev/shell/ie/BrowserWidgetIE6.java
@@ -86,6 +86,17 @@
}
}
+ /**
+ * Causes a link to occur for the specified module.
+ *
+ * @param moduleName the module name to link
+ * @return <code>true</code> if this module is stale and should be
+ * reloaded
+ */
+ public boolean initModule(String moduleName) {
+ return getHost().initModule(moduleName);
+ }
+
@Override
protected void getIDsOfNames(String[] names, int[] ids)
throws HResultException {
@@ -98,6 +109,9 @@
if (name.equals("gwtonload")) {
ids[0] = 1;
return;
+ } else if (name.equals("initmodule")) {
+ ids[0] = 2;
+ return;
}
throw new HResultException(DISP_E_UNKNOWNNAME);
@@ -126,15 +140,15 @@
} else if (dispId == 1) {
if ((flags & COM.DISPATCH_METHOD) != 0) {
try {
- if (params.length < 2) {
- reportIncorrectGwtOnLoadInvocation(params.length);
+ if (params.length < 3) {
+ reportIncorrectInvocation("gwtOnLoad", 3, params.length);
throw new HResultException(COM.E_INVALIDARG);
}
IDispatch frameWnd = (params[0].getType() == COM.VT_DISPATCH)
? params[0].getDispatch() : null;
String moduleName = (params[1].getType() == COM.VT_BSTR)
? params[1].getString() : null;
- String version = (params.length > 2 && params[2].getType() == COM.VT_BSTR)
+ String version = (params[2].getType() == COM.VT_BSTR)
? params[2].getString() : null;
boolean success = gwtOnLoad(frameWnd, moduleName, version);
@@ -159,6 +173,38 @@
}
}
throw new HResultException(COM.E_NOTSUPPORTED);
+ } else if (dispId == 2) {
+ if ((flags & COM.DISPATCH_METHOD) != 0) {
+ try {
+ if (params.length < 1) {
+ reportIncorrectInvocation("initModule", 1, params.length);
+ throw new HResultException(COM.E_INVALIDARG);
+ }
+ String moduleName = (params[0].getType() == COM.VT_BSTR)
+ ? params[0].getString() : null;
+ boolean reload = initModule(moduleName);
+
+ // boolean return type
+ return new Variant(reload);
+ } catch (SWTException e) {
+ throw new HResultException(COM.E_INVALIDARG);
+ }
+ } else if ((flags & COM.DISPATCH_PROPERTYGET) != 0) {
+ // property get on the method itself
+ try {
+ Method gwtOnLoadMethod = getClass().getMethod("initModule",
+ new Class[] {String.class});
+ MethodAdaptor methodAdaptor = new MethodAdaptor(gwtOnLoadMethod);
+ IDispatchImpl funcObj = new MethodDispatch(null, methodAdaptor);
+ IDispatch disp = new IDispatch(funcObj.getAddress());
+ disp.AddRef();
+ return new Variant(disp);
+ } catch (Exception e) {
+ // just return VT_EMPTY
+ return new Variant();
+ }
+ }
+ throw new HResultException(COM.E_NOTSUPPORTED);
}
// The specified member id is out of range.
diff --git a/samples/dynatable2/src.war/WEB-INF/web.xml b/samples/dynatable2/src.war/WEB-INF/web.xml
index 01c3949..1feeb14 100644
--- a/samples/dynatable2/src.war/WEB-INF/web.xml
+++ b/samples/dynatable2/src.war/WEB-INF/web.xml
@@ -9,7 +9,7 @@
</servlet>
<servlet-mapping>
<servlet-name>calendar</servlet-name>
- <url-pattern>/com.google.gwt.sample.dynatable2.DynaTable2/calendar</url-pattern>
+ <url-pattern>/dynatable2/calendar</url-pattern>
</servlet-mapping>
</web-app>
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index a5141a3..5d68977 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -28,7 +28,6 @@
import com.google.gwt.dev.cfg.Properties;
import com.google.gwt.dev.cfg.Property;
import com.google.gwt.dev.javac.CompilationUnit;
-import com.google.gwt.dev.shell.BrowserWidgetHost;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import com.google.gwt.junit.client.TimeoutException;
import com.google.gwt.junit.client.impl.GWTRunner;
@@ -590,9 +589,7 @@
((BindingProperty) userAgent).setAllowedValues(userAgentString);
}
}
- BrowserWidgetHost browserHost = getBrowserHost();
- assert (browserHost != null);
- browserHost.compile(module);
+ super.compile(getTopLogger(), module);
}
/**