KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xpath > VariableStack


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: VariableStack.java,v 1.46 2004/02/17 04:30:02 minchau Exp $
18  */

19 package org.apache.xpath;
20
21 import javax.xml.transform.TransformerException JavaDoc;
22
23 import org.apache.xalan.res.XSLMessages;
24 import org.apache.xpath.objects.XObject;
25 import org.apache.xpath.res.XPATHErrorResources;
26
27 /**
28  * Defines a class to keep track of a stack for
29  * template arguments and variables.
30  *
31  * <p>This has been changed from the previous incarnations of this
32  * class to be fairly low level.</p>
33  * @xsl.usage internal
34  */

35 public class VariableStack implements Cloneable JavaDoc
36 {
37   /**
38    * limitation for 1K
39    */

40   public static final int CLEARLIMITATION= 1024;
41
42   /**
43    * Constructor for a variable stack.
44    */

45   public VariableStack()
46   {
47     reset();
48   }
49
50   /**
51    * Returns a clone of this variable stack.
52    *
53    * @return a clone of this variable stack.
54    *
55    * @throws CloneNotSupportedException
56    */

57   public synchronized Object JavaDoc clone() throws CloneNotSupportedException JavaDoc
58   {
59
60     VariableStack vs = (VariableStack) super.clone();
61
62     // I *think* I can get away with a shallow clone here?
63
vs._stackFrames = (XObject[]) _stackFrames.clone();
64     vs._links = (int[]) _links.clone();
65
66     return vs;
67   }
68
69   /**
70    * The stack frame where all variables and params will be kept.
71    * @serial
72    */

73   XObject[] _stackFrames = new XObject[XPathContext.RECURSIONLIMIT * 2];
74
75   /**
76    * The top of the stack frame (<code>_stackFrames</code>).
77    * @serial
78    */

79   int _frameTop;
80
81   /**
82    * The bottom index of the current frame (relative to <code>_stackFrames</code>).
83    * @serial
84    */

85   private int _currentFrameBottom;
86
87   /**
88    * The stack of frame positions. I call 'em links because of distant
89    * <a HREF="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
90    * Motorola 68000 assembler</a> memories. :-)
91    * @serial
92    */

93   int[] _links = new int[XPathContext.RECURSIONLIMIT];
94
95   /**
96    * The top of the links stack.
97    */

98   int _linksTop;
99
100   /**
101    * Get the element at the given index, regardless of stackframe.
102    *
103    * @param i index from zero.
104    *
105    * @return The item at the given index.
106    */

107   public XObject elementAt(final int i)
108   {
109     return _stackFrames[i];
110   }
111
112   /**
113    * Get size of the stack.
114    *
115    * @return the total size of the execution stack.
116    */

117   public int size()
118   {
119     return _frameTop;
120   }
121
122   /**
123    * Reset the stack to a start position.
124    *
125    * @return the total size of the execution stack.
126    */

127   public void reset()
128   {
129
130     _frameTop = 0;
131     _linksTop = 0;
132
133     // Adding one here to the stack of frame positions will allow us always
134
// to look one under without having to check if we're at zero.
135
// (As long as the caller doesn't screw up link/unlink.)
136
_links[_linksTop++] = 0;
137     _stackFrames = new XObject[_stackFrames.length];
138   }
139
140   /**
141    * Set the current stack frame.
142    *
143    * @param sf The new stack frame position.
144    */

145   public void setStackFrame(int sf)
146   {
147     _currentFrameBottom = sf;
148   }
149
150   /**
151    * Get the position from where the search should start,
152    * which is either the searchStart property, or the top
153    * of the stack if that value is -1.
154    *
155    * @return The current stack frame position.
156    */

157   public int getStackFrame()
158   {
159     return _currentFrameBottom;
160   }
161
162   /**
163    * Allocates memory (called a stackframe) on the stack; used to store
164    * local variables and parameter arguments.
165    *
166    * <p>I use the link/unlink concept because of distant
167    * <a HREF="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
168    * Motorola 68000 assembler</a> memories.</p>
169    *
170    * @param size The size of the stack frame allocation. This ammount should
171    * normally be the maximum number of variables that you can have allocated
172    * at one time in the new stack frame.
173    *
174    * @return The bottom of the stack frame, from where local variable addressing
175    * should start from.
176    */

177   public int link(final int size)
178   {
179
180     _currentFrameBottom = _frameTop;
181     _frameTop += size;
182
183     if (_frameTop >= _stackFrames.length)
184     {
185       XObject newsf[] = new XObject[_stackFrames.length + XPathContext.RECURSIONLIMIT + size];
186
187       System.arraycopy(_stackFrames, 0, newsf, 0, _stackFrames.length);
188
189       _stackFrames = newsf;
190     }
191
192     if (_linksTop + 1 >= _links.length)
193     {
194       int newlinks[] = new int[_links.length + (CLEARLIMITATION * 2)];
195
196       System.arraycopy(_links, 0, newlinks, 0, _links.length);
197
198       _links = newlinks;
199     }
200
201     _links[_linksTop++] = _currentFrameBottom;
202
203     return _currentFrameBottom;
204   }
205
206   /**
207    * Free up the stack frame that was last allocated with
208    * {@link link(int size)}.
209    */

210   public void unlink()
211   {
212     _frameTop = _links[--_linksTop];
213     _currentFrameBottom = _links[_linksTop - 1];
214   }
215   
216   /**
217    * Free up the stack frame that was last allocated with
218    * {@link link(int size)}.
219    * @param currentFrame The current frame to set to
220    * after the unlink.
221    */

222   public void unlink(int currentFrame)
223   {
224     _frameTop = _links[--_linksTop];
225     _currentFrameBottom = currentFrame;
226   }
227
228   /**
229    * Set a local variable or parameter in the current stack frame.
230    *
231    *
232    * @param index Local variable index relative to the current stack
233    * frame bottom.
234    *
235    * @param val The value of the variable that is being set.
236    */

237   public void setLocalVariable(int index, XObject val)
238   {
239     _stackFrames[index + _currentFrameBottom] = val;
240   }
241
242   /**
243    * Set a local variable or parameter in the specified stack frame.
244    *
245    *
246    * @param index Local variable index relative to the current stack
247    * frame bottom.
248    * NEEDSDOC @param stackFrame
249    *
250    * @param val The value of the variable that is being set.
251    */

252   public void setLocalVariable(int index, XObject val, int stackFrame)
253   {
254     _stackFrames[index + stackFrame] = val;
255   }
256
257   /**
258    * Get a local variable or parameter in the current stack frame.
259    *
260    *
261    * @param xctxt The XPath context, which must be passed in order to
262    * lazy evaluate variables.
263    *
264    * @param index Local variable index relative to the current stack
265    * frame bottom.
266    *
267    * @return The value of the variable.
268    *
269    * @throws TransformerException
270    */

271   public XObject getLocalVariable(XPathContext xctxt, int index)
272           throws TransformerException JavaDoc
273   {
274
275     index += _currentFrameBottom;
276
277     XObject val = _stackFrames[index];
278     
279     if(null == val)
280       throw new TransformerException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VARIABLE_ACCESSED_BEFORE_BIND, null),
281                      xctxt.getSAXLocator());
282       // "Variable accessed before it is bound!", xctxt.getSAXLocator());
283

284     // Lazy execution of variables.
285
if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
286       return (_stackFrames[index] = val.execute(xctxt));
287
288     return val;
289   }
290
291   /**
292    * Get a local variable or parameter in the current stack frame.
293    *
294    *
295    * @param index Local variable index relative to the given
296    * frame bottom.
297    * NEEDSDOC @param frame
298    *
299    * @return The value of the variable.
300    *
301    * @throws TransformerException
302    */

303   public XObject getLocalVariable(int index, int frame)
304           throws TransformerException JavaDoc
305   {
306
307     index += frame;
308
309     XObject val = _stackFrames[index];
310
311     return val;
312   }
313   
314   /**
315    * Get a local variable or parameter in the current stack frame.
316    *
317    *
318    * @param xctxt The XPath context, which must be passed in order to
319    * lazy evaluate variables.
320    *
321    * @param index Local variable index relative to the current stack
322    * frame bottom.
323    *
324    * @return The value of the variable.
325    *
326    * @throws TransformerException
327    */

328   public XObject getLocalVariable(XPathContext xctxt, int index, boolean destructiveOK)
329           throws TransformerException JavaDoc
330   {
331
332     index += _currentFrameBottom;
333
334     XObject val = _stackFrames[index];
335     
336     if(null == val)
337       throw new TransformerException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VARIABLE_ACCESSED_BEFORE_BIND, null),
338                      xctxt.getSAXLocator());
339       // "Variable accessed before it is bound!", xctxt.getSAXLocator());
340

341     // Lazy execution of variables.
342
if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
343       return (_stackFrames[index] = val.execute(xctxt));
344
345     return destructiveOK ? val : val.getFresh();
346   }
347
348   /**
349    * Tell if a local variable has been set or not.
350    *
351    * @param index Local variable index relative to the current stack
352    * frame bottom.
353    *
354    * @return true if the value at the index is not null.
355    *
356    * @throws TransformerException
357    */

358   public boolean isLocalSet(int index) throws TransformerException JavaDoc
359   {
360     return (_stackFrames[index + _currentFrameBottom] != null);
361   }
362
363   /** NEEDSDOC Field m_nulls */
364   private static XObject[] m_nulls = new XObject[CLEARLIMITATION];
365
366   /**
367    * Use this to clear the variables in a section of the stack. This is
368    * used to clear the parameter section of the stack, so that default param
369    * values can tell if they've already been set. It is important to note that
370    * this function has a 1K limitation.
371    *
372    * @param start The start position, relative to the current local stack frame.
373    * @param len The number of slots to be cleared.
374    */

375   public void clearLocalSlots(int start, int len)
376   {
377
378     start += _currentFrameBottom;
379
380     System.arraycopy(m_nulls, 0, _stackFrames, start, len);
381   }
382
383   /**
384    * Set a global variable or parameter in the global stack frame.
385    *
386    *
387    * @param index Local variable index relative to the global stack frame
388    * bottom.
389    *
390    * @param val The value of the variable that is being set.
391    */

392   public void setGlobalVariable(final int index, final XObject val)
393   {
394     _stackFrames[index] = val;
395   }
396
397   /**
398    * Get a global variable or parameter from the global stack frame.
399    *
400    *
401    * @param xctxt The XPath context, which must be passed in order to
402    * lazy evaluate variables.
403    *
404    * @param index Global variable index relative to the global stack
405    * frame bottom.
406    *
407    * @return The value of the variable.
408    *
409    * @throws TransformerException
410    */

411   public XObject getGlobalVariable(XPathContext xctxt, final int index)
412           throws TransformerException JavaDoc
413   {
414
415     XObject val = _stackFrames[index];
416
417     // Lazy execution of variables.
418
if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
419       return (_stackFrames[index] = val.execute(xctxt));
420
421     return val;
422   }
423   
424   /**
425    * Get a global variable or parameter from the global stack frame.
426    *
427    *
428    * @param xctxt The XPath context, which must be passed in order to
429    * lazy evaluate variables.
430    *
431    * @param index Global variable index relative to the global stack
432    * frame bottom.
433    *
434    * @return The value of the variable.
435    *
436    * @throws TransformerException
437    */

438   public XObject getGlobalVariable(XPathContext xctxt, final int index, boolean destructiveOK)
439           throws TransformerException JavaDoc
440   {
441
442     XObject val = _stackFrames[index];
443
444     // Lazy execution of variables.
445
if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
446       return (_stackFrames[index] = val.execute(xctxt));
447
448     return destructiveOK ? val : val.getFresh();
449   }
450
451   /**
452    * Get a variable based on it's qualified name.
453    * This is for external use only.
454    *
455    * @param xctxt The XPath context, which must be passed in order to
456    * lazy evaluate variables.
457    *
458    * @param qname The qualified name of the variable.
459    *
460    * @return The evaluated value of the variable.
461    *
462    * @throws javax.xml.transform.TransformerException
463    */

464   public XObject getVariableOrParam(
465           XPathContext xctxt, org.apache.xml.utils.QName qname)
466             throws javax.xml.transform.TransformerException JavaDoc
467   {
468
469     org.apache.xml.utils.PrefixResolver prefixResolver =
470       xctxt.getNamespaceContext();
471
472     // Get the current ElemTemplateElement, which must be pushed in as the
473
// prefix resolver, and then walk backwards in document order, searching
474
// for an xsl:param element or xsl:variable element that matches our
475
// qname. If we reach the top level, use the StylesheetRoot's composed
476
// list of top level variables and parameters.
477

478     if (prefixResolver instanceof org.apache.xalan.templates.ElemTemplateElement)
479     {
480       
481       org.apache.xalan.templates.ElemVariable vvar;
482
483       org.apache.xalan.templates.ElemTemplateElement prev =
484         (org.apache.xalan.templates.ElemTemplateElement) prefixResolver;
485
486       if (!(prev instanceof org.apache.xalan.templates.Stylesheet))
487       {
488         while ( !(prev.getParentNode() instanceof org.apache.xalan.templates.Stylesheet) )
489         {
490           org.apache.xalan.templates.ElemTemplateElement savedprev = prev;
491
492           while (null != (prev = prev.getPreviousSiblingElem()))
493           {
494             if (prev instanceof org.apache.xalan.templates.ElemVariable)
495             {
496               vvar = (org.apache.xalan.templates.ElemVariable) prev;
497
498               if (vvar.getName().equals(qname))
499                 return getLocalVariable(xctxt, vvar.getIndex());
500             }
501           }
502           prev = savedprev.getParentElem();
503         }
504       }
505
506       vvar = prev.getStylesheetRoot().getVariableOrParamComposed(qname);
507       if (null != vvar)
508         return getGlobalVariable(xctxt, vvar.getIndex());
509     }
510
511     throw new javax.xml.transform.TransformerException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VAR_NOT_RESOLVABLE, new Object JavaDoc[]{qname.toString()})); //"Variable not resolvable: " + qname);
512
}
513 } // end VariableStack
514

515
Popular Tags