PrecompiledTemplateMapFileReader.java revision 56ed4167b942ec265f9cee70ac4d71d10b3835ce
1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Copyright (C) 2010 Google Inc.
3ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
4ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Licensed under the Apache License, Version 2.0 (the "License");
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * you may not use this file except in compliance with the License.
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * You may obtain a copy of the License at
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * http://www.apache.org/licenses/LICENSE-2.0
9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Unless required by applicable law or agreed to in writing, software
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * distributed under the License is distributed on an "AS IS" BASIS,
12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * See the License for the specific language governing permissions and
14ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * limitations under the License.
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querupackage com.google.clearsilver.jsilver.precompiler;
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport com.google.clearsilver.jsilver.autoescape.EscapeMode;
20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport com.google.clearsilver.jsilver.exceptions.JSilverAutoEscapingException;
21ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport com.google.common.annotations.VisibleForTesting;
22ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport com.google.common.collect.ImmutableMap;
23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport java.io.FileNotFoundException;
25ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport java.io.IOException;
26ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport java.io.InputStream;
27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport java.io.InputStreamReader;
28ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport java.io.LineNumberReader;
29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport java.io.Reader;
30ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport java.util.HashMap;
31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport java.util.Map;
32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruimport java.util.StringTokenizer;
33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Utility class that reads in the file output by BatchCompiler that is a list of template names and
36ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * corresponding class names and returns a Map of template filenames to class names which can be fed
37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * to {@see com.google.clearsilver.jsilver.JSilverOptions#setPrecompiledTemplateMap}
38ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
39ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querupublic class PrecompiledTemplateMapFileReader {
40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
41ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  private final String mapFileName;
42ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  private final String dirPattern;
43ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  private final String rootDir;
44ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
45ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  private Map<Object, String> templateMap = null;
46ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
47ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  /**
48ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru   * Helper object that reads in the specified resource file and generates a mapping of template
49ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru   * filenames to corresponding BaseCompiledTemplate class names.
50ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru   *
51ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru   * @param filename name of the resource file to read the map from.
52ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru   * @param dirPattern prefix to remove from read in template names. Used in conjunction with
53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru   *        rootDir to update template file paths.
54ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru   * @param rootDir optional string to prepend to all non-absolute template filenames. Should be set
55ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru   *        to the location of the templates in production via a flag.
56ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru   */
57ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  public PrecompiledTemplateMapFileReader(String filename, String dirPattern, String rootDir) {
58ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    this.mapFileName = filename;
59ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    this.dirPattern = dirPattern;
60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    this.rootDir = rootDir;
61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  }
62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  public Map<Object, String> getTemplateMap() throws IOException {
64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (templateMap == null) {
65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      templateMap = makeTemplateMap(mapFileName, rootDir);
66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return templateMap;
68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  }
69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  private Map<Object, String> makeTemplateMap(String templateMapFile, String rootDir)
71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      throws IOException {
72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    Map<Object, String> templateMap = new HashMap<Object, String>();
73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    LineNumberReader reader = null;
74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    try {
75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      reader = new LineNumberReader(getMapFileReader(templateMapFile));
76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      for (String line = reader.readLine(); line != null; line = reader.readLine()) {
77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Process single line from the templateMapFile
78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // and put found templates into templateMap.
79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        processTemplateMapFileLine(line, reader.getLineNumber(), templateMap, templateMapFile,
80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            rootDir);
81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      }
82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } finally {
83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      if (reader != null) {
84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        reader.close();
85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      }
86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return ImmutableMap.copyOf(templateMap);
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  }
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  private void processTemplateMapFileLine(String line, int lineNumber,
91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      Map<Object, String> templateMap, String templateMapFile, String rootDir) {
92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    line = line.trim();
94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (line.isEmpty() || line.startsWith("#")) {
95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      // Ignore blank lines and comment lines.
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru      return;
97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    StringTokenizer st = new StringTokenizer(line);
99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (!st.hasMoreTokens()) {
100      throw new IllegalArgumentException("No template file name found in " + templateMapFile
101          + " on line " + lineNumber + ": " + line);
102    }
103    String templateName = st.nextToken();
104    if (dirPattern != null && templateName.startsWith(dirPattern)) {
105      templateName = templateName.substring(dirPattern.length());
106    }
107    if (rootDir != null) {
108      // If it is not an absolute path and we were given a root directory,
109      // prepend it.
110      templateName = rootDir + templateName;
111    }
112    if (!st.hasMoreTokens()) {
113      throw new IllegalArgumentException("No class name found in " + templateMapFile + " on line "
114          + lineNumber + ": " + line);
115    }
116    String className = st.nextToken();
117    EscapeMode escapeMode;
118    if (!st.hasMoreTokens()) {
119      escapeMode = EscapeMode.ESCAPE_NONE;
120    } else {
121      String escapeCmd = st.nextToken();
122      try {
123        escapeMode = EscapeMode.computeEscapeMode(escapeCmd);
124      } catch (JSilverAutoEscapingException e) {
125        throw new IllegalArgumentException("Invalid escape mode found in " + templateMapFile
126            + " on line " + lineNumber + ": " + escapeCmd);
127      }
128    }
129    PrecompiledTemplateMapKey key = new PrecompiledTemplateMapKey(templateName, escapeMode);
130    templateMap.put(key, className);
131  }
132
133  @VisibleForTesting
134  protected Reader getMapFileReader(String templateMapFile) throws IOException {
135    ClassLoader classLoader = getClass().getClassLoader();
136    InputStream in = classLoader.getResourceAsStream(templateMapFile);
137    if (in == null) {
138      throw new FileNotFoundException("Unable to locate resource: " + templateMapFile);
139    }
140    return new InputStreamReader(in, "UTF-8");
141  }
142
143}
144