1 /* 2 * Copyright (C) 2018 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 package com.google.escapevelocity; 17 18 import com.google.common.collect.ImmutableSet; 19 import java.lang.reflect.Method; 20 import java.util.Map; 21 import java.util.TreeMap; 22 23 /** 24 * The context of a template evaluation. This consists of the template variables and the template 25 * macros. The template variables start with the values supplied by the evaluation call, and can 26 * be changed by {@code #set} directives and during the execution of {@code #foreach} and macro 27 * calls. The macros are extracted from the template during parsing and never change thereafter. 28 * 29 * @author emcmanus@google.com (Éamonn McManus) 30 */ 31 interface EvaluationContext { getVar(String var)32 Object getVar(String var); 33 varIsDefined(String var)34 boolean varIsDefined(String var); 35 36 /** 37 * Sets the given variable to the given value. 38 * 39 * @return a Runnable that will restore the variable to the value it had before. If the variable 40 * was undefined before this method was executed, the Runnable will make it undefined again. 41 * This allows us to restore the state of {@code $x} after {@code #foreach ($x in ...)}. 42 */ setVar(final String var, Object value)43 Runnable setVar(final String var, Object value); 44 45 /** See {@link MethodFinder#publicMethodsWithName}. */ publicMethodsWithName(Class<?> startClass, String name)46 ImmutableSet<Method> publicMethodsWithName(Class<?> startClass, String name); 47 48 class PlainEvaluationContext implements EvaluationContext { 49 private final Map<String, Object> vars; 50 private final MethodFinder methodFinder; 51 PlainEvaluationContext(Map<String, ?> vars, MethodFinder methodFinder)52 PlainEvaluationContext(Map<String, ?> vars, MethodFinder methodFinder) { 53 this.vars = new TreeMap<>(vars); 54 this.methodFinder = methodFinder; 55 } 56 57 @Override getVar(String var)58 public Object getVar(String var) { 59 return vars.get(var); 60 } 61 62 @Override varIsDefined(String var)63 public boolean varIsDefined(String var) { 64 return vars.containsKey(var); 65 } 66 67 @Override setVar(final String var, Object value)68 public Runnable setVar(final String var, Object value) { 69 Runnable undo; 70 if (vars.containsKey(var)) { 71 final Object oldValue = vars.get(var); 72 undo = () -> vars.put(var, oldValue); 73 } else { 74 undo = () -> vars.remove(var); 75 } 76 vars.put(var, value); 77 return undo; 78 } 79 80 @Override publicMethodsWithName(Class<?> startClass, String name)81 public ImmutableSet<Method> publicMethodsWithName(Class<?> startClass, String name) { 82 return methodFinder.publicMethodsWithName(startClass, name); 83 } 84 } 85 } 86