1 /* 2 * Copyright (C) 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.clearsilver.jsilver.precompiler; 18 19 import com.google.clearsilver.jsilver.autoescape.EscapeMode; 20 import com.google.clearsilver.jsilver.exceptions.JSilverAutoEscapingException; 21 import com.google.common.annotations.VisibleForTesting; 22 import com.google.common.collect.ImmutableMap; 23 24 import java.io.FileNotFoundException; 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.io.InputStreamReader; 28 import java.io.LineNumberReader; 29 import java.io.Reader; 30 import java.util.HashMap; 31 import java.util.Map; 32 import java.util.StringTokenizer; 33 34 /** 35 * Utility class that reads in the file output by BatchCompiler that is a list of template names and 36 * corresponding class names and returns a Map of template filenames to class names which can be fed 37 * to {@see com.google.clearsilver.jsilver.JSilverOptions#setPrecompiledTemplateMap} 38 */ 39 public class PrecompiledTemplateMapFileReader { 40 41 private final String mapFileName; 42 private final String dirPattern; 43 private final String rootDir; 44 45 private Map<Object, String> templateMap = null; 46 47 /** 48 * Helper object that reads in the specified resource file and generates a mapping of template 49 * filenames to corresponding BaseCompiledTemplate class names. 50 * 51 * @param filename name of the resource file to read the map from. 52 * @param dirPattern prefix to remove from read in template names. Used in conjunction with 53 * rootDir to update template file paths. 54 * @param rootDir optional string to prepend to all non-absolute template filenames. Should be set 55 * to the location of the templates in production via a flag. 56 */ PrecompiledTemplateMapFileReader(String filename, String dirPattern, String rootDir)57 public PrecompiledTemplateMapFileReader(String filename, String dirPattern, String rootDir) { 58 this.mapFileName = filename; 59 this.dirPattern = dirPattern; 60 this.rootDir = rootDir; 61 } 62 getTemplateMap()63 public Map<Object, String> getTemplateMap() throws IOException { 64 if (templateMap == null) { 65 templateMap = makeTemplateMap(mapFileName, rootDir); 66 } 67 return templateMap; 68 } 69 makeTemplateMap(String templateMapFile, String rootDir)70 private Map<Object, String> makeTemplateMap(String templateMapFile, String rootDir) 71 throws IOException { 72 Map<Object, String> templateMap = new HashMap<Object, String>(); 73 LineNumberReader reader = null; 74 try { 75 reader = new LineNumberReader(getMapFileReader(templateMapFile)); 76 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 77 // Process single line from the templateMapFile 78 // and put found templates into templateMap. 79 processTemplateMapFileLine(line, reader.getLineNumber(), templateMap, templateMapFile, 80 rootDir); 81 } 82 } finally { 83 if (reader != null) { 84 reader.close(); 85 } 86 } 87 return ImmutableMap.copyOf(templateMap); 88 } 89 processTemplateMapFileLine(String line, int lineNumber, Map<Object, String> templateMap, String templateMapFile, String rootDir)90 private void processTemplateMapFileLine(String line, int lineNumber, 91 Map<Object, String> templateMap, String templateMapFile, String rootDir) { 92 93 line = line.trim(); 94 if (line.isEmpty() || line.startsWith("#")) { 95 // Ignore blank lines and comment lines. 96 return; 97 } 98 StringTokenizer st = new StringTokenizer(line); 99 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 getMapFileReader(String templateMapFile)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