156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/* 256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc. 356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License"); 556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License. 656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at 756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0 956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software 1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS, 1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and 1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License. 1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage com.google.clearsilver.jsilver.functions; 1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.autoescape.EscapeMode; 2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.JSilverInterpreterException; 2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.values.Value; 2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException; 2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.HashMap; 2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.Map; 2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/** 2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Simple implementation of FunctionFinder that you can register your own functions with. 3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @see FunctionExecutor 3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class FunctionRegistry implements FunctionExecutor { 3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected Map<String, Function> functions = new HashMap<String, Function>(); 3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected Map<String, TextFilter> escapers = new HashMap<String, TextFilter>(); 3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public FunctionRegistry() { 3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setupDefaultFunctions(); 4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public Value executeFunction(String name, Value... args) { 4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Function function = functions.get(name); 4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (function == null) { 4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException("Function not found " + name); 4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value result = function.execute(args); 4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (result == null) { 5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException("Function " + name + " did not return value"); 5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return result; 5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void escape(String name, String input, Appendable output) throws IOException { 5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (name == null || name.isEmpty() || name.equals("none")) { 5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson output.append(input); 5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson TextFilter escaper = escapers.get(name); 6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (escaper == null) { 6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException("Unknown escaper: " + name); 6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson escaper.filter(input, output); 6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public boolean isEscapingFunction(String name) { 7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Function function = functions.get(name); 7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (function == null) { 7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException("Function not found " + name); 7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return function.isEscapingFunction(); 7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Subclasses can override this to register their own functions. 7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected void setupDefaultFunctions() {} 8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Register a Function with a given name. 8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void registerFunction(String name, Function function) { 8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson functions.put(name, function); 8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Register a TextFilter as a Function that takes a single String argument and returns the 9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * filtered value. 9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void registerFunction(String name, final TextFilter textFilter) { 9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson registerFunction(name, textFilter, false); 9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void registerFunction(String name, final TextFilter textFilter, final boolean isEscaper) { 9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Adapt a TextFilter to the Function interface. 10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson registerFunction(name, new Function() { 10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public Value execute(Value... args) { 10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (args.length != 1) { 10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new IllegalArgumentException("Expected 1 argument"); 10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String in = args[0].asString(); 10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder out = new StringBuilder(in.length()); 10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson try { 10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson textFilter.filter(in, out); 11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } catch (IOException e) { 11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException(e.getMessage()); 11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson EscapeMode mode; 11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson boolean isPartiallyEscaped; 11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isEscaper) { 11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // This function escapes its input. Hence the output is 11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // partiallyEscaped. 11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson mode = EscapeMode.ESCAPE_IS_CONSTANT; 12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson isPartiallyEscaped = true; 12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson mode = EscapeMode.ESCAPE_NONE; 12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson isPartiallyEscaped = false; 12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (Value arg : args) { 12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (arg.isPartiallyEscaped()) { 12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson isPartiallyEscaped = true; 12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson break; 12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return Value.literalValue(out.toString(), mode, isPartiallyEscaped); 13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public boolean isEscapingFunction() { 13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return isEscaper; 13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson }); 13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Registers an escaper, that is called when executing a <?cs escape ?> command. 14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param name The name with which <?cs escape ?> will invoke this escaper. 14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param escaper A TextFilter that implements the escaping functionality. 14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void registerEscapeMode(String name, TextFilter escaper) { 14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson escapers.put(name, escaper); 14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson} 152