Home | History | Annotate | Download | only in functions
      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    */
     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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    247   public void checkNumberArgs(int argNum) throws WrongNumberArgsException{}
    248 
    249 
    250   class ArgExtOwner implements ExpressionOwner
    251   {
    252 
    253     Expression m_exp;
    254 
    255   	ArgExtOwner(Expression exp)
    256   	{
    257   		m_exp = exp;
    258   	}
    259 
    260     /**
    261      * @see ExpressionOwner#getExpression()
    262      */
    263     public Expression getExpression()
    264     {
    265       return m_exp;
    266     }
    267 
    268 
    269     /**
    270      * @see ExpressionOwner#setExpression(Expression)
    271      */
    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    */
    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    */
    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    */
    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    */
    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