All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.query.client.plugins.deferred.Deferred Maven / Gradle / Ivy

The newest version!
/*
 * 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;

/**
 * Implementation of jQuery.Deferred for gwtquery.
 */
public class Deferred implements Promise.Deferred {

  /**
   * Implementation of the Promise interface which is used internally by
   * Deferred.
   */
  public static class DeferredPromiseImpl implements Promise {
    // Using 'int' instead of 'enum' because we use them as indexes as well
    private static final int DONE = 0, FAIL = 1, PROGRESS = 2;

    // Private class used to handle `Promise.then()`
    private static class ThenFunction extends Function {

      // Original filter function
      private final Function filter;
      // Type of action (DONE/FAIL/PROGRESS)
      private final int type;
      // Original deferred object
      private final Deferred dfd;
      // Whether break the flow if old deferred fails
      boolean cont = false;

      public ThenFunction(Deferred newDfd, Function[] subordinates, int funcType,
          boolean continueFlow) {
        type = funcType;
        filter = subordinates.length > type ? subordinates[type] : null;
        dfd = newDfd;
        cont = continueFlow;
      }

      public void f() {
        final Object[] oldArgs = getArguments();
        if (filter != null) {
          // We filter resolved arguments with the filter function
          Object newArgs = filter.setArguments(oldArgs).f(oldArgs);

          if (newArgs instanceof Promise) {
            // If filter function returns a promise we pipeline it.
            final Promise p = (Promise) newArgs;
            if (type == PROGRESS) {
              p.progress(new Function() {
                public void f() {
                  settle(PROGRESS, getArguments());
                }
              });
            } else {
              p.always(new Function() {
                public void f() {
                  settle((type == DONE || type == FAIL && cont) && p.isResolved() ? DONE : FAIL,
                      getArguments());
                }
              });
            }
          } else {
            // Otherwise we change the arguments by the new ones
            newArgs = Boolean.TRUE.equals(newArgs) ? oldArgs :
                newArgs != null && newArgs.getClass().isArray() ? (Object[]) newArgs : newArgs;
            settle(type, newArgs);
          }
        } else {
          // just continue the flow when filter is null
          settle(type, oldArgs);
        }
      }

      private void settle(int action, Object... args) {
        if (action == DONE)
          dfd.resolve(args);
        if (action == FAIL)
          dfd.reject(args);
        if (action == PROGRESS)
          dfd.notify(args);
      }
    }

    protected com.google.gwt.query.client.plugins.deferred.Deferred dfd;

    /**
     * Utility function which can be used inside classes extending this to
     * resolve this deferred in a call to any other promise method.
     *
     * Example:
     * 
     * new PromiseFunction() {
     *   public void f(final Deferred dfd) {
     *     anotherPromise.done( resolve );
     *   }
     * }
     * 
*/ public Function resolve = new Function() { public void f() { dfd.resolve(arguments); }; }; /** * Utility function which can be used inside classes extending this to * reject this deferred in a call to any other promise method. * * Example: *
     * new PromiseFunction() {
     *   public void f(final Deferred dfd) {
     *     anotherPromise.done( reject );
     *   }
     * }
     * 
*/ public Function reject = new Function() { public void f() { dfd.reject(arguments); }; }; 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 and(Function f) { return then(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 or(final Function f) { return then(true, null, f); } 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; } private Promise then(boolean continueFlow, final Function... f) { final Deferred newDfd = new com.google.gwt.query.client.plugins.deferred.Deferred(); done(new ThenFunction(newDfd, f, DONE, continueFlow)); fail(new ThenFunction(newDfd, f, FAIL, continueFlow)); progress(new ThenFunction(newDfd, f, PROGRESS, continueFlow)); return newDfd.promise(); } public Promise then(final Function... f) { return then(false, f); } public boolean isResolved() { return Promise.RESOLVED.equals(state()); } public boolean isRejected() { return Promise.REJECTED.equals(state()); } public boolean isPending() { return Promise.PENDING.equals(state()); } public String toString() { return "Promise this=" + hashCode() + " " + dfd; } } /** * 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.length == 1 ? args[0] : 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); } } } /** * Provides a way to execute callback functions based on one or more objects, * usually Deferred objects that represent asynchronous events. * * Returns the Promise from a new "master" Deferred object that tracks the aggregate * state of all the Deferreds passed. The method will resolve its master * Deferred as soon as all the Deferreds resolve, or reject the master Deferred as * soon as one of the Deferreds is rejected */ public static Promise when(Object... d) { int l = d.length; Promise[] p = new Promise[l]; for (int i = 0; i < l; i++) { p[i] = makePromise(d[i]); } return when(p); } private static Promise makePromise(final Object o) { if (o instanceof Promise) { return (Promise) o; } else if (o instanceof Function) { return makePromise(((Function) o).f(new Object[0])); } else if (o instanceof GQuery) { return ((GQuery) o).promise(); } else { return new PromiseFunction() { public void f(Deferred dfd) { dfd.resolve(o); } }; } } 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() { 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) { if (state == PENDING) 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) { if (state == PENDING) reject.fire(o); return this; } /** * Resolve a Deferred object and call any doneCallbacks with the given args. */ public Deferred resolve(Object... o) { if (state == PENDING) resolve.fire(o); return this; } @Override public String toString() { return "Deferred this=" + hashCode() + " promise=" + promise().hashCode() + " state=" + promise.state() + " restatus=" + resolve.status(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy