First 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@4262 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/CompilePerms.java b/dev/core/src/com/google/gwt/dev/CompilePerms.java
index 94ef4c4..810a9b9 100644
--- a/dev/core/src/com/google/gwt/dev/CompilePerms.java
+++ b/dev/core/src/com/google/gwt/dev/CompilePerms.java
@@ -193,15 +193,14 @@
/**
* Compile multiple permutations.
*/
- public static boolean compile(TreeLogger logger,
- Precompilation precompilation, Permutation[] perms, int localWorkers,
- File[] resultFiles) throws UnableToCompleteException {
+ public static void compile(TreeLogger logger, Precompilation precompilation,
+ Permutation[] perms, int localWorkers, File[] resultFiles)
+ throws UnableToCompleteException {
final TreeLogger branch = logger.branch(TreeLogger.INFO, "Compiling "
+ perms.length + " permutations");
PermutationWorkerFactory.compilePermutations(logger, precompilation, perms,
localWorkers, resultFiles);
branch.log(TreeLogger.INFO, "Permutation compile succeeded");
- return true;
}
public static void main(String[] args) {
@@ -250,49 +249,53 @@
}
public boolean run(TreeLogger logger) throws UnableToCompleteException {
- File precompilationFile = new File(options.getCompilerWorkDir(),
- Precompile.PRECOMPILATION_FILENAME);
- if (!precompilationFile.exists()) {
- logger.log(TreeLogger.ERROR, "File not found '"
- + precompilationFile.getAbsolutePath()
- + "'; please run Precompile first");
- return false;
- }
- Precompilation precompilation;
- try {
- /*
- * TODO: don't bother deserializing the generated artifacts.
- */
- precompilation = Util.readFileAsObject(precompilationFile,
- Precompilation.class);
- } catch (ClassNotFoundException e) {
- logger.log(TreeLogger.ERROR, "Unable to deserialize '"
- + precompilationFile.getAbsolutePath() + "'", e);
- return false;
- }
-
- Permutation[] perms = precompilation.getPermutations();
- Permutation[] subPerms;
- int[] permsToRun = options.getPermsToCompile();
- if (permsToRun.length == 0) {
- subPerms = perms;
- } else {
- int i = 0;
- subPerms = new Permutation[permsToRun.length];
- // Range check the supplied perms.
- for (int permToRun : permsToRun) {
- if (permToRun >= perms.length) {
- logger.log(TreeLogger.ERROR, "The specified perm number '"
- + permToRun + "' is too big; the maximum value is "
- + (perms.length - 1) + "'");
- return false;
- }
- subPerms[i++] = perms[permToRun];
+ for (String moduleName : options.getModuleNames()) {
+ File compilerWorkDir = options.getCompilerWorkDir(moduleName);
+ File precompilationFile = new File(compilerWorkDir,
+ Precompile.PRECOMPILATION_FILENAME);
+ if (!precompilationFile.exists()) {
+ logger.log(TreeLogger.ERROR, "File not found '"
+ + precompilationFile.getAbsolutePath()
+ + "'; please run Precompile first");
+ return false;
}
- }
+ Precompilation precompilation;
+ try {
+ /*
+ * TODO: don't bother deserializing the generated artifacts.
+ */
+ precompilation = Util.readFileAsObject(precompilationFile,
+ Precompilation.class);
+ } catch (ClassNotFoundException e) {
+ logger.log(TreeLogger.ERROR, "Unable to deserialize '"
+ + precompilationFile.getAbsolutePath() + "'", e);
+ return false;
+ }
- File[] resultFiles = makeResultFiles(options.getCompilerWorkDir(), perms);
- return compile(logger, precompilation, subPerms, options.getLocalWorkers(),
- resultFiles);
+ Permutation[] perms = precompilation.getPermutations();
+ Permutation[] subPerms;
+ int[] permsToRun = options.getPermsToCompile();
+ if (permsToRun.length == 0) {
+ subPerms = perms;
+ } else {
+ int i = 0;
+ subPerms = new Permutation[permsToRun.length];
+ // Range check the supplied perms.
+ for (int permToRun : permsToRun) {
+ if (permToRun >= perms.length) {
+ logger.log(TreeLogger.ERROR, "The specified perm number '"
+ + permToRun + "' is too big; the maximum value is "
+ + (perms.length - 1) + "'");
+ return false;
+ }
+ subPerms[i++] = perms[permToRun];
+ }
+ }
+
+ File[] resultFiles = makeResultFiles(compilerWorkDir, perms);
+ compile(logger, precompilation, subPerms, options.getLocalWorkers(),
+ resultFiles);
+ }
+ return true;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java b/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java
index e92d1c8..cabbc4f 100644
--- a/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java
+++ b/dev/core/src/com/google/gwt/dev/CompileTaskOptionsImpl.java
@@ -18,6 +18,8 @@
import com.google.gwt.core.ext.TreeLogger.Type;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
/**
* Concrete class to implement compiler task options.
@@ -25,7 +27,7 @@
class CompileTaskOptionsImpl implements CompileTaskOptions {
private Type logLevel;
- private String moduleName;
+ private final List<String> moduleNames = new ArrayList<String>();
private boolean useGuiLogger;
private File workDir;
@@ -36,23 +38,27 @@
copyFrom(other);
}
+ public void addModuleName(String moduleName) {
+ moduleNames.add(moduleName);
+ }
+
public void copyFrom(CompileTaskOptions other) {
setLogLevel(other.getLogLevel());
- setModuleName(other.getModuleName());
+ setModuleNames(other.getModuleNames());
setUseGuiLogger(other.isUseGuiLogger());
setWorkDir(other.getWorkDir());
}
- public File getCompilerWorkDir() {
- return new File(new File(getWorkDir(), getModuleName()), "compiler");
+ public File getCompilerWorkDir(String moduleName) {
+ return new File(new File(getWorkDir(), moduleName), "compiler");
}
public Type getLogLevel() {
return logLevel;
}
- public String getModuleName() {
- return moduleName;
+ public List<String> getModuleNames() {
+ return new ArrayList<String>(moduleNames);
}
public File getWorkDir() {
@@ -67,8 +73,9 @@
this.logLevel = logLevel;
}
- public void setModuleName(String moduleName) {
- this.moduleName = moduleName;
+ public void setModuleNames(List<String> moduleNames) {
+ this.moduleNames.clear();
+ this.moduleNames.addAll(moduleNames);
}
public void setUseGuiLogger(boolean useGuiLogger) {
diff --git a/dev/core/src/com/google/gwt/dev/CompileTaskRunner.java b/dev/core/src/com/google/gwt/dev/CompileTaskRunner.java
index a5efcfb..ce1ef6a 100644
--- a/dev/core/src/com/google/gwt/dev/CompileTaskRunner.java
+++ b/dev/core/src/com/google/gwt/dev/CompileTaskRunner.java
@@ -46,7 +46,7 @@
if (options.isUseGuiLogger()) {
// Initialize a tree logger window.
DetachedTreeLoggerWindow loggerWindow = DetachedTreeLoggerWindow.getInstance(
- "Build Output for " + options.getModuleName(), 800, 600, true);
+ "Build Output for " + options.getModuleNames(), 800, 600, true);
// Eager AWT initialization for OS X to ensure safe coexistence with SWT.
BootStrapPlatform.maybeInitializeAWT();
diff --git a/dev/core/src/com/google/gwt/dev/Compiler.java b/dev/core/src/com/google/gwt/dev/Compiler.java
new file mode 100644
index 0000000..3ecb3d2
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/Compiler.java
@@ -0,0 +1,192 @@
+/*
+ * 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;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.CompileTaskRunner.CompileTask;
+import com.google.gwt.dev.Link.LinkOptionsImpl;
+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.util.PerfLogger;
+import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
+import com.google.gwt.dev.util.arg.ArgHandlerLocalWorkers;
+import com.google.gwt.dev.util.arg.ArgHandlerWarDir;
+import com.google.gwt.dev.util.arg.ArgHandlerWorkDirOptional;
+import com.google.gwt.util.tools.Utility;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * The main executable entry point for the GWT Java to JavaScript compiler.
+ */
+public class Compiler {
+
+ static class ArgProcessor extends Precompile.ArgProcessor {
+ public ArgProcessor(CompilerOptions options) {
+ super(options);
+
+ registerHandler(new ArgHandlerLocalWorkers(options));
+
+ // Override the ArgHandlerWorkDirRequired in the super class.
+ registerHandler(new ArgHandlerWorkDirOptional(options));
+
+ registerHandler(new ArgHandlerWarDir(options));
+ registerHandler(new ArgHandlerExtraDir(options));
+ }
+
+ @Override
+ protected String getName() {
+ return GWTCompiler.class.getName();
+ }
+ }
+
+ static class CompilerOptionsImpl extends PrecompileOptionsImpl implements
+ CompilerOptions {
+
+ private LinkOptionsImpl linkOptions = new LinkOptionsImpl();
+ private int localWorkers;
+
+ public CompilerOptionsImpl() {
+ }
+
+ public CompilerOptionsImpl(CompilerOptions other) {
+ copyFrom(other);
+ }
+
+ public void copyFrom(CompilerOptions other) {
+ super.copyFrom(other);
+ linkOptions.copyFrom(other);
+ localWorkers = other.getLocalWorkers();
+ }
+
+ public File getExtraDir() {
+ return linkOptions.getExtraDir();
+ }
+
+ public int getLocalWorkers() {
+ return localWorkers;
+ }
+
+ public File getWarDir() {
+ return linkOptions.getWarDir();
+ }
+
+ public void setExtraDir(File extraDir) {
+ linkOptions.setExtraDir(extraDir);
+ }
+
+ public void setLocalWorkers(int localWorkers) {
+ this.localWorkers = localWorkers;
+ }
+
+ public void setWarDir(File outDir) {
+ linkOptions.setWarDir(outDir);
+ }
+ }
+
+ public static void main(String[] args) {
+ /*
+ * 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
+ * shutdown AWT related threads, since the contract for their termination is
+ * still implementation-dependent.
+ */
+ final CompilerOptions options = new CompilerOptionsImpl();
+ if (new ArgProcessor(options).processArgs(args)) {
+ CompileTask task = new CompileTask() {
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ return new Compiler(options).run(logger);
+ }
+ };
+ if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
+ // Exit w/ success code.
+ System.exit(0);
+ }
+ }
+ // Exit w/ non-success code.
+ System.exit(1);
+ }
+
+ private final CompilerOptionsImpl options;
+
+ public Compiler(CompilerOptions options) {
+ this.options = new CompilerOptionsImpl(options);
+ }
+
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ PerfLogger.start("compile");
+ boolean tempWorkDir = false;
+ try {
+ if (options.getWorkDir() == null) {
+ options.setWorkDir(Utility.makeTemporaryDirectory(null, "gwtc"));
+ tempWorkDir = true;
+ }
+
+ for (String moduleName : options.getModuleNames()) {
+ ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, moduleName);
+ File compilerWorkDir = options.getCompilerWorkDir(moduleName);
+
+ if (options.isValidateOnly()) {
+ if (!Precompile.validate(logger, options, module,
+ options.getGenDir(), compilerWorkDir)) {
+ return false;
+ }
+ } else {
+ long compileStart = System.currentTimeMillis();
+ logger = logger.branch(TreeLogger.INFO, "Compiling module "
+ + moduleName);
+
+ Precompilation precompilation = Precompile.precompile(logger,
+ options, module, options.getGenDir(), compilerWorkDir);
+
+ if (precompilation == null) {
+ return false;
+ }
+
+ Permutation[] allPerms = precompilation.getPermutations();
+ File[] resultFiles = CompilePerms.makeResultFiles(compilerWorkDir,
+ allPerms);
+ CompilePerms.compile(logger, precompilation, allPerms,
+ options.getLocalWorkers(), resultFiles);
+
+ Link.link(logger.branch(TreeLogger.INFO, "Linking into "
+ + options.getWarDir().getPath()), module, precompilation,
+ resultFiles, options.getWarDir(), options.getExtraDir());
+
+ long compileDone = System.currentTimeMillis();
+ long delta = compileDone - compileStart;
+ logger.log(TreeLogger.INFO, "Compilation succeeded -- "
+ + String.format("%.3f", delta / 1000d) + "s");
+ }
+ }
+
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Unable to create compiler work directory",
+ e);
+ return false;
+ } finally {
+ PerfLogger.end();
+ if (tempWorkDir) {
+ Util.recursiveDelete(options.getWorkDir(), false);
+ }
+ }
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index 3e81a49..93d16ab 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -18,13 +18,11 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.CompileTaskRunner.CompileTask;
-import com.google.gwt.dev.Link.LinkOptionsImpl;
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.util.PerfLogger;
import com.google.gwt.dev.util.Util;
-import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
import com.google.gwt.dev.util.arg.ArgHandlerLocalWorkers;
import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
import com.google.gwt.dev.util.arg.ArgHandlerWorkDirOptional;
@@ -39,15 +37,15 @@
public class GWTCompiler {
static final class ArgProcessor extends Precompile.ArgProcessor {
- public ArgProcessor(CompilerOptions options) {
+ public ArgProcessor(LegacyCompilerOptions options) {
super(options);
+ registerHandler(new ArgHandlerOutDir(options));
+
// Override the ArgHandlerWorkDirRequired in the super class.
registerHandler(new ArgHandlerWorkDirOptional(options));
- registerHandler(new ArgHandlerExtraDir(options));
registerHandler(new ArgHandlerLocalWorkers(options));
- registerHandler(new ArgHandlerOutDir(options));
}
@Override
@@ -57,26 +55,22 @@
}
static class GWTCompilerOptionsImpl extends PrecompileOptionsImpl implements
- CompilerOptions {
+ LegacyCompilerOptions {
- private LinkOptionsImpl linkOptions = new LinkOptionsImpl();
private int localWorkers;
+ private File outDir;
public GWTCompilerOptionsImpl() {
}
- public GWTCompilerOptionsImpl(CompilerOptions other) {
+ public GWTCompilerOptionsImpl(LegacyCompilerOptions other) {
copyFrom(other);
}
- public void copyFrom(CompilerOptions other) {
+ public void copyFrom(LegacyCompilerOptions other) {
super.copyFrom(other);
- linkOptions.copyFrom(other);
- localWorkers = other.getLocalWorkers();
- }
-
- public File getExtraDir() {
- return linkOptions.getExtraDir();
+ setLocalWorkers(other.getLocalWorkers());
+ setOutDir(other.getOutDir());
}
public int getLocalWorkers() {
@@ -84,11 +78,7 @@
}
public File getOutDir() {
- return linkOptions.getOutDir();
- }
-
- public void setExtraDir(File extraDir) {
- linkOptions.setExtraDir(extraDir);
+ return outDir;
}
public void setLocalWorkers(int localWorkers) {
@@ -96,7 +86,7 @@
}
public void setOutDir(File outDir) {
- linkOptions.setOutDir(outDir);
+ this.outDir = outDir;
}
}
@@ -107,7 +97,7 @@
* shutdown AWT related threads, since the contract for their termination is
* still implementation-dependent.
*/
- final CompilerOptions options = new GWTCompilerOptionsImpl();
+ final LegacyCompilerOptions options = new GWTCompilerOptionsImpl();
if (new ArgProcessor(options).processArgs(args)) {
CompileTask task = new CompileTask() {
public boolean run(TreeLogger logger) throws UnableToCompleteException {
@@ -125,62 +115,67 @@
private final GWTCompilerOptionsImpl options;
- public GWTCompiler(CompilerOptions options) {
+ public GWTCompiler(LegacyCompilerOptions options) {
this.options = new GWTCompilerOptionsImpl(options);
}
public boolean run(TreeLogger logger) throws UnableToCompleteException {
- ModuleDef module = ModuleDefLoader.loadFromClassPath(logger,
- options.getModuleName());
+ PerfLogger.start("compile");
+ boolean tempWorkDir = false;
+ try {
+ if (options.getWorkDir() == null) {
+ options.setWorkDir(Utility.makeTemporaryDirectory(null, "gwtc"));
+ tempWorkDir = true;
+ }
- if (options.isValidateOnly()) {
- return Precompile.validate(logger, options, module, options.getGenDir(),
- options.getCompilerWorkDir());
- } else {
- PerfLogger.start("compile");
- long compileStart = System.currentTimeMillis();
- logger = logger.branch(TreeLogger.INFO, "Compiling module "
- + options.getModuleName());
+ for (String moduleName : options.getModuleNames()) {
+ ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, moduleName);
+ File compilerWorkDir = options.getCompilerWorkDir(moduleName);
- boolean tempWorkDir = false;
- try {
- if (options.getWorkDir() == null) {
- options.setWorkDir(Utility.makeTemporaryDirectory(null, "gwtc"));
- tempWorkDir = true;
- }
+ if (options.isValidateOnly()) {
+ if (!Precompile.validate(logger, options, module,
+ options.getGenDir(), compilerWorkDir)) {
+ return false;
+ }
+ } else {
+ long compileStart = System.currentTimeMillis();
+ logger = logger.branch(TreeLogger.INFO, "Compiling module "
+ + moduleName);
- Precompilation precompilation = Precompile.precompile(logger, options,
- module, options.getGenDir(), options.getCompilerWorkDir());
+ Precompilation precompilation = Precompile.precompile(logger,
+ options, module, options.getGenDir(), compilerWorkDir);
- if (precompilation == null) {
- return false;
- }
+ if (precompilation == null) {
+ return false;
+ }
- Permutation[] allPerms = precompilation.getPermutations();
- File[] resultFiles = CompilePerms.makeResultFiles(
- options.getCompilerWorkDir(), allPerms);
- CompilePerms.compile(logger, precompilation, allPerms,
- options.getLocalWorkers(), resultFiles);
+ Permutation[] allPerms = precompilation.getPermutations();
+ File[] resultFiles = CompilePerms.makeResultFiles(compilerWorkDir,
+ allPerms);
+ CompilePerms.compile(logger, precompilation, allPerms,
+ options.getLocalWorkers(), resultFiles);
- Link.link(logger.branch(TreeLogger.INFO, "Linking into "
- + options.getOutDir().getPath()), module, precompilation,
- resultFiles, options.getOutDir(), options.getExtraDir());
+ Link.legacyLink(logger.branch(TreeLogger.INFO, "Linking into "
+ + options.getOutDir().getPath()), module, precompilation,
+ resultFiles, options.getOutDir());
- long compileDone = System.currentTimeMillis();
- long delta = compileDone - compileStart;
- logger.log(TreeLogger.INFO, "Compilation succeeded -- "
- + String.format("%.3f", delta / 1000d) + "s");
- return true;
- } catch (IOException e) {
- logger.log(TreeLogger.ERROR,
- "Unable to create compiler work directory", e);
- } finally {
- PerfLogger.end();
- if (tempWorkDir) {
- Util.recursiveDelete(options.getWorkDir(), false);
+ long compileDone = System.currentTimeMillis();
+ long delta = compileDone - compileStart;
+ logger.log(TreeLogger.INFO, "Compilation succeeded -- "
+ + String.format("%.3f", delta / 1000d) + "s");
}
}
+
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Unable to create compiler work directory",
+ e);
return false;
+ } finally {
+ PerfLogger.end();
+ if (tempWorkDir) {
+ Util.recursiveDelete(options.getWorkDir(), false);
+ }
}
+ return true;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/GWTHosted.java b/dev/core/src/com/google/gwt/dev/GWTHosted.java
deleted file mode 100644
index 87bd0d4..0000000
--- a/dev/core/src/com/google/gwt/dev/GWTHosted.java
+++ /dev/null
@@ -1,257 +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;
-
-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.dev.cfg.ModuleDef;
-import com.google.gwt.dev.cfg.ModuleDefLoader;
-import com.google.gwt.dev.shell.ArtifactAcceptor;
-import com.google.gwt.dev.shell.GWTShellServletFilter;
-import com.google.gwt.dev.shell.ServletContainer;
-import com.google.gwt.dev.shell.ServletContainerLauncher;
-import com.google.gwt.dev.shell.jetty.JettyLauncher;
-import com.google.gwt.dev.util.PerfLogger;
-import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
-import com.google.gwt.util.tools.ArgHandlerExtra;
-import com.google.gwt.util.tools.ArgHandlerString;
-
-import java.io.PrintWriter;
-import java.net.BindException;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * The main executable class for the hosted mode shell.
- */
-public class GWTHosted extends GWTShell {
-
- /**
- * Handles the set of modules that can be passed at the end of the command
- * line.
- */
- protected class ArgHandlerModulesExtra extends ArgHandlerExtra {
-
- @Override
- public boolean addExtraArg(String arg) {
- return addModule(console, arg);
- }
-
- @Override
- public String getPurpose() {
- return "Specifies the set of modules to host";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"module"};
- }
- }
- /**
- * Handles the -server command line flag.
- */
- protected class ArgHandlerServer extends ArgHandlerString {
- @Override
- public String getPurpose() {
- return "Prevents the embedded Tomcat server from running, even if a port is specified";
- }
-
- @Override
- public String getTag() {
- return "-server";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"serverLauncherClass"};
- }
-
- @Override
- public boolean setString(String arg) {
- // Supercedes -noserver.
- setRunTomcat(true);
- return setServer(console, arg);
- }
- }
-
- /**
- * Handles a startup url that can be passed on the command line.
- */
- protected class ArgHandlerStartupURLs extends ArgHandlerString {
-
- @Override
- public String getPurpose() {
- return "Automatically launches the specified URL";
- }
-
- @Override
- public String getTag() {
- return "-startupUrl";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"url"};
- }
-
- @Override
- public boolean setString(String arg) {
- addStartupURL(arg);
- return true;
- }
- }
-
- public static void main(String[] args) {
- /*
- * 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
- * shutdown AWT related threads, since the contract for their termination is
- * still implementation-dependent.
- */
- GWTHosted shellMain = new GWTHosted();
- if (shellMain.processArgs(args)) {
- shellMain.run();
- }
- System.exit(0);
- }
-
- protected final PrintWriterTreeLogger console = new PrintWriterTreeLogger(
- new PrintWriter(System.err, true));
-
- /**
- * The servlet launcher to use (defaults to embedded Jetty).
- */
- private ServletContainerLauncher launcher = new JettyLauncher();
-
- /**
- * The set of modules this hosted mode instance can run.
- */
- private Set<ModuleDef> modules = new HashSet<ModuleDef>();
-
- /**
- * The server that was started.
- */
- private ServletContainer server;
-
- /**
- * Our servlet filter, embedded into the server, which autogenerates GWT
- * modules when the selection script is requested.
- */
- private GWTShellServletFilter servletFilter;
-
- {
- console.setMaxDetail(TreeLogger.WARN);
- }
-
- public GWTHosted() {
- super(false, true);
- registerHandler(new ArgHandlerServer());
- registerHandler(new ArgHandlerStartupURLs());
- registerHandler(new ArgHandlerModulesExtra());
- }
-
- public boolean addModule(TreeLogger logger, String moduleName) {
- try {
- ModuleDef moduleDef = ModuleDefLoader.loadFromClassPath(logger,
- moduleName);
- modules.add(moduleDef);
- return true;
- } catch (UnableToCompleteException e) {
- logger.log(TreeLogger.ERROR, "Unable to load module '" + moduleName + "'");
- return false;
- }
- }
-
- public boolean setServer(TreeLogger logger, String serverClassName) {
- Throwable t;
- try {
- Class<?> clazz = Class.forName(serverClassName, true,
- Thread.currentThread().getContextClassLoader());
- Class<? extends ServletContainerLauncher> sclClass = clazz.asSubclass(ServletContainerLauncher.class);
- launcher = sclClass.newInstance();
- return true;
- } catch (ClassCastException e) {
- t = e;
- } catch (ClassNotFoundException e) {
- t = e;
- } catch (InstantiationException e) {
- t = e;
- } catch (IllegalAccessException e) {
- t = e;
- }
- logger.log(TreeLogger.ERROR, "Unable to load server class '"
- + serverClassName + "'", t);
- return false;
- }
-
- @Override
- protected ArtifactAcceptor doCreateArtifactAcceptor(final ModuleDef module) {
- return new ArtifactAcceptor() {
- public void accept(TreeLogger logger, ArtifactSet newlyGeneratedArtifacts)
- throws UnableToCompleteException {
- servletFilter.relink(logger, module, newlyGeneratedArtifacts);
- }
- };
- }
-
- @Override
- protected void shutDown() {
- if (server != null) {
- try {
- server.stop();
- } catch (UnableToCompleteException e) {
- // Already logged.
- }
- server = null;
- }
- }
-
- @Override
- protected int startUpServer() {
- PerfLogger.start("GWTHosted.startUpServer");
- try {
- TreeLogger serverLogger = getTopLogger().branch(TreeLogger.INFO,
- "Starting HTTP on port " + getPort(), null);
- ModuleDef[] moduleArray = modules.toArray(new ModuleDef[modules.size()]);
- for (ModuleDef moduleDef : moduleArray) {
- String[] servletPaths = moduleDef.getServletPaths();
- if (servletPaths.length > 0) {
- serverLogger.log(TreeLogger.WARN,
- "Ignoring legacy <servlet> tag(s) in module '"
- + moduleDef.getName()
- + "'; add servlet tags to your web.xml instead");
- }
- }
- servletFilter = new GWTShellServletFilter(serverLogger, options,
- moduleArray);
- server = launcher.start(serverLogger, getPort(), options.getOutDir(),
- servletFilter);
- assert (server != null);
- return server.getPort();
- } catch (BindException e) {
- System.err.println("Port "
- + getPort()
- + " is already is use; you probably still have another session active");
- } catch (Exception e) {
- System.err.println("Unable to start embedded HTTP server");
- e.printStackTrace();
- } finally {
- PerfLogger.end();
- }
- return -1;
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index 48a5d17..a83f85d 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -17,153 +17,23 @@
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.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.EmittedArtifact;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.GWTCompiler.GWTCompilerOptionsImpl;
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.BrowserWidget;
-import com.google.gwt.dev.shell.BrowserWidgetHost;
-import com.google.gwt.dev.shell.BrowserWidgetHostChecker;
-import com.google.gwt.dev.shell.LowLevel;
-import com.google.gwt.dev.shell.ModuleSpaceHost;
-import com.google.gwt.dev.shell.PlatformSpecific;
-import com.google.gwt.dev.shell.ShellMainWindow;
-import com.google.gwt.dev.shell.ShellModuleSpaceHost;
import com.google.gwt.dev.shell.WorkDirs;
import com.google.gwt.dev.shell.tomcat.EmbeddedTomcatServer;
import com.google.gwt.dev.util.Util;
-import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
-import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
-import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
-import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
-import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
-import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
-import com.google.gwt.dev.util.arg.ArgHandlerWorkDirOptional;
-import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.util.tools.ArgHandlerExtra;
-import com.google.gwt.util.tools.ArgHandlerFlag;
-import com.google.gwt.util.tools.ArgHandlerString;
-import com.google.gwt.util.tools.ToolBase;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.graphics.Cursor;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.internal.Library;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
import java.io.File;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
/**
* The main executable class for the hosted mode shell.
*/
-public class GWTShell extends ToolBase {
-
- /**
- * Handles the -blacklist command line argument.
- */
- protected class ArgHandlerBlacklist extends ArgHandlerString {
-
- @Override
- public String[] getDefaultArgs() {
- return new String[] {"-blacklist", ""};
- }
-
- @Override
- public String getPurpose() {
- return "Prevents the user browsing URLs that match the specified regexes (comma or space separated)";
- }
-
- @Override
- public String getTag() {
- return "-blacklist";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"blacklist-string"};
- }
-
- @Override
- public boolean setString(String blacklistStr) {
- return BrowserWidgetHostChecker.blacklistRegexes(blacklistStr);
- }
- }
-
- /**
- * Handles the -noserver command line flag.
- */
- protected class ArgHandlerNoServerFlag extends ArgHandlerFlag {
- @Override
- public String getPurpose() {
- return "Prevents the embedded Tomcat server from running, even if a port is specified";
- }
-
- @Override
- public String getTag() {
- return "-noserver";
- }
-
- @Override
- public boolean setFlag() {
- runTomcat = false;
- return true;
- }
- }
-
- /**
- * Handles the -port command line flag.
- */
- protected class ArgHandlerPort extends ArgHandlerString {
-
- @Override
- public String[] getDefaultArgs() {
- return new String[] {"-port", "8888"};
- }
-
- @Override
- public String getPurpose() {
- return "Runs an embedded Tomcat instance on the specified port (defaults to 8888)";
- }
-
- @Override
- public String getTag() {
- return "-port";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"port-number | \"auto\""};
- }
-
- @Override
- public boolean setString(String value) {
- if (value.equals("auto")) {
- port = 0;
- } else {
- try {
- port = Integer.parseInt(value);
- } catch (NumberFormatException e) {
- System.err.println("A port must be an integer or \"auto\"");
- return false;
- }
- }
- return true;
- }
- }
+public class GWTShell extends HostedModeBase {
/**
* Handles the list of startup urls that can be passed at the end of the
@@ -189,33 +59,23 @@
}
/**
- * Handles the -whitelist command line flag.
+ * The GWTShell argument processor.
*/
- protected class ArgHandlerWhitelist extends ArgHandlerString {
+ protected class ArgProcessor extends HostedModeBase.ArgProcessor {
+ public ArgProcessor(boolean forceServer, boolean noURLs) {
+ if (!forceServer) {
+ registerHandler(new ArgHandlerNoServerFlag());
+ }
- @Override
- public String[] getDefaultArgs() {
- return new String[] {"-whitelist", ""};
+ if (!noURLs) {
+ registerHandler(new ArgHandlerStartupURLsExtra());
+ }
+ registerHandler(new ArgHandlerOutDir(options));
}
@Override
- public String getPurpose() {
- return "Allows the user to browse URLs that match the specified regexes (comma or space separated)";
- }
-
- @Override
- public String getTag() {
- return "-whitelist";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"whitelist-string"};
- }
-
- @Override
- public boolean setString(String whitelistStr) {
- return BrowserWidgetHostChecker.whitelistRegexes(whitelistStr);
+ protected String getName() {
+ return GWTShell.class.getName();
}
}
@@ -223,153 +83,23 @@
* Concrete class to implement all compiler options.
*/
static class ShellOptionsImpl extends GWTCompilerOptionsImpl implements
- ShellOptions, WorkDirs {
+ HostedModeBaseOptions, WorkDirs {
public File getCompilerOutputDir(ModuleDef moduleDef) {
- return new File(getOutDir(), moduleDef.getDeployTo());
+ return new File(getOutDir(), moduleDef.getName());
+ }
+
+ public File getShellBaseWorkDir(ModuleDef moduleDef) {
+ return new File(new File(getWorkDir(), moduleDef.getName()), "shell");
}
public File getShellPublicGenDir(ModuleDef moduleDef) {
return new File(getShellBaseWorkDir(moduleDef), "public");
}
- /**
- * The base shell work directory.
- */
- protected File getShellBaseWorkDir(ModuleDef moduleDef) {
- return new File(new File(getWorkDir(), moduleDef.getName()), "shell");
+ @Override
+ public File getWorkDir() {
+ return new File(getOutDir(), ".gwt-tmp");
}
-
- /**
- * Where generated files go by default until we are sure they are public;
- * then they are copied into {@link #getShellPublicGenDir(ModuleDef)}.
- */
- protected File getShellPrivateGenDir(ModuleDef moduleDef) {
- return new File(getShellBaseWorkDir(moduleDef), "gen");
- }
- }
-
- private class BrowserWidgetHostImpl implements BrowserWidgetHost {
- public BrowserWidgetHostImpl() {
- }
-
- public void compile(ModuleDef moduleDef) throws UnableToCompleteException {
- GWTShell.this.compile(getLogger(), moduleDef);
- }
-
- public void compile(String[] moduleNames) throws UnableToCompleteException {
- for (int i = 0; i < moduleNames.length; i++) {
- String moduleName = moduleNames[i];
- ModuleDef moduleDef = loadModule(moduleName, getLogger());
- compile(moduleDef);
- }
- }
-
- public ModuleSpaceHost createModuleSpaceHost(BrowserWidget widget,
- final String moduleName) throws UnableToCompleteException {
- TreeLogger logger = getLogger();
-
- // Switch to a wait cursor.
- //
- Shell widgetShell = widget.getShell();
- try {
- Cursor waitCursor = display.getSystemCursor(SWT.CURSOR_WAIT);
- widgetShell.setCursor(waitCursor);
-
- // Try to find an existing loaded version of the module def.
- //
- ModuleDef moduleDef = loadModule(moduleName, logger);
- assert (moduleDef != null);
-
- TypeOracle typeOracle = moduleDef.getTypeOracle(logger);
- ShellModuleSpaceHost host = doCreateShellModuleSpaceHost(logger,
- typeOracle, moduleDef);
- return host;
- } finally {
- Cursor normalCursor = display.getSystemCursor(SWT.CURSOR_ARROW);
- widgetShell.setCursor(normalCursor);
- }
- }
-
- public TreeLogger getLogger() {
- return getTopLogger();
- }
-
- public String normalizeURL(String whatTheUserTyped) {
- return GWTShell.this.normalizeURL(whatTheUserTyped);
- }
-
- public BrowserWidget openNewBrowserWindow()
- throws UnableToCompleteException {
- return GWTShell.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;
- }
- }
-
- private static Image[] icons;
-
- static {
- // Correct menu on Mac OS X
- Display.setAppName("GWT");
- }
-
- public static String checkHost(String hostUnderConsideration,
- Set<String> hosts) {
- hostUnderConsideration = hostUnderConsideration.toLowerCase();
- for (String rule : hosts) {
- // match on lowercased regex
- if (hostUnderConsideration.matches(".*" + rule + ".*")) {
- return rule;
- }
- }
- return null;
- }
-
- public static String computeHostRegex(String url) {
- // the entire URL up to the first slash not prefixed by a slash or colon.
- String raw = url.split("(?<![:/])/")[0];
- // escape the dots and put a begin line specifier on the result
- return "^" + raw.replaceAll("[.]", "[.]");
- }
-
- public static String formatRules(Set<String> invalidHttpHosts) {
- StringBuffer out = new StringBuffer();
- for (String rule : invalidHttpHosts) {
- out.append(rule);
- out.append(" ");
- }
- return out.toString();
- }
-
- /**
- * Well-known place to get the GWT icons.
- */
- public static Image[] getIcons() {
- // Make sure icon images are loaded.
- //
- if (icons == null) {
- icons = new Image[] {
- LowLevel.loadImage("icon16.png"), LowLevel.loadImage("icon24.png"),
- LowLevel.loadImage("icon32.png"), LowLevel.loadImage("icon48.png"),
- LowLevel.loadImage("icon128.png")};
- }
- return icons;
}
public static void main(String[] args) {
@@ -380,225 +110,30 @@
* still implementation-dependent.
*/
GWTShell shellMain = new GWTShell();
- if (shellMain.processArgs(args)) {
+ if (shellMain.new ArgProcessor(false, false).processArgs(args)) {
shellMain.run();
+ // Exit w/ success code.
+ System.exit(0);
}
- System.exit(0);
+ // Exit w/ non-success code.
+ System.exit(-1);
}
/**
- * Use the default display; constructing a new one would make instantiating
- * multiple GWTShells fail with a mysterious exception.
+ * Hiding super field because it's actually the same object, just with a
+ * stronger type.
*/
- protected final Display display = Display.getDefault();
+ @SuppressWarnings("hiding")
+ protected final ShellOptionsImpl options = (ShellOptionsImpl) super.options;
- protected final ShellOptionsImpl options = new ShellOptionsImpl();
-
- /**
- * Cheat on the first load's refresh by assuming the module loaded by
- * {@link com.google.gwt.dev.shell.GWTShellServlet} is still fresh. This
- * prevents a double-refresh on startup. Subsequent refreshes will trigger a
- * real refresh.
- */
- private Set<String> alreadySeenModules = new HashSet<String>();
-
- private BrowserWidgetHostImpl browserHost = new BrowserWidgetHostImpl();
-
- private final List<Shell> browserShells = new ArrayList<Shell>();
-
- private boolean headlessMode = false;
-
- private ShellMainWindow mainWnd;
-
- private int port;
-
- private boolean runTomcat = true;
-
- private boolean started;
-
- private final List<String> startupUrls = new ArrayList<String>();
-
- public GWTShell() {
- this(false, false);
- }
-
- protected GWTShell(boolean forceServer, boolean noURLs) {
- // Set any platform specific system properties.
- BootStrapPlatform.init();
- BootStrapPlatform.applyPlatformHacks();
-
- registerHandler(getArgHandlerPort());
-
- if (!forceServer) {
- registerHandler(new ArgHandlerNoServerFlag());
- }
-
- registerHandler(new ArgHandlerWhitelist());
- registerHandler(new ArgHandlerBlacklist());
-
- registerHandler(new ArgHandlerLogLevel(options));
-
- registerHandler(new ArgHandlerGenDir(options));
- registerHandler(new ArgHandlerWorkDirOptional(options));
-
- if (!noURLs) {
- registerHandler(new ArgHandlerStartupURLsExtra());
- }
-
- registerHandler(new ArgHandlerExtraDir(options));
- registerHandler(new ArgHandlerOutDir(options));
-
- registerHandler(new ArgHandlerScriptStyle(options));
- registerHandler(new ArgHandlerEnableAssertions(options));
- registerHandler(new ArgHandlerDisableAggressiveOptimization(options));
- }
-
- public void addStartupURL(String url) {
- startupUrls.add(url);
- }
-
- public void closeAllBrowserWindows() {
- while (!browserShells.isEmpty()) {
- browserShells.get(0).dispose();
- }
- }
-
- public CompilerOptions getCompilerOptions() {
+ public LegacyCompilerOptions getCompilerOptions() {
return new GWTCompilerOptionsImpl(options);
}
- public int getPort() {
- return port;
- }
-
- public TreeLogger getTopLogger() {
- return mainWnd.getLogger();
- }
-
- public boolean hasBrowserWindowsOpen() {
- if (browserShells.isEmpty()) {
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * Launch the arguments as Urls in separate windows.
- */
- public void launchStartupUrls(final TreeLogger logger) {
- if (startupUrls != null) {
- // Launch a browser window for each startup url.
- //
- String startupURL = "";
- try {
- for (String prenormalized : startupUrls) {
- startupURL = normalizeURL(prenormalized);
- logger.log(TreeLogger.TRACE, "Starting URL: " + startupURL, null);
- BrowserWidget bw = openNewBrowserWindow();
- bw.go(startupURL);
- }
- } catch (UnableToCompleteException e) {
- logger.log(TreeLogger.ERROR,
- "Unable to open new window for startup URL: " + startupURL, null);
- }
- }
- }
-
- public String normalizeURL(String unknownUrlText) {
- if (unknownUrlText.indexOf(":") != -1) {
- // Assume it's a full url.
- return unknownUrlText;
- }
-
- // Assume it's a trailing url path.
- //
- if (unknownUrlText.length() > 0 && unknownUrlText.charAt(0) == '/') {
- unknownUrlText = unknownUrlText.substring(1);
- }
-
- int prt = getPort();
- if (prt != 80 && prt != 0) {
- // CHECKSTYLE_OFF: Not really an assembled error message, so no space
- // after ':'.
- return "http://localhost:" + prt + "/" + unknownUrlText;
- // CHECKSTYLE_ON
- } else {
- return "http://localhost/" + unknownUrlText;
- }
- }
-
- /**
- * Called directly by ShellMainWindow and indirectly via BrowserWidgetHost.
- */
- public BrowserWidget openNewBrowserWindow() throws UnableToCompleteException {
- boolean succeeded = false;
- Shell s = createTrackedBrowserShell();
- try {
- BrowserWidget bw = PlatformSpecific.createBrowserWidget(getTopLogger(),
- s, browserHost);
-
- if (mainWnd != null) {
- Rectangle r = mainWnd.getShell().getBounds();
- int n = browserShells.size() + 1;
- s.setBounds(r.x + n * 50, r.y + n * 50, 800, 600);
- } else {
- s.setSize(800, 600);
- }
-
- if (!isHeadless()) {
- s.open();
- }
-
- bw.onFirstShown();
- succeeded = true;
- return bw;
- } finally {
- if (!succeeded) {
- s.dispose();
- }
- }
- }
-
- /**
- * Sets up all the major aspects of running the shell graphically, including
- * creating the main window and optionally starting the embedded Tomcat
- * server.
- */
- public void run() {
- try {
- if (!startUp()) {
- // Failed to initalize.
- return;
- }
-
- // Eager AWT initialization for OS X to ensure safe coexistence with SWT.
- BootStrapPlatform.maybeInitializeAWT();
-
- // Tomcat's running now, so launch browsers for startup urls now.
- launchStartupUrls(getTopLogger());
-
- pumpEventLoop();
-
- shutDown();
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
public void setCompilerOptions(CompilerOptions options) {
this.options.copyFrom(options);
}
- public void setPort(int port) {
- this.port = port;
- }
-
- public void setRunTomcat(boolean run) {
- runTomcat = run;
- }
-
/**
* Compiles a logical module def. The caller can modify the specified module
* def programmatically in some cases (this is needed for JUnit support, for
@@ -606,11 +141,16 @@
*/
protected void compile(TreeLogger logger, ModuleDef moduleDef)
throws UnableToCompleteException {
- CompilerOptions newOptions = new GWTCompilerOptionsImpl(options);
- newOptions.setModuleName(moduleDef.getName());
+ LegacyCompilerOptions newOptions = new GWTCompilerOptionsImpl(options);
+ newOptions.addModuleName(moduleDef.getName());
new GWTCompiler(newOptions).run(logger);
}
+ @Override
+ protected HostedModeBaseOptions createOptions() {
+ return new ShellOptionsImpl();
+ }
+
protected ArtifactAcceptor doCreateArtifactAcceptor(final ModuleDef module) {
return new ArtifactAcceptor() {
public void accept(TreeLogger logger, ArtifactSet artifacts)
@@ -631,147 +171,13 @@
};
}
- /**
- * Creates an instance of ShellModuleSpaceHost (or a derived class) using the
- * specified constituent parts. This method is made to be overridden for
- * subclasses that need to change the behavior of ShellModuleSpaceHost.
- *
- * @param logger TreeLogger to use
- * @param typeOracle
- * @param moduleDef
- * @param genDir
- * @return ShellModuleSpaceHost instance
- */
- protected ShellModuleSpaceHost doCreateShellModuleSpaceHost(
- TreeLogger logger, TypeOracle typeOracle, ModuleDef moduleDef) {
- // Clear out the shell temp directory.
- Util.recursiveDelete(options.getShellBaseWorkDir(moduleDef), true);
- return new ShellModuleSpaceHost(logger, typeOracle, moduleDef,
- options.getGenDir(), options.getShellPrivateGenDir(moduleDef),
- doCreateArtifactAcceptor(moduleDef));
- }
-
- /**
- * Can be override to change the default log level in subclasses. JUnit does
- * this for example.
- */
- protected Type doGetDefaultLogLevel() {
- return Type.INFO;
- }
-
- /**
- * Derived classes can override to prevent automatic update checking.
- */
- protected boolean doShouldCheckForUpdates() {
- return true;
- }
-
- /**
- * Derived classes can override to set a default port.
- */
- protected ArgHandlerPort getArgHandlerPort() {
- return new ArgHandlerPort();
- }
-
- protected BrowserWidgetHost getBrowserHost() {
- return browserHost;
- }
-
- protected void initializeLogger() {
- final AbstractTreeLogger logger = mainWnd.getLogger();
- logger.setMaxDetail(options.getLogLevel());
- }
-
- /**
- * By default we will open the application window.
- *
- * @return true if we are running in headless mode
- */
- protected boolean isHeadless() {
- return headlessMode;
- }
-
- protected boolean notDone() {
- if (!mainWnd.isDisposed()) {
- return true;
- }
- if (!browserShells.isEmpty()) {
- return true;
- }
- return false;
- }
-
- /**
- *
- */
- protected void pumpEventLoop() {
- TreeLogger logger = getTopLogger();
-
- // Run the event loop. When there are no open shells, quit.
- //
- while (notDone()) {
- try {
- if (!display.readAndDispatch()) {
- sleep();
- }
- } catch (Throwable e) {
- String msg = e.getMessage();
- msg = (msg != null ? msg : e.getClass().getName());
- logger.log(TreeLogger.ERROR, msg, e);
- }
- }
- }
-
- protected void setHeadless(boolean headlessMode) {
- this.headlessMode = headlessMode;
- }
-
- /**
- *
- */
- protected void shutDown() {
- if (!runTomcat) {
- return;
- }
-
+ @Override
+ protected void shutDownServer() {
// Stop the HTTP server.
//
EmbeddedTomcatServer.stop();
}
- protected void sleep() {
- display.sleep();
- }
-
- protected boolean startUp() {
- if (started) {
- throw new IllegalStateException("Startup code has already been run");
- }
-
- started = true;
-
- loadRequiredNativeLibs();
-
- // Create the main app window.
- // When it is up and running, it will start the Tomcat server if desired.
- //
- openAppWindow();
-
- // Initialize the logger.
- //
- initializeLogger();
-
- if (runTomcat) {
- int resultPort = startUpServer();
- if (resultPort < 0) {
- return false;
- }
- port = resultPort;
- }
-
- return true;
- }
-
protected int startUpServer() {
// TODO(bruce): make tomcat work in terms of the modular launcher
String whyFailed = EmbeddedTomcatServer.start(getTopLogger(), getPort(),
@@ -785,59 +191,4 @@
}
return EmbeddedTomcatServer.getPort();
}
-
- private Shell createTrackedBrowserShell() {
- final Shell shell = new Shell(display);
- FillLayout fillLayout = new FillLayout();
- fillLayout.marginWidth = 0;
- fillLayout.marginHeight = 0;
- shell.setLayout(fillLayout);
- browserShells.add(shell);
- shell.addDisposeListener(new DisposeListener() {
- public void widgetDisposed(DisposeEvent e) {
- if (e.widget == shell) {
- browserShells.remove(shell);
- }
- }
- });
-
- shell.setImages(getIcons());
-
- return shell;
- }
-
- private void loadRequiredNativeLibs() {
- String libName = null;
- try {
- libName = "swt";
- Library.loadLibrary(libName);
- } catch (UnsatisfiedLinkError e) {
- StringBuffer sb = new StringBuffer();
- sb.append("Unable to load required native library '" + libName + "'");
- sb.append("\n\tPlease specify the JVM startup argument ");
- sb.append("\"-Djava.library.path\"");
- throw new RuntimeException(sb.toString(), e);
- }
- }
-
- private void openAppWindow() {
- final Shell shell = new Shell(display);
-
- FillLayout fillLayout = new FillLayout();
- fillLayout.marginWidth = 0;
- fillLayout.marginHeight = 0;
- shell.setLayout(fillLayout);
-
- shell.setImages(getIcons());
-
- boolean checkForUpdates = doShouldCheckForUpdates();
-
- mainWnd = new ShellMainWindow(this, shell, runTomcat ? getPort() : 0,
- checkForUpdates);
-
- shell.setSize(700, 600);
- if (!isHeadless()) {
- shell.open();
- }
- }
}
diff --git a/dev/core/src/com/google/gwt/dev/HostedMode.java b/dev/core/src/com/google/gwt/dev/HostedMode.java
new file mode 100644
index 0000000..f19bf27
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/HostedMode.java
@@ -0,0 +1,320 @@
+/*
+ * 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;
+
+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;
+import com.google.gwt.dev.shell.jetty.JettyLauncher;
+import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
+import com.google.gwt.dev.util.arg.ArgHandlerModuleName;
+import com.google.gwt.dev.util.arg.ArgHandlerWarDir;
+import com.google.gwt.dev.util.arg.ArgHandlerWorkDirOptional;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.util.tools.ArgHandlerString;
+import com.google.gwt.util.tools.Utility;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.BindException;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+/**
+ * The main executable class for the hosted mode shell.
+ */
+public class HostedMode extends HostedModeBase {
+
+ /**
+ * Handles the -server command line flag.
+ */
+ protected class ArgHandlerServer extends ArgHandlerString {
+ @Override
+ public String getPurpose() {
+ return "Prevents the embedded Tomcat server from running, even if a port is specified";
+ }
+
+ @Override
+ public String getTag() {
+ return "-server";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"serverLauncherClass"};
+ }
+
+ @Override
+ public boolean setString(String arg) {
+ // Supercedes -noserver.
+ setRunTomcat(true);
+ return setServer(console, arg);
+ }
+ }
+
+ /**
+ * Handles a startup url that can be passed on the command line.
+ */
+ protected class ArgHandlerStartupURLs extends ArgHandlerString {
+
+ @Override
+ public String getPurpose() {
+ return "Automatically launches the specified URL";
+ }
+
+ @Override
+ public String getTag() {
+ return "-startupUrl";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"url"};
+ }
+
+ @Override
+ public boolean setString(String arg) {
+ addStartupURL(arg);
+ return true;
+ }
+ }
+
+ class ArgProcessor extends HostedModeBase.ArgProcessor {
+ public ArgProcessor() {
+ registerHandler(new ArgHandlerServer());
+ registerHandler(new ArgHandlerNoServerFlag());
+ 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 ArgHandlerModuleName(options));
+ }
+
+ @Override
+ protected String getName() {
+ return GWTShell.class.getName();
+ }
+ }
+
+ /**
+ * Concrete class to implement all compiler options.
+ */
+ static class HostedModeOptionsImpl extends CompilerOptionsImpl implements
+ HostedModeBaseOptions {
+ public File getShellBaseWorkDir(ModuleDef moduleDef) {
+ return new File(new File(getWorkDir(), moduleDef.getName()), "shell");
+ }
+ }
+
+ public static void main(String[] args) {
+ /*
+ * 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
+ * shutdown AWT related threads, since the contract for their termination is
+ * still implementation-dependent.
+ */
+ HostedMode shellMain = new HostedMode();
+ if (shellMain.new ArgProcessor().processArgs(args)) {
+ // Exit w/ success code.
+ System.exit(0);
+ }
+ // Exit w/ non-success code.
+ System.exit(-1);
+ }
+
+ protected final PrintWriterTreeLogger console = new PrintWriterTreeLogger(
+ new PrintWriter(System.err, true));
+
+ /**
+ * Hiding super field because it's actually the same object, just with a
+ * stronger type.
+ */
+ @SuppressWarnings("hiding")
+ protected final HostedModeOptionsImpl options = (HostedModeOptionsImpl) super.options;
+
+ /**
+ * The servlet launcher to use (defaults to embedded Jetty).
+ */
+ private ServletContainerLauncher launcher = new JettyLauncher();
+
+ private final Map<ModuleDef, StandardLinkerContext> linkerMap = new IdentityHashMap<ModuleDef, StandardLinkerContext>();
+
+ /**
+ * The server that was started.
+ */
+ private ServletContainer server;
+
+ /**
+ * Tracks whether we created a temp workdir that we need to destroy.
+ */
+ private boolean tempWorkDir = false;
+
+ {
+ console.setMaxDetail(TreeLogger.WARN);
+ }
+
+ public boolean setServer(TreeLogger logger, String serverClassName) {
+ Throwable t;
+ try {
+ Class<?> clazz = Class.forName(serverClassName, true,
+ Thread.currentThread().getContextClassLoader());
+ Class<? extends ServletContainerLauncher> sclClass = clazz.asSubclass(ServletContainerLauncher.class);
+ launcher = sclClass.newInstance();
+ return true;
+ } catch (ClassCastException e) {
+ t = e;
+ } catch (ClassNotFoundException e) {
+ t = e;
+ } catch (InstantiationException e) {
+ t = e;
+ } catch (IllegalAccessException e) {
+ t = e;
+ }
+ logger.log(TreeLogger.ERROR, "Unable to load server class '"
+ + serverClassName + "'", t);
+ return false;
+ }
+
+ protected void compile(TreeLogger logger, ModuleDef moduleDef)
+ throws UnableToCompleteException {
+ CompilerOptions newOptions = new CompilerOptionsImpl(options);
+ newOptions.addModuleName(moduleDef.getName());
+ new Compiler(newOptions).run(logger);
+ }
+
+ @Override
+ protected HostedModeBaseOptions createOptions() {
+ return new HostedModeOptionsImpl();
+ }
+
+ @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);
+ }
+ };
+ }
+
+ @Override
+ protected void shutDownServer() {
+ if (server != null) {
+ try {
+ server.stop();
+ } catch (UnableToCompleteException e) {
+ // Already logged.
+ }
+ server = null;
+ }
+
+ if (tempWorkDir) {
+ Util.recursiveDelete(options.getWorkDir(), false);
+ }
+ }
+
+ @Override
+ protected int startUpServer() {
+ tempWorkDir = options.getWorkDir() == null;
+ if (tempWorkDir) {
+ try {
+ options.setWorkDir(Utility.makeTemporaryDirectory(null, "gwtc"));
+ } catch (IOException e) {
+ System.err.println("Unable to create hosted mode work directory");
+ e.printStackTrace();
+ return -1;
+ }
+ }
+
+ for (String moduleName : options.getModuleNames()) {
+ TreeLogger linkLogger = getTopLogger().branch(TreeLogger.DEBUG,
+ "Prelinking module " + moduleName);
+ try {
+ ModuleDef module = ModuleDefLoader.loadFromClassPath(linkLogger,
+ moduleName);
+
+ // TODO: Validate servlet tags.
+ String[] servletPaths = module.getServletPaths();
+ if (servletPaths.length > 0) {
+ linkLogger.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());
+ // }
+ }
+ }
+ } catch (UnableToCompleteException e) {
+ // Already logged.
+ return -1;
+ }
+ }
+
+ try {
+ TreeLogger serverLogger = getTopLogger().branch(TreeLogger.INFO,
+ "Starting HTTP on port " + getPort(), null);
+ server = launcher.start(serverLogger, getPort(), options.getWarDir());
+ assert (server != null);
+ return server.getPort();
+ } catch (BindException e) {
+ System.err.println("Port "
+ + getPort()
+ + " is already is use; you probably still have another session active");
+ } catch (Exception e) {
+ System.err.println("Unable to start embedded HTTP server");
+ e.printStackTrace();
+ }
+ return -1;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/HostedModeBase.java b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
new file mode 100644
index 0000000..f351ff8
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
@@ -0,0 +1,685 @@
+/*
+ * 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;
+
+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.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.BrowserWidget;
+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.ModuleSpaceHost;
+import com.google.gwt.dev.shell.PlatformSpecific;
+import com.google.gwt.dev.shell.ShellMainWindow;
+import com.google.gwt.dev.shell.ShellModuleSpaceHost;
+import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
+import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
+import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
+import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
+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.AbstractTreeLogger;
+import com.google.gwt.util.tools.ArgHandlerFlag;
+import com.google.gwt.util.tools.ArgHandlerString;
+import com.google.gwt.util.tools.ToolBase;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.internal.Library;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The main executable class for the hosted mode shell.
+ */
+abstract class HostedModeBase implements BrowserWindowController {
+
+ /**
+ * Handles the -blacklist command line argument.
+ */
+ protected class ArgHandlerBlacklist extends ArgHandlerString {
+
+ @Override
+ public String[] getDefaultArgs() {
+ return new String[] {"-blacklist", ""};
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Prevents the user browsing URLs that match the specified regexes (comma or space separated)";
+ }
+
+ @Override
+ public String getTag() {
+ return "-blacklist";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"blacklist-string"};
+ }
+
+ @Override
+ public boolean setString(String blacklistStr) {
+ return BrowserWidgetHostChecker.blacklistRegexes(blacklistStr);
+ }
+ }
+
+ /**
+ * Handles the -noserver command line flag.
+ */
+ protected class ArgHandlerNoServerFlag extends ArgHandlerFlag {
+ @Override
+ public String getPurpose() {
+ return "Prevents the embedded Tomcat server from running, even if a port is specified";
+ }
+
+ @Override
+ public String getTag() {
+ return "-noserver";
+ }
+
+ @Override
+ public boolean setFlag() {
+ runTomcat = false;
+ return true;
+ }
+ }
+
+ /**
+ * Handles the -port command line flag.
+ */
+ protected class ArgHandlerPort extends ArgHandlerString {
+
+ @Override
+ public String[] getDefaultArgs() {
+ return new String[] {"-port", "8888"};
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Runs an embedded Tomcat instance on the specified port (defaults to 8888)";
+ }
+
+ @Override
+ public String getTag() {
+ return "-port";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"port-number | \"auto\""};
+ }
+
+ @Override
+ public boolean setString(String value) {
+ if (value.equals("auto")) {
+ port = 0;
+ } else {
+ try {
+ port = Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ System.err.println("A port must be an integer or \"auto\"");
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Handles the -whitelist command line flag.
+ */
+ protected class ArgHandlerWhitelist extends ArgHandlerString {
+
+ @Override
+ public String[] getDefaultArgs() {
+ return new String[] {"-whitelist", ""};
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Allows the user to browse URLs that match the specified regexes (comma or space separated)";
+ }
+
+ @Override
+ public String getTag() {
+ return "-whitelist";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"whitelist-string"};
+ }
+
+ @Override
+ public boolean setString(String whitelistStr) {
+ return BrowserWidgetHostChecker.whitelistRegexes(whitelistStr);
+ }
+ }
+
+ abstract class ArgProcessor extends ToolBase {
+ public ArgProcessor() {
+ registerHandler(getArgHandlerPort());
+ registerHandler(new ArgHandlerWhitelist());
+ registerHandler(new ArgHandlerBlacklist());
+ registerHandler(new ArgHandlerLogLevel(options));
+ registerHandler(new ArgHandlerGenDir(options));
+ registerHandler(new ArgHandlerScriptStyle(options));
+ registerHandler(new ArgHandlerEnableAssertions(options));
+ registerHandler(new ArgHandlerDisableAggressiveOptimization(options));
+ }
+
+ /*
+ * Overridden to make public.
+ */
+ @Override
+ public final boolean processArgs(String[] args) {
+ return super.processArgs(args);
+ }
+
+ /*
+ * Overridden to make abstract.
+ */
+ @Override
+ protected abstract String getName();
+ }
+
+ interface HostedModeBaseOptions extends JJSOptions, OptionLogLevel,
+ OptionGenDir {
+
+ /**
+ * The base shell work directory.
+ */
+ File getShellBaseWorkDir(ModuleDef moduleDef);
+ }
+
+ private class BrowserWidgetHostImpl implements BrowserWidgetHost {
+ public BrowserWidgetHostImpl() {
+ }
+
+ public void compile(ModuleDef moduleDef) throws UnableToCompleteException {
+ HostedModeBase.this.compile(getLogger(), moduleDef);
+ }
+
+ public void compile(String[] moduleNames) throws UnableToCompleteException {
+ for (int i = 0; i < moduleNames.length; i++) {
+ String moduleName = moduleNames[i];
+ ModuleDef moduleDef = loadModule(moduleName, getLogger());
+ compile(moduleDef);
+ }
+ }
+
+ public ModuleSpaceHost createModuleSpaceHost(BrowserWidget widget,
+ final String moduleName) throws UnableToCompleteException {
+ TreeLogger logger = getLogger();
+
+ // Switch to a wait cursor.
+ //
+ Shell widgetShell = widget.getShell();
+ try {
+ Cursor waitCursor = display.getSystemCursor(SWT.CURSOR_WAIT);
+ widgetShell.setCursor(waitCursor);
+
+ // Try to find an existing loaded version of the module def.
+ //
+ ModuleDef moduleDef = loadModule(moduleName, logger);
+ assert (moduleDef != null);
+
+ TypeOracle typeOracle = moduleDef.getTypeOracle(logger);
+ ShellModuleSpaceHost host = doCreateShellModuleSpaceHost(logger,
+ typeOracle, moduleDef);
+ return host;
+ } finally {
+ Cursor normalCursor = display.getSystemCursor(SWT.CURSOR_ARROW);
+ widgetShell.setCursor(normalCursor);
+ }
+ }
+
+ public TreeLogger getLogger() {
+ return getTopLogger();
+ }
+
+ public String normalizeURL(String whatTheUserTyped) {
+ return HostedModeBase.this.normalizeURL(whatTheUserTyped);
+ }
+
+ public BrowserWidget openNewBrowserWindow()
+ 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 {
+ // Force ToolBase to clinit, which causes SWT stuff to happen.
+ new ToolBase() {
+ };
+ // Correct menu on Mac OS X
+ Display.setAppName("GWT");
+ }
+
+ protected final HostedModeBaseOptions options;
+
+ /**
+ * Cheat on the first load's refresh by assuming the module loaded by
+ * {@link com.google.gwt.dev.shell.GWTShellServlet} is still fresh. This
+ * prevents a double-refresh on startup. Subsequent refreshes will trigger a
+ * real refresh.
+ */
+ private Set<String> alreadySeenModules = new HashSet<String>();
+
+ private BrowserWidgetHostImpl browserHost = new BrowserWidgetHostImpl();
+
+ private final List<Shell> browserShells = new ArrayList<Shell>();
+
+ /**
+ * Use the default display; constructing a new one would make instantiating
+ * multiple GWTShells fail with a mysterious exception.
+ */
+ private final Display display = Display.getDefault();
+
+ private boolean headlessMode = false;
+
+ private ShellMainWindow mainWnd;
+
+ private int port;
+
+ private boolean runTomcat = true;
+
+ private boolean started;
+
+ private final List<String> startupUrls = new ArrayList<String>();
+
+ public HostedModeBase() {
+ // Set any platform specific system properties.
+ BootStrapPlatform.init();
+ BootStrapPlatform.applyPlatformHacks();
+ options = createOptions();
+ }
+
+ public final void addStartupURL(String url) {
+ startupUrls.add(url);
+ }
+
+ public final void closeAllBrowserWindows() {
+ while (!browserShells.isEmpty()) {
+ browserShells.get(0).dispose();
+ }
+ }
+
+ public final int getPort() {
+ return port;
+ }
+
+ public TreeLogger getTopLogger() {
+ return mainWnd.getLogger();
+ }
+
+ public final boolean hasBrowserWindowsOpen() {
+ if (browserShells.isEmpty()) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Launch the arguments as Urls in separate windows.
+ */
+ public final void launchStartupUrls(final TreeLogger logger) {
+ if (startupUrls != null) {
+ // Launch a browser window for each startup url.
+ //
+ String startupURL = "";
+ try {
+ for (String prenormalized : startupUrls) {
+ startupURL = normalizeURL(prenormalized);
+ logger.log(TreeLogger.TRACE, "Starting URL: " + startupURL, null);
+ BrowserWidget bw = openNewBrowserWindow();
+ bw.go(startupURL);
+ }
+ } catch (UnableToCompleteException e) {
+ logger.log(TreeLogger.ERROR,
+ "Unable to open new window for startup URL: " + startupURL, null);
+ }
+ }
+ }
+
+ public final String normalizeURL(String unknownUrlText) {
+ if (unknownUrlText.indexOf(":") != -1) {
+ // Assume it's a full url.
+ return unknownUrlText;
+ }
+
+ // Assume it's a trailing url path.
+ //
+ if (unknownUrlText.length() > 0 && unknownUrlText.charAt(0) == '/') {
+ unknownUrlText = unknownUrlText.substring(1);
+ }
+
+ int prt = getPort();
+ if (prt != 80 && prt != 0) {
+ // CHECKSTYLE_OFF: Not really an assembled error message, so no space
+ // after ':'.
+ return "http://localhost:" + prt + "/" + unknownUrlText;
+ // CHECKSTYLE_ON
+ } else {
+ return "http://localhost/" + unknownUrlText;
+ }
+ }
+
+ /**
+ * Called directly by ShellMainWindow and indirectly via BrowserWidgetHost.
+ */
+ public final BrowserWidget openNewBrowserWindow()
+ throws UnableToCompleteException {
+ boolean succeeded = false;
+ Shell s = createTrackedBrowserShell();
+ try {
+ BrowserWidget bw = PlatformSpecific.createBrowserWidget(getTopLogger(),
+ s, browserHost);
+
+ if (mainWnd != null) {
+ Rectangle r = mainWnd.getShell().getBounds();
+ int n = browserShells.size() + 1;
+ s.setBounds(r.x + n * 50, r.y + n * 50, 800, 600);
+ } else {
+ s.setSize(800, 600);
+ }
+
+ if (!isHeadless()) {
+ s.open();
+ }
+
+ bw.onFirstShown();
+ succeeded = true;
+ return bw;
+ } finally {
+ if (!succeeded) {
+ s.dispose();
+ }
+ }
+ }
+
+ /**
+ * 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() {
+ try {
+ if (!startUp()) {
+ // Failed to initalize.
+ return;
+ }
+
+ // Eager AWT initialization for OS X to ensure safe coexistence with SWT.
+ BootStrapPlatform.maybeInitializeAWT();
+
+ // Tomcat's running now, so launch browsers for startup urls now.
+ launchStartupUrls(getTopLogger());
+
+ pumpEventLoop();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ shutDown();
+ }
+ }
+
+ public final void setPort(int port) {
+ this.port = port;
+ }
+
+ public final void setRunTomcat(boolean run) {
+ runTomcat = run;
+ }
+
+ /**
+ * Compiles a module.
+ */
+ protected abstract void compile(TreeLogger logger, ModuleDef moduleDef)
+ throws UnableToCompleteException;
+
+ protected abstract HostedModeBaseOptions createOptions();
+
+ protected abstract ArtifactAcceptor doCreateArtifactAcceptor(ModuleDef module);
+
+ /**
+ * Creates an instance of ShellModuleSpaceHost (or a derived class) using the
+ * specified constituent parts. This method is made to be overridden for
+ * subclasses that need to change the behavior of ShellModuleSpaceHost.
+ *
+ * @param logger TreeLogger to use
+ * @param typeOracle
+ * @param moduleDef
+ * @param genDir
+ * @return ShellModuleSpaceHost instance
+ */
+ protected final ShellModuleSpaceHost doCreateShellModuleSpaceHost(
+ TreeLogger logger, TypeOracle typeOracle, ModuleDef moduleDef) {
+ // Clear out the shell temp directory.
+ Util.recursiveDelete(options.getShellBaseWorkDir(moduleDef), true);
+ return new ShellModuleSpaceHost(logger, typeOracle, moduleDef,
+ options.getGenDir(), new File(options.getShellBaseWorkDir(moduleDef),
+ "gen"), doCreateArtifactAcceptor(moduleDef));
+ }
+
+ /**
+ * Can be override to change the default log level in subclasses. JUnit does
+ * this for example.
+ */
+ protected Type doGetDefaultLogLevel() {
+ return Type.INFO;
+ }
+
+ /**
+ * Derived classes can override to prevent automatic update checking.
+ */
+ protected boolean doShouldCheckForUpdates() {
+ return true;
+ }
+
+ /**
+ * Derived classes can override to set a default port.
+ */
+ protected ArgHandlerPort getArgHandlerPort() {
+ return new ArgHandlerPort();
+ }
+
+ protected final BrowserWidgetHost getBrowserHost() {
+ return browserHost;
+ }
+
+ protected void initializeLogger() {
+ final AbstractTreeLogger logger = mainWnd.getLogger();
+ logger.setMaxDetail(options.getLogLevel());
+ }
+
+ /**
+ * By default we will open the application window.
+ *
+ * @return true if we are running in headless mode
+ */
+ protected final boolean isHeadless() {
+ return headlessMode;
+ }
+
+ protected boolean notDone() {
+ if (!mainWnd.isDisposed()) {
+ return true;
+ }
+ if (!browserShells.isEmpty()) {
+ return true;
+ }
+ return false;
+ }
+
+ protected final void pumpEventLoop() {
+ TreeLogger logger = getTopLogger();
+
+ // Run the event loop. When there are no open shells, quit.
+ //
+ while (notDone()) {
+ try {
+ if (!display.readAndDispatch()) {
+ sleep();
+ }
+ } 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;
+ }
+
+ protected final void shutDown() {
+ if (!runTomcat) {
+ return;
+ }
+ shutDownServer();
+ }
+
+ protected abstract void shutDownServer();
+
+ protected void sleep() {
+ display.sleep();
+ }
+
+ protected final boolean startUp() {
+ if (started) {
+ throw new IllegalStateException("Startup code has already been run");
+ }
+
+ started = true;
+
+ loadRequiredNativeLibs();
+
+ // Create the main app window.
+ openAppWindow();
+
+ // Initialize the logger.
+ //
+ initializeLogger();
+
+ if (runTomcat) {
+ int resultPort = startUpServer();
+ if (resultPort < 0) {
+ return false;
+ }
+ port = resultPort;
+ }
+
+ return true;
+ }
+
+ protected abstract int startUpServer();
+
+ private Shell createTrackedBrowserShell() {
+ final Shell shell = new Shell(display);
+ FillLayout fillLayout = new FillLayout();
+ fillLayout.marginWidth = 0;
+ fillLayout.marginHeight = 0;
+ shell.setLayout(fillLayout);
+ browserShells.add(shell);
+ shell.addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ if (e.widget == shell) {
+ browserShells.remove(shell);
+ }
+ }
+ });
+
+ shell.setImages(ShellMainWindow.getIcons());
+
+ return shell;
+ }
+
+ private void loadRequiredNativeLibs() {
+ String libName = null;
+ try {
+ libName = "swt";
+ Library.loadLibrary(libName);
+ } catch (UnsatisfiedLinkError e) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Unable to load required native library '" + libName + "'");
+ sb.append("\n\tPlease specify the JVM startup argument ");
+ sb.append("\"-Djava.library.path\"");
+ throw new RuntimeException(sb.toString(), e);
+ }
+ }
+
+ private void openAppWindow() {
+ final Shell shell = new Shell(display);
+
+ FillLayout fillLayout = new FillLayout();
+ fillLayout.marginWidth = 0;
+ fillLayout.marginHeight = 0;
+ shell.setLayout(fillLayout);
+
+ shell.setImages(ShellMainWindow.getIcons());
+
+ boolean checkForUpdates = doShouldCheckForUpdates();
+
+ mainWnd = new ShellMainWindow(this, shell, runTomcat ? getPort() : 0,
+ checkForUpdates);
+
+ shell.setSize(700, 600);
+ if (!isHeadless()) {
+ shell.open();
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/ShellOptions.java b/dev/core/src/com/google/gwt/dev/HostedModeOptions.java
similarity index 83%
rename from dev/core/src/com/google/gwt/dev/ShellOptions.java
rename to dev/core/src/com/google/gwt/dev/HostedModeOptions.java
index 71ea4e8..53ed608 100644
--- a/dev/core/src/com/google/gwt/dev/ShellOptions.java
+++ b/dev/core/src/com/google/gwt/dev/HostedModeOptions.java
@@ -19,11 +19,11 @@
import com.google.gwt.dev.util.arg.OptionExtraDir;
import com.google.gwt.dev.util.arg.OptionGenDir;
import com.google.gwt.dev.util.arg.OptionLogLevel;
-import com.google.gwt.dev.util.arg.OptionOutDir;
+import com.google.gwt.dev.util.arg.OptionWarDir;
/**
* The complete set of options for the GWT compiler.
*/
-public interface ShellOptions extends JJSOptions, OptionLogLevel, OptionOutDir,
- OptionGenDir, OptionExtraDir {
+public interface HostedModeOptions extends JJSOptions, OptionLogLevel,
+ OptionExtraDir, OptionWarDir, OptionGenDir {
}
diff --git a/dev/core/src/com/google/gwt/dev/ShellOptions.java b/dev/core/src/com/google/gwt/dev/LegacyCompilerOptions.java
similarity index 65%
copy from dev/core/src/com/google/gwt/dev/ShellOptions.java
copy to dev/core/src/com/google/gwt/dev/LegacyCompilerOptions.java
index 71ea4e8..c72bcc1 100644
--- a/dev/core/src/com/google/gwt/dev/ShellOptions.java
+++ b/dev/core/src/com/google/gwt/dev/LegacyCompilerOptions.java
@@ -15,15 +15,13 @@
*/
package com.google.gwt.dev;
-import com.google.gwt.dev.jjs.JJSOptions;
-import com.google.gwt.dev.util.arg.OptionExtraDir;
-import com.google.gwt.dev.util.arg.OptionGenDir;
-import com.google.gwt.dev.util.arg.OptionLogLevel;
-import com.google.gwt.dev.util.arg.OptionOutDir;
+import com.google.gwt.dev.Link.LegacyLinkOptions;
+import com.google.gwt.dev.Precompile.PrecompileOptions;
/**
* The complete set of options for the GWT compiler.
*/
-public interface ShellOptions extends JJSOptions, OptionLogLevel, OptionOutDir,
- OptionGenDir, OptionExtraDir {
+public interface LegacyCompilerOptions extends PrecompileOptions, LegacyLinkOptions,
+ OptionLocalWorkers {
}
+
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/Link.java b/dev/core/src/com/google/gwt/dev/Link.java
index f10d910..b16262f 100644
--- a/dev/core/src/com/google/gwt/dev/Link.java
+++ b/dev/core/src/com/google/gwt/dev/Link.java
@@ -28,9 +28,10 @@
import com.google.gwt.dev.cfg.StaticPropertyOracle;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
-import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
+import com.google.gwt.dev.util.arg.ArgHandlerWarDir;
import com.google.gwt.dev.util.arg.OptionExtraDir;
import com.google.gwt.dev.util.arg.OptionOutDir;
+import com.google.gwt.dev.util.arg.OptionWarDir;
import java.io.File;
import java.util.HashMap;
@@ -43,15 +44,21 @@
/**
* Options for Link.
*/
+ public interface LegacyLinkOptions extends CompileTaskOptions, OptionOutDir {
+ }
+
+ /**
+ * Options for Link.
+ */
public interface LinkOptions extends CompileTaskOptions, OptionExtraDir,
- OptionOutDir {
+ OptionWarDir {
}
static class ArgProcessor extends CompileArgProcessor {
public ArgProcessor(LinkOptions options) {
super(options);
registerHandler(new ArgHandlerExtraDir(options));
- registerHandler(new ArgHandlerOutDir(options));
+ registerHandler(new ArgHandlerWarDir(options));
}
@Override
@@ -67,7 +74,7 @@
LinkOptions {
private File extraDir;
- private File outDir;
+ private File warDir;
public LinkOptionsImpl() {
}
@@ -79,26 +86,36 @@
public void copyFrom(LinkOptions other) {
super.copyFrom(other);
setExtraDir(other.getExtraDir());
- setOutDir(other.getOutDir());
+ setWarDir(other.getWarDir());
}
public File getExtraDir() {
return extraDir;
}
- public File getOutDir() {
- return outDir;
+ public File getWarDir() {
+ return warDir;
}
public void setExtraDir(File extraDir) {
this.extraDir = extraDir;
}
- public void setOutDir(File outDir) {
- this.outDir = outDir;
+ public void setWarDir(File warDir) {
+ this.warDir = warDir;
}
}
+ public static void legacyLink(TreeLogger logger, ModuleDef module,
+ Precompilation precompilation, File[] resultFiles, File outDir)
+ throws UnableToCompleteException {
+ StandardLinkerContext linkerContext = new StandardLinkerContext(logger,
+ module, precompilation.getUnifiedAst().getOptions());
+ ArtifactSet artifacts = doLink(logger, linkerContext, precompilation,
+ resultFiles);
+ doProduceLegacyOutput(logger, artifacts, linkerContext, module, outDir);
+ }
+
public static ArtifactSet link(TreeLogger logger, ModuleDef module,
Precompilation precompilation, File[] resultFiles)
throws UnableToCompleteException {
@@ -157,45 +174,30 @@
return linkerContext.invokeLink(logger);
}
- private static void doProduceOutput(TreeLogger logger, ArtifactSet artifacts,
- StandardLinkerContext linkerContext, ModuleDef module, File outDir,
- File extraDir) throws UnableToCompleteException {
- boolean warnOnExtra = false;
- File moduleExtraDir;
- if (extraDir == null) {
- /*
- * Legacy behavior for backwards compatibility; if the extra directory is
- * not specified, make it a sibling to the deploy directory, with -aux.
- */
- String deployDir = module.getDeployTo();
- deployDir = deployDir.substring(0, deployDir.length() - 1) + "-aux";
- moduleExtraDir = new File(outDir, deployDir);
-
- /*
- * Only warn when we create a new legacy extra dir.
- */
- warnOnExtra = !moduleExtraDir.exists();
- } else {
- moduleExtraDir = new File(extraDir, module.getDeployTo());
- }
-
- File moduleOutDir = new File(outDir, module.getDeployTo());
+ private static void doProduceLegacyOutput(TreeLogger logger,
+ ArtifactSet artifacts, StandardLinkerContext linkerContext,
+ ModuleDef module, File outDir) throws UnableToCompleteException {
+ File moduleOutDir = new File(outDir, module.getName());
+ File moduleExtraDir = new File(outDir, module.getName() + "-aux");
Util.recursiveDelete(moduleOutDir, true);
Util.recursiveDelete(moduleExtraDir, true);
linkerContext.produceOutputDirectory(logger, artifacts, moduleOutDir,
moduleExtraDir);
+ logger.log(TreeLogger.INFO, "Link succeeded");
+ }
- /*
- * Warn on legacy extra directory, but only if: 1) It didn't exist before.
- * 2) We just created it.
- */
- if (warnOnExtra && moduleExtraDir.exists()) {
- logger.log(
- TreeLogger.WARN,
- "Non-public artificats were produced in '"
- + moduleExtraDir.getAbsolutePath()
- + "' within the public output folder; use -extra to specify an alternate location");
+ private static void doProduceOutput(TreeLogger logger, ArtifactSet artifacts,
+ StandardLinkerContext linkerContext, ModuleDef module, File outDir,
+ File extraDir) throws UnableToCompleteException {
+ File moduleOutDir = new File(outDir, module.getName());
+ File moduleExtraDir = (extraDir == null) ? null : new File(extraDir,
+ module.getName());
+ Util.recursiveDelete(moduleOutDir, true);
+ if (moduleExtraDir != null) {
+ Util.recursiveDelete(moduleExtraDir, true);
}
+ linkerContext.produceOutputDirectory(logger, artifacts, moduleOutDir,
+ moduleExtraDir);
logger.log(TreeLogger.INFO, "Link succeeded");
}
@@ -224,8 +226,6 @@
}
}
- private ModuleDef module;
-
private final LinkOptionsImpl options;
public Link(LinkOptions options) {
@@ -233,48 +233,50 @@
}
public boolean run(TreeLogger logger) throws UnableToCompleteException {
- module = ModuleDefLoader.loadFromClassPath(logger, options.getModuleName());
+ for (String moduleName : options.getModuleNames()) {
+ File compilerWorkDir = options.getCompilerWorkDir(moduleName);
+ ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, moduleName);
- File precompilationFile = new File(options.getCompilerWorkDir(),
- Precompile.PRECOMPILATION_FILENAME);
- if (!precompilationFile.exists()) {
- logger.log(TreeLogger.ERROR, "File not found '"
- + precompilationFile.getAbsolutePath()
- + "'; please run Precompile first");
- return false;
- }
-
- Precompilation precompilation;
- try {
- precompilation = Util.readFileAsObject(precompilationFile,
- Precompilation.class);
- } catch (ClassNotFoundException e) {
- logger.log(TreeLogger.ERROR, "Unable to deserialize '"
- + precompilationFile.getAbsolutePath() + "'", e);
- return false;
- }
- Permutation[] perms = precompilation.getPermutations();
- File[] resultFiles = new File[perms.length];
- for (int i = 0; i < perms.length; ++i) {
- resultFiles[i] = CompilePerms.makePermFilename(
- options.getCompilerWorkDir(), i);
- if (!resultFiles[i].exists()) {
+ File precompilationFile = new File(compilerWorkDir,
+ Precompile.PRECOMPILATION_FILENAME);
+ if (!precompilationFile.exists()) {
logger.log(TreeLogger.ERROR, "File not found '"
+ precompilationFile.getAbsolutePath()
- + "'; please compile all permutations");
+ + "'; please run Precompile first");
return false;
}
+
+ Precompilation precompilation;
+ try {
+ precompilation = Util.readFileAsObject(precompilationFile,
+ Precompilation.class);
+ } catch (ClassNotFoundException e) {
+ logger.log(TreeLogger.ERROR, "Unable to deserialize '"
+ + precompilationFile.getAbsolutePath() + "'", e);
+ return false;
+ }
+ Permutation[] perms = precompilation.getPermutations();
+ File[] resultFiles = new File[perms.length];
+ for (int i = 0; i < perms.length; ++i) {
+ resultFiles[i] = CompilePerms.makePermFilename(compilerWorkDir, i);
+ if (!resultFiles[i].exists()) {
+ logger.log(TreeLogger.ERROR, "File not found '"
+ + precompilationFile.getAbsolutePath()
+ + "'; please compile all permutations");
+ return false;
+ }
+ }
+
+ TreeLogger branch = logger.branch(TreeLogger.INFO, "Linking module "
+ + module.getName());
+ StandardLinkerContext linkerContext = new StandardLinkerContext(branch,
+ module, precompilation.getUnifiedAst().getOptions());
+ ArtifactSet artifacts = doLink(branch, linkerContext, precompilation,
+ resultFiles);
+
+ doProduceOutput(branch, artifacts, linkerContext, module,
+ options.getWarDir(), options.getExtraDir());
}
-
- TreeLogger branch = logger.branch(TreeLogger.INFO, "Linking module "
- + module.getName());
- StandardLinkerContext linkerContext = new StandardLinkerContext(branch,
- module, precompilation.getUnifiedAst().getOptions());
- ArtifactSet artifacts = doLink(branch, linkerContext, precompilation,
- resultFiles);
-
- doProduceOutput(branch, artifacts, linkerContext, module,
- options.getOutDir(), options.getExtraDir());
return true;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index bb96be3..b8f6997 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -351,50 +351,44 @@
}
public boolean run(TreeLogger logger) throws UnableToCompleteException {
- if (options.isValidateOnly()) {
- init(logger);
- TreeLogger branch = logger.branch(TreeLogger.INFO,
- "Validating compilation " + module.getName());
- if (validate(branch, options, module, options.getGenDir(),
- options.getCompilerWorkDir())) {
+ for (String moduleName : options.getModuleNames()) {
+ File compilerWorkDir = options.getCompilerWorkDir(moduleName);
+ Util.recursiveDelete(compilerWorkDir, true);
+ compilerWorkDir.mkdirs();
+
+ this.module = ModuleDefLoader.loadFromClassPath(logger, moduleName);
+
+ // TODO: All JDT checks now before even building TypeOracle?
+ module.getCompilationState(logger);
+
+ if (options.isValidateOnly()) {
+ TreeLogger branch = logger.branch(TreeLogger.INFO,
+ "Validating compilation " + module.getName());
+ if (!validate(branch, options, module, options.getGenDir(),
+ compilerWorkDir)) {
+ branch.log(TreeLogger.ERROR, "Validation failed");
+ return false;
+ }
branch.log(TreeLogger.INFO, "Validation succeeded");
- return true;
} else {
- branch.log(TreeLogger.ERROR, "Validation failed");
- return false;
- }
- } else {
- init(logger);
- TreeLogger branch = logger.branch(TreeLogger.INFO, "Precompiling module "
- + module.getName());
- Precompilation precompilation = precompile(branch, options, module,
- options.getGenDir(), options.getCompilerWorkDir());
- if (precompilation != null) {
- Util.writeObjectAsFile(branch, new File(options.getCompilerWorkDir(),
+ TreeLogger branch = logger.branch(TreeLogger.INFO,
+ "Precompiling module " + module.getName());
+ Precompilation precompilation = precompile(branch, options, module,
+ options.getGenDir(), compilerWorkDir);
+ if (precompilation == null) {
+ branch.log(TreeLogger.ERROR, "Precompilation failed");
+ return false;
+ }
+ Util.writeObjectAsFile(branch, new File(compilerWorkDir,
PRECOMPILATION_FILENAME), precompilation);
- Util.writeStringAsFile(branch, new File(options.getCompilerWorkDir(),
+ Util.writeStringAsFile(branch, new File(compilerWorkDir,
PERM_COUNT_FILENAME),
String.valueOf(precompilation.getPermutations().length));
branch.log(TreeLogger.INFO,
"Precompilation succeeded, number of permutations: "
+ precompilation.getPermutations().length);
- return true;
}
- branch.log(TreeLogger.ERROR, "Precompilation failed");
- return false;
}
- }
-
- private void init(TreeLogger logger) throws UnableToCompleteException {
- // Clean out the work dir and/or create it.
- File compilerWorkDir = options.getCompilerWorkDir();
- Util.recursiveDelete(compilerWorkDir, true);
- compilerWorkDir.mkdirs();
-
- this.module = ModuleDefLoader.loadFromClassPath(logger,
- options.getModuleName());
-
- // TODO: All JDT checks now before even building TypeOracle?
- module.getCompilationState(logger);
+ return true;
}
}
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 cbc3e39..8f66eaf 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -85,8 +85,6 @@
private Class<? extends Linker> activePrimaryLinker;
- private String deployTo;
-
private final List<String> entryPointTypeNames = new ArrayList<String>();
private final Set<File> gwtXmlFiles = new HashSet<File>();
@@ -269,17 +267,6 @@
return lazyCompilationState;
}
- /**
- * Returns the desired deployment path within the output directory. The
- * returned value will start and end with a <code>'/'</code> character.
- */
- public String getDeployTo() {
- String result = (deployTo == null) ? ('/' + getName() + '/') : deployTo;
- assert result.startsWith("/");
- assert result.endsWith("/");
- return result;
- }
-
public synchronized String[] getEntryPointTypeNames() {
final int n = entryPointTypeNames.size();
return entryPointTypeNames.toArray(new String[n]);
@@ -407,26 +394,6 @@
}
/**
- * Set the deployment path for this module. Setting this value to
- * <code>null</code> or the empty string will default to the fully-qualified
- * module name.
- */
- public void setDeployTo(String deployTo) {
- if (deployTo != null && deployTo.length() == 0) {
- deployTo = null;
- } else {
- assert deployTo.startsWith("/");
- // Ensure ends with trailing slash.
- if (!deployTo.endsWith("/")) {
- deployTo += '/';
- }
- assert deployTo.endsWith("/");
- }
-
- this.deployTo = deployTo;
- }
-
- /**
* Override the module's apparent name. Setting this value to
* <code>null<code> will disable the name override.
*/
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
index bd394eb..a0c2e94 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
@@ -921,7 +921,6 @@
}
protected final String __module_1_rename_to = "";
- protected final String __module_2_deploy_to = "";
private final PropertyAttrCvt bindingPropAttrCvt = new PropertyAttrCvt(
BindingProperty.class);
@@ -968,21 +967,11 @@
registerAttributeConverter(Class.class, classAttrCvt);
}
- protected Schema __module_begin(NullableName renameTo, String deployTo)
- throws UnableToCompleteException {
-
- if (deployTo != null && deployTo.length() > 0) {
- // Only absolute paths, although it is okay to have multiple slashes.
- if (!deployTo.startsWith("/")) {
- logger.log(TreeLogger.ERROR, "deploy-to '" + deployTo
- + "' must begin with forward slash (e.g. '/foo')");
- throw new UnableToCompleteException();
- }
- }
+ protected Schema __module_begin(NullableName renameTo) {
return bodySchema;
}
- protected void __module_end(NullableName renameTo, String deployTo) {
+ protected void __module_end(NullableName renameTo) {
// Maybe infer source and public.
//
if (!foundExplicitSourceOrSuperSource) {
@@ -997,7 +986,6 @@
// We do this in __module_end so this value is never inherited
moduleDef.setNameOverride(renameTo.token);
- moduleDef.setDeployTo(deployTo);
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java b/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java
new file mode 100644
index 0000000..e2bb884
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java
@@ -0,0 +1,31 @@
+/*
+ * 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.UnableToCompleteException;
+
+/**
+ * Interface to the browser window controller.
+ */
+public interface BrowserWindowController {
+ void closeAllBrowserWindows();
+
+ boolean hasBrowserWindowsOpen();
+
+ String normalizeURL(String string);
+
+ BrowserWidget openNewBrowserWindow() throws UnableToCompleteException;
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/shell/DialogBase.java b/dev/core/src/com/google/gwt/dev/shell/DialogBase.java
index 8642486..358abdc 100644
--- a/dev/core/src/com/google/gwt/dev/shell/DialogBase.java
+++ b/dev/core/src/com/google/gwt/dev/shell/DialogBase.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.dev.shell;
-import com.google.gwt.dev.GWTShell;
-
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
@@ -136,7 +134,7 @@
Shell parent = getParent();
shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL
| SWT.RESIZE);
- shell.setImages(GWTShell.getIcons());
+ shell.setImages(ShellMainWindow.getIcons());
shell.setText(getText());
shell.setLayout(new FillLayout());
diff --git a/dev/core/src/com/google/gwt/dev/shell/GWTShellServletFilter.java b/dev/core/src/com/google/gwt/dev/shell/GWTShellServletFilter.java
deleted file mode 100644
index 4b5c6a6..0000000
--- a/dev/core/src/com/google/gwt/dev/shell/GWTShellServletFilter.java
+++ /dev/null
@@ -1,155 +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;
-import com.google.gwt.core.ext.linker.ArtifactSet;
-import com.google.gwt.core.ext.linker.impl.StandardLinkerContext;
-import com.google.gwt.dev.ShellOptions;
-import com.google.gwt.dev.cfg.ModuleDef;
-
-import org.apache.commons.collections.map.AbstractReferenceMap;
-import org.apache.commons.collections.map.ReferenceIdentityMap;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * Built-in servlet for convenient access to the public path of a specified
- * module.
- */
-public class GWTShellServletFilter implements Filter {
-
- private final Map<String, ModuleDef> autogenScripts = new HashMap<String, ModuleDef>();
- /**
- * Maintains a persistent map of linker contexts for each module, for
- * incremental re-link with new generated artifacts.
- */
- @SuppressWarnings("unchecked")
- private final Map<ModuleDef, StandardLinkerContext> linkerContextsByModule = new ReferenceIdentityMap(
- AbstractReferenceMap.WEAK, AbstractReferenceMap.HARD, true);
-
- private TreeLogger logger;
-
- private final ShellOptions options;
-
- public GWTShellServletFilter(TreeLogger logger, ShellOptions options,
- ModuleDef[] moduleDefs) {
- this.logger = logger;
- this.options = options;
- for (ModuleDef moduleDef : moduleDefs) {
- String scriptName = moduleDef.getDeployTo() + moduleDef.getName()
- + ".nocache.js";
- autogenScripts.put(scriptName, moduleDef);
- }
- }
-
- public void destroy() {
- }
-
- public void doFilter(ServletRequest req, ServletResponse resp,
- FilterChain chain) throws IOException, ServletException {
-
- if (req instanceof HttpServletRequest) {
- HttpServletRequest request = (HttpServletRequest) req;
- String pathInfo = request.getRequestURI();
- logger.log(TreeLogger.TRACE, "Request for: " + pathInfo);
- ModuleDef moduleDef = autogenScripts.get(pathInfo);
- if (moduleDef != null) {
- /*
- * If the '?compiled' request property is specified, don't
- * auto-generate.
- *
- * TODO(scottb): does this even do anything anymore?
- *
- * TODO(scottb): how do we avoid clobbering a compiled selection script?
- */
- if (req.getParameter("compiled") == null) {
- try {
- // Run the linkers for hosted mode.
- hostedModeLink(logger.branch(TreeLogger.TRACE, "Request for '"
- + pathInfo + "' maps to script generator for module '"
- + moduleDef.getName() + "'"), moduleDef);
- } catch (UnableToCompleteException e) {
- /*
- * The error will have already been logged. Continue, since this
- * could actually be a request for a static file that happens to
- * have an unfortunately confusing name.
- */
- }
- }
- }
- }
-
- // Do normal handling, knowing that the linkers may have run earlier to
- // produce files we are just about to serve.
- chain.doFilter(req, resp);
- }
-
- public void init(FilterConfig filterConfig) throws ServletException {
- }
-
- /**
- * Called when new generated artifacts are produced.
- */
- public void relink(TreeLogger logger, ModuleDef moduleDef,
- ArtifactSet newArtifacts) throws UnableToCompleteException {
- StandardLinkerContext context = linkerContextsByModule.get(moduleDef);
- assert context != null;
-
- ArtifactSet artifacts = context.invokeRelink(logger, newArtifacts);
- dumpArtifacts(logger, moduleDef, context, artifacts);
- }
-
- private void dumpArtifacts(TreeLogger logger, ModuleDef moduleDef,
- StandardLinkerContext context, ArtifactSet artifacts)
- throws UnableToCompleteException {
- File outputPath = new File(options.getOutDir(), moduleDef.getDeployTo());
- File extraPath = null;
- if (options.getExtraDir() != null) {
- extraPath = new File(options.getExtraDir(), moduleDef.getDeployTo());
- }
- context.produceOutputDirectory(logger, artifacts, outputPath, extraPath);
- }
-
- private void hostedModeLink(TreeLogger logger, ModuleDef moduleDef)
- throws UnableToCompleteException {
- String moduleName = moduleDef.getName();
- logger.log(TreeLogger.TRACE, "Running linkers for module " + moduleName);
-
- // TODO: blow away artifacts from a previous link.
-
- // Perform the initial link.
- StandardLinkerContext context = new StandardLinkerContext(logger,
- moduleDef, options);
- ArtifactSet artifacts = context.invokeLink(logger);
- dumpArtifacts(logger, moduleDef, context, artifacts);
-
- // Save off a new active link state (which may overwrite an old one).
- linkerContextsByModule.put(moduleDef, context);
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java b/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java
index d9ef731..ffec980 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ServletContainerLauncher.java
@@ -20,8 +20,6 @@
import java.io.File;
import java.net.BindException;
-import javax.servlet.Filter;
-
/**
* Defines the service provider interface for launching servlet containers that
* can be used by the shell.
@@ -34,12 +32,10 @@
* @param logger the server logger
* @param port the TCP port to serve on
* @param appRootDir the base WAR directory
- * @param filter a servlet filter that must be installed on the root path to
- * serve generated files
* @return the launch servlet contained
* @throws BindException if the requested port is already in use
* @throws Exception if the server fails to start for any other reason
*/
- ServletContainer start(TreeLogger logger, int port, File appRootDir,
- Filter filter) throws BindException, Exception;
+ ServletContainer start(TreeLogger logger, int port, File appRootDir)
+ throws BindException, Exception;
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java b/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
index 1e46069..031cc44 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
@@ -17,7 +17,6 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.GWTShell;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.TreeLoggerWidget;
@@ -30,6 +29,7 @@
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
@@ -46,7 +46,6 @@
private class Toolbar extends HeaderBarBase {
private ToolItem about;
-
private ToolItem clearLog;
private ToolItem collapseAll;
private ToolItem expandAll;
@@ -60,9 +59,9 @@
newWindow.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
- String startupUrl = serverWindow.normalizeURL("/");
+ String startupUrl = browserWindowController.normalizeURL("/");
try {
- BrowserWidget bw = serverWindow.openNewBrowserWindow();
+ BrowserWidget bw = browserWindowController.openNewBrowserWindow();
bw.go(startupUrl);
} catch (UnableToCompleteException e) {
getLogger().log(TreeLogger.ERROR,
@@ -137,6 +136,23 @@
}
}
+ private static Image[] icons;
+
+ /**
+ * Well-known place to get the GWT icons.
+ */
+ public static Image[] getIcons() {
+ // Make sure icon images are loaded.
+ //
+ if (icons == null) {
+ icons = new Image[] {
+ LowLevel.loadImage("icon16.png"), LowLevel.loadImage("icon24.png"),
+ LowLevel.loadImage("icon32.png"), LowLevel.loadImage("icon48.png"),
+ LowLevel.loadImage("icon128.png")};
+ }
+ return icons;
+ }
+
private static String verify(String hash) {
char[] in = hash.toCharArray();
char[] ou = new char[in.length];
@@ -156,19 +172,19 @@
return String.valueOf(ou);
}
+ private BrowserWindowController browserWindowController;
+
private Color colorWhite;
private TreeLoggerWidget logPane;
- private GWTShell serverWindow;
-
private Toolbar toolbar;
- public ShellMainWindow(GWTShell serverWindow, final Shell parent,
- int serverPort, boolean checkForUpdates) {
+ public ShellMainWindow(BrowserWindowController browserWindowController,
+ final Shell parent, int serverPort, boolean checkForUpdates) {
super(parent, SWT.NONE);
- this.serverWindow = serverWindow;
+ this.browserWindowController = browserWindowController;
colorWhite = new Color(null, 255, 255, 255);
@@ -256,7 +272,7 @@
}
public void shellClosed(ShellEvent e) {
- if (serverWindow.hasBrowserWindowsOpen()) {
+ if (browserWindowController.hasBrowserWindowsOpen()) {
boolean closeWindows = true;
if (System.getProperty("gwt.shell.endquick") == null) {
closeWindows = DialogBase.confirmAction((Shell) e.widget,
@@ -265,7 +281,7 @@
}
if (closeWindows) {
- serverWindow.closeAllBrowserWindows();
+ browserWindowController.closeAllBrowserWindows();
e.doit = true;
} else {
e.doit = false;
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
index 832311d..cf1dcdb 100644
--- a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
+++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
@@ -21,18 +21,14 @@
import com.google.gwt.dev.shell.ServletContainer;
import com.google.gwt.dev.shell.ServletContainerLauncher;
-import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.nio.SelectChannelConnector;
-import org.mortbay.jetty.servlet.FilterHolder;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.log.Log;
import org.mortbay.log.Logger;
import java.io.File;
-import javax.servlet.Filter;
-
/**
* A launcher for an embedded Jetty server.
*/
@@ -190,20 +186,23 @@
}
@SuppressWarnings("unchecked")
- public ServletContainer start(TreeLogger logger, int port, File appRootDir,
- Filter shellServletFilter) throws Exception {
+ public ServletContainer start(TreeLogger logger, int port, File appRootDir)
+ throws Exception {
checkStartParams(logger, port, appRootDir);
- // The dance we do with Jetty's logging system.
- System.setProperty("VERBOSE", "true");
- JettyTreeLogger.setDefaultConstruction(logger, TreeLogger.INFO);
- System.setProperty("org.mortbay.log.class", JettyTreeLogger.class.getName());
- // Force initialization.
- Log.isDebugEnabled();
- if (JettyTreeLogger.isDefaultConstructionReady()) {
- // The log system was already initialized and did not use our
- // newly-constructed logger, set it explicitly now.
- Log.setLog(new JettyTreeLogger());
+ // The dance we do with Jetty's logging system -- disabled, log to console.
+ if (false) {
+ System.setProperty("VERBOSE", "true");
+ JettyTreeLogger.setDefaultConstruction(logger, TreeLogger.INFO);
+ System.setProperty("org.mortbay.log.class",
+ JettyTreeLogger.class.getName());
+ // Force initialization.
+ Log.isDebugEnabled();
+ if (JettyTreeLogger.isDefaultConstructionReady()) {
+ // The log system was already initialized and did not use our
+ // newly-constructed logger, set it explicitly now.
+ Log.setLog(new JettyTreeLogger());
+ }
}
Server server = new Server();
@@ -222,12 +221,6 @@
wac.getInitParams().put(
"org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false");
- // Setup the shell servlet filter to generate nocache.js files (and run
- // the hosted mode linker stack.
- FilterHolder filterHolder = new FilterHolder();
- filterHolder.setFilter(shellServletFilter);
- wac.addFilter(filterHolder, "/*", Handler.ALL);
-
server.setHandler(wac);
server.setStopAtShutdown(true);
server.start();
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerModuleName.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerModuleName.java
index 3dab092..4b010ed 100644
--- a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerModuleName.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerModuleName.java
@@ -30,7 +30,7 @@
@Override
public boolean addExtraArg(String arg) {
- option.setModuleName(arg);
+ option.addModuleName(arg);
return true;
}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWarDir.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWarDir.java
new file mode 100644
index 0000000..5f74707
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWarDir.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2006 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.util.arg;
+
+import com.google.gwt.util.tools.ArgHandlerDir;
+
+import java.io.File;
+
+/**
+ * Argument handler for processing the output directory flag.
+ */
+public final class ArgHandlerWarDir extends ArgHandlerDir {
+
+ private final OptionWarDir option;
+
+ public ArgHandlerWarDir(OptionWarDir option) {
+ this.option = option;
+ }
+
+ public String[] getDefaultArgs() {
+ return new String[] {"-war", "war"};
+ }
+
+ public String getPurpose() {
+ return "The war directory to write output files into (defaults to war)";
+ }
+
+ public String getTag() {
+ return "-war";
+ }
+
+ @Override
+ public void setDir(File dir) {
+ option.setWarDir(dir);
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDirOptional.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDirOptional.java
index fc923fd..80c8f32 100644
--- a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDirOptional.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDirOptional.java
@@ -22,7 +22,7 @@
/**
* Argument handler for processing an optional working directory.
*/
-public final class ArgHandlerWorkDirOptional extends ArgHandlerDir {
+public class ArgHandlerWorkDirOptional extends ArgHandlerDir {
private final OptionWorkDir option;
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDirRequired.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDirRequired.java
index 6413f35..0f86683 100644
--- a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDirRequired.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerWorkDirRequired.java
@@ -15,37 +15,21 @@
*/
package com.google.gwt.dev.util.arg;
-import com.google.gwt.util.tools.ArgHandlerDir;
-
-import java.io.File;
-
/**
* Argument handler for processing a required work directory.
*/
-public final class ArgHandlerWorkDirRequired extends ArgHandlerDir {
-
- private final OptionWorkDir option;
+public class ArgHandlerWorkDirRequired extends ArgHandlerWorkDirOptional {
public ArgHandlerWorkDirRequired(OptionWorkDir option) {
- this.option = option;
+ super(option);
}
public String getPurpose() {
return "The compiler work directory (must be writeable)";
}
- public String getTag() {
- return "-workDir";
- }
-
@Override
public boolean isRequired() {
return true;
}
-
- @Override
- public void setDir(File dir) {
- option.setWorkDir(dir);
- }
-
}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionModuleName.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionModuleName.java
index 688406e..749b563 100644
--- a/dev/core/src/com/google/gwt/dev/util/arg/OptionModuleName.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionModuleName.java
@@ -15,18 +15,25 @@
*/
package com.google.gwt.dev.util.arg;
+import java.util.List;
+
/**
* Option to set the module name.
*/
public interface OptionModuleName {
/**
- * Returns the name of the module.
+ * Returns the list of module names.
*/
- String getModuleName();
+ List<String> getModuleNames();
/**
* Sets the name of the module.
*/
- void setModuleName(String moduleName);
+ void addModuleName(String moduleName);
+
+ /**
+ * Sets the list of module names.
+ */
+ void setModuleNames(List<String> moduleNames);
}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionWarDir.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionWarDir.java
new file mode 100644
index 0000000..0839e95
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionWarDir.java
@@ -0,0 +1,34 @@
+/*
+ * 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.util.arg;
+
+import java.io.File;
+
+/**
+ * Option to set the output directory.
+ */
+public interface OptionWarDir {
+
+ /**
+ * Returns the output directory.
+ */
+ File getWarDir();
+
+ /**
+ * Sets the output directory.
+ */
+ void setWarDir(File dir);
+}
diff --git a/eclipse/samples/DynaTable2/.classpath b/eclipse/samples/DynaTable2/.classpath
index 447a770..85b7671 100644
--- a/eclipse/samples/DynaTable2/.classpath
+++ b/eclipse/samples/DynaTable2/.classpath
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="core/src"/>
+ <classpathentry kind="src" output="war" path="core/src.war"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/gwt-user"/>
<classpathentry kind="output" path="war/WEB-INF/classes"/>
diff --git a/eclipse/samples/DynaTable2/.project b/eclipse/samples/DynaTable2/.project
index 5ece582..e8b7c7e 100644
--- a/eclipse/samples/DynaTable2/.project
+++ b/eclipse/samples/DynaTable2/.project
@@ -24,7 +24,7 @@
<link>
<name>core</name>
<type>2</type>
- <locationURI>GWT_ROOT/samples/dynatable</locationURI>
+ <locationURI>GWT_ROOT/samples/dynatable2</locationURI>
</link>
</linkedResources>
</projectDescription>
diff --git a/eclipse/samples/DynaTable2/DynaTable2 compile.launch b/eclipse/samples/DynaTable2/DynaTable2 compile.launch
index ff78aaf..c171104 100644
--- a/eclipse/samples/DynaTable2/DynaTable2 compile.launch
+++ b/eclipse/samples/DynaTable2/DynaTable2 compile.launch
@@ -16,8 +16,8 @@
<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="DynaTable2"/> </runtimeClasspathEntry> "/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.GWTCompiler"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out war -style PRETTY -logLevel INFO -extra extra com.google.gwt.sample.dynatable.DynaTable2"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.Compiler"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-style PRETTY -logLevel INFO com.google.gwt.sample.dynatable2.DynaTable2"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="DynaTable2"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Dgwt.devjar=C:\gwt\releases\1.6\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=C:\gwt\releases\1.6\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar"/>
</launchConfiguration>
diff --git a/eclipse/samples/DynaTable2/DynaTable2 hosted.launch b/eclipse/samples/DynaTable2/DynaTable2 hosted.launch
index e25b728..562af59 100644
--- a/eclipse/samples/DynaTable2/DynaTable2 hosted.launch
+++ b/eclipse/samples/DynaTable2/DynaTable2 hosted.launch
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/DynaTable2"/>
+<listEntry value="/gwt-dev-windows/core/src/com/google/gwt/dev/HostedMode.java"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="4"/>
+<listEntry value="1"/>
</listAttribute>
<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
@@ -16,8 +16,8 @@
<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="DynaTable2"/> </runtimeClasspathEntry> "/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.GWTHosted"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out war -style PRETTY -logLevel INFO -extra extra -startupUrl DynaTable2.html com.google.gwt.sample.dynatable.DynaTable2"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.HostedMode"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-style PRETTY -logLevel INFO -extra extra -startupUrl DynaTable2.html com.google.gwt.sample.dynatable2.DynaTable2"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="DynaTable2"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Dgwt.devjar=C:\gwt\releases\1.6\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=C:\gwt\releases\1.6\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar"/>
</launchConfiguration>
diff --git a/eclipse/samples/DynaTable2/DynaTable2Legacy compile.launch b/eclipse/samples/DynaTable2/DynaTable2Legacy compile.launch
new file mode 100644
index 0000000..868f116
--- /dev/null
+++ b/eclipse/samples/DynaTable2/DynaTable2Legacy compile.launch
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/gwt-dev-windows/core/src/com/google/gwt/dev/GWTCompiler.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER" javaProject="DynaTable2" path="1" type="4"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/DynaTable2/core/src" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/src" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/super" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-dev-windows/core/super" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="DynaTable2"/> </runtimeClasspathEntry> "/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.GWTCompiler"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out www -style PRETTY -logLevel INFO com.google.gwt.sample.dynatable2.DynaTable2Legacy"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="DynaTable2"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=C:\gwt\releases\1.6\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar"/>
+</launchConfiguration>
diff --git a/eclipse/samples/DynaTable2/DynaTable2Legacy shell.launch b/eclipse/samples/DynaTable2/DynaTable2Legacy shell.launch
new file mode 100644
index 0000000..a8a2fdc
--- /dev/null
+++ b/eclipse/samples/DynaTable2/DynaTable2Legacy shell.launch
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/gwt-dev-windows/core/src/com/google/gwt/dev/GWTShell.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER" javaProject="DynaTable2" path="1" type="4"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/DynaTable2/core/src" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/src" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/super" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-dev-windows/core/super" path="3" type="2"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="DynaTable2"/> </runtimeClasspathEntry> "/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.GWTShell"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out www -style PRETTY -logLevel INFO com.google.gwt.sample.dynatable2.DynaTable2Legacy/DynaTable2Legacy.html"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="DynaTable2"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=C:\gwt\releases\1.6\build\staging\gwt-windows-0.0.0\gwt-dev-windows.jar"/>
+</launchConfiguration>
diff --git a/samples/dynatable2/build.xml b/samples/dynatable2/build.xml
new file mode 100644
index 0000000..00c96d6
--- /dev/null
+++ b/samples/dynatable2/build.xml
@@ -0,0 +1,5 @@
+<project name="dynatable" default="build" basedir=".">
+ <property name="sample.root" value="dynatable" />
+ <property name="sample.module" value="DynaTable" />
+ <import file="../common.ant.xml" />
+</project>
diff --git a/samples/dynatable2/src.war/DynaTable2.css b/samples/dynatable2/src.war/DynaTable2.css
new file mode 100644
index 0000000..ab81abf
--- /dev/null
+++ b/samples/dynatable2/src.war/DynaTable2.css
@@ -0,0 +1,85 @@
+
+body {
+ background-color: white;
+ color: black;
+ font-family: Arial, sans-serif;
+ font-size: small;
+ margin: 8px;
+ margin-top: 3px;
+}
+
+.DynaTable-DynaTableWidget {
+ width: 100%;
+ border: 1px solid #ACA899;
+}
+
+
+.DynaTable-DynaTableWidget .navbar {
+ width: 100%;
+ background-color: #ECE9D8;
+ vertical-align: middle;
+ border-bottom: 1px solid #ACA899;
+}
+
+.DynaTable-DynaTableWidget .navbar button {
+ width: 3em;
+ text-align: center;
+ vertical-align: middle;
+}
+
+.DynaTable-DynaTableWidget .navbar .status {
+ vertical-align: middle;
+ padding-right: 10px;
+}
+
+.DynaTable-DynaTableWidget .table {
+ margin: 10px;
+}
+
+.DynaTable-DynaTableWidget .table td.header {
+ text-align: left;
+ font-weight: bold;
+ text-decoration: underline;
+}
+
+.DynaTable-DynaTableWidget .table td.name {
+ width: 10em;
+}
+
+.DynaTable-DynaTableWidget .table td.desc {
+ width: 20em;
+}
+
+.DynaTable-DynaTableWidget .table td.sched {
+ width: 20em;
+}
+
+.DynaTable-DynaTableWidget .table td {
+ vertical-align: top;
+}
+
+.DynaTable-DayFilterWidget {
+ margin: 3em 1em 1em 0;
+ width: 10em;
+ padding: 0px 8px 0px 8px;
+ border: 1px solid #ACA899;
+}
+
+.DynaTable-DayFilterWidget button {
+ width: 4em;
+ margin: 8px 4px 8px 4px;
+}
+
+.DynaTable-ErrorDialog {
+ border: 2px outset;
+ background-color: white;
+ width: 50%;
+}
+
+.DynaTable-ErrorDialog .Caption {
+ background-color: #C3D9FF;
+ padding: 3px;
+ margin: 2px;
+ font-weight: bold;
+ cursor: default;
+}
diff --git a/samples/dynatable2/src.war/DynaTable2.html b/samples/dynatable2/src.war/DynaTable2.html
new file mode 100644
index 0000000..d4b8b2e
--- /dev/null
+++ b/samples/dynatable2/src.war/DynaTable2.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!-- -->
+<!-- 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 -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <link type="text/css" rel="stylesheet" href="DynaTable2.css">
+ <title></title>
+ </head>
+ <body>
+ <iframe src="javascript:''" id='__gwt_historyFrame' tabIndex='-1' style='width:0;height:0;border:0'></iframe>
+ <script type="text/javascript" language='javascript' src='dynatable2/dynatable2.nocache.js'></script>
+ <h1>School Schedule for Professors and Students</h1>
+ <table width="100%" border="0" summary="School Schedule for Professors and Students">
+ <tr valign="top">
+ <td id="calendar" align="center" width="90%">
+ </td>
+ <td id="days" align="center" width="10%">
+ </td>
+ </tr>
+ </table>
+ </body>
+</html>
diff --git a/samples/dynatable2/src.war/WEB-INF/classes/marker b/samples/dynatable2/src.war/WEB-INF/classes/marker
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/samples/dynatable2/src.war/WEB-INF/classes/marker
diff --git a/samples/dynatable2/src.war/WEB-INF/web.xml b/samples/dynatable2/src.war/WEB-INF/web.xml
new file mode 100644
index 0000000..01c3949
--- /dev/null
+++ b/samples/dynatable2/src.war/WEB-INF/web.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app>
+
+ <servlet>
+ <servlet-name>calendar</servlet-name>
+ <servlet-class>
+ com.google.gwt.sample.dynatable2.server.SchoolCalendarServiceImpl
+ </servlet-class>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>calendar</servlet-name>
+ <url-pattern>/com.google.gwt.sample.dynatable2.DynaTable2/calendar</url-pattern>
+ </servlet-mapping>
+
+</web-app>
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/COPYING b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/COPYING
new file mode 100644
index 0000000..d9a10c0
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/COPYING
@@ -0,0 +1,176 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/DynaTable2.gwt.xml b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/DynaTable2.gwt.xml
new file mode 100644
index 0000000..7781947
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/DynaTable2.gwt.xml
@@ -0,0 +1,19 @@
+<!-- -->
+<!-- Copyright 2007 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 -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module rename-to="dynatable2">
+ <inherits name='com.google.gwt.user.User'/>
+ <entry-point class='com.google.gwt.sample.dynatable2.client.DynaTable'/>
+ <servlet path='/calendar' class='com.google.gwt.sample.dynatable2.server.SchoolCalendarServiceImpl'/>
+</module>
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/DynaTable2Legacy.gwt.xml b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/DynaTable2Legacy.gwt.xml
new file mode 100644
index 0000000..85f806e
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/DynaTable2Legacy.gwt.xml
@@ -0,0 +1,20 @@
+<!-- -->
+<!-- Copyright 2007 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 -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <inherits name='com.google.gwt.user.User'/>
+ <entry-point class='com.google.gwt.sample.dynatable2.client.DynaTable'/>
+ <servlet path='/calendar' class='com.google.gwt.sample.dynatable2.server.SchoolCalendarServiceImpl'/>
+ <public path='legacyPublic'/>
+</module>
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DayFilterWidget.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DayFilterWidget.java
new file mode 100644
index 0000000..7be4cd8
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DayFilterWidget.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HasAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * A UI Widget that allows a user to filter the days being displayed in the
+ * dynamic table.
+ */
+public class DayFilterWidget extends Composite {
+
+ private class DayCheckBox extends CheckBox {
+ public final int day;
+
+ public DayCheckBox(String caption, int day) {
+ super(caption);
+
+ // Remember custom data for this widget.
+ this.day = day;
+
+ // Use a shared handler to save memory.
+ addClickHandler(dayCheckBoxHandler);
+
+ // Initialize based on the calendar's current value.
+ setChecked(calendar.getDayIncluded(day));
+ }
+ }
+
+ private class DayCheckBoxHandler implements ClickHandler {
+ public void onClick(ClickEvent event) {
+ onClick((DayCheckBox) event.getSource());
+ }
+
+ public void onClick(DayCheckBox dayCheckBox) {
+ calendar.setDayIncluded(dayCheckBox.day, dayCheckBox.isChecked());
+ }
+ }
+
+ private final SchoolCalendarWidget calendar;
+
+ private final VerticalPanel outer = new VerticalPanel();
+
+ private final DayCheckBoxHandler dayCheckBoxHandler = new DayCheckBoxHandler();
+
+ public DayFilterWidget(SchoolCalendarWidget calendar) {
+ this.calendar = calendar;
+ initWidget(outer);
+ setStyleName("DynaTable-DayFilterWidget");
+ outer.add(new DayCheckBox("Sunday", 0));
+ outer.add(new DayCheckBox("Monday", 1));
+ outer.add(new DayCheckBox("Tuesday", 2));
+ outer.add(new DayCheckBox("Wednesday", 3));
+ outer.add(new DayCheckBox("Thursday", 4));
+ outer.add(new DayCheckBox("Friday", 5));
+ outer.add(new DayCheckBox("Saturday", 6));
+
+ Button buttonAll = new Button("All", new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ setAllCheckBoxes(true);
+ }
+ });
+
+ Button buttonNone = new Button("None", new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ setAllCheckBoxes(false);
+ }
+ });
+
+ HorizontalPanel hp = new HorizontalPanel();
+ hp.setHorizontalAlignment(HasAlignment.ALIGN_CENTER);
+ hp.add(buttonAll);
+ hp.add(buttonNone);
+
+ outer.add(hp);
+ outer.setCellVerticalAlignment(hp, HasAlignment.ALIGN_BOTTOM);
+ outer.setCellHorizontalAlignment(hp, HasAlignment.ALIGN_CENTER);
+ }
+
+ private void setAllCheckBoxes(boolean checked) {
+ for (int i = 0, n = outer.getWidgetCount(); i < n; ++i) {
+ Widget w = outer.getWidget(i);
+ if (w instanceof DayCheckBox) {
+ ((DayCheckBox) w).setChecked(checked);
+ dayCheckBoxHandler.onClick((DayCheckBox) w);
+ }
+ }
+ }
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DynaTable.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DynaTable.java
new file mode 100644
index 0000000..41e208b
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DynaTable.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.client.ui.RootPanel;
+
+/**
+ * The entry point class which performs the initial loading of the DynaTable
+ * application.
+ */
+public class DynaTable implements EntryPoint {
+
+ public void onModuleLoad() {
+ // Find the slot for the calendar widget.
+ //
+ RootPanel slot = RootPanel.get("calendar");
+ if (slot != null) {
+ SchoolCalendarWidget calendar = new SchoolCalendarWidget(15);
+ slot.add(calendar);
+
+ // Find the slot for the days filter widget.
+ //
+ slot = RootPanel.get("days");
+ if (slot != null) {
+ DayFilterWidget filter = new DayFilterWidget(calendar);
+ slot.add(filter);
+ }
+ }
+ }
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DynaTableDataProvider.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DynaTableDataProvider.java
new file mode 100644
index 0000000..6875d63
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DynaTableDataProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+/**
+ * An interface for providing row-level updates of data, intended here to used
+ * to update a DynaTableWidget.
+ */
+public interface DynaTableDataProvider {
+
+ /**
+ * An interface allow a widget to accept or report failure when a row data
+ * is issued for update.
+ */
+ interface RowDataAcceptor {
+ void accept(int startRow, String[][] rows);
+ void failed(Throwable caught);
+ }
+
+ void updateRowData(int startRow, int maxRows, RowDataAcceptor acceptor);
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DynaTableWidget.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DynaTableWidget.java
new file mode 100644
index 0000000..fb96245
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/DynaTableWidget.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.sample.dynatable2.client.DynaTableDataProvider.RowDataAcceptor;
+import com.google.gwt.user.client.rpc.InvocationException;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.DockPanel;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+/**
+ * A composite Widget that implements the main interface for the dynamic table,
+ * including the data table, status indicators, and paging buttons.
+ */
+public class DynaTableWidget extends Composite {
+
+ /**
+ * A dialog box for displaying an error.
+ */
+ private static class ErrorDialog extends DialogBox implements ClickHandler {
+ private HTML body = new HTML("");
+
+ public ErrorDialog() {
+ setStylePrimaryName("DynaTable-ErrorDialog");
+ Button closeButton = new Button("Close", this);
+ VerticalPanel panel = new VerticalPanel();
+ panel.setSpacing(4);
+ panel.add(body);
+ panel.add(closeButton);
+ panel.setCellHorizontalAlignment(closeButton, VerticalPanel.ALIGN_RIGHT);
+ setWidget(panel);
+ }
+
+ public String getBody() {
+ return body.getHTML();
+ }
+
+ public void onClick(ClickEvent event) {
+ hide();
+ }
+
+ public void setBody(String html) {
+ body.setHTML(html);
+ }
+ }
+
+ private class NavBar extends Composite implements ClickHandler {
+
+ public final DockPanel bar = new DockPanel();
+ public final Button gotoFirst = new Button("<<", this);
+ public final Button gotoNext = new Button(">", this);
+ public final Button gotoPrev = new Button("<", this);
+ public final HTML status = new HTML();
+
+ public NavBar() {
+ initWidget(bar);
+ bar.setStyleName("navbar");
+ status.setStyleName("status");
+
+ HorizontalPanel buttons = new HorizontalPanel();
+ buttons.add(gotoFirst);
+ buttons.add(gotoPrev);
+ buttons.add(gotoNext);
+ bar.add(buttons, DockPanel.EAST);
+ bar.setCellHorizontalAlignment(buttons, DockPanel.ALIGN_RIGHT);
+ bar.add(status, DockPanel.CENTER);
+ bar.setVerticalAlignment(DockPanel.ALIGN_MIDDLE);
+ bar.setCellHorizontalAlignment(status, HasAlignment.ALIGN_RIGHT);
+ bar.setCellVerticalAlignment(status, HasAlignment.ALIGN_MIDDLE);
+ bar.setCellWidth(status, "100%");
+
+ // Initialize prev & first button to disabled.
+ //
+ gotoPrev.setEnabled(false);
+ gotoFirst.setEnabled(false);
+ }
+
+ public void onClick(ClickEvent event) {
+ Object source = event.getSource();
+ if (source == gotoNext) {
+ startRow += getDataRowCount();
+ refresh();
+ } else if (source == gotoPrev) {
+ startRow -= getDataRowCount();
+ if (startRow < 0) {
+ startRow = 0;
+ }
+ refresh();
+ } else if (source == gotoFirst) {
+ startRow = 0;
+ refresh();
+ }
+ }
+ }
+
+ private class RowDataAcceptorImpl implements RowDataAcceptor {
+ public void accept(int startRow, String[][] data) {
+
+ int destRowCount = getDataRowCount();
+ int destColCount = grid.getCellCount(0);
+ assert (data.length <= destRowCount) : "Too many rows";
+
+ int srcRowIndex = 0;
+ int srcRowCount = data.length;
+ int destRowIndex = 1; // skip navbar row
+ for (; srcRowIndex < srcRowCount; ++srcRowIndex, ++destRowIndex) {
+ String[] srcRowData = data[srcRowIndex];
+ assert (srcRowData.length == destColCount) : " Column count mismatch";
+ for (int srcColIndex = 0; srcColIndex < destColCount; ++srcColIndex) {
+ String cellHTML = srcRowData[srcColIndex];
+ grid.setText(destRowIndex, srcColIndex, cellHTML);
+ }
+ }
+
+ // Clear remaining table rows.
+ //
+ boolean isLastPage = false;
+ for (; destRowIndex < destRowCount + 1; ++destRowIndex) {
+ isLastPage = true;
+ for (int destColIndex = 0; destColIndex < destColCount; ++destColIndex) {
+ grid.clearCell(destRowIndex, destColIndex);
+ }
+ }
+
+ // Synchronize the nav buttons.
+ navbar.gotoNext.setEnabled(!isLastPage);
+ navbar.gotoFirst.setEnabled(startRow > 0);
+ navbar.gotoPrev.setEnabled(startRow > 0);
+
+ // Update the status message.
+ //
+ setStatusText((startRow + 1) + " - " + (startRow + srcRowCount));
+ }
+
+ public void failed(Throwable caught) {
+ setStatusText("Error");
+ if (errorDialog == null) {
+ errorDialog = new ErrorDialog();
+ }
+ if (caught instanceof InvocationException) {
+ errorDialog.setText("An RPC server could not be reached");
+ errorDialog.setBody(NO_CONNECTION_MESSAGE);
+ } else {
+ errorDialog.setText("Unexcepted Error processing remote call");
+ errorDialog.setBody(caught.getMessage());
+ }
+ errorDialog.center();
+ }
+ }
+
+ private static final String NO_CONNECTION_MESSAGE = "<p>The DynaTable example uses a <a href=\"http://code.google.com/"
+ + "webtoolkit/documentation/com.google.gwt.doc.DeveloperGuide."
+ + "RemoteProcedureCalls.html\" target=\"_blank\">Remote Procedure Call</a> "
+ + "(RPC) to request data from the server. In order for the RPC to "
+ + "successfully return data, the server component must be available.</p>"
+ + "<p>If you are running this demo from compiled code, the server "
+ + "component may not be available to respond to the RPC requests from "
+ + "DynaTable. Try running DynaTable in hosted mode to see the demo "
+ + "in action.</p> "
+ + "<p>Click on the Remote Procedure Call link above for more information "
+ + "on GWT's RPC infrastructure.";
+
+ private final RowDataAcceptor acceptor = new RowDataAcceptorImpl();
+
+ private final Grid grid = new Grid();
+
+ private final NavBar navbar = new NavBar();
+
+ private ErrorDialog errorDialog = null;
+
+ private final DockPanel outer = new DockPanel();
+
+ private final DynaTableDataProvider provider;
+
+ private int startRow = 0;
+
+ public DynaTableWidget(DynaTableDataProvider provider, String[] columns,
+ String[] columnStyles, int rowCount) {
+
+ if (columns.length == 0) {
+ throw new IllegalArgumentException(
+ "expecting a positive number of columns");
+ }
+
+ if (columnStyles != null && columns.length != columnStyles.length) {
+ throw new IllegalArgumentException("expecting as many styles as columns");
+ }
+
+ this.provider = provider;
+ initWidget(outer);
+ grid.setStyleName("table");
+ outer.add(navbar, DockPanel.NORTH);
+ outer.add(grid, DockPanel.CENTER);
+ initTable(columns, columnStyles, rowCount);
+ setStyleName("DynaTable-DynaTableWidget");
+ }
+
+ public void clearStatusText() {
+ navbar.status.setHTML(" ");
+ }
+
+ public void refresh() {
+ // Disable buttons temporarily to stop the user from running off the end.
+ //
+ navbar.gotoFirst.setEnabled(false);
+ navbar.gotoPrev.setEnabled(false);
+ navbar.gotoNext.setEnabled(false);
+
+ setStatusText("Please wait...");
+ provider.updateRowData(startRow, grid.getRowCount() - 1, acceptor);
+ }
+
+ public void setRowCount(int rows) {
+ grid.resizeRows(rows);
+ }
+
+ public void setStatusText(String text) {
+ navbar.status.setText(text);
+ }
+
+ private int getDataRowCount() {
+ return grid.getRowCount() - 1;
+ }
+
+ private void initTable(String[] columns, String[] columnStyles, int rowCount) {
+ // Set up the header row. It's one greater than the number of visible rows.
+ //
+ grid.resize(rowCount + 1, columns.length);
+ for (int i = 0, n = columns.length; i < n; i++) {
+ grid.setText(0, i, columns[i]);
+ if (columnStyles != null) {
+ grid.getCellFormatter().setStyleName(0, i, columnStyles[i] + " header");
+ }
+ }
+ }
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Person.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Person.java
new file mode 100644
index 0000000..d73702f
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Person.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+import com.google.gwt.user.client.rpc.IsSerializable;
+
+/**
+ * Hold relevant data for Person. This class is meant to be serialized in RPC
+ * calls.
+ */
+public abstract class Person implements IsSerializable {
+
+ private String description = "DESC";
+
+ private String name;
+
+ public Person() {
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public abstract String getSchedule(boolean[] daysFilter);
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Professor.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Professor.java
new file mode 100644
index 0000000..932d188
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Professor.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+/**
+ * Holds relevant data for a Professor type Person. This class is intended to be
+ * serialized in RPC calls.
+ */
+public class Professor extends Person {
+
+ private Schedule teachingSchedule = new Schedule();
+
+ public Professor() {
+ }
+
+ @Override
+ public String getSchedule(boolean[] daysFilter) {
+ return teachingSchedule.getDescription(daysFilter);
+ }
+
+ public Schedule getTeachingSchedule() {
+ return teachingSchedule;
+ }
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Schedule.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Schedule.java
new file mode 100644
index 0000000..ac0b40e
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Schedule.java
@@ -0,0 +1,62 @@
+/*
+ * 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.sample.dynatable2.client;
+
+import com.google.gwt.user.client.rpc.IsSerializable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Hold the relevant data for a Schedule. This class is meant to be serialized
+ * in RPC calls.
+ */
+public class Schedule implements IsSerializable {
+
+ private List<TimeSlot> timeSlots = new ArrayList<TimeSlot>();
+
+ public Schedule() {
+ }
+
+ public void addTimeSlot(TimeSlot timeSlot) {
+ timeSlots.add(timeSlot);
+ }
+
+ public String getDescription(boolean[] daysFilter) {
+ String s = null;
+ for (TimeSlot timeSlot : timeSlots) {
+ if (daysFilter[timeSlot.getDayOfWeek()]) {
+ if (s == null) {
+ s = timeSlot.getDescription();
+ } else {
+ s += ", " + timeSlot.getDescription();
+ }
+ }
+ }
+
+ if (s != null) {
+ return s;
+ } else {
+ return "";
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getDescription(null);
+ }
+
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/SchoolCalendarService.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/SchoolCalendarService.java
new file mode 100644
index 0000000..fee68f6
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/SchoolCalendarService.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+
+/**
+ * The interface for the RPC server endpoint to get school calendar
+ * information.
+ */
+public interface SchoolCalendarService extends RemoteService {
+
+ Person[] getPeople(int startIndex, int maxCount);
+
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/SchoolCalendarServiceAsync.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/SchoolCalendarServiceAsync.java
new file mode 100644
index 0000000..3aa3757
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/SchoolCalendarServiceAsync.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+/**
+ * The interface for the RPC server endpoint that provides school calendar
+ * information for clients that will be calling asynchronously.
+ */
+public interface SchoolCalendarServiceAsync {
+
+ void getPeople(int startIndex, int maxCount, AsyncCallback<Person[]> callback);
+
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/SchoolCalendarWidget.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/SchoolCalendarWidget.java
new file mode 100644
index 0000000..65e4fd2
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/SchoolCalendarWidget.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.rpc.ServiceDefTarget;
+import com.google.gwt.user.client.ui.Composite;
+
+/**
+ * A Composite widget that abstracts a DynaTableWidget and a data provider tied
+ * to the <@link SchoolCalendarService> RPC endpoint.
+ */
+public class SchoolCalendarWidget extends Composite {
+
+ /**
+ * A data provider that bridges the provides row level updates from the data
+ * available through a <@link SchoolCalendarService>.
+ */
+ public class CalendarProvider implements DynaTableDataProvider {
+
+ private final SchoolCalendarServiceAsync calService;
+
+ private int lastMaxRows = -1;
+
+ private Person[] lastPeople;
+
+ private int lastStartRow = -1;
+
+ public CalendarProvider() {
+ // Initialize the service.
+ //
+ calService = (SchoolCalendarServiceAsync) GWT.create(SchoolCalendarService.class);
+
+ // By default, we assume we'll make RPCs to a servlet, but see
+ // updateRowData(). There is special support for canned RPC responses.
+ // (Which is a totally demo hack, by the way :-)
+ //
+ ServiceDefTarget target = (ServiceDefTarget) calService;
+
+ // Use a module-relative URLs to ensure that this client code can find
+ // its way home, even when the URL changes (as might happen when you
+ // deploy this as a webapp under an external servlet container).
+ String moduleRelativeURL = GWT.getModuleBaseURL() + "calendar";
+ target.setServiceEntryPoint(moduleRelativeURL);
+ }
+
+ public void updateRowData(final int startRow, final int maxRows,
+ final RowDataAcceptor acceptor) {
+ // Check the simple cache first.
+ //
+ if (startRow == lastStartRow) {
+ if (maxRows == lastMaxRows) {
+ // Use the cached batch.
+ //
+ pushResults(acceptor, startRow, lastPeople);
+ return;
+ }
+ }
+
+ // Fetch the data remotely.
+ //
+ calService.getPeople(startRow, maxRows, new AsyncCallback<Person[]>() {
+ public void onFailure(Throwable caught) {
+ acceptor.failed(caught);
+ }
+
+ public void onSuccess(Person[] result) {
+ lastStartRow = startRow;
+ lastMaxRows = maxRows;
+ lastPeople = result;
+ pushResults(acceptor, startRow, result);
+ }
+
+ });
+ }
+
+ private void pushResults(RowDataAcceptor acceptor, int startRow,
+ Person[] people) {
+ String[][] rows = new String[people.length][];
+ for (int i = 0, n = rows.length; i < n; i++) {
+ Person person = people[i];
+ rows[i] = new String[3];
+ rows[i][0] = person.getName();
+ rows[i][1] = person.getDescription();
+ rows[i][2] = person.getSchedule(daysFilter);
+ }
+ acceptor.accept(startRow, rows);
+ }
+ }
+
+ private final CalendarProvider calProvider = new CalendarProvider();
+
+ private final boolean[] daysFilter = new boolean[] {
+ true, true, true, true, true, true, true};
+
+ private final DynaTableWidget dynaTable;
+
+ private Command pendingRefresh;
+
+ public SchoolCalendarWidget(int visibleRows) {
+ String[] columns = new String[] {"Name", "Description", "Schedule"};
+ String[] styles = new String[] {"name", "desc", "sched"};
+ dynaTable = new DynaTableWidget(calProvider, columns, styles, visibleRows);
+ initWidget(dynaTable);
+ }
+
+ protected boolean getDayIncluded(int day) {
+ return daysFilter[day];
+ }
+
+ @Override
+ protected void onLoad() {
+ dynaTable.refresh();
+ }
+
+ protected void setDayIncluded(int day, boolean included) {
+ if (daysFilter[day] == included) {
+ // No change.
+ //
+ return;
+ }
+
+ daysFilter[day] = included;
+ if (pendingRefresh == null) {
+ pendingRefresh = new Command() {
+ public void execute() {
+ pendingRefresh = null;
+ dynaTable.refresh();
+ }
+ };
+ DeferredCommand.addCommand(pendingRefresh);
+ }
+ }
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Student.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Student.java
new file mode 100644
index 0000000..ff8d068
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/Student.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+/**
+ * Holds relevant data for a Student type Person. This class is intended to be
+ * serialized in RPC calls.
+ */
+public class Student extends Person {
+
+ private Schedule classSchedule = new Schedule();
+
+ public Schedule getClassSchedule() {
+ return classSchedule;
+ }
+
+ @Override
+ public String getSchedule(boolean[] daysFilter) {
+ return classSchedule.getDescription(daysFilter);
+ }
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/TimeSlot.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/TimeSlot.java
new file mode 100644
index 0000000..1a0f130
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/client/TimeSlot.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.client;
+
+import com.google.gwt.user.client.rpc.IsSerializable;
+
+/**
+ * Hold relevant data for a time slot. This class is intended to be serialized
+ * as part of RPC calls.
+ */
+public class TimeSlot implements IsSerializable, Comparable<TimeSlot> {
+
+ private static final transient String[] DAYS = new String[] {
+ "Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"};
+
+ private int endMinutes;
+
+ private int startMinutes;
+
+ private int zeroBasedDayOfWeek;
+
+ public TimeSlot() {
+ }
+
+ public TimeSlot(int zeroBasedDayOfWeek, int startMinutes, int endMinutes) {
+ this.zeroBasedDayOfWeek = zeroBasedDayOfWeek;
+ this.startMinutes = startMinutes;
+ this.endMinutes = endMinutes;
+ }
+
+ public int compareTo(TimeSlot o) {
+ if (zeroBasedDayOfWeek < o.zeroBasedDayOfWeek) {
+ return -1;
+ } else if (zeroBasedDayOfWeek > o.zeroBasedDayOfWeek) {
+ return 1;
+ } else {
+ if (startMinutes < o.startMinutes) {
+ return -1;
+ } else if (startMinutes > o.startMinutes) {
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ public int getDayOfWeek() {
+ return zeroBasedDayOfWeek;
+ }
+
+ public String getDescription() {
+ return DAYS[zeroBasedDayOfWeek] + " " + getHrsMins(startMinutes) + "-"
+ + getHrsMins(endMinutes);
+ }
+
+ public int getEndMinutes() {
+ return endMinutes;
+ }
+
+ public int getStartMinutes() {
+ return startMinutes;
+ }
+
+ public void setDayOfWeek(int zeroBasedDayOfWeek) {
+ if (0 <= zeroBasedDayOfWeek && zeroBasedDayOfWeek < 7) {
+ this.zeroBasedDayOfWeek = zeroBasedDayOfWeek;
+ } else {
+ throw new IllegalArgumentException("day must be in the range 0-6");
+ }
+ }
+
+ public void setEndMinutes(int endMinutes) {
+ this.endMinutes = endMinutes;
+ }
+
+ public void setStartMinutes(int startMinutes) {
+ this.startMinutes = startMinutes;
+ }
+
+ private String getHrsMins(int mins) {
+ int hrs = mins / 60;
+ if (hrs > 12) {
+ hrs -= 12;
+ }
+
+ int remainder = mins % 60;
+
+ return hrs + ":"
+ + (remainder < 10 ? "0" + remainder : String.valueOf(remainder));
+ }
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/legacyPublic/DynaTable2Legacy.css b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/legacyPublic/DynaTable2Legacy.css
new file mode 100644
index 0000000..ab81abf
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/legacyPublic/DynaTable2Legacy.css
@@ -0,0 +1,85 @@
+
+body {
+ background-color: white;
+ color: black;
+ font-family: Arial, sans-serif;
+ font-size: small;
+ margin: 8px;
+ margin-top: 3px;
+}
+
+.DynaTable-DynaTableWidget {
+ width: 100%;
+ border: 1px solid #ACA899;
+}
+
+
+.DynaTable-DynaTableWidget .navbar {
+ width: 100%;
+ background-color: #ECE9D8;
+ vertical-align: middle;
+ border-bottom: 1px solid #ACA899;
+}
+
+.DynaTable-DynaTableWidget .navbar button {
+ width: 3em;
+ text-align: center;
+ vertical-align: middle;
+}
+
+.DynaTable-DynaTableWidget .navbar .status {
+ vertical-align: middle;
+ padding-right: 10px;
+}
+
+.DynaTable-DynaTableWidget .table {
+ margin: 10px;
+}
+
+.DynaTable-DynaTableWidget .table td.header {
+ text-align: left;
+ font-weight: bold;
+ text-decoration: underline;
+}
+
+.DynaTable-DynaTableWidget .table td.name {
+ width: 10em;
+}
+
+.DynaTable-DynaTableWidget .table td.desc {
+ width: 20em;
+}
+
+.DynaTable-DynaTableWidget .table td.sched {
+ width: 20em;
+}
+
+.DynaTable-DynaTableWidget .table td {
+ vertical-align: top;
+}
+
+.DynaTable-DayFilterWidget {
+ margin: 3em 1em 1em 0;
+ width: 10em;
+ padding: 0px 8px 0px 8px;
+ border: 1px solid #ACA899;
+}
+
+.DynaTable-DayFilterWidget button {
+ width: 4em;
+ margin: 8px 4px 8px 4px;
+}
+
+.DynaTable-ErrorDialog {
+ border: 2px outset;
+ background-color: white;
+ width: 50%;
+}
+
+.DynaTable-ErrorDialog .Caption {
+ background-color: #C3D9FF;
+ padding: 3px;
+ margin: 2px;
+ font-weight: bold;
+ cursor: default;
+}
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/legacyPublic/DynaTable2Legacy.html b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/legacyPublic/DynaTable2Legacy.html
new file mode 100644
index 0000000..3c5887a
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/legacyPublic/DynaTable2Legacy.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!-- -->
+<!-- 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 -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <link type="text/css" rel="stylesheet" href="DynaTable2Legacy.css">
+ <title></title>
+ </head>
+ <body>
+ <iframe src="javascript:''" id='__gwt_historyFrame' tabIndex='-1' style='width:0;height:0;border:0'></iframe>
+ <script type="text/javascript" language='javascript' src='com.google.gwt.sample.dynatable2.DynaTable2Legacy.nocache.js'></script>
+ <h1>School Schedule for Professors and Students</h1>
+ <table width="100%" border="0" summary="School Schedule for Professors and Students">
+ <tr valign="top">
+ <td id="calendar" align="center" width="90%">
+ </td>
+ <td id="days" align="center" width="10%">
+ </td>
+ </tr>
+ </table>
+ </body>
+</html>
diff --git a/samples/dynatable2/src/com/google/gwt/sample/dynatable2/server/SchoolCalendarServiceImpl.java b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/server/SchoolCalendarServiceImpl.java
new file mode 100644
index 0000000..2705edb
--- /dev/null
+++ b/samples/dynatable2/src/com/google/gwt/sample/dynatable2/server/SchoolCalendarServiceImpl.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2007 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.sample.dynatable2.server;
+
+import com.google.gwt.sample.dynatable2.client.Person;
+import com.google.gwt.sample.dynatable2.client.Professor;
+import com.google.gwt.sample.dynatable2.client.Schedule;
+import com.google.gwt.sample.dynatable2.client.SchoolCalendarService;
+import com.google.gwt.sample.dynatable2.client.Student;
+import com.google.gwt.sample.dynatable2.client.TimeSlot;
+import com.google.gwt.user.server.rpc.RemoteServiceServlet;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * The implementation of the RPC service which runs on the server.
+ */
+public class SchoolCalendarServiceImpl extends RemoteServiceServlet implements
+ SchoolCalendarService {
+
+ private static final String[] FIRST_NAMES = new String[] {
+ "Inman", "Sally", "Omar", "Teddy", "Jimmy", "Cathy", "Barney", "Fred",
+ "Eddie", "Carlos"};
+
+ private static final String[] LAST_NAMES = new String[] {
+ "Smith", "Jones", "Epps", "Gibbs", "Webber", "Blum", "Mendez",
+ "Crutcher", "Needler", "Wilson", "Chase", "Edelstein"};
+
+ private static final String[] SUBJECTS = new String[] {
+ "Chemistry", "Phrenology", "Geometry", "Underwater Basket Weaving",
+ "Basketball", "Computer Science", "Statistics", "Materials Engineering",
+ "English Literature", "Geology"};
+
+ private static final Person[] NO_PEOPLE = new Person[0];
+
+ private static final int CLASS_LENGTH_MINS = 50;
+
+ private static final int MAX_SCHED_ENTRIES = 5;
+
+ private static final int MIN_SCHED_ENTRIES = 1;
+
+ private static final int MAX_PEOPLE = 100;
+
+ private static final int STUDENTS_PER_PROF = 5;
+
+ private final List<Person> people = new ArrayList<Person>();
+
+ private final Random rnd = new Random(3);
+
+ public SchoolCalendarServiceImpl() {
+ generateRandomPeople();
+ }
+
+ public Person[] getPeople(int startIndex, int maxCount) {
+ int peopleCount = people.size();
+
+ int start = startIndex;
+ if (start >= peopleCount) {
+ return NO_PEOPLE;
+ }
+
+ int end = Math.min(startIndex + maxCount, peopleCount);
+ if (start == end) {
+ return NO_PEOPLE;
+ }
+
+ int resultCount = end - start;
+ Person[] results = new Person[resultCount];
+ for (int from = start, to = 0; to < resultCount; ++from, ++to) {
+ results[to] = people.get(from);
+ }
+
+ return results;
+ }
+
+ /**
+ * Write the serialized response out to stdout. This is a very unusual thing
+ * to do, but it allows us to create a static file version of the response
+ * without deploying a servlet.
+ */
+ @Override
+ protected void onAfterResponseSerialized(String serializedResponse) {
+ System.out.println(serializedResponse);
+ }
+
+ private void generateRandomPeople() {
+ for (int i = 0; i < MAX_PEOPLE; ++i) {
+ Person person = generateRandomPerson();
+ people.add(person);
+ }
+ }
+
+ private Person generateRandomPerson() {
+ // 1 out of every so many people is a prof.
+ //
+ if (rnd.nextInt(STUDENTS_PER_PROF) == 1) {
+ return generateRandomProfessor();
+ } else {
+ return generateRandomStudent();
+ }
+ }
+
+ private Person generateRandomProfessor() {
+ Professor prof = new Professor();
+
+ String firstName = pickRandomString(FIRST_NAMES);
+ String lastName = pickRandomString(LAST_NAMES);
+ prof.setName("Dr. " + firstName + " " + lastName);
+
+ String subject = pickRandomString(SUBJECTS);
+ prof.setDescription("Professor of " + subject);
+
+ generateRandomSchedule(prof.getTeachingSchedule());
+
+ return prof;
+ }
+
+ private void generateRandomSchedule(Schedule sched) {
+ int range = MAX_SCHED_ENTRIES - MIN_SCHED_ENTRIES + 1;
+ int howMany = MIN_SCHED_ENTRIES + rnd.nextInt(range);
+
+ TimeSlot[] timeSlots = new TimeSlot[howMany];
+
+ for (int i = 0; i < howMany; ++i) {
+ int startHrs = 8 + rnd.nextInt(9); // 8 am - 5 pm
+ int startMins = 15 * rnd.nextInt(4); // on the hour or some quarter
+ int dayOfWeek = 1 + rnd.nextInt(5); // Mon - Fri
+
+ int absStartMins = 60 * startHrs + startMins; // convert to minutes
+ int absStopMins = absStartMins + CLASS_LENGTH_MINS;
+
+ timeSlots[i] = new TimeSlot(dayOfWeek, absStartMins, absStopMins);
+ }
+
+ Arrays.sort(timeSlots);
+
+ for (int i = 0; i < howMany; ++i) {
+ sched.addTimeSlot(timeSlots[i]);
+ }
+ }
+
+ private Person generateRandomStudent() {
+ Student student = new Student();
+
+ String firstName = pickRandomString(FIRST_NAMES);
+ String lastName = pickRandomString(LAST_NAMES);
+ student.setName(firstName + " " + lastName);
+
+ String subject = pickRandomString(SUBJECTS);
+ student.setDescription("Majoring in " + subject);
+
+ generateRandomSchedule(student.getClassSchedule());
+
+ return student;
+ }
+
+ private String pickRandomString(String[] a) {
+ int i = rnd.nextInt(a.length);
+ return a[i];
+ }
+}
diff --git a/user/build.xml b/user/build.xml
index 6bc6113..0539253 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -78,7 +78,7 @@
<target name="remoteweb-test" description="Run a remoteweb test at the given host and path" if="gwt.remote.browsers">
<echo message="Performing remote browser testing at ${gwt.remote.browsers}" />
- <gwt.junit test.args="${test.args} -out www -workDir ${junit.out}/remoteweb/workdir -remoteweb ${gwt.remote.browsers}" test.out="${junit.out}/remoteweb" test.cases="default.web.tests" >
+ <gwt.junit test.args="${test.args} -out www -remoteweb ${gwt.remote.browsers}" test.out="${junit.out}/remoteweb" test.cases="default.web.tests" >
<extraclasspaths>
<pathelement location="${gwt.build}/out/dev/core/bin-test" />
</extraclasspaths>
@@ -87,7 +87,7 @@
<target name="selenium-test" description="Run a remote test using Selenium RC test at the given host and path" if="gwt.selenium.hosts">
<echo message="Performing remote browser testing using Selenium RC at ${gwt.selenium.hosts}" />
- <gwt.junit test.args="${test.args} -out www -workDir ${junit.out}/selenium/workdir -selenium ${gwt.selenium.hosts}" test.out="${junit.out}/selenium" test.cases="default.web.tests" >
+ <gwt.junit test.args="${test.args} -out www -selenium ${gwt.selenium.hosts}" test.out="${junit.out}/selenium" test.cases="default.web.tests" >
<extraclasspaths>
<pathelement location="${gwt.build}/out/dev/core/bin-test" />
</extraclasspaths>
@@ -95,7 +95,7 @@
</target>
<target name="test.hosted" depends="compile, compile.tests" description="Run only hosted-mode tests for this project.">
- <gwt.junit test.args="${test.args} -workDir ${junit.out}/${build.host.platform}-hosted-mode/workdir" test.out="${junit.out}/${build.host.platform}-hosted-mode" test.cases="default.hosted.tests" >
+ <gwt.junit test.args="${test.args}" test.out="${junit.out}/${build.host.platform}-hosted-mode" test.cases="default.hosted.tests" >
<extraclasspaths>
<pathelement location="${gwt.build}/out/dev/core/bin-test" />
</extraclasspaths>
@@ -103,7 +103,7 @@
</target>
<target name="test.web" depends="compile, compile.tests" description="Run only web-mode tests for this project.">
- <gwt.junit test.args="${test.args} -out www -workDir ${junit.out}/${build.host.platform}-web-mode/workdir -web" test.out="${junit.out}/${build.host.platform}-web-mode" test.cases="default.web.tests" >
+ <gwt.junit test.args="${test.args} -out www -web" test.out="${junit.out}/${build.host.platform}-web-mode" test.cases="default.web.tests" >
<extraclasspaths>
<pathelement location="${gwt.build}/out/dev/core/bin-test" />
</extraclasspaths>
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index cd21132..a5141a3 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -90,6 +90,189 @@
void processResult(TestCase testCase, JUnitResult result);
}
+ class ArgProcessor extends GWTShell.ArgProcessor {
+
+ public ArgProcessor() {
+ super(true, true);
+ registerHandler(new ArgHandlerFlag() {
+
+ @Override
+ public String getPurpose() {
+ return "Causes your test to run in web (compiled) mode (defaults to hosted mode)";
+ }
+
+ @Override
+ public String getTag() {
+ return "-web";
+ }
+
+ @Override
+ public boolean setFlag() {
+ runStyle = new RunStyleLocalWeb(JUnitShell.this);
+ numClients = 1;
+ return true;
+ }
+
+ });
+
+ registerHandler(new ArgHandlerString() {
+
+ @Override
+ public String getPurpose() {
+ return "Runs web mode via RMI to a set of BrowserManagerServers; "
+ + "e.g. rmi://localhost/ie6,rmi://localhost/firefox";
+ }
+
+ @Override
+ public String getTag() {
+ return "-remoteweb";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"rmiUrl"};
+ }
+
+ @Override
+ public boolean isUndocumented() {
+ return true;
+ }
+
+ @Override
+ public boolean setString(String str) {
+ String[] urls = str.split(",");
+ runStyle = RunStyleRemoteWeb.create(JUnitShell.this, urls);
+ numClients = urls.length;
+ return runStyle != null;
+ }
+ });
+
+ registerHandler(new ArgHandlerString() {
+
+ @Override
+ public String getPurpose() {
+ return "Runs web mode via HTTP to a set of Selenium servers; "
+ + "e.g. localhost:4444/*firefox,remotehost:4444/*iexplore";
+ }
+
+ @Override
+ public String getTag() {
+ return "-selenium";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"seleniumHost"};
+ }
+
+ @Override
+ public boolean setString(String str) {
+ String[] targets = str.split(",");
+ numClients = targets.length;
+ runStyle = RunStyleSelenium.create(JUnitShell.this, targets);
+ return runStyle != null;
+ }
+ });
+
+ registerHandler(new ArgHandlerString() {
+
+ @Override
+ public String getPurpose() {
+ return "Run external browsers in web mode (pass a comma separated list of executables.)";
+ }
+
+ @Override
+ public String getTag() {
+ return "-externalbrowser";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"browserPaths"};
+ }
+
+ @Override
+ public boolean isUndocumented() {
+ return true;
+ }
+
+ @Override
+ public boolean setString(String str) {
+ String[] paths = str.split(",");
+ runStyle = new RunStyleExternalBrowser(JUnitShell.this, paths);
+ numClients = paths.length;
+ return runStyle != null;
+ }
+ });
+
+ registerHandler(new ArgHandler() {
+
+ @Override
+ public String[] getDefaultArgs() {
+ return null;
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Causes the system to wait for a remote browser to connect";
+ }
+
+ @Override
+ public String getTag() {
+ return "-manual";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"[numClients]"};
+ }
+
+ @Override
+ public int handle(String[] args, int tagIndex) {
+ int value = 1;
+ if (tagIndex + 1 < args.length) {
+ try {
+ // See if the next item is an integer.
+ value = Integer.parseInt(args[tagIndex + 1]);
+ if (value >= 1) {
+ setInt(value);
+ return 1;
+ }
+ } catch (NumberFormatException e) {
+ // fall-through
+ }
+ }
+ setInt(1);
+ return 0;
+ }
+
+ public void setInt(int value) {
+ runStyle = new RunStyleManual(JUnitShell.this, value);
+ numClients = value;
+ }
+
+ });
+
+ registerHandler(new ArgHandlerFlag() {
+ @Override
+ public String getPurpose() {
+ return "Causes the log window and browser windows to be displayed; useful for debugging";
+ }
+
+ @Override
+ public String getTag() {
+ return "-notHeadless";
+ }
+
+ @Override
+ public boolean setFlag() {
+ setHeadless(false);
+ return true;
+ }
+ });
+ }
+ }
+
private static class JUnitStrategy implements Strategy {
public String getModuleInherit() {
return "com.google.gwt.junit.JUnit";
@@ -204,8 +387,8 @@
unitTestShell = new JUnitShell();
unitTestShell.lastLaunchFailed = true;
String[] args = unitTestShell.synthesizeArgs();
- if (!unitTestShell.processArgs(args)) {
-
+ ArgProcessor argProcessor = unitTestShell.new ArgProcessor();
+ if (!argProcessor.processArgs(args)) {
throw new JUnitFatalLaunchException("Error processing shell arguments");
}
@@ -215,6 +398,11 @@
if (!unitTestShell.startUp()) {
throw new JUnitFatalLaunchException("Shell failed to start");
}
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ public void run() {
+ unitTestShell.shutDown();
+ }
+ }));
unitTestShell.lastLaunchFailed = false;
}
@@ -242,6 +430,16 @@
private boolean lastLaunchFailed;
/**
+ * We need to keep a hard reference to the last module that was launched until
+ * all client browsers have successfully transitioned to the current module.
+ * Failure to do so allows the last module to be GC'd, which transitively
+ * kills the {@link com.google.gwt.junit.server.JUnitHostImpl} servlet. If the
+ * servlet dies, the client browsers will be unable to transition.
+ */
+ @SuppressWarnings("unused")
+ private ModuleDef lastModule;
+
+ /**
* Portal to interact with the servlet.
*/
private JUnitMessageQueue messageQueue;
@@ -270,200 +468,10 @@
private long testBeginTimeout;
/**
- * We need to keep a hard reference to the last module that was launched until
- * all client browsers have successfully transitioned to the current module.
- * Failure to do so allows the last module to be GC'd, which transitively
- * kills the {@link com.google.gwt.junit.server.JUnitHostImpl} servlet. If the
- * servlet dies, the client browsers will be unable to transition.
- */
- @SuppressWarnings("unused")
- private ModuleDef lastModule;
-
- /**
* 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() {
- super(true, true);
-
- registerHandler(new ArgHandlerFlag() {
-
- @Override
- public String getPurpose() {
- return "Causes your test to run in web (compiled) mode (defaults to hosted mode)";
- }
-
- @Override
- public String getTag() {
- return "-web";
- }
-
- @Override
- public boolean setFlag() {
- runStyle = new RunStyleLocalWeb(JUnitShell.this);
- numClients = 1;
- return true;
- }
-
- });
-
- registerHandler(new ArgHandlerString() {
-
- @Override
- public String getPurpose() {
- return "Runs web mode via RMI to a set of BrowserManagerServers; "
- + "e.g. rmi://localhost/ie6,rmi://localhost/firefox";
- }
-
- @Override
- public String getTag() {
- return "-remoteweb";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"rmiUrl"};
- }
-
- @Override
- public boolean isUndocumented() {
- return true;
- }
-
- @Override
- public boolean setString(String str) {
- String[] urls = str.split(",");
- runStyle = RunStyleRemoteWeb.create(JUnitShell.this, urls);
- numClients = urls.length;
- return runStyle != null;
- }
- });
-
- registerHandler(new ArgHandlerString() {
-
- @Override
- public String getPurpose() {
- return "Runs web mode via HTTP to a set of Selenium servers; "
- + "e.g. localhost:4444/*firefox,remotehost:4444/*iexplore";
- }
-
- @Override
- public String getTag() {
- return "-selenium";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"seleniumHost"};
- }
-
- @Override
- public boolean setString(String str) {
- String[] targets = str.split(",");
- numClients = targets.length;
- runStyle = RunStyleSelenium.create(JUnitShell.this, targets);
- return runStyle != null;
- }
- });
-
- registerHandler(new ArgHandlerString() {
-
- @Override
- public String getPurpose() {
- return "Run external browsers in web mode (pass a comma separated list of executables.)";
- }
-
- @Override
- public String getTag() {
- return "-externalbrowser";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"browserPaths"};
- }
-
- @Override
- public boolean isUndocumented() {
- return true;
- }
-
- @Override
- public boolean setString(String str) {
- String[] paths = str.split(",");
- runStyle = new RunStyleExternalBrowser(JUnitShell.this, paths);
- numClients = paths.length;
- return runStyle != null;
- }
- });
-
- registerHandler(new ArgHandler() {
-
- @Override
- public String[] getDefaultArgs() {
- return null;
- }
-
- @Override
- public String getPurpose() {
- return "Causes the system to wait for a remote browser to connect";
- }
-
- @Override
- public String getTag() {
- return "-manual";
- }
-
- @Override
- public String[] getTagArgs() {
- return new String[] {"[numClients]"};
- }
-
- @Override
- public int handle(String[] args, int tagIndex) {
- int value = 1;
- if (tagIndex + 1 < args.length) {
- try {
- // See if the next item is an integer.
- value = Integer.parseInt(args[tagIndex + 1]);
- if (value >= 1) {
- setInt(value);
- return 1;
- }
- } catch (NumberFormatException e) {
- // fall-through
- }
- }
- setInt(1);
- return 0;
- }
-
- public void setInt(int value) {
- runStyle = new RunStyleManual(JUnitShell.this, value);
- numClients = value;
- }
-
- });
-
- registerHandler(new ArgHandlerFlag() {
-
- @Override
- public String getPurpose() {
- return "Causes the log window and browser windows to be displayed; useful for debugging";
- }
-
- @Override
- public String getTag() {
- return "-notHeadless";
- }
-
- @Override
- public boolean setFlag() {
- setHeadless(false);
- return true;
- }
- });
-
setRunTomcat(true);
setHeadless(true);