Package com.sencha.gxt.data.shared.loader

Source Code of com.sencha.gxt.data.shared.loader.Loader$WrapperProxy

/**
* Sencha GXT 3.1.0-beta - Sencha for GWT
* Copyright(c) 2007-2014, Sencha, Inc.
* licensing@sencha.com
*
* http://www.sencha.com/products/gxt/license/
*/
package com.sencha.gxt.data.shared.loader;

import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.event.shared.SimpleEventBus;
import com.sencha.gxt.core.shared.event.CancellableEvent;
import com.sencha.gxt.core.shared.event.GroupingHandlerRegistration;
import com.sencha.gxt.data.shared.loader.BeforeLoadEvent.BeforeLoadHandler;
import com.sencha.gxt.data.shared.loader.LoadExceptionEvent.LoadExceptionHandler;
import com.sencha.gxt.data.shared.loader.LoaderHandler.HasLoaderHandlers;

/**
* Abstract base class for objects that can load remote data.
*
* <p />
* The optional input object passed with the load request is logically called a
* "load config" with the object returned by the loader called the
* "load result".
*
* <p />
* Typically, loaders work with {@link DataProxy} and {@link DataReader} to help
* perform the load operations. The <code>DataProxy</code> is responsible for
* obtaining the remote data. The <code>DataReader</code> is responsible for
* "processing" the remote data and converting the data to the expected format.
*
* <dl>
* <dt><b>Events:</b></dt>
* <dd>{@link BeforeLoadEvent}</b></dd>
* <dd>{@link LoadEvent}</b></dd>
* <dd>{@link LoadExceptionEvent}</b></dd>
* </dl>
*
* @param <C> the type of the data used to configure
* @param <M> the type of data being returned by the loader
*/
public class Loader<C, M> implements HasLoaderHandlers<C, M> {

  private static class WrapperProxy<M, C, T> implements DataProxy<C, M> {
    private final DataProxy<C, T> proxy;
    private final DataReader<M, T> reader;

    public WrapperProxy(DataProxy<C, T> proxy, DataReader<M, T> reader) {
      this.proxy = proxy;
      this.reader = reader;
    }

    public void load(final C loadConfig, final Callback<M, Throwable> callback) {
      proxy.load(loadConfig, new Callback<T, Throwable>() {
        @Override
        public void onFailure(Throwable caught) {
          callback.onFailure(caught);
        }

        public void onSuccess(T result) {
          if (GWT.isProdMode()) {
            callback.onSuccess(reader.read(loadConfig, result));
          } else {
            try {
              callback.onSuccess(reader.read(loadConfig, result));
            } catch (ClassCastException ex) {
              GWT.log("Improper cast in " + reader.getClass()
                  + ", cannot convert the incoming data to the correct return type. "
                  + "Please provide an implementation of createReturnData()", ex);
              throw ex;
            }
          }
        }
      });
    }
  }

  private final DataProxy<C, M> proxy;
  private C lastLoadConfig;
  private boolean reuseLoadConfig;

  private SimpleEventBus eventBus;

  /**
   * Creates a new base loader instance. Since a data reader is not used, the
   * data returned by the data proxy will not be read and converted by a reader.
   *
   * @param proxy the data proxy
   */
  public Loader(DataProxy<C, M> proxy) {
    this.proxy = proxy;
  }

  /**
   * Creates a new loader with the given proxy and reader.
   *
   * @param proxy the data proxy
   * @param reader the data reader
   */
  public <T> Loader(DataProxy<C, T> proxy, DataReader<M, T> reader) {
    this(new WrapperProxy<M, C, T>(proxy, reader));
  }

  @Override
  public HandlerRegistration addBeforeLoadHandler(BeforeLoadHandler<C> handler) {
    return addHandler(BeforeLoadEvent.getType(), handler);
  }

  /**
   * Adds an event handler to the loader.
   *
   * @param <H> type parameter to ensure that the event and handler match
   * @param type the type of event to listen for
   * @param handler the handler to call when the event goes off
   * @return a handler registration to remove the handler if needed
   */
  protected <H extends EventHandler> HandlerRegistration addHandler(GwtEvent.Type<H> type, H handler) {
    if (eventBus == null) {
      eventBus = new SimpleEventBus();
    }
    return eventBus.addHandler(type, handler);
  }

  @Override
  public HandlerRegistration addLoaderHandler(LoaderHandler<C, M> handler) {
    GroupingHandlerRegistration group = new GroupingHandlerRegistration();
    group.add(addHandler(BeforeLoadEvent.getType(), handler));
    group.add(addHandler(LoadEvent.getType(), handler));
    group.add(addHandler(LoadExceptionEvent.getType(), handler));
    return group;
  }

  @Override
  public HandlerRegistration addLoadExceptionHandler(LoadExceptionHandler<C> handler) {
    return addHandler(LoadExceptionEvent.getType(), handler);
  }

  @Override
  public HandlerRegistration addLoadHandler(LoadHandler<C, M> handler) {
    return addHandler(LoadEvent.getType(), handler);
  }

  /**
   * Returns the last load config.
   *
   * @return the last load config
   */
  public C getLastLoadConfig() {
    return lastLoadConfig;
  }

  /**
   * Returns the loader's data proxy.
   *
   * @return the data proxy
   */
  public DataProxy<?, ?> getProxy() {
    return proxy;
  }

  /**
   * Returns true if the load config is being reused.
   *
   * @return the reuse load config state
   */
  public boolean isReuseLoadConfig() {
    return reuseLoadConfig;
  }

  /**
   * Loads the data using the current configuration. Fires the
   * {@link BeforeLoadEvent} before the request, then the {@link LoadEvent}
   * after the load operation.
   *
   * @return true if the load was requested, false if cancelled
   */
  public boolean load() {
    C config = (reuseLoadConfig && lastLoadConfig != null) ? lastLoadConfig : newLoadConfig();
    config = prepareLoadConfig(config);
    return load(config);
  }

  /**
   * Loads the data using the given load configuration. Fires the
   * {@link BeforeLoadEvent} before the request, then the {@link LoadEvent}
   * after the load operation. The current load configuration object can be
   * retrieved using {@link #getLastLoadConfig()}.
   *
   * @param loadConfig the load config
   * @return true if the load was requested, false if cancelled
   */
  public boolean load(C loadConfig) {
    if (fireEvent(new BeforeLoadEvent<C>(loadConfig))) {
      lastLoadConfig = loadConfig;
      loadData(loadConfig);
      return true;
    }
    return false;
  }

  /**
   * Sets whether the same load config instance should be used for load
   * operations (defaults to false).
   *
   * @param reuseLoadConfig true to reuse
   */
  public void setReuseLoadConfig(boolean reuseLoadConfig) {
    this.reuseLoadConfig = reuseLoadConfig;
  }

  /**
   * Fires the given event.
   *
   * @param event the event to fire
   * @return true if the event was not cancelled, false if the event was
   *         cancelled
   */
  protected boolean fireEvent(GwtEvent<?> event) {
    if (eventBus != null) {
      eventBus.fireEvent(event);
    }
    if (event instanceof CancellableEvent) {
      return !((CancellableEvent) event).isCancelled();
    }
    return true;
  }

  /**
   * Load data, delegating to {@link DataProxy} if configured, or forwarding to
   * {@link #loadData(Object)} if not.
   *
   * @param config the load config
   */
  protected void loadData(final C config) {
    Callback<M, Throwable> callback = new Callback<M, Throwable>() {
      public void onFailure(Throwable caught) {
        caught.printStackTrace();
        onLoadFailure(config, caught);
      }

      public void onSuccess(M result) {
        onLoadSuccess(config, result);
      }
    };
    if (proxy == null) {
      loadData(config, callback);
      return;
    }
    proxy.load(config, callback);
  }

  /**
   * Called by {@link #loadData(Object)} when a data proxy is not being used.
   *
   * @param config the load config
   * @param callback the callback
   */
  protected void loadData(C config, Callback<M, Throwable> callback) {

  }

  /**
   * Template method to allow custom BaseLoader subclasses to provide their own
   * implementation of LoadConfig. This implementation return null.
   */
  protected C newLoadConfig() {
    return null;
  }

  /**
   * Called when a load operation fails.
   *
   * @param loadConfig the load config
   * @param t the exception
   */
  protected void onLoadFailure(C loadConfig, Throwable t) {
    fireEvent(new LoadExceptionEvent<C>(loadConfig, t));
  }

  /**
   * Called when the remote data has been received.
   *
   * @param loadConfig the load config
   * @param data data
   */
  protected void onLoadSuccess(C loadConfig, M data) {
    fireEvent(new LoadEvent<C, M>(loadConfig, data));
  }

  /**
   * Template method to allow custom subclasses to prepare the load config prior
   * to loading data
   */
  protected C prepareLoadConfig(C config) {
    return config;
  }

  /**
   * Sets the most recent load config.
   *
   * @param lastLoadConfig the most recent load config to set
   */
  protected void setLastLoadConfig(C lastLoadConfig) {
    this.lastLoadConfig = lastLoadConfig;
  }

}
TOP

Related Classes of com.sencha.gxt.data.shared.loader.Loader$WrapperProxy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.