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 }