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: FunctionMultiArgs.java 468655 2006-10-28 07:12:06Z minchau $
020     */
021    package org.apache.xpath.functions;
022    
023    import org.apache.xalan.res.XSLMessages;
024    import org.apache.xpath.Expression;
025    import org.apache.xpath.ExpressionOwner;
026    import org.apache.xpath.XPathVisitor;
027    import org.apache.xpath.res.XPATHErrorResources;
028    
029    /**
030     * Base class for functions that accept an undetermined number of multiple
031     * arguments.
032     * @xsl.usage advanced
033     */
034    public class FunctionMultiArgs extends Function3Args
035    {
036        static final long serialVersionUID = 7117257746138417181L;
037    
038      /** Argument expressions that are at index 3 or greater.
039       *  @serial */
040      Expression[] m_args;
041      
042      /**
043       * Return an expression array containing arguments at index 3 or greater.
044       *
045       * @return An array that contains the arguments at index 3 or greater.
046       */
047      public Expression[] getArgs()
048      {
049        return m_args;
050      }
051    
052      /**
053       * Set an argument expression for a function.  This method is called by the
054       * XPath compiler.
055       *
056       * @param arg non-null expression that represents the argument.
057       * @param argNum The argument number index.
058       *
059       * @throws WrongNumberArgsException If a derived class determines that the
060       * number of arguments is incorrect.
061       */
062      public void setArg(Expression arg, int argNum)
063              throws WrongNumberArgsException
064      {
065    
066        if (argNum < 3)
067          super.setArg(arg, argNum);
068        else
069        {
070          if (null == m_args)
071          {
072            m_args = new Expression[1];
073            m_args[0] = arg;
074          }
075          else
076          {
077    
078            // Slow but space conservative.
079            Expression[] args = new Expression[m_args.length + 1];
080    
081            System.arraycopy(m_args, 0, args, 0, m_args.length);
082    
083            args[m_args.length] = arg;
084            m_args = args;
085          }
086          arg.exprSetParent(this);
087        }
088      }
089      
090      /**
091       * This function is used to fixup variables from QNames to stack frame 
092       * indexes at stylesheet build time.
093       * @param vars List of QNames that correspond to variables.  This list 
094       * should be searched backwards for the first qualified name that 
095       * corresponds to the variable reference qname.  The position of the 
096       * QName in the vector from the start of the vector will be its position 
097       * in the stack frame (but variables above the globalsTop value will need 
098       * to be offset to the current stack frame).
099       */
100      public void fixupVariables(java.util.Vector vars, int globalsSize)
101      {
102        super.fixupVariables(vars, globalsSize);
103        if(null != m_args)
104        {
105          for (int i = 0; i < m_args.length; i++) 
106          {
107            m_args[i].fixupVariables(vars, globalsSize);
108          }
109        }
110      }
111    
112      /**
113       * Check that the number of arguments passed to this function is correct.
114       *
115       *
116       * @param argNum The number of arguments that is being passed to the function.
117       *
118       * @throws WrongNumberArgsException
119       */
120      public void checkNumberArgs(int argNum) throws WrongNumberArgsException{}
121    
122      /**
123       * Constructs and throws a WrongNumberArgException with the appropriate
124       * message for this function object.  This class supports an arbitrary
125       * number of arguments, so this method must never be called.
126       *
127       * @throws WrongNumberArgsException
128       */
129      protected void reportWrongNumberArgs() throws WrongNumberArgsException {
130        String fMsg = XSLMessages.createXPATHMessage(
131            XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
132            new Object[]{ "Programmer's assertion:  the method FunctionMultiArgs.reportWrongNumberArgs() should never be called." });
133    
134        throw new RuntimeException(fMsg);
135      }
136    
137      /**
138       * Tell if this expression or it's subexpressions can traverse outside
139       * the current subtree.
140       *
141       * @return true if traversal outside the context node's subtree can occur.
142       */
143      public boolean canTraverseOutsideSubtree()
144      {
145    
146        if (super.canTraverseOutsideSubtree())
147          return true;
148        else
149        {
150          int n = m_args.length;
151    
152          for (int i = 0; i < n; i++)
153          {
154            if (m_args[i].canTraverseOutsideSubtree())
155              return true;
156          }
157    
158          return false;
159        }
160      }
161      
162      class ArgMultiOwner implements ExpressionOwner
163      {
164            int m_argIndex;
165            
166            ArgMultiOwner(int index)
167            {
168                    m_argIndex = index;
169            }
170            
171        /**
172         * @see ExpressionOwner#getExpression()
173         */
174        public Expression getExpression()
175        {
176          return m_args[m_argIndex];
177        }
178    
179    
180        /**
181         * @see ExpressionOwner#setExpression(Expression)
182         */
183        public void setExpression(Expression exp)
184        {
185            exp.exprSetParent(FunctionMultiArgs.this);
186            m_args[m_argIndex] = exp;
187        }
188      }
189    
190       
191        /**
192         * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
193         */
194        public void callArgVisitors(XPathVisitor visitor)
195        {
196          super.callArgVisitors(visitor);
197          if (null != m_args)
198          {
199            int n = m_args.length;
200            for (int i = 0; i < n; i++)
201            {
202              m_args[i].callVisitors(new ArgMultiOwner(i), visitor);
203            }
204          }
205        }
206        
207        /**
208         * @see Expression#deepEquals(Expression)
209         */
210        public boolean deepEquals(Expression expr)
211        {
212          if (!super.deepEquals(expr))
213                return false;
214    
215          FunctionMultiArgs fma = (FunctionMultiArgs) expr;
216          if (null != m_args)
217          {
218            int n = m_args.length;
219            if ((null == fma) || (fma.m_args.length != n))
220                  return false;
221    
222            for (int i = 0; i < n; i++)
223            {
224              if (!m_args[i].deepEquals(fma.m_args[i]))
225                    return false;
226            }
227    
228          }
229          else if (null != fma.m_args)
230          {
231              return false;
232          }
233    
234          return true;
235        }
236    }