Home | History | Annotate | Download | only in compiler
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the  "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 /*
     19  * $Id: FunctionTable.java 468655 2006-10-28 07:12:06Z minchau $
     20  */
     21 package org.apache.xpath.compiler;
     22 
     23 import org.apache.xpath.Expression;
     24 import org.apache.xpath.functions.Function;
     25 import java.util.HashMap;
     26 import javax.xml.transform.TransformerException;
     27 
     28 /**
     29  * The function table for XPath.
     30  */
     31 public class FunctionTable
     32 {
     33 
     34   /** The 'current()' id. */
     35   public static final int FUNC_CURRENT = 0;
     36 
     37   /** The 'last()' id. */
     38   public static final int FUNC_LAST = 1;
     39 
     40   /** The 'position()' id. */
     41   public static final int FUNC_POSITION = 2;
     42 
     43   /** The 'count()' id. */
     44   public static final int FUNC_COUNT = 3;
     45 
     46   /** The 'id()' id. */
     47   public static final int FUNC_ID = 4;
     48 
     49   /** The 'key()' id (XSLT). */
     50   public static final int FUNC_KEY = 5;
     51 
     52   /** The 'local-name()' id. */
     53   public static final int FUNC_LOCAL_PART = 7;
     54 
     55   /** The 'namespace-uri()' id. */
     56   public static final int FUNC_NAMESPACE = 8;
     57 
     58   /** The 'name()' id. */
     59   public static final int FUNC_QNAME = 9;
     60 
     61   /** The 'generate-id()' id. */
     62   public static final int FUNC_GENERATE_ID = 10;
     63 
     64   /** The 'not()' id. */
     65   public static final int FUNC_NOT = 11;
     66 
     67   /** The 'true()' id. */
     68   public static final int FUNC_TRUE = 12;
     69 
     70   /** The 'false()' id. */
     71   public static final int FUNC_FALSE = 13;
     72 
     73   /** The 'boolean()' id. */
     74   public static final int FUNC_BOOLEAN = 14;
     75 
     76   /** The 'number()' id. */
     77   public static final int FUNC_NUMBER = 15;
     78 
     79   /** The 'floor()' id. */
     80   public static final int FUNC_FLOOR = 16;
     81 
     82   /** The 'ceiling()' id. */
     83   public static final int FUNC_CEILING = 17;
     84 
     85   /** The 'round()' id. */
     86   public static final int FUNC_ROUND = 18;
     87 
     88   /** The 'sum()' id. */
     89   public static final int FUNC_SUM = 19;
     90 
     91   /** The 'string()' id. */
     92   public static final int FUNC_STRING = 20;
     93 
     94   /** The 'starts-with()' id. */
     95   public static final int FUNC_STARTS_WITH = 21;
     96 
     97   /** The 'contains()' id. */
     98   public static final int FUNC_CONTAINS = 22;
     99 
    100   /** The 'substring-before()' id. */
    101   public static final int FUNC_SUBSTRING_BEFORE = 23;
    102 
    103   /** The 'substring-after()' id. */
    104   public static final int FUNC_SUBSTRING_AFTER = 24;
    105 
    106   /** The 'normalize-space()' id. */
    107   public static final int FUNC_NORMALIZE_SPACE = 25;
    108 
    109   /** The 'translate()' id. */
    110   public static final int FUNC_TRANSLATE = 26;
    111 
    112   /** The 'concat()' id. */
    113   public static final int FUNC_CONCAT = 27;
    114 
    115   /** The 'substring()' id. */
    116   public static final int FUNC_SUBSTRING = 29;
    117 
    118   /** The 'string-length()' id. */
    119   public static final int FUNC_STRING_LENGTH = 30;
    120 
    121   /** The 'system-property()' id. */
    122   public static final int FUNC_SYSTEM_PROPERTY = 31;
    123 
    124   /** The 'lang()' id. */
    125   public static final int FUNC_LANG = 32;
    126 
    127   /** The 'function-available()' id (XSLT). */
    128   public static final int FUNC_EXT_FUNCTION_AVAILABLE = 33;
    129 
    130   /** The 'element-available()' id (XSLT). */
    131   public static final int FUNC_EXT_ELEM_AVAILABLE = 34;
    132 
    133   /** The 'unparsed-entity-uri()' id (XSLT). */
    134   public static final int FUNC_UNPARSED_ENTITY_URI = 36;
    135 
    136   // Proprietary
    137 
    138   /** The 'document-location()' id (Proprietary). */
    139   public static final int FUNC_DOCLOCATION = 35;
    140 
    141   /**
    142    * The function table.
    143    */
    144   private static Class m_functions[];
    145 
    146   /** Table of function name to function ID associations. */
    147   private static HashMap m_functionID = new HashMap();
    148 
    149   /**
    150    * The function table contains customized functions
    151    */
    152   private Class m_functions_customer[] = new Class[NUM_ALLOWABLE_ADDINS];
    153 
    154   /**
    155    * Table of function name to function ID associations for customized functions
    156    */
    157   private HashMap m_functionID_customer = new HashMap();
    158 
    159   /**
    160    * Number of built in functions.  Be sure to update this as
    161    * built-in functions are added.
    162    */
    163   private static final int NUM_BUILT_IN_FUNCS = 37;
    164 
    165   /**
    166    * Number of built-in functions that may be added.
    167    */
    168   private static final int NUM_ALLOWABLE_ADDINS = 30;
    169 
    170   /**
    171    * The index to the next free function index.
    172    */
    173   private int m_funcNextFreeIndex = NUM_BUILT_IN_FUNCS;
    174 
    175   static
    176   {
    177     m_functions = new Class[NUM_BUILT_IN_FUNCS];
    178     m_functions[FUNC_CURRENT] = org.apache.xpath.functions.FuncCurrent.class;
    179     m_functions[FUNC_LAST] = org.apache.xpath.functions.FuncLast.class;
    180     m_functions[FUNC_POSITION] = org.apache.xpath.functions.FuncPosition.class;
    181     m_functions[FUNC_COUNT] = org.apache.xpath.functions.FuncCount.class;
    182     m_functions[FUNC_ID] = org.apache.xpath.functions.FuncId.class;
    183     m_functions[FUNC_KEY] =
    184       org.apache.xalan.templates.FuncKey.class;
    185     m_functions[FUNC_LOCAL_PART] =
    186       org.apache.xpath.functions.FuncLocalPart.class;
    187     m_functions[FUNC_NAMESPACE] =
    188       org.apache.xpath.functions.FuncNamespace.class;
    189     m_functions[FUNC_QNAME] = org.apache.xpath.functions.FuncQname.class;
    190     m_functions[FUNC_GENERATE_ID] =
    191       org.apache.xpath.functions.FuncGenerateId.class;
    192     m_functions[FUNC_NOT] = org.apache.xpath.functions.FuncNot.class;
    193     m_functions[FUNC_TRUE] = org.apache.xpath.functions.FuncTrue.class;
    194     m_functions[FUNC_FALSE] = org.apache.xpath.functions.FuncFalse.class;
    195     m_functions[FUNC_BOOLEAN] = org.apache.xpath.functions.FuncBoolean.class;
    196     m_functions[FUNC_LANG] = org.apache.xpath.functions.FuncLang.class;
    197     m_functions[FUNC_NUMBER] = org.apache.xpath.functions.FuncNumber.class;
    198     m_functions[FUNC_FLOOR] = org.apache.xpath.functions.FuncFloor.class;
    199     m_functions[FUNC_CEILING] = org.apache.xpath.functions.FuncCeiling.class;
    200     m_functions[FUNC_ROUND] = org.apache.xpath.functions.FuncRound.class;
    201     m_functions[FUNC_SUM] = org.apache.xpath.functions.FuncSum.class;
    202     m_functions[FUNC_STRING] = org.apache.xpath.functions.FuncString.class;
    203     m_functions[FUNC_STARTS_WITH] =
    204       org.apache.xpath.functions.FuncStartsWith.class;
    205     m_functions[FUNC_CONTAINS] = org.apache.xpath.functions.FuncContains.class;
    206     m_functions[FUNC_SUBSTRING_BEFORE] =
    207       org.apache.xpath.functions.FuncSubstringBefore.class;
    208     m_functions[FUNC_SUBSTRING_AFTER] =
    209       org.apache.xpath.functions.FuncSubstringAfter.class;
    210     m_functions[FUNC_NORMALIZE_SPACE] =
    211       org.apache.xpath.functions.FuncNormalizeSpace.class;
    212     m_functions[FUNC_TRANSLATE] =
    213       org.apache.xpath.functions.FuncTranslate.class;
    214     m_functions[FUNC_CONCAT] = org.apache.xpath.functions.FuncConcat.class;
    215     m_functions[FUNC_SYSTEM_PROPERTY] =
    216       org.apache.xpath.functions.FuncSystemProperty.class;
    217     m_functions[FUNC_EXT_FUNCTION_AVAILABLE] =
    218       org.apache.xpath.functions.FuncExtFunctionAvailable.class;
    219     m_functions[FUNC_EXT_ELEM_AVAILABLE] =
    220       org.apache.xpath.functions.FuncExtElementAvailable.class;
    221     m_functions[FUNC_SUBSTRING] =
    222       org.apache.xpath.functions.FuncSubstring.class;
    223     m_functions[FUNC_STRING_LENGTH] =
    224       org.apache.xpath.functions.FuncStringLength.class;
    225     m_functions[FUNC_DOCLOCATION] =
    226       org.apache.xpath.functions.FuncDoclocation.class;
    227     m_functions[FUNC_UNPARSED_ENTITY_URI] =
    228       org.apache.xpath.functions.FuncUnparsedEntityURI.class;
    229   }
    230 
    231   static{
    232           m_functionID.put(Keywords.FUNC_CURRENT_STRING,
    233                           new Integer(FunctionTable.FUNC_CURRENT));
    234           m_functionID.put(Keywords.FUNC_LAST_STRING,
    235                           new Integer(FunctionTable.FUNC_LAST));
    236           m_functionID.put(Keywords.FUNC_POSITION_STRING,
    237                           new Integer(FunctionTable.FUNC_POSITION));
    238           m_functionID.put(Keywords.FUNC_COUNT_STRING,
    239                           new Integer(FunctionTable.FUNC_COUNT));
    240           m_functionID.put(Keywords.FUNC_ID_STRING,
    241                           new Integer(FunctionTable.FUNC_ID));
    242           m_functionID.put(Keywords.FUNC_KEY_STRING,
    243                           new Integer(FunctionTable.FUNC_KEY));
    244           m_functionID.put(Keywords.FUNC_LOCAL_PART_STRING,
    245                           new Integer(FunctionTable.FUNC_LOCAL_PART));
    246           m_functionID.put(Keywords.FUNC_NAMESPACE_STRING,
    247                           new Integer(FunctionTable.FUNC_NAMESPACE));
    248           m_functionID.put(Keywords.FUNC_NAME_STRING,
    249                           new Integer(FunctionTable.FUNC_QNAME));
    250           m_functionID.put(Keywords.FUNC_GENERATE_ID_STRING,
    251                           new Integer(FunctionTable.FUNC_GENERATE_ID));
    252           m_functionID.put(Keywords.FUNC_NOT_STRING,
    253                           new Integer(FunctionTable.FUNC_NOT));
    254           m_functionID.put(Keywords.FUNC_TRUE_STRING,
    255                           new Integer(FunctionTable.FUNC_TRUE));
    256           m_functionID.put(Keywords.FUNC_FALSE_STRING,
    257                           new Integer(FunctionTable.FUNC_FALSE));
    258           m_functionID.put(Keywords.FUNC_BOOLEAN_STRING,
    259                           new Integer(FunctionTable.FUNC_BOOLEAN));
    260           m_functionID.put(Keywords.FUNC_LANG_STRING,
    261                           new Integer(FunctionTable.FUNC_LANG));
    262           m_functionID.put(Keywords.FUNC_NUMBER_STRING,
    263                           new Integer(FunctionTable.FUNC_NUMBER));
    264           m_functionID.put(Keywords.FUNC_FLOOR_STRING,
    265                           new Integer(FunctionTable.FUNC_FLOOR));
    266           m_functionID.put(Keywords.FUNC_CEILING_STRING,
    267                           new Integer(FunctionTable.FUNC_CEILING));
    268           m_functionID.put(Keywords.FUNC_ROUND_STRING,
    269                           new Integer(FunctionTable.FUNC_ROUND));
    270           m_functionID.put(Keywords.FUNC_SUM_STRING,
    271                           new Integer(FunctionTable.FUNC_SUM));
    272           m_functionID.put(Keywords.FUNC_STRING_STRING,
    273                           new Integer(FunctionTable.FUNC_STRING));
    274           m_functionID.put(Keywords.FUNC_STARTS_WITH_STRING,
    275                           new Integer(FunctionTable.FUNC_STARTS_WITH));
    276           m_functionID.put(Keywords.FUNC_CONTAINS_STRING,
    277                           new Integer(FunctionTable.FUNC_CONTAINS));
    278           m_functionID.put(Keywords.FUNC_SUBSTRING_BEFORE_STRING,
    279                           new Integer(FunctionTable.FUNC_SUBSTRING_BEFORE));
    280           m_functionID.put(Keywords.FUNC_SUBSTRING_AFTER_STRING,
    281                           new Integer(FunctionTable.FUNC_SUBSTRING_AFTER));
    282           m_functionID.put(Keywords.FUNC_NORMALIZE_SPACE_STRING,
    283                           new Integer(FunctionTable.FUNC_NORMALIZE_SPACE));
    284           m_functionID.put(Keywords.FUNC_TRANSLATE_STRING,
    285                           new Integer(FunctionTable.FUNC_TRANSLATE));
    286           m_functionID.put(Keywords.FUNC_CONCAT_STRING,
    287                           new Integer(FunctionTable.FUNC_CONCAT));
    288           m_functionID.put(Keywords.FUNC_SYSTEM_PROPERTY_STRING,
    289                           new Integer(FunctionTable.FUNC_SYSTEM_PROPERTY));
    290           m_functionID.put(Keywords.FUNC_EXT_FUNCTION_AVAILABLE_STRING,
    291                         new Integer(FunctionTable.FUNC_EXT_FUNCTION_AVAILABLE));
    292           m_functionID.put(Keywords.FUNC_EXT_ELEM_AVAILABLE_STRING,
    293                           new Integer(FunctionTable.FUNC_EXT_ELEM_AVAILABLE));
    294           m_functionID.put(Keywords.FUNC_SUBSTRING_STRING,
    295                           new Integer(FunctionTable.FUNC_SUBSTRING));
    296           m_functionID.put(Keywords.FUNC_STRING_LENGTH_STRING,
    297                           new Integer(FunctionTable.FUNC_STRING_LENGTH));
    298           m_functionID.put(Keywords.FUNC_UNPARSED_ENTITY_URI_STRING,
    299                           new Integer(FunctionTable.FUNC_UNPARSED_ENTITY_URI));
    300           m_functionID.put(Keywords.FUNC_DOCLOCATION_STRING,
    301                           new Integer(FunctionTable.FUNC_DOCLOCATION));
    302   }
    303 
    304   public FunctionTable(){
    305   }
    306 
    307   /**
    308    * Return the name of the a function in the static table. Needed to avoid
    309    * making the table publicly available.
    310    */
    311   String getFunctionName(int funcID) {
    312       if (funcID < NUM_BUILT_IN_FUNCS) return m_functions[funcID].getName();
    313       else return m_functions_customer[funcID - NUM_BUILT_IN_FUNCS].getName();
    314   }
    315 
    316   /**
    317    * Obtain a new Function object from a function ID.
    318    *
    319    * @param which  The function ID, which may correspond to one of the FUNC_XXX
    320    *    values found in {@link org.apache.xpath.compiler.FunctionTable}, but may
    321    *    be a value installed by an external module.
    322    *
    323    * @return a a new Function instance.
    324    *
    325    * @throws javax.xml.transform.TransformerException if ClassNotFoundException,
    326    *    IllegalAccessException, or InstantiationException is thrown.
    327    */
    328   Function getFunction(int which)
    329           throws javax.xml.transform.TransformerException
    330   {
    331           try{
    332               if (which < NUM_BUILT_IN_FUNCS)
    333                   return (Function) m_functions[which].newInstance();
    334               else
    335                   return (Function) m_functions_customer[
    336                       which-NUM_BUILT_IN_FUNCS].newInstance();
    337           }catch (IllegalAccessException ex){
    338                   throw new TransformerException(ex.getMessage());
    339           }catch (InstantiationException ex){
    340                   throw new TransformerException(ex.getMessage());
    341           }
    342   }
    343 
    344   /**
    345    * Obtain a function ID from a given function name
    346    * @param key the function name in a java.lang.String format.
    347    * @return a function ID, which may correspond to one of the FUNC_XXX values
    348    * found in {@link org.apache.xpath.compiler.FunctionTable}, but may be a
    349    * value installed by an external module.
    350    */
    351   Object getFunctionID(String key){
    352           Object id = m_functionID_customer.get(key);
    353           if (null == id) id = m_functionID.get(key);
    354           return id;
    355   }
    356 
    357   /**
    358    * Install a built-in function.
    359    * @param name The unqualified name of the function, must not be null
    360    * @param func A Implementation of an XPath Function object.
    361    * @return the position of the function in the internal index.
    362    */
    363   public int installFunction(String name, Class func)
    364   {
    365 
    366     int funcIndex;
    367     Object funcIndexObj = getFunctionID(name);
    368 
    369     if (null != funcIndexObj)
    370     {
    371       funcIndex = ((Integer) funcIndexObj).intValue();
    372 
    373       if (funcIndex < NUM_BUILT_IN_FUNCS){
    374               funcIndex = m_funcNextFreeIndex++;
    375               m_functionID_customer.put(name, new Integer(funcIndex));
    376       }
    377       m_functions_customer[funcIndex - NUM_BUILT_IN_FUNCS] = func;
    378     }
    379     else
    380     {
    381             funcIndex = m_funcNextFreeIndex++;
    382 
    383             m_functions_customer[funcIndex-NUM_BUILT_IN_FUNCS] = func;
    384 
    385             m_functionID_customer.put(name,
    386                 new Integer(funcIndex));
    387     }
    388     return funcIndex;
    389   }
    390 
    391   /**
    392    * Tell if a built-in, non-namespaced function is available.
    393    *
    394    * @param methName The local name of the function.
    395    *
    396    * @return True if the function can be executed.
    397    */
    398   public boolean functionAvailable(String methName)
    399   {
    400       Object tblEntry = m_functionID.get(methName);
    401       if (null != tblEntry) return true;
    402       else{
    403               tblEntry = m_functionID_customer.get(methName);
    404               return (null != tblEntry)? true : false;
    405       }
    406   }
    407 }
    408