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{
m_functionID.put(Keywords.FUNC_CURRENT_STRING, new Integer(FunctionTable.FUNC_CURRENT))232           m_functionID.put(Keywords.FUNC_CURRENT_STRING,
233                           new Integer(FunctionTable.FUNC_CURRENT));
m_functionID.put(Keywords.FUNC_LAST_STRING, new Integer(FunctionTable.FUNC_LAST))234           m_functionID.put(Keywords.FUNC_LAST_STRING,
235                           new Integer(FunctionTable.FUNC_LAST));
m_functionID.put(Keywords.FUNC_POSITION_STRING, new Integer(FunctionTable.FUNC_POSITION))236           m_functionID.put(Keywords.FUNC_POSITION_STRING,
237                           new Integer(FunctionTable.FUNC_POSITION));
m_functionID.put(Keywords.FUNC_COUNT_STRING, new Integer(FunctionTable.FUNC_COUNT))238           m_functionID.put(Keywords.FUNC_COUNT_STRING,
239                           new Integer(FunctionTable.FUNC_COUNT));
m_functionID.put(Keywords.FUNC_ID_STRING, new Integer(FunctionTable.FUNC_ID))240           m_functionID.put(Keywords.FUNC_ID_STRING,
241                           new Integer(FunctionTable.FUNC_ID));
m_functionID.put(Keywords.FUNC_KEY_STRING, new Integer(FunctionTable.FUNC_KEY))242           m_functionID.put(Keywords.FUNC_KEY_STRING,
243                           new Integer(FunctionTable.FUNC_KEY));
m_functionID.put(Keywords.FUNC_LOCAL_PART_STRING, new Integer(FunctionTable.FUNC_LOCAL_PART))244           m_functionID.put(Keywords.FUNC_LOCAL_PART_STRING,
245                           new Integer(FunctionTable.FUNC_LOCAL_PART));
m_functionID.put(Keywords.FUNC_NAMESPACE_STRING, new Integer(FunctionTable.FUNC_NAMESPACE))246           m_functionID.put(Keywords.FUNC_NAMESPACE_STRING,
247                           new Integer(FunctionTable.FUNC_NAMESPACE));
m_functionID.put(Keywords.FUNC_NAME_STRING, new Integer(FunctionTable.FUNC_QNAME))248           m_functionID.put(Keywords.FUNC_NAME_STRING,
249                           new Integer(FunctionTable.FUNC_QNAME));
m_functionID.put(Keywords.FUNC_GENERATE_ID_STRING, new Integer(FunctionTable.FUNC_GENERATE_ID))250           m_functionID.put(Keywords.FUNC_GENERATE_ID_STRING,
251                           new Integer(FunctionTable.FUNC_GENERATE_ID));
m_functionID.put(Keywords.FUNC_NOT_STRING, new Integer(FunctionTable.FUNC_NOT))252           m_functionID.put(Keywords.FUNC_NOT_STRING,
253                           new Integer(FunctionTable.FUNC_NOT));
m_functionID.put(Keywords.FUNC_TRUE_STRING, new Integer(FunctionTable.FUNC_TRUE))254           m_functionID.put(Keywords.FUNC_TRUE_STRING,
255                           new Integer(FunctionTable.FUNC_TRUE));
m_functionID.put(Keywords.FUNC_FALSE_STRING, new Integer(FunctionTable.FUNC_FALSE))256           m_functionID.put(Keywords.FUNC_FALSE_STRING,
257                           new Integer(FunctionTable.FUNC_FALSE));
m_functionID.put(Keywords.FUNC_BOOLEAN_STRING, new Integer(FunctionTable.FUNC_BOOLEAN))258           m_functionID.put(Keywords.FUNC_BOOLEAN_STRING,
259                           new Integer(FunctionTable.FUNC_BOOLEAN));
m_functionID.put(Keywords.FUNC_LANG_STRING, new Integer(FunctionTable.FUNC_LANG))260           m_functionID.put(Keywords.FUNC_LANG_STRING,
261                           new Integer(FunctionTable.FUNC_LANG));
m_functionID.put(Keywords.FUNC_NUMBER_STRING, new Integer(FunctionTable.FUNC_NUMBER))262           m_functionID.put(Keywords.FUNC_NUMBER_STRING,
263                           new Integer(FunctionTable.FUNC_NUMBER));
m_functionID.put(Keywords.FUNC_FLOOR_STRING, new Integer(FunctionTable.FUNC_FLOOR))264           m_functionID.put(Keywords.FUNC_FLOOR_STRING,
265                           new Integer(FunctionTable.FUNC_FLOOR));
m_functionID.put(Keywords.FUNC_CEILING_STRING, new Integer(FunctionTable.FUNC_CEILING))266           m_functionID.put(Keywords.FUNC_CEILING_STRING,
267                           new Integer(FunctionTable.FUNC_CEILING));
m_functionID.put(Keywords.FUNC_ROUND_STRING, new Integer(FunctionTable.FUNC_ROUND))268           m_functionID.put(Keywords.FUNC_ROUND_STRING,
269                           new Integer(FunctionTable.FUNC_ROUND));
m_functionID.put(Keywords.FUNC_SUM_STRING, new Integer(FunctionTable.FUNC_SUM))270           m_functionID.put(Keywords.FUNC_SUM_STRING,
271                           new Integer(FunctionTable.FUNC_SUM));
m_functionID.put(Keywords.FUNC_STRING_STRING, new Integer(FunctionTable.FUNC_STRING))272           m_functionID.put(Keywords.FUNC_STRING_STRING,
273                           new Integer(FunctionTable.FUNC_STRING));
m_functionID.put(Keywords.FUNC_STARTS_WITH_STRING, new Integer(FunctionTable.FUNC_STARTS_WITH))274           m_functionID.put(Keywords.FUNC_STARTS_WITH_STRING,
275                           new Integer(FunctionTable.FUNC_STARTS_WITH));
m_functionID.put(Keywords.FUNC_CONTAINS_STRING, new Integer(FunctionTable.FUNC_CONTAINS))276           m_functionID.put(Keywords.FUNC_CONTAINS_STRING,
277                           new Integer(FunctionTable.FUNC_CONTAINS));
m_functionID.put(Keywords.FUNC_SUBSTRING_BEFORE_STRING, new Integer(FunctionTable.FUNC_SUBSTRING_BEFORE))278           m_functionID.put(Keywords.FUNC_SUBSTRING_BEFORE_STRING,
279                           new Integer(FunctionTable.FUNC_SUBSTRING_BEFORE));
m_functionID.put(Keywords.FUNC_SUBSTRING_AFTER_STRING, new Integer(FunctionTable.FUNC_SUBSTRING_AFTER))280           m_functionID.put(Keywords.FUNC_SUBSTRING_AFTER_STRING,
281                           new Integer(FunctionTable.FUNC_SUBSTRING_AFTER));
m_functionID.put(Keywords.FUNC_NORMALIZE_SPACE_STRING, new Integer(FunctionTable.FUNC_NORMALIZE_SPACE))282           m_functionID.put(Keywords.FUNC_NORMALIZE_SPACE_STRING,
283                           new Integer(FunctionTable.FUNC_NORMALIZE_SPACE));
m_functionID.put(Keywords.FUNC_TRANSLATE_STRING, new Integer(FunctionTable.FUNC_TRANSLATE))284           m_functionID.put(Keywords.FUNC_TRANSLATE_STRING,
285                           new Integer(FunctionTable.FUNC_TRANSLATE));
m_functionID.put(Keywords.FUNC_CONCAT_STRING, new Integer(FunctionTable.FUNC_CONCAT))286           m_functionID.put(Keywords.FUNC_CONCAT_STRING,
287                           new Integer(FunctionTable.FUNC_CONCAT));
m_functionID.put(Keywords.FUNC_SYSTEM_PROPERTY_STRING, new Integer(FunctionTable.FUNC_SYSTEM_PROPERTY))288           m_functionID.put(Keywords.FUNC_SYSTEM_PROPERTY_STRING,
289                           new Integer(FunctionTable.FUNC_SYSTEM_PROPERTY));
m_functionID.put(Keywords.FUNC_EXT_FUNCTION_AVAILABLE_STRING, new Integer(FunctionTable.FUNC_EXT_FUNCTION_AVAILABLE))290           m_functionID.put(Keywords.FUNC_EXT_FUNCTION_AVAILABLE_STRING,
291                         new Integer(FunctionTable.FUNC_EXT_FUNCTION_AVAILABLE));
m_functionID.put(Keywords.FUNC_EXT_ELEM_AVAILABLE_STRING, new Integer(FunctionTable.FUNC_EXT_ELEM_AVAILABLE))292           m_functionID.put(Keywords.FUNC_EXT_ELEM_AVAILABLE_STRING,
293                           new Integer(FunctionTable.FUNC_EXT_ELEM_AVAILABLE));
m_functionID.put(Keywords.FUNC_SUBSTRING_STRING, new Integer(FunctionTable.FUNC_SUBSTRING))294           m_functionID.put(Keywords.FUNC_SUBSTRING_STRING,
295                           new Integer(FunctionTable.FUNC_SUBSTRING));
m_functionID.put(Keywords.FUNC_STRING_LENGTH_STRING, new Integer(FunctionTable.FUNC_STRING_LENGTH))296           m_functionID.put(Keywords.FUNC_STRING_LENGTH_STRING,
297                           new Integer(FunctionTable.FUNC_STRING_LENGTH));
m_functionID.put(Keywords.FUNC_UNPARSED_ENTITY_URI_STRING, new Integer(FunctionTable.FUNC_UNPARSED_ENTITY_URI))298           m_functionID.put(Keywords.FUNC_UNPARSED_ENTITY_URI_STRING,
299                           new Integer(FunctionTable.FUNC_UNPARSED_ENTITY_URI));
m_functionID.put(Keywords.FUNC_DOCLOCATION_STRING, new Integer(FunctionTable.FUNC_DOCLOCATION))300           m_functionID.put(Keywords.FUNC_DOCLOCATION_STRING,
301                           new Integer(FunctionTable.FUNC_DOCLOCATION));
302   }
303 
FunctionTable()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    */
getFunctionName(int funcID)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    */
getFunction(int which)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    */
getFunctionID(String key)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    */
installFunction(String name, Class func)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    */
functionAvailable(String methName)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