From 99da8fc97f5de84a2602d7d261b6deb627cf8bd6 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Mon, 23 Dec 2013 19:06:45 +0100 Subject: FallBack to dummy implementation in IE8 IE9 --- .../gwt/query/client/impl/ConsoleBrowser.java | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/ConsoleBrowser.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/ConsoleBrowser.java index ec63c852..1ccc04d6 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/ConsoleBrowser.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/ConsoleBrowser.java @@ -31,7 +31,11 @@ public class ConsoleBrowser implements Console { private static class ConsoleIe8 extends ConsoleIe9 { @Override protected native void init()/*-{ - Function.prototype.call.call($wnd.console.log, $wnd.console, Array.prototype.slice.call(arguments)); + try { + Function.prototype.call.call($wnd.console.log, $wnd.console, Array.prototype.slice.call(arguments)); + } catch(e) { + this.@com.google.gwt.query.client.impl.ConsoleBrowser.ConsoleIe9::initFallBack()(); + } }-*/; } @@ -39,15 +43,33 @@ public class ConsoleBrowser implements Console { * See: http://whattheheadsaid.com/2011/04/internet-explorer-9s-problematic-console-object */ private static class ConsoleIe9 extends ConsoleImpl { + public ConsoleIe9(){ init(); } protected native void init()/*-{ + try { [ "log", "info", "warn", "error", "dir", "clear", "profile", "profileEnd" ] .forEach(function(method) { $wnd.console[method] = this.call($wnd.console[method], $wnd.console); }, Function.prototype.bind); + } catch(e) { + this.@com.google.gwt.query.client.impl.ConsoleBrowser.ConsoleIe9::initFallBack()(); + } + }-*/; + + /** + * Dummy implementation of console if IE8 or IE9 fail using dev tools. + */ + private native void initFallBack() /*-{ + if (!$wnd.console || !$wnd.console.log) { + $wnd.console = {}; + [ "log", "info", "warn", "error", "dir", "clear", "profile", "profileEnd" ] + .forEach(function(method) { + $wnd.console[method] = function(){}; + }); + } }-*/; @Override -- cgit v1.2.3 From 0a9322ccb029bf6edc1f0bf01a29303fd8600614 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Mon, 23 Dec 2013 19:27:44 +0100 Subject: Set credentials with gQuery utilities to avoid breaking apps before 2.5.1 --- .../google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java index c19cf704..dea15355 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java @@ -124,7 +124,9 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal xmlHttpRequest.setRequestHeader("Content-Type", ctype); } - xmlHttpRequest.setWithCredentials(true); + // Using gQuery to set credentials since this method was added in 2.5.1 + // xmlHttpRequest.setWithCredentials(true); + JsUtils.prop(xmlHttpRequest, "withCredentials", true); final Request request = createRequestVltr(xmlHttpRequest, settings.getTimeout(), this); -- cgit v1.2.3 From 7955d166c4f92187e6541fd6046650ccdcbf71a8 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Mon, 23 Dec 2013 19:44:30 +0100 Subject: Fix merge issue --- .../com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java index dea15355..8ec7cc7a 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java @@ -171,6 +171,6 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal * Using violator pattern to use protected constructor */ private native Request createRequestVltr(XMLHttpRequest rq, int ms, RequestCallback cb) /*-{ - return @com.google.gwt.http.client.Request::new(Lcom/google/gwt/xhr/client/XMLHttpRequest;ILcom/google/gwt/http/client/RequestCallback;)(rq, + return @com.google.gwt.http.client.Request::new(Lcom/google/gwt/xhr/client/XMLHttpRequest;ILcom/google/gwt/http/client/RequestCallback;)(rq,cb); }-*/; } -- cgit v1.2.3 From ad30b3e7f61bcf25cce84d46f9527f6e075c8b1e Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Fri, 27 Dec 2013 21:44:49 +0100 Subject: Implementation of JsonBuilders for the JVM. Moved tests to class which can be run either in JVM and in client side. Added an utility class to create Json objects so as we can use it in server and client, we dont depend on ClientFactories nor Injectors like autoBeans and other implementations do --- gwtquery-core/pom.xml | 2 +- .../main/java/com/google/gwt/query/Query.gwt.xml | 6 + .../java/com/google/gwt/query/QueryMin.gwt.xml | 20 +- .../main/java/com/google/gwt/query/client/GQ.java | 41 +++++ .../gwt/query/client/builders/JsonBuilder.java | 6 +- .../gwt/query/client/builders/JsonBuilderBase.java | 3 +- .../gwt/query/client/builders/JsonFactory.java | 5 + .../gwt/query/rebind/JsonBuilderGenerator.java | 94 +++++++--- .../com/google/gwt/query/vm/JsonFactoryJre.java | 203 +++++++++++++++++++++ .../super/com/google/gwt/query/client/GQ.java | 39 ++++ .../google/gwt/query/client/GQueryAjaxTestGwt.java | 82 +-------- .../gwt/query/client/dbinding/DataBindingTest.java | 113 ++++++++++++ .../query/client/dbinding/DataBindingTestGwt.java | 29 +++ 13 files changed, 514 insertions(+), 129 deletions(-) create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java create mode 100644 gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/pom.xml b/gwtquery-core/pom.xml index a90c6a82..c44b7f9b 100644 --- a/gwtquery-core/pom.xml +++ b/gwtquery-core/pom.xml @@ -51,7 +51,7 @@ ${basedir}/src/main/java - ${basedir}/src/main/resources + ${basedir}/src/main/super diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml index 520ceaa0..5398aa58 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml +++ b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml @@ -17,6 +17,9 @@ + + + @@ -36,6 +39,9 @@ + + + diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/QueryMin.gwt.xml b/gwtquery-core/src/main/java/com/google/gwt/query/QueryMin.gwt.xml index 6453aba3..f3e2e72a 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/QueryMin.gwt.xml +++ b/gwtquery-core/src/main/java/com/google/gwt/query/QueryMin.gwt.xml @@ -22,7 +22,10 @@ - + + + + @@ -42,21 +45,6 @@ - - - - - - - - - - - - - - - diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java new file mode 100644 index 00000000..0791feaf --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java @@ -0,0 +1,41 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client; + +import com.google.gwt.core.shared.GWT; +import com.google.gwt.query.client.builders.JsonBuilder; +import com.google.gwt.query.client.builders.JsonFactory; +import com.google.gwt.query.vm.JsonFactoryJre; + +public class GQ { + + private static JsonFactory jsonFactory; + + public static T create(Class clz) { + if (jsonFactory == null) { + jsonFactory = GWT.isClient() ? + GWT.create(JsonFactory.class) : + new JsonFactoryJre(); + } + return jsonFactory.create(clz); + } + + public static T create(Class clz, String payload) { + T ret = create(clz); + ret.load(payload); + return ret; + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java index 41a7171c..596d5473 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java @@ -15,7 +15,6 @@ */ package com.google.gwt.query.client.builders; -import com.google.gwt.query.client.Properties; /** * Tagging interface used to generate JsonBuilder classes. @@ -40,9 +39,10 @@ public interface JsonBuilder { J parse(String json, boolean fix); /** - * Returns the javascript properties object. + * Returns the wrapped object, normally a Properties jso in client + * but can be used to return the underlying Json implementation in JVM */ - Properties getProperties(); + J getProperties(); /** * return a list of field names. diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index e0d48c26..66de0898 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java @@ -51,7 +51,7 @@ public abstract class JsonBuilderBase> implements J if (r.length > 0 && r[0] instanceof JsonBuilder) { JsArray a = JavaScriptObject.createArray().cast(); for (T o : r) { - a.push(((JsonBuilder)o).getProperties()); + a.push(((JsonBuilder)o).getProperties()); } p.set(n, a); } else { @@ -88,6 +88,7 @@ public abstract class JsonBuilderBase> implements J return p.tostring(); } + @SuppressWarnings("unchecked") public Properties getProperties() { return p; } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java new file mode 100644 index 00000000..30f08bb9 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java @@ -0,0 +1,5 @@ +package com.google.gwt.query.client.builders; + +public interface JsonFactory { + T create(Class clz); +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index 51543454..ead7ecd0 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -15,10 +15,19 @@ */ package com.google.gwt.query.rebind; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.ext.Generator; import com.google.gwt.core.ext.GeneratorContext; import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.TreeLogger.Type; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JArrayType; import com.google.gwt.core.ext.typeinfo.JClassType; @@ -30,17 +39,12 @@ import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.builders.JsonBuilder; +import com.google.gwt.query.client.builders.JsonBuilderBase; +import com.google.gwt.query.client.builders.JsonFactory; import com.google.gwt.query.client.builders.Name; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; -import java.io.PrintWriter; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - /** */ public class JsonBuilderGenerator extends Generator { @@ -50,6 +54,9 @@ public class JsonBuilderGenerator extends Generator { static JClassType jsType; static JClassType listType; static JClassType stringType; + static JClassType jsonCreatorType; + + public static String capitalize(String s) { if (s.length() == 0) return s; @@ -70,39 +77,47 @@ public class JsonBuilderGenerator extends Generator { public String generate(TreeLogger treeLogger, GeneratorContext generatorContext, String requestedClass) throws UnableToCompleteException { + oracle = generatorContext.getTypeOracle(); JClassType clazz = oracle.findType(requestedClass); + jsonBuilderType = oracle.findType(JsonBuilder.class.getName()); stringType = oracle.findType(String.class.getName()); jsType = oracle.findType(JavaScriptObject.class.getName()); listType = oracle.findType(List.class.getName()); functionType = oracle.findType(Function.class.getName()); + jsonCreatorType = oracle.findType(JsonFactory.class.getName()); String t[] = generateClassName(clazz); - SourceWriter sw = getSourceWriter(treeLogger, generatorContext, t[0], t[1], - requestedClass); + boolean isFactory = clazz.isAssignableTo(jsonCreatorType); + + SourceWriter sw = getSourceWriter(treeLogger, generatorContext, t[0], t[1], isFactory, requestedClass); if (sw != null) { - Set attrs = new HashSet(); - for (JMethod method : clazz.getInheritableMethods()) { - String methName = method.getName(); - //skip method from JsonBuilder - if(jsonBuilderType.findMethod(method.getName(), method.getParameterTypes()) != null){ - continue; - } + if (isFactory) { + generateCreateMethod(sw, treeLogger); + } else { + Set attrs = new HashSet(); + for (JMethod method : clazz.getInheritableMethods()) { + String methName = method.getName(); + //skip method from JsonBuilder + if(jsonBuilderType.findMethod(method.getName(), method.getParameterTypes()) != null) { + continue; + } - Name nameAnnotation = method.getAnnotation(Name.class); - String name = nameAnnotation != null - ? nameAnnotation.value() - : methName.replaceFirst("^(get|set)", ""); - if (nameAnnotation == null) { - name = name.substring(0, 1).toLowerCase() + name.substring(1); + Name nameAnnotation = method.getAnnotation(Name.class); + String name = nameAnnotation != null + ? nameAnnotation.value() + : methName.replaceFirst("^(get|set)", ""); + if (nameAnnotation == null) { + name = name.substring(0, 1).toLowerCase() + name.substring(1); + } + attrs.add(name); + generateMethod(sw, method, name, treeLogger); } - attrs.add(name); - generateMethod(sw, method, name, treeLogger); + generateFieldNamesMethod(sw, attrs, treeLogger); + generateToJsonMethod(sw, t[3], treeLogger); } - generateFieldNamesMethod(sw, attrs, treeLogger); - generateToJsonMethod(sw, t[3], treeLogger); sw.commit(treeLogger); } return t[2]; @@ -255,7 +270,7 @@ public class JsonBuilderGenerator extends Generator { } protected SourceWriter getSourceWriter(TreeLogger logger, - GeneratorContext context, String packageName, String className, + GeneratorContext context, String packageName, String className, boolean isFactory, String... interfaceNames) { PrintWriter printWriter = context.tryCreate(logger, packageName, className); if (printWriter == null) { @@ -263,8 +278,10 @@ public class JsonBuilderGenerator extends Generator { } ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory( packageName, className); - composerFactory.setSuperclass("com.google.gwt.query.client.builders.JsonBuilderBase<" - + packageName + "." + className + ">"); + if (!isFactory) { + composerFactory.setSuperclass(JsonBuilderBase.class.getName() + + "<" + packageName + "." + className + ">"); + } composerFactory.addImport("com.google.gwt.query.client.js.*"); composerFactory.addImport("com.google.gwt.query.client.*"); composerFactory.addImport("com.google.gwt.core.client.*"); @@ -281,4 +298,23 @@ public class JsonBuilderGenerator extends Generator { JClassType c = t.isClassOrInterface(); return (c != null && c.isAssignableTo(o)); } + + private void generateCreateMethod(SourceWriter sw, TreeLogger logger) { + sw.println("public T create(Class clz) {"); + sw.indent(); + ArrayList types = new ArrayList(); + for (JClassType t : oracle.getTypes()) { + if (t.isInterface() != null && t.isAssignableTo(jsonBuilderType) ) { + if (t.isPublic()) { + sw.println("if (clz == " + t.getQualifiedSourceName() + ".class) return GWT.create(" + t.getQualifiedSourceName() + ".class);"); + } else { + logger.log(Type.WARN, t.getQualifiedSourceName() + " is not public"); + } + types.add(t); + } + } + sw.println("return null;"); + sw.outdent(); + sw.println("}"); + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java new file mode 100644 index 00000000..49b5877f --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -0,0 +1,203 @@ +package com.google.gwt.query.vm; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONObject; + +import com.google.gwt.query.client.builders.JsonBuilder; +import com.google.gwt.query.client.builders.JsonFactory; +import com.google.gwt.query.client.builders.Name; +import com.google.gwt.query.rebind.JsonBuilderGenerator; + +public class JsonFactoryJre implements JsonFactory { + + static JsonFactoryJre jsonFactory = new JsonFactoryJre(); + + public static class JsonBuilderHandler implements InvocationHandler { + private JSONObject jsonObject; + + public JsonBuilderHandler() { + jsonObject = new JSONObject(); + } + + public JsonBuilderHandler(JSONObject j) { + jsonObject = j; + } + + public JsonBuilderHandler(String payload) throws Throwable { + jsonObject = new JSONObject(payload); + } + + @SuppressWarnings("unchecked") + private Object jsonArrayToList(JSONArray j, Class ctype, boolean isArray) throws Throwable { + List l = new ArrayList(); + for (int i = 0; j != null && i < j.length() ; i++) { + l.add((T)getValue(j, i, null, null, ctype, null)); + } + return l.isEmpty() ? null : isArray ? l.toArray((T[])Array.newInstance(ctype, l.size())) : l; + } + + private Object getValue(JSONArray arr, int idx, JSONObject obj, String attr, Class clz, Method method) { + Object ret = null; + try { + if (clz.isArray() || clz.equals(List.class)) { + Class ctype = Object.class; + if (clz.isArray()) { + ctype = clz.getComponentType(); + } else { + Type returnType = method.getGenericReturnType(); + if (returnType instanceof ParameterizedType) { + ctype = (Class)((ParameterizedType) returnType).getActualTypeArguments()[0]; + } + } + ret = jsonArrayToList(obj.getJSONArray(attr), ctype, clz.isArray()); + } else if (clz.equals(Date.class)) { + ret = new Date(obj != null ? obj.getLong(attr): arr.getLong(idx)); + } else if (clz.equals(String.class)) { + ret = obj != null ? obj.getString(attr) : arr.getString(idx); + } else if (clz.equals(Boolean.class) || clz.isPrimitive() && clz == Boolean.TYPE) { + try { + ret = obj != null ? obj.getBoolean(attr): arr.getBoolean(idx); + } catch (Exception e) { + return Boolean.FALSE; + } + } else if (clz.equals(Byte.class) || clz.equals(Short.class) || clz.equals(Integer.class) + || clz.isPrimitive() && (clz == Byte.TYPE || clz == Short.TYPE || clz == Integer.TYPE)) { + try { + ret = obj != null ? obj.getInt(attr): arr.getInt(idx); + } catch (Exception e) { + return 0; + } + } else if (clz.equals(Double.class) || clz.equals(Float.class) + || clz.isPrimitive() && (clz == Double.TYPE || clz == Float.TYPE)) { + try { + ret = obj != null ? obj.getDouble(attr): arr.getDouble(idx); + } catch (Exception e) { + return .0; + } + } else if (clz.equals(Long.class) + || clz.isPrimitive() && clz == Long.TYPE) { + try { + ret = obj != null ? obj.getLong(attr): arr.getLong(idx); + } catch (Exception e) { + return 0l; + } + } else { + ret = obj != null ? obj.get(attr): arr.get(idx); + if (ret instanceof JSONObject && JsonBuilder.class.isAssignableFrom(clz) && !clz.isAssignableFrom(ret.getClass())) { + ret = jsonFactory.create(clz, (JSONObject)ret); + } + } + } catch (Throwable e) { + System.out.println(this.getClass().getSimpleName() + " ERROR getting attr=" + attr + " idx=" + idx + " Exception=" + e.getMessage()); + } + return ret; + } + + private JSONArray listToJsonArray(Object...l) throws Throwable { + JSONArray ret = new JSONArray(); + for (Object o: l) { + setValue(ret, null, null, o, null); + } + return ret; + } + + private Object setValue(JSONArray arr, JSONObject obj, String attr, Object o, Method method) { + try { + if (o == null) { + return o; + } + if (o instanceof String) { + return obj != null ? obj.put(attr, o) : arr.put(o); + } else if (o instanceof Boolean) { + return obj != null ? obj.put(attr, o) : arr.put(o); + } else if (o instanceof Number) { + return obj != null ? obj.put(attr, o) : arr.put(o); + } else if (o instanceof Date) { + return obj != null ? obj.put(attr, ((Date) o).getTime()) : arr.put(((Date) o).getTime()); + } else if (o instanceof JsonBuilder) { + return obj != null ? obj.put(attr, ((JsonBuilder) o).getProperties()) : arr.put(((JsonBuilder) o).getProperties()); + } else if (o.getClass().isArray() || o instanceof List) { + Object[] arg; + if (o.getClass().isArray()) { + arg = (Object[])o; + } else { + arg = ((List)o).toArray(); + } + JSONArray a = listToJsonArray(arg); + return obj != null ? obj.put(attr, a) : arr.put(a); + } else { + System.out.println("Unkown setter object " + attr + " " + o.getClass().getName() + " " + o); + return obj != null ? obj.put(attr, o) : arr.put(o); + } + } catch (Throwable e) { + e.printStackTrace(); + } + return null; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String mname = method.getName(); + Class[] classes = method.getParameterTypes(); + int largs = classes.length; + + Name name = method.getAnnotation(Name.class); + String attr = name != null ? name.value() : deCapitalize(mname.replaceFirst("^[gs]et", "")); + + if ("getFieldNames".equals(mname)) { + return JSONObject.getNames(jsonObject); + } else if ("getProperties".equals(mname)) { + return jsonObject; + } else if (largs > 0 && ("parse".equals(mname) || "load".equals(mname))) { + jsonObject = new JSONObject(String.valueOf(args[0])); + } else if ("toString".equals(mname) || "toJson".equals(mname)) { + String jsonName = JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass())); + return "{\"" + jsonName + "\":"+ jsonObject.toString(); + } else if (largs == 0 || mname.startsWith("get")) { + Class ret = method.getReturnType(); + return getValue(null, 0, jsonObject, attr, ret, method); + } else if (largs == 1 || mname.startsWith("set")) { + setValue(null, jsonObject, attr, args[0], method); + return proxy; + } + return null; + } + } + + @SuppressWarnings("unchecked") + public T create(Class clz, JSONObject jso) { + InvocationHandler handler = new JsonBuilderHandler(jso); + return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] {clz}, handler); + } + + @SuppressWarnings("unchecked") + public T create(Class clz) { + InvocationHandler handler = new JsonBuilderHandler(); + return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] {clz}, handler); + } + + private static String deCapitalize(String s) { + return s != null && s.length() > 0 ? s.substring(0, 1).toLowerCase() + s.substring(1) : s; + } + + private static String getDataBindingClassName(Class type) { + for (Class c : type.getInterfaces()) { + if (c.equals(JsonBuilder.class)) { + return type.getName(); + } else { + return getDataBindingClassName(c); + } + } + return null; + } +} diff --git a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java new file mode 100644 index 00000000..edad9154 --- /dev/null +++ b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java @@ -0,0 +1,39 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client; + +import com.google.gwt.core.shared.GWT; +import com.google.gwt.query.client.builders.JsonBuilder; +import com.google.gwt.query.client.builders.JsonFactory; +import com.google.gwt.query.vm.JsonFactoryJre; + +public class GQ { + + private static JsonFactory jsonFactory; + + public static T create(Class clz) { + if (jsonFactory == null) { + jsonFactory = GWT.create(JsonFactory.class); + } + return jsonFactory.create(clz); + } + + public static T create(Class clz, String payload) { + T ret = create(clz); + ret.load(payload); + return ret; + } +} diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java index 695e1d01..945a7fa4 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java @@ -1,5 +1,5 @@ /* - * Copyright 2011, The gwtquery team. + * Copyright 2013, The gwtquery team. * * 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 @@ -18,16 +18,11 @@ package com.google.gwt.query.client; import static com.google.gwt.query.client.GQuery.$; -import java.util.Arrays; -import java.util.Date; -import java.util.List; - import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.junit.DoNotRunWith; import com.google.gwt.junit.Platform; import com.google.gwt.junit.client.GWTTestCase; -import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.Name; import com.google.gwt.query.client.builders.XmlBuilder; import com.google.gwt.query.client.plugins.ajax.Ajax; @@ -64,77 +59,6 @@ public class GQueryAjaxTestGwt extends GWTTestCase { } } - interface Item extends JsonBuilder { - Date getDate(); - void setDate(Date d); - } - - interface JsonExample extends JsonBuilder { - int getA(); - JsonExample getB(); - @Name("M") - int getM(); - @Name("u") - String getUrl(); - long getD(); - Boolean getZ(); - String[] getT(); - JsonExample setT(String[] strings); - JsonExample setZ(Boolean b); - JsonExample setD(long l); - List getItems(); - void setItems(List a); - String y(); - void y(String s); - Function getF(); - void setF(Function f); - } - - boolean functionRun = false; - public void testJsonBuilder() { - String json = "{M:0, a:1, b:{a:2,b:{a:3}},u:url, d:'2','t':['hola','adios'], 'z': true}"; - JsonExample c = GWT.create(JsonExample.class); - assertEquals(0, c.getA()); - c.parse(json, true); - assertEquals(0, c.getM()); - assertEquals(1, c.getA()); - assertNotNull(c.getB()); - assertEquals(2, c.getB().getA()); - assertEquals(3, c.getB().getB().getA()); - assertTrue(c.getZ()); - assertEquals("hola", c.getT()[0]); - assertEquals("adios", c.getT()[1]); - assertEquals("url", c.getUrl()); - c.setT(new String[]{"foo", "bar"}) - .setZ(false).setD(1234); - assertFalse(c.getZ()); - assertEquals("foo", c.getT()[0]); - assertEquals("bar", c.getT()[1]); - assertEquals(1234l, c.getD()); - c.y("y"); - assertEquals("y", c.y()); - - c.setF(new Function() { - public void f() { - functionRun = true; - } - }); - assertFalse(functionRun); - c.getF().f(); - assertTrue(functionRun); - - Item i1 = GWT.create(Item.class); - Item i2 = GWT.create(Item.class); - i1.setDate(new Date(2000)); - i2.setDate(new Date(3000)); - Item[] items = new Item[]{i1, i2}; - c.setItems(Arrays.asList(items)); - assertEquals(2000l, c.getItems().get(0).getDate().getTime()); - assertEquals(3000l, c.getItems().get(1).getDate().getTime()); - String s = "{'M':0,'a':1,'b':{'a':2,'b':{'a':3}},'u':'url','d':1234,'t':['foo','bar'],'z':false,'y':'y','items':[{'date':2000},{'date':3000}]"; - assertEquals(s, c.toString().replaceAll("\"", "'")); - } - interface XmlExample extends XmlBuilder { interface T extends XmlBuilder { } @@ -292,11 +216,11 @@ public class GQueryAjaxTestGwt extends GWTTestCase { Ajax.ajax(s); } - + public void testAjaxError() { delayTestFinish(5000); String url = "http://127.0.0.1/nopage"; - + Ajax.ajax(Ajax.createSettings().setTimeout(1000).setUrl(url)) .done(new Function(){ public void f() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java new file mode 100644 index 00000000..05054b75 --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java @@ -0,0 +1,113 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client.dbinding; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import com.google.gwt.junit.client.GWTTestCase; +import com.google.gwt.query.client.Function; +import com.google.gwt.query.client.GQ; +import com.google.gwt.query.client.builders.JsonBuilder; +import com.google.gwt.query.client.builders.Name; + +/** + * Tests for Deferred which can run either in JVM and GWT + */ +public class DataBindingTest extends GWTTestCase { + + public String getModuleName() { + return null; + } + + public interface Item extends JsonBuilder { + Date getDate(); + void setDate(Date d); + } + + public interface JsonExample extends JsonBuilder { + int getA(); + JsonExample getB(); + @Name("M") + int getM(); + @Name("u") + String getUrl(); + long getD(); + Boolean getZ(); + String[] getT(); + JsonExample setT(String[] strings); + JsonExample setZ(Boolean b); + JsonExample setD(long l); + List getItems(); + void setItems(List a); + String y(); + void y(String s); + Function getF(); + void setF(Function f); + } + + boolean functionRun = false; + public void testJsonBuilder() { + String json = "{M:0, a:1, b:{a:2,b:{a:3}},u:url, d:'2','t':['hola','adios'], 'z': true, 'items':[{'date':100}]}"; + + JsonExample c = GQ.create(JsonExample.class); + assertEquals(0, c.getA()); + c.parse(json, true); + + assertEquals(0, c.getM()); + assertEquals(1, c.getA()); + assertNotNull(c.getB()); + assertEquals(2, c.getB().getA()); + assertEquals(3, c.getB().getB().getA()); + assertTrue(c.getZ()); + assertEquals("hola", c.getT()[0]); + assertEquals("adios", c.getT()[1]); + assertEquals("url", c.getUrl()); + c.setT(new String[]{"foo", "bar"}) + .setZ(false).setD(1234); + assertFalse(c.getZ()); + assertEquals("foo", c.getT()[0]); + assertEquals("bar", c.getT()[1]); + assertEquals(1234l, c.getD()); + c.y("y"); + assertEquals("y", c.y()); + assertEquals(1, c.getItems().size()); + + c.setF(new Function() { + public void f() { + functionRun = true; + } + }); + assertFalse(functionRun); + c.getF().f(); + assertTrue(functionRun); + + Item i1 = GQ.create(Item.class); + Item i2 = GQ.create(Item.class); + i1.setDate(new Date(2000)); + i2.setDate(new Date(3000)); + Item[] items = new Item[]{i1, i2}; + c.setItems(Arrays.asList(items)); + System.out.println(c.toJson()); + System.out.println(c.getItems().get(0).getDate()); + assertEquals(2000l, c.getItems().get(0).getDate().getTime()); + assertEquals(3000l, c.getItems().get(1).getDate().getTime()); + + assertTrue(c.toJson().startsWith("{\"jsonExample\":{")); + assertTrue(c.toJson().contains("\"items\":[{\"date\":")); + } +} \ No newline at end of file diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java new file mode 100644 index 00000000..c01e6c5c --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java @@ -0,0 +1,29 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client.dbinding; + + +/** + * Test for data binding shared code run in gwt + */ +public class DataBindingTestGwt extends DataBindingTest { + + @Override + public String getModuleName() { + return "com.google.gwt.query.Query"; + } + +} -- cgit v1.2.3 From d929f42f8953b311a24fd4ef562cd08763dbe34e Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Fri, 27 Dec 2013 22:58:04 +0100 Subject: add new test to suite --- .../src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java index eeecd7a1..60b62360 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java @@ -3,6 +3,7 @@ package com.google.gwt.query.client; import junit.framework.Test; import com.google.gwt.junit.tools.GWTTestSuite; +import com.google.gwt.query.client.dbinding.DataBindingTestGwt; import com.google.gwt.query.client.deferred.DeferredTestGwt; import com.google.gwt.query.client.impl.SelectorEnginesTestGwt; @@ -15,6 +16,7 @@ public class GQueryGwtSuiteTest extends GWTTestSuite public static Test suite() { GWTTestSuite suite = new GWTTestSuite( "GQuery Suite" ); + suite.addTestSuite(DataBindingTestGwt.class); suite.addTestSuite(GQueryAjaxTestGwt.class); suite.addTestSuite(GQueryDeferredTestGwt.class); suite.addTestSuite(DeferredTestGwt.class); -- cgit v1.2.3 From 2a32e4e8618c97b5130f9c4c2769fbb84cbb93fe Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sat, 28 Dec 2013 11:17:31 +0100 Subject: remove println --- .../test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java | 2 -- 1 file changed, 2 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java index 05054b75..d6923a15 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java @@ -102,8 +102,6 @@ public class DataBindingTest extends GWTTestCase { i2.setDate(new Date(3000)); Item[] items = new Item[]{i1, i2}; c.setItems(Arrays.asList(items)); - System.out.println(c.toJson()); - System.out.println(c.getItems().get(0).getDate()); assertEquals(2000l, c.getItems().get(0).getDate().getTime()); assertEquals(3000l, c.getItems().get(1).getDate().getTime()); -- cgit v1.2.3 From 660641a9f2a3028fadfed7cfcc45f0df9fce05e1 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sat, 28 Dec 2013 16:06:03 +0100 Subject: Implement generic interface for Binders so as we can use it in JS and JVM --- .../com/google/gwt/query/client/Properties.java | 33 ++++++- .../gwt/query/client/builders/JsonBuilder.java | 26 +----- .../gwt/query/client/builders/JsonBuilderBase.java | 27 +++++- .../com/google/gwt/query/client/js/JsCache.java | 18 ++-- .../gwt/query/rebind/JsonBuilderGenerator.java | 6 +- .../com/google/gwt/query/vm/JsonFactoryJre.java | 101 +++++++++++++++++---- .../gwt/query/client/dbinding/DataBindingTest.java | 4 + 7 files changed, 164 insertions(+), 51 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java index 3d31e852..af671474 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java @@ -15,16 +15,16 @@ */ package com.google.gwt.query.client; +import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArrayMixed; -import com.google.gwt.core.client.GWT; import com.google.gwt.query.client.js.JsCache; import com.google.gwt.query.client.js.JsUtils; /** * JSO for accessing Javascript objective literals used by GwtQuery functions. */ -public class Properties extends JavaScriptObject { +public class Properties extends JavaScriptObject implements Binder { public static Properties create() { return JsCache.create().cast(); @@ -199,4 +199,33 @@ public class Properties extends JavaScriptObject { return c().length() == 0; } + public final J load(Object prp) { + c().clear(); + if (prp instanceof JsCache) { + c().copy((JsCache)prp); + } + return getBound(); + } + + public final J parse(String json) { + return load(JsUtils.parseJSON(json)); + } + + public final String[] getFieldNames() { + return c().keys(); + } + + public final String toJson() { + return toJsonString(); + } + + @SuppressWarnings("unchecked") + public final J getBound() { + return (J)this; + } + + public final String getName() { + return "jso"; + } + } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java index 596d5473..887695d3 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java @@ -15,21 +15,13 @@ */ package com.google.gwt.query.client.builders; +import com.google.gwt.query.client.Binder; + /** * Tagging interface used to generate JsonBuilder classes. */ -public interface JsonBuilder { - - /** - * load a properties object. - */ - J load(Object prp); - - /** - * parses a json string and loads the resulting properties object. - */ - J parse(String json); +public interface JsonBuilder extends Binder { /** * parses a json string and loads the resulting properties object, @@ -41,21 +33,13 @@ public interface JsonBuilder { /** * Returns the wrapped object, normally a Properties jso in client * but can be used to return the underlying Json implementation in JVM + * @deprecated use asObject() instead */ J getProperties(); - /** - * return a list of field names. - */ - String[] getFieldNames(); - - /** - * return a string which represents the object with an alias for the className - */ - String toJson(); - /** * return the Json name for this class + * @deprecated use getName() instead; */ String getJsonName(); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index 66de0898..4ec95de8 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java @@ -26,16 +26,19 @@ public abstract class JsonBuilderBase> implements J protected Properties p = Properties.create(); @SuppressWarnings("unchecked") + @Override public J parse(String json) { return load(JsUtils.parseJSON(json)); } @SuppressWarnings("unchecked") + @Override public J parse(String json, boolean fix) { return fix ? parse(Properties.wrapPropertiesString(json)) : parse(json); } @SuppressWarnings("unchecked") + @Override public J load(Object prp) { assert prp == null || prp instanceof JavaScriptObject || prp instanceof String; if (prp != null && prp instanceof String) { @@ -51,7 +54,7 @@ public abstract class JsonBuilderBase> implements J if (r.length > 0 && r[0] instanceof JsonBuilder) { JsArray a = JavaScriptObject.createArray().cast(); for (T o : r) { - a.push(((JsonBuilder)o).getProperties()); + a.push(((JsonBuilder)o).getBound()); } p.set(n, a); } else { @@ -89,8 +92,28 @@ public abstract class JsonBuilderBase> implements J } @SuppressWarnings("unchecked") + @Override public Properties getProperties() { return p; } - + + @Override + public String toQueryString() { + return p.toQueryString(); + } + + @Override + public String getName() { + return getJsonName(); + } + + @SuppressWarnings("unchecked") + @Override + public Properties getBound() { + return p; + } + + public T get(Object key) { + return p.get(key); + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java index c8f00a6c..f10d998b 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java @@ -36,6 +36,12 @@ public class JsCache extends JavaScriptObject { if (ary) this.concat(ary); }-*/; + public final void copy(JsCache jso) { + for (String k : jso.keys()) { + put(k, jso.get(k)); + } + } + public final void pushAll(JavaScriptObject prevElem) { checkNull(); JsCache c = prevElem.cast(); @@ -47,14 +53,12 @@ public class JsCache extends JavaScriptObject { public final native void delete(Object name) /*-{ delete this[name]; }-*/; - - public final native void clear() /*-{ - if (this.length) { - for (i = this.length - 1; i >= 0; i--) - delete this[i]; - this.length = 0; + + public final void clear() { + for (String k : keys()) { + delete(k); } - }-*/; + } public final native boolean exists(Object name) /*-{ return !!this[name]; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index ead7ecd0..8a45c6f9 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -38,6 +38,7 @@ import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.Properties; +import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.JsonBuilderBase; import com.google.gwt.query.client.builders.JsonFactory; @@ -51,6 +52,7 @@ public class JsonBuilderGenerator extends Generator { static JClassType functionType; static JClassType jsonBuilderType; + static JClassType settingsType; static JClassType jsType; static JClassType listType; static JClassType stringType; @@ -82,6 +84,7 @@ public class JsonBuilderGenerator extends Generator { JClassType clazz = oracle.findType(requestedClass); jsonBuilderType = oracle.findType(JsonBuilder.class.getName()); + settingsType = oracle.findType(Binder.class.getName()); stringType = oracle.findType(String.class.getName()); jsType = oracle.findType(JavaScriptObject.class.getName()); listType = oracle.findType(List.class.getName()); @@ -101,7 +104,8 @@ public class JsonBuilderGenerator extends Generator { for (JMethod method : clazz.getInheritableMethods()) { String methName = method.getName(); //skip method from JsonBuilder - if(jsonBuilderType.findMethod(method.getName(), method.getParameterTypes()) != null) { + if(jsonBuilderType.findMethod(method.getName(), method.getParameterTypes()) != null || + settingsType.findMethod(method.getName(), method.getParameterTypes()) != null ) { continue; } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index 49b5877f..ec115086 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -13,6 +13,7 @@ import java.util.List; import org.json.JSONArray; import org.json.JSONObject; +import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.JsonFactory; import com.google.gwt.query.client.builders.Name; @@ -125,7 +126,7 @@ public class JsonFactoryJre implements JsonFactory { } else if (o instanceof Date) { return obj != null ? obj.put(attr, ((Date) o).getTime()) : arr.put(((Date) o).getTime()); } else if (o instanceof JsonBuilder) { - return obj != null ? obj.put(attr, ((JsonBuilder) o).getProperties()) : arr.put(((JsonBuilder) o).getProperties()); + return obj != null ? obj.put(attr, ((JsonBuilder) o).getBound()) : arr.put(((JsonBuilder) o).getBound()); } else if (o.getClass().isArray() || o instanceof List) { Object[] arg; if (o.getClass().isArray()) { @@ -156,13 +157,23 @@ public class JsonFactoryJre implements JsonFactory { if ("getFieldNames".equals(mname)) { return JSONObject.getNames(jsonObject); - } else if ("getProperties".equals(mname)) { + } else if ("getName".equals(mname)) { + return JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass())); + } else if (mname.matches("getProperties|getBound")) { return jsonObject; } else if (largs > 0 && ("parse".equals(mname) || "load".equals(mname))) { jsonObject = new JSONObject(String.valueOf(args[0])); - } else if ("toString".equals(mname) || "toJson".equals(mname)) { + } else if (mname.matches("toString")) { + return jsonObject.toString(); + } else if (mname.matches("toJson")) { String jsonName = JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass())); - return "{\"" + jsonName + "\":"+ jsonObject.toString(); + return "{\"" + jsonName + "\":"+ jsonObject.toString() + "}"; + } else if ("toQueryString".equals(mname)) { + return param(jsonObject); + } else if (largs == 1 && mname.equals("get")) { + Class ret = method.getReturnType(); + attr = String.valueOf(args[0]); + return getValue(null, 0, jsonObject, attr, ret, method); } else if (largs == 0 || mname.startsWith("get")) { Class ret = method.getReturnType(); return getValue(null, 0, jsonObject, attr, ret, method); @@ -172,6 +183,70 @@ public class JsonFactoryJre implements JsonFactory { } return null; } + + private String deCapitalize(String s) { + return s != null && s.length() > 0 ? s.substring(0, 1).toLowerCase() + s.substring(1) : s; + } + + private String getDataBindingClassName(Class type) { + for (Class c : type.getInterfaces()) { + if (c.equals(JsonBuilder.class)) { + return type.getName(); + } else { + return getDataBindingClassName(c); + } + } + return null; + } + + private String param(JSONObject o) { + String ret = ""; + for (String k : JSONObject.getNames(o)) { + ret += ret.isEmpty() ? "" : "&"; + JSONObject p = null; + JSONArray a = null; + String s = null; + try { + a = o.getJSONArray(k); + } catch (Exception e) { + } + if (a != null) { + for (int i = 0, l = a.length(); i < l ; i++) { + ret += i > 0 ? "&" : ""; + try { + p = a.getJSONObject(i); + } catch (Exception e) { + try { + s = String.valueOf(a.get(i)); + } catch (Exception d) { + } + } + if (p != null) { + ret += k + "[]=" + p.toString(); + } else if (s != null){ + ret += k + "[]=" + s; + } + } + } else { + try { + p = o.getJSONObject(k); + } catch (Exception e) { + try { + s = String.valueOf(o.get(k)); + } catch (Exception d) { + } + } + if (p != null) { + ret += param(p); + } else if (s != null) { + if (!s.isEmpty() && !"null".equalsIgnoreCase(s)) { + ret += k + "=" + s; + } + } + } + } + return ret; + } } @SuppressWarnings("unchecked") @@ -185,19 +260,9 @@ public class JsonFactoryJre implements JsonFactory { InvocationHandler handler = new JsonBuilderHandler(); return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] {clz}, handler); } - - private static String deCapitalize(String s) { - return s != null && s.length() > 0 ? s.substring(0, 1).toLowerCase() + s.substring(1) : s; - } - - private static String getDataBindingClassName(Class type) { - for (Class c : type.getInterfaces()) { - if (c.equals(JsonBuilder.class)) { - return type.getName(); - } else { - return getDataBindingClassName(c); - } - } - return null; + + public Binder createBinder() { + InvocationHandler handler = new JsonBuilderHandler(); + return (Binder)Proxy.newProxyInstance(Binder.class.getClassLoader(), new Class[] {Binder.class}, handler); } } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java index d6923a15..d94b706a 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java @@ -107,5 +107,9 @@ public class DataBindingTest extends GWTTestCase { assertTrue(c.toJson().startsWith("{\"jsonExample\":{")); assertTrue(c.toJson().contains("\"items\":[{\"date\":")); + assertTrue(c.toQueryString().contains("t[]=bar")); + assertTrue(c.toQueryString().contains("a=2")); + + assertEquals(1, c.get("a").intValue()); } } \ No newline at end of file -- cgit v1.2.3 From 954b0e839a6ee93da7aece0822f558f7124d0942 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sat, 28 Dec 2013 18:09:51 +0100 Subject: Use getName makes more sense --- .../java/com/google/gwt/query/client/builders/JsonBuilder.java | 5 ++--- .../com/google/gwt/query/client/builders/JsonBuilderBase.java | 10 +++++----- .../java/com/google/gwt/query/rebind/JsonBuilderGenerator.java | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java index 887695d3..6508d300 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java @@ -38,8 +38,7 @@ public interface JsonBuilder extends Binder { J getProperties(); /** - * return the Json name for this class - * @deprecated use getName() instead; + * return the short name of this class, to use in json structures. */ - String getJsonName(); + String getName(); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index 4ec95de8..af3a5128 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java @@ -91,6 +91,11 @@ public abstract class JsonBuilderBase> implements J return p.tostring(); } + @Override + public String toJson() { + return "{\"" + getName() + "\":" + p.tostring() + "}"; + } + @SuppressWarnings("unchecked") @Override public Properties getProperties() { @@ -102,11 +107,6 @@ public abstract class JsonBuilderBase> implements J return p.toQueryString(); } - @Override - public String getName() { - return getJsonName(); - } - @SuppressWarnings("unchecked") @Override public Properties getBound() { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index 8a45c6f9..8c9c7408 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -270,7 +270,7 @@ public class JsonBuilderGenerator extends Generator { public void generateToJsonMethod(SourceWriter sw, String name, TreeLogger logger) { sw.println("public final String getJsonName() {return \"" + name + "\";}"); - sw.println("public final String toJson() {return \"{\\\"\" + getJsonName() + \"\\\":\" + toString() + \"}\";}"); + sw.println("public final String getName() {return \"" + name + "\";}"); } protected SourceWriter getSourceWriter(TreeLogger logger, -- cgit v1.2.3 From 1e3810ad25a55a3f17be29e2627f89ec51bab07c Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sat, 28 Dec 2013 23:26:57 +0100 Subject: Using Binder interface in certain ajax properties --- .../java/com/google/gwt/query/client/Binder.java | 68 ++++++++++++++++++++++ .../com/google/gwt/query/client/Properties.java | 4 +- .../gwt/query/client/builders/JsonBuilderBase.java | 6 ++ .../google/gwt/query/client/plugins/ajax/Ajax.java | 36 +++++++----- .../client/plugins/deferred/PromiseReqBuilder.java | 8 +-- .../gwt/query/rebind/JsonBuilderGenerator.java | 7 ++- 6 files changed, 108 insertions(+), 21 deletions(-) create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java new file mode 100644 index 00000000..c43122ac --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java @@ -0,0 +1,68 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client; + + +/** + * Interface using for Data Binders valid for JVM and JS. + */ +public interface Binder { + /** + * load a properties object. + */ + J load(Object prp); + + /** + * parses a json string and loads the resulting properties object. + */ + J parse(String json); + + /** + * Returns the underlying object, normally a Properties jso in client + * and a Json implementation in JVM. + */ + J getBound(); + + /** + * Return the Object with the given key. + */ + T get(Object key); + + /** + * Set an Object with the given key. + */ + T set(Object key, Object val); + + /** + * return a list of field names. + */ + String[] getFieldNames(); + + /** + * return a string which represents the object with an alias for the className + */ + String toJson(); + + /** + * return a string which represents the object in a queryString format. + */ + String toQueryString(); + + /** + * return the name for this type + */ + String getName(); +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java index af671474..b8e341c4 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java @@ -179,8 +179,10 @@ public class Properties extends JavaScriptObject implements Binder { this[name].__f = f; }-*/; - public final void set(T name, O val) { + @SuppressWarnings("unchecked") + public final Properties set(Object name, Object val) { c().put(String.valueOf(name), val); + return this; } public final String tostring() { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index af3a5128..61cca6f3 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java @@ -116,4 +116,10 @@ public abstract class JsonBuilderBase> implements J public T get(Object key) { return p.get(key); } + + @SuppressWarnings("unchecked") + public T set(Object key, Object val) { + p.set(key, val); + return (T)this; + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index 3170c3cb..9e99f3b5 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -4,12 +4,15 @@ import com.google.gwt.core.client.Callback; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.ScriptInjector; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.ScriptElement; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.Response; import com.google.gwt.query.client.Function; +import com.google.gwt.query.client.GQ; import com.google.gwt.query.client.GQuery; import com.google.gwt.query.client.Promise; import com.google.gwt.query.client.Properties; +import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.query.client.plugins.Plugin; @@ -39,11 +42,11 @@ public class Ajax extends GQuery { public interface Settings extends JsonBuilder { String getContentType(); Element getContext(); - Properties getData(); + Binder getData(); String getDataString(); String getDataType(); Function getError(); - Properties getHeaders(); + Binder getHeaders(); String getPassword(); Function getSuccess(); int getTimeout(); @@ -52,11 +55,11 @@ public class Ajax extends GQuery { String getUsername(); Settings setContentType(String t); Settings setContext(Element e); - Settings setData(Properties p); + Settings setData(Object p); Settings setDataString(String d); Settings setDataType(String t); Settings setError(Function f); - Settings setHeaders(Properties p); + Settings setHeaders(Binder p); Settings setPassword(String p); Settings setSuccess(Function f); Settings setTimeout(int t); @@ -172,16 +175,21 @@ public class Ajax extends GQuery { private static Promise createPromiseScriptInjector(final String url) { return new PromiseFunction() { + private ScriptElement scriptElement; public void f(final Deferred dfd) { - ScriptInjector.fromUrl(url).setWindow(window) + scriptElement = ScriptInjector.fromUrl(url).setWindow(window) .setCallback(new Callback() { public void onSuccess(Void result) { - dfd.resolve(); + $(window).delay(0, new Function(){ + public void f() { + dfd.resolve(scriptElement); + } + }); } public void onFailure(Exception reason) { dfd.reject(reason); } - }).inject(); + }).inject().cast(); } }; } @@ -197,15 +205,15 @@ public class Ajax extends GQuery { private static Object resolveData(Settings settings, String httpMethod) { Object data = settings.getDataString(); - Properties sdata = settings.getData(); + Binder sdata = settings.getData(); if (data == null && sdata != null) { String type = settings.getDataType(); if (type != null && (httpMethod.matches("(POST|PUT)")) && type.equalsIgnoreCase("json")) { - data = sdata.toJsonString(); - } else if (JsUtils.isFormData(sdata)) { - data = sdata; + data = sdata.toString(); +// } else if (JsUtils.isFormData(sdata)) { +// data = sdata; } else { data = sdata.toQueryString(); } @@ -244,9 +252,9 @@ public class Ajax extends GQuery { return createSettings($$(prop)); } - public static Settings createSettings(Properties p) { - Settings s = GWT.create(Settings.class); - s.load(p); + public static Settings createSettings(Binder p) { + Settings s = GQ.create(Settings.class); + s.load(p.getBound()); return s; } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java index 61273296..3d1d0194 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java @@ -21,8 +21,8 @@ import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.RequestPermissionException; import com.google.gwt.http.client.Response; +import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.Function; -import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.js.JsCache; import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; @@ -102,10 +102,10 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal } })); - Properties headers = settings.getHeaders(); + Binder headers = settings.getHeaders(); if (headers != null) { - for (String headerKey : headers.keys()) { - xmlHttpRequest.setRequestHeader(headerKey, headers.getStr(headerKey)); + for (String headerKey : headers.getFieldNames()) { + xmlHttpRequest.setRequestHeader(headerKey, String.valueOf(headers.get(headerKey))); } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index 8c9c7408..2e66bc3f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -184,6 +184,9 @@ public class JsonBuilderGenerator extends Generator { String q = method.getReturnType().getQualifiedSourceName(); sw.println("return " + "((" + q + ")GWT.create(" + q + ".class))" + ".load(p.getJavaScriptObject(\"" + name + "\"));"); + } else if (isTypeAssignableTo(method.getReturnType(), settingsType)) { + String q = method.getReturnType().getQualifiedSourceName(); + sw.println("return " + "((" + q + ")p.getJavaScriptObject(\"" + name + "\"));"); } else if (retType.equals(Properties.class.getName())) { sw.println("return getPropertiesBase(\"" + name + "\");"); } else if (isTypeAssignableTo(method.getReturnType(), jsType)) { @@ -218,8 +221,8 @@ public class JsonBuilderGenerator extends Generator { sw.println("return Arrays.asList(" + ret + ");"); } } else if (method.getReturnType().isEnum() != null){ - sw.println("return "+method.getReturnType().getQualifiedSourceName()+".valueOf(p.getStr(\"" + name + "\"));"); - }else { + sw.println("return "+ method.getReturnType().getQualifiedSourceName() + ".valueOf(p.getStr(\"" + name + "\"));"); + } else { sw.println("System.err.println(\"JsonBuilderGenerator WARN: unknown return type " + retType + " " + ifaceName + "." + name + "()\"); "); // We return the object because probably the user knows how to handle it -- cgit v1.2.3 From 93b8d5792dfe60014cfbaaaec0a17ed0111ebccd Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sat, 28 Dec 2013 23:29:16 +0100 Subject: Adding first stuff to implement ajax in js and jvm --- .../query/client/plugins/ajax/AjaxTransportJs.java | 44 ++++++++++++++++++ .../com/google/gwt/query/vm/AjaxTransportJre.java | 8 ++++ .../com/google/gwt/query/client/ajax/AjaxTest.java | 54 ++++++++++++++++++++++ .../google/gwt/query/client/ajax/AjaxTestGwt.java | 29 ++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java new file mode 100644 index 00000000..bc7a72ef --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java @@ -0,0 +1,44 @@ +package com.google.gwt.query.client.plugins.ajax; + +import com.google.gwt.core.client.Callback; +import com.google.gwt.core.client.ScriptInjector; +import com.google.gwt.dom.client.ScriptElement; +import com.google.gwt.query.client.Function; +import com.google.gwt.query.client.GQuery; +import com.google.gwt.query.client.Promise; +import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; +import com.google.gwt.query.client.plugins.deferred.PromiseFunction; +import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilderJSONP; + +/** + * Ajax transport for Client side. + */ +public class AjaxTransportJs { + + + public Promise getJsonP(Settings settings) { + return new PromiseReqBuilderJSONP(settings.getUrl(), settings.getTimeout()); + } + + public Promise getLoadScript(final Settings settings) { + return new PromiseFunction() { + private ScriptElement scriptElement; + public void f(final Deferred dfd) { + scriptElement = ScriptInjector.fromUrl(settings.getUrl()).setWindow(GQuery.window) + .setCallback(new Callback() { + public void onSuccess(Void result) { + GQuery.$(GQuery.window).delay(0, new Function(){ + public void f() { + dfd.resolve(scriptElement); + } + }); + } + public void onFailure(Exception reason) { + dfd.reject(reason); + } + }).inject().cast(); + } + }; + } + +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java new file mode 100644 index 00000000..7e882d62 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -0,0 +1,8 @@ +package com.google.gwt.query.vm; + + +/** + */ +public class AjaxTransportJre { + +} diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java new file mode 100644 index 00000000..a21ec648 --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client.ajax; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import com.google.gwt.junit.client.GWTTestCase; +import com.google.gwt.query.client.Function; +import com.google.gwt.query.client.GQ; +import com.google.gwt.query.client.Properties; +import com.google.gwt.query.client.builders.JsonBuilder; +import com.google.gwt.query.client.builders.Name; +import com.google.gwt.query.client.plugins.ajax.Ajax; + +/** + * Tests for Deferred which can run either in JVM and GWT + */ +public class AjaxTest extends GWTTestCase { + + public String getModuleName() { + return null; + } + + public void testJsonValidService() { + delayTestFinish(5000); + // Use a public json service + String testJsonpUrl = "https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY"; + Ajax.getJSONP(testJsonpUrl, new Function(){ + public void f() { + Properties p = getDataProperties(); + // It should return error since we do not use a valid key + // {"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}} + assertEquals(400, p.getJavaScriptObject("error").cast().getInt("code")); + finishTest(); + } + }, null, 0); + } + +} \ No newline at end of file diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java new file mode 100644 index 00000000..b30d53d6 --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java @@ -0,0 +1,29 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client.ajax; + + +/** + * Test for data binding shared code run in gwt + */ +public class AjaxTestGwt extends AjaxTest { + + @Override + public String getModuleName() { + return "com.google.gwt.query.Query"; + } + +} -- cgit v1.2.3 From 26d30bf88f643c043768960d356c4f7e84e5667d Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Mon, 30 Dec 2013 21:00:47 +0100 Subject: Fix some issues related with FormData submit --- .../google/gwt/query/client/plugins/ajax/Ajax.java | 69 +++++++++++----------- .../client/plugins/deferred/PromiseReqBuilder.java | 29 ++++----- 2 files changed, 49 insertions(+), 49 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index 9e99f3b5..97a95996 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -2,6 +2,7 @@ package com.google.gwt.query.client.plugins.ajax; import com.google.gwt.core.client.Callback; import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.ScriptInjector; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.ScriptElement; @@ -119,23 +120,22 @@ public class Ajax extends GQuery { onError.setElement(settings.getContext()); } - String httpMethod = settings.getType() == null ? "POST" : settings.getType().toUpperCase(); - Object data = resolveData(settings, httpMethod); - final String url = resolveUrl(settings, httpMethod, data); + resolveSettings(settings); + final String dataType = settings.getDataType(); Promise ret = null; if ("jsonp".equalsIgnoreCase(dataType)) { - ret = new PromiseReqBuilderJSONP(url, null, settings.getTimeout()); + ret = new PromiseReqBuilderJSONP(settings.getUrl(), null, settings.getTimeout()); } else if ("loadscript".equalsIgnoreCase(dataType)){ - ret = createPromiseScriptInjector(url); + ret = createPromiseScriptInjector(settings.getUrl()); } else { - ret = new PromiseReqBuilder(settings, httpMethod, url, data) + ret = new PromiseReqBuilder(settings) .then(new Function() { public Object f(Object...args) { - Response response = (Response)args[0]; - Request request = (Request)args[1]; + Response response = arguments(0); + Request request = arguments(1); Object retData = null; try { if ("xml".equalsIgnoreCase(dataType)) { @@ -172,7 +172,29 @@ public class Ajax extends GQuery { return ret; } + private static void resolveSettings(Settings settings) { + String url = settings.getUrl(); + assert settings != null && settings.getUrl() != null: "no url found in settings"; + + settings.setType(settings.getType() == null ? "POST" : settings.getType().toUpperCase()); + + Binder data = settings.getData(); + if (data != null) { + if (data.getBound() instanceof JavaScriptObject && JsUtils.isFormData(data.getBound())) { + settings.setDataString(null); + } else if (settings.getType().matches("(POST|PUT)") && "json".equalsIgnoreCase(settings.getDataType())) { + settings.setDataString(data.toJson()); + } else { + settings.setDataString(data.toQueryString()); + } + } + if ("GET".equals(settings.getType()) && settings.getDataString() != null) { + url += (url.contains("?") ? "&" : "?") + settings.getDataString(); + settings.setUrl(url); + } + } + private static Promise createPromiseScriptInjector(final String url) { return new PromiseFunction() { private ScriptElement scriptElement; @@ -194,33 +216,6 @@ public class Ajax extends GQuery { }; } - private static String resolveUrl(Settings settings, String httpMethod, Object data) { - String url = settings.getUrl(); - assert url != null : "no url found in settings"; - if ("GET".equals(httpMethod) && data instanceof String) { - url += (url.contains("?") ? "&" : "?") + data; - } - return url; - } - - private static Object resolveData(Settings settings, String httpMethod) { - Object data = settings.getDataString(); - Binder sdata = settings.getData(); - if (data == null && sdata != null) { - String type = settings.getDataType(); - if (type != null - && (httpMethod.matches("(POST|PUT)")) - && type.equalsIgnoreCase("json")) { - data = sdata.toString(); -// } else if (JsUtils.isFormData(sdata)) { -// data = sdata; - } else { - data = sdata.toQueryString(); - } - } - return data; - } - public static Promise ajax(String url, Function onSuccess, Function onError) { return ajax(url, onSuccess, onError, (Settings) null); } @@ -334,6 +329,10 @@ public class Ajax extends GQuery { .setSuccess(success) ); } + + public static Promise post(Settings s) { + return ajax(s); + } public static Promise post(String url, Properties data) { return post(url, data, null); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java index 3d1d0194..5b687e54 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java @@ -64,7 +64,13 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal * which are not available in GWT, like adding progress handles or sending * javascript data (like forms in modern html5 file api) */ - public PromiseReqBuilder(Settings settings, String httpMethod, String url, Object data) { + public PromiseReqBuilder(Settings settings) { + String httpMethod = settings.getType(); + String url = settings.getUrl(); + Binder data = settings.getData(); + String ctype = settings.getContentType(); + Boolean isFormData = data != null && data.getBound() instanceof JavaScriptObject && JsUtils.isFormData(data.getBound()); + XMLHttpRequest xmlHttpRequest = XMLHttpRequest.create(); try { if (settings.getUsername() != null && settings.getPassword() != null) { @@ -86,7 +92,7 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal JsCache p = arguments(0); double total = p.getDouble("total"); double loaded = p.getDouble("loaded"); - double percent = 100 * loaded / total; + double percent = loaded == 0 ? 0 : total == 0 ? 100 : (100 * loaded / total); dfd.notify(total, loaded, percent, "download"); } })); @@ -109,17 +115,12 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal } } - if (data != null && !"GET".equalsIgnoreCase(httpMethod)) { - String ctype = settings.getContentType(); - if (data instanceof JavaScriptObject && JsUtils.isFormData((JavaScriptObject)data)) { - ctype = FormPanel.ENCODING_MULTIPART;; - } else if (ctype == null) { - String type = settings.getDataType(); - if (type != null && type.toLowerCase().startsWith("json")) { - ctype = "application/json; charset=utf-8"; - } else { - ctype = FormPanel.ENCODING_URLENCODED; - } + if (data != null && !isFormData && !"GET".equalsIgnoreCase(httpMethod)) { + String type = settings.getDataType(); + if (type != null && type.toLowerCase().startsWith("json")) { + ctype = "application/json; charset=utf-8"; + } else { + ctype = FormPanel.ENCODING_URLENCODED; } xmlHttpRequest.setRequestHeader("Content-Type", ctype); } @@ -140,7 +141,7 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal }); try { - JsUtils.runJavascriptFunction(xmlHttpRequest, "send", data); + JsUtils.runJavascriptFunction(xmlHttpRequest, "send", isFormData ? data.getBound() : settings.getDataString()); } catch (JavaScriptException e) { onError(null, e); } -- cgit v1.2.3 From 2de421f5509374242b5704d098b7e9ae2532d5ca Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Mon, 30 Dec 2013 21:03:03 +0100 Subject: Remove method used for testing --- .../src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java | 4 ---- 1 file changed, 4 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index 97a95996..9da8e7dd 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -330,10 +330,6 @@ public class Ajax extends GQuery { ); } - public static Promise post(Settings s) { - return ajax(s); - } - public static Promise post(String url, Properties data) { return post(url, data, null); } -- cgit v1.2.3 From a82893e83e0dd75aff77df6a71d32ecaf8140886 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sat, 4 Jan 2014 22:57:15 +0100 Subject: Implemented Ajax for JVM, and tests --- gwtquery-core/pom.xml | 7 +- .../com/google/gwt/junit/RunStyleHtmlUnit.java | 318 ++++ .../main/java/com/google/gwt/query/client/GQ.java | 33 +- .../gwt/query/client/builders/JsonFactory.java | 3 + .../com/google/gwt/query/client/js/JsUtils.java | 2 +- .../google/gwt/query/client/plugins/Effects.java | 3 +- .../google/gwt/query/client/plugins/ajax/Ajax.java | 85 +- .../query/client/plugins/ajax/AjaxTransportJs.java | 12 +- .../query/client/plugins/effects/Transitions.java | 2 +- .../gwt/query/rebind/JsonBuilderGenerator.java | 11 +- .../com/google/gwt/query/vm/AjaxTransportJre.java | 103 +- .../com/google/gwt/query/vm/JsonFactoryJre.java | 21 +- .../java/com/google/gwt/query/vm/ResponseJre.java | 66 + .../super/com/google/gwt/query/client/GQ.java | 28 +- .../com/google/gwt/dev/shell/BrowserChannel.java | 1720 ++++++++++++++++++++ .../java/com/google/gwt/query/QueryTest.gwt.xml | 21 + .../google/gwt/query/client/ajax/AjaxCommon.java | 156 ++ .../com/google/gwt/query/client/ajax/AjaxTest.java | 90 +- .../google/gwt/query/client/ajax/AjaxTestGwt.java | 17 +- .../gwt/query/servlet/GQAjaxTestServlet.java | 74 + 20 files changed, 2676 insertions(+), 96 deletions(-) create mode 100644 gwtquery-core/src/main/java/com/google/gwt/junit/RunStyleHtmlUnit.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/vm/ResponseJre.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannel.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/QueryTest.gwt.xml create mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/pom.xml b/gwtquery-core/pom.xml index c44b7f9b..7bfbbb9a 100644 --- a/gwtquery-core/pom.xml +++ b/gwtquery-core/pom.xml @@ -16,9 +16,14 @@ junit junit 4.7 - jar test + + net.sourceforge.htmlunit + htmlunit + 2.13 + test + com.google.gwt gwt-user diff --git a/gwtquery-core/src/main/java/com/google/gwt/junit/RunStyleHtmlUnit.java b/gwtquery-core/src/main/java/com/google/gwt/junit/RunStyleHtmlUnit.java new file mode 100644 index 00000000..0d8b5fe1 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/junit/RunStyleHtmlUnit.java @@ -0,0 +1,318 @@ +/* + * 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 RunStyleHtmlUnit 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 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 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 createBrowserMap() { + Map browserMap = new HashMap(); + 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 browsers = new HashSet(); + private boolean developmentMode; + private final List threads = new ArrayList(); + + /** + * Create a RunStyle instance with the passed-in browser targets. + */ + public RunStyleHtmlUnit(JUnitShell shell) { + super(shell); + } + + @Override + public Set 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 browserSet = new HashSet(); + 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); + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java index 0791feaf..1e6aa304 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java @@ -18,19 +18,18 @@ package com.google.gwt.query.client; import com.google.gwt.core.shared.GWT; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.JsonFactory; +import com.google.gwt.query.client.plugins.ajax.Ajax.AjaxTransport; +import com.google.gwt.query.client.plugins.ajax.AjaxTransportJs; +import com.google.gwt.query.vm.AjaxTransportJre; import com.google.gwt.query.vm.JsonFactoryJre; public class GQ { private static JsonFactory jsonFactory; + private static AjaxTransport ajaxTransport; public static T create(Class clz) { - if (jsonFactory == null) { - jsonFactory = GWT.isClient() ? - GWT.create(JsonFactory.class) : - new JsonFactoryJre(); - } - return jsonFactory.create(clz); + return getFactory().create(clz); } public static T create(Class clz, String payload) { @@ -38,4 +37,26 @@ public class GQ { ret.load(payload); return ret; } + + public static T create(String s) { + return getFactory().create(s); + } + + public static AjaxTransport getAjaxTransport() { + if (ajaxTransport == null) { + ajaxTransport = GWT.isClient() ? + new AjaxTransportJs() : + new AjaxTransportJre(); + } + return ajaxTransport; + } + + private static JsonFactory getFactory() { + if (jsonFactory == null) { + jsonFactory = GWT.isClient() ? + GWT.create(JsonFactory.class) : + new JsonFactoryJre(); + } + return jsonFactory; + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java index 30f08bb9..adcd5212 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java @@ -1,5 +1,8 @@ package com.google.gwt.query.client.builders; +import com.google.gwt.query.client.Binder; + public interface JsonFactory { T create(Class clz); + T create(String s); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java index be06f79b..ac01f7ca 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java @@ -531,7 +531,7 @@ public class JsUtils { } else { Properties p = prop.getJavaScriptObject(k); if (p != null) { - ret += p.toQueryString(); + ret += k + "=" + p.tostring(); } else { String v = prop.getStr(k); if (v != null && !v.isEmpty() && !"null".equalsIgnoreCase(v)) { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java index c7b66d5b..7f6ce927 100755 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java @@ -166,7 +166,8 @@ public class Effects extends QueuePlugin { public Effects animate(Object stringOrProperties, int duration, Easing easing, Function... funcs) { final Properties p = (stringOrProperties instanceof String) - ? $$((String) stringOrProperties) : (Properties) stringOrProperties; + ? (Properties) $$((String) stringOrProperties) + : (Properties) stringOrProperties; if (p.getStr("duration") != null) { duration = p.getInt("duration"); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index 9da8e7dd..ecf5b626 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -1,25 +1,20 @@ package com.google.gwt.query.client.plugins.ajax; -import com.google.gwt.core.client.Callback; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.ScriptInjector; import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.ScriptElement; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.Response; +import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQ; import com.google.gwt.query.client.GQuery; import com.google.gwt.query.client.Promise; import com.google.gwt.query.client.Properties; -import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.query.client.plugins.Plugin; -import com.google.gwt.query.client.plugins.deferred.PromiseFunction; -import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilder; -import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilderJSONP; /** * Ajax class for GQuery. @@ -37,6 +32,17 @@ import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilderJSONP; */ public class Ajax extends GQuery { + public static interface AjaxTransport { + + Promise getJsonP(Settings settings); + + Promise getLoadScript(Settings settings); + + Promise getXhr(Settings settings); + } + + static AjaxTransport transport = GQ.getAjaxTransport(); + /** * Ajax Settings object */ @@ -109,7 +115,8 @@ public class Ajax extends GQuery { * @param settings a Properties object with the configuration of the Ajax request. */ public static Promise ajax(Settings settings) { - + resolveSettings(settings); + final Function onSuccess = settings.getSuccess(); if (onSuccess != null) { onSuccess.setElement(settings.getContext()); @@ -120,28 +127,26 @@ public class Ajax extends GQuery { onError.setElement(settings.getContext()); } - resolveSettings(settings); - final String dataType = settings.getDataType(); Promise ret = null; if ("jsonp".equalsIgnoreCase(dataType)) { - ret = new PromiseReqBuilderJSONP(settings.getUrl(), null, settings.getTimeout()); + ret = transport.getJsonP(settings); } else if ("loadscript".equalsIgnoreCase(dataType)){ - ret = createPromiseScriptInjector(settings.getUrl()); + ret = transport.getLoadScript(settings); } else { - ret = new PromiseReqBuilder(settings) + ret = transport.getXhr(settings) .then(new Function() { public Object f(Object...args) { Response response = arguments(0); Request request = arguments(1); - Object retData = null; + Object retData = response.getText(); try { if ("xml".equalsIgnoreCase(dataType)) { retData = JsUtils.parseXML(response.getText()); } else if ("json".equalsIgnoreCase(dataType)) { - retData = JsUtils.parseJSON(response.getText()); + retData = GQ.create(response.getText()); } else { retData = response.getText(); if ("script".equalsIgnoreCase(dataType)) { @@ -149,17 +154,20 @@ public class Ajax extends GQuery { } } } catch (Exception e) { - if (GWT.getUncaughtExceptionHandler() != null) { + if (GWT.isClient() && GWT.getUncaughtExceptionHandler() != null) { GWT.getUncaughtExceptionHandler().onUncaughtException(e); + } else { + e.printStackTrace(); } } return new Object[]{retData, "success", request, response}; } }, new Function() { public Object f(Object...args) { - Throwable exception = (Throwable)args[0]; - Request request = (Request)args[1]; - return new Object[]{null, exception.getMessage(), request, null, exception}; + Throwable exception = getArgument(0, Throwable.class); + Request request = getArgument(0, Request.class); + String msg = String.valueOf(exception); + return new Object[]{null, msg, request, null, exception}; } }); } @@ -175,9 +183,16 @@ public class Ajax extends GQuery { private static void resolveSettings(Settings settings) { String url = settings.getUrl(); assert settings != null && settings.getUrl() != null: "no url found in settings"; - - settings.setType(settings.getType() == null ? "POST" : settings.getType().toUpperCase()); + String type = "POST"; + if (settings.getType() != null) { + type = settings.getType().toUpperCase(); + } + if ("jsonp".equalsIgnoreCase(settings.getDataType())) { + type = "GET"; + } + settings.setType(type); + Binder data = settings.getData(); if (data != null) { if (data.getBound() instanceof JavaScriptObject && JsUtils.isFormData(data.getBound())) { @@ -195,27 +210,6 @@ public class Ajax extends GQuery { } } - private static Promise createPromiseScriptInjector(final String url) { - return new PromiseFunction() { - private ScriptElement scriptElement; - public void f(final Deferred dfd) { - scriptElement = ScriptInjector.fromUrl(url).setWindow(window) - .setCallback(new Callback() { - public void onSuccess(Void result) { - $(window).delay(0, new Function(){ - public void f() { - dfd.resolve(scriptElement); - } - }); - } - public void onFailure(Exception reason) { - dfd.reject(reason); - } - }).inject().cast(); - } - }; - } - public static Promise ajax(String url, Function onSuccess, Function onError) { return ajax(url, onSuccess, onError, (Settings) null); } @@ -240,11 +234,14 @@ public class Ajax extends GQuery { } public static Settings createSettings() { - return createSettings($$("")); + return createSettings(""); } public static Settings createSettings(String prop) { - return createSettings($$(prop)); + Settings s = GQ.create(Settings.class); + if (prop != null && !prop.isEmpty()) + s.parse(prop); + return s; } public static Settings createSettings(Binder p) { @@ -366,7 +363,7 @@ public class Ajax extends GQuery { // Note: using '\s\S' instead of '.' because gwt String emulation does // not support java embedded flag expressions (?s) and javascript does // not have multidot flag. - String s = getArguments()[0].toString().replaceAll("]+>\\s*", "") + String s = arguments(0).toString().replaceAll("]+>\\s*", "") .replaceAll("\\s*", "") .replaceAll("\\s*", "") .replaceAll("\\s*", "") diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java index bc7a72ef..fe4e91b8 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java @@ -6,20 +6,24 @@ import com.google.gwt.dom.client.ScriptElement; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQuery; import com.google.gwt.query.client.Promise; +import com.google.gwt.query.client.plugins.ajax.Ajax.AjaxTransport; import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; +import com.google.gwt.query.client.plugins.deferred.Deferred.DeferredPromiseImpl; import com.google.gwt.query.client.plugins.deferred.PromiseFunction; +import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilder; import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilderJSONP; /** * Ajax transport for Client side. */ -public class AjaxTransportJs { - +public class AjaxTransportJs implements AjaxTransport { + @Override public Promise getJsonP(Settings settings) { return new PromiseReqBuilderJSONP(settings.getUrl(), settings.getTimeout()); } + @Override public Promise getLoadScript(final Settings settings) { return new PromiseFunction() { private ScriptElement scriptElement; @@ -40,5 +44,9 @@ public class AjaxTransportJs { } }; } + + public Promise getXhr(Settings settings) { + return new PromiseReqBuilder(settings); + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java index 57403501..ac9581cd 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java @@ -311,7 +311,7 @@ public class Transitions extends GQuery { } final Properties cssProps = (stringOrProperties instanceof String) - ? $$((String) stringOrProperties) + ? (Properties) $$((String) stringOrProperties) : (Properties) stringOrProperties; final String ease = easing == null ? "ease" : easing.toString(); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index 2e66bc3f..e1c905af 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -56,7 +56,7 @@ public class JsonBuilderGenerator extends Generator { static JClassType jsType; static JClassType listType; static JClassType stringType; - static JClassType jsonCreatorType; + static JClassType jsonFactoryType; public static String capitalize(String s) { @@ -89,11 +89,11 @@ public class JsonBuilderGenerator extends Generator { jsType = oracle.findType(JavaScriptObject.class.getName()); listType = oracle.findType(List.class.getName()); functionType = oracle.findType(Function.class.getName()); - jsonCreatorType = oracle.findType(JsonFactory.class.getName()); + jsonFactoryType = oracle.findType(JsonFactory.class.getName()); String t[] = generateClassName(clazz); - boolean isFactory = clazz.isAssignableTo(jsonCreatorType); + boolean isFactory = clazz.isAssignableTo(jsonFactoryType); SourceWriter sw = getSourceWriter(treeLogger, generatorContext, t[0], t[1], isFactory, requestedClass); if (sw != null) { @@ -323,5 +323,10 @@ public class JsonBuilderGenerator extends Generator { sw.println("return null;"); sw.outdent(); sw.println("}"); + sw.println("public T create(String s) {"); + sw.indent(); + sw.println("return (T)" + Properties.class.getName() + ".create(s);"); + sw.outdent(); + sw.println("}"); } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index 7e882d62..822da4c2 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -1,8 +1,109 @@ package com.google.gwt.query.vm; +// import org.apache.http.impl.client.HttpClientBuilder; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +import com.google.gwt.http.client.RequestException; +import com.google.gwt.http.client.Response; +import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.Function; +import com.google.gwt.query.client.GQ; +import com.google.gwt.query.client.Promise; +import com.google.gwt.query.client.plugins.ajax.Ajax.AjaxTransport; +import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; +import com.google.gwt.query.client.plugins.deferred.PromiseFunction; +import com.google.gwt.user.server.Base64Utils; /** + * */ -public class AjaxTransportJre { +public class AjaxTransportJre implements AjaxTransport { + + private final String USER_AGENT = "Mozilla/5.0"; + + public Promise getJsonP(final Settings settings) { + String url = settings.getUrl().replaceFirst("callback=[^&]*", ""); + url += (url.contains("?") ? "&" : "?") + "callback=jre_callback"; + settings.setUrl(url); + + return getXhr(settings) + .then(new Function() { + public Object f(Object... args) { + ResponseJre response = arguments(0); + return GQ.create(response.getText().replaceFirst("jre_callback\\((.*)\\)", "$1")); + } + }); + } + + public Promise getLoadScript(Settings settings) { + return getXhr(settings); + } + + public Promise getXhr(final Settings settings) { + return new PromiseFunction() { + public void f(Deferred dfd) { + try { + Response response = httpClient(settings); + int status = response.getStatusCode(); + if (status <= 0 || status >= 400) { + String statusText = status <= 0 ? "Bad CORS" : response.getStatusText(); + dfd.reject(null, new RequestException("HTTP ERROR: " + status + " " + statusText + "\n" + response.getText())); + } else { + dfd.resolve(response, null); + } + } catch (Exception e) { + dfd.reject(e, null); + } + } + }; + } + + private Response httpClient(Settings s) throws Exception { + + URL u = new URL(s.getUrl()); + + HttpURLConnection c = (HttpURLConnection) u.openConnection(); + c.setRequestMethod(s.getType()); + c.setRequestProperty("User-Agent", USER_AGENT); + if (s.getUsername() != null && s.getPassword() != null) { + c.setRequestProperty ("Authorization", "Basic " + Base64Utils.toBase64((s.getUsername() + ":" + s.getPassword()).getBytes())); + } + + Binder headers = s.getHeaders(); + if (headers != null) { + for (String h : headers.getFieldNames()) { + c.setRequestProperty(h, "" + headers.get(h)); + } + } + + if (!s.getType().equals("GET")) { + String ctype = s.getDataType(); + if (s.getDataType().toLowerCase().startsWith("json")) { + ctype = "application/json; charset=utf-8"; + } + c.setRequestProperty("Content-Type", ctype); + + c.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(c.getOutputStream()); + wr.writeBytes(s.getDataString()); + wr.flush(); + wr.close(); + } + int code = c.getResponseCode(); + BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream())); + String inputLine; + StringBuffer response = new StringBuffer(); + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + + return new ResponseJre(code, c.getResponseMessage(), response.toString(), c.getHeaderFields()); + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index ec115086..b81ca2d4 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -14,6 +14,7 @@ import org.json.JSONArray; import org.json.JSONObject; import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.JsonFactory; import com.google.gwt.query.client.builders.Name; @@ -94,7 +95,7 @@ public class JsonFactoryJre implements JsonFactory { } } else { ret = obj != null ? obj.get(attr): arr.get(idx); - if (ret instanceof JSONObject && JsonBuilder.class.isAssignableFrom(clz) && !clz.isAssignableFrom(ret.getClass())) { + if (ret instanceof JSONObject && Binder.class.isAssignableFrom(clz) && !clz.isAssignableFrom(ret.getClass())) { ret = jsonFactory.create(clz, (JSONObject)ret); } } @@ -125,8 +126,8 @@ public class JsonFactoryJre implements JsonFactory { return obj != null ? obj.put(attr, o) : arr.put(o); } else if (o instanceof Date) { return obj != null ? obj.put(attr, ((Date) o).getTime()) : arr.put(((Date) o).getTime()); - } else if (o instanceof JsonBuilder) { - return obj != null ? obj.put(attr, ((JsonBuilder) o).getBound()) : arr.put(((JsonBuilder) o).getBound()); + } else if (o instanceof Binder) { + return obj != null ? obj.put(attr, ((Binder) o).getBound()) : arr.put(((Binder) o).getBound()); } else if (o.getClass().isArray() || o instanceof List) { Object[] arg; if (o.getClass().isArray()) { @@ -166,8 +167,9 @@ public class JsonFactoryJre implements JsonFactory { } else if (mname.matches("toString")) { return jsonObject.toString(); } else if (mname.matches("toJson")) { - String jsonName = JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass())); - return "{\"" + jsonName + "\":"+ jsonObject.toString() + "}"; +// String jsonName = JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass())); +// return "{\"" + jsonName + "\":"+ jsonObject.toString() + "}"; + return jsonObject.toString() ; } else if ("toQueryString".equals(mname)) { return param(jsonObject); } else if (largs == 1 && mname.equals("get")) { @@ -237,7 +239,7 @@ public class JsonFactoryJre implements JsonFactory { } } if (p != null) { - ret += param(p); + ret += k + "=" + p.toString(); } else if (s != null) { if (!s.isEmpty() && !"null".equalsIgnoreCase(s)) { ret += k + "=" + s; @@ -265,4 +267,11 @@ public class JsonFactoryJre implements JsonFactory { InvocationHandler handler = new JsonBuilderHandler(); return (Binder)Proxy.newProxyInstance(Binder.class.getClassLoader(), new Class[] {Binder.class}, handler); } + + @SuppressWarnings("unchecked") + public T create(String s) { + Binder ret = createBinder(); + ret.parse(Properties.wrapPropertiesString(s)); + return (T)ret; + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/ResponseJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/ResponseJre.java new file mode 100644 index 00000000..36aafd37 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/ResponseJre.java @@ -0,0 +1,66 @@ +package com.google.gwt.query.vm; + +import java.util.List; +import java.util.Map; + +import com.google.gwt.http.client.Header; +import com.google.gwt.http.client.Response; + +/** + * Implementation of `Response` in the JVM + */ +public class ResponseJre extends Response { + private int status; + private Map> headers; + private String responseText; + private String statusText; + + public ResponseJre(int status, String statusText, String text, Map> headers) { + this.status = status; + this.headers = headers; + this.responseText = text; + this.statusText = statusText; + } + + public String getHeader(String header) { + List l = headers.get(header); + if (l != null && !l.isEmpty()) { + String ret = ""; + for (String s : l) { + ret += ret.isEmpty() ? s : (", " + s); + } + return ret; + } + return null; + } + + public Header[] getHeaders() { + Header[] ret = new Header[headers.size()]; + int i = 0; + for (final String s : headers.keySet()) { + final String v = getHeader(s); + ret[i] = new Header() { + public String getValue() { + return v; + } + public String getName() { + return s; + } + }; + i++; + } + return ret; + } + public String getHeadersAsString() { + return null; + } + public int getStatusCode() { + return status; + } + public String getStatusText() { + return statusText; + } + public String getText() { + return responseText; + } +} \ No newline at end of file diff --git a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java index edad9154..d694afa5 100644 --- a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java @@ -16,19 +16,21 @@ package com.google.gwt.query.client; import com.google.gwt.core.shared.GWT; +import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.JsonFactory; +import com.google.gwt.query.client.plugins.ajax.AjaxTransportJs; +import com.google.gwt.query.client.plugins.ajax.Ajax.AjaxTransport; +import com.google.gwt.query.vm.AjaxTransportJre; import com.google.gwt.query.vm.JsonFactoryJre; public class GQ { private static JsonFactory jsonFactory; + private static AjaxTransport ajaxTransport; public static T create(Class clz) { - if (jsonFactory == null) { - jsonFactory = GWT.create(JsonFactory.class); - } - return jsonFactory.create(clz); + return getFactory().create(clz); } public static T create(Class clz, String payload) { @@ -36,4 +38,22 @@ public class GQ { ret.load(payload); return ret; } + + public static T create(String s) { + return getFactory().create(s); + } + + public static AjaxTransport getAjaxTransport() { + if (ajaxTransport == null) { + ajaxTransport = new AjaxTransportJs(); + } + return ajaxTransport; + } + + private static JsonFactory getFactory() { + if (jsonFactory == null) { + jsonFactory = GWT.create(JsonFactory.class); + } + return jsonFactory; + } } diff --git a/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannel.java b/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannel.java new file mode 100644 index 00000000..9a5a925e --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannel.java @@ -0,0 +1,1720 @@ +/* + * 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.BrowserChannel.SessionHandler.ExceptionOrReturnValue; +import com.google.gwt.dev.shell.BrowserChannel.SessionHandler.SpecialDispatchId; +import com.google.gwt.dev.shell.BrowserChannel.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 BrowserChannel { + + /** + * 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. + * + *

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 { + + /** + * 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). + * + *

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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel channel) + throws IOException { + DataInputStream stream = channel.getStreamFromOtherSide(); + String js = readUtf8String(stream); + return new LoadJsniMessage(channel, js); + } + + public static void send(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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 BrowserChannel channel; + + public Message(BrowserChannel channel) { + this.channel = channel; + } + + public final BrowserChannel 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 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel channel) + throws IOException { + DataInputStream stream = channel.getStreamFromOtherSide(); + int protocolVersion = stream.readInt(); + return new ProtocolVersionMessage(channel, protocolVersion); + } + + private final int protocolVersion; + + public ProtocolVersionMessage(BrowserChannel 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(BrowserChannel channel) { + return new QuitMessage(channel); + } + + public static void send(BrowserChannel channel) throws IOException { + final DataOutputStream stream = channel.getStreamToOtherSide(); + stream.writeByte(MessageType.QUIT.getId()); + stream.flush(); + } + + public QuitMessage(BrowserChannel 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. + *

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(BrowserChannel channel) + throws IOException { + return new RequestIconMessage(channel); + } + + public static void send(BrowserChannel channel) + throws IOException { + DataOutputStream stream = channel.getStreamToOtherSide(); + stream.writeByte(MessageType.REQUEST_ICON.getId()); + stream.flush(); + } + + public RequestIconMessage(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel channel, + ExceptionOrReturnValue returnOrException) throws IOException { + send(channel, returnOrException.isException(), + returnOrException.getReturnValue()); + } + + private final boolean isException; + private final Value returnValue; + + public ReturnMessage(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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. + *

See {@link RequestIconMessage}. + */ + protected static class UserAgentIconMessage extends Message { + public static UserAgentIconMessage receive(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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 BrowserChannel(Socket socket, ObjectRefFactory objectRefFactory) + throws IOException { + this(new BufferedInputStream(socket.getInputStream()), + new BufferedOutputStream(socket.getOutputStream()), + objectRefFactory); + this.socket = socket; + } + + protected BrowserChannel(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 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 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; + } + } +} diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/QueryTest.gwt.xml b/gwtquery-core/src/test/java/com/google/gwt/query/QueryTest.gwt.xml new file mode 100644 index 00000000..5b2b1d35 --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/query/QueryTest.gwt.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java new file mode 100644 index 00000000..2ff30953 --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java @@ -0,0 +1,156 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client.ajax; + +import static com.google.gwt.query.client.GQuery.*; + +import org.mortbay.jetty.Server; + +import net.sourceforge.htmlunit.corejs.javascript.Context; +import net.sourceforge.htmlunit.corejs.javascript.Scriptable; + +import com.gargoylesoftware.htmlunit.javascript.host.xml.XMLHttpRequest; +import com.google.gwt.core.client.GWT; +import com.google.gwt.junit.client.GWTTestCase; +import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.Function; +import com.google.gwt.query.client.GQ; +import com.google.gwt.query.client.Properties; +import com.google.gwt.query.client.plugins.ajax.Ajax; +import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; + +/** + * Tests for Deferred which can run either in JVM and GWT + */ +public abstract class AjaxCommon extends GWTTestCase { + + public String getModuleName() { + return null; + } + + protected String echoUrl, corsUrl; + protected Binder json, jsonData; + protected String servletPath = "test.json"; + + private void performAjaxJsonTest(Settings s) { + delayTestFinish(5000); + Ajax.ajax(s).done(new Function(){public void f() { + Binder p = arguments(0); + assertEquals("abc", p.get("a")); + finishTest(); + }}).fail(new Function(){public void f() { + fail(); + }}); + } + + public void testAjaxJsonPost() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setUrl(echoUrl) + .setData(json) + .setDataType("json") + .setUsername("testuser") + .setPassword("testpassword") + ; + performAjaxJsonTest(s); + } + + public void testAjaxJsonPost_CORS() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setUrl(corsUrl) + .setData(json) + .setDataType("json"); + + performAjaxJsonTest(s); + } + + public void testAjaxJsonGet() { + Settings s = Ajax.createSettings() + .setType("get") + .setUrl(echoUrl) + .setData(jsonData) + .setDataType("json"); + + performAjaxJsonTest(s); + } + + public void testAjaxJsonGet_CORS() { + Settings s = Ajax.createSettings() + .setType("get") + .setUrl(corsUrl) + .setData(jsonData) + .setDataType("json"); + + performAjaxJsonTest(s); + } + + public void testAjaxGetJsonP() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setType("post") + .setUrl(echoUrl) + .setData(jsonData) + .setDataType("jsonp"); + + performAjaxJsonTest(s); + } + + public void testAjaxGetJsonP_CORS() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setType("post") + .setUrl(corsUrl) + .setData(jsonData) + .setDataType("jsonp"); + + performAjaxJsonTest(s); + } + + + +// public void testAjaxJson() { +// delayTestFinish(5000); +// Settings s = Ajax.createSettings() +// .setType("get") +// .setUrl(GWT.getModuleBaseURL() + "test.json") +// .setData($$("data: {a: abc, d: ddd}")) +// .setDataType("json"); +// +// Ajax.ajax(s).done(new Function(){public void f() { +// Binder p = arguments(0); +// assertEquals("abc", p.get("a")); +// finishTest(); +// }}).fail(new Function(){public void f() { +// fail(); +// }}); +// } + public void testJsonValidService() { + delayTestFinish(5000); + // Use a public json service + String testJsonpUrl = "https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY"; + Ajax.getJSONP(testJsonpUrl, new Function(){ + public void f() { + Binder p = arguments(0); + // It should return error since we do not use a valid key + // {"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}} + assertEquals(400, p.get("error").get("code")); + finishTest(); + } + }, null, 0); + } + +} \ No newline at end of file diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java index a21ec648..45636766 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java @@ -15,40 +15,86 @@ */ package com.google.gwt.query.client.ajax; -import java.util.Arrays; -import java.util.Date; -import java.util.List; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.Servlet; + +import org.mortbay.jetty.Server; +import org.mortbay.jetty.handler.HandlerWrapper; +import org.mortbay.jetty.servlet.DefaultServlet; +import org.mortbay.jetty.webapp.WebAppClassLoader; +import org.mortbay.jetty.webapp.WebAppContext; -import com.google.gwt.junit.client.GWTTestCase; -import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQ; -import com.google.gwt.query.client.Properties; -import com.google.gwt.query.client.builders.JsonBuilder; -import com.google.gwt.query.client.builders.Name; -import com.google.gwt.query.client.plugins.ajax.Ajax; +import com.google.gwt.query.servlet.GQAjaxTestServlet; /** * Tests for Deferred which can run either in JVM and GWT */ -public class AjaxTest extends GWTTestCase { +public class AjaxTest extends AjaxCommon { + + static Server server; + int port = 3333; public String getModuleName() { return null; } - public void testJsonValidService() { - delayTestFinish(5000); - // Use a public json service - String testJsonpUrl = "https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY"; - Ajax.getJSONP(testJsonpUrl, new Function(){ - public void f() { - Properties p = getDataProperties(); - // It should return error since we do not use a valid key - // {"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}} - assertEquals(400, p.getJavaScriptObject("error").cast().getInt("code")); - finishTest(); + protected void gwtSetUp() throws Exception { + echoUrl = "http://127.0.0.1:" + port + "/" + servletPath; + corsUrl = "http://localhost:" + port + "/" + servletPath; + jsonData = GQ.create("data: {a: abc, d: ddd}"); + json = GQ.create("a: abc, d: ddd"); + startWebServer(); + } + + protected void startWebServer() throws Exception { + if (server == null) { + final Map> servlets = new HashMap>(); + servlets.put("/" + servletPath, GQAjaxTestServlet.class); + server = createWebServer(port, ".", null, servlets, null); + } + } + + public static Server createWebServer(final int port, final String resourceBase, final String[] classpath, + final Map> servlets, final HandlerWrapper handler) throws Exception { + + final Server server = new Server(port); + + final WebAppContext context = new WebAppContext(); + context.setContextPath("/"); + context.setResourceBase(resourceBase); + + if (servlets != null) { + for (final Map.Entry> entry : servlets.entrySet()) { + final String pathSpec = entry.getKey(); + final Class servlet = entry.getValue(); + context.addServlet(servlet, pathSpec); + + // disable defaults if someone likes to register his own root servlet + if ("/".equals(pathSpec)) { + context.setDefaultsDescriptor(null); + context.addServlet(DefaultServlet.class, "/favicon.ico"); + } + } + } + + final WebAppClassLoader loader = new WebAppClassLoader(context); + if (classpath != null) { + for (final String path : classpath) { + loader.addClassPath(path); } - }, null, 0); + } + context.setClassLoader(loader); + if (handler != null) { + handler.setHandler(context); + server.setHandler(handler); + } else { + server.setHandler(context); + } + server.start(); + return server; } } \ No newline at end of file diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java index b30d53d6..022c84b1 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java @@ -15,15 +15,24 @@ */ package com.google.gwt.query.client.ajax; +import com.google.gwt.core.client.GWT; +import com.google.gwt.query.client.GQ; + /** * Test for data binding shared code run in gwt */ -public class AjaxTestGwt extends AjaxTest { - +public class AjaxTestGwt extends AjaxCommon { @Override public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; + } + + @Override + protected void gwtSetUp() throws Exception { + echoUrl = (GWT.isClient() ? GWT.getHostPageBaseURL() : "http://localhost:3333/") + servletPath; + corsUrl = echoUrl.replaceFirst("http://[\\d\\.]+:", "http://localhost:") + "?cors=true"; + jsonData = GQ.create("data: {a: abc, d: ddd}"); + json = GQ.create("a: abc, d: ddd"); } - } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java b/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java new file mode 100644 index 00000000..6ba602da --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java @@ -0,0 +1,74 @@ +package com.google.gwt.query.servlet; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Enumeration; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class GQAjaxTestServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + String name = this.getClass().getSimpleName() + " "; + + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + System.out.println(name + req.getMethod() + " " + req.getContentType()); + Enumeration en = req.getHeaderNames(); + while (en.hasMoreElements()) { + String s = (String) en.nextElement(); + System.out.println(name + s + " " + req.getHeader(s)); + } + + + String t = req.getParameter("timeout"); + if (t != null && t.matches("\\d+")) { + try { + int ms = Integer.parseInt(t); + System.out.println(" Sleeping: " + ms); + Thread.sleep(ms); + } catch (Exception e) { + } + } + + String data = ""; + if (req.getMethod().equalsIgnoreCase("get")) { + data = req.getParameter("data") != null ? req.getParameter("data") : ""; + if (req.getParameter("callback") != null) { + data = req.getParameter("callback") + "(" + data + ");"; + } + } else if (req.getMethod().equalsIgnoreCase("post") + && req.getContentType().toLowerCase().startsWith("application/json")) { + BufferedReader reader = req.getReader(); + String line; + while ((line = reader.readLine()) != null) + data += line; + } + + String origin = req.getHeader("Origin"); + if ("true".equals(req.getParameter("cors")) && origin != null) { + resp.addHeader("Access-Control-Allow-Origin", origin); + resp.addHeader("Access-Control-Allow-Credentials", "true"); + String method = req.getHeader("Access-Control-Request-Method"); + if (method != null) { + resp.addHeader("Access-Control-Allow-Methods", method); + resp.setHeader("Allow", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS"); + } + String headers = req.getHeader("Access-Control-Request-Headers"); + if (headers != null) { + resp.addHeader("Access-Control-Allow-Headers", headers); + } + } + + PrintWriter p = resp.getWriter(); + p.print(data); + p.flush(); + p.close(); + + System.out.println(name + "returns: " + data); + } +} -- cgit v1.2.3 From aca58c8c0c56f28b7038012832b4c37c9f2abf5a Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Sun, 5 Jan 2014 16:45:17 +0100 Subject: Fix timeout and CORS implementation of JVM --- .../main/java/com/google/gwt/query/client/GQ.java | 9 +- .../google/gwt/query/client/plugins/ajax/Ajax.java | 1 - .../client/plugins/deferred/PromiseReqBuilder.java | 1 + .../com/google/gwt/query/vm/AjaxTransportJre.java | 73 +++++-- .../com/google/gwt/query/vm/JsonFactoryJre.java | 26 ++- .../super/com/google/gwt/query/client/GQ.java | 3 + .../google/gwt/query/client/GQueryAjaxTestGwt.java | 84 -------- .../google/gwt/query/client/ajax/AjaxCommon.java | 224 ++++++++++++++------- .../com/google/gwt/query/client/ajax/AjaxTest.java | 16 +- .../google/gwt/query/client/ajax/AjaxTestGwt.java | 11 +- .../gwt/query/servlet/GQAjaxTestServlet.java | 2 + 11 files changed, 259 insertions(+), 191 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java index 1e6aa304..aa10ce6c 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java @@ -15,15 +15,20 @@ */ package com.google.gwt.query.client; -import com.google.gwt.core.shared.GWT; +import com.google.gwt.core.client.GWT; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.JsonFactory; import com.google.gwt.query.client.plugins.ajax.Ajax.AjaxTransport; import com.google.gwt.query.client.plugins.ajax.AjaxTransportJs; import com.google.gwt.query.vm.AjaxTransportJre; import com.google.gwt.query.vm.JsonFactoryJre; +import com.google.gwt.user.client.Window; -public class GQ { +public abstract class GQ { + + public static String domain = GWT.isClient() + ? (Window.Location.getProtocol() + Window.Location.getHost()) + : "http://127.0.0.1"; private static JsonFactory jsonFactory; private static AjaxTransport ajaxTransport; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index ecf5b626..9df0f582 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -33,7 +33,6 @@ import com.google.gwt.query.client.plugins.Plugin; public class Ajax extends GQuery { public static interface AjaxTransport { - Promise getJsonP(Settings settings); Promise getLoadScript(Settings settings); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java index 5b687e54..e6bc6d63 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java @@ -130,6 +130,7 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal JsUtils.prop(xmlHttpRequest, "withCredentials", true); final Request request = createRequestVltr(xmlHttpRequest, settings.getTimeout(), this); + System.out.println("REQ timeout " + settings.getTimeout()); xmlHttpRequest.setOnReadyStateChange(new ReadyStateChangeHandler() { public void onReadyStateChange(XMLHttpRequest xhr) { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index 822da4c2..b5f6d40f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -13,6 +13,7 @@ import com.google.gwt.http.client.Response; import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQ; +import com.google.gwt.query.client.GQuery; import com.google.gwt.query.client.Promise; import com.google.gwt.query.client.plugins.ajax.Ajax.AjaxTransport; import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; @@ -24,31 +25,48 @@ import com.google.gwt.user.server.Base64Utils; */ public class AjaxTransportJre implements AjaxTransport { + public AjaxTransportJre() { + System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); + } + private final String USER_AGENT = "Mozilla/5.0"; + private final String jsonpCbRexp = "(?ms)^.*jre_callback\\((.*)\\).*$"; public Promise getJsonP(final Settings settings) { String url = settings.getUrl().replaceFirst("callback=[^&]*", ""); url += (url.contains("?") ? "&" : "?") + "callback=jre_callback"; settings.setUrl(url); - return getXhr(settings) + if (settings.getTimeout() < 1) { + settings.setTimeout(10000); + } + + return getXhr(settings, false) .then(new Function() { public Object f(Object... args) { - ResponseJre response = arguments(0); - return GQ.create(response.getText().replaceFirst("jre_callback\\((.*)\\)", "$1")); + Response response = arguments(0); + if (response.getText().matches(jsonpCbRexp)) { + return GQ.create(response.getText().replaceFirst(jsonpCbRexp, "$1")); + } else { + return GQuery.Deferred().reject().promise(); + } } }); } public Promise getLoadScript(Settings settings) { - return getXhr(settings); + return getXhr(settings, false); } - + public Promise getXhr(final Settings settings) { + return getXhr(settings, true); + } + + private Promise getXhr(final Settings settings, final boolean cors) { return new PromiseFunction() { public void f(Deferred dfd) { try { - Response response = httpClient(settings); + Response response = httpClient(settings, cors); int status = response.getStatusCode(); if (status <= 0 || status >= 400) { String statusText = status <= 0 ? "Bad CORS" : response.getStatusText(); @@ -63,10 +81,12 @@ public class AjaxTransportJre implements AjaxTransport { }; } - private Response httpClient(Settings s) throws Exception { - - URL u = new URL(s.getUrl()); - + private Response httpClient(Settings s, boolean cors) throws Exception { + String url = s.getUrl(); + if (!url.toLowerCase().startsWith("http")) { + url = GQ.domain + (url.startsWith("/") ? "" : "/") + url; + } + URL u = new URL(url); HttpURLConnection c = (HttpURLConnection) u.openConnection(); c.setRequestMethod(s.getType()); c.setRequestProperty("User-Agent", USER_AGENT); @@ -74,6 +94,31 @@ public class AjaxTransportJre implements AjaxTransport { c.setRequestProperty ("Authorization", "Basic " + Base64Utils.toBase64((s.getUsername() + ":" + s.getPassword()).getBytes())); } + boolean isCORS = cors && !s.getUrl().contains(GQ.domain); + if (isCORS) { + // TODO: fetch options previously to the request + // >> OPTIONS + // Origin: http://127.0.0.1:8888 + // Access-Control-Allow-Origin: http://127.0.0.1:8888 + // Access-Control-Allow-Credentials: true + // Access-Control-Request-Headers: content-type + // Access-Control-Allow-Headers + // Access-Control-Request-Method + // Access-Control-Allow-Methods: POST, GET + // Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS + + // >> POST/GET + // Origin: http://127.0.0.1:8888 + // Access-Control-Allow-Origin: http://127.0.0.1:8888 + // Access-Control-Allow-Credentials: true + c.setRequestProperty("Origin", GQ.domain); + } + + if (s.getTimeout() > 0) { + c.setConnectTimeout(s.getTimeout()); + c.setReadTimeout(s.getTimeout()); + } + Binder headers = s.getHeaders(); if (headers != null) { for (String h : headers.getFieldNames()) { @@ -94,13 +139,17 @@ public class AjaxTransportJre implements AjaxTransport { wr.flush(); wr.close(); } - + int code = c.getResponseCode(); + if (isCORS && !GQ.domain.equals(c.getHeaderField("Access-Control-Allow-Origin"))) { + code = 0; + } + BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { - response.append(inputLine); + response.append(inputLine + "\n"); } in.close(); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index b81ca2d4..de07995a 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -11,9 +11,11 @@ import java.util.Date; import java.util.List; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.Function; import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.JsonFactory; @@ -40,7 +42,7 @@ public class JsonFactoryJre implements JsonFactory { } @SuppressWarnings("unchecked") - private Object jsonArrayToList(JSONArray j, Class ctype, boolean isArray) throws Throwable { + private Object jsonArrayToList(JSONArray j, Class ctype, boolean isArray) { List l = new ArrayList(); for (int i = 0; j != null && i < j.length() ; i++) { l.add((T)getValue(j, i, null, null, ctype, null)); @@ -95,12 +97,15 @@ public class JsonFactoryJre implements JsonFactory { } } else { ret = obj != null ? obj.get(attr): arr.get(idx); - if (ret instanceof JSONObject && Binder.class.isAssignableFrom(clz) && !clz.isAssignableFrom(ret.getClass())) { - ret = jsonFactory.create(clz, (JSONObject)ret); + if (ret instanceof JSONObject) { + if (clz == Object.class) { + ret = jsonFactory.createBinder((JSONObject)ret); + } else if (Binder.class.isAssignableFrom(clz) && !clz.isAssignableFrom(ret.getClass())) { + ret = jsonFactory.create(clz, (JSONObject)ret); + } } } - } catch (Throwable e) { - System.out.println(this.getClass().getSimpleName() + " ERROR getting attr=" + attr + " idx=" + idx + " Exception=" + e.getMessage()); + } catch (JSONException e) { } return ret; } @@ -138,7 +143,9 @@ public class JsonFactoryJre implements JsonFactory { JSONArray a = listToJsonArray(arg); return obj != null ? obj.put(attr, a) : arr.put(a); } else { - System.out.println("Unkown setter object " + attr + " " + o.getClass().getName() + " " + o); + if (!(o instanceof Function)) { + System.out.println("Unkown setter object " + attr + " " + o.getClass().getName() + " " + o); + } return obj != null ? obj.put(attr, o) : arr.put(o); } } catch (Throwable e) { @@ -267,7 +274,12 @@ public class JsonFactoryJre implements JsonFactory { InvocationHandler handler = new JsonBuilderHandler(); return (Binder)Proxy.newProxyInstance(Binder.class.getClassLoader(), new Class[] {Binder.class}, handler); } - + + public Binder createBinder(JSONObject jso) { + InvocationHandler handler = new JsonBuilderHandler(jso); + return (Binder)Proxy.newProxyInstance(Binder.class.getClassLoader(), new Class[] {Binder.class}, handler); + } + @SuppressWarnings("unchecked") public T create(String s) { Binder ret = createBinder(); diff --git a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java index d694afa5..f4211249 100644 --- a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java @@ -23,8 +23,11 @@ import com.google.gwt.query.client.plugins.ajax.AjaxTransportJs; import com.google.gwt.query.client.plugins.ajax.Ajax.AjaxTransport; import com.google.gwt.query.vm.AjaxTransportJre; import com.google.gwt.query.vm.JsonFactoryJre; +import com.google.gwt.user.client.Window; public class GQ { + + public static final String domain = Window.Location.getHost(); private static JsonFactory jsonFactory; private static AjaxTransport ajaxTransport; diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java index 945a7fa4..f22ce1e3 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java @@ -167,21 +167,6 @@ public class GQueryAjaxTestGwt extends GWTTestCase { assertEquals("AName", f.getEntry()[0].getAuthor().getName().getText()); } - public void testJsonValidService() { - delayTestFinish(5000); - // Use a public json service - String testJsonpUrl = "https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY"; - Ajax.getJSONP(testJsonpUrl, new Function(){ - public void f() { - Properties p = getDataProperties(); - // It should return error since we do not use a valid key - // {"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}} - assertEquals(400, p.getJavaScriptObject("error").cast().getInt("code")); - finishTest(); - } - }, null, 0); - } - @DoNotRunWith({Platform.HtmlUnitLayout}) public void testJsonNonCallbackResponse() { delayTestFinish(5000); @@ -194,73 +179,4 @@ public class GQueryAjaxTestGwt extends GWTTestCase { } }, 500); } - - public void testJsonpTimeout() { - delayTestFinish(5000); - String nonJsonpUrl = "http://127.0.0.1/nopage"; - - Settings s = Ajax.createSettings(); - s.setTimeout(1000); - s.setSuccess(new Function(){ - public void f() { - fail(); - } - }); - s.setError(new Function(){ - public void f() { - finishTest(); - } - }); - s.setDataType("jsonp"); - s.setUrl(nonJsonpUrl); - - Ajax.ajax(s); - } - - public void testAjaxError() { - delayTestFinish(5000); - String url = "http://127.0.0.1/nopage"; - - Ajax.ajax(Ajax.createSettings().setTimeout(1000).setUrl(url)) - .done(new Function(){ - public void f() { - fail(); - } - }).fail(new Function(){ - public void f() { - finishTest(); - } - }); - } - - public void testGetScript() { - delayTestFinish(5000); - String url = "http://code.jquery.com/jquery-2.0.3.min.js"; - Ajax.loadScript(url) - .done(new Function(){ - public void f() { - finishTest(); - } - }).fail(new Function(){ - public void f() { - fail(); - } - }); - } - - public void testGetScriptFail() { - delayTestFinish(5000); - String url = "http://127.0.0.1/nopage"; - Ajax.getScript(url) - .done(new Function(){ - public void f() { - fail(); - } - }).fail(new Function(){ - public void f() { - finishTest(); - } - }); - } - } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java index 2ff30953..fa790236 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java @@ -15,45 +15,61 @@ */ package com.google.gwt.query.client.ajax; -import static com.google.gwt.query.client.GQuery.*; - -import org.mortbay.jetty.Server; - -import net.sourceforge.htmlunit.corejs.javascript.Context; -import net.sourceforge.htmlunit.corejs.javascript.Scriptable; - -import com.gargoylesoftware.htmlunit.javascript.host.xml.XMLHttpRequest; -import com.google.gwt.core.client.GWT; +import com.google.gwt.http.client.Response; +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.Platform; import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQ; -import com.google.gwt.query.client.Properties; +import com.google.gwt.query.client.Promise; import com.google.gwt.query.client.plugins.ajax.Ajax; import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; /** - * Tests for Deferred which can run either in JVM and GWT + * Common Tests for Data Binding and Ajax which can run either in JVM and GWT */ public abstract class AjaxCommon extends GWTTestCase { - public String getModuleName() { - return null; - } - - protected String echoUrl, corsUrl; - protected Binder json, jsonData; + protected String echoUrl, echoUrlCORS; + protected Binder json, jsonGET; protected String servletPath = "test.json"; - private void performAjaxJsonTest(Settings s) { - delayTestFinish(5000); - Ajax.ajax(s).done(new Function(){public void f() { - Binder p = arguments(0); - assertEquals("abc", p.get("a")); - finishTest(); - }}).fail(new Function(){public void f() { + private Function failFunction = new Function() { + public void f() { fail(); - }}); + } + }; + + private Function finishFunction = new Function() { + public void f() { + finishTest(); + } + }; + + public AjaxCommon() { + jsonGET = GQ.create("data: {a: abc, d: def}"); + json = GQ.create("a: abc, d: def"); + } + + private Promise performAjaxJsonTest(Settings s) { + delayTestFinish(5000); + return Ajax.ajax(s) + .done(new Function(){public void f() { + Binder p = arguments(0); + assertEquals("abc", p.get("a")); + finishTest(); + }}) + .fail(failFunction); + } + + private Promise performAjaxJsonTest_CORS(Settings s) { + return performAjaxJsonTest(s) + .done(new Function() {public void f() { + Response r = arguments(3); + assertNotNull(r.getHeader("Access-Control-Allow-Origin")); + assertTrue(r.getHeader("Access-Control-Allow-Origin").contains(GQ.domain)); + }}); } public void testAjaxJsonPost() { @@ -63,26 +79,26 @@ public abstract class AjaxCommon extends GWTTestCase { .setData(json) .setDataType("json") .setUsername("testuser") - .setPassword("testpassword") - ; + .setPassword("testpassword"); + performAjaxJsonTest(s); } public void testAjaxJsonPost_CORS() { delayTestFinish(5000); Settings s = Ajax.createSettings() - .setUrl(corsUrl) + .setUrl(echoUrlCORS) .setData(json) .setDataType("json"); - performAjaxJsonTest(s); + performAjaxJsonTest_CORS(s); } public void testAjaxJsonGet() { Settings s = Ajax.createSettings() .setType("get") .setUrl(echoUrl) - .setData(jsonData) + .setData(jsonGET) .setDataType("json"); performAjaxJsonTest(s); @@ -91,66 +107,136 @@ public abstract class AjaxCommon extends GWTTestCase { public void testAjaxJsonGet_CORS() { Settings s = Ajax.createSettings() .setType("get") - .setUrl(corsUrl) - .setData(jsonData) + .setUrl(echoUrlCORS) + .setData(jsonGET) .setDataType("json"); - performAjaxJsonTest(s); + performAjaxJsonTest_CORS(s); } public void testAjaxGetJsonP() { delayTestFinish(5000); Settings s = Ajax.createSettings() .setType("post") - .setUrl(echoUrl) - .setData(jsonData) + .setUrl(echoUrlCORS) + .setData(jsonGET) .setDataType("jsonp"); performAjaxJsonTest(s); } - public void testAjaxGetJsonP_CORS() { + public void testJsonValidService() { + delayTestFinish(5000); + // Use a public json service supporting callback parameter + Ajax.getJSONP("https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY") + .done(new Function(){ + public void f() { + Binder p = arguments(0); + // It should return error since we do not use a valid key + // {"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}} + assertEquals(400, p.get("error").get("code").intValue()); + finishTest(); + } + }) + .fail(failFunction); + } + + public void testInvalidOrigin() { delayTestFinish(5000); Settings s = Ajax.createSettings() - .setType("post") - .setUrl(corsUrl) - .setData(jsonData) - .setDataType("jsonp"); + // Use a public json service non CORS enabled + .setUrl("https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?key=NO-KEY") + .setDataType("json") + .setTimeout(1000); + + Ajax.ajax(s) + .done(failFunction) + .fail(finishFunction); + } + + public void testJsonInvalidService() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + // Use a valid javascript which does not wrap content in a callback + .setUrl("http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js") + .setDataType("jsonp") + .setTimeout(1000); + + Ajax.ajax(s) + .done(failFunction) + .fail(finishFunction); + } + + @DoNotRunWith(Platform.HtmlUnitBug) + public void testAjaxTimeout() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setTimeout(100) + .setType("get") + // Connecting to private networks out of our LAN raises a timeout because + // there is no route for them in public networks. + .setUrl("http://10.32.45.67:7654"); - performAjaxJsonTest(s); + Ajax.ajax(s) + .done(failFunction) + .fail(finishFunction); } + public void testJsonpTimeout() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setTimeout(1000) + .setDataType("jsonp") + .setUrl(echoUrl + "?timeout=2000"); + + Ajax.ajax(s) + .done(failFunction) + .fail(finishFunction); + } + public void testAjaxError() { + delayTestFinish(5000); + String url = "http://127.0.0.1/nopage"; + + Ajax.ajax(Ajax.createSettings().setTimeout(1000).setUrl(url)) + .done(new Function(){ + public void f() { + fail(); + } + }).fail(new Function(){ + public void f() { + finishTest(); + } + }); + } -// public void testAjaxJson() { -// delayTestFinish(5000); -// Settings s = Ajax.createSettings() -// .setType("get") -// .setUrl(GWT.getModuleBaseURL() + "test.json") -// .setData($$("data: {a: abc, d: ddd}")) -// .setDataType("json"); -// -// Ajax.ajax(s).done(new Function(){public void f() { -// Binder p = arguments(0); -// assertEquals("abc", p.get("a")); -// finishTest(); -// }}).fail(new Function(){public void f() { -// fail(); -// }}); -// } - public void testJsonValidService() { + public void testLoadScript() { delayTestFinish(5000); - // Use a public json service - String testJsonpUrl = "https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY"; - Ajax.getJSONP(testJsonpUrl, new Function(){ - public void f() { - Binder p = arguments(0); - // It should return error since we do not use a valid key - // {"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}} - assertEquals(400, p.get("error").get("code")); - finishTest(); - } - }, null, 0); + String url = "http://code.jquery.com/jquery-2.0.3.min.js"; + Ajax.loadScript(url) + .done(new Function(){ + public void f() { + finishTest(); + } + }).fail(new Function(){ + public void f() { + fail(); + } + }); } + public void testGetScriptFail() { + delayTestFinish(5000); + String url = "http://127.0.0.1/nopage"; + Ajax.getScript(url) + .done(new Function(){ + public void f() { + fail(); + } + }).fail(new Function(){ + public void f() { + finishTest(); + } + }); + } } \ No newline at end of file diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java index 45636766..031e5303 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java @@ -17,6 +17,7 @@ package com.google.gwt.query.client.ajax; import java.util.HashMap; import java.util.Map; +import java.util.Random; import javax.servlet.Servlet; @@ -26,30 +27,27 @@ import org.mortbay.jetty.servlet.DefaultServlet; import org.mortbay.jetty.webapp.WebAppClassLoader; import org.mortbay.jetty.webapp.WebAppContext; -import com.google.gwt.query.client.GQ; import com.google.gwt.query.servlet.GQAjaxTestServlet; /** - * Tests for Deferred which can run either in JVM and GWT + * Tests for Data Binders and Ajax run in the JVM */ public class AjaxTest extends AjaxCommon { static Server server; - int port = 3333; + static int port = new Random().nextInt(1000) + 2000; public String getModuleName() { return null; } - protected void gwtSetUp() throws Exception { + public AjaxTest() throws Exception { echoUrl = "http://127.0.0.1:" + port + "/" + servletPath; - corsUrl = "http://localhost:" + port + "/" + servletPath; - jsonData = GQ.create("data: {a: abc, d: ddd}"); - json = GQ.create("a: abc, d: ddd"); - startWebServer(); + echoUrlCORS = "http://localhost:" + port + "/" + servletPath + "?cors=true"; + startWebServer(port); } - protected void startWebServer() throws Exception { + protected void startWebServer(int port) throws Exception { if (server == null) { final Map> servlets = new HashMap>(); servlets.put("/" + servletPath, GQAjaxTestServlet.class); diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java index 022c84b1..0e6bf736 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java @@ -16,23 +16,20 @@ package com.google.gwt.query.client.ajax; import com.google.gwt.core.client.GWT; -import com.google.gwt.query.client.GQ; /** - * Test for data binding shared code run in gwt + * Test for data binding and Ajax which is run in gwt */ public class AjaxTestGwt extends AjaxCommon { + @Override public String getModuleName() { return "com.google.gwt.query.QueryTest"; } - @Override - protected void gwtSetUp() throws Exception { + public AjaxTestGwt() { echoUrl = (GWT.isClient() ? GWT.getHostPageBaseURL() : "http://localhost:3333/") + servletPath; - corsUrl = echoUrl.replaceFirst("http://[\\d\\.]+:", "http://localhost:") + "?cors=true"; - jsonData = GQ.create("data: {a: abc, d: ddd}"); - json = GQ.create("a: abc, d: ddd"); + echoUrlCORS = echoUrl.replaceFirst("http://[\\d\\.]+:", "http://localhost:") + "?cors=true"; } } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java b/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java index 6ba602da..6f4fc1a4 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java @@ -33,6 +33,8 @@ public class GQAjaxTestServlet extends HttpServlet { Thread.sleep(ms); } catch (Exception e) { } + System.out.println(name + "timeout"); + return; } String data = ""; -- cgit v1.2.3 From c05283e47175f11d99f3f5a6784468e62ac71724 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sun, 5 Jan 2014 19:01:10 +0100 Subject: Fix tests, and clean servlet output --- gwtquery-core/pom.xml | 14 +- .../com/google/gwt/junit/RunStyleHtmlUnit.java | 318 ---- .../java/com/google/gwt/query/client/Binder.java | 11 +- .../com/google/gwt/query/client/Properties.java | 4 + .../gwt/query/client/builders/JsonBuilderBase.java | 4 + .../com/google/gwt/query/vm/JsonFactoryJre.java | 5 +- .../com/google/gwt/dev/shell/BrowserChannel.java | 1720 -------------------- .../gwt/dev/shell/BrowserChannelPatched.java | 1720 ++++++++++++++++++++ .../google/gwt/junit/RunStyleHtmlUnitPatched.java | 318 ++++ .../google/gwt/query/client/GQueryAjaxTestGwt.java | 2 +- .../google/gwt/query/client/GQueryCoreTestGwt.java | 2 +- .../google/gwt/query/client/GQueryCssTestGwt.java | 2 +- .../gwt/query/client/GQueryDeferredTestGwt.java | 2 +- .../gwt/query/client/GQueryEffectsTestGwt.java | 2 +- .../gwt/query/client/GQueryEventsTestGwt.java | 7 +- .../gwt/query/client/GQueryGwtSuiteTest.java | 8 +- .../google/gwt/query/client/GQueryJsTestGwt.java | 2 +- .../gwt/query/client/GQuerySelectorsTestGwt.java | 2 +- .../gwt/query/client/GQueryWidgetsTestGwt.java | 2 +- .../google/gwt/query/client/ajax/AjaxCommon.java | 15 +- .../gwt/query/client/dbinding/DataBindingTest.java | 6 +- .../query/client/dbinding/DataBindingTestGwt.java | 2 +- .../gwt/query/client/deferred/DeferredTestGwt.java | 2 +- .../query/client/impl/SelectorEnginesTestGwt.java | 2 +- .../gwt/query/servlet/GQAjaxTestServlet.java | 15 +- 25 files changed, 2111 insertions(+), 2076 deletions(-) delete mode 100644 gwtquery-core/src/main/java/com/google/gwt/junit/RunStyleHtmlUnit.java delete mode 100644 gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannel.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannelPatched.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/junit/RunStyleHtmlUnitPatched.java (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/pom.xml b/gwtquery-core/pom.xml index 7bfbbb9a..6ccb811b 100644 --- a/gwtquery-core/pom.xml +++ b/gwtquery-core/pom.xml @@ -18,12 +18,14 @@ 4.7 test - - net.sourceforge.htmlunit - htmlunit - 2.13 - test - + com.google.gwt gwt-user diff --git a/gwtquery-core/src/main/java/com/google/gwt/junit/RunStyleHtmlUnit.java b/gwtquery-core/src/main/java/com/google/gwt/junit/RunStyleHtmlUnit.java deleted file mode 100644 index 0d8b5fe1..00000000 --- a/gwtquery-core/src/main/java/com/google/gwt/junit/RunStyleHtmlUnit.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * 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 RunStyleHtmlUnit 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 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 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 createBrowserMap() { - Map browserMap = new HashMap(); - 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 browsers = new HashSet(); - private boolean developmentMode; - private final List threads = new ArrayList(); - - /** - * Create a RunStyle instance with the passed-in browser targets. - */ - public RunStyleHtmlUnit(JUnitShell shell) { - super(shell); - } - - @Override - public Set 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 browserSet = new HashSet(); - 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); - } -} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java index c43122ac..ba45ceb1 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java @@ -52,10 +52,19 @@ public interface Binder { String[] getFieldNames(); /** - * return a string which represents the object with an alias for the className + * return a json string which represents the object. + * Example {"name":"manolo","surname":"carrasco"} */ String toJson(); + /** + * return a string which represents the object with an alias for the + * className useful for serialization. + * + * Example {"user":{"name":"manolo","surname":"carrasco"}} + */ + String toJsonWithName(); + /** * return a string which represents the object in a queryString format. */ diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java index b8e341c4..b367e19f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java @@ -220,6 +220,10 @@ public class Properties extends JavaScriptObject implements Binder { public final String toJson() { return toJsonString(); } + + public final String toJsonWithName() { + return "{\"properties\":{" + toJson() + "}"; + } @SuppressWarnings("unchecked") public final J getBound() { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index 61cca6f3..dd45ec7d 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java @@ -93,6 +93,10 @@ public abstract class JsonBuilderBase> implements J @Override public String toJson() { + return p.tostring(); + } + + public String toJsonWithName() { return "{\"" + getName() + "\":" + p.tostring() + "}"; } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index de07995a..d3820772 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -173,9 +173,10 @@ public class JsonFactoryJre implements JsonFactory { jsonObject = new JSONObject(String.valueOf(args[0])); } else if (mname.matches("toString")) { return jsonObject.toString(); + } else if (mname.matches("toJsonWithName")) { + String jsonName = JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass())); + return "{\"" + jsonName + "\":"+ jsonObject.toString() + "}"; } else if (mname.matches("toJson")) { -// String jsonName = JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass())); -// return "{\"" + jsonName + "\":"+ jsonObject.toString() + "}"; return jsonObject.toString() ; } else if ("toQueryString".equals(mname)) { return param(jsonObject); diff --git a/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannel.java b/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannel.java deleted file mode 100644 index 9a5a925e..00000000 --- a/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannel.java +++ /dev/null @@ -1,1720 +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.dev.shell.BrowserChannel.SessionHandler.ExceptionOrReturnValue; -import com.google.gwt.dev.shell.BrowserChannel.SessionHandler.SpecialDispatchId; -import com.google.gwt.dev.shell.BrowserChannel.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 BrowserChannel { - - /** - * 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. - * - *

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 { - - /** - * 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). - * - *

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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel channel) - throws IOException { - DataInputStream stream = channel.getStreamFromOtherSide(); - String js = readUtf8String(stream); - return new LoadJsniMessage(channel, js); - } - - public static void send(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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 BrowserChannel channel; - - public Message(BrowserChannel channel) { - this.channel = channel; - } - - public final BrowserChannel 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 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel channel) - throws IOException { - DataInputStream stream = channel.getStreamFromOtherSide(); - int protocolVersion = stream.readInt(); - return new ProtocolVersionMessage(channel, protocolVersion); - } - - private final int protocolVersion; - - public ProtocolVersionMessage(BrowserChannel 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(BrowserChannel channel) { - return new QuitMessage(channel); - } - - public static void send(BrowserChannel channel) throws IOException { - final DataOutputStream stream = channel.getStreamToOtherSide(); - stream.writeByte(MessageType.QUIT.getId()); - stream.flush(); - } - - public QuitMessage(BrowserChannel 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. - *

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(BrowserChannel channel) - throws IOException { - return new RequestIconMessage(channel); - } - - public static void send(BrowserChannel channel) - throws IOException { - DataOutputStream stream = channel.getStreamToOtherSide(); - stream.writeByte(MessageType.REQUEST_ICON.getId()); - stream.flush(); - } - - public RequestIconMessage(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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(BrowserChannel channel, - ExceptionOrReturnValue returnOrException) throws IOException { - send(channel, returnOrException.isException(), - returnOrException.getReturnValue()); - } - - private final boolean isException; - private final Value returnValue; - - public ReturnMessage(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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. - *

See {@link RequestIconMessage}. - */ - protected static class UserAgentIconMessage extends Message { - public static UserAgentIconMessage receive(BrowserChannel 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(BrowserChannel 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(BrowserChannel 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 BrowserChannel(Socket socket, ObjectRefFactory objectRefFactory) - throws IOException { - this(new BufferedInputStream(socket.getInputStream()), - new BufferedOutputStream(socket.getOutputStream()), - objectRefFactory); - this.socket = socket; - } - - protected BrowserChannel(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 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 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; - } - } -} diff --git a/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannelPatched.java b/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannelPatched.java new file mode 100644 index 00000000..dc357d6f --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannelPatched.java @@ -0,0 +1,1720 @@ +/* + * 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. + * + *

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 { + + /** + * 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). + * + *

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 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. + *

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. + *

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 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 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; + } + } +} diff --git a/gwtquery-core/src/test/java/com/google/gwt/junit/RunStyleHtmlUnitPatched.java b/gwtquery-core/src/test/java/com/google/gwt/junit/RunStyleHtmlUnitPatched.java new file mode 100644 index 00000000..c7644868 --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/junit/RunStyleHtmlUnitPatched.java @@ -0,0 +1,318 @@ +/* + * 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 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 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 createBrowserMap() { + Map browserMap = new HashMap(); + 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 browsers = new HashSet(); + private boolean developmentMode; + private final List threads = new ArrayList(); + + /** + * Create a RunStyle instance with the passed-in browser targets. + */ + public RunStyleHtmlUnitPatched(JUnitShell shell) { + super(shell); + } + + @Override + public Set 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 browserSet = new HashSet(); + 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); + } +} diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java index f22ce1e3..188e516e 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java @@ -40,7 +40,7 @@ public class GQueryAjaxTestGwt extends GWTTestCase { static HTML testPanel = null; public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } public void gwtTearDown() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java index 50f99d6f..f5a5d157 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java @@ -82,7 +82,7 @@ public class GQueryCoreTestGwt extends GWTTestCase { int done = 0; public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } public void gwtTearDown() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCssTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCssTestGwt.java index ea9b91dd..90654507 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCssTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCssTestGwt.java @@ -68,7 +68,7 @@ public class GQueryCssTestGwt extends GWTTestCase { static HTML testPanel = null; public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } public void gwtTearDown() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryDeferredTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryDeferredTestGwt.java index 1ad4e907..2e0c6821 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryDeferredTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryDeferredTestGwt.java @@ -39,7 +39,7 @@ public class GQueryDeferredTestGwt extends GWTTestCase { static HTML testPanel = null; public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } public void gwtTearDown() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java index 8cf497db..ac79febe 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java @@ -41,7 +41,7 @@ public class GQueryEffectsTestGwt extends GWTTestCase { static HTML testPanel = null; public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } public void gwtTearDown() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java index b781d1d9..681faa78 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java @@ -14,6 +14,7 @@ package com.google.gwt.query.client; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NodeList; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.junit.DoNotRunWith; @@ -68,7 +69,7 @@ public class GQueryEventsTestGwt extends GWTTestCase { int testSubmitEventCont = 0; public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } public void gwtSetUp() { @@ -996,17 +997,13 @@ public class GQueryEventsTestGwt extends GWTTestCase { public void testRebind() { final GQuery b = $("

content

"); assertEquals(1, b.size()); - assertEquals(1, b.get().getLength()); b.click(new Function() { public void f(Element e) { b.css(CSS.COLOR.with(RGBColor.RED)); } }); $(e).append(b); - // TODO: dom manipulations some times modifies gquery nodelist, - // we could remove the nodelist since we maintain a list of elements. assertEquals(1, b.size()); - assertEquals(1, b.get().getLength()); b.click(); assertEquals("red", b.css("color", false)); } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java index 60b62360..e94d27eb 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java @@ -3,6 +3,7 @@ package com.google.gwt.query.client; import junit.framework.Test; import com.google.gwt.junit.tools.GWTTestSuite; +import com.google.gwt.query.client.ajax.AjaxTestGwt; import com.google.gwt.query.client.dbinding.DataBindingTestGwt; import com.google.gwt.query.client.deferred.DeferredTestGwt; import com.google.gwt.query.client.impl.SelectorEnginesTestGwt; @@ -11,13 +12,12 @@ import com.google.gwt.query.client.impl.SelectorEnginesTestGwt; * Class to run all Gwt test in a jvm instance. * It speeds up maven testing phase. */ -public class GQueryGwtSuiteTest extends GWTTestSuite -{ - public static Test suite() - { +public class GQueryGwtSuiteTest extends GWTTestSuite { + public static Test suite() { GWTTestSuite suite = new GWTTestSuite( "GQuery Suite" ); suite.addTestSuite(DataBindingTestGwt.class); suite.addTestSuite(GQueryAjaxTestGwt.class); + suite.addTestSuite(AjaxTestGwt.class); suite.addTestSuite(GQueryDeferredTestGwt.class); suite.addTestSuite(DeferredTestGwt.class); suite.addTestSuite(GQuerySelectorsTestGwt.class); diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryJsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryJsTestGwt.java index 74f91d12..a15af268 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryJsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryJsTestGwt.java @@ -34,7 +34,7 @@ public class GQueryJsTestGwt extends GWTTestCase { static HTML testPanel = null; public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } public void gwtSetUp() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTestGwt.java index 36083eee..d60eb9a0 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTestGwt.java @@ -175,7 +175,7 @@ public class GQuerySelectorsTestGwt extends GWTTestCase { }-*/; public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } public void gwtTearDown() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryWidgetsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryWidgetsTestGwt.java index c5399e83..b509fa00 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryWidgetsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryWidgetsTestGwt.java @@ -44,7 +44,7 @@ public class GQueryWidgetsTestGwt extends GWTTestCase { int testSubmitEventCont = 0; public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } public void testGWTQueryCoreWidgets() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java index fa790236..9c03b823 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java @@ -83,7 +83,15 @@ public abstract class AjaxCommon extends GWTTestCase { performAjaxJsonTest(s); } - + + // This test needs htmlunit at least 2.11 + // https://groups.google.com/forum/#!msg/google-web-toolkit/dmyTt1Bh0pM/lBTIFiTyrpkJ + // + // It is necessary to patch RunStyleHtmlUnit because GWT default browser is FF3 since + // minimun version in htmlunit-2.1x is FF3.6 + // It is necessary to patch BrowserChannel as well because convertFromJavaValue receives + // non string objects under certain circumstances. + @DoNotRunWith(Platform.HtmlUnitBug) public void testAjaxJsonPost_CORS() { delayTestFinish(5000); Settings s = Ajax.createSettings() @@ -104,6 +112,7 @@ public abstract class AjaxCommon extends GWTTestCase { performAjaxJsonTest(s); } + @DoNotRunWith(Platform.HtmlUnitBug) public void testAjaxJsonGet_CORS() { Settings s = Ajax.createSettings() .setType("get") @@ -167,7 +176,9 @@ public abstract class AjaxCommon extends GWTTestCase { .fail(finishFunction); } - @DoNotRunWith(Platform.HtmlUnitBug) + // For some reason htmlunit 2.16 does not raises a timeout, 2.9 does though, + // when server sleeps or connection lasts a while. Tested with htmlunit 2.16 + // @DoNotRunWith(Platform.HtmlUnitBug) public void testAjaxTimeout() { delayTestFinish(5000); Settings s = Ajax.createSettings() diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java index d94b706a..04bae0b9 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java @@ -105,10 +105,12 @@ public class DataBindingTest extends GWTTestCase { assertEquals(2000l, c.getItems().get(0).getDate().getTime()); assertEquals(3000l, c.getItems().get(1).getDate().getTime()); - assertTrue(c.toJson().startsWith("{\"jsonExample\":{")); + assertFalse(c.toJson().startsWith("{\"jsonExample\":")); + assertTrue(c.toJsonWithName().startsWith("{\"jsonExample\":")); assertTrue(c.toJson().contains("\"items\":[{\"date\":")); assertTrue(c.toQueryString().contains("t[]=bar")); - assertTrue(c.toQueryString().contains("a=2")); + assertTrue(c.toQueryString().contains("a=1")); + assertTrue(c.toQueryString().contains("\"a\":2")); assertEquals(1, c.get("a").intValue()); } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java index c01e6c5c..bcd697b1 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java @@ -23,7 +23,7 @@ public class DataBindingTestGwt extends DataBindingTest { @Override public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/deferred/DeferredTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/deferred/DeferredTestGwt.java index de6375db..f972d3db 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/deferred/DeferredTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/deferred/DeferredTestGwt.java @@ -23,7 +23,7 @@ public class DeferredTestGwt extends DeferredTest { @Override public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/impl/SelectorEnginesTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/impl/SelectorEnginesTestGwt.java index 57c7749a..8dd79411 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/impl/SelectorEnginesTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/impl/SelectorEnginesTestGwt.java @@ -23,7 +23,7 @@ public class SelectorEnginesTestGwt extends SelectorEnginesTest { @Override public String getModuleName() { - return "com.google.gwt.query.Query"; + return "com.google.gwt.query.QueryTest"; } } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java b/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java index 6f4fc1a4..a41dd1d7 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java @@ -13,17 +13,22 @@ import javax.servlet.http.HttpServletResponse; public class GQAjaxTestServlet extends HttpServlet { private static final long serialVersionUID = 1L; - String name = this.getClass().getSimpleName() + " "; - - @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + private String name = this.getClass().getSimpleName() + " "; + + @SuppressWarnings("unused") + private void dumpHeaders(HttpServletRequest req) { System.out.println(name + req.getMethod() + " " + req.getContentType()); + + @SuppressWarnings("unchecked") Enumeration en = req.getHeaderNames(); while (en.hasMoreElements()) { String s = (String) en.nextElement(); System.out.println(name + s + " " + req.getHeader(s)); } - + } + + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String t = req.getParameter("timeout"); if (t != null && t.matches("\\d+")) { -- cgit v1.2.3 From 678d438e2183286844a3f0444b10bd5bd92ff228 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Mon, 6 Jan 2014 21:22:14 +0100 Subject: Test refactoring. Remove hacked classes used during testing --- .../main/java/com/google/gwt/query/client/GQ.java | 4 - .../com/google/gwt/query/vm/AjaxTransportJre.java | 18 +- .../super/com/google/gwt/query/client/GQ.java | 2 - .../gwt/dev/shell/BrowserChannelPatched.java | 1720 -------------------- .../google/gwt/junit/RunStyleHtmlUnitPatched.java | 318 ---- .../gwt/query/client/GQueryGwtSuiteTest.java | 4 + .../google/gwt/query/client/ajax/AjaxCommon.java | 253 --- .../com/google/gwt/query/client/ajax/AjaxTest.java | 98 -- .../google/gwt/query/client/ajax/AjaxTestGwt.java | 2 +- .../google/gwt/query/client/ajax/AjaxTestJre.java | 103 ++ .../google/gwt/query/client/ajax/AjaxTests.java | 252 +++ .../gwt/query/client/dbinding/DataBindingTest.java | 117 -- .../query/client/dbinding/DataBindingTestGwt.java | 2 +- .../query/client/dbinding/DataBindingTestJre.java | 117 ++ 14 files changed, 488 insertions(+), 2522 deletions(-) delete mode 100644 gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannelPatched.java delete mode 100644 gwtquery-core/src/test/java/com/google/gwt/junit/RunStyleHtmlUnitPatched.java delete mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java delete mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java delete mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java create mode 100644 gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java index aa10ce6c..5120bf3d 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java @@ -26,10 +26,6 @@ import com.google.gwt.user.client.Window; public abstract class GQ { - public static String domain = GWT.isClient() - ? (Window.Location.getProtocol() + Window.Location.getHost()) - : "http://127.0.0.1"; - private static JsonFactory jsonFactory; private static AjaxTransport ajaxTransport; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index b5f6d40f..04020049 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -25,7 +25,10 @@ import com.google.gwt.user.server.Base64Utils; */ public class AjaxTransportJre implements AjaxTransport { - public AjaxTransportJre() { + private static String localDomain = null; + + public static void enableCORS(String domain) { + localDomain = domain; System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); } @@ -83,9 +86,8 @@ public class AjaxTransportJre implements AjaxTransport { private Response httpClient(Settings s, boolean cors) throws Exception { String url = s.getUrl(); - if (!url.toLowerCase().startsWith("http")) { - url = GQ.domain + (url.startsWith("/") ? "" : "/") + url; - } + assert url.toLowerCase().startsWith("http"); + URL u = new URL(url); HttpURLConnection c = (HttpURLConnection) u.openConnection(); c.setRequestMethod(s.getType()); @@ -94,7 +96,7 @@ public class AjaxTransportJre implements AjaxTransport { c.setRequestProperty ("Authorization", "Basic " + Base64Utils.toBase64((s.getUsername() + ":" + s.getPassword()).getBytes())); } - boolean isCORS = cors && !s.getUrl().contains(GQ.domain); + boolean isCORS = cors && localDomain != null && !s.getUrl().contains(localDomain); if (isCORS) { // TODO: fetch options previously to the request // >> OPTIONS @@ -111,7 +113,7 @@ public class AjaxTransportJre implements AjaxTransport { // Origin: http://127.0.0.1:8888 // Access-Control-Allow-Origin: http://127.0.0.1:8888 // Access-Control-Allow-Credentials: true - c.setRequestProperty("Origin", GQ.domain); + c.setRequestProperty("Origin", localDomain); } if (s.getTimeout() > 0) { @@ -141,8 +143,8 @@ public class AjaxTransportJre implements AjaxTransport { } int code = c.getResponseCode(); - if (isCORS && !GQ.domain.equals(c.getHeaderField("Access-Control-Allow-Origin"))) { - code = 0; + if (isCORS && !localDomain.equals(c.getHeaderField("Access-Control-Allow-Origin"))) { + code = 0; } BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream())); diff --git a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java index f4211249..a351fbbe 100644 --- a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java @@ -27,8 +27,6 @@ import com.google.gwt.user.client.Window; public class GQ { - public static final String domain = Window.Location.getHost(); - private static JsonFactory jsonFactory; private static AjaxTransport ajaxTransport; diff --git a/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannelPatched.java b/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannelPatched.java deleted file mode 100644 index dc357d6f..00000000 --- a/gwtquery-core/src/test/java/com/google/gwt/dev/shell/BrowserChannelPatched.java +++ /dev/null @@ -1,1720 +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.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. - * - *

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 { - - /** - * 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). - * - *

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 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. - *

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. - *

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 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 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; - } - } -} diff --git a/gwtquery-core/src/test/java/com/google/gwt/junit/RunStyleHtmlUnitPatched.java b/gwtquery-core/src/test/java/com/google/gwt/junit/RunStyleHtmlUnitPatched.java deleted file mode 100644 index c7644868..00000000 --- a/gwtquery-core/src/test/java/com/google/gwt/junit/RunStyleHtmlUnitPatched.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * 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 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 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 createBrowserMap() { - Map browserMap = new HashMap(); - 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 browsers = new HashSet(); - private boolean developmentMode; - private final List threads = new ArrayList(); - - /** - * Create a RunStyle instance with the passed-in browser targets. - */ - public RunStyleHtmlUnitPatched(JUnitShell shell) { - super(shell); - } - - @Override - public Set 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 browserSet = new HashSet(); - 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); - } -} diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java index e94d27eb..0bda7e76 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryGwtSuiteTest.java @@ -3,7 +3,9 @@ package com.google.gwt.query.client; import junit.framework.Test; import com.google.gwt.junit.tools.GWTTestSuite; +import com.google.gwt.query.client.ajax.AjaxTestJre; import com.google.gwt.query.client.ajax.AjaxTestGwt; +import com.google.gwt.query.client.dbinding.DataBindingTestJre; import com.google.gwt.query.client.dbinding.DataBindingTestGwt; import com.google.gwt.query.client.deferred.DeferredTestGwt; import com.google.gwt.query.client.impl.SelectorEnginesTestGwt; @@ -15,6 +17,8 @@ import com.google.gwt.query.client.impl.SelectorEnginesTestGwt; public class GQueryGwtSuiteTest extends GWTTestSuite { public static Test suite() { GWTTestSuite suite = new GWTTestSuite( "GQuery Suite" ); + suite.addTestSuite(AjaxTestJre.class); + suite.addTestSuite(DataBindingTestJre.class); suite.addTestSuite(DataBindingTestGwt.class); suite.addTestSuite(GQueryAjaxTestGwt.class); suite.addTestSuite(AjaxTestGwt.class); diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java deleted file mode 100644 index 9c03b823..00000000 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxCommon.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright 2013, The gwtquery team. - * - * 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.query.client.ajax; - -import com.google.gwt.http.client.Response; -import com.google.gwt.junit.DoNotRunWith; -import com.google.gwt.junit.Platform; -import com.google.gwt.junit.client.GWTTestCase; -import com.google.gwt.query.client.Binder; -import com.google.gwt.query.client.Function; -import com.google.gwt.query.client.GQ; -import com.google.gwt.query.client.Promise; -import com.google.gwt.query.client.plugins.ajax.Ajax; -import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; - -/** - * Common Tests for Data Binding and Ajax which can run either in JVM and GWT - */ -public abstract class AjaxCommon extends GWTTestCase { - - protected String echoUrl, echoUrlCORS; - protected Binder json, jsonGET; - protected String servletPath = "test.json"; - - private Function failFunction = new Function() { - public void f() { - fail(); - } - }; - - private Function finishFunction = new Function() { - public void f() { - finishTest(); - } - }; - - public AjaxCommon() { - jsonGET = GQ.create("data: {a: abc, d: def}"); - json = GQ.create("a: abc, d: def"); - } - - private Promise performAjaxJsonTest(Settings s) { - delayTestFinish(5000); - return Ajax.ajax(s) - .done(new Function(){public void f() { - Binder p = arguments(0); - assertEquals("abc", p.get("a")); - finishTest(); - }}) - .fail(failFunction); - } - - private Promise performAjaxJsonTest_CORS(Settings s) { - return performAjaxJsonTest(s) - .done(new Function() {public void f() { - Response r = arguments(3); - assertNotNull(r.getHeader("Access-Control-Allow-Origin")); - assertTrue(r.getHeader("Access-Control-Allow-Origin").contains(GQ.domain)); - }}); - } - - public void testAjaxJsonPost() { - delayTestFinish(5000); - Settings s = Ajax.createSettings() - .setUrl(echoUrl) - .setData(json) - .setDataType("json") - .setUsername("testuser") - .setPassword("testpassword"); - - performAjaxJsonTest(s); - } - - // This test needs htmlunit at least 2.11 - // https://groups.google.com/forum/#!msg/google-web-toolkit/dmyTt1Bh0pM/lBTIFiTyrpkJ - // - // It is necessary to patch RunStyleHtmlUnit because GWT default browser is FF3 since - // minimun version in htmlunit-2.1x is FF3.6 - // It is necessary to patch BrowserChannel as well because convertFromJavaValue receives - // non string objects under certain circumstances. - @DoNotRunWith(Platform.HtmlUnitBug) - public void testAjaxJsonPost_CORS() { - delayTestFinish(5000); - Settings s = Ajax.createSettings() - .setUrl(echoUrlCORS) - .setData(json) - .setDataType("json"); - - performAjaxJsonTest_CORS(s); - } - - public void testAjaxJsonGet() { - Settings s = Ajax.createSettings() - .setType("get") - .setUrl(echoUrl) - .setData(jsonGET) - .setDataType("json"); - - performAjaxJsonTest(s); - } - - @DoNotRunWith(Platform.HtmlUnitBug) - public void testAjaxJsonGet_CORS() { - Settings s = Ajax.createSettings() - .setType("get") - .setUrl(echoUrlCORS) - .setData(jsonGET) - .setDataType("json"); - - performAjaxJsonTest_CORS(s); - } - - public void testAjaxGetJsonP() { - delayTestFinish(5000); - Settings s = Ajax.createSettings() - .setType("post") - .setUrl(echoUrlCORS) - .setData(jsonGET) - .setDataType("jsonp"); - - performAjaxJsonTest(s); - } - - public void testJsonValidService() { - delayTestFinish(5000); - // Use a public json service supporting callback parameter - Ajax.getJSONP("https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY") - .done(new Function(){ - public void f() { - Binder p = arguments(0); - // It should return error since we do not use a valid key - // {"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}} - assertEquals(400, p.get("error").get("code").intValue()); - finishTest(); - } - }) - .fail(failFunction); - } - - public void testInvalidOrigin() { - delayTestFinish(5000); - Settings s = Ajax.createSettings() - // Use a public json service non CORS enabled - .setUrl("https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?key=NO-KEY") - .setDataType("json") - .setTimeout(1000); - - Ajax.ajax(s) - .done(failFunction) - .fail(finishFunction); - } - - public void testJsonInvalidService() { - delayTestFinish(5000); - Settings s = Ajax.createSettings() - // Use a valid javascript which does not wrap content in a callback - .setUrl("http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js") - .setDataType("jsonp") - .setTimeout(1000); - - Ajax.ajax(s) - .done(failFunction) - .fail(finishFunction); - } - - // For some reason htmlunit 2.16 does not raises a timeout, 2.9 does though, - // when server sleeps or connection lasts a while. Tested with htmlunit 2.16 - // @DoNotRunWith(Platform.HtmlUnitBug) - public void testAjaxTimeout() { - delayTestFinish(5000); - Settings s = Ajax.createSettings() - .setTimeout(100) - .setType("get") - // Connecting to private networks out of our LAN raises a timeout because - // there is no route for them in public networks. - .setUrl("http://10.32.45.67:7654"); - - Ajax.ajax(s) - .done(failFunction) - .fail(finishFunction); - } - - public void testJsonpTimeout() { - delayTestFinish(5000); - Settings s = Ajax.createSettings() - .setTimeout(1000) - .setDataType("jsonp") - .setUrl(echoUrl + "?timeout=2000"); - - Ajax.ajax(s) - .done(failFunction) - .fail(finishFunction); - } - - public void testAjaxError() { - delayTestFinish(5000); - String url = "http://127.0.0.1/nopage"; - - Ajax.ajax(Ajax.createSettings().setTimeout(1000).setUrl(url)) - .done(new Function(){ - public void f() { - fail(); - } - }).fail(new Function(){ - public void f() { - finishTest(); - } - }); - } - - public void testLoadScript() { - delayTestFinish(5000); - String url = "http://code.jquery.com/jquery-2.0.3.min.js"; - Ajax.loadScript(url) - .done(new Function(){ - public void f() { - finishTest(); - } - }).fail(new Function(){ - public void f() { - fail(); - } - }); - } - - public void testGetScriptFail() { - delayTestFinish(5000); - String url = "http://127.0.0.1/nopage"; - Ajax.getScript(url) - .done(new Function(){ - public void f() { - fail(); - } - }).fail(new Function(){ - public void f() { - finishTest(); - } - }); - } -} \ No newline at end of file diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java deleted file mode 100644 index 031e5303..00000000 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2013, The gwtquery team. - * - * 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.query.client.ajax; - -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -import javax.servlet.Servlet; - -import org.mortbay.jetty.Server; -import org.mortbay.jetty.handler.HandlerWrapper; -import org.mortbay.jetty.servlet.DefaultServlet; -import org.mortbay.jetty.webapp.WebAppClassLoader; -import org.mortbay.jetty.webapp.WebAppContext; - -import com.google.gwt.query.servlet.GQAjaxTestServlet; - -/** - * Tests for Data Binders and Ajax run in the JVM - */ -public class AjaxTest extends AjaxCommon { - - static Server server; - static int port = new Random().nextInt(1000) + 2000; - - public String getModuleName() { - return null; - } - - public AjaxTest() throws Exception { - echoUrl = "http://127.0.0.1:" + port + "/" + servletPath; - echoUrlCORS = "http://localhost:" + port + "/" + servletPath + "?cors=true"; - startWebServer(port); - } - - protected void startWebServer(int port) throws Exception { - if (server == null) { - final Map> servlets = new HashMap>(); - servlets.put("/" + servletPath, GQAjaxTestServlet.class); - server = createWebServer(port, ".", null, servlets, null); - } - } - - public static Server createWebServer(final int port, final String resourceBase, final String[] classpath, - final Map> servlets, final HandlerWrapper handler) throws Exception { - - final Server server = new Server(port); - - final WebAppContext context = new WebAppContext(); - context.setContextPath("/"); - context.setResourceBase(resourceBase); - - if (servlets != null) { - for (final Map.Entry> entry : servlets.entrySet()) { - final String pathSpec = entry.getKey(); - final Class servlet = entry.getValue(); - context.addServlet(servlet, pathSpec); - - // disable defaults if someone likes to register his own root servlet - if ("/".equals(pathSpec)) { - context.setDefaultsDescriptor(null); - context.addServlet(DefaultServlet.class, "/favicon.ico"); - } - } - } - - final WebAppClassLoader loader = new WebAppClassLoader(context); - if (classpath != null) { - for (final String path : classpath) { - loader.addClassPath(path); - } - } - context.setClassLoader(loader); - if (handler != null) { - handler.setHandler(context); - server.setHandler(handler); - } else { - server.setHandler(context); - } - server.start(); - return server; - } - -} \ No newline at end of file diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java index 0e6bf736..b69c0ac5 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java @@ -21,7 +21,7 @@ import com.google.gwt.core.client.GWT; /** * Test for data binding and Ajax which is run in gwt */ -public class AjaxTestGwt extends AjaxCommon { +public class AjaxTestGwt extends AjaxTests { @Override public String getModuleName() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java new file mode 100644 index 00000000..abe00e30 --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java @@ -0,0 +1,103 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client.ajax; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import javax.servlet.Servlet; + +import org.mortbay.jetty.Server; +import org.mortbay.jetty.handler.HandlerWrapper; +import org.mortbay.jetty.servlet.DefaultServlet; +import org.mortbay.jetty.webapp.WebAppClassLoader; +import org.mortbay.jetty.webapp.WebAppContext; + +import com.google.gwt.query.servlet.GQAjaxTestServlet; +import com.google.gwt.query.vm.AjaxTransportJre; + +/** + * Tests for Data Binders and Ajax run in the JVM + */ +public class AjaxTestJre extends AjaxTests { + + static Server server; + static int port = new Random().nextInt(1000) + 2000; + + public String getModuleName() { + return null; + } + + public AjaxTestJre() throws Exception { + String localDomain = "http://127.0.0.1:" + port; + AjaxTransportJre.enableCORS(localDomain); + String corsDomain = "http://localhost:" + port; + + echoUrl = localDomain + "/" + servletPath; + echoUrlCORS = corsDomain + "/" + servletPath + "?cors=true"; + startWebServer(port); + } + + protected void startWebServer(int port) throws Exception { + if (server == null) { + final Map> servlets = new HashMap>(); + servlets.put("/" + servletPath, GQAjaxTestServlet.class); + server = createWebServer(port, ".", null, servlets, null); + } + } + + public static Server createWebServer(final int port, final String resourceBase, final String[] classpath, + final Map> servlets, final HandlerWrapper handler) throws Exception { + + final Server server = new Server(port); + + final WebAppContext context = new WebAppContext(); + context.setContextPath("/"); + context.setResourceBase(resourceBase); + + if (servlets != null) { + for (final Map.Entry> entry : servlets.entrySet()) { + final String pathSpec = entry.getKey(); + final Class servlet = entry.getValue(); + context.addServlet(servlet, pathSpec); + + // disable defaults if someone likes to register his own root servlet + if ("/".equals(pathSpec)) { + context.setDefaultsDescriptor(null); + context.addServlet(DefaultServlet.class, "/favicon.ico"); + } + } + } + + final WebAppClassLoader loader = new WebAppClassLoader(context); + if (classpath != null) { + for (final String path : classpath) { + loader.addClassPath(path); + } + } + context.setClassLoader(loader); + if (handler != null) { + handler.setHandler(context); + server.setHandler(handler); + } else { + server.setHandler(context); + } + server.start(); + return server; + } + +} \ No newline at end of file diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java new file mode 100644 index 00000000..f6a064c5 --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java @@ -0,0 +1,252 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client.ajax; + +import com.google.gwt.http.client.Response; +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.Platform; +import com.google.gwt.junit.client.GWTTestCase; +import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.Function; +import com.google.gwt.query.client.GQ; +import com.google.gwt.query.client.Promise; +import com.google.gwt.query.client.plugins.ajax.Ajax; +import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; + +/** + * Common Tests for Data Binding and Ajax which can run either in JVM and GWT + */ +public abstract class AjaxTests extends GWTTestCase { + + protected String echoUrl, echoUrlCORS; + protected Binder json, jsonGET; + protected String servletPath = "test.json"; + + private Function failFunction = new Function() { + public void f() { + fail(); + } + }; + + private Function finishFunction = new Function() { + public void f() { + finishTest(); + } + }; + + public AjaxTests() { + jsonGET = GQ.create("data: {a: abc, d: def}"); + json = GQ.create("a: abc, d: def"); + } + + private Promise performAjaxJsonTest(Settings s) { + delayTestFinish(5000); + return Ajax.ajax(s) + .done(new Function(){public void f() { + Binder p = arguments(0); + assertEquals("abc", p.get("a")); + finishTest(); + }}) + .fail(failFunction); + } + + private Promise performAjaxJsonTest_CORS(Settings s) { + return performAjaxJsonTest(s) + .done(new Function() {public void f() { + Response r = arguments(3); + assertNotNull(r.getHeader("Access-Control-Allow-Origin")); + }}); + } + + public void testAjaxJsonPost() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setUrl(echoUrl) + .setData(json) + .setDataType("json") + .setUsername("testuser") + .setPassword("testpassword"); + + performAjaxJsonTest(s); + } + + // This test needs htmlunit at least 2.11 + // https://groups.google.com/forum/#!msg/google-web-toolkit/dmyTt1Bh0pM/lBTIFiTyrpkJ + // + // It is necessary to patch RunStyleHtmlUnit because GWT default browser is FF3 since + // minimun version in htmlunit-2.1x is FF3.6 + // It is necessary to patch BrowserChannel as well because convertFromJavaValue receives + // non string objects under certain circumstances. + @DoNotRunWith(Platform.HtmlUnitBug) + public void testAjaxJsonPost_CORS() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setUrl(echoUrlCORS) + .setData(json) + .setDataType("json"); + + performAjaxJsonTest_CORS(s); + } + + public void testAjaxJsonGet() { + Settings s = Ajax.createSettings() + .setType("get") + .setUrl(echoUrl) + .setData(jsonGET) + .setDataType("json"); + + performAjaxJsonTest(s); + } + + @DoNotRunWith(Platform.HtmlUnitBug) + public void testAjaxJsonGet_CORS() { + Settings s = Ajax.createSettings() + .setType("get") + .setUrl(echoUrlCORS) + .setData(jsonGET) + .setDataType("json"); + + performAjaxJsonTest_CORS(s); + } + + public void testAjaxGetJsonP() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setType("post") + .setUrl(echoUrlCORS) + .setData(jsonGET) + .setDataType("jsonp"); + + performAjaxJsonTest(s); + } + + public void testJsonValidService() { + delayTestFinish(5000); + // Use a public json service supporting callback parameter + Ajax.getJSONP("https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY") + .done(new Function(){ + public void f() { + Binder p = arguments(0); + // It should return error since we do not use a valid key + // {"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}} + assertEquals(400, p.get("error").get("code").intValue()); + finishTest(); + } + }) + .fail(failFunction); + } + + public void testInvalidOrigin() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + // Use a public json service non CORS enabled + .setUrl("https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?key=NO-KEY") + .setDataType("json") + .setTimeout(1000); + + Ajax.ajax(s) + .done(failFunction) + .fail(finishFunction); + } + + public void testJsonInvalidService() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + // Use a valid javascript which does not wrap content in a callback + .setUrl("http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js") + .setDataType("jsonp") + .setTimeout(1000); + + Ajax.ajax(s) + .done(failFunction) + .fail(finishFunction); + } + + // For some reason htmlunit 2.16 does not raises a timeout, 2.9 does though, + // when server sleeps or connection lasts a while. Tested with htmlunit 2.16 + // @DoNotRunWith(Platform.HtmlUnitBug) + public void testAjaxTimeout() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setTimeout(100) + .setType("get") + // Connecting to private networks out of our LAN raises a timeout because + // there is no route for them in public networks. + .setUrl("http://10.32.45.67:7654"); + + Ajax.ajax(s) + .done(failFunction) + .fail(finishFunction); + } + + public void testJsonpTimeout() { + delayTestFinish(5000); + Settings s = Ajax.createSettings() + .setTimeout(1000) + .setDataType("jsonp") + .setUrl(echoUrl + "?timeout=2000"); + + Ajax.ajax(s) + .done(failFunction) + .fail(finishFunction); + } + + public void testAjaxError() { + delayTestFinish(5000); + String url = "http://127.0.0.1/nopage"; + + Ajax.ajax(Ajax.createSettings().setTimeout(1000).setUrl(url)) + .done(new Function(){ + public void f() { + fail(); + } + }).fail(new Function(){ + public void f() { + finishTest(); + } + }); + } + + public void testLoadScript() { + delayTestFinish(5000); + String url = "http://code.jquery.com/jquery-2.0.3.min.js"; + Ajax.loadScript(url) + .done(new Function(){ + public void f() { + finishTest(); + } + }).fail(new Function(){ + public void f() { + fail(); + } + }); + } + + public void testGetScriptFail() { + delayTestFinish(5000); + String url = "http://127.0.0.1/nopage"; + Ajax.getScript(url) + .done(new Function(){ + public void f() { + fail(); + } + }).fail(new Function(){ + public void f() { + finishTest(); + } + }); + } +} \ No newline at end of file diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java deleted file mode 100644 index 04bae0b9..00000000 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2013, The gwtquery team. - * - * 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.query.client.dbinding; - -import java.util.Arrays; -import java.util.Date; -import java.util.List; - -import com.google.gwt.junit.client.GWTTestCase; -import com.google.gwt.query.client.Function; -import com.google.gwt.query.client.GQ; -import com.google.gwt.query.client.builders.JsonBuilder; -import com.google.gwt.query.client.builders.Name; - -/** - * Tests for Deferred which can run either in JVM and GWT - */ -public class DataBindingTest extends GWTTestCase { - - public String getModuleName() { - return null; - } - - public interface Item extends JsonBuilder { - Date getDate(); - void setDate(Date d); - } - - public interface JsonExample extends JsonBuilder { - int getA(); - JsonExample getB(); - @Name("M") - int getM(); - @Name("u") - String getUrl(); - long getD(); - Boolean getZ(); - String[] getT(); - JsonExample setT(String[] strings); - JsonExample setZ(Boolean b); - JsonExample setD(long l); - List getItems(); - void setItems(List a); - String y(); - void y(String s); - Function getF(); - void setF(Function f); - } - - boolean functionRun = false; - public void testJsonBuilder() { - String json = "{M:0, a:1, b:{a:2,b:{a:3}},u:url, d:'2','t':['hola','adios'], 'z': true, 'items':[{'date':100}]}"; - - JsonExample c = GQ.create(JsonExample.class); - assertEquals(0, c.getA()); - c.parse(json, true); - - assertEquals(0, c.getM()); - assertEquals(1, c.getA()); - assertNotNull(c.getB()); - assertEquals(2, c.getB().getA()); - assertEquals(3, c.getB().getB().getA()); - assertTrue(c.getZ()); - assertEquals("hola", c.getT()[0]); - assertEquals("adios", c.getT()[1]); - assertEquals("url", c.getUrl()); - c.setT(new String[]{"foo", "bar"}) - .setZ(false).setD(1234); - assertFalse(c.getZ()); - assertEquals("foo", c.getT()[0]); - assertEquals("bar", c.getT()[1]); - assertEquals(1234l, c.getD()); - c.y("y"); - assertEquals("y", c.y()); - assertEquals(1, c.getItems().size()); - - c.setF(new Function() { - public void f() { - functionRun = true; - } - }); - assertFalse(functionRun); - c.getF().f(); - assertTrue(functionRun); - - Item i1 = GQ.create(Item.class); - Item i2 = GQ.create(Item.class); - i1.setDate(new Date(2000)); - i2.setDate(new Date(3000)); - Item[] items = new Item[]{i1, i2}; - c.setItems(Arrays.asList(items)); - assertEquals(2000l, c.getItems().get(0).getDate().getTime()); - assertEquals(3000l, c.getItems().get(1).getDate().getTime()); - - assertFalse(c.toJson().startsWith("{\"jsonExample\":")); - assertTrue(c.toJsonWithName().startsWith("{\"jsonExample\":")); - assertTrue(c.toJson().contains("\"items\":[{\"date\":")); - assertTrue(c.toQueryString().contains("t[]=bar")); - assertTrue(c.toQueryString().contains("a=1")); - assertTrue(c.toQueryString().contains("\"a\":2")); - - assertEquals(1, c.get("a").intValue()); - } -} \ No newline at end of file diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java index bcd697b1..3cd087ce 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestGwt.java @@ -19,7 +19,7 @@ package com.google.gwt.query.client.dbinding; /** * Test for data binding shared code run in gwt */ -public class DataBindingTestGwt extends DataBindingTest { +public class DataBindingTestGwt extends DataBindingTestJre { @Override public String getModuleName() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java new file mode 100644 index 00000000..9fa9a555 --- /dev/null +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java @@ -0,0 +1,117 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client.dbinding; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import com.google.gwt.junit.client.GWTTestCase; +import com.google.gwt.query.client.Function; +import com.google.gwt.query.client.GQ; +import com.google.gwt.query.client.builders.JsonBuilder; +import com.google.gwt.query.client.builders.Name; + +/** + * Tests for Deferred which can run either in JVM and GWT + */ +public class DataBindingTestJre extends GWTTestCase { + + public String getModuleName() { + return null; + } + + public interface Item extends JsonBuilder { + Date getDate(); + void setDate(Date d); + } + + public interface JsonExample extends JsonBuilder { + int getA(); + JsonExample getB(); + @Name("M") + int getM(); + @Name("u") + String getUrl(); + long getD(); + Boolean getZ(); + String[] getT(); + JsonExample setT(String[] strings); + JsonExample setZ(Boolean b); + JsonExample setD(long l); + List getItems(); + void setItems(List a); + String y(); + void y(String s); + Function getF(); + void setF(Function f); + } + + boolean functionRun = false; + public void testJsonBuilder() { + String json = "{M:0, a:1, b:{a:2,b:{a:3}},u:url, d:'2','t':['hola','adios'], 'z': true, 'items':[{'date':100}]}"; + + JsonExample c = GQ.create(JsonExample.class); + assertEquals(0, c.getA()); + c.parse(json, true); + + assertEquals(0, c.getM()); + assertEquals(1, c.getA()); + assertNotNull(c.getB()); + assertEquals(2, c.getB().getA()); + assertEquals(3, c.getB().getB().getA()); + assertTrue(c.getZ()); + assertEquals("hola", c.getT()[0]); + assertEquals("adios", c.getT()[1]); + assertEquals("url", c.getUrl()); + c.setT(new String[]{"foo", "bar"}) + .setZ(false).setD(1234); + assertFalse(c.getZ()); + assertEquals("foo", c.getT()[0]); + assertEquals("bar", c.getT()[1]); + assertEquals(1234l, c.getD()); + c.y("y"); + assertEquals("y", c.y()); + assertEquals(1, c.getItems().size()); + + c.setF(new Function() { + public void f() { + functionRun = true; + } + }); + assertFalse(functionRun); + c.getF().f(); + assertTrue(functionRun); + + Item i1 = GQ.create(Item.class); + Item i2 = GQ.create(Item.class); + i1.setDate(new Date(2000)); + i2.setDate(new Date(3000)); + Item[] items = new Item[]{i1, i2}; + c.setItems(Arrays.asList(items)); + assertEquals(2000l, c.getItems().get(0).getDate().getTime()); + assertEquals(3000l, c.getItems().get(1).getDate().getTime()); + + assertFalse(c.toJson().startsWith("{\"jsonExample\":")); + assertTrue(c.toJsonWithName().startsWith("{\"jsonExample\":")); + assertTrue(c.toJson().contains("\"items\":[{\"date\":")); + assertTrue(c.toQueryString().contains("t[]=bar")); + assertTrue(c.toQueryString().contains("a=1")); + assertTrue(c.toQueryString().contains("\"a\":2")); + + assertEquals(1, c.get("a").intValue()); + } +} \ No newline at end of file -- cgit v1.2.3 From 235ee04e1a8b1fb274be05c7755c511377908404 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Tue, 7 Jan 2014 07:52:46 +0100 Subject: Implement as method to convert between types --- .../src/main/java/com/google/gwt/query/client/Binder.java | 7 ++++++- gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java | 7 ++++++- .../src/main/java/com/google/gwt/query/client/Properties.java | 8 +++++++- .../java/com/google/gwt/query/client/builders/JsonBuilder.java | 2 +- .../com/google/gwt/query/client/builders/JsonBuilderBase.java | 6 +++++- .../java/com/google/gwt/query/rebind/JsonBuilderGenerator.java | 1 - .../src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java | 6 +++++- 7 files changed, 30 insertions(+), 7 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java index ba45ceb1..2f0e47e5 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java @@ -15,6 +15,8 @@ */ package com.google.gwt.query.client; +import com.google.gwt.query.client.builders.JsonBuilder; + /** * Interface using for Data Binders valid for JVM and JS. @@ -73,5 +75,8 @@ public interface Binder { /** * return the name for this type */ - String getName(); + String getJsonName(); + + + T as (Class clz); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java index 5120bf3d..46cee7e1 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java @@ -22,7 +22,6 @@ import com.google.gwt.query.client.plugins.ajax.Ajax.AjaxTransport; import com.google.gwt.query.client.plugins.ajax.AjaxTransportJs; import com.google.gwt.query.vm.AjaxTransportJre; import com.google.gwt.query.vm.JsonFactoryJre; -import com.google.gwt.user.client.Window; public abstract class GQ { @@ -39,6 +38,12 @@ public abstract class GQ { return ret; } + public static T create(Class clz, Binder obj) { + T ret = create(clz); + ret.load(obj.getBound()); + return ret; + } + public static T create(String s) { return getFactory().create(s); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java index b367e19f..60ac6a6b 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java @@ -18,6 +18,7 @@ package com.google.gwt.query.client; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArrayMixed; +import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.js.JsCache; import com.google.gwt.query.client.js.JsUtils; @@ -230,8 +231,13 @@ public class Properties extends JavaScriptObject implements Binder { return (J)this; } - public final String getName() { + public final String getJsonName() { return "jso"; } + public final T as(Class clz) { + T ret = GQ.create(clz); + ret.load(this); + return ret; + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java index 6508d300..6e6d6f3a 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java @@ -40,5 +40,5 @@ public interface JsonBuilder extends Binder { /** * return the short name of this class, to use in json structures. */ - String getName(); + String getJsonName(); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index dd45ec7d..c4b5af88 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java @@ -97,7 +97,7 @@ public abstract class JsonBuilderBase> implements J } public String toJsonWithName() { - return "{\"" + getName() + "\":" + p.tostring() + "}"; + return "{\"" + getJsonName() + "\":" + p.tostring() + "}"; } @SuppressWarnings("unchecked") @@ -126,4 +126,8 @@ public abstract class JsonBuilderBase> implements J p.set(key, val); return (T)this; } + + public T as(Class clz) { + return p.as(clz); + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index e1c905af..38f32b0e 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -273,7 +273,6 @@ public class JsonBuilderGenerator extends Generator { public void generateToJsonMethod(SourceWriter sw, String name, TreeLogger logger) { sw.println("public final String getJsonName() {return \"" + name + "\";}"); - sw.println("public final String getName() {return \"" + name + "\";}"); } protected SourceWriter getSourceWriter(TreeLogger logger, diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index d3820772..abef1b8f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -16,6 +16,7 @@ import org.json.JSONObject; import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.Function; +import com.google.gwt.query.client.GQ; import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.JsonFactory; @@ -165,7 +166,10 @@ public class JsonFactoryJre implements JsonFactory { if ("getFieldNames".equals(mname)) { return JSONObject.getNames(jsonObject); - } else if ("getName".equals(mname)) { + } else if ("as".equals(mname)) { + Class clz = (Class)args[0]; + return jsonFactory.create(clz, jsonObject); + } else if ("getJsonName".equals(mname)) { return JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass())); } else if (mname.matches("getProperties|getBound")) { return jsonObject; -- cgit v1.2.3 From 8b2d5f3d35c5550a78100616d7ef34294a44f70a Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Tue, 7 Jan 2014 08:00:58 +0100 Subject: Use gwtSetup instead of constructor in gwt test --- .../src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java index b69c0ac5..69b0021a 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestGwt.java @@ -28,8 +28,8 @@ public class AjaxTestGwt extends AjaxTests { return "com.google.gwt.query.QueryTest"; } - public AjaxTestGwt() { - echoUrl = (GWT.isClient() ? GWT.getHostPageBaseURL() : "http://localhost:3333/") + servletPath; + protected void gwtSetUp() throws Exception { + echoUrl = GWT.getHostPageBaseURL() + servletPath; echoUrlCORS = echoUrl.replaceFirst("http://[\\d\\.]+:", "http://localhost:") + "?cors=true"; } } -- cgit v1.2.3 From c4e2abb513ed173d7bd6fe240b65af2646dc2fd7 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Tue, 7 Jan 2014 08:26:21 +0100 Subject: Fix setters with Binder objects --- .../java/com/google/gwt/query/client/builders/JsonBuilderBase.java | 7 ++++++- .../java/com/google/gwt/query/rebind/JsonBuilderGenerator.java | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index c4b5af88..40dbdae7 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java @@ -17,6 +17,7 @@ package com.google.gwt.query.client.builders; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; +import com.google.gwt.query.client.Binder; import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.js.JsObjectArray; import com.google.gwt.query.client.js.JsUtils; @@ -123,7 +124,11 @@ public abstract class JsonBuilderBase> implements J @SuppressWarnings("unchecked") public T set(Object key, Object val) { - p.set(key, val); + if (val instanceof Binder) { + p.set(key, ((Binder)val).getBound()); + } else { + p.set(key, val); + } return (T)this; } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index 38f32b0e..5de9dc31 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -256,7 +256,7 @@ public class JsonBuilderGenerator extends Generator { } else if (type.isEnum() != null){ sw.println("p.set(\"" + name + "\", a.name());"); }else { - sw.println("p.set(\"" + name + "\", a);"); + sw.println("set(\"" + name + "\", a);"); } if (!"void".equals(retType)) { if (isTypeAssignableTo(method.getReturnType(), -- cgit v1.2.3 From 9ff6b89b9ee8da3c7afc8713eb52a3e998ded4f4 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Wed, 15 Jan 2014 19:43:48 +0100 Subject: PUT and POST should be handled in the same way --- .../src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index 04020049..0725465f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -128,7 +128,7 @@ public class AjaxTransportJre implements AjaxTransport { } } - if (!s.getType().equals("GET")) { + if (s.getType().matches("POST|PUT")) { String ctype = s.getDataType(); if (s.getDataType().toLowerCase().startsWith("json")) { ctype = "application/json; charset=utf-8"; -- cgit v1.2.3 From 5a56b36ba5fa3d912375f85f2ac5ed66e2eef108 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Sat, 18 Jan 2014 13:29:56 +0100 Subject: Safe type casting --- .../src/main/java/com/google/gwt/query/client/GQ.java | 6 +++++- .../com/google/gwt/query/client/builders/JsonFactory.java | 3 ++- .../main/java/com/google/gwt/query/vm/JsonFactoryJre.java | 13 +++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java index 46cee7e1..27dbbe78 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java @@ -44,9 +44,13 @@ public abstract class GQ { return ret; } - public static T create(String s) { + public static Binder create(String s) { return getFactory().create(s); } + + public static Binder create() { + return getFactory().create(); + } public static AjaxTransport getAjaxTransport() { if (ajaxTransport == null) { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java index adcd5212..4bc57c9c 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java @@ -4,5 +4,6 @@ import com.google.gwt.query.client.Binder; public interface JsonFactory { T create(Class clz); - T create(String s); + Binder create(String s); + Binder create(); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index abef1b8f..d234d854 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -284,11 +284,16 @@ public class JsonFactoryJre implements JsonFactory { InvocationHandler handler = new JsonBuilderHandler(jso); return (Binder)Proxy.newProxyInstance(Binder.class.getClassLoader(), new Class[] {Binder.class}, handler); } - - @SuppressWarnings("unchecked") - public T create(String s) { + + @Override + public Binder create(String s) { Binder ret = createBinder(); ret.parse(Properties.wrapPropertiesString(s)); - return (T)ret; + return ret; + } + + @Override + public Binder create() { + return createBinder(); } } -- cgit v1.2.3 From 6f8ccb8062ca975d2d75104cc4b08088944bc974 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Sat, 18 Jan 2014 13:50:14 +0100 Subject: Add new methods to generator --- .../java/com/google/gwt/query/rebind/JsonBuilderGenerator.java | 9 +++++++-- .../google/gwt/query/super/com/google/gwt/query/client/GQ.java | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index 5de9dc31..3fc7868c 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -322,9 +322,14 @@ public class JsonBuilderGenerator extends Generator { sw.println("return null;"); sw.outdent(); sw.println("}"); - sw.println("public T create(String s) {"); + sw.println("public Binder create(String s) {"); sw.indent(); - sw.println("return (T)" + Properties.class.getName() + ".create(s);"); + sw.println("return " + Properties.class.getName() + ".create(s);"); + sw.outdent(); + sw.println("}"); + sw.println("public Binder create() {"); + sw.indent(); + sw.println("return " + Properties.class.getName() + ".create();"); sw.outdent(); sw.println("}"); } diff --git a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java index a351fbbe..732d2902 100644 --- a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java @@ -40,10 +40,14 @@ public class GQ { return ret; } - public static T create(String s) { + public static Binder create(String s) { return getFactory().create(s); } - + + public static Binder create() { + return getFactory().create(); + } + public static AjaxTransport getAjaxTransport() { if (ajaxTransport == null) { ajaxTransport = new AjaxTransportJs(); -- cgit v1.2.3 From f0949bb68e5a753ecf6527af8b5d1c9bc84a9f7c Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sun, 19 Jan 2014 17:29:27 +0000 Subject: Use Constants to set Json content-type and simply code --- .../com/google/gwt/query/client/plugins/ajax/Ajax.java | 17 ++++++++++++++--- .../client/plugins/deferred/PromiseReqBuilder.java | 8 -------- .../java/com/google/gwt/query/vm/AjaxTransportJre.java | 7 +------ .../com/google/gwt/query/servlet/GQAjaxTestServlet.java | 12 +++++++----- 4 files changed, 22 insertions(+), 22 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index 9df0f582..b22516d8 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -15,6 +15,7 @@ import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.query.client.plugins.Plugin; +import com.google.gwt.user.client.ui.FormPanel; /** * Ajax class for GQuery. @@ -31,6 +32,10 @@ import com.google.gwt.query.client.plugins.Plugin; * */ public class Ajax extends GQuery { + + public static final String JSON_CONTENT_TYPE = "application/json"; + + public static final String JSON_CONTENT_TYPE_UTF8 = JSON_CONTENT_TYPE + "; charset=utf-8"; public static interface AjaxTransport { Promise getJsonP(Settings settings); @@ -194,13 +199,19 @@ public class Ajax extends GQuery { Binder data = settings.getData(); if (data != null) { + String dataString = null, contentType = null; if (data.getBound() instanceof JavaScriptObject && JsUtils.isFormData(data.getBound())) { - settings.setDataString(null); + dataString = null; + contentType = FormPanel.ENCODING_URLENCODED; } else if (settings.getType().matches("(POST|PUT)") && "json".equalsIgnoreCase(settings.getDataType())) { - settings.setDataString(data.toJson()); + dataString = data.toJson(); + contentType = JSON_CONTENT_TYPE_UTF8; } else { - settings.setDataString(data.toQueryString()); + dataString = data.toQueryString(); + contentType = FormPanel.ENCODING_URLENCODED; } + settings.setDataString(dataString); + settings.setContentType(contentType); } if ("GET".equals(settings.getType()) && settings.getDataString() != null) { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java index e6bc6d63..79d3fa8d 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java @@ -27,7 +27,6 @@ import com.google.gwt.query.client.js.JsCache; import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; import com.google.gwt.query.client.plugins.deferred.Deferred.DeferredPromiseImpl; -import com.google.gwt.user.client.ui.FormPanel; import com.google.gwt.xhr.client.ReadyStateChangeHandler; import com.google.gwt.xhr.client.XMLHttpRequest; @@ -116,12 +115,6 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal } if (data != null && !isFormData && !"GET".equalsIgnoreCase(httpMethod)) { - String type = settings.getDataType(); - if (type != null && type.toLowerCase().startsWith("json")) { - ctype = "application/json; charset=utf-8"; - } else { - ctype = FormPanel.ENCODING_URLENCODED; - } xmlHttpRequest.setRequestHeader("Content-Type", ctype); } @@ -130,7 +123,6 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal JsUtils.prop(xmlHttpRequest, "withCredentials", true); final Request request = createRequestVltr(xmlHttpRequest, settings.getTimeout(), this); - System.out.println("REQ timeout " + settings.getTimeout()); xmlHttpRequest.setOnReadyStateChange(new ReadyStateChangeHandler() { public void onReadyStateChange(XMLHttpRequest xhr) { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index 0725465f..0433738b 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -129,12 +129,7 @@ public class AjaxTransportJre implements AjaxTransport { } if (s.getType().matches("POST|PUT")) { - String ctype = s.getDataType(); - if (s.getDataType().toLowerCase().startsWith("json")) { - ctype = "application/json; charset=utf-8"; - } - c.setRequestProperty("Content-Type", ctype); - + c.setRequestProperty("Content-Type", s.getContentType()); c.setDoOutput(true); DataOutputStream wr = new DataOutputStream(c.getOutputStream()); wr.writeBytes(s.getDataString()); diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java b/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java index a41dd1d7..5152de4c 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java @@ -10,6 +10,8 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import com.google.gwt.query.client.plugins.ajax.Ajax; + public class GQAjaxTestServlet extends HttpServlet { private static final long serialVersionUID = 1L; @@ -29,16 +31,14 @@ public class GQAjaxTestServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String t = req.getParameter("timeout"); if (t != null && t.matches("\\d+")) { try { int ms = Integer.parseInt(t); - System.out.println(" Sleeping: " + ms); + System.out.println(name + "sleeping: " + ms); Thread.sleep(ms); } catch (Exception e) { } - System.out.println(name + "timeout"); return; } @@ -49,11 +49,13 @@ public class GQAjaxTestServlet extends HttpServlet { data = req.getParameter("callback") + "(" + data + ");"; } } else if (req.getMethod().equalsIgnoreCase("post") - && req.getContentType().toLowerCase().startsWith("application/json")) { + && req.getContentType() != null + && req.getContentType().toLowerCase().startsWith(Ajax.JSON_CONTENT_TYPE)) { BufferedReader reader = req.getReader(); String line; - while ((line = reader.readLine()) != null) + while ((line = reader.readLine()) != null) { data += line; + } } String origin = req.getHeader("Origin"); -- cgit v1.2.3 From 66b15fa9b6e16a5e5fd17b43e28e81eaa2afaf34 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sun, 19 Jan 2014 17:51:49 +0000 Subject: adjust generics --- .../src/main/java/com/google/gwt/query/client/Binder.java | 8 ++++---- .../src/main/java/com/google/gwt/query/client/Properties.java | 4 ++-- .../com/google/gwt/query/client/builders/JsonBuilderBase.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java index 2f0e47e5..852a3c41 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java @@ -25,18 +25,18 @@ public interface Binder { /** * load a properties object. */ - J load(Object prp); + T load(Object prp); /** * parses a json string and loads the resulting properties object. */ - J parse(String json); + T parse(String json); /** * Returns the underlying object, normally a Properties jso in client * and a Json implementation in JVM. */ - J getBound(); + T getBound(); /** * Return the Object with the given key. @@ -46,7 +46,7 @@ public interface Binder { /** * Set an Object with the given key. */ - T set(Object key, Object val); + T set(Object key, Object val); /** * return a list of field names. diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java index 60ac6a6b..d24a7f98 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java @@ -202,7 +202,7 @@ public class Properties extends JavaScriptObject implements Binder { return c().length() == 0; } - public final J load(Object prp) { + public final J load(Object prp) { c().clear(); if (prp instanceof JsCache) { c().copy((JsCache)prp); @@ -210,7 +210,7 @@ public class Properties extends JavaScriptObject implements Binder { return getBound(); } - public final J parse(String json) { + public final J parse(String json) { return load(JsUtils.parseJSON(json)); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index 40dbdae7..cfa77296 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java @@ -123,7 +123,7 @@ public abstract class JsonBuilderBase> implements J } @SuppressWarnings("unchecked") - public T set(Object key, Object val) { + public T set(Object key, Object val) { if (val instanceof Binder) { p.set(key, ((Binder)val).getBound()); } else { -- cgit v1.2.3 From d5005837513b7f28a5200d6c69fd89c21c711ec2 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sun, 19 Jan 2014 22:22:22 +0000 Subject: Fix get method in jre --- .../src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index d234d854..05c2bff0 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -191,6 +191,9 @@ public class JsonFactoryJre implements JsonFactory { } else if (largs == 0 || mname.startsWith("get")) { Class ret = method.getReturnType(); return getValue(null, 0, jsonObject, attr, ret, method); + } else if (largs == 2 && mname.equals("set")) { + setValue(null, jsonObject, String.valueOf(args[0]), args[1], method); + return proxy; } else if (largs == 1 || mname.startsWith("set")) { setValue(null, jsonObject, attr, args[0], method); return proxy; -- cgit v1.2.3 From 8cb8d24e5a4f50aa9a26f9708deef1d380b11ee0 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sun, 19 Jan 2014 22:24:44 +0000 Subject: Use interface instead of properties implementation --- .../google/gwt/query/client/plugins/ajax/Ajax.java | 41 +++++++++++++++------- .../query/client/plugins/ajax/AjaxTransportJs.java | 1 - 2 files changed, 28 insertions(+), 14 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index b22516d8..70a9b1a8 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -11,7 +11,6 @@ import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQ; import com.google.gwt.query.client.GQuery; import com.google.gwt.query.client.Promise; -import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.query.client.plugins.Plugin; @@ -85,7 +84,7 @@ public class Ajax extends GQuery { } }); - public static Promise ajax(Properties p) { + public static Promise ajax(Binder p) { Settings s = createSettings(); s.load(p); return ajax(s); @@ -232,7 +231,7 @@ public class Ajax extends GQuery { return ajax(s); } - public static Promise ajax(String url, Properties p) { + public static Promise ajax(String url, Binder p) { Settings s = createSettings(); s.load(p); s.setUrl(url); @@ -260,7 +259,15 @@ public class Ajax extends GQuery { return s; } - public static Promise get(String url, Properties data, Function onSuccess) { + public static Promise get(String url) { + return get(url, null, null); + } + + public static Promise get(String url, Binder data) { + return get(url, data, null); + } + + public static Promise get(String url, Binder data, Function onSuccess) { Settings s = createSettings(); s.setUrl(url); s.setDataType("txt"); @@ -270,7 +277,11 @@ public class Ajax extends GQuery { return ajax(s); } - public static Promise getJSON(String url, Properties data, Function onSuccess) { + public static Promise getJSON(String url, Binder data) { + return getJSON(url, data, null); + } + + public static Promise getJSON(String url, Binder data, Function onSuccess) { Settings s = createSettings(); s.setUrl(url); s.setDataType("json"); @@ -279,12 +290,16 @@ public class Ajax extends GQuery { s.setSuccess(onSuccess); return ajax(s); } - + public static Promise getJSONP(String url) { return getJSONP(url, null, null); } - public static Promise getJSONP(String url, Properties data, Function onSuccess) { + public static Promise getJSONP(String url, Binder data) { + return getJSONP(url, data, null); + } + + public static Promise getJSONP(String url, Binder data, Function onSuccess) { Settings s = createSettings(); s.setUrl(url); s.setDataType("jsonp"); @@ -336,12 +351,12 @@ public class Ajax extends GQuery { .setSuccess(success) ); } - - public static Promise post(String url, Properties data) { + + public static Promise post(String url, Binder data) { return post(url, data, null); } - - public static Promise post(String url, Properties data, final Function onSuccess) { + + public static Promise post(String url, Binder data, final Function onSuccess) { Settings s = createSettings(); s.setUrl(url); s.setDataType("txt"); @@ -355,11 +370,11 @@ public class Ajax extends GQuery { super(gq); } - public Ajax load(String url, Properties data) { + public Ajax load(String url, Binder data) { return load(url, data); } - public Ajax load(String url, Properties data, final Function onSuccess) { + public Ajax load(String url, Binder data, final Function onSuccess) { Settings s = createSettings(); final String filter = url.contains(" ") ? url.replaceFirst("^[^\\s]+\\s+", "") : ""; s.setUrl(url.replaceAll("\\s+.+$", "")); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java index fe4e91b8..12ce7cda 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/AjaxTransportJs.java @@ -8,7 +8,6 @@ import com.google.gwt.query.client.GQuery; import com.google.gwt.query.client.Promise; import com.google.gwt.query.client.plugins.ajax.Ajax.AjaxTransport; import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; -import com.google.gwt.query.client.plugins.deferred.Deferred.DeferredPromiseImpl; import com.google.gwt.query.client.plugins.deferred.PromiseFunction; import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilder; import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilderJSONP; -- cgit v1.2.3 From 7d9feb50039b44a89b37642137944e9add8713da Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Sun, 19 Jan 2014 22:32:10 +0000 Subject: fix tests --- .../src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index 70a9b1a8..928f667f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -292,11 +292,11 @@ public class Ajax extends GQuery { } public static Promise getJSONP(String url) { - return getJSONP(url, null, null); + return getJSONP(url, null); } public static Promise getJSONP(String url, Binder data) { - return getJSONP(url, data, null); + return getJSONP(url, (Binder)data, null); } public static Promise getJSONP(String url, Binder data, Function onSuccess) { -- cgit v1.2.3 From 1698ef35053af4ed3e22a5f9602e35ec2e8cf8e4 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Mon, 20 Jan 2014 07:23:55 +0000 Subject: select appropriate overloaded methods --- .../main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index 928f667f..6591fc0a 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -260,11 +260,11 @@ public class Ajax extends GQuery { } public static Promise get(String url) { - return get(url, null, null); + return get(url, null); } public static Promise get(String url, Binder data) { - return get(url, data, null); + return get(url, (Binder)data, null); } public static Promise get(String url, Binder data, Function onSuccess) { @@ -353,7 +353,7 @@ public class Ajax extends GQuery { } public static Promise post(String url, Binder data) { - return post(url, data, null); + return post(url, (Binder)data, null); } public static Promise post(String url, Binder data, final Function onSuccess) { -- cgit v1.2.3 From 7a5db3ca23d4db216aa705d0a9790293a672adc0 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Mon, 20 Jan 2014 09:18:30 +0100 Subject: merge --- .../java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java index 9fa9a555..ac648fc1 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java @@ -35,8 +35,12 @@ public class DataBindingTestJre extends GWTTestCase { } public interface Item extends JsonBuilder { + public static enum Type {BIG, SMALL} + Date getDate(); void setDate(Date d); + Type getType(); + void setType(Type t); } public interface JsonExample extends JsonBuilder { -- cgit v1.2.3 From 9164a892dd9371e67bfc6cac50973b4588cd861d Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Tue, 21 Jan 2014 07:34:14 +0000 Subject: managing cookies --- .../google/gwt/query/client/plugins/ajax/Ajax.java | 6 +- .../com/google/gwt/query/vm/AjaxTransportJre.java | 7 + .../com/google/gwt/query/vm/CookieManager.java | 217 +++++++++++++++++++++ .../com/google/gwt/query/vm/JsonFactoryJre.java | 2 +- .../java/com/google/gwt/query/vm/ResponseJre.java | 6 +- 5 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index 6591fc0a..f516fc6a 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -167,8 +167,8 @@ public class Ajax extends GQuery { } }, new Function() { public Object f(Object...args) { - Throwable exception = getArgument(0, Throwable.class); - Request request = getArgument(0, Request.class); + Throwable exception = arguments(0); + Request request = arguments(1); String msg = String.valueOf(exception); return new Object[]{null, msg, request, null, exception}; } @@ -212,6 +212,8 @@ public class Ajax extends GQuery { settings.setDataString(dataString); settings.setContentType(contentType); } + + System.out.println(settings.getDataString()); if ("GET".equals(settings.getType()) && settings.getDataString() != null) { url += (url.contains("?") ? "&" : "?") + settings.getDataString(); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index 0433738b..91df6353 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -26,6 +26,7 @@ import com.google.gwt.user.server.Base64Utils; public class AjaxTransportJre implements AjaxTransport { private static String localDomain = null; + private static CookieManager cookieManager = CookieManager.getInstance(); public static void enableCORS(String domain) { localDomain = domain; @@ -95,6 +96,8 @@ public class AjaxTransportJre implements AjaxTransport { if (s.getUsername() != null && s.getPassword() != null) { c.setRequestProperty ("Authorization", "Basic " + Base64Utils.toBase64((s.getUsername() + ":" + s.getPassword()).getBytes())); } + System.err.println("SET COOK"); + cookieManager.setCookies(c); boolean isCORS = cors && localDomain != null && !s.getUrl().contains(localDomain); if (isCORS) { @@ -141,6 +144,7 @@ public class AjaxTransportJre implements AjaxTransport { if (isCORS && !localDomain.equals(c.getHeaderField("Access-Control-Allow-Origin"))) { code = 0; } + System.err.println(c.getResponseCode()); BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream())); String inputLine; @@ -150,6 +154,9 @@ public class AjaxTransportJre implements AjaxTransport { } in.close(); + cookieManager.storeCookies(c); + return new ResponseJre(code, c.getResponseMessage(), response.toString(), c.getHeaderFields()); } + } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java new file mode 100644 index 00000000..e33620b6 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java @@ -0,0 +1,217 @@ +package com.google.gwt.query.vm; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * @author Ian Brown spam@hccp.org + * http://www.hccp.org/java-net-cookie-how-to.html + */ +public class CookieManager { + + private Map>> store = new HashMap>>(); + + private static final String SET_COOKIE = "Set-Cookie"; + private static final String COOKIE_VALUE_DELIMITER = ";"; + private static final String PATH = "path"; + private static final String EXPIRES = "expires"; + private static final String DATE_FORMAT = "EEE, dd-MMM-yyyy hh:mm:ss z"; + private static final String SET_COOKIE_SEPARATOR = "; "; + private static final String COOKIE = "Cookie"; + + private static final char NAME_VALUE_SEPARATOR = '='; + private static final char DOT = '.'; + + private DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);; + + private static CookieManager cookieManager = new CookieManager(); + + public static CookieManager getInstance() { + return cookieManager; + } + + public void removeDomainCookies(String domain) { + store.remove(domain); + } + + public void removeDomainCookie(String domain, String... cookies) { + Map> domainStore = store.get(domain); + if (domainStore != null) { + for (String cookie: cookies) { + domainStore.remove(cookie); + } + } + } + + public void setDomcainCookieProp(String host, String name, String prop, String value) { + String domain = getDomainFromHost(host); + Map> domainStore = store.get(domain); + if (domainStore == null) { + domainStore = new HashMap>(); + store.put(domain, domainStore); + } + Map cookie = domainStore.get(name); + if (cookie == null) { + cookie = new HashMap(); + domainStore.put(name, cookie); + } + if (value == null) { + cookie.remove(prop); + } else { + cookie.put(prop, value); + } + } + + /** + * Retrieves and stores cookies returned by the host on the other side of the the open + * java.net.URLConnection. + * + * The connection MUST have been opened using the connect() method or a IOException will be + * thrown. + * + * @param conn a java.net.URLConnection - must be open, or IOException will be thrown + * @throws java.io.IOException Thrown if conn is not open. + */ + public void storeCookies(URLConnection conn) throws IOException { + // let's determine the domain from where these cookies are being sent + String domain = getDomainFromHost(conn.getURL().getHost()); + + Map> domainStore; // this is where we will store cookies for this domain + + // now let's check the store to see if we have an entry for this domain + if (store.containsKey(domain)) { + // we do, so lets retrieve it from the store + domainStore = store.get(domain); + } else { + // we don't, so let's create it and put it in the store + domainStore = new HashMap>(); + store.put(domain, domainStore); + } + + // OK, now we are ready to get the cookies out of the URLConnection + + String headerName = null; + for (int i = 1; (headerName = conn.getHeaderFieldKey(i)) != null; i++) { + if (headerName.equalsIgnoreCase(SET_COOKIE)) { + Map cookie = new HashMap(); + StringTokenizer st = new StringTokenizer(conn.getHeaderField(i), COOKIE_VALUE_DELIMITER); + + // the specification dictates that the first name/value pair + // in the string is the cookie name and value, so let's handle + // them as a special case: + + if (st.hasMoreTokens()) { + String token = st.nextToken(); + String name = token.substring(0, token.indexOf(NAME_VALUE_SEPARATOR)); + String value = token.substring(token.indexOf(NAME_VALUE_SEPARATOR) + 1, token.length()); + domainStore.put(name, cookie); + cookie.put(name, value); + } + + while (st.hasMoreTokens()) { + String token = st.nextToken().toLowerCase(); + int idx = token.indexOf(NAME_VALUE_SEPARATOR); + if (idx > 0 && idx < token.length() -1) { + cookie.put(token.substring(0, idx).toLowerCase(), token.substring(idx + 1, token.length())); + } + } + } + } + } + + /** + * Prior to opening a URLConnection, calling this method will set all unexpired cookies that match + * the path or subpaths for thi underlying URL + * + * The connection MUST NOT have been opened method or an IOException will be thrown. + * + * @param conn a java.net.URLConnection - must NOT be open, or IOException will be thrown + * @throws java.io.IOException Thrown if conn has already been opened. + */ + public void setCookies(URLConnection conn) throws IOException { + + // let's determine the domain and path to retrieve the appropriate cookies + URL url = conn.getURL(); + String domain = getDomainFromHost(url.getHost()); + if (domain.equals("localhost")) { + domain = "linkedin.com"; + } + String path = url.getPath(); + + Map> domainStore = store.get(domain); + if (domainStore == null) + return; + StringBuffer cookieStringBuffer = new StringBuffer(); + + Iterator cookieNames = domainStore.keySet().iterator(); + while (cookieNames.hasNext()) { + String cookieName = cookieNames.next(); + Map cookie = domainStore.get(cookieName); + // check cookie to ensure path matches and cookie is not expired + // if all is cool, add cookie to header string + if (comparePaths((String) cookie.get(PATH), path) + && isNotExpired(cookie.get(EXPIRES))) { + cookieStringBuffer.append(cookieName); + cookieStringBuffer.append("="); + cookieStringBuffer.append(cookie.get(cookieName)); + if (cookieNames.hasNext()) + cookieStringBuffer.append(SET_COOKIE_SEPARATOR); + } + } + try { + conn.setRequestProperty(COOKIE, cookieStringBuffer.toString()); + System.err.println(">>> SET cookie: " + COOKIE + " " + cookieStringBuffer.toString()); + } catch (java.lang.IllegalStateException ise) { + IOException ioe = + new IOException( + "Illegal State! Cookies cannot be set on a URLConnection that is already connected. " + + "Only call setCookies(java.net.URLConnection) AFTER calling java.net.URLConnection.connect()."); + throw ioe; + } + } + + private String getDomainFromHost(String host) { + if (host.indexOf(DOT) != host.lastIndexOf(DOT)) { + return host.substring(host.indexOf(DOT) + 1); + } else { + return host; + } + } + + private boolean isNotExpired(String cookieExpires) { + if (cookieExpires == null) + return true; + Date now = new Date(); + try { + return (now.compareTo(dateFormat.parse(cookieExpires))) <= 0; + } catch (java.text.ParseException pe) { + pe.printStackTrace(); + return false; + } + } + + private boolean comparePaths(String cookiePath, String targetPath) { + if (cookiePath == null) { + return true; + } else if (cookiePath.equals("/")) { + return true; + } else if (targetPath.regionMatches(0, cookiePath, 0, cookiePath.length())) { + return true; + } else { + return false; + } + } + + public String toString() { + return store.toString(); + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index 05c2bff0..e40feca0 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -256,7 +256,7 @@ public class JsonFactoryJre implements JsonFactory { if (p != null) { ret += k + "=" + p.toString(); } else if (s != null) { - if (!s.isEmpty() && !"null".equalsIgnoreCase(s)) { + if (!"null".equalsIgnoreCase(s)) { ret += k + "=" + s; } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/ResponseJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/ResponseJre.java index 36aafd37..207484a9 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/ResponseJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/ResponseJre.java @@ -52,7 +52,11 @@ public class ResponseJre extends Response { return ret; } public String getHeadersAsString() { - return null; + String ret = ""; + for (Header h : getHeaders()) { + ret += h.getName() + ":" + h.getValue() + "\n"; + } + return ret; } public int getStatusCode() { return status; -- cgit v1.2.3 From 916030ed0dd8872a5467087140f45ac63b165c7d Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Tue, 21 Jan 2014 13:08:37 +0100 Subject: Return double always when getting numbers like JS --- .../src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index e40feca0..4a1b9c3c 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -105,6 +105,10 @@ public class JsonFactoryJre implements JsonFactory { ret = jsonFactory.create(clz, (JSONObject)ret); } } + // Javascript always returns a double + if (ret instanceof Number) { + ret = Double.valueOf(((Number) ret).doubleValue()); + } } } catch (JSONException e) { } -- cgit v1.2.3 From 8d34610fa2bfbd02ab623f73f5f30b2189bb04be Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Tue, 21 Jan 2014 13:09:16 +0100 Subject: support for urls when setting cookies --- .../java/com/google/gwt/query/client/plugins/ajax/Ajax.java | 2 -- .../main/java/com/google/gwt/query/vm/AjaxTransportJre.java | 5 +---- .../main/java/com/google/gwt/query/vm/CookieManager.java | 13 ++++++++++--- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index f516fc6a..5857de9b 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -212,8 +212,6 @@ public class Ajax extends GQuery { settings.setDataString(dataString); settings.setContentType(contentType); } - - System.out.println(settings.getDataString()); if ("GET".equals(settings.getType()) && settings.getDataString() != null) { url += (url.contains("?") ? "&" : "?") + settings.getDataString(); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index 91df6353..f1a73f9a 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -26,6 +26,7 @@ import com.google.gwt.user.server.Base64Utils; public class AjaxTransportJre implements AjaxTransport { private static String localDomain = null; + private static CookieManager cookieManager = CookieManager.getInstance(); public static void enableCORS(String domain) { @@ -96,7 +97,6 @@ public class AjaxTransportJre implements AjaxTransport { if (s.getUsername() != null && s.getPassword() != null) { c.setRequestProperty ("Authorization", "Basic " + Base64Utils.toBase64((s.getUsername() + ":" + s.getPassword()).getBytes())); } - System.err.println("SET COOK"); cookieManager.setCookies(c); boolean isCORS = cors && localDomain != null && !s.getUrl().contains(localDomain); @@ -144,7 +144,6 @@ public class AjaxTransportJre implements AjaxTransport { if (isCORS && !localDomain.equals(c.getHeaderField("Access-Control-Allow-Origin"))) { code = 0; } - System.err.println(c.getResponseCode()); BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream())); String inputLine; @@ -155,8 +154,6 @@ public class AjaxTransportJre implements AjaxTransport { in.close(); cookieManager.storeCookies(c); - return new ResponseJre(code, c.getResponseMessage(), response.toString(), c.getHeaderFields()); } - } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java index e33620b6..1f1241ba 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java @@ -3,7 +3,6 @@ package com.google.gwt.query.vm; import java.io.IOException; import java.net.URL; import java.net.URLConnection; -import java.net.URLEncoder; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; @@ -39,6 +38,10 @@ public class CookieManager { return cookieManager; } + public void clear() { + store.clear(); + } + public void removeDomainCookies(String domain) { store.remove(domain); } @@ -52,7 +55,11 @@ public class CookieManager { } } - public void setDomcainCookieProp(String host, String name, String prop, String value) { + public void setDomcainCookie(String host, String name, String value) { + setDomcainCookieProperty(host, name, name, value); + } + + public void setDomcainCookieProperty(String host, String name, String prop, String value) { String domain = getDomainFromHost(host); Map> domainStore = store.get(domain); if (domainStore == null) { @@ -169,7 +176,6 @@ public class CookieManager { } try { conn.setRequestProperty(COOKIE, cookieStringBuffer.toString()); - System.err.println(">>> SET cookie: " + COOKIE + " " + cookieStringBuffer.toString()); } catch (java.lang.IllegalStateException ise) { IOException ioe = new IOException( @@ -180,6 +186,7 @@ public class CookieManager { } private String getDomainFromHost(String host) { + host = host.toLowerCase().replaceFirst("https?://", "").replaceAll("[/?:].*$", ""); if (host.indexOf(DOT) != host.lastIndexOf(DOT)) { return host.substring(host.indexOf(DOT) + 1); } else { -- cgit v1.2.3 From ab79a6dbefbafaa8a12d6976a467fabec26ecd2f Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Wed, 22 Jan 2014 07:05:36 +0000 Subject: remove println --- .../src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index f516fc6a..8f0846c6 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -168,7 +168,7 @@ public class Ajax extends GQuery { }, new Function() { public Object f(Object...args) { Throwable exception = arguments(0); - Request request = arguments(1); + Request request = getArgument(1, Request.class); String msg = String.valueOf(exception); return new Object[]{null, msg, request, null, exception}; } @@ -212,8 +212,6 @@ public class Ajax extends GQuery { settings.setDataString(dataString); settings.setContentType(contentType); } - - System.out.println(settings.getDataString()); if ("GET".equals(settings.getType()) && settings.getDataString() != null) { url += (url.contains("?") ? "&" : "?") + settings.getDataString(); -- cgit v1.2.3 From 80cc7d50d8958a547c4c9c60227295864cb761c4 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Wed, 22 Jan 2014 07:08:26 +0000 Subject: utility method to debug output request --- .../com/google/gwt/query/vm/AjaxTransportJre.java | 36 +++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index 91df6353..015dcc94 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -26,14 +26,17 @@ import com.google.gwt.user.server.Base64Utils; public class AjaxTransportJre implements AjaxTransport { private static String localDomain = null; + private static CookieManager cookieManager = CookieManager.getInstance(); + + public static boolean debugOutput = false; public static void enableCORS(String domain) { localDomain = domain; System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); } - private final String USER_AGENT = "Mozilla/5.0"; + private final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:26.0) Gecko/20100101 Firefox/26.0"; private final String jsonpCbRexp = "(?ms)^.*jre_callback\\((.*)\\).*$"; public Promise getJsonP(final Settings settings) { @@ -79,6 +82,7 @@ public class AjaxTransportJre implements AjaxTransport { dfd.resolve(response, null); } } catch (Exception e) { + e.printStackTrace(); dfd.reject(e, null); } } @@ -96,7 +100,6 @@ public class AjaxTransportJre implements AjaxTransport { if (s.getUsername() != null && s.getPassword() != null) { c.setRequestProperty ("Authorization", "Basic " + Base64Utils.toBase64((s.getUsername() + ":" + s.getPassword()).getBytes())); } - System.err.println("SET COOK"); cookieManager.setCookies(c); boolean isCORS = cors && localDomain != null && !s.getUrl().contains(localDomain); @@ -133,18 +136,22 @@ public class AjaxTransportJre implements AjaxTransport { if (s.getType().matches("POST|PUT")) { c.setRequestProperty("Content-Type", s.getContentType()); + + debugRequest(c, s.getDataString()); + c.setDoOutput(true); DataOutputStream wr = new DataOutputStream(c.getOutputStream()); wr.writeBytes(s.getDataString()); wr.flush(); wr.close(); + } else { + debugRequest(c, null); } int code = c.getResponseCode(); if (isCORS && !localDomain.equals(c.getHeaderField("Access-Control-Allow-Origin"))) { code = 0; } - System.err.println(c.getResponseCode()); BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream())); String inputLine; @@ -155,8 +162,29 @@ public class AjaxTransportJre implements AjaxTransport { in.close(); cookieManager.storeCookies(c); - return new ResponseJre(code, c.getResponseMessage(), response.toString(), c.getHeaderFields()); } + private void debugRequest(HttpURLConnection c, String payload) { + if (debugOutput) { + System.out.println(c.getRequestMethod() + " " + c.getURL().getPath()); + for (String s : c.getRequestProperties().keySet()) { + String v = c.getRequestProperties().get(s).get(0); + if ("Cookie".equals(s)) { + System.out.println(s + ":"); + for (String y : v.split("; ")) { + System.out.println(" " + y); + } + } else { + System.out.println(s + ": " + v); + } + } + if (payload != null) { + for (String y : payload.split("&")) { + System.out.println(" " + y); + } + } + System.out.println(""); + } + } } -- cgit v1.2.3 From 842f365194d3861c71aa3494a1ba6b521391b0e7 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Wed, 22 Jan 2014 07:09:01 +0000 Subject: Support passing full url to cookie manager --- .../main/java/com/google/gwt/query/vm/CookieManager.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java index e33620b6..1f1241ba 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/CookieManager.java @@ -3,7 +3,6 @@ package com.google.gwt.query.vm; import java.io.IOException; import java.net.URL; import java.net.URLConnection; -import java.net.URLEncoder; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; @@ -39,6 +38,10 @@ public class CookieManager { return cookieManager; } + public void clear() { + store.clear(); + } + public void removeDomainCookies(String domain) { store.remove(domain); } @@ -52,7 +55,11 @@ public class CookieManager { } } - public void setDomcainCookieProp(String host, String name, String prop, String value) { + public void setDomcainCookie(String host, String name, String value) { + setDomcainCookieProperty(host, name, name, value); + } + + public void setDomcainCookieProperty(String host, String name, String prop, String value) { String domain = getDomainFromHost(host); Map> domainStore = store.get(domain); if (domainStore == null) { @@ -169,7 +176,6 @@ public class CookieManager { } try { conn.setRequestProperty(COOKIE, cookieStringBuffer.toString()); - System.err.println(">>> SET cookie: " + COOKIE + " " + cookieStringBuffer.toString()); } catch (java.lang.IllegalStateException ise) { IOException ioe = new IOException( @@ -180,6 +186,7 @@ public class CookieManager { } private String getDomainFromHost(String host) { + host = host.toLowerCase().replaceFirst("https?://", "").replaceAll("[/?:].*$", ""); if (host.indexOf(DOT) != host.lastIndexOf(DOT)) { return host.substring(host.indexOf(DOT) + 1); } else { -- cgit v1.2.3 From f4b20ca9e43b603979fbe89d73d8c662dbd01af2 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Wed, 22 Jan 2014 21:31:58 +0100 Subject: adding some configuration flags --- .../com/google/gwt/query/vm/AjaxTransportJre.java | 30 +++++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index 015dcc94..166fa3b4 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -29,13 +29,27 @@ public class AjaxTransportJre implements AjaxTransport { private static CookieManager cookieManager = CookieManager.getInstance(); - public static boolean debugOutput = false; + private static boolean debugOutput = false; + + private static boolean followRedirections = true; public static void enableCORS(String domain) { localDomain = domain; System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); } + public static void enableDebug(boolean b) { + debugOutput = b; + } + + public static void enableCookies(boolean b) { + cookieManager = b ? CookieManager.getInstance() : null; + } + + public static void enableRedirections(boolean b) { + followRedirections = b; + } + private final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:26.0) Gecko/20100101 Firefox/26.0"; private final String jsonpCbRexp = "(?ms)^.*jre_callback\\((.*)\\).*$"; @@ -95,12 +109,17 @@ public class AjaxTransportJre implements AjaxTransport { URL u = new URL(url); HttpURLConnection c = (HttpURLConnection) u.openConnection(); + + c.setInstanceFollowRedirects(followRedirections); + c.setRequestMethod(s.getType()); c.setRequestProperty("User-Agent", USER_AGENT); if (s.getUsername() != null && s.getPassword() != null) { c.setRequestProperty ("Authorization", "Basic " + Base64Utils.toBase64((s.getUsername() + ":" + s.getPassword()).getBytes())); } - cookieManager.setCookies(c); + if (cookieManager != null) { + cookieManager.setCookies(c); + } boolean isCORS = cors && localDomain != null && !s.getUrl().contains(localDomain); if (isCORS) { @@ -160,8 +179,11 @@ public class AjaxTransportJre implements AjaxTransport { response.append(inputLine + "\n"); } in.close(); - - cookieManager.storeCookies(c); + + if (cookieManager != null) { + cookieManager.storeCookies(c); + } + return new ResponseJre(code, c.getResponseMessage(), response.toString(), c.getHeaderFields()); } -- cgit v1.2.3 From 6df7c6a8f2461d918d305c883985023d9d05b43d Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Mon, 27 Jan 2014 11:40:32 +0100 Subject: Dont set credentials by default for ajax requests. Fixes issue #261 --- .../google/gwt/query/client/plugins/ajax/Ajax.java | 2 + .../client/plugins/deferred/PromiseReqBuilder.java | 2 +- .../com/google/gwt/query/vm/AjaxTransportJre.java | 9 ++++- .../google/gwt/query/client/ajax/AjaxTestJre.java | 1 + .../google/gwt/query/client/ajax/AjaxTests.java | 46 +++++++++++++++++++++- .../gwt/query/servlet/GQAjaxTestServlet.java | 4 +- 6 files changed, 59 insertions(+), 5 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index 8f0846c6..566ab14d 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -63,6 +63,7 @@ public class Ajax extends GQuery { String getType(); String getUrl(); String getUsername(); + boolean getWithCredentials(); Settings setContentType(String t); Settings setContext(Element e); Settings setData(Object p); @@ -76,6 +77,7 @@ public class Ajax extends GQuery { Settings setType(String t); Settings setUrl(String u); Settings setUsername(String u); + Settings setWithCredentials(boolean b); } public static final Class Ajax = registerPlugin(Ajax.class, new Plugin() { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java index 79d3fa8d..1d1bf013 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java @@ -120,7 +120,7 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal // Using gQuery to set credentials since this method was added in 2.5.1 // xmlHttpRequest.setWithCredentials(true); - JsUtils.prop(xmlHttpRequest, "withCredentials", true); + JsUtils.prop(xmlHttpRequest, "withCredentials", settings.getWithCredentials()); final Request request = createRequestVltr(xmlHttpRequest, settings.getTimeout(), this); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index 166fa3b4..9da7f420 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -168,8 +168,13 @@ public class AjaxTransportJre implements AjaxTransport { } int code = c.getResponseCode(); - if (isCORS && !localDomain.equals(c.getHeaderField("Access-Control-Allow-Origin"))) { - code = 0; + if (isCORS) { + if (!localDomain.equals(c.getHeaderField("Access-Control-Allow-Origin"))) { + code = 0; + } + if (s.getWithCredentials() && c.getHeaderField("Access-Control-Allow-Credentials") == null) { + code = 0; + } } BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream())); diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java index abe00e30..1167651d 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java @@ -49,6 +49,7 @@ public class AjaxTestJre extends AjaxTests { echoUrl = localDomain + "/" + servletPath; echoUrlCORS = corsDomain + "/" + servletPath + "?cors=true"; + startWebServer(port); } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java index f6a064c5..ee3005c9 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java @@ -15,6 +15,8 @@ */ package com.google.gwt.query.client.ajax; +import junit.framework.Assert; + import com.google.gwt.http.client.Response; import com.google.gwt.junit.DoNotRunWith; import com.google.gwt.junit.Platform; @@ -119,7 +121,49 @@ public abstract class AjaxTests extends GWTTestCase { .setData(jsonGET) .setDataType("json"); - performAjaxJsonTest_CORS(s); + performAjaxJsonTest_CORS(s) + .done(new Function() { + public void f() { + Response r = arguments(3); + Assert.assertNotNull(r.getHeader("Access-Control-Allow-Origin")); + Assert.assertNull(r.getHeader("Access-Control-Allow-Credentials")); + } + }); + } + + @DoNotRunWith(Platform.HtmlUnitBug) + public void testAjaxJsonGet_CORS_WithCredentials_Supported() { + Settings s = Ajax.createSettings() + .setType("get") + // Enable credentials in servlet + .setUrl(echoUrlCORS + "&credentials=true") + .setData(jsonGET) + .setDataType("json") + .setWithCredentials(true); + + performAjaxJsonTest_CORS(s) + .done(new Function() { + public void f() { + Response r = arguments(3); + Assert.assertNotNull(r.getHeader("Access-Control-Allow-Origin")); + Assert.assertNotNull(r.getHeader("Access-Control-Allow-Credentials")); + } + }); + } + + @DoNotRunWith(Platform.HtmlUnitBug) + public void testAjaxJsonGet_CORS_WithCredentials_Unsupported() { + Settings s = Ajax.createSettings() + .setType("get") + // Disable credentials in servlet + .setUrl(echoUrlCORS) + .setData(jsonGET) + .setDataType("json") + .setWithCredentials(true); + + Ajax.ajax(s) + .fail(finishFunction) + .done(failFunction); } public void testAjaxGetJsonP() { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java b/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java index 5152de4c..b00d2469 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/servlet/GQAjaxTestServlet.java @@ -61,7 +61,9 @@ public class GQAjaxTestServlet extends HttpServlet { String origin = req.getHeader("Origin"); if ("true".equals(req.getParameter("cors")) && origin != null) { resp.addHeader("Access-Control-Allow-Origin", origin); - resp.addHeader("Access-Control-Allow-Credentials", "true"); + if ("true".equals(req.getParameter("credentials"))) { + resp.addHeader("Access-Control-Allow-Credentials", "true"); + } String method = req.getHeader("Access-Control-Request-Method"); if (method != null) { resp.addHeader("Access-Control-Allow-Methods", method); -- cgit v1.2.3 From 8a0328a2d3edc5319aa4206d2061356a48f35e72 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Mon, 27 Jan 2014 12:30:33 +0100 Subject: Refactoring using more meaningful names for properties interface and getter --- .../java/com/google/gwt/query/client/Binder.java | 82 ---------------------- .../main/java/com/google/gwt/query/client/GQ.java | 8 +-- .../com/google/gwt/query/client/IsProperties.java | 82 ++++++++++++++++++++++ .../com/google/gwt/query/client/Properties.java | 10 +-- .../gwt/query/client/builders/JsonBuilder.java | 4 +- .../gwt/query/client/builders/JsonBuilderBase.java | 12 ++-- .../gwt/query/client/builders/JsonFactory.java | 6 +- .../google/gwt/query/client/plugins/ajax/Ajax.java | 46 ++++++------ .../client/plugins/deferred/PromiseReqBuilder.java | 10 +-- .../gwt/query/rebind/JsonBuilderGenerator.java | 4 +- .../com/google/gwt/query/vm/AjaxTransportJre.java | 4 +- .../com/google/gwt/query/vm/JsonFactoryJre.java | 24 +++---- .../google/gwt/query/client/ajax/AjaxTests.java | 10 +-- 13 files changed, 151 insertions(+), 151 deletions(-) delete mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java deleted file mode 100644 index 852a3c41..00000000 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Binder.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013, The gwtquery team. - * - * 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.query.client; - -import com.google.gwt.query.client.builders.JsonBuilder; - - -/** - * Interface using for Data Binders valid for JVM and JS. - */ -public interface Binder { - /** - * load a properties object. - */ - T load(Object prp); - - /** - * parses a json string and loads the resulting properties object. - */ - T parse(String json); - - /** - * Returns the underlying object, normally a Properties jso in client - * and a Json implementation in JVM. - */ - T getBound(); - - /** - * Return the Object with the given key. - */ - T get(Object key); - - /** - * Set an Object with the given key. - */ - T set(Object key, Object val); - - /** - * return a list of field names. - */ - String[] getFieldNames(); - - /** - * return a json string which represents the object. - * Example {"name":"manolo","surname":"carrasco"} - */ - String toJson(); - - /** - * return a string which represents the object with an alias for the - * className useful for serialization. - * - * Example {"user":{"name":"manolo","surname":"carrasco"}} - */ - String toJsonWithName(); - - /** - * return a string which represents the object in a queryString format. - */ - String toQueryString(); - - /** - * return the name for this type - */ - String getJsonName(); - - - T as (Class clz); -} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java index 27dbbe78..ea2fcce3 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java @@ -38,17 +38,17 @@ public abstract class GQ { return ret; } - public static T create(Class clz, Binder obj) { + public static T create(Class clz, IsProperties obj) { T ret = create(clz); - ret.load(obj.getBound()); + ret.load(obj.getDataImpl()); return ret; } - public static Binder create(String s) { + public static IsProperties create(String s) { return getFactory().create(s); } - public static Binder create() { + public static IsProperties create() { return getFactory().create(); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java new file mode 100644 index 00000000..f973afb0 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java @@ -0,0 +1,82 @@ +/* + * Copyright 2013, The gwtquery team. + * + * 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.query.client; + +import com.google.gwt.query.client.builders.JsonBuilder; + + +/** + * Interface using for Data Binders valid for JVM and JS. + */ +public interface IsProperties { + /** + * load a properties object. + */ + T load(Object prp); + + /** + * parses a json string and loads the resulting properties object. + */ + T parse(String json); + + /** + * Returns the underlying object, normally a Properties jso in client + * and a Json implementation in the JVM. + */ + T getDataImpl(); + + /** + * Return the Object with the given key. + */ + T get(Object key); + + /** + * Set an Object with the given key. + */ + T set(Object key, Object val); + + /** + * return a list of field names. + */ + String[] getFieldNames(); + + /** + * return a json string which represents the object. + * Example {"name":"manolo","surname":"carrasco"} + */ + String toJson(); + + /** + * return a string which represents the object with an alias for the + * className useful for serialization. + * + * Example {"user":{"name":"manolo","surname":"carrasco"}} + */ + String toJsonWithName(); + + /** + * return a string which represents the object in a queryString format. + */ + String toQueryString(); + + /** + * return the name for this type + */ + String getJsonName(); + + + T as (Class clz); +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java index d24a7f98..ce703aed 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java @@ -25,7 +25,7 @@ import com.google.gwt.query.client.js.JsUtils; /** * JSO for accessing Javascript objective literals used by GwtQuery functions. */ -public class Properties extends JavaScriptObject implements Binder { +public class Properties extends JavaScriptObject implements IsProperties { public static Properties create() { return JsCache.create().cast(); @@ -202,15 +202,15 @@ public class Properties extends JavaScriptObject implements Binder { return c().length() == 0; } - public final J load(Object prp) { + public final J load(Object prp) { c().clear(); if (prp instanceof JsCache) { c().copy((JsCache)prp); } - return getBound(); + return getDataImpl(); } - public final J parse(String json) { + public final J parse(String json) { return load(JsUtils.parseJSON(json)); } @@ -227,7 +227,7 @@ public class Properties extends JavaScriptObject implements Binder { } @SuppressWarnings("unchecked") - public final J getBound() { + public final J getDataImpl() { return (J)this; } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java index 6e6d6f3a..b5f30451 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilder.java @@ -15,13 +15,13 @@ */ package com.google.gwt.query.client.builders; -import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.IsProperties; /** * Tagging interface used to generate JsonBuilder classes. */ -public interface JsonBuilder extends Binder { +public interface JsonBuilder extends IsProperties { /** * parses a json string and loads the resulting properties object, diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index cfa77296..8ccc9e75 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java @@ -17,7 +17,7 @@ package com.google.gwt.query.client.builders; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; -import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.IsProperties; import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.js.JsObjectArray; import com.google.gwt.query.client.js.JsUtils; @@ -55,7 +55,7 @@ public abstract class JsonBuilderBase> implements J if (r.length > 0 && r[0] instanceof JsonBuilder) { JsArray a = JavaScriptObject.createArray().cast(); for (T o : r) { - a.push(((JsonBuilder)o).getBound()); + a.push(((JsonBuilder)o).getDataImpl()); } p.set(n, a); } else { @@ -114,7 +114,7 @@ public abstract class JsonBuilderBase> implements J @SuppressWarnings("unchecked") @Override - public Properties getBound() { + public Properties getDataImpl() { return p; } @@ -123,9 +123,9 @@ public abstract class JsonBuilderBase> implements J } @SuppressWarnings("unchecked") - public T set(Object key, Object val) { - if (val instanceof Binder) { - p.set(key, ((Binder)val).getBound()); + public T set(Object key, Object val) { + if (val instanceof IsProperties) { + p.set(key, ((IsProperties)val).getDataImpl()); } else { p.set(key, val); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java index 4bc57c9c..847fcfbd 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonFactory.java @@ -1,9 +1,9 @@ package com.google.gwt.query.client.builders; -import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.IsProperties; public interface JsonFactory { T create(Class clz); - Binder create(String s); - Binder create(); + IsProperties create(String s); + IsProperties create(); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java index 566ab14d..7b472ba5 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java @@ -6,7 +6,7 @@ import com.google.gwt.core.client.ScriptInjector; import com.google.gwt.dom.client.Element; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.Response; -import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.IsProperties; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQ; import com.google.gwt.query.client.GQuery; @@ -52,11 +52,11 @@ public class Ajax extends GQuery { public interface Settings extends JsonBuilder { String getContentType(); Element getContext(); - Binder getData(); + IsProperties getData(); String getDataString(); String getDataType(); Function getError(); - Binder getHeaders(); + IsProperties getHeaders(); String getPassword(); Function getSuccess(); int getTimeout(); @@ -70,7 +70,7 @@ public class Ajax extends GQuery { Settings setDataString(String d); Settings setDataType(String t); Settings setError(Function f); - Settings setHeaders(Binder p); + Settings setHeaders(IsProperties p); Settings setPassword(String p); Settings setSuccess(Function f); Settings setTimeout(int t); @@ -86,7 +86,7 @@ public class Ajax extends GQuery { } }); - public static Promise ajax(Binder p) { + public static Promise ajax(IsProperties p) { Settings s = createSettings(); s.load(p); return ajax(s); @@ -198,10 +198,10 @@ public class Ajax extends GQuery { } settings.setType(type); - Binder data = settings.getData(); + IsProperties data = settings.getData(); if (data != null) { String dataString = null, contentType = null; - if (data.getBound() instanceof JavaScriptObject && JsUtils.isFormData(data.getBound())) { + if (data.getDataImpl() instanceof JavaScriptObject && JsUtils.isFormData(data.getDataImpl())) { dataString = null; contentType = FormPanel.ENCODING_URLENCODED; } else if (settings.getType().matches("(POST|PUT)") && "json".equalsIgnoreCase(settings.getDataType())) { @@ -233,7 +233,7 @@ public class Ajax extends GQuery { return ajax(s); } - public static Promise ajax(String url, Binder p) { + public static Promise ajax(String url, IsProperties p) { Settings s = createSettings(); s.load(p); s.setUrl(url); @@ -255,9 +255,9 @@ public class Ajax extends GQuery { return s; } - public static Settings createSettings(Binder p) { + public static Settings createSettings(IsProperties p) { Settings s = GQ.create(Settings.class); - s.load(p.getBound()); + s.load(p.getDataImpl()); return s; } @@ -265,11 +265,11 @@ public class Ajax extends GQuery { return get(url, null); } - public static Promise get(String url, Binder data) { - return get(url, (Binder)data, null); + public static Promise get(String url, IsProperties data) { + return get(url, (IsProperties)data, null); } - public static Promise get(String url, Binder data, Function onSuccess) { + public static Promise get(String url, IsProperties data, Function onSuccess) { Settings s = createSettings(); s.setUrl(url); s.setDataType("txt"); @@ -279,11 +279,11 @@ public class Ajax extends GQuery { return ajax(s); } - public static Promise getJSON(String url, Binder data) { + public static Promise getJSON(String url, IsProperties data) { return getJSON(url, data, null); } - public static Promise getJSON(String url, Binder data, Function onSuccess) { + public static Promise getJSON(String url, IsProperties data, Function onSuccess) { Settings s = createSettings(); s.setUrl(url); s.setDataType("json"); @@ -297,11 +297,11 @@ public class Ajax extends GQuery { return getJSONP(url, null); } - public static Promise getJSONP(String url, Binder data) { - return getJSONP(url, (Binder)data, null); + public static Promise getJSONP(String url, IsProperties data) { + return getJSONP(url, (IsProperties)data, null); } - public static Promise getJSONP(String url, Binder data, Function onSuccess) { + public static Promise getJSONP(String url, IsProperties data, Function onSuccess) { Settings s = createSettings(); s.setUrl(url); s.setDataType("jsonp"); @@ -354,11 +354,11 @@ public class Ajax extends GQuery { ); } - public static Promise post(String url, Binder data) { - return post(url, (Binder)data, null); + public static Promise post(String url, IsProperties data) { + return post(url, (IsProperties)data, null); } - public static Promise post(String url, Binder data, final Function onSuccess) { + public static Promise post(String url, IsProperties data, final Function onSuccess) { Settings s = createSettings(); s.setUrl(url); s.setDataType("txt"); @@ -372,11 +372,11 @@ public class Ajax extends GQuery { super(gq); } - public Ajax load(String url, Binder data) { + public Ajax load(String url, IsProperties data) { return load(url, data); } - public Ajax load(String url, Binder data, final Function onSuccess) { + public Ajax load(String url, IsProperties data, final Function onSuccess) { Settings s = createSettings(); final String filter = url.contains(" ") ? url.replaceFirst("^[^\\s]+\\s+", "") : ""; s.setUrl(url.replaceAll("\\s+.+$", "")); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java index 4aec8a37..41f32b37 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java @@ -21,7 +21,7 @@ import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.RequestPermissionException; import com.google.gwt.http.client.Response; -import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.IsProperties; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.js.JsCache; import com.google.gwt.query.client.js.JsUtils; @@ -66,9 +66,9 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal public PromiseReqBuilder(Settings settings) { String httpMethod = settings.getType(); String url = settings.getUrl(); - Binder data = settings.getData(); + IsProperties data = settings.getData(); String ctype = settings.getContentType(); - Boolean isFormData = data != null && data.getBound() instanceof JavaScriptObject && JsUtils.isFormData(data.getBound()); + Boolean isFormData = data != null && data.getDataImpl() instanceof JavaScriptObject && JsUtils.isFormData(data.getDataImpl()); XMLHttpRequest xmlHttpRequest = XMLHttpRequest.create(); try { @@ -107,7 +107,7 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal } })); - Binder headers = settings.getHeaders(); + IsProperties headers = settings.getHeaders(); if (headers != null) { for (String headerKey : headers.getFieldNames()) { xmlHttpRequest.setRequestHeader(headerKey, String.valueOf(headers.get(headerKey))); @@ -134,7 +134,7 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal }); try { - JsUtils.runJavascriptFunction(xmlHttpRequest, "send", isFormData ? data.getBound() : settings.getDataString()); + JsUtils.runJavascriptFunction(xmlHttpRequest, "send", isFormData ? data.getDataImpl() : settings.getDataString()); } catch (JavaScriptException e) { onError(null, e); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index 3fc7868c..729f3a46 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -38,7 +38,7 @@ import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.Properties; -import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.IsProperties; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.JsonBuilderBase; import com.google.gwt.query.client.builders.JsonFactory; @@ -84,7 +84,7 @@ public class JsonBuilderGenerator extends Generator { JClassType clazz = oracle.findType(requestedClass); jsonBuilderType = oracle.findType(JsonBuilder.class.getName()); - settingsType = oracle.findType(Binder.class.getName()); + settingsType = oracle.findType(IsProperties.class.getName()); stringType = oracle.findType(String.class.getName()); jsType = oracle.findType(JavaScriptObject.class.getName()); listType = oracle.findType(List.class.getName()); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java index 9da7f420..d6f2fcdb 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/AjaxTransportJre.java @@ -10,7 +10,7 @@ import java.net.URL; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; -import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.IsProperties; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQ; import com.google.gwt.query.client.GQuery; @@ -146,7 +146,7 @@ public class AjaxTransportJre implements AjaxTransport { c.setReadTimeout(s.getTimeout()); } - Binder headers = s.getHeaders(); + IsProperties headers = s.getHeaders(); if (headers != null) { for (String h : headers.getFieldNames()) { c.setRequestProperty(h, "" + headers.get(h)); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index 4a1b9c3c..80881507 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -14,7 +14,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.IsProperties; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQ; import com.google.gwt.query.client.Properties; @@ -101,7 +101,7 @@ public class JsonFactoryJre implements JsonFactory { if (ret instanceof JSONObject) { if (clz == Object.class) { ret = jsonFactory.createBinder((JSONObject)ret); - } else if (Binder.class.isAssignableFrom(clz) && !clz.isAssignableFrom(ret.getClass())) { + } else if (IsProperties.class.isAssignableFrom(clz) && !clz.isAssignableFrom(ret.getClass())) { ret = jsonFactory.create(clz, (JSONObject)ret); } } @@ -136,8 +136,8 @@ public class JsonFactoryJre implements JsonFactory { return obj != null ? obj.put(attr, o) : arr.put(o); } else if (o instanceof Date) { return obj != null ? obj.put(attr, ((Date) o).getTime()) : arr.put(((Date) o).getTime()); - } else if (o instanceof Binder) { - return obj != null ? obj.put(attr, ((Binder) o).getBound()) : arr.put(((Binder) o).getBound()); + } else if (o instanceof IsProperties) { + return obj != null ? obj.put(attr, ((IsProperties) o).getDataImpl()) : arr.put(((IsProperties) o).getDataImpl()); } else if (o.getClass().isArray() || o instanceof List) { Object[] arg; if (o.getClass().isArray()) { @@ -175,7 +175,7 @@ public class JsonFactoryJre implements JsonFactory { return jsonFactory.create(clz, jsonObject); } else if ("getJsonName".equals(mname)) { return JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass())); - } else if (mname.matches("getProperties|getBound")) { + } else if (mname.matches("getProperties|getDataImpl")) { return jsonObject; } else if (largs > 0 && ("parse".equals(mname) || "load".equals(mname))) { jsonObject = new JSONObject(String.valueOf(args[0])); @@ -282,25 +282,25 @@ public class JsonFactoryJre implements JsonFactory { return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] {clz}, handler); } - public Binder createBinder() { + public IsProperties createBinder() { InvocationHandler handler = new JsonBuilderHandler(); - return (Binder)Proxy.newProxyInstance(Binder.class.getClassLoader(), new Class[] {Binder.class}, handler); + return (IsProperties)Proxy.newProxyInstance(IsProperties.class.getClassLoader(), new Class[] {IsProperties.class}, handler); } - public Binder createBinder(JSONObject jso) { + public IsProperties createBinder(JSONObject jso) { InvocationHandler handler = new JsonBuilderHandler(jso); - return (Binder)Proxy.newProxyInstance(Binder.class.getClassLoader(), new Class[] {Binder.class}, handler); + return (IsProperties)Proxy.newProxyInstance(IsProperties.class.getClassLoader(), new Class[] {IsProperties.class}, handler); } @Override - public Binder create(String s) { - Binder ret = createBinder(); + public IsProperties create(String s) { + IsProperties ret = createBinder(); ret.parse(Properties.wrapPropertiesString(s)); return ret; } @Override - public Binder create() { + public IsProperties create() { return createBinder(); } } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java index ee3005c9..f5d0cbf5 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTests.java @@ -21,7 +21,7 @@ import com.google.gwt.http.client.Response; import com.google.gwt.junit.DoNotRunWith; import com.google.gwt.junit.Platform; import com.google.gwt.junit.client.GWTTestCase; -import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.IsProperties; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQ; import com.google.gwt.query.client.Promise; @@ -34,7 +34,7 @@ import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; public abstract class AjaxTests extends GWTTestCase { protected String echoUrl, echoUrlCORS; - protected Binder json, jsonGET; + protected IsProperties json, jsonGET; protected String servletPath = "test.json"; private Function failFunction = new Function() { @@ -58,7 +58,7 @@ public abstract class AjaxTests extends GWTTestCase { delayTestFinish(5000); return Ajax.ajax(s) .done(new Function(){public void f() { - Binder p = arguments(0); + IsProperties p = arguments(0); assertEquals("abc", p.get("a")); finishTest(); }}) @@ -183,10 +183,10 @@ public abstract class AjaxTests extends GWTTestCase { Ajax.getJSONP("https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY") .done(new Function(){ public void f() { - Binder p = arguments(0); + IsProperties p = arguments(0); // It should return error since we do not use a valid key // {"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}} - assertEquals(400, p.get("error").get("code").intValue()); + assertEquals(400, p.get("error").get("code").intValue()); finishTest(); } }) -- cgit v1.2.3 From a59638d5c982c0336e08e3fa61d05afbfccfbba6 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Mon, 27 Jan 2014 13:18:48 +0100 Subject: update super and generator implementation with new refactored names --- .../main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java | 4 ++-- .../com/google/gwt/query/super/com/google/gwt/query/client/GQ.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index 729f3a46..270db704 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -322,12 +322,12 @@ public class JsonBuilderGenerator extends Generator { sw.println("return null;"); sw.outdent(); sw.println("}"); - sw.println("public Binder create(String s) {"); + sw.println("public " + IsProperties.class.getName() + " create(String s) {"); sw.indent(); sw.println("return " + Properties.class.getName() + ".create(s);"); sw.outdent(); sw.println("}"); - sw.println("public Binder create() {"); + sw.println("public " + IsProperties.class.getName() + " create() {"); sw.indent(); sw.println("return " + Properties.class.getName() + ".create();"); sw.outdent(); diff --git a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java index 732d2902..7f8fb42e 100644 --- a/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/super/com/google/gwt/query/super/com/google/gwt/query/client/GQ.java @@ -16,7 +16,7 @@ package com.google.gwt.query.client; import com.google.gwt.core.shared.GWT; -import com.google.gwt.query.client.Binder; +import com.google.gwt.query.client.IsProperties; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.JsonFactory; import com.google.gwt.query.client.plugins.ajax.AjaxTransportJs; @@ -40,11 +40,11 @@ public class GQ { return ret; } - public static Binder create(String s) { + public static IsProperties create(String s) { return getFactory().create(s); } - public static Binder create() { + public static IsProperties create() { return getFactory().create(); } -- cgit v1.2.3 From 0c1e6a3967c1667122c266c10822c6ee6925674d Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Mon, 27 Jan 2014 16:30:40 +0100 Subject: Update lazy interfaces --- extractInterface.pl | 1 + gwtquery-core/pom.xml | 8 -- .../com/google/gwt/query/client/LazyGQuery.java | 105 ++++++++++++++++++++- .../gwt/query/client/plugins/LazyEffects.java | 1 + .../gwt/query/client/plugins/LazyEvents.java | 3 + .../gwt/query/client/plugins/LazyWidgets.java | 1 + 6 files changed, 107 insertions(+), 12 deletions(-) (limited to 'gwtquery-core/src') diff --git a/extractInterface.pl b/extractInterface.pl index c0510ee8..0414e373 100644 --- a/extractInterface.pl +++ b/extractInterface.pl @@ -76,6 +76,7 @@ close(F); my $class = "public interface $oclass"; if ($lazy) { $class .= " extends LazyBase" if ($lazy); + $head .= "import com.google.gwt.query.client.GQuery.Offset;\n"; $head .= "import com.google.gwt.query.client.LazyBase;\n\n"; } diff --git a/gwtquery-core/pom.xml b/gwtquery-core/pom.xml index 6ccb811b..1514e2e5 100644 --- a/gwtquery-core/pom.xml +++ b/gwtquery-core/pom.xml @@ -18,14 +18,6 @@ 4.7 test - com.google.gwt gwt-user diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java index da25dba4..958ed2a8 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java @@ -12,23 +12,61 @@ * the License. */ package com.google.gwt.query.client; -import java.util.List; -import java.util.Map; - +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.JsArray; +import com.google.gwt.core.client.JsArrayMixed; +import com.google.gwt.core.client.JsArrayString; +import com.google.gwt.core.client.ScriptInjector; +import com.google.gwt.dom.client.BodyElement; +import com.google.gwt.dom.client.ButtonElement; +import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.InputElement; import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.NodeList; +import com.google.gwt.dom.client.OptionElement; +import com.google.gwt.dom.client.SelectElement; +import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.HasCssName; -import com.google.gwt.query.client.GQuery.Offset; +import com.google.gwt.dom.client.TextAreaElement; import com.google.gwt.query.client.css.CSS; import com.google.gwt.query.client.css.HasCssValue; import com.google.gwt.query.client.css.TakesCssValue; import com.google.gwt.query.client.css.TakesCssValue.CssSetter; +import com.google.gwt.query.client.impl.AttributeImpl; +import com.google.gwt.query.client.impl.DocumentStyleImpl; +import com.google.gwt.query.client.impl.SelectorEngine; +import com.google.gwt.query.client.js.JsCache; +import com.google.gwt.query.client.js.JsMap; import com.google.gwt.query.client.js.JsNamedArray; import com.google.gwt.query.client.js.JsNodeArray; +import com.google.gwt.query.client.js.JsObjectArray; +import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.query.client.plugins.Effects; +import com.google.gwt.query.client.plugins.Events; +import com.google.gwt.query.client.plugins.Plugin; +import com.google.gwt.query.client.plugins.Widgets; +import com.google.gwt.query.client.plugins.ajax.Ajax; +import com.google.gwt.query.client.plugins.ajax.Ajax.Settings; +import com.google.gwt.query.client.plugins.deferred.Deferred; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing; +import com.google.gwt.query.client.plugins.events.EventsListener; +import com.google.gwt.query.client.plugins.widgets.WidgetsUtils; +import com.google.gwt.regexp.shared.RegExp; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.EventListener; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.Widget; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import static com.google.gwt.query.client.plugins.QueuePlugin.Queue; +import com.google.gwt.query.client.GQuery.Offset; +import com.google.gwt.query.client.LazyBase; public interface LazyGQuery extends LazyBase{ @@ -705,6 +743,7 @@ public interface LazyGQuery extends LazyBase{ *

    *  $("div.main").delegate(".subMain", Event.ONCLICK | Event.ONDBLCLICK, new Function(){...});
    * 
+ * @deprecated use {@link #on(String, String, Function...)} */ LazyGQuery delegate(String selector, int eventbits, Function... handlers); @@ -743,6 +782,7 @@ public interface LazyGQuery extends LazyBase{ *
    *  $("div.main").delegate(".subMain", Event.ONCLICK | Event.ONDBLCLICK, new Function(){...});
    * 
+ * @deprecated use {@link #on(String, String, Object, Function...)} */ LazyGQuery delegate(String selector, int eventbits, Object data, Function... handlers); @@ -783,6 +823,7 @@ public interface LazyGQuery extends LazyBase{ * * * + * @deprecated use {@link #on(String, String, Function...)} */ LazyGQuery delegate(String selector, String eventType, Function... handlers); @@ -821,6 +862,7 @@ public interface LazyGQuery extends LazyBase{ * * * + * @deprecated use {@link #on(String, String, Object, Function...)} */ LazyGQuery delegate(String selector, String eventType, Object data, Function... handlers); @@ -860,6 +902,7 @@ public interface LazyGQuery extends LazyBase{ * Remove all event handlers previously attached using {@link #live(String, Function)}. In order * for this method to function correctly, the selector used with it must match exactly the * selector initially used with {@link #live(String, Function)} + * @deprecated use {@link #off(String, String)} instead */ LazyGQuery die(); @@ -867,6 +910,7 @@ public interface LazyGQuery extends LazyBase{ * Remove an event handlers previously attached using {@link #live(int, Function)} In order for * this method to function correctly, the selector used with it must match exactly the selector * initially used with {@link #live(int, Function)} + * @deprecated use {@link #off(String)} */ LazyGQuery die(int eventbits); @@ -1118,6 +1162,11 @@ public interface LazyGQuery extends LazyBase{ */ int index(Element element); + /** + * Return the position of the first matched element in relation with its sibblings. + */ + int index(); + /** * Returns the inner height of the first matched element, including padding but not the vertical * scrollbar height, border, or margin. @@ -1237,12 +1286,14 @@ public interface LazyGQuery extends LazyBase{ /** * Attach a handler for this event to all elements which match the current selector, now and in * the future. + * @deprecated use {@link #on(String, Function...)} */ LazyGQuery live(int eventbits, Function... funcs); /** * Attach a handler for this event to all elements which match the current selector, now and in * the future. + * @deprecated use {@link #on(String, Object, Function...)} */ LazyGQuery live(int eventbits, Object data, Function... funcs); @@ -1295,6 +1346,7 @@ public interface LazyGQuery extends LazyBase{ * descendant of myElement. * *

+ * @deprecated use {@link #on(String, Function...)} */ LazyGQuery live(String eventName, Function... funcs); @@ -1347,6 +1399,7 @@ public interface LazyGQuery extends LazyBase{ * descendant of myElement. * *

+ * @deprecated use {@link #on(String, Object, Function...)} */ LazyGQuery live(String eventName, Object data, Function... funcs); @@ -1554,6 +1607,46 @@ public interface LazyGQuery extends LazyBase{ */ LazyGQuery offsetParent(); + /** + * Attach an event handler function for one or more events to the selected elements. + */ + LazyGQuery on(String eventName, Function... funcs); + + /** + * Attach an event handler function for one or more events to the selected elements. + */ + LazyGQuery on(String eventName, Object data, Function... funcs); + + /** + * Attach an event handler function for one or more events to the selected elements. + */ + LazyGQuery on(String eventName, String selector, Function... funcs); + + /** + * Attach an event handler function for one or more events to the selected elements. + */ + LazyGQuery on(String eventName, String selector, Object data, Function... funcs); + + /** + * Remove all event handlers. + */ + LazyGQuery off(); + + /** + * Remove an event handler + */ + LazyGQuery off(String eventName); + + /** + * Remove an event handler + */ + LazyGQuery off(String eventName, Function f); + + /** + * Remove an event handler + */ + LazyGQuery off(String eventName, String selector); + /** * Binds a handler to a particular Event (like Event.ONCLICK) for each matched element. The * handler is executed only once for each element. @@ -2232,24 +2325,28 @@ public interface LazyGQuery extends LazyBase{ /** * Remove all event delegation that have been bound using * {@link #delegate(String, int, Function...)} {@link #live(int, Function...)} methods + * @deprecated use {@link #off()} */ LazyGQuery undelegate(); /** * Undelegate is a way of removing event handlers that have been bound using * {@link #delegate(String, int, Function...)} method + * @deprecated use {@link #off(String)} */ LazyGQuery undelegate(String selector); /** * Undelegate is a way of removing event handlers that have been bound using * {@link #delegate(String, int, Function...)} method + * @deprecated use {@link #off(String)} */ LazyGQuery undelegate(String selector, int eventBit); /** * Undelegate is a way of removing event handlers that have been bound using * {@link #delegate(String, int, Function...)} method + * @deprecated use {@link #off(String, String)} */ LazyGQuery undelegate(String selector, String eventName); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java index 2a921a4e..b59ebeb2 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java @@ -25,6 +25,7 @@ import com.google.gwt.query.client.plugins.effects.Fx; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve; import com.google.gwt.query.client.plugins.effects.TransitionsAnimation.TransitionsClipAnimation; +import com.google.gwt.query.client.GQuery.Offset; import com.google.gwt.query.client.LazyBase; public interface LazyEffects extends LazyBase{ diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java index c0689af6..1d84d8a6 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java @@ -23,6 +23,7 @@ import com.google.gwt.query.client.plugins.events.EventsListener; import com.google.gwt.query.client.plugins.events.EventsListener.SpecialEvent; import com.google.gwt.query.client.plugins.events.GqEvent; import com.google.gwt.user.client.Event; +import com.google.gwt.query.client.GQuery.Offset; import com.google.gwt.query.client.LazyBase; public interface LazyEvents extends LazyBase{ @@ -153,6 +154,8 @@ public interface LazyEvents extends LazyBase{ */ LazyEvents unbind(int eventbits); + LazyEvents off(); + /** * Removes all handlers, that matches the events bits and the namespace passed, from each element. * diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyWidgets.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyWidgets.java index 5fe7de8b..c678c8f1 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyWidgets.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyWidgets.java @@ -33,6 +33,7 @@ import com.google.gwt.user.client.ui.PasswordTextBox; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.query.client.GQuery.Offset; import com.google.gwt.query.client.LazyBase; public interface LazyWidgets extends LazyBase{ -- cgit v1.2.3 From 30352ce90c8bded13ad5129ac03f2c2a32949a21 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Moñino Date: Mon, 27 Jan 2014 21:02:58 +0000 Subject: javadoc in GQ class --- .../main/java/com/google/gwt/query/client/GQ.java | 54 +++++++++++++++++----- 1 file changed, 43 insertions(+), 11 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java index ea2fcce3..292321b8 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQ.java @@ -23,35 +23,58 @@ import com.google.gwt.query.client.plugins.ajax.AjaxTransportJs; import com.google.gwt.query.vm.AjaxTransportJre; import com.google.gwt.query.vm.JsonFactoryJre; +/** + * A set of useful methods for gQuery which can be run in browser or JVM. + */ public abstract class GQ { - private static JsonFactory jsonFactory; private static AjaxTransport ajaxTransport; + + private static JsonFactory jsonFactory; + + public static IsProperties create() { + return getFactory().create(); + } + /** + * Create an instance of a JsonBuilder object whose type is + */ public static T create(Class clz) { return getFactory().create(clz); } - public static T create(Class clz, String payload) { + /** + * Create an instance of a JsonBuilder object whose type is + * and set the the underlying properties object. + */ + public static T create(Class clz, IsProperties obj) { T ret = create(clz); - ret.load(payload); + ret.load(obj.getDataImpl()); return ret; } - - public static T create(Class clz, IsProperties obj) { + + /** + * Create an instance of a JsonBuilder object whose type is + * and load all its properties from a json string. + */ + public static T create(Class clz, String payload) { T ret = create(clz); - ret.load(obj.getDataImpl()); + ret.load(payload); return ret; } + /** + * Create an instance of IsProperties. Normally a Properties javascript + * object in client side, or a proxy object in the JVM + */ public static IsProperties create(String s) { return getFactory().create(s); } - - public static IsProperties create() { - return getFactory().create(); - } + /** + * Return the appropriate transport implementation depending on the runtime + * environment: browser or JVM + */ public static AjaxTransport getAjaxTransport() { if (ajaxTransport == null) { ajaxTransport = GWT.isClient() ? @@ -60,7 +83,7 @@ public abstract class GQ { } return ajaxTransport; } - + private static JsonFactory getFactory() { if (jsonFactory == null) { jsonFactory = GWT.isClient() ? @@ -69,4 +92,13 @@ public abstract class GQ { } return jsonFactory; } + + /** + * Change the default Ajax transport by a customized one, useful for + * testing purposes. + */ + public static void setAjaxTransport(AjaxTransport transport) { + ajaxTransport = transport; + } + } -- cgit v1.2.3 From 96705cf9e96e8e78771bfd4376cca90d00f4fbc8 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Sun, 2 Feb 2014 07:34:58 +0100 Subject: Changing script to generate lazy interfaces so as plugins could import any class defined in GQuery class without compilation errors. Adding missing javadoc for public interface method. Overloading method in Properties so as the user could set the serialization name in case --- extractInterface.pl | 2 +- .../src/main/java/com/google/gwt/query/client/IsProperties.java | 6 +++++- .../src/main/java/com/google/gwt/query/client/LazyGQuery.java | 2 +- .../src/main/java/com/google/gwt/query/client/Properties.java | 6 +++++- .../main/java/com/google/gwt/query/client/plugins/LazyEffects.java | 2 +- .../main/java/com/google/gwt/query/client/plugins/LazyEvents.java | 2 +- .../main/java/com/google/gwt/query/client/plugins/LazyWidgets.java | 2 +- 7 files changed, 15 insertions(+), 7 deletions(-) (limited to 'gwtquery-core/src') diff --git a/extractInterface.pl b/extractInterface.pl index 0414e373..c1b1e6b5 100644 --- a/extractInterface.pl +++ b/extractInterface.pl @@ -76,7 +76,7 @@ close(F); my $class = "public interface $oclass"; if ($lazy) { $class .= " extends LazyBase" if ($lazy); - $head .= "import com.google.gwt.query.client.GQuery.Offset;\n"; + $head .= "import com.google.gwt.query.client.GQuery.*;\n"; $head .= "import com.google.gwt.query.client.LazyBase;\n\n"; } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java index f973afb0..bcd79cdb 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java @@ -66,7 +66,7 @@ public interface IsProperties { * Example {"user":{"name":"manolo","surname":"carrasco"}} */ String toJsonWithName(); - + /** * return a string which represents the object in a queryString format. */ @@ -78,5 +78,9 @@ public interface IsProperties { String getJsonName(); + /** + * converts a JsonBuilder instance into another JsonBuilder type but + * preserving the underlying data object. + */ T as (Class clz); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java index 958ed2a8..804e533b 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java @@ -65,7 +65,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; import static com.google.gwt.query.client.plugins.QueuePlugin.Queue; -import com.google.gwt.query.client.GQuery.Offset; +import com.google.gwt.query.client.GQuery.*; import com.google.gwt.query.client.LazyBase; public interface LazyGQuery extends LazyBase{ diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java index ce703aed..ed39d4eb 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java @@ -223,7 +223,11 @@ public class Properties extends JavaScriptObject implements IsProperties { } public final String toJsonWithName() { - return "{\"properties\":{" + toJson() + "}"; + return toJsonWithName(getJsonName()); + } + + public final String toJsonWithName(String name) { + return "{\"" + name + "\":{" + toJson() + "}"; } @SuppressWarnings("unchecked") diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java index b59ebeb2..cf62be4f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java @@ -25,7 +25,7 @@ import com.google.gwt.query.client.plugins.effects.Fx; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve; import com.google.gwt.query.client.plugins.effects.TransitionsAnimation.TransitionsClipAnimation; -import com.google.gwt.query.client.GQuery.Offset; +import com.google.gwt.query.client.GQuery.*; import com.google.gwt.query.client.LazyBase; public interface LazyEffects extends LazyBase{ diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java index 1d84d8a6..37244237 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java @@ -23,7 +23,7 @@ import com.google.gwt.query.client.plugins.events.EventsListener; import com.google.gwt.query.client.plugins.events.EventsListener.SpecialEvent; import com.google.gwt.query.client.plugins.events.GqEvent; import com.google.gwt.user.client.Event; -import com.google.gwt.query.client.GQuery.Offset; +import com.google.gwt.query.client.GQuery.*; import com.google.gwt.query.client.LazyBase; public interface LazyEvents extends LazyBase{ diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyWidgets.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyWidgets.java index c678c8f1..8c40c293 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyWidgets.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyWidgets.java @@ -33,7 +33,7 @@ import com.google.gwt.user.client.ui.PasswordTextBox; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; -import com.google.gwt.query.client.GQuery.Offset; +import com.google.gwt.query.client.GQuery.*; import com.google.gwt.query.client.LazyBase; public interface LazyWidgets extends LazyBase{ -- cgit v1.2.3