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
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 2005-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.api.xml;
043:
044: import java.util.HashMap;
045:
046: import org.xml.sax.Attributes;
047:
048: /**
049: * Receive notification of the content of an XML element named via {@link #tag}.
050: * <p>
051: * XMLDocReader will call {@link #start} upon encountering an element named
052: * via {@link #tag}, and will call {@link #end} when the closing tag is
053: * encountered.
054: * <p>
055: * Any elements encountered between those will cause {@link #startElement}
056: * and {@link #endElement} to get called, <i>unless</i> a sub-decoder has
057: * been registered using {@link #registerXMLDecoder} in which case
058: * all of this recursively applies to the nested element.
059: * <p>
060: * For example, if <code>FamilyXMLDecoder</code> has <code>tag()</code>
061: * return <code>"family"</code> and calls
062: * <pre>registerXMLDecoder(new PersonXMLDecoder(...))</pre>
063: * then the following trace of XML elements and corresponding callbacks
064: * will occur:
065: * <pre>
066: <family> start(null)
067: <person firstName="X" lastName="Y"/> PersonXMLDecoder.start(...)
068: <heritage>Algebra</heritage> startElement("heritage", ...)
069: endElement("heritage", "Algebra");
070: </family> end();
071: * </pre>
072: * <p>
073: * An XMLDecoder should be extended by a subclass, which would typically also
074: * implement {@link XMLEncoder} to create a <b>codec</b>.
075: */
076:
077: public abstract class XMLDecoder {
078:
079: abstract protected String tag();
080:
081: abstract protected void start(Attributes atts)
082: throws VersionException;
083:
084: abstract protected void end();
085:
086: abstract protected void startElement(String name, Attributes atts);
087:
088: abstract protected void endElement(String name, String currentText);
089:
090: protected void registerXMLDecoder(XMLDecoder decoder) {
091: tagMap.put(decoder.tag(), decoder);
092: }
093:
094: protected void deregisterXMLDecoder(XMLDecoder decoder) {
095: tagMap.remove(decoder.tag());
096: }
097:
098: private HashMap/*<String,XMLDecoder>*/tagMap = new HashMap();
099: private XMLDecoder currentDecoder;
100: private String currentElement;
101:
102: public XMLDecoder() {
103: }
104:
105: void _startElement(String name, Attributes atts)
106: throws VersionException {
107: if (checkStartRecursion(name, atts))
108: return;
109: else
110: startElement(name, atts);
111: }
112:
113: void _endElement(String name, String currentText) {
114: // see if need to terminate the current decoder
115: if (checkEndRecursion(name, currentText)) {
116: return;
117: } else {
118: // pass on to current decoder
119: endElement(name, currentText);
120: }
121: }
122:
123: private boolean checkStartRecursion(String name, Attributes atts)
124: throws VersionException {
125:
126: if (currentDecoder != null) {
127: currentDecoder._startElement(name, atts);
128: return true;
129: }
130:
131: XMLDecoder tentativeDecoder = (XMLDecoder) tagMap.get(name);
132: if (tentativeDecoder != null) {
133: /* DEBUG
134: System.out.println("Switching to decoder for " + name);
135: */
136: tentativeDecoder.start(atts); // throws VersionException
137: // everything went fine, commit to it
138: currentDecoder = tentativeDecoder;
139: currentElement = name;
140: return true;
141: }
142: return false;
143: }
144:
145: private boolean checkEndRecursion(String name, String currentText) {
146: if (currentDecoder != null) {
147: if (currentDecoder.checkEndRecursion(name, currentText)) {
148: return true;
149: } else if (name.equals(currentElement)) {
150: // ending this decoder
151: currentDecoder.end();
152: currentDecoder = null;
153: currentElement = null;
154: return true;
155: } else {
156: currentDecoder.endElement(name, currentText);
157: return true;
158: }
159: }
160: return false;
161: }
162:
163: private void registerXMLDecoder(String tag, XMLDecoder decoder) {
164: tagMap.put(tag, decoder);
165: }
166:
167: protected void checkVersion(Attributes atts, String what,
168: int maxVersion) throws VersionException {
169:
170: int version = 0;
171: String versionString = atts.getValue("version"); // NOI18N
172: if (versionString != null)
173: version = new Integer(versionString).intValue();
174: if (version > maxVersion) {
175: throw new VersionException(what, maxVersion, version);
176: }
177: }
178: }
|