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 17 package com.google.clearsilver.jsilver.functions; 18 19 import com.google.clearsilver.jsilver.autoescape.EscapeMode; 20 21 import com.google.clearsilver.jsilver.exceptions.JSilverInterpreterException; 22 import com.google.clearsilver.jsilver.values.Value; 23 24 import java.io.IOException; 25 import java.util.HashMap; 26 import java.util.Map; 27 28 /** 29 * Simple implementation of FunctionFinder that you can register your own functions with. 30 * 31 * @see FunctionExecutor 32 */ 33 public class FunctionRegistry implements FunctionExecutor { 34 35 protected Map<String, Function> functions = new HashMap<String, Function>(); 36 protected Map<String, TextFilter> escapers = new HashMap<String, TextFilter>(); 37 38 public FunctionRegistry() { 39 setupDefaultFunctions(); 40 } 41 42 @Override 43 public Value executeFunction(String name, Value... args) { 44 Function function = functions.get(name); 45 if (function == null) { 46 throw new JSilverInterpreterException("Function not found " + name); 47 } 48 Value result = function.execute(args); 49 if (result == null) { 50 throw new JSilverInterpreterException("Function " + name + " did not return value"); 51 } 52 return result; 53 } 54 55 @Override 56 public void escape(String name, String input, Appendable output) throws IOException { 57 if (name == null || name.isEmpty() || name.equals("none")) { 58 output.append(input); 59 } else { 60 TextFilter escaper = escapers.get(name); 61 if (escaper == null) { 62 throw new JSilverInterpreterException("Unknown escaper: " + name); 63 } 64 escaper.filter(input, output); 65 } 66 } 67 68 @Override 69 public boolean isEscapingFunction(String name) { 70 Function function = functions.get(name); 71 if (function == null) { 72 throw new JSilverInterpreterException("Function not found " + name); 73 } 74 return function.isEscapingFunction(); 75 } 76 77 /** 78 * Subclasses can override this to register their own functions. 79 */ 80 protected void setupDefaultFunctions() {} 81 82 /** 83 * Register a Function with a given name. 84 */ 85 public void registerFunction(String name, Function function) { 86 functions.put(name, function); 87 } 88 89 /** 90 * Register a TextFilter as a Function that takes a single String argument and returns the 91 * filtered value. 92 */ 93 public void registerFunction(String name, final TextFilter textFilter) { 94 registerFunction(name, textFilter, false); 95 } 96 97 public void registerFunction(String name, final TextFilter textFilter, final boolean isEscaper) { 98 99 // Adapt a TextFilter to the Function interface. 100 registerFunction(name, new Function() { 101 @Override 102 public Value execute(Value... args) { 103 if (args.length != 1) { 104 throw new IllegalArgumentException("Expected 1 argument"); 105 } 106 String in = args[0].asString(); 107 StringBuilder out = new StringBuilder(in.length()); 108 try { 109 textFilter.filter(in, out); 110 } catch (IOException e) { 111 throw new JSilverInterpreterException(e.getMessage()); 112 } 113 114 EscapeMode mode; 115 boolean isPartiallyEscaped; 116 if (isEscaper) { 117 // This function escapes its input. Hence the output is 118 // partiallyEscaped. 119 mode = EscapeMode.ESCAPE_IS_CONSTANT; 120 isPartiallyEscaped = true; 121 } else { 122 mode = EscapeMode.ESCAPE_NONE; 123 isPartiallyEscaped = false; 124 for (Value arg : args) { 125 if (arg.isPartiallyEscaped()) { 126 isPartiallyEscaped = true; 127 break; 128 } 129 } 130 } 131 return Value.literalValue(out.toString(), mode, isPartiallyEscaped); 132 } 133 134 public boolean isEscapingFunction() { 135 return isEscaper; 136 } 137 }); 138 } 139 140 /** 141 * Registers an escaper, that is called when executing a <?cs escape ?> command. 142 * 143 * @param name The name with which <?cs escape ?> will invoke this escaper. 144 * @param escaper A TextFilter that implements the escaping functionality. 145 */ 146 public void registerEscapeMode(String name, TextFilter escaper) { 147 148 escapers.put(name, escaper); 149 } 150 151 } 152