
play.templates.GroovyTemplate Maven / Gradle / Ivy
package play.templates;
import com.jamonapi.Monitor;
import com.jamonapi.MonitorFactory;
import groovy.lang.*;
import org.apache.commons.io.FileUtils;
import org.codehaus.groovy.control.*;
import org.codehaus.groovy.control.CompilationUnit.GroovyClassOperation;
import org.codehaus.groovy.control.messages.ExceptionMessage;
import org.codehaus.groovy.control.messages.Message;
import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.syntax.SyntaxException;
import org.codehaus.groovy.tools.GroovyClass;
import play.Logger;
import play.Play;
import play.Play.Mode;
import play.classloading.BytecodeCache;
import play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer;
import play.data.binding.Unbinder;
import play.exceptions.*;
import play.exceptions.TemplateExecutionException.DoBodyException;
import play.i18n.Lang;
import play.i18n.Messages;
import play.libs.Codec;
import play.mvc.ActionInvoker;
import play.mvc.Http;
import play.mvc.Http.Request;
import play.mvc.Router;
import play.templates.types.SafeCSVFormatter;
import play.templates.types.SafeHTMLFormatter;
import play.templates.types.SafeXMLFormatter;
import play.utils.HTML;
import play.utils.Java;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
/**
* A template
*/
public class GroovyTemplate extends BaseTemplate {
static final Map safeFormatters = new HashMap();
static {
safeFormatters.put("csv", new SafeCSVFormatter());
safeFormatters.put("html", new SafeHTMLFormatter());
safeFormatters.put("xml", new SafeXMLFormatter());
}
public static void registerFormatter(String format, SafeFormatter formatter) {
safeFormatters.put(format, formatter);
}
static {
new GroovyShell().evaluate("java.lang.String.metaClass.if = { condition -> if(condition) delegate; else '' }");
}
public GroovyTemplate(String name, String source) {
super(name, source);
}
public GroovyTemplate(String source) {
super(source);
}
public static class TClassLoader extends GroovyClassLoader {
public TClassLoader() {
super(Play.classloader);
}
public Class defineTemplate(String name, byte[] byteCode) {
return defineClass(name, byteCode, 0, byteCode.length, Play.classloader.protectionDomain);
}
}
@SuppressWarnings("unchecked")
void directLoad(byte[] code) throws Exception {
TClassLoader tClassLoader = new TClassLoader();
String[] lines = new String(code, "utf-8").split("\n");
this.linesMatrix = (HashMap) Java.deserialize(Codec.decodeBASE64(lines[1]));
this.doBodyLines = (HashSet) Java.deserialize(Codec.decodeBASE64(lines[3]));
for (int i = 4; i < lines.length; i = i + 2) {
String className = lines[i];
byte[] byteCode = Codec.decodeBASE64(lines[i + 1]);
Class c = tClassLoader.defineTemplate(className, byteCode);
if (compiledTemplate == null) {
compiledTemplate = c;
}
}
}
/**
* Define the Compiler configuration
* @return the compiler Configuration
*/
protected CompilerConfiguration setUpCompilerConfiguration(){
CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
compilerConfiguration.setSourceEncoding("utf-8"); // ouf
return compilerConfiguration;
}
protected void onCompileEnd(){
}
public void compile() {
if (compiledTemplate == null) {
try {
long start = System.currentTimeMillis();
TClassLoader tClassLoader = new TClassLoader();
// Let's compile the groovy source
final List groovyClassesForThisTemplate = new ArrayList();
// ~~~ Please !
CompilerConfiguration compilerConfiguration = this.setUpCompilerConfiguration();
CompilationUnit compilationUnit = new CompilationUnit(compilerConfiguration);
compilationUnit.addSource(new SourceUnit(name, compiledSource, compilerConfiguration, tClassLoader, compilationUnit.getErrorCollector()));
Field phasesF = compilationUnit.getClass().getDeclaredField("phaseOperations");
phasesF.setAccessible(true);
LinkedList[] phases = (LinkedList[]) phasesF.get(compilationUnit);
LinkedList output = new LinkedList();
phases[Phases.OUTPUT] = output;
output.add(new GroovyClassOperation() {
public void call(GroovyClass gclass) {
groovyClassesForThisTemplate.add(gclass);
}
});
compilationUnit.compile();
// ouf
// Define script classes
StringBuilder sb = new StringBuilder();
sb.append("LINESMATRIX" + "\n");
sb.append(Codec.encodeBASE64(Java.serialize(linesMatrix)).replaceAll("\\s", ""));
sb.append("\n");
sb.append("DOBODYLINES" + "\n");
sb.append(Codec.encodeBASE64(Java.serialize(doBodyLines)).replaceAll("\\s", ""));
sb.append("\n");
for (GroovyClass gclass : groovyClassesForThisTemplate) {
tClassLoader.defineTemplate(gclass.getName(), gclass.getBytes());
sb.append(gclass.getName());
sb.append("\n");
sb.append(Codec.encodeBASE64(gclass.getBytes()).replaceAll("\\s", ""));
sb.append("\n");
}
// Cache
BytecodeCache.cacheBytecode(sb.toString().getBytes("utf-8"), name, source);
compiledTemplate = tClassLoader.loadClass(groovyClassesForThisTemplate.get(0).getName());
if (System.getProperty("precompile") != null) {
try {
// emit bytecode to standard class layout as well
File f = Play.getFile("precompiled/templates/" + name.replaceAll("\\{(.*)\\}", "from_$1").replace(":", "_").replace("..", "parent"));
f.getParentFile().mkdirs();
FileUtils.write(f, sb.toString(), "utf-8");
} catch (Exception e) {
Logger.warn(e, "Unexpected");
}
}
if (Logger.isTraceEnabled()) {
Logger.trace("%sms to compile template %s to %d classes", System.currentTimeMillis() - start, name, groovyClassesForThisTemplate.size());
}
} catch (MultipleCompilationErrorsException e) {
if (e.getErrorCollector().getLastError() != null) {
Message errorMsg = e.getErrorCollector().getLastError();
if (errorMsg instanceof SyntaxErrorMessage) {
SyntaxErrorMessage errorMessage = (SyntaxErrorMessage) e.getErrorCollector().getLastError();
SyntaxException syntaxException = errorMessage.getCause();
Integer line = this.linesMatrix.get(syntaxException.getLine());
if (line == null) {
line = 0;
}
String message = syntaxException.getMessage();
if (message.indexOf("@") > 0) {
message = message.substring(0, message.lastIndexOf("@"));
}
throw new TemplateCompilationException(this, line, message);
} else{
ExceptionMessage errorMessage = (ExceptionMessage ) e.getErrorCollector().getLastError();
Exception exception = errorMessage.getCause();
Integer line = 0;
String message = exception.getMessage();
throw new TemplateCompilationException(this, line, message);
}
}
throw new UnexpectedException(e);
} catch (Exception e) {
throw new UnexpectedException(e);
} finally{
this.onCompileEnd();
}
}
compiledTemplateName = compiledTemplate.getName();
}
@Override
public String render(Map args) {
try {
return super.render(args);
} finally {
currentTemplate.remove();
}
}
protected Binding setUpBindingVariables(Map args){
Binding binding = new Binding(args);
binding.setVariable("play", new Play());
binding.setVariable("messages", new Messages());
binding.setVariable("lang", Lang.get());
return binding;
}
@Override
protected String internalRender(Map args) {
compile();
Binding binding = this.setUpBindingVariables(args);
// If current response-object is present, add _response_encoding'
Http.Response currentResponse = Http.Response.current();
if (currentResponse != null) {
binding.setVariable("_response_encoding", currentResponse.encoding);
}
StringWriter writer = null;
Boolean applyLayouts = false;
// must check if this is the first template being rendered..
// If this template is called from inside another template,
// then args("out") have already been initialized
if (!args.containsKey("out")) {
// This is the first template being rendered.
// We have to set up the PrintWriter that this (and all sub-templates) are going
// to write the output to..
applyLayouts = true;
layout.set(null);
writer = new StringWriter();
binding.setProperty("out", new PrintWriter(writer));
currentTemplate.set(this);
}
if (!args.containsKey("_body") && !args.containsKey("_isLayout") && !args.containsKey("_isInclude")) {
layoutData.set(new HashMap
© 2015 - 2025 Weber Informatics LLC | Privacy Policy