FunctionTable.java revision 9f8118474e9513f7a5b7d2a05e4a0fb15d1a6569
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 */
21package org.apache.xpath.compiler;
22
23import org.apache.xpath.Expression;
24import org.apache.xpath.functions.Function;
25import java.util.HashMap;
26import javax.xml.transform.TransformerException;
27
28/**
29 * The function table for XPath.
30 */
31public 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