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.interpreter; 18 19import com.google.clearsilver.jsilver.autoescape.EscapeMode; 20import com.google.clearsilver.jsilver.data.Data; 21import com.google.clearsilver.jsilver.exceptions.JSilverInterpreterException; 22import com.google.clearsilver.jsilver.resourceloader.ResourceLoader; 23import com.google.clearsilver.jsilver.syntax.node.PCommand; 24import com.google.clearsilver.jsilver.template.Macro; 25import com.google.clearsilver.jsilver.template.RenderingContext; 26import com.google.clearsilver.jsilver.template.Template; 27 28import java.io.IOException; 29 30/** 31 * User defined macro that will be executed by the interpreter. 32 * 33 * NOTE: This is not thread safe and cannot be shared between RenderingContexts. This is taken care 34 * of by the TemplateInterpreter. 35 */ 36public class InterpretedMacro implements Macro { 37 38 private final PCommand command; 39 private final Template owningTemplate; 40 private final String macroName; 41 private final String[] argumentNames; 42 private final TemplateInterpreter templateInterpreter; 43 private final RenderingContext owningContext; 44 45 public InterpretedMacro(PCommand command, Template owningTemplate, String macroName, 46 String[] argumentNames, TemplateInterpreter templateInterpreter, 47 RenderingContext owningContext) { 48 this.command = command; 49 this.owningTemplate = owningTemplate; 50 this.macroName = macroName; 51 this.argumentNames = argumentNames; 52 this.templateInterpreter = templateInterpreter; 53 this.owningContext = owningContext; 54 } 55 56 @Override 57 public void render(RenderingContext context) throws IOException { 58 assert context == owningContext : "Cannot render macro defined in another context"; 59 context.pushExecutionContext(this); 60 boolean doRuntimeAutoEscaping = !(context.isRuntimeAutoEscaping()); 61 if (doRuntimeAutoEscaping) { 62 context.startRuntimeAutoEscaping(); 63 } 64 command.apply(templateInterpreter); 65 if (doRuntimeAutoEscaping) { 66 context.stopRuntimeAutoEscaping(); 67 } 68 context.popExecutionContext(); 69 } 70 71 @Override 72 public void render(Data data, Appendable out, ResourceLoader resourceLoader) throws IOException { 73 render(createRenderingContext(data, out, resourceLoader)); 74 } 75 76 @Override 77 public RenderingContext createRenderingContext(Data data, Appendable out, 78 ResourceLoader resourceLoader) { 79 return owningTemplate.createRenderingContext(data, out, resourceLoader); 80 } 81 82 @Override 83 public String getTemplateName() { 84 return owningTemplate.getTemplateName(); 85 } 86 87 @Override 88 public EscapeMode getEscapeMode() { 89 return owningTemplate.getEscapeMode(); 90 } 91 92 @Override 93 public String getDisplayName() { 94 return owningTemplate.getDisplayName() + ":" + macroName; 95 } 96 97 @Override 98 public String getMacroName() { 99 return macroName; 100 } 101 102 @Override 103 public String getArgumentName(int index) { 104 if (index >= argumentNames.length) { 105 // TODO: Make sure this behavior of failing if too many 106 // arguments are passed to a macro is consistent with JNI / interpreter. 107 throw new JSilverInterpreterException("Too many arguments supplied to macro " + macroName); 108 } 109 return argumentNames[index]; 110 } 111 112 @Override 113 public int getArgumentCount() { 114 return argumentNames.length; 115 } 116} 117