code: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements. See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership. The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the  "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  /*
   * $Id$
   */
  package org.apache.xalan.templates;
  
  import javax.xml.transform.TransformerException;
  
  import org.apache.xalan.extensions.ExtensionNamespaceSupport;
  import org.apache.xalan.transformer.TransformerImpl;
  import org.apache.xpath.VariableStack;
  import org.apache.xpath.XPathContext;
  import org.apache.xpath.objects.XObject;
  
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  
  
  /**
   * Implement func:function.
   * @xsl.usage advanced
   */
  public class ElemExsltFunction extends ElemTemplate
  {
      static final long serialVersionUID = 272154954793534771L;
    /**
     * Get an integer representation of the element type.
     *
     * @return An integer representation of the element, defined in the
     *     Constants class.
     * @see org.apache.xalan.templates.Constants
     */
    public int getXSLToken()
    {
      return Constants.EXSLT_ELEMNAME_FUNCTION;
    }
  
     /**
     * Return the node name, defined in the
     *     Constants class.
     * @see org.apache.xalan.templates.Constants
     * @return The node name
     * 
     */ 
    public String getNodeName()
    {
      return Constants.EXSLT_ELEMNAME_FUNCTION_STRING;
    }
    
    public void execute(TransformerImpl transformer, XObject[] args)
            throws TransformerException
    {
      XPathContext xctxt = transformer.getXPathContext();
      VariableStack vars = xctxt.getVarStack();
      
      // Increment the frame bottom of the variable stack by the
      // frame size
      int thisFrame = vars.getStackFrame();
      int nextFrame = vars.link(m_frameSize);
  
      if (m_inArgsSize < args.length) {
        throw new TransformerException ("function called with too many args");
      }
      
      // Set parameters,
      // have to clear the section of the stack frame that has params.
      if (m_inArgsSize > 0) {
        vars.clearLocalSlots(0, m_inArgsSize);
  
        if (args.length > 0) {
          vars.setStackFrame(thisFrame);
          NodeList children = this.getChildNodes();
          
          for (int i = 0; i < args.length; i ++) {
            Node child = children.item(i);
            if (children.item(i) instanceof ElemParam) {
              ElemParam param = (ElemParam)children.item(i);
              vars.setLocalVariable(param.getIndex(), args[i], nextFrame);
            }
          }
          
          vars.setStackFrame(nextFrame);
        }
      }
  
      //  Removed ElemTemplate 'push' and 'pop' of RTFContext, in order to avoid losing the RTF context 
      //  before a value can be returned. ElemExsltFunction operates in the scope of the template that called 
      //  the function.
      //  xctxt.pushRTFContext();
      
      if (transformer.getDebug())
        transformer.getTraceManager().fireTraceEvent(this);
      
      vars.setStackFrame(nextFrame);
      transformer.executeChildTemplates(this, true);
      
      // Reset the stack frame after the function call
      vars.unlink(thisFrame);
  
      if (transformer.getDebug())
        transformer.getTraceManager().fireTraceEndEvent(this);
  
      // Following ElemTemplate 'pop' removed -- see above.
      // xctxt.popRTFContext(); 
      
    }
          
    /**
     * Called after everything else has been
     * recomposed, and allows the function to set remaining
     * values that may be based on some other property that
     * depends on recomposition.
     */
    public void compose(StylesheetRoot sroot) throws TransformerException
    {
      super.compose(sroot);
      
      // Register the function namespace (if not already registered).
      String namespace = getName().getNamespace();
      String handlerClass = sroot.getExtensionHandlerClass();
      Object[] args ={namespace, sroot};
      ExtensionNamespaceSupport extNsSpt = 
                           new ExtensionNamespaceSupport(namespace, handlerClass, args);
      sroot.getExtensionNamespacesManager().registerExtension(extNsSpt);
      // Make sure there is a handler for the EXSLT functions namespace
      // -- for isElementAvailable().    
      if (!(namespace.equals(Constants.S_EXSLT_FUNCTIONS_URL)))
      {
        namespace = Constants.S_EXSLT_FUNCTIONS_URL;
        args = new Object[]{namespace, sroot};
        extNsSpt = new ExtensionNamespaceSupport(namespace, handlerClass, args);
        sroot.getExtensionNamespacesManager().registerExtension(extNsSpt);
      }
    }
  }
  