001: package net.myvietnam.mvncore.configuration;
002:
003: /* ====================================================================
004: * The Apache Software License, Version 1.1
005: *
006: * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
007: * reserved.
008: *
009: * Redistribution and use in source and binary forms, with or without
010: * modification, are permitted provided that the following conditions
011: * are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution, if
022: * any, must include the following acknowledgement:
023: * "This product includes software developed by the
024: * Apache Software Foundation (http://www.apache.org/)."
025: * Alternately, this acknowledgement may appear in the software itself,
026: * if and wherever such third-party acknowledgements normally appear.
027: *
028: * 4. The names "The Jakarta Project", "Commons", and "Apache Software
029: * Foundation" must not be used to endorse or promote products derived
030: * from this software without prior written permission. For written
031: * permission, please contact apache@apache.org.
032: *
033: * 5. Products derived from this software may not be called "Apache"
034: * nor may "Apache" appear in their names without prior written
035: * permission of the Apache Software Foundation.
036: *
037: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
038: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
039: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
040: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
041: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
042: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
043: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
044: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
045: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
046: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
047: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
048: * SUCH DAMAGE.
049: * ====================================================================
050: *
051: * This software consists of voluntary contributions made by many
052: * individuals on behalf of the Apache Software Foundation. For more
053: * information on the Apache Software Foundation, please see
054: * <http://www.apache.org/>.
055: */
056:
057: import java.io.IOException;
058:
059: import net.myvietnam.mvncore.configuration.HierarchicalConfiguration.*;
060: import org.xml.sax.Attributes;
061: import org.xml.sax.SAXException;
062: import org.xml.sax.helpers.AttributesImpl;
063:
064: /**
065: * <p>A specialized SAX2 XML parser that "parses" hierarchical
066: * configuration objects.</p>
067: * <p>This class mimics to be a SAX conform XML parser. Instead of parsing
068: * XML documents it processes a <code>Configuration</code> object and
069: * generates SAX events for the single properties defined there. This enables
070: * the whole world of XML processing for configuration objects.</p>
071: * <p>The <code>HierarchicalConfiguration</code> object to be parsed can be
072: * specified using a constructor or the <code>setConfiguration()</code> method.
073: * This object will be processed by the <code>parse()</code> methods. Note
074: * that these methods ignore their argument.</p>
075: *
076: * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
077: * @version $Id: HierarchicalConfigurationXMLReader.java,v 1.1 2003/12/09 08:25:30 huumai Exp $
078: */
079: public class HierarchicalConfigurationXMLReader extends
080: ConfigurationXMLReader {
081: /** Stores the configuration object to be parsed.*/
082: private HierarchicalConfiguration configuration;
083:
084: /**
085: * Creates a new instance of
086: * <code>HierarchicalConfigurationXMLReader</code>.
087: */
088: public HierarchicalConfigurationXMLReader() {
089: super ();
090: }
091:
092: /**
093: * Creates a new instance of
094: * <code>HierarchicalConfigurationXMLReader</code> and sets the
095: * configuration to be parsed.
096: * @param config the configuration object
097: */
098: public HierarchicalConfigurationXMLReader(
099: HierarchicalConfiguration config) {
100: this ();
101: setConfiguration(config);
102: }
103:
104: /**
105: * Returns the configuration object to be parsed.
106: * @return the configuration object to be parsed
107: */
108: public HierarchicalConfiguration getConfiguration() {
109: return configuration;
110: }
111:
112: /**
113: * Sets the configuration object to be parsed.
114: * @param config the configuration object to be parsed
115: */
116: public void setConfiguration(HierarchicalConfiguration config) {
117: configuration = config;
118: }
119:
120: /**
121: * Returns the configuration object to be processed.
122: * @return the actual configuration object
123: */
124: public Configuration getParsedConfiguration() {
125: return getConfiguration();
126: }
127:
128: /**
129: * Processes the actual configuration object to generate SAX parsing
130: * events.
131: * @throws IOException if no configuration has been specified
132: * @throws SAXException if an error occurs during parsing
133: */
134: protected void processKeys() throws IOException, SAXException {
135: getConfiguration().getRoot().visit(new SAXVisitor(), null);
136: }
137:
138: /**
139: * A specialized visitor class for generating SAX events for a
140: * hierarchical node structure.
141: *
142: * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
143: */
144: class SAXVisitor extends HierarchicalConfiguration.NodeVisitor {
145: /** Constant for the attribute type.*/
146: private static final String ATTR_TYPE = "CDATA";
147:
148: /**
149: * Visits the specified node after its children have been processed.
150: * @param node the actual node
151: * @param key the key of this node
152: */
153: public void visitAfterChildren(Node node, ConfigurationKey key) {
154: if (!isAttributeNode(node)) {
155: fireElementEnd(nodeName(node));
156: } /* if */
157: }
158:
159: /**
160: * Visits the specified node.
161: * @param node the actual node
162: * @param key the key of this node
163: */
164: public void visitBeforeChildren(Node node, ConfigurationKey key) {
165: if (!isAttributeNode(node)) {
166: fireElementStart(nodeName(node), fetchAttributes(node));
167:
168: if (node.getValue() != null) {
169: fireCharacters(node.getValue().toString());
170: } /* if */
171: } /* if */
172: }
173:
174: /**
175: * Checks if iteration should be terminated. This implementation stops
176: * iteration after an exception has occurred.
177: * @return a flag if iteration should be stopped
178: */
179: public boolean terminate() {
180: return getException() != null;
181: }
182:
183: /**
184: * Returns an object with all attributes for the specified node.
185: * @param node the actual node
186: * @return an object with all attributes of this node
187: */
188: protected Attributes fetchAttributes(Node node) {
189: AttributesImpl attrs = new AttributesImpl();
190: AbstractConfiguration.Container children = node
191: .getChildren();
192:
193: for (int i = 0; i < children.size(); i++) {
194: Node child = (Node) children.get(i);
195: if (isAttributeNode(child) && child.getValue() != null) {
196: String attr = ConfigurationKey.attributeName(child
197: .getName());
198: attrs.addAttribute(NS_URI, attr, attr, ATTR_TYPE,
199: child.getValue().toString());
200: } /* if */
201: } /* for */
202:
203: return attrs;
204: }
205:
206: /**
207: * Helper method for determining the name of a node. If a node has no
208: * name (which is true for the root node), the specified default name
209: * will be used.
210: * @param node the node to be checked
211: * @return the name for this node
212: */
213: private String nodeName(Node node) {
214: return (node.getName() == null) ? getRootName() : node
215: .getName();
216: }
217:
218: /**
219: * Checks if the specified node is an attribute node. In the node
220: * hierarchy attributes are stored as normal child nodes, but with
221: * special names.
222: * @param node the node to be checked
223: * @return a flag if this is an attribute node
224: */
225: private boolean isAttributeNode(Node node) {
226: return ConfigurationKey.isAttributeKey(node.getName());
227: }
228: }
229: }
|