156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/*
256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc.
356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License");
556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License.
656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at
756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0
956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software
1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS,
1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and
1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License.
1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage com.google.clearsilver.jsilver.precompiler;
1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.autoescape.EscapeMode;
2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.JSilverAutoEscapingException;
2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.common.annotations.VisibleForTesting;
2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.common.collect.ImmutableMap;
2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.FileNotFoundException;
2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException;
2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.InputStream;
2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.InputStreamReader;
2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.LineNumberReader;
2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.Reader;
3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.HashMap;
3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.Map;
3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.StringTokenizer;
3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/**
3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Utility class that reads in the file output by BatchCompiler that is a list of template names and
3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * corresponding class names and returns a Map of template filenames to class names which can be fed
3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * to {@see com.google.clearsilver.jsilver.JSilverOptions#setPrecompiledTemplateMap}
3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class PrecompiledTemplateMapFileReader {
4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final String mapFileName;
4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final String dirPattern;
4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final String rootDir;
4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private Map<Object, String> templateMap = null;
4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Helper object that reads in the specified resource file and generates a mapping of template
4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * filenames to corresponding BaseCompiledTemplate class names.
5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param filename name of the resource file to read the map from.
5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param dirPattern prefix to remove from read in template names. Used in conjunction with
5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *        rootDir to update template file paths.
5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param rootDir optional string to prepend to all non-absolute template filenames. Should be set
5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *        to the location of the templates in production via a flag.
5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public PrecompiledTemplateMapFileReader(String filename, String dirPattern, String rootDir) {
5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.mapFileName = filename;
5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.dirPattern = dirPattern;
6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.rootDir = rootDir;
6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public Map<Object, String> getTemplateMap() throws IOException {
6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (templateMap == null) {
6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      templateMap = makeTemplateMap(mapFileName, rootDir);
6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return templateMap;
6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private Map<Object, String> makeTemplateMap(String templateMapFile, String rootDir)
7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throws IOException {
7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Map<Object, String> templateMap = new HashMap<Object, String>();
7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    LineNumberReader reader = null;
7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    try {
7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      reader = new LineNumberReader(getMapFileReader(templateMapFile));
7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      for (String line = reader.readLine(); line != null; line = reader.readLine()) {
7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        // Process single line from the templateMapFile
7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        // and put found templates into templateMap.
7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        processTemplateMapFileLine(line, reader.getLineNumber(), templateMap, templateMapFile,
8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson            rootDir);
8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } finally {
8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (reader != null) {
8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        reader.close();
8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return ImmutableMap.copyOf(templateMap);
8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void processTemplateMapFileLine(String line, int lineNumber,
9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      Map<Object, String> templateMap, String templateMapFile, String rootDir) {
9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    line = line.trim();
9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (line.isEmpty() || line.startsWith("#")) {
9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Ignore blank lines and comment lines.
9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return;
9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    StringTokenizer st = new StringTokenizer(line);
9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (!st.hasMoreTokens()) {
10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new IllegalArgumentException("No template file name found in " + templateMapFile
10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          + " on line " + lineNumber + ": " + line);
10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String templateName = st.nextToken();
10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (dirPattern != null && templateName.startsWith(dirPattern)) {
10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      templateName = templateName.substring(dirPattern.length());
10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (rootDir != null) {
10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // If it is not an absolute path and we were given a root directory,
10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // prepend it.
11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      templateName = rootDir + templateName;
11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (!st.hasMoreTokens()) {
11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new IllegalArgumentException("No class name found in " + templateMapFile + " on line "
11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          + lineNumber + ": " + line);
11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String className = st.nextToken();
11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    EscapeMode escapeMode;
11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (!st.hasMoreTokens()) {
11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      escapeMode = EscapeMode.ESCAPE_NONE;
12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      String escapeCmd = st.nextToken();
12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      try {
12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        escapeMode = EscapeMode.computeEscapeMode(escapeCmd);
12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      } catch (JSilverAutoEscapingException e) {
12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        throw new IllegalArgumentException("Invalid escape mode found in " + templateMapFile
12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson            + " on line " + lineNumber + ": " + escapeCmd);
12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    PrecompiledTemplateMapKey key = new PrecompiledTemplateMapKey(templateName, escapeMode);
13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    templateMap.put(key, className);
13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @VisibleForTesting
13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  protected Reader getMapFileReader(String templateMapFile) throws IOException {
13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    ClassLoader classLoader = getClass().getClassLoader();
13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    InputStream in = classLoader.getResourceAsStream(templateMapFile);
13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (in == null) {
13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new FileNotFoundException("Unable to locate resource: " + templateMapFile);
13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return new InputStreamReader(in, "UTF-8");
14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson}
144