001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.compass.core.util.config;
018:
019: import java.io.File;
020: import java.io.FileInputStream;
021: import java.io.FileNotFoundException;
022: import java.io.IOException;
023: import java.io.InputStream;
024:
025: import javax.xml.parsers.SAXParser;
026: import javax.xml.parsers.SAXParserFactory;
027:
028: import org.compass.core.config.ConfigurationException;
029: import org.xml.sax.EntityResolver;
030: import org.xml.sax.InputSource;
031: import org.xml.sax.SAXException;
032: import org.xml.sax.SAXParseException;
033: import org.xml.sax.XMLReader;
034:
035: /**
036: * A DefaultConfigurationBuilder builds <code>Configuration</code>s from XML,
037: * via a SAX2 compliant parser.
038: */
039: public class XmlConfigurationHelperBuilder {
040: private SAXConfigurationHandler m_handler;
041:
042: private XMLReader m_parser;
043:
044: /**
045: * Create a Configuration Builder with a default XMLReader that ignores
046: * namespaces. In order to enable namespaces, use either the constructor
047: * that has a boolean or that allows you to pass in your own
048: * namespace-enabled XMLReader.
049: */
050: public XmlConfigurationHelperBuilder() {
051: this (false);
052: }
053:
054: /**
055: * Create a Configuration Builder, specifying a flag that determines
056: * namespace support.
057: */
058: public XmlConfigurationHelperBuilder(final boolean enableNamespaces) {
059: // yaya the bugs with some compilers and final variables ..
060: try {
061: final SAXParserFactory saxParserFactory = SAXParserFactory
062: .newInstance();
063: if (enableNamespaces) {
064: saxParserFactory.setNamespaceAware(true);
065: }
066: saxParserFactory.setValidating(true);
067: final SAXParser saxParser = saxParserFactory.newSAXParser();
068: setParser(saxParser.getXMLReader());
069: } catch (final Exception se) {
070: throw new Error("Unable to setup SAX parser" + se);
071: }
072: }
073:
074: /**
075: * Create a Configuration Builder with your own XMLReader.
076: */
077: public XmlConfigurationHelperBuilder(XMLReader parser) {
078: setParser(parser);
079: }
080:
081: /**
082: * Internally sets up the XMLReader
083: */
084: private void setParser(XMLReader parser) {
085: m_parser = parser;
086: m_handler = getHandler();
087: m_parser.setContentHandler(m_handler);
088: m_parser.setErrorHandler(m_handler);
089: }
090:
091: /**
092: * Get a SAXConfigurationHandler for your configuration reading.
093: */
094: protected SAXConfigurationHandler getHandler() {
095: try {
096: if (m_parser
097: .getFeature("http://xml.org/sax/features/namespaces")) {
098: return new NamespacedSAXConfigurationHandler();
099: }
100: } catch (Exception e) {
101: // ignore error and fall through to the non-namespaced version
102: }
103: return new SAXConfigurationHandler();
104: }
105:
106: /**
107: * Build a configuration object from a file using a filename.
108: */
109: public ConfigurationHelper buildFromFile(final String filename)
110: throws ConfigurationException {
111: return buildFromFile(new File(filename));
112: }
113:
114: /**
115: * Build a configuration object from a file using a File object.
116: */
117: public ConfigurationHelper buildFromFile(final File file)
118: throws ConfigurationException {
119: InputStream inputStream;
120: try {
121: inputStream = new FileInputStream(file);
122: } catch (FileNotFoundException e) {
123: throw new ConfigurationException("Failed to find file ["
124: + file.getAbsolutePath() + "]");
125: }
126: return build(inputStream, file.getAbsolutePath());
127: }
128:
129: /**
130: * Build a configuration object using an InputStream; supplying a systemId
131: * to make messages about all kinds of errors more meaningfull.
132: */
133: public ConfigurationHelper build(final InputStream inputStream,
134: final String systemId) throws ConfigurationException {
135: final InputSource inputSource = new InputSource(inputStream);
136: inputSource.setSystemId(systemId);
137: return build(inputSource);
138: }
139:
140: /**
141: * Build a configuration object using an URI
142: */
143: public ConfigurationHelper build(final String uri)
144: throws ConfigurationException {
145: return build(new InputSource(uri));
146: }
147:
148: /**
149: * Build a configuration object using an XML InputSource object
150: */
151: public ConfigurationHelper build(final InputSource input)
152: throws ConfigurationException {
153: synchronized (this ) {
154: m_handler.clear();
155: try {
156: m_parser.parse(input);
157: } catch (SAXParseException e) {
158: throw new ConfigurationException("Line ["
159: + e.getLineNumber() + "] Column ["
160: + e.getColumnNumber() + "] in XML document ["
161: + input.getSystemId() + "] is invalid", e);
162: } catch (SAXException e) {
163: throw new ConfigurationException("XML document ["
164: + input.getSystemId() + "] is invalid", e);
165: } catch (IOException e) {
166: throw new ConfigurationException(
167: "IOException parsing XML document ["
168: + input.getSystemId() + "]", e);
169: }
170: return m_handler.getConfiguration();
171: }
172: }
173:
174: /**
175: * Sets the <code>EntityResolver</code> to be used by parser. Useful when
176: * dealing with xml files that reference external entities.
177: */
178: public void setEntityResolver(final EntityResolver resolver) {
179: synchronized (this) {
180: m_parser.setEntityResolver(resolver);
181: }
182: }
183: }
|