com.github.mustachejava.DefaultMustacheFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of compiler Show documentation
Show all versions of compiler Show documentation
Implementation of mustache.js for Java
package com.github.mustachejava;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.regex.Pattern;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.github.mustachejava.reflect.ReflectionObjectHandler;
/**
* Simplest possible code factory
*/
public class DefaultMustacheFactory implements MustacheFactory {
private final MustacheParser mc = new MustacheParser(this);
private final Map templateCache = new ConcurrentHashMap();
private final LoadingCache mustacheCache = CacheBuilder.newBuilder().build(
new CacheLoader() {
@Override
public Mustache load(String key) throws Exception {
return mc.compile(key);
}
});
private ObjectHandler oh = new ReflectionObjectHandler();
private String resourceRoot;
private File fileRoot;
private ListeningExecutorService les;
public DefaultMustacheFactory() {
}
public DefaultMustacheFactory(String resourceRoot) {
if (!resourceRoot.endsWith("/")) resourceRoot += "/";
this.resourceRoot = resourceRoot;
}
public DefaultMustacheFactory(File fileRoot) {
if (!fileRoot.exists()) {
throw new MustacheException(fileRoot + " does not exist");
}
if (!fileRoot.isDirectory()) {
throw new MustacheException(fileRoot + " is not a directory");
}
this.fileRoot = fileRoot;
}
@Override
public MustacheVisitor createMustacheVisitor() {
return new DefaultMustacheVisitor(this);
}
@Override
public Reader getReader(String resourceName) {
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
InputStream is = ccl.getResourceAsStream(
(resourceRoot == null ? "" : resourceRoot) + resourceName);
if (is == null) {
File file = fileRoot == null ? new File(resourceName) : new File(fileRoot, resourceName);
if (file.exists() && file.isFile()) {
try {
return new BufferedReader(new FileReader(file));
} catch (FileNotFoundException e) {
throw new MustacheException("Found file, could not open: " + file, e);
}
}
throw new MustacheException("Template " + resourceName + " not found");
} else {
return new BufferedReader(new InputStreamReader(is, Charset.forName("utf-8")));
}
}
private static Pattern escapedPattern = Pattern.compile("^&\\w+;");
// Override this in a super class if you don't want encoding or would like
// to change the way encoding works. Also, if you use unexecute, make sure
// also do the inverse in decode.
@Override
public void encode(String value, Writer writer) {
try {
int position = 0;
int length = value.length();
for (int i = 0; i < length; i++) {
char c = value.charAt(i);
switch (c) {
case '&':
if (!escapedPattern.matcher(value.substring(i, length)).find()) {
position = append(value, writer, position, i, "&");
} else {
if (position != 0) {
position = append(value, writer, position, i, "&");
}
}
break;
case '\\':
position = append(value, writer, position, i, "\\\\");
break;
case '"':
position = append(value, writer, position, i, """);
break;
case '<':
position = append(value, writer, position, i, "<");
break;
case '>':
position = append(value, writer, position, i, ">");
break;
case '\n':
position = append(value, writer, position, i, "
");
break;
}
}
writer.append(value, position, length);
} catch (IOException e) {
throw new MustacheException("Failed to encode value: " + value);
}
}
private int append(String value, Writer writer, int position, int i, String replace) throws IOException {
writer.append(value, position, i);
writer.append(replace);
return i + 1;
}
@Override
public ObjectHandler getObjectHandler() {
return oh;
}
public void setObjectHandler(ObjectHandler oh) {
this.oh = oh;
}
public ExecutorService getExecutorService() {
return les;
}
public void setExecutorService(ExecutorService es) {
if (es instanceof ListeningExecutorService) {
les = (ListeningExecutorService) es;
} else {
les = MoreExecutors.listeningDecorator(es);
}
}
public Mustache getTemplate(String templateText) {
return templateCache.get(templateText);
}
public void putTemplate(String templateText, Mustache mustache) {
templateCache.put(templateText, mustache);
}
@Override
public Mustache compile(String name) {
try {
Mustache mustache = mustacheCache.get(name);
mustache.init();
return mustache;
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof MustacheException) {
throw (MustacheException) cause;
}
throw new MustacheException(cause);
}
}
@Override
public Mustache compile(Reader reader, String name) {
return compile(reader, name, "{{", "}}");
}
// Template functions need this to comply with the specification
public Mustache compile(Reader reader, String file, String sm, String em) {
Mustache compile = mc.compile(reader, file, sm, em);
compile.init();
return compile;
}
@Override
public String translate(String from) {
return from;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy