Package com.google.caja.plugin

Source Code of com.google.caja.plugin.PluginCompilerMain$CachingUriFetcher

// Copyright (C) 2006 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.caja.plugin;

import com.google.caja.SomethingWidgyHappenedError;
import com.google.caja.lexer.ExternalReference;
import com.google.caja.lexer.FetchedData;
import com.google.caja.lexer.InputSource;
import com.google.caja.lexer.ParseException;
import com.google.caja.lexer.TokenConsumer;
import com.google.caja.parser.ParseTreeNode;
import com.google.caja.parser.ParserContext;
import com.google.caja.parser.html.Nodes;
import com.google.caja.parser.js.CajoledModule;
import com.google.caja.plugin.UriFetcher.ChainingUriFetcher;
import com.google.caja.render.Concatenator;
import com.google.caja.render.JsMinimalPrinter;
import com.google.caja.reporting.BuildInfo;
import com.google.caja.reporting.Message;
import com.google.caja.reporting.MessageContext;
import com.google.caja.reporting.MessageLevel;
import com.google.caja.reporting.MessagePart;
import com.google.caja.reporting.MessageQueue;
import com.google.caja.reporting.MessageType;
import com.google.caja.reporting.RenderContext;
import com.google.caja.reporting.SimpleMessageQueue;
import com.google.caja.util.Callback;
import com.google.caja.util.Charsets;
import com.google.caja.util.Maps;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.URI;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.w3c.dom.Node;

/**
* An executable that invokes the {@link PluginCompiler}.
*
* @author mikesamuel@gmail.com
*/
public final class PluginCompilerMain {
  private final MessageQueue mq;
  private final MessageContext mc;
  private final Map<InputSource, CharSequence> originalSources
      = Maps.newHashMap();
  private final Config config = new Config(
      getClass(), System.err, "Cajoles HTML, CSS, and JS files to JS.");
  private final Callback<IOException> exHandler = new Callback<IOException>() {
    public void handle(IOException ex) {
      mq.addMessage(
          MessageType.IO_ERROR, MessagePart.Factory.valueOf(ex.toString()));
    }
  };

  private class CachingUriFetcher extends FileSystemUriFetcher {
    public CachingUriFetcher(UriToFile u2f) { super(u2f); }

    @Override
    protected Reader newReader(File f) throws FileNotFoundException {
      return createReader(new FileInputStream(f));
    }

    @Override
    protected InputStream newInputStream(File f) throws FileNotFoundException {
      return new FileInputStream(f);
    }
  }

  private PluginCompilerMain() {
    mq = new SimpleMessageQueue();
    mc = new MessageContext();
  }

  private int run(String[] argv) {
    if (!config.processArguments(argv)) {
      return -1;
    }
    if (config.getBenchmark() == 0) {
      return runOnce(true);
    } else {
      runBench(argv, false);
      runBench(argv, true);
      pause();
      return 0;
    }
  }

  private int runOnce(boolean writeFiles) {
    boolean success = false;
    MessageContext mc = null;
    CajoledModule compiledJsOutput = null;
    Node compiledDomOutput = null;
    String compiledHtmlOutput = null;
    File fileLimitAncestor = config.getFetcherBase();

    File jsOutputDest = config.getOutputJsFile();
    File htmlOutputDest = config.getOutputHtmlFile();

    try {
      UriFetcher fetcher;
      UriPolicy policy;
      try {
        if (fileLimitAncestor != null) {
          UriToFile u2f = new UriToFile(fileLimitAncestor);
          fetcher = ChainingUriFetcher.make(
              new DataUriFetcher(),
              new CachingUriFetcher(u2f));
          policy = new FileSystemUriPolicy(u2f);
        } else {
          fetcher = new DataUriFetcher();
          policy = UriPolicy.DENY_ALL;
        }
      } catch (IOException e) {  // Could not resolve file name
        fetcher = new DataUriFetcher();
        policy = UriPolicy.DENY_ALL;
      }
      final Set<String> lUrls = config.getLinkableUris();
      if (!lUrls.isEmpty()) {
        final UriPolicy prePolicy = policy;
        policy = new UriPolicy() {
          public String rewriteUri(
              ExternalReference u, UriEffect effect,
              LoaderType loader, Map<String, ?> hints) {
            String uri = u.getUri().toString();
            if (lUrls.contains(uri)) { return uri; }
            return prePolicy.rewriteUri(u, effect, loader, hints);
          }
        };
      }
      final Set<String> fUris = config.getFetchableUris();
      final boolean fUriAll = config.hasFetchableUriAll();
      if (fUriAll || !fUris.isEmpty()) {
        fetcher = ChainingUriFetcher.make(
            fetcher,
            new UriFetcher() {
              public FetchedData fetch(ExternalReference ref, String mimeType)
                  throws UriFetchException {
                String uri = ref.getUri().toString();
                if (!fUriAll && !fUris.contains(uri)) {
                  throw new UriFetchException(ref, mimeType);
                }
                try {
                  return FetchedData.fromConnection(
                      new URL(uri).openConnection());
                } catch (IOException ex) {
                  throw new UriFetchException(ref, mimeType, ex);
                }
              }
            });
      }

      if (config.hasLinkableUriAll()) {
        policy = UriPolicy.IDENTITY;
      } else if (config.hasLinkableUriRuntime()) {
        policy = null;
      }

      PluginMeta meta = new PluginMeta(fetcher, policy);
      meta.setIdClass(config.getIdClass());
      meta.setPrecajoleMinify(
          config.renderer() == Config.SourceRenderMode.MINIFY);
      if (config.hasNoPrecajoled()) {
        meta.setPrecajoleMap(null);
      }

      PluginCompiler compiler = new PluginCompiler(
          BuildInfo.getInstance(), meta, mq);
      compiler.setPreconditions(
          config.preconditions(compiler.getPreconditions()));
      compiler.setGoals(config.goals(compiler.getGoals()));

      mc = compiler.getMessageContext();
      compiler.setCssSchema(config.getCssSchema(mq));
      compiler.setHtmlSchema(config.getHtmlSchema(mq));

      success = parseInputs(meta, config.getInputUris(), compiler)
          && compiler.run();
      if (success) {
        compiledJsOutput = compiler.getJavascript();
        compiledDomOutput = compiler.getStaticHtml();
        compiledHtmlOutput = compiledDomOutput != null ?
            Nodes.render(compiledDomOutput) : "";
      }
    } finally {
      if (mc == null) { mc = new MessageContext(); }
      MessageLevel maxMessageLevel = dumpMessages(mq, mc, System.err);
      success &= MessageLevel.ERROR.compareTo(maxMessageLevel) > 0;
    }

    if (!writeFiles) {
      return success ? 0 : -1;
    }

    if (success) {
      if (jsOutputDest != null) {
        writeFile(jsOutputDest, compiledJsOutput);
      } else {
        StringBuilder compiledJsOutputBuf = new StringBuilder();
        compiledJsOutputBuf.append("<script>");
        try {
          writeFile(compiledJsOutputBuf, compiledJsOutput);
        } catch (IOException ex) {
          throw new SomethingWidgyHappenedError(ex);
        }
        compiledJsOutputBuf.append("</script>");
        compiledHtmlOutput += compiledJsOutputBuf;
      }
      if (htmlOutputDest != null) {
        writeFile(htmlOutputDest, compiledHtmlOutput);
      }
    } else {
      // Make sure there is no previous output file from a failed run.
      if (jsOutputDest != null) { jsOutputDest.delete(); }
      if (htmlOutputDest != null) { htmlOutputDest.delete(); }
      // If it wasn't there in the first place, or is not writable, that's OK,
      // so ignore the return value.
    }

    return success ? 0 : -1;
  }

  private boolean parseInputs(PluginMeta meta, Collection<URI> inputs,
      PluginCompiler pluginc) {
    boolean parsePassed = true;
    for (URI input : inputs) {
      try {
        ParseTreeNode parseTree = new ParserContext(mq)
            .withInput(new InputSource(input))
            .withConfig(meta)
            .withConfig(mc)
            .withSourceMap(originalSources)
            .build();
        if (null != parseTree) { pluginc.addInput(parseTree, input); }
      } catch (ParseException ex) {
        ex.toMessageQueue(mq);
        parsePassed = false;
      } catch (IOException ex) {
        mq.addMessage(MessageType.IO_ERROR,
                      MessagePart.Factory.valueOf(ex.toString()));
        parsePassed = false;
      }
    }
    return parsePassed;
  }

  /** Write the given HTML to the given file. */
  private void writeFile(File outputHtmlFile, String compiledHtmlOutput) {
    try {
      OutputStreamWriter out = new OutputStreamWriter(
            new FileOutputStream(outputHtmlFile), Charsets.UTF_8);
      try {
        out.append(compiledHtmlOutput);
      } finally {
        try { out.close(); } catch (IOException e) { /* close quietly */ }
      }
    } catch (IOException ex) {
      exHandler.handle(ex);
    }
  }

  /** Write the given parse tree to the given file. */
  private void writeFile(File f, CajoledModule module) {
    if (module == null) { return; }

    Writer out = null;

    try {
      out = new OutputStreamWriter(new FileOutputStream(f), Charsets.UTF_8);
      writeFile(out, module);
    } catch (IOException ex) {
      ex.printStackTrace();
    } finally {
      if (out != null) {
        try {
          out.close();
        } catch (IOException e) {
          /* no zero-argument ctor */
        }
      }
    }
  }

  private void writeFile(Appendable out, CajoledModule module)
      throws IOException {
    TokenConsumer tc;
    switch (config.renderer()) {
      case PRETTY:
        tc = module.makeRenderer(out, exHandler);
        break;
      case MINIFY:
        tc = new JsMinimalPrinter(new Concatenator(out,  exHandler));
        break;
      default:
        throw new SomethingWidgyHappenedError(
            "Unrecognized renderer: " + config.renderer());
    }
    RenderContext rc = new RenderContext(tc);
    module.render(rc);
    tc.noMoreTokens();
    out.append('\n');
  }

  /**
   * Dumps messages to the given output stream, returning the highest message
   * level seen.
   */
  static MessageLevel dumpMessages(
      MessageQueue mq, MessageContext mc, Appendable out) {
    MessageLevel maxLevel = MessageLevel.values()[0];
    for (Message m : mq.getMessages()) {
      MessageLevel level = m.getMessageLevel();
      if (maxLevel.compareTo(level) < 0) { maxLevel = level; }
    }
    MessageLevel ignoreLevel = null;
    if (maxLevel.compareTo(MessageLevel.LINT) < 0) {
      // If there's only checkpoints, be quiet.
      ignoreLevel = MessageLevel.LOG;
    }
    try {
      for (Message m : mq.getMessages()) {
        MessageLevel level = m.getMessageLevel();
        if (ignoreLevel != null && level.compareTo(ignoreLevel) <= 0) {
          continue;
        }
        String levelName = level.name();
        out.append(levelName);
        if (levelName.length() < 7) {
          out.append("       ".substring(levelName.length()));
        }
        out.append(": ");
        m.format(mc, out);
        out.append("\n");

        if (maxLevel.compareTo(level) < 0) { maxLevel = level; }
      }
    } catch (IOException ex) {
      ex.printStackTrace();
    }
    return maxLevel;
  }

  private Reader createReader(InputStream stream) {
    return new InputStreamReader(stream, Charsets.UTF_8);
  }

  public static void main(String[] args) {
    int exitCode;
    try {
      PluginCompilerMain main = new PluginCompilerMain();
      exitCode = main.run(args);
    } catch (Exception ex) {
      ex.printStackTrace();
      exitCode = -1;
    }
    try {
      System.exit(exitCode);
    } catch (SecurityException ex) {
      // This method may be invoked under a SecurityManager, e.g. by Ant,
      // so just suppress the security exception and return normally.
    }
  }

  private void pause() {
    try {
      BufferedReader b = new BufferedReader(new InputStreamReader(System.in));
      System.out.println("press return...");
      b.readLine();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  private void runBench(String[] argv, boolean warm) {
    pause();

    int trials = Math.max(config.getBenchmark(), 1);
    long first_time = 0;
    long all_times = 0;

    for (int i = 0; i < trials; i++) {
      long t0 = System.nanoTime();
      runBenchOnce(argv);
      long dt = System.nanoTime() - t0;
      all_times += dt;
      if (i == 0) {
        first_time = dt;
      }
    }

    DecimalFormat fmt = new DecimalFormat("#.## msec");
    if (!warm) {
      System.out.println(
          fmt.format(first_time / 1e6) + ": first run");
    }
    System.out.println(
        fmt.format(all_times / (trials * 1e6)) + ": all runs");
  }

  private void runBenchOnce(String[] argv) {
    // We create a new PluginCompilerMain because it's not re-usable.
    PluginCompilerMain pc = new PluginCompilerMain();
    pc.config.processArguments(argv);
    pc.runOnce(false);
  }
}
TOP

Related Classes of com.google.caja.plugin.PluginCompilerMain$CachingUriFetcher

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.