001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: FunctionTable.java 468655 2006-10-28 07:12:06Z minchau $
020     */
021    package org.apache.xpath.compiler;
022    
023    import org.apache.xpath.Expression;
024    import org.apache.xpath.functions.Function;
025    import java.util.HashMap;
026    import javax.xml.transform.TransformerException;
027    
028    /**
029     * The function table for XPath.
030     */
031    public class FunctionTable
032    {
033    
034      /** The 'current()' id. */
035      public static final int FUNC_CURRENT = 0;
036    
037      /** The 'last()' id. */
038      public static final int FUNC_LAST = 1;
039    
040      /** The 'position()' id. */
041      public static final int FUNC_POSITION = 2;
042    
043      /** The 'count()' id. */
044      public static final int FUNC_COUNT = 3;
045    
046      /** The 'id()' id. */
047      public static final int FUNC_ID = 4;
048    
049      /** The 'key()' id (XSLT). */
050      public static final int FUNC_KEY = 5;
051    
052      /** The 'local-name()' id. */
053      public static final int FUNC_LOCAL_PART = 7;
054    
055      /** The 'namespace-uri()' id. */
056      public static final int FUNC_NAMESPACE = 8;
057    
058      /** The 'name()' id. */
059      public static final int FUNC_QNAME = 9;
060    
061      /** The 'generate-id()' id. */
062      public static final int FUNC_GENERATE_ID = 10;
063    
064      /** The 'not()' id. */
065      public static final int FUNC_NOT = 11;
066    
067      /** The 'true()' id. */
068      public static final int FUNC_TRUE = 12;
069    
070      /** The 'false()' id. */
071      public static final int FUNC_FALSE = 13;
072    
073      /** The 'boolean()' id. */
074      public static final int FUNC_BOOLEAN = 14;
075    
076      /** The 'number()' id. */
077      public static final int FUNC_NUMBER = 15;
078    
079      /** The 'floor()' id. */
080      public static final int FUNC_FLOOR = 16;
081    
082      /** The 'ceiling()' id. */
083      public static final int FUNC_CEILING = 17;
084    
085      /** The 'round()' id. */
086      public static final int FUNC_ROUND = 18;
087    
088      /** The 'sum()' id. */
089      public static final int FUNC_SUM = 19;
090    
091      /** The 'string()' id. */
092      public static final int FUNC_STRING = 20;
093    
094      /** The 'starts-with()' id. */
095      public static final int FUNC_STARTS_WITH = 21;
096    
097      /** The 'contains()' id. */
098      public static final int FUNC_CONTAINS = 22;
099    
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    }