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;
18
19import com.google.clearsilver.jsilver.autoescape.EscapeMode;
20import com.google.clearsilver.jsilver.data.NoOpStringInternStrategy;
21import com.google.clearsilver.jsilver.data.StringInternStrategy;
22
23import java.util.Map;
24
25/**
26 * Options for JSilver.
27 *
28 * Note: Setter methods also return reference to this, allowing options to be defined in one
29 * statement.
30 *
31 * e.g. new JSilver(..., new JSilverOptions().setSomething(true).setAnother(false));
32 *
33 * @see JSilver
34 */
35public class JSilverOptions implements Cloneable {
36
37  private boolean cacheTemplates = true;
38  private boolean compileTemplates = false;
39  private int initialBufferSize = 8192;
40  private boolean ignoreAttributes = false;
41  private Map<Object, String> precompiledTemplateMap = null;
42  private boolean useStrongCacheReferences = false;
43  private EscapeMode escapeMode = EscapeMode.ESCAPE_NONE;
44  private boolean propagateEscapeStatus = false;
45
46  /**
47   * A pool of strings used to optimize HDF parsing.
48   *
49   * String interning has been shown to improve GC performance, but also to increase CPU usage. To
50   * avoid any possible unexpected changes in behavior it is disabled by default.
51   */
52  private StringInternStrategy stringInternStrategy = new NoOpStringInternStrategy();
53
54  /**
55   * This flag is used to enable logging of all variables whose values are modified by auto escaping
56   * or &lt;cs escape&gt; commands. These will be logged at {@code Level.WARNING}.
57   */
58  private boolean logEscapedVariables = false;
59  private boolean useOutputBufferPool = false;
60  private boolean stripHtmlWhiteSpace = false;
61  private boolean stripStructuralWhiteSpace = false;
62  private boolean allowGlobalDataModification = false;
63  private boolean keepTemplateCacheFresh = false;
64  private int loadPathCacheSize = 1000;
65
66  // When adding fields, ensure you:
67  // * add getter.
68  // * add setter (which returns this).
69  // * add to clone() method if necessary.
70
71  /**
72   * Set the initial size of the load path cache container. Setting this to 0 causes load path cache
73   * to be disabled.
74   */
75  public JSilverOptions setLoadPathCacheSize(int loadPathCacheSize) {
76    this.loadPathCacheSize = loadPathCacheSize;
77    return this;
78  }
79
80  /**
81   * @see #setLoadPathCacheSize(int)
82   */
83  public int getLoadPathCacheSize() {
84    return loadPathCacheSize;
85  }
86
87  /**
88   * Whether to cache templates. This will only ever load and parse a template from disk once. Best
89   * switched on for production but left off for production (so you can update templates without
90   * restarting).
91   */
92  public JSilverOptions setCacheTemplates(boolean cacheTemplates) {
93    this.cacheTemplates = cacheTemplates;
94    return this;
95  }
96
97  /**
98   * @see #setCacheTemplates(boolean)
99   */
100  public boolean getCacheTemplates() {
101    return cacheTemplates;
102  }
103
104  /**
105   * Compile templates to Java byte code. This slows down the initial render as it performs a
106   * compilation step, but then subsequent render are faster.
107   *
108   * Compiled templates are always cached.
109   *
110   * WARNING: This functionality is experimental. Use with caution.
111   */
112  public JSilverOptions setCompileTemplates(boolean compileTemplates) {
113    this.compileTemplates = compileTemplates;
114    return this;
115  }
116
117  /**
118   * @see #setCompileTemplates(boolean)
119   */
120  public boolean getCompileTemplates() {
121    return compileTemplates;
122  }
123
124  /**
125   * If set, then HDF attributes in HDF files will be ignored and not stored in the Data object
126   * filled by the parser. Default is {@code false}. Many applications use HDF attributes only in
127   * template preprocessing (like translation support) and never in production servers where the
128   * templates are rendered. By disabling attribute parsing, these applications can save on memory
129   * for storing HDF structures read from files.
130   */
131  public JSilverOptions setIgnoreAttributes(boolean ignoreAttributes) {
132    this.ignoreAttributes = ignoreAttributes;
133    return this;
134  }
135
136  /**
137   * @see #setIgnoreAttributes(boolean)
138   */
139  public boolean getIgnoreAttributes() {
140    return ignoreAttributes;
141  }
142
143  /**
144   * Initial buffer size used when rendering directly to a string.
145   */
146  public JSilverOptions setInitialBufferSize(int initialBufferSize) {
147    this.initialBufferSize = initialBufferSize;
148    return this;
149  }
150
151  /**
152   * @see #setInitialBufferSize(int)
153   */
154  public int getInitialBufferSize() {
155    return initialBufferSize;
156  }
157
158  /**
159   * Optional mapping of TemplateLoader keys to Template instances that will be queried when loading
160   * a template. If the Template is found it is returned. If not, the next template loader is
161   * consulted.
162   *
163   * @param precompiledTemplateMap map of TemplateLoader keys to corresponding class names that
164   *        should be valid BaseCompiledTemplate subclasses. Set to {@code null} (default) to not
165   *        load precompiled templates.
166   */
167  public JSilverOptions setPrecompiledTemplateMap(Map<Object, String> precompiledTemplateMap) {
168    this.precompiledTemplateMap = precompiledTemplateMap;
169    return this;
170  }
171
172  /**
173   * @see #setPrecompiledTemplateMap(java.util.Map)
174   * @return a mapping of TemplateLoader keys to corresponding BaseCompiledTemplate class names, or
175   *         {@code null} (default) if no precompiled templates should be preloaded.
176   */
177  public Map<Object, String> getPrecompiledTemplateMap() {
178    return precompiledTemplateMap;
179  }
180
181  /**
182   * If {@code true}, then the template cache will use strong persistent references for the values.
183   * If {@code false} (default) it will use soft references. Warning: The cache size is unbounded so
184   * only use this option if you have sufficient memory to load all the Templates into memory.
185   */
186  public JSilverOptions setUseStrongCacheReferences(boolean value) {
187    this.useStrongCacheReferences = value;
188    return this;
189  }
190
191  /**
192   * @see #setUseStrongCacheReferences(boolean)
193   */
194  public boolean getUseStrongCacheReferences() {
195    return useStrongCacheReferences;
196  }
197
198  /**
199   * @see #setEscapeMode(com.google.clearsilver.jsilver.autoescape.EscapeMode)
200   */
201  public EscapeMode getEscapeMode() {
202    return escapeMode;
203  }
204
205  /**
206   * Escape any template being rendered with the given escaping mode. If the mode is ESCAPE_HTML,
207   * ESCAPE_URL or ESCAPE_JS, the corresponding escaping will be all variables in the template. If
208   * the mode is ESCAPE_AUTO, enable <a href="http://go/autoescapecs">auto escaping</a> on
209   * templates. For each variable in the template, this will determine what type of escaping should
210   * be applied to the variable, and automatically apply this escaping. This flag can be overriden
211   * by setting appropriate HDF variables before loading a template. If Config.AutoEscape is 1, auto
212   * escaping is enabled. If Config.VarEscapeMode is set to one of 'html', 'js' or 'url', the
213   * corresponding escaping is applied to all variables.
214   *
215   * @param escapeMode
216   */
217  public JSilverOptions setEscapeMode(EscapeMode escapeMode) {
218    this.escapeMode = escapeMode;
219    return this;
220  }
221
222  /**
223   * @see #setPropagateEscapeStatus
224   */
225  public boolean getPropagateEscapeStatus() {
226    return propagateEscapeStatus;
227  }
228
229  /**
230   * Only used for templates that are being <a href="http://go/autoescapecs">auto escaped</a>. If
231   * {@code true} and auto escaping is enabled, variables created by &lt;cs set&gt; or &lt;cs
232   * call&gt; commands are not auto escaped if they are assigned constant or escaped values. This is
233   * disabled by default.
234   *
235   * @see #setEscapeMode
236   */
237  public JSilverOptions setPropagateEscapeStatus(boolean propagateEscapeStatus) {
238    this.propagateEscapeStatus = propagateEscapeStatus;
239    return this;
240  }
241
242  /**
243   * Sets the {@link StringInternStrategy} object that will be used to optimize HDF parsing.
244   *
245   * <p>
246   * Set value should not be {@code null} as it can cause {@link NullPointerException}.
247   *
248   * @param stringInternStrategy - {@link StringInternStrategy} object
249   */
250  public void setStringInternStrategy(StringInternStrategy stringInternStrategy) {
251    if (stringInternStrategy == null) {
252      throw new IllegalArgumentException("StringInternStrategy should not be null.");
253    }
254    this.stringInternStrategy = stringInternStrategy;
255  }
256
257  /**
258   * Returns {@link StringInternStrategy} object that is used for optimization of HDF parsing.
259   *
260   * <p>
261   * The returned value should never be {@code null}.
262   *
263   * @return currently used {@link StringInternStrategy} object.
264   */
265  public StringInternStrategy getStringInternStrategy() {
266    return stringInternStrategy;
267  }
268
269  /**
270   * If {@code true}, then use a threadlocal buffer pool for holding rendered output when outputting
271   * to String. Assumes that render() is called from a thread and that thread will not reenter
272   * render() while it is running. If {@code false}, a new buffer is allocated for each request
273   * where an Appendable output object was not provided.
274   */
275  public JSilverOptions setUseOutputBufferPool(boolean value) {
276    this.useOutputBufferPool = value;
277    return this;
278  }
279
280  /**
281   * @see #setUseOutputBufferPool(boolean)
282   */
283  public boolean getUseOutputBufferPool() {
284    return useOutputBufferPool;
285  }
286
287  /**
288   * If {@code true}, then unnecessary whitespace will be stripped from the output. 'Unnecessary' is
289   * meant in terms of HTML output. See
290   * {@link com.google.clearsilver.jsilver.template.HtmlWhiteSpaceStripper} for more info.
291   */
292  public JSilverOptions setStripHtmlWhiteSpace(boolean value) {
293    this.stripHtmlWhiteSpace = value;
294    return this;
295  }
296
297  /**
298   * @see #setStripHtmlWhiteSpace(boolean)
299   */
300  public boolean getStripHtmlWhiteSpace() {
301    return stripHtmlWhiteSpace;
302  }
303
304  /**
305   * If {@code true}, then structural whitespace will be stripped from the output. This allows
306   * templates to be written to more closely match normal programming languages. See
307   * {@link com.google.clearsilver.jsilver.syntax.StructuralWhitespaceStripper} for more info.
308   */
309  public JSilverOptions setStripStructuralWhiteSpace(boolean value) {
310    this.stripStructuralWhiteSpace = value;
311    return this;
312  }
313
314  /**
315   * @see #setStripHtmlWhiteSpace(boolean)
316   */
317  public boolean getStripStructuralWhiteSpace() {
318    return stripStructuralWhiteSpace;
319  }
320
321  /**
322   * Use this method to disable wrapping the global HDF with an UnmodifiableData object which
323   * prevents modification. This flag is here in case there are corner cases or performance reasons
324   * that someone may want to disable this protection.
325   *
326   * Should not be set to {@code true} unless incompatibilities or performance issues found. Note,
327   * that setting to {@code true} could introduce bugs in templates that acquire local references to
328   * the global data structure and then try to modify them, which is not the intended behavior.
329   * Allowing global data modification during rendering is not compatible with the recently fixed
330   * JNI Clearsilver library.
331   *
332   * TODO: Remove once legacy mode is no longer needed.
333   *
334   * @param allowGlobalDataModification {@code true} if you want to avoid wrapping the global HDF so
335   *        that all writes to it during rendering are prevented and throw an exception.
336   * @return this object.
337   */
338  public JSilverOptions setAllowGlobalDataModification(boolean allowGlobalDataModification) {
339    this.allowGlobalDataModification = allowGlobalDataModification;
340    return this;
341  }
342
343  /**
344   * @see #setAllowGlobalDataModification(boolean)
345   */
346  public boolean getAllowGlobalDataModification() {
347    return allowGlobalDataModification;
348  }
349
350  /**
351   * @param keepTemplateCacheFresh {@code true} to have the template cache call
352   *        {@link com.google.clearsilver.jsilver.resourceloader.ResourceLoader#getResourceVersionId(String)}
353   *        to check if it should refresh its cache entries (this incurs a small performance penalty
354   *        each time the cache is accessed)
355   * @return this object
356   */
357  public JSilverOptions setKeepTemplateCacheFresh(boolean keepTemplateCacheFresh) {
358    this.keepTemplateCacheFresh = keepTemplateCacheFresh;
359    return this;
360  }
361
362  /**
363   * @see #setKeepTemplateCacheFresh(boolean)
364   */
365  public boolean getKeepTemplateCacheFresh() {
366    return keepTemplateCacheFresh;
367  }
368
369  @Override
370  public JSilverOptions clone() {
371    try {
372      return (JSilverOptions) super.clone();
373    } catch (CloneNotSupportedException impossible) {
374      throw new AssertionError(impossible);
375    }
376  }
377
378  /**
379   * @see #setLogEscapedVariables
380   */
381  public boolean getLogEscapedVariables() {
382    return logEscapedVariables;
383  }
384
385  /**
386   * Use this method to enable logging of all variables whose values are modified by auto escaping
387   * or &lt;cs escape&gt; commands. These will be logged at {@code Level.WARNING}. This is useful
388   * for detecting variables that should be exempt from auto escaping.
389   *
390   * <p>
391   * It is recommended to only enable this flag during testing or debugging and not for production
392   * jobs.
393   *
394   * @see #setEscapeMode
395   */
396  public JSilverOptions setLogEscapedVariables(boolean logEscapedVariables) {
397    this.logEscapedVariables = logEscapedVariables;
398    return this;
399  }
400}
401