001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the License). You may not use this file except in
005: * compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * Header Notice in each file and include the License file
014: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
015: * If applicable, add the following below the CDDL Header,
016: * with the fields enclosed by brackets [] replaced by
017: * you own identifying information:
018: * "Portions Copyrighted [year] [name of copyright owner]"
019: *
020: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
021: */
022:
023: /*
024: * Copyright 1999-2004 The Apache Software Foundation.
025: *
026: * Licensed under the Apache License, Version 2.0 (the "License");
027: * you may not use this file except in compliance with the License.
028: * You may obtain a copy of the License at
029: *
030: * http://www.apache.org/licenses/LICENSE-2.0
031: *
032: * Unless required by applicable law or agreed to in writing, software
033: * distributed under the License is distributed on an "AS IS" BASIS,
034: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
035: * See the License for the specific language governing permissions and
036: * limitations under the License.
037: *
038: */
039: package com.sun.xml.wss.impl.transform;
040:
041: import java.util.ArrayList;
042: import java.util.Collection;
043: import java.util.HashMap;
044: import java.util.Iterator;
045: import java.util.List;
046: import java.util.Map;
047:
048: import org.w3c.dom.Attr;
049: import org.w3c.dom.Node;
050:
051: /**
052: * A stack based Symble Table.
053: *<br>For speed reasons all the symbols are introduced in the same map,
054: * and at the same time in a list so it can be removed when the frame is pop back.
055: * @author Raul Benito
056: **/
057: public class NameSpaceSymbTable {
058:
059: /**The map betwen prefix-> entry table. */
060: HashMap symb = new HashMap();
061: /**The level of nameSpaces (for Inclusive visibility).*/
062: int nameSpaces = 0;
063: /**The stacks for removing the definitions when doing pop.*/
064: List level = new ArrayList();
065: boolean cloned = true;
066: static final String XMLNS = "xmlns";
067:
068: /**
069: * Default constractor
070: **/
071: public NameSpaceSymbTable() {
072: //Insert the default binding for xmlns.
073: NameSpaceSymbEntry ne = new NameSpaceSymbEntry("", null, true);
074: ne.lastrendered = "";
075: symb.put(XMLNS, ne);
076: }
077:
078: /**
079: * Get all the unrendered nodes in the name space.
080: * For Inclusive rendering
081: * @param result the list where to fill the unrendered xmlns definitions.
082: **/
083: public void getUnrenderedNodes(Collection result) {
084: //List result=new ArrayList();
085: Iterator it = symb.entrySet().iterator();
086: while (it.hasNext()) {
087: NameSpaceSymbEntry n = (NameSpaceSymbEntry) ((Map.Entry) it
088: .next()).getValue();
089: //put them rendered?
090: if ((!n.rendered) && (n.n != null)) {
091: result.add(n.n);
092: n.rendered = true;
093: }
094: }
095: }
096:
097: /**
098: * Push a frame for visible namespace.
099: * For Inclusive rendering.
100: **/
101: public void outputNodePush() {
102: nameSpaces++;
103: push();
104: }
105:
106: /**
107: * Pop a frame for visible namespace.
108: **/
109: public void outputNodePop() {
110: nameSpaces--;
111: pop();
112: }
113:
114: /**
115: * Push a frame for a node.
116: * Inclusive or Exclusive.
117: **/
118: public void push() {
119: //Put the number of namespace definitions in the stack.
120: /**if (cloned) {
121: Object ob[]= {symb,cloned ? symb : null};
122: level.add(ob);
123: } **/
124: level.add(null);
125: cloned = false;
126: }
127:
128: /**
129: * Pop a frame.
130: * Inclusive or Exclusive.
131: **/
132: public void pop() {
133: int size = level.size() - 1;
134: Object ob = level.remove(size);
135: if (ob != null) {
136: symb = (HashMap) ob;
137: if (size == 0) {
138: cloned = false;
139: } else
140: cloned = (level.get(size - 1) != symb);
141: } else {
142: cloned = false;
143: }
144:
145: }
146:
147: final void needsClone() {
148: if (!cloned) {
149: level.remove(level.size() - 1);
150: level.add(symb);
151: symb = (HashMap) symb.clone();
152: cloned = true;
153: }
154: }
155:
156: /**
157: * Gets the attribute node that defines the binding for the prefix.
158: * @param prefix the prefix to obtain the attribute.
159: * @return null if there is no need to render the prefix. Otherwise the node of
160: * definition.
161: **/
162: public Attr getMapping(String prefix) {
163: NameSpaceSymbEntry entry = (NameSpaceSymbEntry) symb
164: .get(prefix);
165: if (entry == null) {
166: //There is no definition for the prefix(a bug?).
167: return null;
168: }
169: if (entry.rendered) {
170: //No need to render an entry already rendered.
171: return null;
172: }
173: // Mark this entry as render.
174: entry = (NameSpaceSymbEntry) entry.clone();
175: needsClone();
176: symb.put(prefix, entry);
177: entry.rendered = true;
178: entry.level = nameSpaces;
179: entry.lastrendered = entry.uri;
180: // Return the node for outputing.
181: return entry.n;
182: }
183:
184: /**
185: * Gets a definition without mark it as render.
186: * For render in exclusive c14n the namespaces in the include prefixes.
187: * @param prefix The prefix whose definition is neaded.
188: * @return the attr to render, null if there is no need to render
189: **/
190: public Attr getMappingWithoutRendered(String prefix) {
191: NameSpaceSymbEntry entry = (NameSpaceSymbEntry) symb
192: .get(prefix);
193: if (entry == null) {
194: return null;
195: }
196: if (entry.rendered) {
197: return null;
198: }
199: return entry.n;
200: }
201:
202: /**
203: * Adds the mapping for a prefix.
204: * @param prefix the prefix of definition
205: * @param uri the Uri of the definition
206: * @param n the attribute that have the definition
207: * @return true if there is already defined.
208: **/
209: public boolean addMapping(String prefix, String uri, Attr n) {
210: NameSpaceSymbEntry ob = (NameSpaceSymbEntry) symb.get(prefix);
211: if ((ob != null) && uri.equals(ob.uri)) {
212: //If we have it previously defined. Don't keep working.
213: return false;
214: }
215: //Creates and entry in the table for this new definition.
216: NameSpaceSymbEntry ne = new NameSpaceSymbEntry(uri, n, false);
217: needsClone();
218: symb.put(prefix, ne);
219: if (ob != null) {
220: //We have a previous definition store it for the pop.
221: //Check if a previous definition(not the inmidiatly one) has been rendered.
222: ne.lastrendered = ob.lastrendered;
223: if ((ob.lastrendered != null)
224: && (ob.lastrendered.equals(uri))) {
225: //Yes it is. Mark as rendered.
226: ne.rendered = true;
227: }
228: }
229: return true;
230: }
231:
232: /**
233: * Adds a definition and mark it as render.
234: * For inclusive c14n.
235: * @param prefix the prefix of definition
236: * @param uri the Uri of the definition
237: * @param n the attribute that have the definition
238: * @return the attr to render, null if there is no need to render
239: **/
240: public Node addMappingAndRender(String prefix, String uri, Attr n) {
241: NameSpaceSymbEntry ob = (NameSpaceSymbEntry) symb.get(prefix);
242:
243: if ((ob != null) && uri.equals(ob.uri)) {
244: if (!ob.rendered) {
245: ob = (NameSpaceSymbEntry) ob.clone();
246: needsClone();
247: symb.put(prefix, ob);
248: ob.lastrendered = uri;
249: ob.rendered = true;
250: return ob.n;
251: }
252: return null;
253: }
254:
255: NameSpaceSymbEntry ne = new NameSpaceSymbEntry(uri, n, true);
256: ne.lastrendered = uri;
257: needsClone();
258: symb.put(prefix, ne);
259: if (ob != null) {
260:
261: if ((ob.lastrendered != null)
262: && (ob.lastrendered.equals(uri))) {
263: ne.rendered = true;
264: return null;
265: }
266: }
267: return ne.n;
268: }
269:
270: /**
271: * Adds & gets(if needed) the attribute node that defines the binding for the prefix.
272: * Take on account if the rules of rendering in the inclusive c14n.
273: * For inclusive c14n.
274: * @param prefix the prefix to obtain the attribute.
275: * @param outputNode the container element is an output element.
276: * @param uri the Uri of the definition
277: * @param n the attribute that have the definition
278: * @return null if there is no need to render the prefix. Otherwise the node of
279: * definition.
280: **/
281: public Node addMappingAndRenderXNodeSet(String prefix, String uri,
282: Attr n, boolean outputNode) {
283: NameSpaceSymbEntry ob = (NameSpaceSymbEntry) symb.get(prefix);
284: int visibleNameSpaces = nameSpaces;
285: if ((ob != null) && uri.equals(ob.uri)) {
286: if (!ob.rendered) {
287: ob = (NameSpaceSymbEntry) ob.clone();
288: needsClone();
289: symb.put(prefix, ob);
290: ob.rendered = true;
291: ob.level = visibleNameSpaces;
292: return ob.n;
293: }
294: ob = (NameSpaceSymbEntry) ob.clone();
295: needsClone();
296: symb.put(prefix, ob);
297: if (outputNode
298: && (((visibleNameSpaces - ob.level) < 2) || XMLNS
299: .equals(prefix))) {
300: ob.level = visibleNameSpaces;
301: return null; //Already rendered, just return nulll
302: }
303: ob.level = visibleNameSpaces;
304: return ob.n;
305: }
306:
307: NameSpaceSymbEntry ne = new NameSpaceSymbEntry(uri, n, true);
308: ne.level = nameSpaces;
309: ne.rendered = true;
310: needsClone();
311: symb.put(prefix, ne);
312: if (ob != null) {
313: ne.lastrendered = ob.lastrendered;
314:
315: if ((ob.lastrendered != null)
316: && (ob.lastrendered.equals(uri))) {
317: ne.rendered = true;
318: }
319: }
320: return ne.n;
321: }
322: }
323:
324: /**
325: * The internal structure of NameSpaceSymbTable.
326: **/
327: class NameSpaceSymbEntry implements Cloneable {
328: NameSpaceSymbEntry(String name, Attr n, boolean rendered) {
329: this .uri = name;
330: this .rendered = rendered;
331: this .n = n;
332: }
333:
334: /** @inheritDoc */
335: public Object clone() {
336: try {
337: return super .clone();
338: } catch (CloneNotSupportedException e) {
339: return null;
340: }
341: }
342:
343: /** The level where the definition was rendered(Only for inclusive) */
344: int level = 0;
345: /**The URI that the prefix defines */
346: String uri;
347: /**The last output in the URI for this prefix (This for speed reason).*/
348: String lastrendered = null;
349: /**This prefix-URI has been already render or not.*/
350: boolean rendered = false;
351: /**The attribute to include.*/
352: Attr n;
353: };
|