/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.compass.core.util.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.compass.core.config.ConfigurationException;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
/**
* A DefaultConfigurationBuilder builds <code>Configuration</code>s from XML,
* via a SAX2 compliant parser.
*/
public class XmlConfigurationHelperBuilder {
private SAXConfigurationHandler m_handler;
private XMLReader m_parser;
/**
* Create a Configuration Builder with a default XMLReader that ignores
* namespaces. In order to enable namespaces, use either the constructor
* that has a boolean or that allows you to pass in your own
* namespace-enabled XMLReader.
*/
public XmlConfigurationHelperBuilder() {
this(false);
}
/**
* Create a Configuration Builder, specifying a flag that determines
* namespace support.
*/
public XmlConfigurationHelperBuilder(final boolean enableNamespaces) {
// yaya the bugs with some compilers and final variables ..
try {
final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
if (enableNamespaces) {
saxParserFactory.setNamespaceAware(true);
}
saxParserFactory.setValidating(true);
final SAXParser saxParser = saxParserFactory.newSAXParser();
setParser(saxParser.getXMLReader());
} catch (final Exception se) {
throw new Error("Unable to setup SAX parser" + se);
}
}
/**
* Create a Configuration Builder with your own XMLReader.
*/
public XmlConfigurationHelperBuilder(XMLReader parser) {
setParser(parser);
}
/**
* Internally sets up the XMLReader
*/
private void setParser(XMLReader parser) {
m_parser = parser;
m_handler = getHandler();
m_parser.setContentHandler(m_handler);
m_parser.setErrorHandler(m_handler);
}
/**
* Get a SAXConfigurationHandler for your configuration reading.
*/
protected SAXConfigurationHandler getHandler() {
try {
if (m_parser.getFeature("http://xml.org/sax/features/namespaces")) {
return new NamespacedSAXConfigurationHandler();
}
} catch (Exception e) {
// ignore error and fall through to the non-namespaced version
}
return new SAXConfigurationHandler();
}
/**
* Build a configuration object from a file using a filename.
*/
public ConfigurationHelper buildFromFile(final String filename) throws ConfigurationException {
return buildFromFile(new File(filename));
}
/**
* Build a configuration object from a file using a File object.
*/
public ConfigurationHelper buildFromFile(final File file) throws ConfigurationException {
InputStream inputStream;
try {
inputStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
throw new ConfigurationException("Failed to find file [" + file.getAbsolutePath() + "]");
}
return build(inputStream, file.getAbsolutePath());
}
/**
* Build a configuration object using an InputStream; supplying a systemId
* to make messages about all kinds of errors more meaningfull.
*/
public ConfigurationHelper build(final InputStream inputStream, final String systemId)
throws ConfigurationException {
final InputSource inputSource = new InputSource(inputStream);
inputSource.setSystemId(systemId);
return build(inputSource);
}
/**
* Build a configuration object using an URI
*/
public ConfigurationHelper build(final String uri) throws ConfigurationException {
return build(new InputSource(uri));
}
/**
* Build a configuration object using an XML InputSource object
*/
public ConfigurationHelper build(final InputSource input) throws ConfigurationException {
synchronized (this) {
m_handler.clear();
try {
m_parser.parse(input);
} catch (SAXParseException e) {
throw new ConfigurationException("Line [" + e.getLineNumber() + "] Column [" + e.getColumnNumber()
+ "] in XML document [" + input.getSystemId() + "] is invalid", e);
} catch (SAXException e) {
throw new ConfigurationException("XML document [" + input.getSystemId() + "] is invalid", e);
} catch (IOException e) {
throw new ConfigurationException("IOException parsing XML document [" + input.getSystemId() + "]", e);
}
return m_handler.getConfiguration();
}
}
/**
* Sets the <code>EntityResolver</code> to be used by parser. Useful when
* dealing with xml files that reference external entities.
*/
public void setEntityResolver(final EntityResolver resolver) {
synchronized (this) {
m_parser.setEntityResolver(resolver);
}
}
}