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