*/
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;
public class Ajax extends GQuery {
public static interface AjaxTransport {
-
Promise getJsonP(Settings settings);
Promise getLoadScript(Settings settings);
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) {
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;
*/
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();
};
}
- 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);
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()) {
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();
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;
}
@SuppressWarnings("unchecked")
- private <T> Object jsonArrayToList(JSONArray j, Class<T> ctype, boolean isArray) throws Throwable {
+ private <T> Object jsonArrayToList(JSONArray j, Class<T> ctype, boolean isArray) {
List<T> l = new ArrayList<T>();
for (int i = 0; j != null && i < j.length() ; i++) {
l.add((T)getValue(j, i, null, null, ctype, null));
}
} 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;
}
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) {
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 extends Binder> T create(String s) {
Binder ret = createBinder();
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;
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").<Properties>cast().getInt("code"));
- finishTest();
- }
- }, null, 0);
- }
-
@DoNotRunWith({Platform.HtmlUnitLayout})
public void testJsonNonCallbackResponse() {
delayTestFinish(5000);
}
}, 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();
- }
- });
- }
-
}
*/
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() {
.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);
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.<Binder>get("error").<Number>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.<Binder>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
import java.util.HashMap;
import java.util.Map;
+import java.util.Random;
import javax.servlet.Servlet;
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<String, Class<? extends Servlet>> servlets = new HashMap<String, Class<? extends Servlet>>();
servlets.put("/" + servletPath, GQAjaxTestServlet.class);
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";
}
}
Thread.sleep(ms);
} catch (Exception e) {
}
+ System.out.println(name + "timeout");
+ return;
}
String data = "";