PrecompiledTemplateLoader.java revision 56ed4167b942ec265f9cee70ac4d71d10b3835ce
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
17package com.google.clearsilver.jsilver.precompiler;
18
19import com.google.clearsilver.jsilver.autoescape.AutoEscapeOptions;
20import com.google.clearsilver.jsilver.autoescape.EscapeMode;
21import com.google.clearsilver.jsilver.compiler.BaseCompiledTemplate;
22import com.google.clearsilver.jsilver.functions.FunctionExecutor;
23import com.google.clearsilver.jsilver.resourceloader.ResourceLoader;
24import com.google.clearsilver.jsilver.template.DelegatingTemplateLoader;
25import com.google.clearsilver.jsilver.template.Template;
26import com.google.clearsilver.jsilver.template.TemplateLoader;
27import com.google.common.annotations.VisibleForTesting;
28import com.google.common.collect.ImmutableMap;
29import java.util.HashMap;
30import java.util.Map;
31
32/**
33 * TemplateLoader that stores objects from precompiled Template classes and serves them when asked
34 * for them. If not found, it passes the request on to the delegate TemplateLoader.
35 */
36public class PrecompiledTemplateLoader implements DelegatingTemplateLoader {
37
38  /**
39   * This is the next TemplateLoader to ask if we don't find the template.
40   */
41  private final TemplateLoader nextLoader;
42
43  private final Map<Object, BaseCompiledTemplate> templateMap;
44  private final AutoEscapeOptions autoEscapeOptions;
45
46  public PrecompiledTemplateLoader(TemplateLoader nextLoader,
47      Map<Object, String> templateToClassNameMap, FunctionExecutor globalFunctionExecutor,
48      AutoEscapeOptions autoEscapeOptions) {
49    this.nextLoader = nextLoader;
50    this.autoEscapeOptions = autoEscapeOptions;
51    this.templateMap = makeTemplateMap(templateToClassNameMap, globalFunctionExecutor);
52  }
53
54  private Map<Object, BaseCompiledTemplate> makeTemplateMap(
55      Map<Object, String> templateToClassNameMap, FunctionExecutor globalFunctionExecutor) {
56    Map<Object, BaseCompiledTemplate> templateMap = new HashMap<Object, BaseCompiledTemplate>();
57    ClassLoader classLoader = getClass().getClassLoader();
58    for (Map.Entry<Object, String> entry : templateToClassNameMap.entrySet()) {
59      String className = entry.getValue();
60      BaseCompiledTemplate compiledTemplate = loadTemplateObject(className, classLoader);
61      // Fill in the necessary
62      compiledTemplate.setFunctionExecutor(globalFunctionExecutor);
63      compiledTemplate.setTemplateName(entry.getKey().toString());
64      compiledTemplate.setTemplateLoader(this);
65      if (entry.getKey() instanceof PrecompiledTemplateMapKey) {
66        PrecompiledTemplateMapKey mapKey = (PrecompiledTemplateMapKey) entry.getKey();
67        // The template's escapeMode is not currently used as the autoescaping is all
68        // handled at compile time. Still set it in case it is needed later on.
69        compiledTemplate.setEscapeMode(mapKey.getEscapeMode());
70      } else {
71        compiledTemplate.setEscapeMode(EscapeMode.ESCAPE_NONE);
72      }
73      compiledTemplate.setAutoEscapeOptions(autoEscapeOptions);
74      templateMap.put(entry.getKey(), compiledTemplate);
75    }
76    return ImmutableMap.copyOf(templateMap);
77  }
78
79  @VisibleForTesting
80  protected BaseCompiledTemplate loadTemplateObject(String className, ClassLoader classLoader) {
81    try {
82      Class<?> templateClass = classLoader.loadClass(className);
83      // TODO: Not safe to use in untrusted environments
84      // Does not handle ClassCastException or
85      // verify class type before calling newInstance.
86      return (BaseCompiledTemplate) templateClass.newInstance();
87    } catch (ClassNotFoundException e) {
88      throw new IllegalArgumentException("Class not found: " + className, e);
89    } catch (IllegalAccessException e) {
90      throw new Error(e);
91    } catch (InstantiationException e) {
92      throw new Error(e);
93    }
94  }
95
96  @Override
97  public void setTemplateLoaderDelegate(TemplateLoader templateLoaderDelegate) {
98    for (BaseCompiledTemplate template : templateMap.values()) {
99      template.setTemplateLoader(templateLoaderDelegate);
100    }
101  }
102
103  @Override
104  public Template load(String templateName, ResourceLoader resourceLoader, EscapeMode escapeMode) {
105    Object key = resourceLoader.getKey(templateName);
106    PrecompiledTemplateMapKey mapKey = new PrecompiledTemplateMapKey(key, escapeMode);
107    Template template = templateMap.get(mapKey);
108    if (template != null) {
109      return template;
110    } else {
111      return nextLoader.load(templateName, resourceLoader, escapeMode);
112    }
113  }
114
115  /**
116   * We don't cache temporary templates here so we just call delegate TemplateLoader.
117   */
118  @Override
119  public Template createTemp(String name, String content, EscapeMode escapeMode) {
120    return nextLoader.createTemp(name, content, escapeMode);
121  }
122}
123