com.smartgwt.linker.SmartGwtScriptInjector.java Source code

Java tutorial

Introduction

Here is the source code for com.smartgwt.linker.SmartGwtScriptInjector.java

Source

/*
 * Smart GWT (GWT for SmartClient)
 * Copyright 2014 and beyond, Isomorphic Software, Inc.
 *
 * Smart GWT is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3
 * is published by the Free Software Foundation.  Smart GWT is also
 * available under typical commercial license terms - see
 * http://smartclient.com/license
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 */

package com.smartgwt.linker;

import com.google.gwt.core.ext.LinkerContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.AbstractLinker;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.Artifact;
import com.google.gwt.core.ext.linker.Shardable;
import com.google.gwt.core.ext.linker.EmittedArtifact;
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.ScriptReference;

import com.google.gwt.dev.About;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.core.linker.CrossSiteIframeLinker;

import java.lang.reflect.Method;
import java.util.Set;

@Shardable
@LinkerOrder(LinkerOrder.Order.POST)
public class SmartGwtScriptInjector extends AbstractLinker {

    private static Class XSI_LINKER_CLASS = CrossSiteIframeLinker.class;
    private static Class MODULE_DEF_LOADER_CLASS = ModuleDefLoader.class;
    private static String COMPILER_CONTEXT = "com.google.gwt.dev.CompilerContext";

    // check whether we need to add a section to manually load the module's script tags
    private boolean forceScriptLoad(TreeLogger logger, String moduleName, Float gwtVersion) {
        try {
            ModuleDef module;
            Method getModuleDef;

            // ModuleDefLoader.loadFromClassPath has two possible signatures
            if (gwtVersion < 2.6f) {
                getModuleDef = MODULE_DEF_LOADER_CLASS.getDeclaredMethod("loadFromClassPath",
                        new Class[] { TreeLogger.class, String.class });
                module = (ModuleDef) getModuleDef.invoke(null, logger, moduleName);
            } else {
                Class compilerContextClass = Class.forName(COMPILER_CONTEXT);
                getModuleDef = MODULE_DEF_LOADER_CLASS.getDeclaredMethod("loadFromClassPath",
                        new Class[] { TreeLogger.class, compilerContextClass, String.class });
                module = (ModuleDef) getModuleDef.invoke(null, logger, null, moduleName);
            }

            // now use the module to check whether primary linker ist he CrossSiteIframeLinker
            if (module != null)
                return XSI_LINKER_CLASS.equals(module.getActivePrimaryLinker());
            logger.log(TreeLogger.WARN, "Can't find module reference - not injecting scripts.");

        } catch (Throwable t) {
            logger.log(TreeLogger.ERROR,
                    "Encountered an exception while trying to " + "resolve the ModuleDef for " + moduleName, t);
        }
        return false;
    }

    private static String XSI_LINKER_MODULE_BASE = "__moduleBase";
    private static String LOADED_SCRIPTS = "__gwt_scriptsLoaded";
    private static String SCRIPT_ANNOUNCE = "   Invoking Linker SmartGwtScriptInjector\n"
            + "      Augmenting module.nocache.js to manually load the following script tags:";

    private String getScriptLoadJS(Set<ScriptReference> scriptsToLoad, LinkerContext context) {
        String moduleName = context.getModuleName();
        System.out.println(SCRIPT_ANNOUNCE.replaceFirst("module", moduleName));

        String result = "\nif (!window." + LOADED_SCRIPTS + ") " + "window." + LOADED_SCRIPTS + " = {};\n";
        for (ScriptReference script : scriptsToLoad) {
            String src = script.getSrc();
            result += "if (!" + LOADED_SCRIPTS + "['" + src + "']) {\n  " + LOADED_SCRIPTS + "['" + src
                    + "'] = true;\n  " + "document.write('<script language=\"javascript\" src=\"'+" + moduleName
                    + "." + XSI_LINKER_MODULE_BASE + "+'" + src + "\"></script>');\n" + "}\n";
            System.out.println(src);
        }
        result += "\n";

        return context.isOutputCompact() ? result.replaceAll("\n\\s*", "") : result;
    }

    public String getDescription() {
        return "ScriptInjector";
    }

    public ArtifactSet link(TreeLogger logger, LinkerContext context, ArtifactSet artifacts, boolean permutation)
            throws UnableToCompleteException {
        Float gwtVersion = Float.parseFloat(About.getGwtVersionNum().replaceFirst("([0-9]+\\.[0-9]+).*", "$1"));
        String moduleName = context.getModuleName();

        // do nothing if the primary linker already handles script injection automatically
        if (permutation || gwtVersion < 2.5f || !forceScriptLoad(logger, moduleName, gwtVersion)) {
            return artifacts;
        }

        // if there are no script tags present, then there's nothing to do
        Set<ScriptReference> scripts = artifacts.find(ScriptReference.class);
        if (scripts.size() == 0)
            return artifacts;

        // script tags are present, and manual load required; emit script loading
        ArtifactSet toReturn = new ArtifactSet(artifacts);

        Set<EmittedArtifact> emittedArtifacts = artifacts.find(EmittedArtifact.class);
        for (EmittedArtifact emittedArtifact : emittedArtifacts) {
            String partialPath = emittedArtifact.getPartialPath();
            if (!partialPath.endsWith(".nocache.js"))
                continue;

            toReturn.remove(emittedArtifact);

            // add code at the end of the <moduleName>.nocache.js file to load the scripts
            String contents = SmartGwtLinkerUtils.getContents(emittedArtifact, logger);
            contents += getScriptLoadJS(scripts, context);

            StringBuffer sb = new StringBuffer(contents);
            toReturn.add(emitString(logger, sb.toString(), partialPath));
            break;
        }

        return toReturn;
    }
}