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: * $Id: DOMSubTreeData.java,v 1.3 2006/09/29 12:04:54 kumarjayanti Exp $
024: */
025: package com.sun.xml.wss.impl.dsig;
026:
027: import javax.xml.crypto.NodeSetData;
028: import java.util.ArrayList;
029: import java.util.Iterator;
030: import java.util.List;
031: import java.util.ListIterator;
032: import java.util.NoSuchElementException;
033: import org.w3c.dom.NamedNodeMap;
034: import org.w3c.dom.Node;
035:
036: /**
037: * This is a subtype of NodeSetData that represents a dereferenced
038: * same-document URI as the root of a subdocument. The main reason is
039: * for efficiency and performance, as some transforms can operate
040: * directly on the subdocument and there is no need to convert it
041: * first to an XPath node-set.
042: */
043: public class DOMSubTreeData implements NodeSetData {
044:
045: private boolean excludeComments;
046: private Iterator ni;
047: private Node root;
048:
049: public DOMSubTreeData(Node root, boolean excludeComments) {
050: this .root = root;
051: this .ni = new DelayedNodeIterator(root, excludeComments);
052: this .excludeComments = excludeComments;
053: }
054:
055: public Iterator iterator() {
056: return ni;
057: }
058:
059: public Node getRoot() {
060: return root;
061: }
062:
063: public boolean excludeComments() {
064: return excludeComments;
065: }
066:
067: /**
068: * This is an Iterator that contains a backing node-set that is
069: * not populated until the caller first attempts to advance the iterator.
070: */
071: static class DelayedNodeIterator implements Iterator {
072: private Node root;
073: private List nodeSet;
074: private ListIterator li;
075: private boolean withComments;
076:
077: DelayedNodeIterator(Node root, boolean excludeComments) {
078: this .root = root;
079: this .withComments = !excludeComments;
080: }
081:
082: public boolean hasNext() {
083: if (nodeSet == null) {
084: nodeSet = dereferenceSameDocumentURI(root);
085: li = nodeSet.listIterator();
086: }
087: return li.hasNext();
088: }
089:
090: public Object next() {
091: if (nodeSet == null) {
092: nodeSet = dereferenceSameDocumentURI(root);
093: li = nodeSet.listIterator();
094: }
095: if (li.hasNext()) {
096: return (Node) li.next();
097: } else {
098: throw new NoSuchElementException();
099: }
100: }
101:
102: public void remove() {
103: throw new UnsupportedOperationException();
104: }
105:
106: /**
107: * Dereferences a same-document URI fragment.
108: *
109: * @param node the node (document or element) referenced by the
110: * URI fragment. If null, returns an empty set.
111: * @return a set of nodes (minus any comment nodes)
112: */
113: private List dereferenceSameDocumentURI(Node node) {
114: List nodeSet = new ArrayList();
115: if (node != null) {
116: nodeSetMinusCommentNodes(node, nodeSet, null);
117: }
118: return nodeSet;
119: }
120:
121: /**
122: * Recursively traverses the subtree, and returns an XPath-equivalent
123: * node-set of all nodes traversed, excluding any comment nodes,
124: * if specified.
125: *
126: * @param node the node to traverse
127: * @param nodeSet the set of nodes traversed so far
128: * @param the previous sibling node
129: */
130: private void nodeSetMinusCommentNodes(Node node, List nodeSet,
131: Node prevSibling) {
132: switch (node.getNodeType()) {
133: case Node.ELEMENT_NODE:
134: NamedNodeMap attrs = node.getAttributes();
135: if (attrs != null) {
136: for (int i = 0; i < attrs.getLength(); i++) {
137: nodeSet.add(attrs.item(i));
138: }
139: }
140: nodeSet.add(node);
141: Node pSibling = null;
142: for (Node child = node.getFirstChild(); child != null; child = child
143: .getNextSibling()) {
144: nodeSetMinusCommentNodes(child, nodeSet, pSibling);
145: pSibling = child;
146: }
147: break;
148: case Node.TEXT_NODE:
149: case Node.CDATA_SECTION_NODE:
150: // emulate XPath which only returns the first node in
151: // contiguous text/cdata nodes
152: if (prevSibling != null
153: && (prevSibling.getNodeType() == Node.TEXT_NODE || prevSibling
154: .getNodeType() == Node.CDATA_SECTION_NODE)) {
155: return;
156: }
157: case Node.PROCESSING_INSTRUCTION_NODE:
158: nodeSet.add(node);
159: break;
160: case Node.COMMENT_NODE:
161: if (withComments) {
162: nodeSet.add(node);
163: }
164: }
165: }
166: }
167: }
|