Home | History | Annotate | Download | only in functions
      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 &lt;?cs escape ?&gt; command.
    142    *
    143    * @param name The name with which &lt;?cs escape ?&gt; 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