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: XUnresolvedVariable.java 468643 2006-10-28 06:56:03Z minchau $
020     */
021    package org.apache.xalan.templates;
022    
023    import org.apache.xalan.res.XSLTErrorResources;
024    import org.apache.xalan.transformer.TransformerImpl;
025    import org.apache.xpath.VariableStack;
026    import org.apache.xpath.XPathContext;
027    import org.apache.xpath.objects.XObject;
028    
029    /**
030     * An instance of this class holds unto a variable until 
031     * it is executed.  It is used at this time for global 
032     * variables which must (we think) forward reference.
033     */
034    public class XUnresolvedVariable extends XObject
035    {  
036        static final long serialVersionUID = -256779804767950188L;
037      /** The node context for execution. */
038      transient private int m_context;
039      
040      /** The transformer context for execution. */
041      transient private TransformerImpl m_transformer;
042      
043      /** An index to the point in the variable stack where we should
044       * begin variable searches for evaluation of expressions.
045       * This is -1 if m_isTopLevel is false. 
046       **/
047      transient private int m_varStackPos = -1;
048    
049      /** An index into the variable stack where the variable context 
050       * ends, i.e. at the point we should terminate the search. 
051       **/
052      transient private int m_varStackContext;
053      
054      /** true if this variable or parameter is a global.
055       *  @serial */
056      private boolean m_isGlobal;
057      
058      /** true if this variable or parameter is not currently being evaluated. */
059      transient private boolean m_doneEval = true;
060      
061      /**
062       * Create an XUnresolvedVariable, that may be executed at a later time.
063       * This is primarily used so that forward referencing works with 
064       * global variables.  An XUnresolvedVariable is initially pushed 
065       * into the global variable stack, and then replaced with the real 
066       * thing when it is accessed.
067       *
068       * @param obj Must be a non-null reference to an ElemVariable.
069       * @param sourceNode The node context for execution.
070       * @param transformer The transformer execution context.
071       * @param varStackPos An index to the point in the variable stack where we should
072       * begin variable searches for evaluation of expressions.
073       * @param varStackContext An index into the variable stack where the variable context 
074       * ends, i.e. at the point we should terminate the search.
075       * @param isGlobal true if this is a global variable.
076       */
077      public XUnresolvedVariable(ElemVariable obj, int sourceNode, 
078                                 TransformerImpl transformer,
079                                 int varStackPos, int varStackContext,
080                                 boolean isGlobal)
081      {
082        super(obj);
083        m_context = sourceNode;
084        m_transformer = transformer;
085        
086        // For globals, this value will have to be updated once we 
087        // have determined how many global variables have been pushed.
088        m_varStackPos = varStackPos;
089        
090        // For globals, this should zero.
091        m_varStackContext = varStackContext;
092        
093        m_isGlobal = isGlobal;
094      }
095        
096      /**
097       * For support of literal objects in xpaths.
098       *
099       * @param xctxt The XPath execution context.
100       *
101       * @return This object.
102       *
103       * @throws javax.xml.transform.TransformerException
104       */
105      public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
106      {
107        if (!m_doneEval) 
108        {
109          this.m_transformer.getMsgMgr().error      
110            (xctxt.getSAXLocator(), XSLTErrorResources.ER_REFERENCING_ITSELF, 
111              new Object[]{((ElemVariable)this.object()).getName().getLocalName()}); 
112        }
113        VariableStack vars = xctxt.getVarStack();
114        
115        // These three statements need to be combined into one operation.
116        int currentFrame = vars.getStackFrame();
117        //// vars.setStackFrame(m_varStackPos);
118       
119    
120        ElemVariable velem = (ElemVariable)m_obj;
121        try
122        {
123          m_doneEval = false;
124          if(-1 != velem.m_frameSize)
125            vars.link(velem.m_frameSize);
126          XObject var = velem.getValue(m_transformer, m_context);
127          m_doneEval = true;
128          return var;
129        }
130        finally
131        {
132          // These two statements need to be combined into one operation.
133          // vars.setStackFrame(currentFrame);
134          
135          if(-1 != velem.m_frameSize)
136                    vars.unlink(currentFrame);
137        }
138      }
139      
140      /**
141       * Set an index to the point in the variable stack where we should
142       * begin variable searches for evaluation of expressions.
143       * This is -1 if m_isTopLevel is false. 
144       * 
145       * @param top A valid value that specifies where in the variable 
146       * stack the search should begin.
147       */
148      public void setVarStackPos(int top)
149      {
150        m_varStackPos = top;
151      }
152    
153      /**
154       * Set an index into the variable stack where the variable context 
155       * ends, i.e. at the point we should terminate the search.
156       * 
157       * @param bottom The point at which the search should terminate, normally 
158       * zero for global variables.
159       */
160      public void setVarStackContext(int bottom)
161      {
162        m_varStackContext = bottom;
163      }
164      
165      /**
166       * Tell what kind of class this is.
167       *
168       * @return CLASS_UNRESOLVEDVARIABLE
169       */
170      public int getType()
171      {
172        return CLASS_UNRESOLVEDVARIABLE;
173      }
174      
175      /**
176       * Given a request type, return the equivalent string.
177       * For diagnostic purposes.
178       *
179       * @return An informational string.
180       */
181      public String getTypeString()
182      {
183        return "XUnresolvedVariable (" + object().getClass().getName() + ")";
184      }
185    
186    
187    }