Package com.google.gwt.chrome.crx.linker

Source Code of com.google.gwt.chrome.crx.linker.ExtensionLinker

/*
* Copyright 2009 Google Inc.
*
* 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.chrome.crx.linker;

import com.google.gwt.chrome.crx.client.Extension;
import com.google.gwt.chrome.crx.linker.ExtensionArtifact.IconInfo;
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.Artifact;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.CompilationResult;
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
import com.google.json.serialization.JsonArray;
import com.google.json.serialization.JsonObject;
import com.google.json.serialization.JsonValue;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Collection;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Linker for chrome Extensions.
*/
@LinkerOrder(Order.PRIMARY)
public class ExtensionLinker extends AbstractLinker {

  private static ArtifactSet addArtifacts(ArtifactSet artifacts,
      Artifact<?>... newArtifacts) {
    final ArtifactSet newSet = new ArtifactSet(artifacts);
    for (Artifact<?> artifact : newArtifacts) {
      newSet.add(artifact);
    }
    return newSet;
  }

  private static void checkForDisallowedJs(String js, String patternString,
      int allowedOccurences, TreeLogger logger)
      throws UnableToCompleteException {
    Pattern pattern = Pattern.compile(patternString);
    Matcher matcher = pattern.matcher(js);
    int count = 0;
    while (matcher.find()) {
      count++;
    }
    if (count > allowedOccurences) {
      logger.log(TreeLogger.ERROR, "You may have a reference to "
          + patternString
          + ". This is not allowed when using the ExtensionLinker! (Got "
          + count + " references, expected " + allowedOccurences + ")");
      throw new UnableToCompleteException();
    }
  }

  private static JsonValue createBgScriptsObject(String bgScriptName) {
    final JsonObject obj = JsonObject.create();
    final JsonArray scriptsArray = JsonArray.create();
    scriptsArray.add(bgScriptName);   
    obj.put("scripts", scriptsArray);
    return obj;
  }

  private static JsonValue createContentScriptsArray(
      SortedSet<ContentScriptArtifact> contentScripts) {
    final JsonArray array = JsonArray.create();
    for (ContentScriptArtifact contentScript : contentScripts) {
      JsonObject entry = JsonObject.create();
      JsonArray whiteList = JsonArray.create();
      String[] patterns = contentScript.getWhiteList();
      for (String pattern : patterns) {
        whiteList.add(pattern);
      }
      entry.put("matches", whiteList);
      JsonArray path = JsonArray.create();
      path.add(contentScript.getPath());
      entry.put("js", path);
      entry.put("run_at", contentScript.getRunAt());
      array.add(entry);
    }
    return array;
  }

  private static JsonValue createPageActionsArray(
      SortedSet<PageActionArtifact> pageActions) {
    final JsonArray pageActionArray = JsonArray.create();
    for (PageActionArtifact pageAction : pageActions) {
      final JsonObject pageActionObject = JsonObject.create();
      pageActionObject.put("id", pageAction.getId());
      pageActionObject.put("name", pageAction.getName());
      final JsonArray iconsArray = JsonArray.create();
      String[] icons = pageAction.getIcons();
      for (String icon : icons) {
        iconsArray.add(icon);
      }
      pageActionObject.put("icons", iconsArray);
      pageActionArray.add(pageActionObject);
    }
    return pageActionArray;
  }

  private static JsonValue createPluginsArray(SortedSet<PluginArtifact> plugins) {
    JsonArray pluginsArray = JsonArray.create();
    for (PluginArtifact plugin : plugins) {
      JsonObject pluginObject = JsonObject.create();
      pluginObject.put("path", plugin.getPath());
      pluginObject.put("public", plugin.isPublic());
      pluginsArray.add(pluginObject);
    }
    return pluginsArray;
  }

  private static CompilationResult findCompilation(TreeLogger logger,
      ArtifactSet artifacts) throws UnableToCompleteException {
    final SortedSet<CompilationResult> compilations = artifacts.find(CompilationResult.class);
    if (compilations.size() != 1) {
      logger.log(TreeLogger.ERROR, "Found " + compilations.size()
          + " permutations compiled in "
          + ExtensionLinker.class.getSimpleName()
          + ".  Use only a single permutation per module with this linker.");
      logPermutations(logger, compilations);
      throw new UnableToCompleteException();
    }
    return compilations.first();
  }

  private static ExtensionArtifact findExtensionArtifact(TreeLogger logger,
      ArtifactSet artifacts) throws UnableToCompleteException {
    final SortedSet<ExtensionArtifact> extensions = artifacts.find(ExtensionArtifact.class);
    if (extensions.size() != 1) {
      // TODO(knorton): Improve error message.
      logger.log(TreeLogger.ERROR, ExtensionLinker.class.getSimpleName()
          + ": got " + extensions.size()
          + " entry points, but there must be one per module.");
      throw new UnableToCompleteException();
    }

    return extensions.first();
  }

  private static String generateJsContents(TreeLogger logger,
      CompilationResult js) throws UnableToCompleteException {
    // Thou shalt not reference $doc or $wnd !!!
    String compiledJs = js.getJavaScript()[0];

    // Work around for GWT 2.0, there are 2 harmless $wnd references that creep
    // in
    checkForDisallowedJs(compiledJs, "\\$wnd", 2, logger);
    checkForDisallowedJs(compiledJs, "\\$doc", 0, logger);

    final StringBuffer buffer = new StringBuffer();   
    buffer.append("var $stats;\n").append(compiledJs).append("gwtOnLoad();\n");
    return buffer.toString();
  }

  private static String getJsFilename(LinkerContext context) {
    return context.getModuleName() + ".js";
  }

  private static void logPermutations(TreeLogger logger,
      Collection<CompilationResult> compilations) {
    int count = 0;
    for (CompilationResult compilationResult : compilations) {
      SortedSet<SortedMap<SelectionProperty, String>> propertyMap = compilationResult.getPropertyMap();
      StringBuilder builder = new StringBuilder();
      for (SortedMap<SelectionProperty, String> propertySubMap : propertyMap) {
        builder.append("{");
        for (Entry<SelectionProperty, String> entry : propertySubMap.entrySet()) {

          SelectionProperty selectionProperty = entry.getKey();
          if (!selectionProperty.isDerived()) {
            builder.append(selectionProperty.getName() + ":" + entry.getValue()
                + " ");
          }
        }
        builder.append("}");
      }
      logger.log(TreeLogger.ERROR, "Permutation " + count + ": "
          + builder.toString());
      count++;
    }
  }

  @Override
  public String getDescription() {
    return "Chrome Extension Linker";
  }

  @Override
  public ArtifactSet link(TreeLogger logger, LinkerContext context,
      ArtifactSet artifacts) throws UnableToCompleteException {
    // Retrieve the spec for the extension.
    final ExtensionArtifact extension = findExtensionArtifact(logger, artifacts);

    // Retrieve the PageActions.
    final SortedSet<PageActionArtifact> pageActions = artifacts.find(PageActionArtifact.class);

    // Retrieve the BrowserAction (should be a collection of size one).
    final SortedSet<BrowserActionArtifact> browserActions = artifacts.find(BrowserActionArtifact.class);

    // Retrieve the ContentScripts
    final SortedSet<ContentScriptArtifact> contentScripts = artifacts.find(ContentScriptArtifact.class);

    // Retrieve the plugins.
    final SortedSet<PluginArtifact> plugins = artifacts.find(PluginArtifact.class);

    // Retrieve the compilation.
    final CompilationResult compilation = findCompilation(logger, artifacts);

    String backgroundPageFileName = getJsFilename(context);
    return addArtifacts(artifacts, emitString(logger, generateJsContents(
        logger, compilation), backgroundPageFileName), emitString(logger,
        generateManifestContents(logger, backgroundPageFileName, extension,
            pageActions, browserActions, contentScripts, plugins),
        "manifest.json"));
  }

  private JsonObject createBrowserAction(
      SortedSet<BrowserActionArtifact> browserActions) {
    int size = browserActions.size();
    if (size == 0) {
      return null;
    }
    // TODO(jaimeyap): This should really be a user error and not an assertion
    // failure.
    assert (size == 1) : "Only 1 BrowserAction per extension allowed.";
    BrowserActionArtifact browserAction = browserActions.first();
    final JsonObject browserActionObject = JsonObject.create();
    browserActionObject.put("name", browserAction.getName());
    final JsonArray iconsArray = JsonArray.create();
    String[] icons = browserAction.getIcons();
    for (String icon : icons) {
      iconsArray.add(icon);
    }
    browserActionObject.put("icons", iconsArray);
    browserActionObject.put("default_icon", browserAction.getDefaultIcon());

    return browserActionObject;
  }

  private String generateManifestContents(TreeLogger logger,
      String backgroundPageFileName, ExtensionArtifact extension,
      SortedSet<PageActionArtifact> pageActions,
      SortedSet<BrowserActionArtifact> browserActions,
      SortedSet<ContentScriptArtifact> contentScripts,
      SortedSet<PluginArtifact> plugins) throws UnableToCompleteException {
    final JsonObject config = JsonObject.create();
    config.put("name", extension.getName());
    config.put("version", extension.getVersion());

    if (!extension.getUpdateUrl().equals(Extension.NO_UPDATE_URL)) {
      config.put("update_url", extension.getUpdateUrl());
    }

    // All other fields in the manifest are optional
    if (extension.getDescription().length() > 0) {
      config.put("description", extension.getDescription());
    }
    if (backgroundPageFileName.length() > 0) {
      config.put("background", createBgScriptsObject(backgroundPageFileName));
    }
    if (contentScripts.size() > 0) {
      config.put("content_scripts", createContentScriptsArray(contentScripts));
    }
    if (pageActions.size() > 0) {
      config.put("page_actions", createPageActionsArray(pageActions));
    }

    if (browserActions.size() > 0) {
      JsonValue browserAction = createBrowserAction(browserActions);
      if (browserAction != null) {
        config.put("browser_action", browserAction);
      }
    }

    if (plugins.size() > 0) {
      config.put("plugins", createPluginsArray(plugins));
    }

    if (extension.getPermissions().length > 0) {
      final JsonArray perms = JsonArray.create();
      for (String perm : extension.getPermissions()) {
        perms.add(perm);
      }
      config.put("permissions", perms);
    }

    if (extension.getIcons().length > 0) {
      JsonObject icons = JsonObject.create();
      for (IconInfo info : extension.getIcons()) {
        icons.put(Integer.toString(info.getSize()), info.getFilename());
      }
      config.put("icons", icons);
    }

    if (extension.getPublicKey().length() > 0) {
      config.put("key", extension.getPublicKey());
    }
    config.put("manifest_version", 2);   
    final StringWriter writer = new StringWriter();
    try {
      config.write(writer);
    } catch (IOException e) {
      logger.log(TreeLogger.ERROR, "Unexpected error.", e);
      throw new UnableToCompleteException();
    }
    return writer.toString();
  }
}
TOP

Related Classes of com.google.gwt.chrome.crx.linker.ExtensionLinker

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.