package play.templates; import java.io.File; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import play.Logger; import play.Play; import play.classloading.BytecodeCache; import play.exceptions.JavaExecutionException; import play.exceptions.NoRouteFoundException; import play.exceptions.TagInternalException; import play.exceptions.TemplateExecutionException; import play.exceptions.TemplateExecutionException.DoBodyException; import play.libs.Codec; import play.libs.IO; /** * A template */ public abstract class BaseTemplate extends Template { public String compiledSource; public Map<Integer, Integer> linesMatrix = new HashMap<Integer, Integer>(); public Set<Integer> doBodyLines = new HashSet<Integer>(); public Class compiledTemplate; public String compiledTemplateName; public Long timestamp = System.currentTimeMillis(); public BaseTemplate(String name, String source) { this.name = name; this.source = source; } public BaseTemplate(String source) { this.name = Codec.UUID(); this.source = source; } public void loadPrecompiled() { try { File file = Play.getFile("precompiled/templates/" + name); byte[] code = IO.readContent(file); directLoad(code); } catch (Exception e) { throw new RuntimeException("Cannot load precompiled template " + name); } } public boolean loadFromCache() { try { long start = System.currentTimeMillis(); byte[] bc = BytecodeCache.getBytecode(name, source); if (bc != null) { directLoad(bc); if (Logger.isTraceEnabled()) { Logger.trace("%sms to load template %s from cache", System.currentTimeMillis() - start, name); } return true; } } catch (Exception e) { Logger.warn(e, "Cannot load %s from cache", name); } return false; } abstract void directLoad(byte[] code) throws Exception; void throwException(Throwable e) { for (StackTraceElement stackTraceElement : e.getStackTrace()) { if (stackTraceElement.getClassName().equals(compiledTemplateName) || stackTraceElement.getClassName().startsWith(compiledTemplateName + "$_run_closure")) { if (doBodyLines.contains(stackTraceElement.getLineNumber())) { throw new DoBodyException(e); } else if (e instanceof TagInternalException) { throw (TagInternalException) cleanStackTrace(e); } else if (e instanceof NoRouteFoundException) { NoRouteFoundException ex = (NoRouteFoundException) cleanStackTrace(e); if (ex.getFile() != null) { throw new NoRouteFoundException(ex.getFile(), this, this.linesMatrix.get(stackTraceElement.getLineNumber())); } throw new NoRouteFoundException(ex.getAction(), ex.getArgs(), this, this.linesMatrix.get(stackTraceElement.getLineNumber())); } else if (e instanceof TemplateExecutionException) { throw (TemplateExecutionException) cleanStackTrace(e); } else { throw new TemplateExecutionException(this, this.linesMatrix.get(stackTraceElement.getLineNumber()), e.getMessage(), cleanStackTrace(e)); } } if (stackTraceElement.getLineNumber() > 0 && Play.classes.hasClass(stackTraceElement.getClassName())) { throw new JavaExecutionException(Play.classes.getApplicationClass(stackTraceElement.getClassName()), stackTraceElement.getLineNumber(), cleanStackTrace(e)); } } throw new RuntimeException(e); } abstract Throwable cleanStackTrace(Throwable e); public static ThreadLocal<BaseTemplate> layout = new ThreadLocal<BaseTemplate>(); public static ThreadLocal<Map<Object, Object>> layoutData = new ThreadLocal<Map<Object, Object>>(); public static ThreadLocal<BaseTemplate> currentTemplate = new ThreadLocal<BaseTemplate>(); public static class RawData { public String data; public RawData(Object val) { if (val == null) { data = ""; } else { data = val.toString(); } } @Override public String toString() { return data; } } }