|
1 /* |
|
2 * reserved comment block |
|
3 * DO NOT REMOVE OR ALTER! |
|
4 */ |
|
5 /* |
|
6 * Licensed to the Apache Software Foundation (ASF) under one or more |
|
7 * contributor license agreements. See the NOTICE file distributed with |
|
8 * this work for additional information regarding copyright ownership. |
|
9 * The ASF licenses this file to You under the Apache License, Version 2.0 |
|
10 * (the "License"); you may not use this file except in compliance with |
|
11 * the License. You may obtain a copy of the License at |
|
12 * |
|
13 * http://www.apache.org/licenses/LICENSE-2.0 |
|
14 * |
|
15 * Unless required by applicable law or agreed to in writing, software |
|
16 * distributed under the License is distributed on an "AS IS" BASIS, |
|
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
18 * See the License for the specific language governing permissions and |
|
19 * limitations under the License. |
|
20 */ |
|
21 |
|
22 package com.sun.org.apache.xpath.internal.functions; |
|
23 |
|
24 import java.util.Vector; |
|
25 |
|
26 import com.sun.org.apache.xalan.internal.res.XSLMessages; |
|
27 import com.sun.org.apache.xpath.internal.Expression; |
|
28 import com.sun.org.apache.xpath.internal.ExpressionNode; |
|
29 import com.sun.org.apache.xpath.internal.ExpressionOwner; |
|
30 import com.sun.org.apache.xpath.internal.ExtensionsProvider; |
|
31 import com.sun.org.apache.xpath.internal.XPathContext; |
|
32 import com.sun.org.apache.xpath.internal.XPathVisitor; |
|
33 import com.sun.org.apache.xpath.internal.objects.XNull; |
|
34 import com.sun.org.apache.xpath.internal.objects.XObject; |
|
35 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; |
|
36 import com.sun.org.apache.xpath.internal.res.XPATHMessages; |
|
37 |
|
38 /** |
|
39 * An object of this class represents an extension call expression. When |
|
40 * the expression executes, it calls ExtensionsTable#extFunction, and then |
|
41 * converts the result to the appropriate XObject. |
|
42 * @xsl.usage advanced |
|
43 */ |
|
44 public class FuncExtFunction extends Function |
|
45 { |
|
46 static final long serialVersionUID = 5196115554693708718L; |
|
47 |
|
48 /** |
|
49 * The namespace for the extension function, which should not normally |
|
50 * be null or empty. |
|
51 * @serial |
|
52 */ |
|
53 String m_namespace; |
|
54 |
|
55 /** |
|
56 * The local name of the extension. |
|
57 * @serial |
|
58 */ |
|
59 String m_extensionName; |
|
60 |
|
61 /** |
|
62 * Unique method key, which is passed to ExtensionsTable#extFunction in |
|
63 * order to allow caching of the method. |
|
64 * @serial |
|
65 */ |
|
66 Object m_methodKey; |
|
67 |
|
68 /** |
|
69 * Array of static expressions which represent the parameters to the |
|
70 * function. |
|
71 * @serial |
|
72 */ |
|
73 Vector m_argVec = new Vector(); |
|
74 |
|
75 /** |
|
76 * This function is used to fixup variables from QNames to stack frame |
|
77 * indexes at stylesheet build time. |
|
78 * @param vars List of QNames that correspond to variables. This list |
|
79 * should be searched backwards for the first qualified name that |
|
80 * corresponds to the variable reference qname. The position of the |
|
81 * QName in the vector from the start of the vector will be its position |
|
82 * in the stack frame (but variables above the globalsTop value will need |
|
83 * to be offset to the current stack frame). |
|
84 * NEEDSDOC @param globalsSize |
|
85 */ |
|
86 public void fixupVariables(java.util.Vector vars, int globalsSize) |
|
87 { |
|
88 |
|
89 if (null != m_argVec) |
|
90 { |
|
91 int nArgs = m_argVec.size(); |
|
92 |
|
93 for (int i = 0; i < nArgs; i++) |
|
94 { |
|
95 Expression arg = (Expression) m_argVec.elementAt(i); |
|
96 |
|
97 arg.fixupVariables(vars, globalsSize); |
|
98 } |
|
99 } |
|
100 } |
|
101 |
|
102 /** |
|
103 * Return the namespace of the extension function. |
|
104 * |
|
105 * @return The namespace of the extension function. |
|
106 */ |
|
107 public String getNamespace() |
|
108 { |
|
109 return m_namespace; |
|
110 } |
|
111 |
|
112 /** |
|
113 * Return the name of the extension function. |
|
114 * |
|
115 * @return The name of the extension function. |
|
116 */ |
|
117 public String getFunctionName() |
|
118 { |
|
119 return m_extensionName; |
|
120 } |
|
121 |
|
122 /** |
|
123 * Return the method key of the extension function. |
|
124 * |
|
125 * @return The method key of the extension function. |
|
126 */ |
|
127 public Object getMethodKey() |
|
128 { |
|
129 return m_methodKey; |
|
130 } |
|
131 |
|
132 /** |
|
133 * Return the nth argument passed to the extension function. |
|
134 * |
|
135 * @param n The argument number index. |
|
136 * @return The Expression object at the given index. |
|
137 */ |
|
138 public Expression getArg(int n) { |
|
139 if (n >= 0 && n < m_argVec.size()) |
|
140 return (Expression) m_argVec.elementAt(n); |
|
141 else |
|
142 return null; |
|
143 } |
|
144 |
|
145 /** |
|
146 * Return the number of arguments that were passed |
|
147 * into this extension function. |
|
148 * |
|
149 * @return The number of arguments. |
|
150 */ |
|
151 public int getArgCount() { |
|
152 return m_argVec.size(); |
|
153 } |
|
154 |
|
155 /** |
|
156 * Create a new FuncExtFunction based on the qualified name of the extension, |
|
157 * and a unique method key. |
|
158 * |
|
159 * @param namespace The namespace for the extension function, which should |
|
160 * not normally be null or empty. |
|
161 * @param extensionName The local name of the extension. |
|
162 * @param methodKey Unique method key, which is passed to |
|
163 * ExtensionsTable#extFunction in order to allow caching |
|
164 * of the method. |
|
165 */ |
|
166 public FuncExtFunction(java.lang.String namespace, |
|
167 java.lang.String extensionName, Object methodKey) |
|
168 { |
|
169 //try{throw new Exception("FuncExtFunction() " + namespace + " " + extensionName);} catch (Exception e){e.printStackTrace();} |
|
170 m_namespace = namespace; |
|
171 m_extensionName = extensionName; |
|
172 m_methodKey = methodKey; |
|
173 } |
|
174 |
|
175 /** |
|
176 * Execute the function. The function must return |
|
177 * a valid object. |
|
178 * @param xctxt The current execution context. |
|
179 * @return A valid XObject. |
|
180 * |
|
181 * @throws javax.xml.transform.TransformerException |
|
182 */ |
|
183 public XObject execute(XPathContext xctxt) |
|
184 throws javax.xml.transform.TransformerException |
|
185 { |
|
186 if (xctxt.isSecureProcessing()) |
|
187 throw new javax.xml.transform.TransformerException( |
|
188 XPATHMessages.createXPATHMessage( |
|
189 XPATHErrorResources.ER_EXTENSION_FUNCTION_CANNOT_BE_INVOKED, |
|
190 new Object[] {toString()})); |
|
191 |
|
192 XObject result; |
|
193 Vector argVec = new Vector(); |
|
194 int nArgs = m_argVec.size(); |
|
195 |
|
196 for (int i = 0; i < nArgs; i++) |
|
197 { |
|
198 Expression arg = (Expression) m_argVec.elementAt(i); |
|
199 |
|
200 XObject xobj = arg.execute(xctxt); |
|
201 /* |
|
202 * Should cache the arguments for func:function |
|
203 */ |
|
204 xobj.allowDetachToRelease(false); |
|
205 argVec.addElement(xobj); |
|
206 } |
|
207 //dml |
|
208 ExtensionsProvider extProvider = (ExtensionsProvider)xctxt.getOwnerObject(); |
|
209 Object val = extProvider.extFunction(this, argVec); |
|
210 |
|
211 if (null != val) |
|
212 { |
|
213 result = XObject.create(val, xctxt); |
|
214 } |
|
215 else |
|
216 { |
|
217 result = new XNull(); |
|
218 } |
|
219 |
|
220 return result; |
|
221 } |
|
222 |
|
223 /** |
|
224 * Set an argument expression for a function. This method is called by the |
|
225 * XPath compiler. |
|
226 * |
|
227 * @param arg non-null expression that represents the argument. |
|
228 * @param argNum The argument number index. |
|
229 * |
|
230 * @throws WrongNumberArgsException If the argNum parameter is beyond what |
|
231 * is specified for this function. |
|
232 */ |
|
233 public void setArg(Expression arg, int argNum) |
|
234 throws WrongNumberArgsException |
|
235 { |
|
236 m_argVec.addElement(arg); |
|
237 arg.exprSetParent(this); |
|
238 } |
|
239 |
|
240 /** |
|
241 * Check that the number of arguments passed to this function is correct. |
|
242 * |
|
243 * |
|
244 * @param argNum The number of arguments that is being passed to the function. |
|
245 * |
|
246 * @throws WrongNumberArgsException |
|
247 */ |
|
248 public void checkNumberArgs(int argNum) throws WrongNumberArgsException{} |
|
249 |
|
250 |
|
251 class ArgExtOwner implements ExpressionOwner |
|
252 { |
|
253 |
|
254 Expression m_exp; |
|
255 |
|
256 ArgExtOwner(Expression exp) |
|
257 { |
|
258 m_exp = exp; |
|
259 } |
|
260 |
|
261 /** |
|
262 * @see ExpressionOwner#getExpression() |
|
263 */ |
|
264 public Expression getExpression() |
|
265 { |
|
266 return m_exp; |
|
267 } |
|
268 |
|
269 |
|
270 /** |
|
271 * @see ExpressionOwner#setExpression(Expression) |
|
272 */ |
|
273 public void setExpression(Expression exp) |
|
274 { |
|
275 exp.exprSetParent(FuncExtFunction.this); |
|
276 m_exp = exp; |
|
277 } |
|
278 } |
|
279 |
|
280 |
|
281 /** |
|
282 * Call the visitors for the function arguments. |
|
283 */ |
|
284 public void callArgVisitors(XPathVisitor visitor) |
|
285 { |
|
286 for (int i = 0; i < m_argVec.size(); i++) |
|
287 { |
|
288 Expression exp = (Expression)m_argVec.elementAt(i); |
|
289 exp.callVisitors(new ArgExtOwner(exp), visitor); |
|
290 } |
|
291 |
|
292 } |
|
293 |
|
294 /** |
|
295 * Set the parent node. |
|
296 * For an extension function, we also need to set the parent |
|
297 * node for all argument expressions. |
|
298 * |
|
299 * @param n The parent node |
|
300 */ |
|
301 public void exprSetParent(ExpressionNode n) |
|
302 { |
|
303 |
|
304 super.exprSetParent(n); |
|
305 |
|
306 int nArgs = m_argVec.size(); |
|
307 |
|
308 for (int i = 0; i < nArgs; i++) |
|
309 { |
|
310 Expression arg = (Expression) m_argVec.elementAt(i); |
|
311 |
|
312 arg.exprSetParent(n); |
|
313 } |
|
314 } |
|
315 |
|
316 /** |
|
317 * Constructs and throws a WrongNumberArgException with the appropriate |
|
318 * message for this function object. This class supports an arbitrary |
|
319 * number of arguments, so this method must never be called. |
|
320 * |
|
321 * @throws WrongNumberArgsException |
|
322 */ |
|
323 protected void reportWrongNumberArgs() throws WrongNumberArgsException { |
|
324 String fMsg = XSLMessages.createXPATHMessage( |
|
325 XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION, |
|
326 new Object[]{ "Programmer's assertion: the method FunctionMultiArgs.reportWrongNumberArgs() should never be called." }); |
|
327 |
|
328 throw new RuntimeException(fMsg); |
|
329 } |
|
330 |
|
331 /** |
|
332 * Return the name of the extesion function in string format |
|
333 */ |
|
334 public String toString() |
|
335 { |
|
336 if (m_namespace != null && m_namespace.length() > 0) |
|
337 return "{" + m_namespace + "}" + m_extensionName; |
|
338 else |
|
339 return m_extensionName; |
|
340 } |
|
341 } |