001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.tools.xjc.reader.xmlschema.bindinfo;
038:
039: import java.util.ArrayList;
040:
041: import org.xml.sax.Attributes;
042: import org.xml.sax.ContentHandler;
043: import org.xml.sax.Locator;
044: import org.xml.sax.SAXException;
045: import org.xml.sax.XMLFilter;
046: import org.xml.sax.helpers.XMLFilterImpl;
047:
048: /**
049: * {@link XMLFilter} that can fork an event to another {@link ContentHandler}
050: * in the middle.
051: *
052: * <p>
053: * The side handler receives SAX events before the next handler in the filter chain does.
054: *
055: * @author Kohsuke Kawaguchi
056: */
057: public class ForkingFilter extends XMLFilterImpl {
058:
059: /**
060: * Non-null if we are also forking events to this handler.
061: */
062: private ContentHandler side;
063:
064: /**
065: * The depth of the current element that the {@link #side} handler
066: * is seeing.
067: */
068: private int depth;
069:
070: /**
071: * In-scope namespace mapping.
072: * namespaces[2n ] := prefix
073: * namespaces[2n+1] := namespace URI
074: */
075: private final ArrayList<String> namespaces = new ArrayList<String>();
076:
077: private Locator loc;
078:
079: public ForkingFilter() {
080: }
081:
082: public ForkingFilter(ContentHandler next) {
083: setContentHandler(next);
084: }
085:
086: public ContentHandler getSideHandler() {
087: return side;
088: }
089:
090: public void setDocumentLocator(Locator locator) {
091: super .setDocumentLocator(locator);
092: this .loc = locator;
093: }
094:
095: public void startDocument() throws SAXException {
096: reset();
097: super .startDocument();
098: }
099:
100: private void reset() {
101: namespaces.clear();
102: side = null;
103: depth = 0;
104: }
105:
106: public void endDocument() throws SAXException {
107: loc = null;
108: reset();
109: super .endDocument();
110: }
111:
112: public void startPrefixMapping(String prefix, String uri)
113: throws SAXException {
114: if (side != null)
115: side.startPrefixMapping(prefix, uri);
116: namespaces.add(prefix);
117: namespaces.add(uri);
118: super .startPrefixMapping(prefix, uri);
119: }
120:
121: public void endPrefixMapping(String prefix) throws SAXException {
122: if (side != null)
123: side.endPrefixMapping(prefix);
124: super .endPrefixMapping(prefix);
125: namespaces.remove(namespaces.size() - 1);
126: namespaces.remove(namespaces.size() - 1);
127: }
128:
129: public void startElement(String uri, String localName,
130: String qName, Attributes atts) throws SAXException {
131: if (side != null) {
132: side.startElement(uri, localName, qName, atts);
133: depth++;
134: }
135: super .startElement(uri, localName, qName, atts);
136: }
137:
138: /**
139: * Starts the event forking.
140: */
141: public void startForking(String uri, String localName,
142: String qName, Attributes atts, ContentHandler side)
143: throws SAXException {
144: if (this .side != null)
145: throw new IllegalStateException(); // can't fork to two handlers
146:
147: this .side = side;
148: depth = 1;
149: side.setDocumentLocator(loc);
150: side.startDocument();
151: for (int i = 0; i < namespaces.size(); i += 2)
152: side.startPrefixMapping(namespaces.get(i), namespaces
153: .get(i + 1));
154: side.startElement(uri, localName, qName, atts);
155: }
156:
157: public void endElement(String uri, String localName, String qName)
158: throws SAXException {
159: if (side != null) {
160: side.endElement(uri, localName, qName);
161: depth--;
162: if (depth == 0) {
163: for (int i = namespaces.size() - 2; i >= 0; i -= 2)
164: side.endPrefixMapping(namespaces.get(i));
165: side.endDocument();
166: side = null;
167: }
168: }
169: super .endElement(uri, localName, qName);
170: }
171:
172: public void characters(char ch[], int start, int length)
173: throws SAXException {
174: if (side != null)
175: side.characters(ch, start, length);
176: super .characters(ch, start, length);
177: }
178:
179: public void ignorableWhitespace(char ch[], int start, int length)
180: throws SAXException {
181: if (side != null)
182: side.ignorableWhitespace(ch, start, length);
183: super.ignorableWhitespace(ch, start, length);
184: }
185: }
|