KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > axis > utils > NSStack


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Axis" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation. For more
52  * information on the Apache Software Foundation, please see
53  * <http://www.apache.org/>.
54  */

55 package org.jboss.axis.utils;
56
57 import org.jboss.logging.Logger;
58
59 import java.util.ArrayList JavaDoc;
60
61 /**
62  * The abstraction this class provides is a push down stack of variable
63  * length frames of prefix to namespace mappings. Used for keeping track
64  * of what namespaces are active at any given point as an XML document is
65  * traversed or produced.
66  * <p/>
67  * From a performance point of view, this data will both be modified frequently
68  * (at a minimum, there will be one push and pop per XML element processed),
69  * and scanned frequently (many of the "good" mappings will be at the bottom
70  * of the stack). The one saving grace is that the expected maximum
71  * cardinalities of the number of frames and the number of total mappings
72  * is only in the dozens, representing the nesting depth of an XML document
73  * and the number of active namespaces at any point in the processing.
74  * <p/>
75  * Accordingly, this stack is implemented as a single array, will null
76  * values used to indicate frame boundaries.
77  *
78  * @author James Snell
79  * @author Glen Daniels (gdaniels@macromedia.com)
80  * @author Sam Ruby (rubys@us.ibm.com)
81  */

82 public class NSStack
83 {
84    private static Logger log = Logger.getLogger(NSStack.class.getName());
85
86    private Mapping[] stack;
87    private int top = 0;
88    private int iterator = 0;
89    private int currentDefaultNS = -1;
90
91    public NSStack()
92    {
93       stack = new Mapping[32];
94       stack[0] = null;
95    }
96
97    /**
98     * Create a new frame at the top of the stack.
99     */

100    public void push()
101    {
102       top++;
103
104       if (top >= stack.length)
105       {
106          Mapping newstack[] = new Mapping[stack.length * 2];
107          System.arraycopy(stack, 0, newstack, 0, stack.length);
108          stack = newstack;
109       }
110
111 // if (log.isTraceEnabled())
112
// log.trace("NSPush (" + stack.length + ")");
113

114       stack[top] = null;
115    }
116
117    /**
118     * Remove the top frame from the stack.
119     */

120    public void pop()
121    {
122       clearFrame();
123
124       top--;
125
126       // If we've moved below the current default NS, figure out the new
127
// default (if any)
128
if (top < currentDefaultNS)
129       {
130          while (currentDefaultNS > 0)
131          {
132             if (stack[currentDefaultNS] != null &&
133                     stack[currentDefaultNS].getPrefix().length() == 0)
134                break;
135             currentDefaultNS--;
136          }
137       }
138
139       if (top == 0)
140       {
141 // if (log.isTraceEnabled())
142
// log.trace("NSPop (" + Messages.getMessage("empty00") + ")");
143
return;
144       }
145         
146 // if (log.isTraceEnabled())
147
// log.trace("NSPop (" + stack.length + ")");
148
}
149
150    /**
151     * Return a copy of the current frame. Returns null if none are present.
152     */

153    public ArrayList JavaDoc cloneFrame()
154    {
155       if (stack[top] == null) return null;
156
157       ArrayList JavaDoc clone = new ArrayList JavaDoc();
158
159       for (Mapping map = topOfFrame(); map != null; map = next())
160       {
161          clone.add(map);
162       }
163
164       return clone;
165    }
166
167    /**
168     * Remove all mappings from the current frame.
169     */

170    private void clearFrame()
171    {
172       while (stack[top] != null) top--;
173    }
174
175    /**
176     * Reset the embedded iterator in this class to the top of the current
177     * (i.e., last) frame. Note that this is not threadsafe, nor does it
178     * provide multiple iterators, so don't use this recursively. Nor
179     * should you modify the stack while iterating over it.
180     */

181    public Mapping topOfFrame()
182    {
183       iterator = top;
184       while (stack[iterator] != null) iterator--;
185       iterator++;
186       return next();
187    }
188
189    /**
190     * Return the next namespace mapping in the top frame.
191     */

192    public Mapping next()
193    {
194       if (iterator > top)
195       {
196          return null;
197       }
198       else
199       {
200          return stack[iterator++];
201       }
202    }
203
204    /**
205     * Add a mapping for a namespaceURI to the specified prefix to the top
206     * frame in the stack. If the prefix is already mapped in that frame,
207     * remap it to the (possibly different) namespaceURI.
208     */

209    public void add(String JavaDoc namespaceURI, String JavaDoc prefix)
210    {
211       int idx = top;
212       try
213       {
214          // Replace duplicate prefixes (last wins - this could also fault)
215
for (int cursor = top; stack[cursor] != null; cursor--)
216          {
217             if (stack[cursor].getPrefix().equals(prefix))
218             {
219                stack[cursor].setNamespaceURI(namespaceURI);
220                idx = cursor;
221                return;
222             }
223          }
224
225          push();
226          stack[top] = new Mapping(namespaceURI, prefix);
227          idx = top;
228       }
229       finally
230       {
231          // If this is the default namespace, note the new in-scope
232
// default is here.
233
if (prefix.length() == 0)
234          {
235             currentDefaultNS = idx;
236          }
237       }
238    }
239
240    /**
241     * Return an active prefix for the given namespaceURI. NOTE : This
242     * may return null even if the namespaceURI was actually mapped further
243     * up the stack IF the prefix which was used has been repeated further
244     * down the stack. I.e.:
245     * <p/>
246     * <pre:outer xmlns:pre="namespace">
247     * <pre:inner xmlns:pre="otherNamespace">
248     * *here's where we're looking*
249     * </pre:inner>
250     * </pre:outer>
251     * <p/>
252     * If we look for a prefix for "namespace" at the indicated spot, we won't
253     * find one because "pre" is actually mapped to "otherNamespace"
254     */

255    public String JavaDoc getPrefix(String JavaDoc namespaceURI, boolean noDefault)
256    {
257       if ((namespaceURI == null) || (namespaceURI.equals("")))
258          return null;
259
260       int hash = namespaceURI.hashCode();
261
262       // If defaults are OK, and the given NS is the current default,
263
// return "" as the prefix to favor defaults where possible.
264
if (!noDefault && currentDefaultNS > 0 && stack[currentDefaultNS] != null &&
265               namespaceURI.equals(stack[currentDefaultNS].getNamespaceURI()))
266          return "";
267
268       for (int cursor = top; cursor > 0; cursor--)
269       {
270          Mapping map = stack[cursor];
271          if (map == null) continue;
272
273          if (map.getNamespaceHash() == hash &&
274                  map.getNamespaceURI().equals(namespaceURI))
275          {
276             String JavaDoc possiblePrefix = map.getPrefix();
277             if (noDefault && possiblePrefix.length() == 0) continue;
278
279             // now make sure that this is the first occurance of this
280
// particular prefix
281
int ppHash = possiblePrefix.hashCode();
282             for (int cursor2 = top; true; cursor2--)
283             {
284                if (cursor2 == cursor) return possiblePrefix;
285                map = stack[cursor2];
286                if (map == null) continue;
287                if (ppHash == map.getPrefixHash() &&
288                        possiblePrefix.equals(map.getPrefix()))
289                   break;
290             }
291          }
292       }
293
294       return null;
295    }
296
297    /**
298     * Return an active prefix for the given namespaceURI, including
299     * the default prefix ("").
300     */

301    public String JavaDoc getPrefix(String JavaDoc namespaceURI)
302    {
303       return getPrefix(namespaceURI, false);
304    }
305
306    /**
307     * Given a prefix, return the associated namespace (if any).
308     */

309    public String JavaDoc getNamespaceURI(String JavaDoc prefix)
310    {
311       if (prefix == null)
312          prefix = "";
313
314       int hash = prefix.hashCode();
315
316       for (int cursor = top; cursor > 0; cursor--)
317       {
318          Mapping map = stack[cursor];
319          if (map == null) continue;
320
321          if (map.getPrefixHash() == hash && map.getPrefix().equals(prefix))
322             return map.getNamespaceURI();
323       }
324
325       return null;
326    }
327
328    /**
329     * Produce a trace dump of the entire stack, starting from the top and
330     * including frame markers.
331     */

332    public void dump(String JavaDoc dumpPrefix)
333    {
334       for (int cursor = top; cursor > 0; cursor--)
335       {
336          Mapping map = stack[cursor];
337
338          if (map == null)
339          {
340             log.trace(dumpPrefix + Messages.getMessage("stackFrame00"));
341          }
342          else
343          {
344             log.trace(dumpPrefix + map.getNamespaceURI() + " -> " + map.getPrefix());
345          }
346       }
347    }
348 }
349
Popular Tags