From: Manuel Carrasco Moñino Date: Mon, 18 Mar 2013 11:48:01 +0000 (+0100) Subject: Extract helper classes from the Deferred class, so as we dont get compilation errors... X-Git-Tag: release-1.4.0~57^2~8 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=34fe13bb0678d01ee7cb19fab2f22d3165be38ba;p=gwtquery.git Extract helper classes from the Deferred class, so as we dont get compilation errors if the project does not depend on RequestFactory. Move all Deferred stuff so its own namespace --- diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java index bdd1e799..36a6647f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java @@ -51,13 +51,13 @@ import com.google.gwt.query.client.js.JsNodeArray; import com.google.gwt.query.client.js.JsObjectArray; import com.google.gwt.query.client.js.JsRegexp; import com.google.gwt.query.client.js.JsUtils; -import com.google.gwt.query.client.plugins.Deferred; 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; 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 68d0a173..6b5113e2 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 @@ -48,13 +48,13 @@ import com.google.gwt.query.client.js.JsNodeArray; import com.google.gwt.query.client.js.JsObjectArray; import com.google.gwt.query.client.js.JsRegexp; import com.google.gwt.query.client.js.JsUtils; -import com.google.gwt.query.client.plugins.Deferred; 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; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Deferred.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Deferred.java deleted file mode 100644 index c868398c..00000000 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Deferred.java +++ /dev/null @@ -1,442 +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.plugins; - -import static com.google.gwt.query.client.Promise.PENDING; -import static com.google.gwt.query.client.Promise.REJECTED; -import static com.google.gwt.query.client.Promise.RESOLVED; - -import java.util.Set; - -import javax.validation.ConstraintViolation; - -import com.google.gwt.http.client.Request; -import com.google.gwt.http.client.RequestBuilder; -import com.google.gwt.http.client.RequestCallback; -import com.google.gwt.http.client.RequestException; -import com.google.gwt.http.client.Response; -import com.google.gwt.jsonp.client.JsonpRequestBuilder; -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.callbacks.Callbacks; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.google.web.bindery.requestfactory.shared.Receiver; -import com.google.web.bindery.requestfactory.shared.ServerFailure; - -/** - * Implementation of jQuery.Deferred for gwtquery. - */ -public class Deferred extends GQuery implements Promise.Deferred { - - /** - * Utility class used to create customized promises which can manipulate - * the associated deferred object. - *
-   *    Promise doSomething = new PromiseFunction() {
-   *      @Override
-   *      public void f(Deferred dfd) {
-   *        dfd.notify("hi");
-   *        dfd.resolve("done");
-   *      }
-   *    };
-   *    
-   *    doSomething.progress(new Function() {
-   *      public void f() {
-   *        String hi = arguments(0);
-   *      }
-   *    }).done(new Function() {
-   *      public void f() {
-   *        String done = arguments(0);
-   *      }
-   *    });
-   * 
- */ - public static abstract class PromiseFunction extends DeferredPromiseImpl { - public PromiseFunction() { - f(dfd); - } - - /** - * This function is called once when the promise is created and the - * new deferred is available. - */ - public abstract void f(Deferred dfd); - } - - /** - * Utility class used to create promises for RequestBuilder. - *
-   *        RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, "http://127.0.0.1:8888/whatever");
-   *        PromiseRequest gettingResponse = new PromiseReqBuilder(builder);
-   *        
-   *        gettingResponse.fail(new Function() {
-   *          public void f() {
-   *            Throwable exception = arguments(0);
-   *          }
-   *        }).done(new Function() {
-   *          public void f() {
-   *            Response response = arguments(0);
-   *          }
-   *        });
-   * 
- */ - public static class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCallback { - public PromiseReqBuilder(RequestBuilder builder) { - builder.setCallback(this); - try { - builder.send(); - } catch (RequestException e) { - onError(null, e); - } - } - - public void onError(Request request, Throwable exception) { - dfd.reject(exception, request); - } - - public void onResponseReceived(Request request, Response response) { - int status = response.getStatusCode(); - if (status <= 0 || status >= 400) { - String statusText = status <= 0 ? "Bad CORS" : response.getStatusText(); - onError(request, new RequestException("HTTP ERROR: " + status + " " + statusText + "\n" + response.getText())); - } else { - dfd.resolve(response, request); - } - } - } - - /** - * Utility class used to create promises for JsonpRequestBuilder. - *
-   *    Promise p = new PromiseJsonpReqBuilder(url, 4000);
-   *    
-   *    p.done(new Function() {
-   *      public void f() {
-   *        Properties p = arguments(0);
-   *      }
-   *    }).fail(new Function() {
-   *      public void f() {
-   *        Throwable error = arguments(0);
-   *      }
-   *    });
-   * 
- */ - public static class PromiseJsonpReqBuilder extends DeferredPromiseImpl { - public PromiseJsonpReqBuilder(String url) { - this(url, null, 0); - } - - public PromiseJsonpReqBuilder(String url, int timeout) { - this(url, null, timeout); - } - - public PromiseJsonpReqBuilder(String url, String callbackParam, int timeout) { - JsonpRequestBuilder builder = new JsonpRequestBuilder(); - if (timeout > 0) { - builder.setTimeout(timeout); - } - if (callbackParam != null) { - builder.setCallbackParam(callbackParam); - } - send(builder, url, new AsyncCallback() { - public void onFailure(Throwable caught) { - dfd.reject(caught); - } - - public void onSuccess(Object result) { - dfd.resolve(result); - } - }); - } - - // Using jsni because method send in JsonpRequestBuilder is private - private final native void send(JsonpRequestBuilder bld, String url, AsyncCallback cb) /*-{ - bld.@com.google.gwt.jsonp.client.JsonpRequestBuilder::send(Ljava/lang/String;Lcom/google/gwt/user/client/rpc/AsyncCallback;Z)(url,cb,false); - }-*/; - } - - /** - * Utility class used to create promises for RequestFactory services. - *
-   *    Request req1 = loginFact.api().login(null, null);
-   *    Request req2 = srvFact.api().getCurrentUser();
-   *    
-   *    Promise requestingAll = Deferred.when(new PromiseRF(req1), new PromiseRF(req2);
-   *    
-   *    requestingAll.done(new Function() {
-   *        public void f() {
-   *          SessionProxy session = arguments(0, 0);
-   *          UserProxy user = arguments(1, 0);
-   *        }
-   *      })
-   *      .fail(new Function() {
-   *        public void f() {
-   *          ServerFailure failure = arguments(0);
-   *        }
-   *      }); 
-   * 
- */ - public static class PromiseRF extends DeferredPromiseImpl { - public PromiseRF(com.google.web.bindery.requestfactory.shared.Request request) { - request.fire(new Receiver() { - public void onConstraintViolation(Set> violations) { - dfd.reject(new ServerFailure("ConstraintViolation"), violations); - } - - public void onFailure(ServerFailure error) { - dfd.reject(error); - } - - public void onSuccess(T response) { - dfd.resolve(response); - } - }); - } - } - - /** - * Utility class used to create promises for RPC services. - *
-   *        PromiseRPC greeting = new PromiseRPC();
-   *        
-   *        GreetingServiceAsync greetingService = GWT.create(GreetingService.class);
-   *        greetingService.greetServer("hi", greeting);
-   *        
-   *        greeting.fail(new Function(){
-   *          public void f() {
-   *            Throwable error = arguments(0);
-   *          }
-   *        }).done(new Function(){
-   *          public void f() {
-   *            String response = arguments(0);
-   *          }
-   *        });
-   * 
- */ - public static class PromiseRPC extends DeferredPromiseImpl implements AsyncCallback { - public void onFailure(Throwable caught) { - dfd.reject(caught); - } - - public void onSuccess(T result) { - dfd.resolve(result); - } - } - - - /** - * Implementation of the Promise interface which is used internally by Deferred. - */ - private static class DeferredPromiseImpl implements Promise { - com.google.gwt.query.client.plugins.Deferred dfd; - - protected DeferredPromiseImpl() { - dfd = new com.google.gwt.query.client.plugins.Deferred(); - } - - protected DeferredPromiseImpl(com.google.gwt.query.client.plugins.Deferred o) { - dfd = o; - } - - public Promise always(Function... f) { - return done(f).fail(f); - } - - public Promise done(Function... f) { - dfd.resolve.add(f); - return this; - } - - public Promise fail(Function... f) { - dfd.reject.add(f); - return this; - } - - public Promise pipe(Function... f) { - return then(f); - } - - public Promise progress(Function... f) { - dfd.notify.add(f); - return this; - } - - public String state() { - return dfd.state; - } - - public Promise then(Function... f) { - assert f.length < 4 : "Promise.then: Too much arguments"; - switch (f.length) { - case 3: progress(f[2]); - case 2: fail(f[1]); - case 1: done(f[0]); - } - return this; - } - } - - /** - * Internal Deferred class used to combine a set of subordinate promises. - */ - private static class WhenDeferredImpl extends Deferred { - /** - * Internal function used to track whether all deferred - * subordinates are resolved. - */ - private class DoneFnc extends Function { - final int idx; - - public DoneFnc(int i, Deferred d) { - idx = i; - } - - public Object f(Object... args) { - values[idx] = args; - if (--remaining == 0) { - WhenDeferredImpl.this.resolve(values); - } - return true; - } - } - - private Function failFnc = new Function() { - public Object f(Object... o) { - WhenDeferredImpl.this.reject(o); - return true; - } - }; - - private Function progressFnc = new Function() { - public Object f(Object... o) { - WhenDeferredImpl.this.notify(o); - return true; - } - }; - - // Remaining counter - private int remaining; - - // An indexed array with the fired values of all subordinated - private final Object[] values; - - public WhenDeferredImpl(Promise[] sub) { - int l = remaining = sub.length; - values = new Object[l]; - for (int i = 0; i < l; i++) { - sub[i].done(new DoneFnc(i, this)).progress(progressFnc).fail(failFnc); - } - } - } - - // Register Deferred as a GQuery plugin - public static final Class Deferred = GQuery.registerPlugin( - Deferred.class, new Plugin() { - public Deferred init(GQuery gq) { - return new Deferred(gq); - } - }); - - public static Promise when(Promise... d) { - final int n = d.length; - switch (n) { - case 1: - return d[0]; - case 0: - return new Deferred().resolve().promise(); - default: - return new WhenDeferredImpl(d).promise(); - } - } - - private Callbacks notify = new Callbacks("memory"); - - private Promise promise = null; - - private Callbacks reject = new Callbacks("once memory"); - - private Callbacks resolve = new Callbacks("once memory"); - - private String state = PENDING; - - public Deferred() { - this(null); - } - - protected Deferred(GQuery gq) { - super(gq); - resolve.add(new Function() { - public void f() { - state = RESOLVED; - resolve.disable(); - notify.lock(); - } - }); - - reject.add(new Function() { - public void f() { - state = REJECTED; - reject.disable(); - notify.lock(); - } - }); - } - - /** - * Call the progressCallbacks on a Deferred object with the given args. - */ - public Deferred notify(Object... o) { - notify.fire(o); - return this; - } - - /** - * Return a Deferred’s Promise object. - */ - public Promise promise() { - if (promise == null) { - promise = new DeferredPromiseImpl(this); - } - return promise; - } - - /** - * Reject a Deferred object and call any failCallbacks with the given args. - */ - public Deferred reject(Object... o) { - reject.fire(o); - return this; - } - - /** - * Resolve a Deferred object and call any doneCallbacks with the given args. - */ - public Deferred resolve(Object... o) { - resolve.fire(o); - return this; - } - - // private, used from jsni because it does not handles variable arguments - @SuppressWarnings("unused") - private void err(Object o) { - reject(o); - } - - // private, used from jsni because it does not handles variable arguments - @SuppressWarnings("unused") - private void ok(Object o) { - resolve(o); - } -} 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 323eb728..8d2ed1dc 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,10 +11,10 @@ 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.Deferred; -import com.google.gwt.query.client.plugins.Deferred.PromiseJsonpReqBuilder; -import com.google.gwt.query.client.plugins.Deferred.PromiseReqBuilder; import com.google.gwt.query.client.plugins.Plugin; +import com.google.gwt.query.client.plugins.deferred.Deferred; +import com.google.gwt.query.client.plugins.deferred.PromiseJsonpReqBuilder; +import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilder; import com.google.gwt.user.client.ui.FormPanel; /** @@ -318,7 +318,7 @@ public class Ajax extends GQuery { public static Promise getJSONP(String url, Function success, Function error, int timeout) { return new PromiseJsonpReqBuilder(url, null, timeout) .done(success) - .fail(error == null ? success : error); + .fail(error); } public static Promise post(String url, Properties data, final Function onSuccess) { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/callbacks/Callbacks.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/callbacks/Callbacks.java deleted file mode 100644 index c7b4fb88..00000000 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/callbacks/Callbacks.java +++ /dev/null @@ -1,188 +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.plugins.callbacks; - -import com.google.gwt.core.shared.GWT; -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.js.JsObjectArray; - -/** - * Implementation of jQuery.Callbacks for gwtquery. - */ -public class Callbacks { - - /** - * Iterface used for callbacks which could cancel the execution - * when returning false; - * - */ - public static interface Callback { - /** - * Return false to avoid executing the rest of functions - */ - boolean f(Object ...objects); - } - - /** - * Interface representing the options of a Callbacks collection. - * - * To create an implementation of this interface just call: Callbacks.createOptions() - */ - public static interface CallbackOptions extends JsonBuilder { - boolean getMemory(); - boolean getOnce(); - boolean getStopOnFalse(); - boolean getUnique(); - CallbackOptions setMemory(); - CallbackOptions setOnce(); - CallbackOptions setStopOnFalse(); - CallbackOptions setUnique(); - } - - public static CallbackOptions createOptions() { - return GWT.create(CallbackOptions.class); - } - - private JsObjectArray stack = JsObjectArray.create(); - - private boolean done = false; - - private JsObjectArray memory = null; - - public final CallbackOptions opts; - - /** - * Create a new Callbacks object with default options - */ - public Callbacks() { - opts = createOptions(); - } - - /** - * Create a new Callbacks object with given options - */ - public Callbacks(CallbackOptions options) { - opts = options; - } - - /** - * Create a new Callbacks object with options given as a space delimited string. - * - * Valid options are: - * - * once, memory, unique, stopOnFalse - */ - public Callbacks(String options) { - this(); - opts.load(Properties.create(options.replaceAll("[^\\S]+|$", ":true,"))); - } - - /** - * Add a Callback or a collection of callbacks to a callback list. - * - */ - public Callbacks add(Callback... c) { - addAll((Object[])c); - return this; - } - - /** - * Add a Callback or a collection of callbacks to a callback list. - */ - public Callbacks add(com.google.gwt.core.client.Callback... c) { - addAll((Object[])c); - return this; - } - - /** - * Add a Function or a collection of Function to a callback list. - */ - public Callbacks add(Function... f) { - addAll((Object[])f); - return this; - } - - /** - * Disable a callback list from doing anything more. - */ - public Callbacks disable() { - stack = memory = null; - done = true; - return this; - } - - /** - * lock - */ - public Callbacks lock() { - if (!opts.getMemory()) { - disable(); - } - stack = null; - return this; - } - - /** - * Call all of the callbacks with the given arguments. - */ - public Callbacks fire(Object... o) { - if (!done) { - done = opts.getOnce(); - if (stack != null) for (Object c : stack.elements()) { - if (!run(c, o) && opts.getStopOnFalse()) { - break; - } - } - if (opts.getMemory()) { - memory = JsObjectArray.create().add(o); - } - } - return this; - } - - /** - * Remove a callback or a collection of callbacks from a callback list. - */ - public Callbacks remove(Object... o) { - stack.remove(o); - return this; - } - - private void addAll(Object...o) { - for (Object c : o) { - if (!done && c != null && (!opts.getUnique() || !stack.contains(c))) { - stack.add(c); - } - // In jQuery add always is run when memory is true even when unique is set - if (opts.getMemory() && memory != null) { - run(c, memory.elements()); - } - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private boolean run(Object c, Object...o) { - if (c instanceof Callback) { - return ((Callback)c).f(o); - } else if (c instanceof Function) { - Object r = ((Function)c).f(o); - return (r instanceof Boolean) ? (Boolean)r : true; - } else if (c instanceof com.google.gwt.core.client.Callback) { - ((com.google.gwt.core.client.Callback)c).onSuccess(o); - } - return true; - } -} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/Callbacks.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/Callbacks.java new file mode 100644 index 00000000..5471ed29 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/Callbacks.java @@ -0,0 +1,188 @@ +/* + * 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.plugins.deferred; + +import com.google.gwt.core.shared.GWT; +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.js.JsObjectArray; + +/** + * Implementation of jQuery.Callbacks for gwtquery. + */ +public class Callbacks { + + /** + * Iterface used for callbacks which could cancel the execution + * when returning false; + * + */ + public static interface Callback { + /** + * Return false to avoid executing the rest of functions + */ + boolean f(Object ...objects); + } + + /** + * Interface representing the options of a Callbacks collection. + * + * To create an implementation of this interface just call: Callbacks.createOptions() + */ + public static interface CallbackOptions extends JsonBuilder { + boolean getMemory(); + boolean getOnce(); + boolean getStopOnFalse(); + boolean getUnique(); + CallbackOptions setMemory(); + CallbackOptions setOnce(); + CallbackOptions setStopOnFalse(); + CallbackOptions setUnique(); + } + + public static CallbackOptions createOptions() { + return GWT.create(CallbackOptions.class); + } + + private JsObjectArray stack = JsObjectArray.create(); + + private boolean done = false; + + private JsObjectArray memory = null; + + public final CallbackOptions opts; + + /** + * Create a new Callbacks object with default options + */ + public Callbacks() { + opts = createOptions(); + } + + /** + * Create a new Callbacks object with given options + */ + public Callbacks(CallbackOptions options) { + opts = options; + } + + /** + * Create a new Callbacks object with options given as a space delimited string. + * + * Valid options are: + * + * once, memory, unique, stopOnFalse + */ + public Callbacks(String options) { + this(); + opts.load(Properties.create(options.replaceAll("[^\\S]+|$", ":true,"))); + } + + /** + * Add a Callback or a collection of callbacks to a callback list. + * + */ + public Callbacks add(Callback... c) { + addAll((Object[])c); + return this; + } + + /** + * Add a Callback or a collection of callbacks to a callback list. + */ + public Callbacks add(com.google.gwt.core.client.Callback... c) { + addAll((Object[])c); + return this; + } + + /** + * Add a Function or a collection of Function to a callback list. + */ + public Callbacks add(Function... f) { + addAll((Object[])f); + return this; + } + + /** + * Disable a callback list from doing anything more. + */ + public Callbacks disable() { + stack = memory = null; + done = true; + return this; + } + + /** + * lock + */ + public Callbacks lock() { + if (!opts.getMemory()) { + disable(); + } + stack = null; + return this; + } + + /** + * Call all of the callbacks with the given arguments. + */ + public Callbacks fire(Object... o) { + if (!done) { + done = opts.getOnce(); + if (stack != null) for (Object c : stack.elements()) { + if (!run(c, o) && opts.getStopOnFalse()) { + break; + } + } + if (opts.getMemory()) { + memory = JsObjectArray.create().add(o); + } + } + return this; + } + + /** + * Remove a callback or a collection of callbacks from a callback list. + */ + public Callbacks remove(Object... o) { + stack.remove(o); + return this; + } + + private void addAll(Object...o) { + for (Object c : o) { + if (!done && c != null && (!opts.getUnique() || !stack.contains(c))) { + stack.add(c); + } + // In jQuery add always is run when memory is true even when unique is set + if (opts.getMemory() && memory != null) { + run(c, memory.elements()); + } + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private boolean run(Object c, Object...o) { + if (c instanceof Callback) { + return ((Callback)c).f(o); + } else if (c instanceof Function) { + Object r = ((Function)c).f(o); + return (r instanceof Boolean) ? (Boolean)r : true; + } else if (c instanceof com.google.gwt.core.client.Callback) { + ((com.google.gwt.core.client.Callback)c).onSuccess(o); + } + return true; + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/Deferred.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/Deferred.java new file mode 100644 index 00000000..017c6aa3 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/Deferred.java @@ -0,0 +1,233 @@ +/* + * 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.plugins.deferred; + +import static com.google.gwt.query.client.Promise.PENDING; +import static com.google.gwt.query.client.Promise.REJECTED; +import static com.google.gwt.query.client.Promise.RESOLVED; + +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.Plugin; + +/** + * Implementation of jQuery.Deferred for gwtquery. + */ +public class Deferred extends GQuery implements Promise.Deferred { + + /** + * Implementation of the Promise interface which is used internally by Deferred. + */ + public static class DeferredPromiseImpl implements Promise { + protected com.google.gwt.query.client.plugins.deferred.Deferred dfd; + + protected DeferredPromiseImpl() { + dfd = new com.google.gwt.query.client.plugins.deferred.Deferred(); + } + + protected DeferredPromiseImpl(com.google.gwt.query.client.plugins.deferred.Deferred o) { + dfd = o; + } + + public Promise always(Function... f) { + return done(f).fail(f); + } + + public Promise done(Function... f) { + dfd.resolve.add(f); + return this; + } + + public Promise fail(Function... f) { + dfd.reject.add(f); + return this; + } + + public Promise pipe(Function... f) { + return then(f); + } + + public Promise progress(Function... f) { + dfd.notify.add(f); + return this; + } + + public String state() { + return dfd.state; + } + + public Promise then(Function... f) { + assert f.length < 4 : "Promise.then: Too much arguments"; + switch (f.length) { + case 3: progress(f[2]); + case 2: fail(f[1]); + case 1: done(f[0]); + } + return this; + } + } + + /** + * Internal Deferred class used to combine a set of subordinate promises. + */ + private static class WhenDeferredImpl extends Deferred { + /** + * Internal function used to track whether all deferred + * subordinates are resolved. + */ + private class DoneFnc extends Function { + final int idx; + + public DoneFnc(int i, Deferred d) { + idx = i; + } + + public Object f(Object... args) { + values[idx] = args; + if (--remaining == 0) { + WhenDeferredImpl.this.resolve(values); + } + return true; + } + } + + private Function failFnc = new Function() { + public Object f(Object... o) { + WhenDeferredImpl.this.reject(o); + return true; + } + }; + + private Function progressFnc = new Function() { + public Object f(Object... o) { + WhenDeferredImpl.this.notify(o); + return true; + } + }; + + // Remaining counter + private int remaining; + + // An indexed array with the fired values of all subordinated + private final Object[] values; + + public WhenDeferredImpl(Promise[] sub) { + int l = remaining = sub.length; + values = new Object[l]; + for (int i = 0; i < l; i++) { + sub[i].done(new DoneFnc(i, this)).progress(progressFnc).fail(failFnc); + } + } + } + + // Register Deferred as a GQuery plugin + public static final Class Deferred = GQuery.registerPlugin( + Deferred.class, new Plugin() { + public Deferred init(GQuery gq) { + return new Deferred(gq); + } + }); + + public static Promise when(Promise... d) { + final int n = d.length; + switch (n) { + case 1: + return d[0]; + case 0: + return new Deferred().resolve().promise(); + default: + return new WhenDeferredImpl(d).promise(); + } + } + + private Callbacks notify = new Callbacks("memory"); + + private Promise promise = null; + + private Callbacks reject = new Callbacks("once memory"); + + private Callbacks resolve = new Callbacks("once memory"); + + private String state = PENDING; + + public Deferred() { + this(null); + } + + protected Deferred(GQuery gq) { + super(gq); + resolve.add(new Function() { + public void f() { + state = RESOLVED; + resolve.disable(); + notify.lock(); + } + }); + + reject.add(new Function() { + public void f() { + state = REJECTED; + reject.disable(); + notify.lock(); + } + }); + } + + /** + * Call the progressCallbacks on a Deferred object with the given args. + */ + public Deferred notify(Object... o) { + notify.fire(o); + return this; + } + + /** + * Return a Deferred’s Promise object. + */ + public Promise promise() { + if (promise == null) { + promise = new DeferredPromiseImpl(this); + } + return promise; + } + + /** + * Reject a Deferred object and call any failCallbacks with the given args. + */ + public Deferred reject(Object... o) { + reject.fire(o); + return this; + } + + /** + * Resolve a Deferred object and call any doneCallbacks with the given args. + */ + public Deferred resolve(Object... o) { + resolve.fire(o); + return this; + } + + // private, used from jsni because it does not handles variable arguments + @SuppressWarnings("unused") + private void err(Object o) { + reject(o); + } + + // private, used from jsni because it does not handles variable arguments + @SuppressWarnings("unused") + private void ok(Object o) { + resolve(o); + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseFunction.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseFunction.java new file mode 100644 index 00000000..72f19ffd --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseFunction.java @@ -0,0 +1,38 @@ +package com.google.gwt.query.client.plugins.deferred; + +import com.google.gwt.query.client.plugins.deferred.Deferred.DeferredPromiseImpl; + +/** + * Utility class used to create customized promises which can manipulate + * the associated deferred object. + *
+ *    Promise doSomething = new PromiseFunction() {
+ *      @Override
+ *      public void f(Deferred dfd) {
+ *        dfd.notify("hi");
+ *        dfd.resolve("done");
+ *      }
+ *    };
+ *    
+ *    doSomething.progress(new Function() {
+ *      public void f() {
+ *        String hi = arguments(0);
+ *      }
+ *    }).done(new Function() {
+ *      public void f() {
+ *        String done = arguments(0);
+ *      }
+ *    });
+ * 
+ */ +public abstract class PromiseFunction extends DeferredPromiseImpl { + public PromiseFunction() { + f(dfd); + } + + /** + * This function is called once when the promise is created and the + * new deferred is available. + */ + public abstract void f(Deferred dfd); +} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseJsonpReqBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseJsonpReqBuilder.java new file mode 100644 index 00000000..80f00826 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseJsonpReqBuilder.java @@ -0,0 +1,68 @@ +package com.google.gwt.query.client.plugins.deferred; + +import com.google.gwt.jsonp.client.JsonpRequestBuilder; +import com.google.gwt.query.client.js.JsObjectArray; +import com.google.gwt.query.client.js.JsRegexp; +import com.google.gwt.query.client.plugins.deferred.Deferred.DeferredPromiseImpl; +import com.google.gwt.user.client.rpc.AsyncCallback; + +/** + * Utility class used to create promises for JsonpRequestBuilder. + *
+ *    Promise p = new PromiseJsonpReqBuilder(url, 4000);
+ *    
+ *    p.done(new Function() {
+ *      public void f() {
+ *        Properties p = arguments(0);
+ *      }
+ *    }).fail(new Function() {
+ *      public void f() {
+ *        Throwable error = arguments(0);
+ *      }
+ *    });
+ * 
+ */ +public class PromiseJsonpReqBuilder extends DeferredPromiseImpl { + + private static final JsRegexp callbackRegex = new JsRegexp("^(.+[\\?&])([^=]+)=\\?(.*)$"); + + public PromiseJsonpReqBuilder(String url) { + this(url, null, 0); + } + + public PromiseJsonpReqBuilder(String url, int timeout) { + this(url, null, timeout); + } + + public PromiseJsonpReqBuilder(String url, String callbackParam, int timeout) { + JsonpRequestBuilder builder = new JsonpRequestBuilder(); + if (timeout > 0) { + builder.setTimeout(timeout); + } + // jQuery allows a parameter callback=? to figure out the callback parameter + if (callbackParam == null) { + JsObjectArray tmp = callbackRegex.exec(url); + if (tmp.length() == 4) { + callbackParam = tmp.get(2); + url = tmp.get(1) + tmp.get(3); + } + } + if (callbackParam != null) { + builder.setCallbackParam(callbackParam); + } + send(builder, url, new AsyncCallback() { + public void onFailure(Throwable caught) { + dfd.reject(caught); + } + + public void onSuccess(Object result) { + dfd.resolve(result); + } + }); + } + + // Using jsni because method send in JsonpRequestBuilder is private + private final native void send(JsonpRequestBuilder bld, String url, AsyncCallback cb) /*-{ + bld.@com.google.gwt.jsonp.client.JsonpRequestBuilder::send(Ljava/lang/String;Lcom/google/gwt/user/client/rpc/AsyncCallback;Z)(url,cb,false); + }-*/; +} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseRF.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseRF.java new file mode 100644 index 00000000..737c7e84 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseRF.java @@ -0,0 +1,48 @@ +package com.google.gwt.query.client.plugins.deferred; + +import java.util.Set; + +import javax.validation.ConstraintViolation; + +import com.google.gwt.query.client.plugins.deferred.Deferred.DeferredPromiseImpl; +import com.google.web.bindery.requestfactory.shared.Receiver; +import com.google.web.bindery.requestfactory.shared.ServerFailure; + +/** + * Utility class used to create promises for RequestFactory services. + *
+ *    Request req1 = loginFact.api().login(null, null);
+ *    Request req2 = srvFact.api().getCurrentUser();
+ *    
+ *    Promise requestingAll = Deferred.when(new PromiseRF(req1), new PromiseRF(req2);
+ *    
+ *    requestingAll.done(new Function() {
+ *        public void f() {
+ *          SessionProxy session = arguments(0, 0);
+ *          UserProxy user = arguments(1, 0);
+ *        }
+ *      })
+ *      .fail(new Function() {
+ *        public void f() {
+ *          ServerFailure failure = arguments(0);
+ *        }
+ *      }); 
+ * 
+ */ +public class PromiseRF extends DeferredPromiseImpl { + public PromiseRF(com.google.web.bindery.requestfactory.shared.Request request) { + request.fire(new Receiver() { + public void onConstraintViolation(Set> violations) { + dfd.reject(new ServerFailure("ConstraintViolation"), violations); + } + + public void onFailure(ServerFailure error) { + dfd.reject(error); + } + + public void onSuccess(T response) { + dfd.resolve(response); + } + }); + } +} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseRPC.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseRPC.java new file mode 100644 index 00000000..41e88cf1 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseRPC.java @@ -0,0 +1,33 @@ +package com.google.gwt.query.client.plugins.deferred; + +import com.google.gwt.query.client.plugins.deferred.Deferred.DeferredPromiseImpl; +import com.google.gwt.user.client.rpc.AsyncCallback; + +/** + * Utility class used to create promises for RPC services. + *
+ *        PromiseRPC greeting = new PromiseRPC();
+ *        
+ *        GreetingServiceAsync greetingService = GWT.create(GreetingService.class);
+ *        greetingService.greetServer("hi", greeting);
+ *        
+ *        greeting.fail(new Function(){
+ *          public void f() {
+ *            Throwable error = arguments(0);
+ *          }
+ *        }).done(new Function(){
+ *          public void f() {
+ *            String response = arguments(0);
+ *          }
+ *        });
+ * 
+ */ +public class PromiseRPC extends DeferredPromiseImpl implements AsyncCallback { + public void onFailure(Throwable caught) { + dfd.reject(caught); + } + + public void onSuccess(T result) { + dfd.resolve(result); + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..26ecefd4 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java @@ -0,0 +1,50 @@ +package com.google.gwt.query.client.plugins.deferred; + +import com.google.gwt.http.client.Request; +import com.google.gwt.http.client.RequestBuilder; +import com.google.gwt.http.client.RequestCallback; +import com.google.gwt.http.client.RequestException; +import com.google.gwt.http.client.Response; +import com.google.gwt.query.client.plugins.deferred.Deferred.DeferredPromiseImpl; + +/** + * Utility class used to create promises for RequestBuilder. + *
+ *        RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, "http://127.0.0.1:8888/whatever");
+ *        PromiseRequest gettingResponse = new PromiseReqBuilder(builder);
+ *        
+ *        gettingResponse.fail(new Function() {
+ *          public void f() {
+ *            Throwable exception = arguments(0);
+ *          }
+ *        }).done(new Function() {
+ *          public void f() {
+ *            Response response = arguments(0);
+ *          }
+ *        });
+ * 
+ */ +public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCallback { + public PromiseReqBuilder(RequestBuilder builder) { + builder.setCallback(this); + try { + builder.send(); + } catch (RequestException e) { + onError(null, e); + } + } + + public void onError(Request request, Throwable exception) { + dfd.reject(exception, request); + } + + public void onResponseReceived(Request request, Response response) { + int status = response.getStatusCode(); + if (status <= 0 || status >= 400) { + String statusText = status <= 0 ? "Bad CORS" : response.getStatusText(); + onError(request, new RequestException("HTTP ERROR: " + status + " " + statusText + "\n" + response.getText())); + } else { + dfd.resolve(response, request); + } + } +} \ No newline at end of file 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 dcd6e20b..8c011a24 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 @@ -17,10 +17,10 @@ package com.google.gwt.query.client; import com.google.gwt.junit.client.GWTTestCase; -import com.google.gwt.query.client.plugins.Deferred.PromiseFunction; import com.google.gwt.query.client.plugins.ajax.Ajax; -import com.google.gwt.query.client.plugins.callbacks.Callbacks; -import com.google.gwt.query.client.plugins.callbacks.Callbacks.Callback; +import com.google.gwt.query.client.plugins.deferred.Callbacks; +import com.google.gwt.query.client.plugins.deferred.PromiseFunction; +import com.google.gwt.query.client.plugins.deferred.Callbacks.Callback; import com.google.gwt.user.client.Timer; /**