Add a tabKey to the LoadModule message so that we can differentiate between
a reload in the same tab and opening a new tab, if the plugin has that
capability.
Also, rename write* methods for better symmetry and more tests/doc.
Patch by: jat
Review by: amitmanjhi
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5936 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html b/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
index 17ae17c..bb8c0d4 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
@@ -229,7 +229,7 @@
}
} catch (e) {
}
- }
+ }
loadIframe("http://google-web-toolkit.googlecode.com/svn/trunk/plugins/MissingBrowserPlugin.html");
} else {
if (!plugin.connect(url, topWin.__gwt_SessionID, $hosted, $moduleName,
diff --git a/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java b/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java
index 7542206..1633bfe 100644
--- a/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java
@@ -76,8 +76,9 @@
}
public ModuleSpaceHost createModuleSpaceHost(TreeLogger logger,
- String moduleName, String userAgent, String url, String sessionKey,
- String remoteEndpoint) throws UnableToCompleteException {
+ String moduleName, String userAgent, String url, String tabKey,
+ String sessionKey, String remoteEndpoint)
+ throws UnableToCompleteException {
throw new UnsupportedOperationException();
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java b/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java
index 019f268..41e7a27 100644
--- a/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java
+++ b/dev/core/src/com/google/gwt/dev/shell/BrowserWidgetHost.java
@@ -53,12 +53,14 @@
* @param logger
* @param moduleName
* @param userAgent
- * @param url URL of top-level window (may be null for old browser plugins)
- * @param sessionKey unique session key (may be null for old browser plugins)
+ * @param url URL of top-level window, may be null for old browser plugins
+ * @param tabKey opaque key for the tab, may be empty string if the plugin
+ * can't distinguish tabs or null if using an old browser plugin
+ * @param sessionKey unique session key, may be null for old browser plugins
* @param remoteEndpoint
*/
ModuleSpaceHost createModuleSpaceHost(TreeLogger logger, String moduleName,
- String userAgent, String url, String sessionKey,
+ String userAgent, String url, String tabKey, String sessionKey,
String remoteEndpoint) throws UnableToCompleteException;
TreeLogger getLogger();
diff --git a/dev/oophm/src/com/google/gwt/dev/OophmHostedModeBase.java b/dev/oophm/src/com/google/gwt/dev/OophmHostedModeBase.java
index b8fe956..6b40983 100644
--- a/dev/oophm/src/com/google/gwt/dev/OophmHostedModeBase.java
+++ b/dev/oophm/src/com/google/gwt/dev/OophmHostedModeBase.java
@@ -142,8 +142,9 @@
}
public ModuleSpaceHost createModuleSpaceHost(TreeLogger mainLogger,
- String moduleName, String userAgent, String url, String sessionKey,
- String remoteSocket) throws UnableToCompleteException {
+ String moduleName, String userAgent, String url, String tabKey,
+ String sessionKey, String remoteSocket)
+ throws UnableToCompleteException {
TreeLogger logger = mainLogger;
TreeLogger.Type maxLevel = TreeLogger.INFO;
if (mainLogger instanceof AbstractTreeLogger) {
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannel.java b/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannel.java
index 85bafa4..e76ea89 100644
--- a/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannel.java
+++ b/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannel.java
@@ -158,9 +158,22 @@
public abstract ExceptionOrReturnValue invoke(BrowserChannel channel,
Value thisObj, int dispId, Value[] args);
+ /**
+ * Load a new instance of a module.
+ *
+ * @param logger
+ * @param channel
+ * @param moduleName
+ * @param userAgent
+ * @param url top-level URL of the main page, null if using an old plugin
+ * @param tabKey opaque key of the tab, may be empty if the plugin can't
+ * distinguish tabs or null if using an old plugin
+ * @param sessionKey opaque key for this session, null if using an old plugin
+ * @return a TreeLogger to use for the module's logs
+ */
public abstract TreeLogger loadModule(TreeLogger logger,
BrowserChannel channel, String moduleName, String userAgent, String url,
- String sessionKey);
+ String tabKey, String sessionKey);
public abstract ExceptionOrReturnValue setProperty(BrowserChannel channel,
int refId, int dispId, Value newValue);
@@ -570,7 +583,7 @@
stream.writeByte(MessageType.CHECK_VERSIONS.ordinal());
stream.writeInt(minVersion);
stream.writeInt(maxVersion);
- writeUntaggedString(stream, hostedHtmlVersion);
+ writeUtf8String(stream, hostedHtmlVersion);
stream.flush();
}
}
@@ -610,7 +623,7 @@
stream.writeByte(MessageType.CHOOSE_TRANSPORT.ordinal());
stream.writeInt(transports.length);
for (String transport : transports) {
- writeUntaggedString(stream, transport);
+ writeUtf8String(stream, transport);
}
}
}
@@ -643,7 +656,7 @@
public void send() throws IOException {
DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
stream.writeByte(MessageType.FATAL_ERROR.ordinal());
- writeUntaggedString(stream, error);
+ writeUtf8String(stream, error);
}
}
@@ -751,7 +764,7 @@
final DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
stream.writeByte(MessageType.INVOKE.ordinal());
- writeUntaggedString(stream, methodName);
+ writeUtf8String(stream, methodName);
writeValue(stream, thisRef);
stream.writeInt(args.length);
for (int i = 0; i < args.length; i++) {
@@ -896,7 +909,7 @@
throws IOException {
DataOutputStream stream = channel.getStreamToOtherSide();
stream.write(MessageType.LOAD_JSNI.ordinal());
- writeUntaggedString(stream, js);
+ writeUtf8String(stream, js);
stream.flush();
}
@@ -931,10 +944,11 @@
throws IOException {
DataInputStream stream = channel.getStreamFromOtherSide();
String url = readUtf8String(stream);
+ String tabKey = readUtf8String(stream);
String sessionKey = readUtf8String(stream);
String moduleName = readUtf8String(stream);
String userAgent = readUtf8String(stream);
- return new LoadModuleMessage(channel, url, sessionKey, moduleName,
+ return new LoadModuleMessage(channel, url, tabKey, sessionKey, moduleName,
userAgent);
}
@@ -946,10 +960,30 @@
private final String sessionKey;
+ private final String tabKey;
+
+ /**
+ * Creates a LoadModule message to be sent to the server.
+ *
+ * @param channel BrowserChannel instance
+ * @param url URL of main top-level window - may not be null
+ * @param tabKey opaque key identifying the tab in the browser, or an
+ * empty string if it cannot be determined - may not be null
+ * @param sessionKey opaque key identifying a particular session (ie,
+ * group of modules) - may not be null
+ * @param moduleName name of GWT module to load - may not be null
+ * @param userAgent user agent identifier of the browser - may not be null
+ */
public LoadModuleMessage(BrowserChannel channel, String url,
- String sessionKey, String moduleName, String userAgent) {
+ String tabKey, String sessionKey, String moduleName, String userAgent) {
super(channel);
+ assert url != null;
+ assert tabKey != null;
+ assert sessionKey != null;
+ assert moduleName != null;
+ assert userAgent != null;
this.url = url;
+ this.tabKey = tabKey;
this.sessionKey = sessionKey;
this.moduleName = moduleName;
this.userAgent = userAgent;
@@ -963,6 +997,10 @@
return sessionKey;
}
+ public String getTabKey() {
+ return tabKey;
+ }
+
public String getUrl() {
return url;
}
@@ -975,10 +1013,11 @@
public void send() throws IOException {
DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
stream.writeByte(MessageType.LOAD_MODULE.ordinal());
- writeUntaggedString(stream, url);
- writeUntaggedString(stream, sessionKey);
- writeUntaggedString(stream, moduleName);
- writeUntaggedString(stream, userAgent);
+ writeUtf8String(stream, url);
+ writeUtf8String(stream, tabKey);
+ writeUtf8String(stream, sessionKey);
+ writeUtf8String(stream, moduleName);
+ writeUtf8String(stream, userAgent);
stream.flush();
}
}
@@ -1070,8 +1109,8 @@
DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
stream.writeByte(MessageType.OLD_LOAD_MODULE.ordinal());
stream.writeInt(protoVersion);
- writeUntaggedString(stream, moduleName);
- writeUntaggedString(stream, userAgent);
+ writeUtf8String(stream, moduleName);
+ writeUtf8String(stream, userAgent);
stream.flush();
}
}
@@ -1227,8 +1266,8 @@
public void send() throws IOException {
DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
stream.writeByte(MessageType.SWITCH_TRANSPORT.ordinal());
- writeUntaggedString(stream, transport);
- writeUntaggedString(stream, transportArgs);
+ writeUtf8String(stream, transport);
+ writeUtf8String(stream, transportArgs);
}
}
@@ -1366,50 +1405,14 @@
return types[type];
}
- protected static void writeBoolean(DataOutputStream stream, boolean value)
- throws IOException {
- stream.writeByte(ValueType.BOOLEAN.getTag());
- stream.writeBoolean(value);
- }
-
- protected static void writeByte(DataOutputStream stream, byte value)
- throws IOException {
- stream.writeByte(ValueType.BYTE.getTag());
- stream.writeByte(value);
- }
-
- protected static void writeChar(DataOutputStream stream, char value)
- throws IOException {
- stream.writeByte(ValueType.CHAR.getTag());
- stream.writeChar(value);
- }
-
- protected static void writeDouble(DataOutputStream stream, double value)
- throws IOException {
- stream.writeByte(ValueType.DOUBLE.getTag());
- stream.writeDouble(value);
- }
-
- protected static void writeFloat(DataOutputStream stream, float value)
- throws IOException {
- stream.writeByte(ValueType.FLOAT.getTag());
- stream.writeFloat(value);
- }
-
- protected static void writeInt(DataOutputStream stream, int value)
- throws IOException {
- stream.writeByte(ValueType.INT.getTag());
- stream.writeInt(value);
- }
-
protected static void writeJavaObject(DataOutputStream stream,
JavaObjectRef value) throws IOException {
stream.writeByte(ValueType.JAVA_OBJECT.getTag());
stream.writeInt(value.getRefid());
}
- protected static void writeJsObject(DataOutputStream stream, JsObjectRef value)
- throws IOException {
+ protected static void writeJsObject(DataOutputStream stream,
+ JsObjectRef value) throws IOException {
stream.writeByte(ValueType.JS_OBJECT.getTag());
stream.writeInt(value.getRefid());
}
@@ -1418,13 +1421,55 @@
stream.writeByte(ValueType.NULL.getTag());
}
- protected static void writeShort(DataOutputStream stream, short value)
+ protected static void writeTaggedBoolean(DataOutputStream stream,
+ boolean value) throws IOException {
+ stream.writeByte(ValueType.BOOLEAN.getTag());
+ stream.writeBoolean(value);
+ }
+
+ protected static void writeTaggedByte(DataOutputStream stream, byte value)
+ throws IOException {
+ stream.writeByte(ValueType.BYTE.getTag());
+ stream.writeByte(value);
+ }
+
+ protected static void writeTaggedChar(DataOutputStream stream, char value)
+ throws IOException {
+ stream.writeByte(ValueType.CHAR.getTag());
+ stream.writeChar(value);
+ }
+
+ protected static void writeTaggedDouble(DataOutputStream stream, double value)
+ throws IOException {
+ stream.writeByte(ValueType.DOUBLE.getTag());
+ stream.writeDouble(value);
+ }
+
+ protected static void writeTaggedFloat(DataOutputStream stream, float value)
+ throws IOException {
+ stream.writeByte(ValueType.FLOAT.getTag());
+ stream.writeFloat(value);
+ }
+
+ protected static void writeTaggedInt(DataOutputStream stream, int value)
+ throws IOException {
+ stream.writeByte(ValueType.INT.getTag());
+ stream.writeInt(value);
+ }
+
+ protected static void writeTaggedShort(DataOutputStream stream, short value)
throws IOException {
stream.writeByte(ValueType.SHORT.getTag());
stream.writeShort(value);
}
- protected static void writeUntaggedString(DataOutputStream stream, String data)
+ protected static void writeTaggedString(DataOutputStream stream, String data)
+ throws IOException {
+ stream.writeByte(ValueType.STRING.getTag());
+ writeUtf8String(stream, data);
+ }
+
+ protected static void writeUtf8String(DataOutputStream stream, String data)
throws IOException {
try {
final byte[] bytes = data.getBytes("UTF8");
@@ -1436,12 +1481,6 @@
}
}
- protected static void writeUtf8String(DataOutputStream stream, String data)
- throws IOException {
- stream.writeByte(ValueType.STRING.getTag());
- writeUntaggedString(stream, data);
- }
-
protected static void writeValue(DataOutputStream stream, Value value)
throws IOException {
if (value.isNull()) {
@@ -1453,21 +1492,21 @@
} else if (value.isJavaObject()) {
writeJavaObject(stream, value.getJavaObject());
} else if (value.isBoolean()) {
- writeBoolean(stream, value.getBoolean());
+ writeTaggedBoolean(stream, value.getBoolean());
} else if (value.isByte()) {
- writeByte(stream, value.getByte());
+ writeTaggedByte(stream, value.getByte());
} else if (value.isChar()) {
- writeChar(stream, value.getChar());
+ writeTaggedChar(stream, value.getChar());
} else if (value.isShort()) {
- writeShort(stream, value.getShort());
+ writeTaggedShort(stream, value.getShort());
} else if (value.isDouble()) {
- writeDouble(stream, value.getDouble());
+ writeTaggedDouble(stream, value.getDouble());
} else if (value.isFloat()) {
- writeFloat(stream, value.getFloat());
+ writeTaggedFloat(stream, value.getFloat());
} else if (value.isInt()) {
- writeInt(stream, value.getInt());
+ writeTaggedInt(stream, value.getInt());
} else if (value.isString()) {
- writeUtf8String(stream, value.getString());
+ writeTaggedString(stream, value.getString());
} else {
assert false;
}
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelServer.java b/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelServer.java
index 4b98529..dd59992 100644
--- a/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelServer.java
+++ b/dev/oophm/src/com/google/gwt/dev/shell/BrowserChannelServer.java
@@ -271,6 +271,7 @@
// TODO(jat): add support for getting the a shim plugin downloading the
// real plugin via a GetRealPlugin message before CheckVersions
String url = null;
+ String tabKey = null;
String sessionKey = null;
switch (type) {
case OLD_LOAD_MODULE:
@@ -327,6 +328,7 @@
}
LoadModuleMessage loadModule = LoadModuleMessage.receive(this);
url = loadModule.getUrl();
+ tabKey = loadModule.getTabKey();
sessionKey = loadModule.getSessionKey();
moduleName = loadModule.getModuleName();
userAgent = loadModule.getUserAgent();
@@ -340,7 +342,7 @@
"Hosting " + moduleName + " for " + userAgent + " on " + url + " @ "
+ sessionKey);
logger = handler.loadModule(logger, this, moduleName, userAgent, url,
- sessionKey);
+ tabKey, sessionKey);
try {
// send LoadModule response
ReturnMessage.send(this, false, new Value());
diff --git a/dev/oophm/src/com/google/gwt/dev/shell/OophmSessionHandler.java b/dev/oophm/src/com/google/gwt/dev/shell/OophmSessionHandler.java
index 1eff0dc..ff73041 100644
--- a/dev/oophm/src/com/google/gwt/dev/shell/OophmSessionHandler.java
+++ b/dev/oophm/src/com/google/gwt/dev/shell/OophmSessionHandler.java
@@ -155,13 +155,14 @@
@Override
public TreeLogger loadModule(TreeLogger logger, BrowserChannel channel,
- String moduleName, String userAgent, String url, String sessionKey) {
+ String moduleName, String userAgent, String url, String tabKey,
+ String sessionKey) {
try {
// Attach a new ModuleSpace to make it programmable.
//
BrowserChannelServer serverChannel = (BrowserChannelServer) channel;
ModuleSpaceHost msh = host.createModuleSpaceHost(logger, moduleName,
- userAgent, url, sessionKey, channel.getRemoteEndpoint());
+ userAgent, url, tabKey, sessionKey, channel.getRemoteEndpoint());
this.logger = logger = msh.getLogger();
ModuleSpace moduleSpace = new ModuleSpaceOOPHM(msh, moduleName,
serverChannel);
diff --git a/dev/oophm/test/com/google/gwt/dev/shell/BrowserChannelTest.java b/dev/oophm/test/com/google/gwt/dev/shell/BrowserChannelTest.java
index 9f472f2..ba7b1d7 100644
--- a/dev/oophm/test/com/google/gwt/dev/shell/BrowserChannelTest.java
+++ b/dev/oophm/test/com/google/gwt/dev/shell/BrowserChannelTest.java
@@ -224,17 +224,81 @@
BrowserChannelException {
String url = "http://www.google.com";
String sessionKey = "asdkfjklAI*23ja";
+ String tabKey = "372F4";
String moduleName = "org.example.Hello";
String userAgent = "Firefox";
- new LoadModuleMessage(channel, url, sessionKey, moduleName,
+ new LoadModuleMessage(channel, url, tabKey, sessionKey, moduleName,
userAgent).send();
MessageType type = channel.readMessageType();
assertEquals(MessageType.LOAD_MODULE, type);
LoadModuleMessage message = LoadModuleMessage.receive(channel);
assertEquals(url, message.getUrl());
+ assertEquals(tabKey, message.getTabKey());
assertEquals(sessionKey, message.getSessionKey());
assertEquals(moduleName, message.getModuleName());
assertEquals(userAgent, message.getUserAgent());
+ url = "https://www.google.com:8443/extra_stuff_that_is_really_long?foo";
+ sessionKey = "asdfkasdjfkjaskldfjkajsfkjasdfjklaasdkfjklAI*23ja";
+ tabKey = "";
+ moduleName = "showcase";
+ userAgent = "Safari";
+ new LoadModuleMessage(channel, url, tabKey, sessionKey, moduleName,
+ userAgent).send();
+ type = channel.readMessageType();
+ assertEquals(MessageType.LOAD_MODULE, type);
+ message = LoadModuleMessage.receive(channel);
+ assertEquals(url, message.getUrl());
+ assertEquals(tabKey, message.getTabKey());
+ assertEquals(sessionKey, message.getSessionKey());
+ assertEquals(moduleName, message.getModuleName());
+ assertEquals(userAgent, message.getUserAgent());
+
+ // create a separate channel so we don't cause problems with partial
+ // messages written to the stream
+ TemporaryBufferStream tempBufferStream = new TemporaryBufferStream();
+ TestBrowserChannel trashableChannel = new TestBrowserChannel(
+ tempBufferStream.getInputStream(),
+ tempBufferStream.getOutputStream());
+
+ try {
+ new LoadModuleMessage(trashableChannel, null, tabKey, sessionKey, moduleName,
+ userAgent).send();
+ fail("Expected exception with null url");
+ } catch (Exception expected) {
+ // will be AssertionError if assertions are turned on, otherwise NPE
+ }
+
+ try {
+ new LoadModuleMessage(trashableChannel, url, null, sessionKey, moduleName,
+ userAgent).send();
+ fail("Expected exception with null tabKey");
+ } catch (Exception expected) {
+ // will be AssertionError if assertions are turned on, otherwise NPE
+ }
+
+ try {
+ new LoadModuleMessage(trashableChannel, url, tabKey, null, moduleName,
+ userAgent).send();
+ fail("Expected exception with null sessionKey");
+ } catch (Exception expected) {
+ // will be AssertionError if assertions are turned on, otherwise NPE
+ }
+
+ try {
+ new LoadModuleMessage(trashableChannel, url, tabKey, sessionKey, null,
+ userAgent).send();
+ fail("Expected exception with null moduleName");
+ } catch (Exception expected) {
+ // will be AssertionError if assertions are turned on, otherwise NPE
+ }
+
+ try {
+ new LoadModuleMessage(trashableChannel, url, tabKey, sessionKey, moduleName,
+ null).send();
+ fail("Expected exception with null userAgent");
+ } catch (Exception expected) {
+ // will be AssertionError if assertions are turned on, otherwise NPE
+ }
}
public void testOldLoadModuleMessage() throws IOException,