KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright 2001-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 package org.apache.axis.utils;
17
18 import org.apache.axis.components.logger.LogFactory;
19 import org.apache.axis.AxisProperties;
20 import org.apache.axis.Constants;
21 import org.apache.commons.logging.Log;
22
23 import java.util.ArrayList JavaDoc;
24
25 /**
26  * The abstraction this class provides is a push down stack of variable
27  * length frames of prefix to namespace mappings. Used for keeping track
28  * of what namespaces are active at any given point as an XML document is
29  * traversed or produced.
30  *
31  * From a performance point of view, this data will both be modified frequently
32  * (at a minimum, there will be one push and pop per XML element processed),
33  * and scanned frequently (many of the "good" mappings will be at the bottom
34  * of the stack). The one saving grace is that the expected maximum
35  * cardinalities of the number of frames and the number of total mappings
36  * is only in the dozens, representing the nesting depth of an XML document
37  * and the number of active namespaces at any point in the processing.
38  *
39  * Accordingly, this stack is implemented as a single array, will null
40  * values used to indicate frame boundaries.
41  *
42  * @author James Snell
43  * @author Glen Daniels (gdaniels@apache.org)
44  * @author Sam Ruby (rubys@us.ibm.com)
45  */

46 public class NSStack {
47     protected static Log log =
48         LogFactory.getLog(NSStack.class.getName());
49     
50     private Mapping[] stack;
51     private int top = 0;
52     private int iterator = 0;
53     private int currentDefaultNS = -1;
54     private boolean optimizePrefixes = true;
55     
56     // invariant member variable to track low-level logging requirements
57
// we cache this once per instance lifecycle to avoid repeated lookups
58
// in heavily used code.
59
private final boolean traceEnabled = log.isTraceEnabled();
60
61     public NSStack(boolean optimizePrefixes) {
62         this.optimizePrefixes = optimizePrefixes;
63         stack = new Mapping[32];
64         stack[0] = null;
65     }
66
67     public NSStack() {
68         stack = new Mapping[32];
69         stack[0] = null;
70     }
71     
72     /**
73      * Create a new frame at the top of the stack.
74      */

75     public void push() {
76         top ++;
77
78         if (top >= stack.length) {
79            Mapping newstack[] = new Mapping[stack.length*2];
80            System.arraycopy (stack, 0, newstack, 0, stack.length);
81            stack = newstack;
82         }
83
84         if (traceEnabled)
85             log.trace("NSPush (" + stack.length + ")");
86
87         stack[top] = null;
88     }
89     
90     /**
91      * Remove the top frame from the stack.
92      */

93     public void pop() {
94         clearFrame();
95
96         top--;
97
98         // If we've moved below the current default NS, figure out the new
99
// default (if any)
100
if (top < currentDefaultNS) {
101             // Reset the currentDefaultNS to ignore the frame just removed.
102
currentDefaultNS = top;
103             while (currentDefaultNS > 0) {
104                 if (stack[currentDefaultNS] != null &&
105                         stack[currentDefaultNS].getPrefix().length() == 0)
106                     break;
107                 currentDefaultNS--;
108             }
109         }
110         
111         if (top == 0) {
112             if (traceEnabled)
113                 log.trace("NSPop (" + Messages.getMessage("empty00") + ")");
114
115             return;
116         }
117         
118         if (traceEnabled){
119             log.trace("NSPop (" + stack.length + ")");
120         }
121     }
122     
123     /**
124      * Return a copy of the current frame. Returns null if none are present.
125      */

126     public ArrayList JavaDoc cloneFrame() {
127         if (stack[top] == null) return null;
128
129         ArrayList JavaDoc clone = new ArrayList JavaDoc();
130
131         for (Mapping map=topOfFrame(); map!=null; map=next()) {
132             clone.add(map);
133         }
134
135         return clone;
136     }
137
138     /**
139      * Remove all mappings from the current frame.
140      */

141     private void clearFrame() {
142         while (stack[top] != null) top--;
143     }
144
145     /**
146      * Reset the embedded iterator in this class to the top of the current
147      * (i.e., last) frame. Note that this is not threadsafe, nor does it
148      * provide multiple iterators, so don't use this recursively. Nor
149      * should you modify the stack while iterating over it.
150      */

151     public Mapping topOfFrame() {
152         iterator = top;
153         while (stack[iterator] != null) iterator--;
154         iterator++;
155         return next();
156     }
157
158     /**
159      * Return the next namespace mapping in the top frame.
160      */

161     public Mapping next() {
162         if (iterator > top) {
163             return null;
164         } else {
165             return stack[iterator++];
166         }
167     }
168
169     /**
170      * Add a mapping for a namespaceURI to the specified prefix to the top
171      * frame in the stack. If the prefix is already mapped in that frame,
172      * remap it to the (possibly different) namespaceURI.
173      */

174     public void add(String JavaDoc namespaceURI, String JavaDoc prefix) {
175         int idx = top;
176         prefix = prefix.intern();
177         try {
178             // Replace duplicate prefixes (last wins - this could also fault)
179
for (int cursor=top; stack[cursor]!=null; cursor--) {
180                 if (stack[cursor].getPrefix() == prefix) {
181                     stack[cursor].setNamespaceURI(namespaceURI);
182                     idx = cursor;
183                     return;
184                 }
185             }
186             
187             push();
188             stack[top] = new Mapping(namespaceURI, prefix);
189             idx = top;
190         } finally {
191             // If this is the default namespace, note the new in-scope
192
// default is here.
193
if (prefix.length() == 0) {
194                 currentDefaultNS = idx;
195             }
196         }
197     }
198     
199     /**
200      * Return an active prefix for the given namespaceURI. NOTE : This
201      * may return null even if the namespaceURI was actually mapped further
202      * up the stack IF the prefix which was used has been repeated further
203      * down the stack. I.e.:
204      *
205      * <pre:outer xmlns:pre="namespace">
206      * <pre:inner xmlns:pre="otherNamespace">
207      * *here's where we're looking*
208      * </pre:inner>
209      * </pre:outer>
210      *
211      * If we look for a prefix for "namespace" at the indicated spot, we won't
212      * find one because "pre" is actually mapped to "otherNamespace"
213      */

214     public String JavaDoc getPrefix(String JavaDoc namespaceURI, boolean noDefault) {
215         if ((namespaceURI == null) || (namespaceURI.length()==0))
216             return null;
217         
218         if(optimizePrefixes) {
219             // If defaults are OK, and the given NS is the current default,
220
// return "" as the prefix to favor defaults where possible.
221
if (!noDefault && currentDefaultNS > 0 && stack[currentDefaultNS] != null &&
222                     namespaceURI == stack[currentDefaultNS].getNamespaceURI())
223                 return "";
224         }
225         namespaceURI = namespaceURI.intern();
226
227         for (int cursor=top; cursor>0; cursor--) {
228             Mapping map = stack[cursor];
229             if (map == null)
230                 continue;
231
232             if (map.getNamespaceURI() == namespaceURI) {
233                 String JavaDoc possiblePrefix = map.getPrefix();
234                 if (noDefault && possiblePrefix.length() == 0)
235                     continue;
236     
237                 // now make sure that this is the first occurance of this
238
// particular prefix
239
for (int cursor2 = top; true; cursor2--) {
240                     if (cursor2 == cursor)
241                         return possiblePrefix;
242                     map = stack[cursor2];
243                     if (map == null)
244                         continue;
245                     if (possiblePrefix == map.getPrefix())
246                         break;
247                 }
248             }
249         }
250         
251         return null;
252     }
253
254     /**
255      * Return an active prefix for the given namespaceURI, including
256      * the default prefix ("").
257      */

258     public String JavaDoc getPrefix(String JavaDoc namespaceURI) {
259         return getPrefix(namespaceURI, false);
260     }
261     
262     /**
263      * Given a prefix, return the associated namespace (if any).
264      */

265     public String JavaDoc getNamespaceURI(String JavaDoc prefix) {
266         if (prefix == null)
267             prefix = "";
268
269         prefix = prefix.intern();
270
271         for (int cursor=top; cursor>0; cursor--) {
272             Mapping map = stack[cursor];
273             if (map == null) continue;
274         
275             if (map.getPrefix() == prefix)
276                 return map.getNamespaceURI();
277         }
278         
279         return null;
280     }
281     
282     /**
283      * Produce a trace dump of the entire stack, starting from the top and
284      * including frame markers.
285      */

286     public void dump(String JavaDoc dumpPrefix)
287     {
288         for (int cursor=top; cursor>0; cursor--) {
289             Mapping map = stack[cursor];
290
291             if (map == null) {
292                 log.trace(dumpPrefix + Messages.getMessage("stackFrame00"));
293             } else {
294                 log.trace(dumpPrefix + map.getNamespaceURI() + " -> " + map.getPrefix());
295             }
296         }
297     }
298 }
299
Popular Tags