+++ /dev/null
-/*
- * 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.dev.shell.BrowserChannelPatched.SessionHandler.ExceptionOrReturnValue;
-import com.google.gwt.dev.shell.BrowserChannelPatched.SessionHandler.SpecialDispatchId;
-import com.google.gwt.dev.shell.BrowserChannelPatched.Value.ValueType;
-import com.google.gwt.util.tools.Utility;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.Socket;
-import java.util.Set;
-
-/**
- *
- */
-public abstract class BrowserChannelPatched {
-
- /**
- * An error indicating that the remote side died and we should unroll the
- * call stack as painlessly as possible to allow cleanup.
- */
- public static class RemoteDeathError extends Error {
-
- public RemoteDeathError(Throwable cause) {
- super("Remote connection lost", cause);
- }
- }
-
- /**
- * Class representing a reference to a Java object.
- */
- public static class JavaObjectRef implements RemoteObjectRef {
- private int refId;
-
- public JavaObjectRef(int refId) {
- this.refId = refId;
- }
-
- public int getRefid() {
- return Math.abs(refId);
- }
-
- @Override
- public int hashCode() {
- return refId;
- }
-
- public boolean isException() {
- return refId < 0;
- }
-
- @Override
- public String toString() {
- return "JavaObjectRef(ref=" + refId + ")";
- }
- }
-
- /**
- * Class representing a reference to a JS object.
- */
- public static class JsObjectRef implements RemoteObjectRef {
-
- private int refId;
-
- public JsObjectRef(int refId) {
- this.refId = refId;
- }
-
- @Override
- public boolean equals(Object o) {
- return (o instanceof JsObjectRef) && ((JsObjectRef) o).refId == refId;
- }
-
- public int getRefid() {
- // exceptions are negative, so we get the absolute value
- return Math.abs(refId);
- }
-
- @Override
- public int hashCode() {
- return refId;
- }
-
- public boolean isException() {
- return refId < 0;
- }
-
- @Override
- public String toString() {
- return "JsObjectRef(" + refId + ")";
- }
- }
-
- /**
- * Enumeration of message type ids.
- *
- * <p>Ids are used instead of relying on the ordinal to avoid sychronization
- * problems with the client.
- */
- public enum MessageType {
- /**
- * A message to invoke a method on the other side of the wire. Note that
- * the messages are asymmetric -- see {@link InvokeOnClientMessage} and
- * {@link InvokeOnServerMessage}.
- */
- INVOKE(0),
-
- /**
- * Returns the result of an INVOKE, INVOKE_SPECIAL, or LOAD_MODULE message.
- */
- RETURN(1),
-
- /**
- * v1 LOAD_MODULE message.
- */
- OLD_LOAD_MODULE(2),
-
- /**
- * Normal closure of the connection.
- */
- QUIT(3),
-
- /**
- * A request by the server to load JSNI source into the client's JS engine.
- */
- LOAD_JSNI(4),
-
- INVOKE_SPECIAL(5),
-
- FREE_VALUE(6),
-
- /**
- * Abnormal termination of the connection.
- */
- FATAL_ERROR(7),
-
- CHECK_VERSIONS(8),
-
- PROTOCOL_VERSION(9),
-
- CHOOSE_TRANSPORT(10),
-
- SWITCH_TRANSPORT(11),
-
- LOAD_MODULE(12),
-
- REQUEST_ICON(13),
-
- USER_AGENT_ICON(14),
-
- REQUEST_PLUGIN(15);
-
- private final int id;
-
- private MessageType(int id) {
- this.id = id;
- }
-
- public int getId() {
- return id;
- }
- }
-
- /**
- * Represents an object on the other side of the channel, known to this side
- * by an reference ID.
- */
- public interface RemoteObjectRef {
-
- /**
- * @return the reference ID for this object.
- */
- int getRefid();
- }
-
- /**
- * Hook interface for responding to messages.
- */
- public abstract static class SessionHandler<T extends BrowserChannelPatched> {
-
- /**
- * Wrapper to return both a return value/exception and a flag as to whether
- * an exception was thrown or not.
- */
- public static class ExceptionOrReturnValue {
- private final boolean isException;
- private final Value returnValue;
-
- public ExceptionOrReturnValue(boolean isException, Value returnValue) {
- this.isException = isException;
- this.returnValue = returnValue;
- }
-
- public Value getReturnValue() {
- return returnValue;
- }
-
- public boolean isException() {
- return isException;
- }
- }
-
- /**
- * Enumeration of dispatch IDs on object 0 (the ServerMethods object).
- *
- * <p>Ids are set specifically rather than relying on the ordinal to avoid
- * synchronization problems with the client.
- *
- * TODO: hasMethod/hasProperty no longer used, remove them!
- */
- public enum SpecialDispatchId {
- HasMethod(0), HasProperty(1), GetProperty(2), SetProperty(3);
-
- private final int id;
-
- private SpecialDispatchId(int id) {
- this.id = id;
- }
-
- public int getId() {
- return id;
- }
- }
-
- public abstract void freeValue(T channel, int[] ids);
- }
-
- /**
- * Represents a value for BrowserChannel.
- */
- public static class Value {
- /**
- * Enum of type tags sent across the wire.
- */
- public enum ValueType {
- /**
- * Primitive values.
- */
- NULL(0), BOOLEAN(1), BYTE(2), CHAR(3), SHORT(4), INT(5), LONG(6),
- FLOAT(7), DOUBLE(8), STRING(9),
-
- /**
- * Representations of Java or JS objects, sent as an index into a table
- * kept on the side holding the actual object.
- */
- JAVA_OBJECT(10), JS_OBJECT(11),
-
- /**
- * A Javascript undef value, also used for void returns.
- */
- UNDEFINED(12);
-
- private final int id;
-
- private ValueType(int id) {
- this.id = id;
- }
-
- byte getTag() {
- return (byte) id;
- }
- }
-
- /**
- * Type tag value.
- */
- private ValueType type = ValueType.UNDEFINED;
-
- /**
- * Represents a value sent/received across the wire.
- */
- private Object value = null;
-
- public Value() {
- }
-
- public Value(Object obj) {
- convertFromJavaValue(obj);
- }
-
- /**
- * Convert a Java object to a value. Objects must be primitive wrappers,
- * Strings, or JsObjectRef/JavaObjectRef instances.
- *
- * @param obj value to convert.
- */
- public void convertFromJavaValue(Object obj) {
- if (obj == null) {
- type = ValueType.NULL;
- } else if (obj instanceof Boolean) {
- type = ValueType.BOOLEAN;
- } else if (obj instanceof Byte) {
- type = ValueType.BYTE;
- } else if (obj instanceof Character) {
- type = ValueType.CHAR;
- } else if (obj instanceof Double) {
- type = ValueType.DOUBLE;
- } else if (obj instanceof Float) {
- type = ValueType.FLOAT;
- } else if (obj instanceof Integer) {
- type = ValueType.INT;
- } else if (obj instanceof Long) {
- type = ValueType.LONG;
- } else if (obj instanceof Short) {
- type = ValueType.SHORT;
- } else if (obj instanceof String) {
- type = ValueType.STRING;
- } else if (obj instanceof JsObjectRef) {
- // TODO: exception handling?
- type = ValueType.JS_OBJECT;
- } else if (obj instanceof JavaObjectRef) {
- // TODO: exception handling?
- type = ValueType.JAVA_OBJECT;
- } else {
- type = ValueType.STRING;
- obj = String.valueOf(obj);
-// throw new RuntimeException(
-// "Unexpected Java type in convertFromJavaValue: " + obj.getClass() + " " + obj);
- }
- value = obj;
- }
-
- /**
- * Convert a value to the requested Java type.
- *
- * @param reqType type to convert to
- * @return value as that type.
- */
- public Object convertToJavaType(Class<?> reqType) {
- if (reqType.isArray()) {
- // TODO(jat): handle arrays?
- }
- if (reqType.equals(Boolean.class)) {
- assert type == ValueType.BOOLEAN;
- return value;
- } else if (reqType.equals(Byte.class) || reqType.equals(byte.class)) {
- assert isNumber();
- return Byte.valueOf(((Number) value).byteValue());
- } else if (reqType.equals(Character.class) || reqType.equals(char.class)) {
- if (type == ValueType.CHAR) {
- return value;
- } else {
- assert isNumber();
- return Character.valueOf((char) ((Number) value).shortValue());
- }
- } else if (reqType.equals(Double.class) || reqType.equals(double.class)) {
- assert isNumber();
- return Double.valueOf(((Number) value).doubleValue());
- } else if (reqType.equals(Float.class) || reqType.equals(float.class)) {
- assert isNumber();
- return Float.valueOf(((Number) value).floatValue());
- } else if (reqType.equals(Integer.class) || reqType.equals(int.class)) {
- assert isNumber();
- return Integer.valueOf(((Number) value).intValue());
- } else if (reqType.equals(Long.class) || reqType.equals(long.class)) {
- assert isNumber();
- return Long.valueOf(((Number) value).longValue());
- } else if (reqType.equals(Short.class) || reqType.equals(short.class)) {
- assert isNumber();
- return Short.valueOf(((Number) value).shortValue());
- } else if (reqType.equals(String.class)) {
- assert type == ValueType.STRING;
- return value;
- } else {
- // Wants an object, caller must deal with object references.
- return value;
- }
- }
-
- public boolean getBoolean() {
- assert type == ValueType.BOOLEAN;
- return ((Boolean) value).booleanValue();
- }
-
- public byte getByte() {
- assert type == ValueType.BYTE;
- return ((Byte) value).byteValue();
- }
-
- public char getChar() {
- assert type == ValueType.CHAR;
- return ((Character) value).charValue();
- }
-
- public double getDouble() {
- assert type == ValueType.DOUBLE;
- return ((Double) value).doubleValue();
- }
-
- public float getFloat() {
- assert type == ValueType.FLOAT;
- return ((Float) value).floatValue();
- }
-
- public int getInt() {
- assert type == ValueType.INT;
- return ((Integer) value).intValue();
- }
-
- public JavaObjectRef getJavaObject() {
- assert type == ValueType.JAVA_OBJECT;
- return (JavaObjectRef) value;
- }
-
- public JsObjectRef getJsObject() {
- assert type == ValueType.JS_OBJECT;
- return (JsObjectRef) value;
- }
-
- public long getLong() {
- assert type == ValueType.LONG;
- return ((Long) value).longValue();
- }
-
- public short getShort() {
- assert type == ValueType.SHORT;
- return ((Short) value).shortValue();
- }
-
- public String getString() {
- assert type == ValueType.STRING;
- return (String) value;
- }
-
- public ValueType getType() {
- return type;
- }
-
- public Object getValue() {
- return value;
- }
-
- public boolean isBoolean() {
- return type == ValueType.BOOLEAN;
- }
-
- public boolean isByte() {
- return type == ValueType.BYTE;
- }
-
- public boolean isChar() {
- return type == ValueType.CHAR;
- }
-
- public boolean isDouble() {
- return type == ValueType.DOUBLE;
- }
-
- public boolean isFloat() {
- return type == ValueType.FLOAT;
- }
-
- public boolean isInt() {
- return type == ValueType.INT;
- }
-
- public boolean isJavaObject() {
- return type == ValueType.JAVA_OBJECT;
- }
-
- public boolean isJsObject() {
- return type == ValueType.JS_OBJECT;
- }
-
- public boolean isLong() {
- return type == ValueType.LONG;
- }
-
- public boolean isNull() {
- return type == ValueType.NULL;
- }
-
- public boolean isNumber() {
- switch (type) {
- case BYTE:
- case CHAR:
- case DOUBLE:
- case FLOAT:
- case INT:
- case LONG:
- case SHORT:
- return true;
- default:
- return false;
- }
- }
-
- public boolean isPrimitive() {
- switch (type) {
- case BOOLEAN:
- case BYTE:
- case CHAR:
- case DOUBLE:
- case FLOAT:
- case INT:
- case LONG:
- case SHORT:
- return true;
- default:
- return false;
- }
- }
-
- public boolean isShort() {
- return type == ValueType.SHORT;
- }
-
- public boolean isString() {
- return type == ValueType.STRING;
- }
-
- public boolean isUndefined() {
- return type == ValueType.UNDEFINED;
- }
-
- public void setBoolean(boolean val) {
- type = ValueType.BOOLEAN;
- value = Boolean.valueOf(val);
- }
-
- public void setByte(byte val) {
- type = ValueType.BYTE;
- value = Byte.valueOf(val);
- }
-
- public void setChar(char val) {
- type = ValueType.CHAR;
- value = Character.valueOf(val);
- }
-
- public void setDouble(double val) {
- type = ValueType.DOUBLE;
- value = Double.valueOf(val);
- }
-
- public void setFloat(float val) {
- type = ValueType.FLOAT;
- value = Float.valueOf(val);
- }
-
- public void setInt(int val) {
- type = ValueType.INT;
- value = Integer.valueOf(val);
- }
-
- public void setJavaObject(JavaObjectRef val) {
- type = ValueType.JAVA_OBJECT;
- value = val;
- }
-
- public void setJsObject(JsObjectRef val) {
- type = ValueType.JS_OBJECT;
- value = val;
- }
-
- public void setLong(long val) {
- type = ValueType.BOOLEAN;
- value = Long.valueOf(val);
- }
-
- public void setNull() {
- type = ValueType.NULL;
- value = null;
- }
-
- public void setShort(short val) {
- type = ValueType.SHORT;
- value = Short.valueOf(val);
- }
-
- public void setString(String val) {
- type = ValueType.STRING;
- value = val;
- }
-
- public void setUndefined() {
- type = ValueType.UNDEFINED;
- value = null;
- }
-
- @Override
- public String toString() {
- return type + ": " + value;
- }
- }
-
- /**
- * The initial request from the client, supplies a range of supported versions
- * and the version from hosted.html (so stale copies on an external server
- * can be detected).
- */
- protected static class CheckVersionsMessage extends Message {
-
- public static CheckVersionsMessage receive(BrowserChannelPatched channel)
- throws IOException {
- DataInputStream stream = channel.getStreamFromOtherSide();
- int minVersion = stream.readInt();
- int maxVersion = stream.readInt();
- String hostedHtmlVersion = readUtf8String(stream);
- return new CheckVersionsMessage(channel, minVersion, maxVersion,
- hostedHtmlVersion);
- }
-
- private final String hostedHtmlVersion;
-
- private final int maxVersion;
-
- private final int minVersion;
-
- public CheckVersionsMessage(BrowserChannelPatched channel, int minVersion,
- int maxVersion, String hostedHtmlVersion) {
- super(channel);
- this.minVersion = minVersion;
- this.maxVersion = maxVersion;
- this.hostedHtmlVersion = hostedHtmlVersion;
- }
-
- public String getHostedHtmlVersion() {
- return hostedHtmlVersion;
- }
-
- public int getMaxVersion() {
- return maxVersion;
- }
-
- public int getMinVersion() {
- return minVersion;
- }
-
- @Override
- public void send() throws IOException {
- DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
- stream.writeByte(MessageType.CHECK_VERSIONS.getId());
- stream.writeInt(minVersion);
- stream.writeInt(maxVersion);
- writeUtf8String(stream, hostedHtmlVersion);
- stream.flush();
- }
- }
-
- /**
- * A message from the client giving a list of supported connection methods
- * and requesting the server choose one of them to switch protocol traffic to.
- */
- protected static class ChooseTransportMessage extends Message {
-
- public static ChooseTransportMessage receive(BrowserChannelPatched channel)
- throws IOException {
- DataInputStream stream = channel.getStreamFromOtherSide();
- int n = stream.readInt();
- String[] transports = new String[n];
- for (int i = 0; i < n; ++i) {
- transports[i] = readUtf8String(stream);
- }
- return new ChooseTransportMessage(channel, transports);
- }
-
- private final String[] transports;
-
- public ChooseTransportMessage(BrowserChannelPatched channel,
- String[] transports) {
- super(channel);
- this.transports = transports;
- }
-
- public String[] getTransports() {
- return transports;
- }
-
- @Override
- public void send() throws IOException {
- DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
- stream.writeByte(MessageType.CHOOSE_TRANSPORT.getId());
- stream.writeInt(transports.length);
- for (String transport : transports) {
- writeUtf8String(stream, transport);
- }
- }
- }
-
- /**
- * A message reporting a connection error to the client.
- */
- protected static class FatalErrorMessage extends Message {
-
- public static FatalErrorMessage receive(BrowserChannelPatched channel)
- throws IOException {
- DataInputStream stream = channel.getStreamFromOtherSide();
- // NOTE: Tag has already been read.
- String error = readUtf8String(stream);
- return new FatalErrorMessage(channel, error);
- }
-
- private final String error;
-
- public FatalErrorMessage(BrowserChannelPatched channel, String error) {
- super(channel);
- this.error = error;
- }
-
- public String getError() {
- return error;
- }
-
- @Override
- public void send() throws IOException {
- DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
- stream.writeByte(MessageType.FATAL_ERROR.getId());
- writeUtf8String(stream, error);
- }
- }
-
- /**
- * A message asking the other side to free object references. Note that there
- * is no response to this message, and this must only be sent immediately
- * before an Invoke or Return message.
- */
- protected static class FreeMessage extends Message {
- public static FreeMessage receive(BrowserChannelPatched channel)
- throws IOException {
- DataInputStream stream = channel.getStreamFromOtherSide();
- int numIds = stream.readInt();
- // TODO: sanity check id count
- int ids[] = new int[numIds];
- for (int i = 0; i < numIds; ++i) {
- ids[i] = stream.readInt();
- }
- return new FreeMessage(channel, ids);
- }
-
- public static void send(BrowserChannelPatched channel, int[] ids)
- throws IOException {
- DataOutputStream stream = channel.getStreamToOtherSide();
- stream.writeByte(MessageType.FREE_VALUE.getId());
- stream.writeInt(ids.length);
- for (int id : ids) {
- stream.writeInt(id);
- }
- stream.flush();
- }
-
- private final int ids[];
-
- public FreeMessage(BrowserChannelPatched channel, int[] ids) {
- super(channel);
- this.ids = ids;
- }
-
- public int[] getIds() {
- return ids;
- }
-
- @Override
- public boolean isAsynchronous() {
- return true;
- }
-
- @Override
- public void send() throws IOException {
- send(getBrowserChannel(), ids);
- }
- }
-
- /**
- * A request from the server to invoke a function on the client.
- *
- * Note that MessageType.INVOKE can refer to either this class
- * or {@link InvokeOnServerMessage} depending on the direction, as the
- * protocol is asymmetric (Java needs a dispatch ID, Javascript needs a
- * name).
- */
- protected static class InvokeOnClientMessage extends Message {
- public static InvokeOnClientMessage receive(BrowserChannelPatched channel)
- throws IOException {
- DataInputStream stream = channel.getStreamFromOtherSide();
- // NOTE: Tag has already been read.
- String methodName = readUtf8String(stream);
- Value thisRef = channel.readValue(stream);
- int argLen = stream.readInt();
- Value[] args = new Value[argLen];
- for (int i = 0; i < argLen; i++) {
- args[i] = channel.readValue(stream);
- }
- return new InvokeOnClientMessage(channel, methodName, thisRef, args);
- }
-
- private final Value[] args;
- private final String methodName;
- private final Value thisRef;
-
- public InvokeOnClientMessage(BrowserChannelPatched channel, String methodName,
- Value thisRef, Value[] args) {
- super(channel);
- this.thisRef = thisRef;
- this.methodName = methodName;
- this.args = args;
- }
-
- public Value[] getArgs() {
- return args;
- }
-
- public String getMethodName() {
- return methodName;
- }
-
- public Value getThis() {
- return thisRef;
- }
-
- @Override
- public void send() throws IOException {
- final DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
-
- stream.writeByte(MessageType.INVOKE.getId());
- writeUtf8String(stream, methodName);
- getBrowserChannel().writeValue(stream, thisRef);
- stream.writeInt(args.length);
- for (int i = 0; i < args.length; i++) {
- getBrowserChannel().writeValue(stream, args[i]);
- }
- stream.flush();
- }
- }
-
- /**
- * A request from the client to invoke a function on the server.
- *
- * Note that MessageType.INVOKE can refer to either this class
- * or {@link InvokeOnClientMessage} depending on the direction, as the
- * protocol is asymmetric (Java needs a dispatch ID, Javascript needs a
- * name).
- */
- protected static class InvokeOnServerMessage extends Message {
- public static InvokeOnServerMessage receive(BrowserChannelPatched channel)
- throws IOException {
- DataInputStream stream = channel.getStreamFromOtherSide();
- // NOTE: Tag has already been read.
- int methodDispatchId = stream.readInt();
- Value thisRef = channel.readValue(stream);
- int argLen = stream.readInt();
- Value[] args = new Value[argLen];
- for (int i = 0; i < argLen; i++) {
- args[i] = channel.readValue(stream);
- }
- return new InvokeOnServerMessage(channel, methodDispatchId, thisRef,
- args);
- }
-
- private final Value[] args;
- private final int methodDispatchId;
- private final Value thisRef;
-
- public InvokeOnServerMessage(BrowserChannelPatched channel, int methodDispatchId,
- Value thisRef, Value[] args) {
- super(channel);
- this.thisRef = thisRef;
- this.methodDispatchId = methodDispatchId;
- this.args = args;
- }
-
- public Value[] getArgs() {
- return args;
- }
-
- public int getMethodDispatchId() {
- return methodDispatchId;
- }
-
- public Value getThis() {
- return thisRef;
- }
-
- @Override
- public void send() throws IOException {
- final DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
-
- stream.writeByte(MessageType.INVOKE.getId());
- stream.writeInt(methodDispatchId);
- getBrowserChannel().writeValue(stream, thisRef);
- stream.writeInt(args.length);
- for (int i = 0; i < args.length; i++) {
- getBrowserChannel().writeValue(stream, args[i]);
- }
- stream.flush();
- }
- }
-
- /**
- * A request from the to invoke a function on the other side.
- */
- protected static class InvokeSpecialMessage extends Message {
- public static InvokeSpecialMessage receive(BrowserChannelPatched channel)
- throws IOException, BrowserChannelException {
- final DataInputStream stream = channel.getStreamFromOtherSide();
- // NOTE: Tag has already been read.
- final int specialMethodInt = stream.readByte();
- SpecialDispatchId[] ids = SpecialDispatchId.values();
- if (specialMethodInt < 0 || specialMethodInt >= ids.length) {
- throw new BrowserChannelException("Invalid dispatch id "
- + specialMethodInt);
- }
- final SpecialDispatchId dispatchId = ids[specialMethodInt];
- final int argLen = stream.readInt();
- final Value[] args = new Value[argLen];
- for (int i = 0; i < argLen; i++) {
- args[i] = channel.readValue(stream);
- }
- return new InvokeSpecialMessage(channel, dispatchId, args);
- }
-
- private final Value[] args;
- private final SpecialDispatchId dispatchId;
-
- public InvokeSpecialMessage(BrowserChannelPatched channel,
- SpecialDispatchId dispatchId, Value[] args) {
- super(channel);
- this.dispatchId = dispatchId;
- this.args = args;
- }
-
- public Value[] getArgs() {
- return args;
- }
-
- public SpecialDispatchId getDispatchId() {
- return dispatchId;
- }
-
- @Override
- public void send() throws IOException {
- final DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
-
- stream.writeByte(MessageType.INVOKE_SPECIAL.getId());
- stream.writeByte(dispatchId.getId());
- stream.writeInt(args.length);
- for (int i = 0; i < args.length; i++) {
- getBrowserChannel().writeValue(stream, args[i]);
- }
- stream.flush();
- }
- }
-
- /**
- * A message sending JSNI code to be evaluated. Note that there is no response
- * to this message, and this must only be sent immediately before an Invoke or
- * Return message.
- */
- protected static class LoadJsniMessage extends Message {
- public static LoadJsniMessage receive(BrowserChannelPatched channel)
- throws IOException {
- DataInputStream stream = channel.getStreamFromOtherSide();
- String js = readUtf8String(stream);
- return new LoadJsniMessage(channel, js);
- }
-
- public static void send(BrowserChannelPatched channel, String js)
- throws IOException {
- DataOutputStream stream = channel.getStreamToOtherSide();
- stream.write(MessageType.LOAD_JSNI.getId());
- writeUtf8String(stream, js);
- stream.flush();
- }
-
- private final String js;
-
- public LoadJsniMessage(BrowserChannelPatched channel, String js) {
- super(channel);
- this.js = js;
- }
-
- public String getJsni() {
- return js;
- }
-
- @Override
- public boolean isAsynchronous() {
- return true;
- }
-
- @Override
- public void send() throws IOException {
- send(getBrowserChannel(), js);
- }
- }
-
- /**
- * A request from the client that the server load and initialize a given
- * module.
- */
- protected static class LoadModuleMessage extends Message {
- public static LoadModuleMessage receive(BrowserChannelPatched channel)
- 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, tabKey, sessionKey, moduleName,
- userAgent);
- }
-
- private final String moduleName;
-
- private final String sessionKey;
-
- private final String tabKey;
-
- private final String url;
-
- private final String userAgent;
-
- /**
- * 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(BrowserChannelPatched channel, String url,
- 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;
- }
-
- public String getModuleName() {
- return moduleName;
- }
-
- public String getSessionKey() {
- return sessionKey;
- }
-
- public String getTabKey() {
- return tabKey;
- }
-
- public String getUrl() {
- return url;
- }
-
- public String getUserAgent() {
- return userAgent;
- }
-
- @Override
- public void send() throws IOException {
- DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
- stream.writeByte(MessageType.LOAD_MODULE.getId());
- writeUtf8String(stream, url);
- writeUtf8String(stream, tabKey);
- writeUtf8String(stream, sessionKey);
- writeUtf8String(stream, moduleName);
- writeUtf8String(stream, userAgent);
- stream.flush();
- }
- }
-
- /**
- * Abstract base class of OOPHM messages.
- */
- protected abstract static class Message {
- public static MessageType readMessageType(DataInputStream stream)
- throws IOException, BrowserChannelException {
- stream.mark(1);
- int type = stream.readByte();
- MessageType[] types = MessageType.values();
- if (type < 0 || type >= types.length) {
- stream.reset();
- throw new BrowserChannelException("Invalid message type " + type);
- }
- return types[type];
- }
-
- private final BrowserChannelPatched channel;
-
- public Message(BrowserChannelPatched channel) {
- this.channel = channel;
- }
-
- public final BrowserChannelPatched getBrowserChannel() {
- return channel;
- }
-
- /**
- * @return true if this message type is asynchronous and does not expect a
- * return message.
- */
- public boolean isAsynchronous() {
- return false;
- }
-
- /**
- * @throws IOException if a subclass encounters an I/O error
- */
- public void send() throws IOException {
- throw new UnsupportedOperationException(getClass().getName()
- + " is a message format that can only be received.");
- }
- }
-
- /**
- * Provides a way of allocating JS and Java object ids without knowing
- * which one is the remote type, so code can be shared between client and
- * server.
- */
- protected interface ObjectRefFactory {
-
- JavaObjectRef getJavaObjectRef(int refId);
-
- JsObjectRef getJsObjectRef(int refId);
-
- Set<Integer> getRefIdsForCleanup();
- }
-
- /**
- * A request from the client that the server load and initialize a given
- * module (original v1 version).
- */
- protected static class OldLoadModuleMessage extends Message {
- public static OldLoadModuleMessage receive(BrowserChannelPatched channel)
- throws IOException {
- DataInputStream stream = channel.getStreamFromOtherSide();
- int protoVersion = stream.readInt();
- String moduleName = readUtf8String(stream);
- String userAgent = readUtf8String(stream);
- return new OldLoadModuleMessage(channel, protoVersion, moduleName,
- userAgent);
- }
-
- private final String moduleName;
-
- private final int protoVersion;
-
- private final String userAgent;
-
- public OldLoadModuleMessage(BrowserChannelPatched channel, int protoVersion,
- String moduleName, String userAgent) {
- super(channel);
- this.protoVersion = protoVersion;
- this.moduleName = moduleName;
- this.userAgent = userAgent;
- }
-
- public String getModuleName() {
- return moduleName;
- }
-
- public int getProtoVersion() {
- return protoVersion;
- }
-
- public String getUserAgent() {
- return userAgent;
- }
-
- @Override
- public void send() throws IOException {
- DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
- stream.writeByte(MessageType.OLD_LOAD_MODULE.getId());
- stream.writeInt(protoVersion);
- writeUtf8String(stream, moduleName);
- writeUtf8String(stream, userAgent);
- stream.flush();
- }
- }
-
- /**
- * Reports the selected protocol version.
- */
- protected static class ProtocolVersionMessage extends Message {
-
- public static ProtocolVersionMessage receive(BrowserChannelPatched channel)
- throws IOException {
- DataInputStream stream = channel.getStreamFromOtherSide();
- int protocolVersion = stream.readInt();
- return new ProtocolVersionMessage(channel, protocolVersion);
- }
-
- private final int protocolVersion;
-
- public ProtocolVersionMessage(BrowserChannelPatched channel, int protocolVersion) {
- super(channel);
- this.protocolVersion = protocolVersion;
- }
-
- public int getProtocolVersion() {
- return protocolVersion;
- }
-
- @Override
- public void send() throws IOException {
- DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
- stream.writeByte(MessageType.PROTOCOL_VERSION.getId());
- stream.writeInt(protocolVersion);
- stream.flush();
- }
- }
-
- /**
- * A message signifying a soft close of the communications channel.
- */
- protected static class QuitMessage extends Message {
- public static QuitMessage receive(BrowserChannelPatched channel) {
- return new QuitMessage(channel);
- }
-
- public static void send(BrowserChannelPatched channel) throws IOException {
- final DataOutputStream stream = channel.getStreamToOtherSide();
- stream.writeByte(MessageType.QUIT.getId());
- stream.flush();
- }
-
- public QuitMessage(BrowserChannelPatched channel) {
- super(channel);
- }
-
- @Override
- public void send() throws IOException {
- send(getBrowserChannel());
- }
- }
-
- /**
- * A message asking the client to send an icon suitable for use in the UI.
- * <p>See {@link UserAgentIconMessage}.
- */
- protected static class RequestIconMessage extends Message {
-
- /**
- * Receive a RequestIconMessage, assuming the message tag has already been
- * read.
- *
- * @throws IOException
- */
- public static RequestIconMessage receive(BrowserChannelPatched channel)
- throws IOException {
- return new RequestIconMessage(channel);
- }
-
- public static void send(BrowserChannelPatched channel)
- throws IOException {
- DataOutputStream stream = channel.getStreamToOtherSide();
- stream.writeByte(MessageType.REQUEST_ICON.getId());
- stream.flush();
- }
-
- public RequestIconMessage(BrowserChannelPatched channel) {
- super(channel);
- }
-
- @Override
- public void send() throws IOException {
- send(getBrowserChannel());
- }
- }
-
- /**
- * Signifies a return from a previous invoke.
- */
- protected static class ReturnMessage extends Message {
- public static ReturnMessage receive(BrowserChannelPatched channel)
- throws IOException {
- final DataInputStream stream = channel.getStreamFromOtherSide();
- final boolean isException = stream.readBoolean();
- final Value returnValue = channel.readValue(stream);
- return new ReturnMessage(channel, isException, returnValue);
- }
-
- public static void send(BrowserChannelPatched channel, boolean isException,
- Value returnValue) throws IOException {
- final DataOutputStream stream = channel.getStreamToOtherSide();
- stream.writeByte(MessageType.RETURN.getId());
- stream.writeBoolean(isException);
- channel.writeValue(stream, returnValue);
- stream.flush();
- }
-
- public static void send(BrowserChannelPatched channel,
- ExceptionOrReturnValue returnOrException) throws IOException {
- send(channel, returnOrException.isException(),
- returnOrException.getReturnValue());
- }
-
- private final boolean isException;
- private final Value returnValue;
-
- public ReturnMessage(BrowserChannelPatched channel, boolean isException,
- Value returnValue) {
- super(channel);
- this.returnValue = returnValue;
- this.isException = isException;
- }
-
- public Value getReturnValue() {
- return returnValue;
- }
-
- public boolean isException() {
- return isException;
- }
-
- @Override
- public void send() throws IOException {
- send(getBrowserChannel(), isException, returnValue);
- }
- }
-
- /**
- * A response to ChooseTransport telling the client which transport should
- * be used for the remainder of the protocol.
- */
- protected static class SwitchTransportMessage extends Message {
-
- public static SwitchTransportMessage receive(BrowserChannelPatched channel)
- throws IOException {
- DataInputStream stream = channel.getStreamFromOtherSide();
- String transport = readUtf8String(stream);
- String transportArgs = readUtf8String(stream);
- return new SwitchTransportMessage(channel, transport, transportArgs);
- }
-
- private final String transport;
-
- private final String transportArgs;
-
- public SwitchTransportMessage(BrowserChannelPatched channel,
- String transport, String transportArgs) {
- super(channel);
- // Change nulls to empty strings
- if (transport == null) {
- transport = "";
- }
- if (transportArgs == null) {
- transportArgs = "";
- }
- this.transport = transport;
- this.transportArgs = transportArgs;
- }
-
- public String getTransport() {
- return transport;
- }
-
- public String getTransportArgs() {
- return transportArgs;
- }
-
- @Override
- public void send() throws IOException {
- DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
- stream.writeByte(MessageType.SWITCH_TRANSPORT.getId());
- writeUtf8String(stream, transport);
- writeUtf8String(stream, transportArgs);
- stream.flush();
- }
- }
-
- /**
- * A message supplying an icon, which fits in 24x24 and in a standard image
- * format such as PNG or GIF, suitable for use in the UI.
- * <p>See {@link RequestIconMessage}.
- */
- protected static class UserAgentIconMessage extends Message {
- public static UserAgentIconMessage receive(BrowserChannelPatched channel)
- throws IOException {
- byte[] iconBytes = null;
- DataInputStream stream = channel.getStreamFromOtherSide();
- int len = stream.readInt();
- if (len > 0) {
- iconBytes = new byte[len];
- for (int i = 0; i < len; ++i) {
- iconBytes[i] = stream.readByte();
- }
- }
- return new UserAgentIconMessage(channel, iconBytes);
- }
-
- public static void send(BrowserChannelPatched channel, byte[] iconBytes)
- throws IOException {
- DataOutputStream stream = channel.getStreamToOtherSide();
- stream.writeByte(MessageType.USER_AGENT_ICON.getId());
- if (iconBytes == null) {
- stream.writeInt(0);
- } else {
- stream.writeInt(iconBytes.length);
- for (byte b : iconBytes) {
- stream.writeByte(b);
- }
- }
- stream.flush();
- }
-
- private byte[] iconBytes;
-
- public UserAgentIconMessage(BrowserChannelPatched channel, byte[] iconBytes) {
- super(channel);
- this.iconBytes = iconBytes;
- }
-
- public byte[] getIconBytes() {
- return iconBytes;
- }
-
- @Override
- public void send() throws IOException {
- send(getBrowserChannel(), iconBytes);
- }
- }
-
- /**
- * The current version of the protocol.
- */
- public static final int PROTOCOL_VERSION_CURRENT = 3;
-
- /**
- * The oldest protocol version supported by this code.
- */
- public static final int PROTOCOL_VERSION_OLDEST = 2;
-
- /**
- * The protocol version that added the GetIcon message.
- */
- public static final int PROTOCOL_VERSION_GET_ICON = 3;
-
- public static final int SPECIAL_CLIENTMETHODS_OBJECT = 0;
-
- public static final int SPECIAL_SERVERMETHODS_OBJECT = 0;
-
- protected static JavaObjectRef getJavaObjectRef(int refId) {
- return new JavaObjectRef(refId);
- }
-
- protected static String readUtf8String(DataInputStream stream)
- throws IOException {
- final int len = stream.readInt();
- final byte[] data = new byte[len];
- stream.readFully(data);
- return new String(data, "UTF8");
- }
-
- protected static ValueType readValueType(DataInputStream stream)
- throws IOException, BrowserChannelException {
- int type = stream.readByte();
- ValueType[] types = ValueType.values();
- if (type < 0 || type >= types.length) {
- throw new BrowserChannelException("Invalid value type " + type);
- }
- return types[type];
- }
-
- 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 {
- stream.writeByte(ValueType.JS_OBJECT.getTag());
- stream.writeInt(value.getRefid());
- }
-
- protected static void writeNull(DataOutputStream stream) throws IOException {
- stream.writeByte(ValueType.NULL.getTag());
- }
-
- 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 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");
- stream.writeInt(bytes.length);
- stream.write(bytes);
- } catch (UnsupportedEncodingException e) {
- // TODO: Add description.
- throw new RuntimeException();
- }
- }
-
- private static void writeUndefined(DataOutputStream stream)
- throws IOException {
- stream.writeByte(ValueType.UNDEFINED.getTag());
- }
-
- private final ObjectRefFactory objectRefFactory;
-
- private Socket socket;
-
- private final DataInputStream streamFromOtherSide;
-
- private final DataOutputStream streamToOtherSide;
-
- public BrowserChannelPatched(Socket socket, ObjectRefFactory objectRefFactory)
- throws IOException {
- this(new BufferedInputStream(socket.getInputStream()),
- new BufferedOutputStream(socket.getOutputStream()),
- objectRefFactory);
- this.socket = socket;
- }
-
- protected BrowserChannelPatched(InputStream inputStream, OutputStream outputStream,
- ObjectRefFactory objectRefFactory) {
- streamFromOtherSide = new DataInputStream(inputStream);
- streamToOtherSide = new DataOutputStream(outputStream);
- socket = null;
- this.objectRefFactory = objectRefFactory;
- }
-
- public void endSession() {
- Utility.close(streamFromOtherSide);
- Utility.close(streamToOtherSide);
- Utility.close(socket);
- }
-
- /**
- * @return a set of remote object reference IDs to be freed.
- */
- public Set<Integer> getRefIdsForCleanup() {
- return objectRefFactory.getRefIdsForCleanup();
- }
-
- public String getRemoteEndpoint() {
- if (socket == null) {
- return "";
- }
- return socket.getInetAddress().getCanonicalHostName() + ":"
- + socket.getPort();
- }
-
- protected DataInputStream getStreamFromOtherSide() {
- return streamFromOtherSide;
- }
-
- protected DataOutputStream getStreamToOtherSide() {
- return streamToOtherSide;
- }
-
- protected Value readValue(DataInputStream stream) throws IOException {
- ValueType tag;
- try {
- tag = readValueType(stream);
- } catch (BrowserChannelException e) {
- IOException ee = new IOException();
- ee.initCause(e);
- throw ee;
- }
- Value value = new Value();
- switch (tag) {
- case NULL:
- value.setNull();
- break;
- case UNDEFINED:
- value.setUndefined();
- break;
- case BOOLEAN:
- value.setBoolean(stream.readByte() != 0);
- break;
- case BYTE:
- value.setByte(stream.readByte());
- break;
- case CHAR:
- value.setChar(stream.readChar());
- break;
- case FLOAT:
- value.setFloat(stream.readFloat());
- break;
- case INT:
- value.setInt(stream.readInt());
- break;
- case LONG:
- value.setLong(stream.readLong());
- break;
- case DOUBLE:
- value.setDouble(stream.readDouble());
- break;
- case SHORT:
- value.setShort(stream.readShort());
- break;
- case STRING:
- value.setString(readUtf8String(stream));
- break;
- case JS_OBJECT:
- value.setJsObject(objectRefFactory.getJsObjectRef(stream.readInt()));
- break;
- case JAVA_OBJECT:
- value.setJavaObject(objectRefFactory.getJavaObjectRef(
- stream.readInt()));
- break;
- }
- return value;
- }
-
- protected void sendFreedValues() throws IOException {
- Set<Integer> freed = objectRefFactory.getRefIdsForCleanup();
- int n = freed.size();
- if (n > 0) {
- int[] ids = new int[n];
- int i = 0;
- for (Integer id : freed) {
- ids[i++] = id;
- }
- FreeMessage.send(this, ids);
- }
- }
-
- protected void writeValue(DataOutputStream stream, Value value)
- throws IOException {
- if (value.isNull()) {
- writeNull(stream);
- } else if (value.isUndefined()) {
- writeUndefined(stream);
- } else if (value.isJsObject()) {
- writeJsObject(stream, value.getJsObject());
- } else if (value.isJavaObject()) {
- writeJavaObject(stream, value.getJavaObject());
- } else if (value.isBoolean()) {
- writeTaggedBoolean(stream, value.getBoolean());
- } else if (value.isByte()) {
- writeTaggedByte(stream, value.getByte());
- } else if (value.isChar()) {
- writeTaggedChar(stream, value.getChar());
- } else if (value.isShort()) {
- writeTaggedShort(stream, value.getShort());
- } else if (value.isDouble()) {
- writeTaggedDouble(stream, value.getDouble());
- } else if (value.isFloat()) {
- writeTaggedFloat(stream, value.getFloat());
- } else if (value.isInt()) {
- writeTaggedInt(stream, value.getInt());
- } else if (value.isString()) {
- writeTaggedString(stream, value.getString());
- } else {
- assert false;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.junit;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.dev.shell.HostedModePluginObject;
-import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet;
-
-import com.gargoylesoftware.htmlunit.AlertHandler;
-import com.gargoylesoftware.htmlunit.BrowserVersion;
-import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
-import com.gargoylesoftware.htmlunit.IncorrectnessListener;
-import com.gargoylesoftware.htmlunit.OnbeforeunloadHandler;
-import com.gargoylesoftware.htmlunit.Page;
-import com.gargoylesoftware.htmlunit.ScriptException;
-import com.gargoylesoftware.htmlunit.WebClient;
-import com.gargoylesoftware.htmlunit.WebWindow;
-import com.gargoylesoftware.htmlunit.html.HtmlPage;
-import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
-import com.gargoylesoftware.htmlunit.javascript.JavaScriptErrorListener;
-import com.gargoylesoftware.htmlunit.javascript.host.Window;
-
-import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
-
-import org.w3c.css.sac.CSSParseException;
-import org.w3c.css.sac.ErrorHandler;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Launches a web-mode test via HTMLUnit.
- */
-public class RunStyleHtmlUnitPatched extends RunStyle {
-
- /**
- * Runs HTMLUnit in a separate thread.
- */
- protected static class HtmlUnitThread extends Thread implements AlertHandler,
- IncorrectnessListener, OnbeforeunloadHandler {
-
- private final BrowserVersion browser;
- private final boolean developmentMode;
- private final TreeLogger treeLogger;
- private final String url;
- private Object waitForUnload = new Object();
-
- public HtmlUnitThread(BrowserVersion browser, String url,
- TreeLogger treeLogger, boolean developmentMode) {
- this.browser = browser;
- this.url = url;
- this.treeLogger = treeLogger;
- this.setName("htmlUnit client thread");
- this.developmentMode = developmentMode;
- }
-
- public void handleAlert(Page page, String message) {
- treeLogger.log(TreeLogger.ERROR, "Alert: " + message);
- }
-
- public boolean handleEvent(Page page, String returnValue) {
- synchronized (waitForUnload) {
- waitForUnload.notifyAll();
- }
- return true;
- }
-
- public void notify(String message, Object origin) {
- if ("Obsolete content type encountered: 'text/javascript'.".equals(message)) {
- // silently eat warning about text/javascript MIME type
- return;
- }
- treeLogger.log(TreeLogger.WARN, message);
- }
-
- @Override
- public void run() {
- WebClient webClient = new WebClient(browser);
- webClient.setAlertHandler(this);
- // Adding a handler that ignores errors to work-around
- // https://sourceforge.net/tracker/?func=detail&aid=3090806&group_id=47038&atid=448266
- webClient.setCssErrorHandler(new ErrorHandler() {
-
- public void error(CSSParseException exception) {
- // ignore
- }
-
- public void fatalError(CSSParseException exception) {
- treeLogger.log(TreeLogger.WARN,
- "CSS fatal error: " + exception.getURI() + " ["
- + exception.getLineNumber() + ":"
- + exception.getColumnNumber() + "] " + exception.getMessage());
- }
-
- public void warning(CSSParseException exception) {
- // ignore
- }
- });
- webClient.setIncorrectnessListener(this);
- webClient.setOnbeforeunloadHandler(this);
- webClient.setJavaScriptErrorListener(new JavaScriptErrorListener() {
-
- @Override
- public void loadScriptError(HtmlPage htmlPage, URL scriptUrl,
- Exception exception) {
- treeLogger.log(TreeLogger.ERROR,
- "Load Script Error: " + exception, exception);
- }
-
- @Override
- public void malformedScriptURL(HtmlPage htmlPage, String url,
- MalformedURLException malformedURLException) {
- treeLogger.log(TreeLogger.ERROR,
- "Malformed Script URL: " + malformedURLException.getLocalizedMessage());
- }
-
- @Override
- public void scriptException(HtmlPage htmlPage,
- ScriptException scriptException) {
- treeLogger.log(TreeLogger.DEBUG,
- "Script Exception: " + scriptException.getLocalizedMessage() +
- ", line " + scriptException.getFailingLine());
- }
-
- @Override
- public void timeoutError(HtmlPage htmlPage, long allowedTime,
- long executionTime) {
- treeLogger.log(TreeLogger.ERROR,
- "Script Timeout Error " + executionTime + " > " + allowedTime);
- }
- });
- setupWebClient(webClient);
- try {
- Page page = webClient.getPage(url);
- webClient.waitForBackgroundJavaScriptStartingBefore(2000);
- if (treeLogger.isLoggable(TreeLogger.SPAM)) {
- treeLogger.log(TreeLogger.SPAM, "getPage returned "
- + ((HtmlPage) page).asXml());
- }
- // TODO(amitmanjhi): call webClient.closeAllWindows()
- } catch (FailingHttpStatusCodeException e) {
- treeLogger.log(TreeLogger.ERROR, "HTTP request failed", e);
- return;
- } catch (MalformedURLException e) {
- treeLogger.log(TreeLogger.ERROR, "Bad URL", e);
- return;
- } catch (IOException e) {
- treeLogger.log(TreeLogger.ERROR, "I/O error on HTTP request", e);
- return;
- }
- }
-
- protected void setupWebClient(WebClient webClient) {
- if (developmentMode) {
- JavaScriptEngine hostedEngine = new HostedJavaScriptEngine(webClient,
- treeLogger);
- webClient.setJavaScriptEngine(hostedEngine);
- }
- }
- }
-
- /**
- * JavaScriptEngine subclass that provides a hook of initializing the
- * __gwt_HostedModePlugin property on any new window, so it acts just like
- * Firefox with the XPCOM plugin installed.
- */
- private static class HostedJavaScriptEngine extends JavaScriptEngine {
-
- private static final long serialVersionUID = 3594816610842448691L;
- private final TreeLogger logger;
-
- public HostedJavaScriptEngine(WebClient webClient, TreeLogger logger) {
- super(webClient);
- this.logger = logger;
- }
-
- @Override
- public void initialize(WebWindow webWindow) {
- // Hook in the hosted-mode plugin after initializing the JS engine.
- super.initialize(webWindow);
- Window window = (Window) webWindow.getScriptObject();
- window.defineProperty("__gwt_HostedModePlugin",
- new HostedModePluginObject(this, logger), ScriptableObject.READONLY);
- }
- }
-
- private static final Map<String, BrowserVersion> BROWSER_MAP = createBrowserMap();
-
- /*
- * as long as this number is greater than 1, GWTTestCaseTest::testRetry will
- * pass
- */
- private static final int DEFAULT_TRIES = 1;
-
- private static final Set<Platform> PLATFORMS = ImmutableSet.of(Platform.HtmlUnitBug,
- Platform.HtmlUnitLayout, Platform.HtmlUnitUnknown);
-
- /**
- * Returns the list of browsers Htmlunit emulates as a comma separated string.
- */
- static String getBrowserList() {
- StringBuffer sb = new StringBuffer();
- for (String str : BROWSER_MAP.keySet()) {
- sb.append(str);
- sb.append(",");
- }
- if (sb.length() > 1) {
- return sb.substring(0, sb.length() - 1);
- }
- return sb.toString();
- }
-
- private static Map<String, BrowserVersion> createBrowserMap() {
- Map<String, BrowserVersion> browserMap = new HashMap<String, BrowserVersion>();
- for (BrowserVersion browser : new BrowserVersion[] {
- BrowserVersion.FIREFOX_3_6, BrowserVersion.INTERNET_EXPLORER_6,
- BrowserVersion.INTERNET_EXPLORER_7}) {
- browserMap.put(browser.getNickname(), browser);
- }
- return Collections.unmodifiableMap(browserMap);
- }
-
- private Set<BrowserVersion> browsers = new HashSet<BrowserVersion>();
- private boolean developmentMode;
- private final List<Thread> threads = new ArrayList<Thread>();
-
- /**
- * Create a RunStyle instance with the passed-in browser targets.
- */
- public RunStyleHtmlUnitPatched(JUnitShell shell) {
- super(shell);
- }
-
- @Override
- public Set<Platform> getPlatforms() {
- return PLATFORMS;
- }
-
- @Override
- public int initialize(String args) {
- if (args == null || args.length() == 0) {
- // If no browsers specified, default to Firefox 3.
- args = "FF3.6";
- }
- Set<BrowserVersion> browserSet = new HashSet<BrowserVersion>();
- for (String browserName : args.split(",")) {
- BrowserVersion browser = BROWSER_MAP.get(browserName);
- if (browser == null) {
- getLogger().log(
- TreeLogger.ERROR,
- "RunStyleHtmlUnit: Unknown browser " + "name " + browserName
- + ", expected browser name: one of " + BROWSER_MAP.keySet());
- return -1;
- }
- browserSet.add(browser);
- }
- browsers = Collections.unmodifiableSet(browserSet);
-
- setTries(DEFAULT_TRIES); // set to the default value for this RunStyle
- return browsers.size();
- }
-
- @Override
- public void launchModule(String moduleName) {
- for (BrowserVersion browser : browsers) {
- String url = shell.getModuleUrl(moduleName);
- HtmlUnitThread hut = createHtmlUnitThread(browser, url);
- TreeLogger logger = shell.getTopLogger();
- if (logger.isLoggable(TreeLogger.INFO)) {
- logger.log(TreeLogger.INFO,
- "Starting " + url + " on browser " + browser.getNickname());
- }
- /*
- * TODO (amitmanjhi): Is it worth pausing here and waiting for the main
- * test thread to get to an "okay" state.
- */
- hut.start();
- threads.add(hut);
- }
- }
-
- public int numBrowsers() {
- return browsers.size();
- }
-
- @Override
- public boolean setupMode(TreeLogger logger, boolean developmentMode) {
- this.developmentMode = developmentMode;
- return true;
- }
-
- protected HtmlUnitThread createHtmlUnitThread(BrowserVersion browser,
- String url) {
- return new HtmlUnitThread(browser, url, shell.getTopLogger().branch(
- TreeLogger.SPAM, "logging for HtmlUnit thread"), developmentMode);
- }
-}