com.floatzcss.gwt.client.util.ScriptInjectorUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.floatzcss.gwt.client.util.ScriptInjectorUtils.java

Source

package com.floatzcss.gwt.client.util;

import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.ScriptInjector;
import com.google.gwt.core.client.ScriptInjector.FromUrl;

import java.util.ArrayList;
import java.util.List;

/**
 * Script injector utilities.
 * <p>
 * Copyright (c) 2010-2015 by :hummldesign http://design.humml.eu
 * Licensed under Apache License 2.0, http://www.apache.org/licenses/LICENSE-2.0
 * </p>
 * <p>
 * See: https://github.com/floatzcss/
 * </p>
 *
 * @author Harald Humml
 * @see com.google.gwt.core.client.ScriptInjector
 * @since 1.3.0
 */

public class ScriptInjectorUtils {

    /**
     * Data structure for scripts.
     */
    private class Script {
        public FromUrl fromUrl;
        public boolean wait;
        public Callback<Void, Exception> waitCallback;

        /**
         * Constructor
         *
         * @param fromUrl Script url
         * @param wait    true to wait until preceding scripts are loaded, false to load it immediately
         */
        public Script(FromUrl fromUrl, boolean wait) {
            this.fromUrl = fromUrl;
            this.wait = wait;
        }
    }

    /**
     * Static members.
     */
    private static ScriptInjectorUtils instance;

    /**
     * Members.
     */
    private List<List<Script>> scheduledScripts = new ArrayList<List<Script>>();
    private List<Script> scripts = new ArrayList<Script>();
    private Exception lastError;

    /**
     * Constructor.
     */
    private ScriptInjectorUtils() {
    }

    /**
     * Get instance.
     *
     * @return ScriptInjectorUtils instance
     */
    public static ScriptInjectorUtils getInstance() {
        return ScriptInjectorUtils.instance != null ? ScriptInjectorUtils.instance : new ScriptInjectorUtils();
    }

    /**
     * Loads all pending scripts.
     * <p>
     * Must be executed after the last injected script.
     * </p>
     */
    public void flush() {
        flush(null);
    }

    /**
     * Loads all pending scripts.
     * <p>
     * Must be executed after the last injected script.
     * </p>
     *
     * @param finalCallback Callback that is executed after all scripts are loaded
     */
    public void flush(Callback<Void, Exception> finalCallback) {

        // Schedule scripts to be loaded
        scheduleScripts();

        // Load scripts according to schedule
        if (scheduledScripts.size() > 0) {
            loadScripts(0, finalCallback);
        }
    }

    /**
     * Schedule scripts.
     * <p>
     * All injected scripts are separated into tranches so that we can wait after each tranche until the last script of
     * the tranche is loaded, before we can continue with the next tranche. See {@link #loadScripts(int, com.google.gwt.core.client.Callback)}.
     * </p>
     */
    private void scheduleScripts() {
        scheduledScripts.add(new ArrayList<Script>());
        for (Script script : scripts) {
            scheduledScripts.get(scheduledScripts.size() - 1).add(script);
            if (script.wait) {
                scheduledScripts.add(new ArrayList<Script>());
            }
        }
    }

    /**
     * Load scripts according to schedule.
     * <p>
     * This method is called recursively until all tranches are loaded.
     * </p>
     *
     * @param tranche       Tranche number
     * @param finalCallback Callback that is executed after all scripts are loaded
     */
    private void loadScripts(final int tranche, final Callback<Void, Exception> finalCallback) {
        List<Script> scripts = scheduledScripts.get(tranche);
        int loaded = 1;
        for (final Script script : scripts) {
            if (loaded++ == scripts.size()) {
                // Last script in tranche must be loaded before new tranche can be started
                loadLastScript(tranche, finalCallback, script);

            } else {
                // All other scripts can be loaded without waiting
                loadScript(script);
            }
        }
    }

    /**
     * Load last script in tranche.
     *
     * @param tranche       Tranche number
     * @param finalCallback Callback that is executed after all scripts are loaded
     * @param script        Script to be loaded
     */
    private void loadLastScript(final int tranche, final Callback<Void, Exception> finalCallback,
            final Script script) {
        script.fromUrl.setWindow(ScriptInjector.TOP_WINDOW).setCallback(new Callback<Void, Exception>() {
            @Override
            public void onSuccess(Void result) {

                // Execute wait callback
                if (script.waitCallback != null) {
                    if (lastError != null) {
                        script.waitCallback.onFailure(lastError);
                    } else {
                        script.waitCallback.onSuccess(result);
                    }
                }

                // Load next tranche of or call final injectCommand after all tranches are loaded
                if ((tranche + 1) < scheduledScripts.size()) {
                    loadScripts(tranche + 1, finalCallback);

                    // Execute final callback
                } else if (finalCallback != null) {
                    if (lastError != null) {
                        finalCallback.onFailure(lastError);
                    } else {
                        finalCallback.onSuccess(result);
                    }
                }
            }

            @Override
            public void onFailure(Exception reason) {
                if (finalCallback != null) {
                    finalCallback.onFailure(reason);
                }
            }
        }).inject();
    }

    /**
     * Load script in tranche.
     *
     * @param script Script to be loaded
     */
    private void loadScript(Script script) {
        script.fromUrl.setWindow(ScriptInjector.TOP_WINDOW).setCallback(new Callback<Void, Exception>() {
            @Override
            public void onSuccess(Void result) {
                // Nothing to do here, we don wait
            }

            @Override
            public void onFailure(Exception reason) {
                // Store error for later
                if (lastError == null) {
                    lastError = reason;
                }
            }
        }).inject();
    }

    /**
     * Inject fromUrl.
     * <p>
     * After the last injected fromUrl {@link #flush()} must be executed.
     * </p>
     *
     * @param url Url of the fromUrl
     * @return Reference for chaining
     */
    public ScriptInjectorUtils inject(String url) {
        scripts.add(new Script(ScriptInjector.fromUrl(url).setWindow(ScriptInjector.TOP_WINDOW), false));
        return this;
    }

    /**
     * Wait until preceding fromUrl has been loaded.
     *
     * @return Reference for chaining
     */
    public ScriptInjectorUtils waitFor() {
        return waitFor(null);
    }

    /**
     * Wait until preceding fromUrl has been loaded.
     *
     * @param waitCallback Callback that is executed after all scripts are loaded
     * @return Reference for chaining
     */
    public ScriptInjectorUtils waitFor(Callback<Void, Exception> waitCallback) {
        Script script = scripts.get(scripts.size() - 1);
        script.waitCallback = waitCallback;
        script.wait = true;
        return this;
    }
}