franta-hg@11: /**
franta-hg@11: * Alt2XML
franta-hg@11: * Copyright © 2014 František Kučera (frantovo.cz)
franta-hg@11: *
franta-hg@11: * This program is free software: you can redistribute it and/or modify
franta-hg@11: * it under the terms of the GNU General Public License as published by
franta-hg@111: * the Free Software Foundation, version 3 of the License.
franta-hg@11: *
franta-hg@11: * This program is distributed in the hope that it will be useful,
franta-hg@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
franta-hg@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
franta-hg@11: * GNU General Public License for more details.
franta-hg@11: *
franta-hg@11: * You should have received a copy of the GNU General Public License
franta-hg@11: * along with this program. If not, see .
franta-hg@11: */
franta-hg@2: package cz.frantovo.alt2xml;
franta-hg@2:
franta-hg@15: import java.util.Deque;
franta-hg@99: import java.util.HashMap;
franta-hg@15: import java.util.LinkedList;
franta-hg@99: import java.util.Map;
franta-hg@99: import java.util.Map.Entry;
franta-hg@15: import java.util.ServiceLoader;
franta-hg@34: import javax.xml.parsers.FactoryConfigurationError;
franta-hg@2: import javax.xml.parsers.ParserConfigurationException;
franta-hg@2: import javax.xml.parsers.SAXParser;
franta-hg@2: import javax.xml.parsers.SAXParserFactory;
franta-hg@2: import org.xml.sax.SAXException;
franta-hg@2: import org.xml.sax.SAXNotRecognizedException;
franta-hg@2: import org.xml.sax.SAXNotSupportedException;
franta-hg@3: import org.xml.sax.XMLReader;
franta-hg@2:
franta-hg@2: /**
franta-hg@2: *
franta-hg@19: * @author Ing. František Kučera (frantovo.cz)
franta-hg@2: */
franta-hg@16: public class ParserFactory extends SAXParserFactory implements ReaderFinder {
franta-hg@15:
franta-hg@15: private final Deque readerFactories = new LinkedList();
franta-hg@34: /**
franta-hg@34: * @see #DEFAULT_FACTORY_PROPERTY
franta-hg@34: */
franta-hg@34: private SAXParserFactory fallbackFactory;
franta-hg@34:
franta-hg@34: /**
franta-hg@34: * System property which contains SAXParserFactory class name for XML.
franta-hg@34: * Will be used as fallback if no alternative factory matches systemId to be parsed.
franta-hg@34: */
franta-hg@34: public static final String DEFAULT_FACTORY_PROPERTY = "cz.frantovo.alt2xml.fallback.javax.xml.parsers.SAXParserFactory";
franta-hg@15:
franta-hg@99: private final Map features = new HashMap<>();
franta-hg@99:
franta-hg@16: public ParserFactory() {
franta-hg@15: super();
franta-hg@15: for (Alt2XmlReaderFactory f : ServiceLoader.load(Alt2XmlReaderFactory.class)) {
franta-hg@15: readerFactories.add(f);
franta-hg@15: }
franta-hg@15:
franta-hg@34: readerFactories.add(new FallbackReaderFactory());
franta-hg@34: }
franta-hg@34:
franta-hg@34: /**
franta-hg@34: * @return factory to be used for XML documents (default/fallback)
franta-hg@34: * @throws FactoryConfigurationError if fallback factory is the same one as this – avoid
franta-hg@34: * infinite recursion.
franta-hg@34: */
franta-hg@34: public SAXParserFactory getFallbackFactory() {
franta-hg@34: if (fallbackFactory == null) {
franta-hg@34: String className = System.getProperty(DEFAULT_FACTORY_PROPERTY);
franta-hg@34: if (className == null) {
franta-hg@34: fallbackFactory = SAXParserFactory.newInstance();
franta-hg@34: } else {
franta-hg@34: fallbackFactory = SAXParserFactory.newInstance(className, null);
franta-hg@34: }
franta-hg@34: }
franta-hg@34:
franta-hg@34: if (fallbackFactory.getClass().equals(getClass())) {
franta-hg@34: throw new FactoryConfigurationError("Fallback factory is the same class as this one – avoid infinite recursion: " + getClass());
franta-hg@34: } else {
franta-hg@34: return fallbackFactory;
franta-hg@34: }
franta-hg@34: }
franta-hg@34:
franta-hg@34: public void setFallbackFactory(SAXParserFactory fallbackFactory) {
franta-hg@34: this.fallbackFactory = fallbackFactory;
franta-hg@34: }
franta-hg@34:
franta-hg@34: private class FallbackReaderFactory implements Alt2XmlReaderFactory {
franta-hg@34:
franta-hg@34: @Override
franta-hg@36: public boolean canRead(AltInputSource inputSource) {
franta-hg@34: return true;
franta-hg@34: }
franta-hg@34:
franta-hg@34: @Override
franta-hg@34: public XMLReader getReader() throws SAXException {
franta-hg@34:
franta-hg@34: try {
franta-hg@34: return getFallbackFactory().newSAXParser().getXMLReader();
franta-hg@34: } catch (ParserConfigurationException e) {
franta-hg@34: throw new SAXException("Unable to instantiate the fallback factory.", e);
franta-hg@34: }
franta-hg@34: }
franta-hg@15: }
franta-hg@15:
franta-hg@15: @Override
franta-hg@36: public XMLReader findReader(AltInputSource inputSource) throws SAXException {
franta-hg@15: for (Alt2XmlReaderFactory f : readerFactories) {
franta-hg@36: if (f.canRead(inputSource)) {
franta-hg@15: return f.getReader();
franta-hg@15: }
franta-hg@15: }
franta-hg@36: throw new SAXException("Iterated over " + readerFactories.size() + " and was unable to find XMLReader for SystemId: " + inputSource);
franta-hg@15: }
franta-hg@2:
franta-hg@2: @Override
franta-hg@2: public SAXParser newSAXParser() throws ParserConfigurationException, SAXException {
franta-hg@99: SuperReader r = new SuperReader(this);
franta-hg@99: for (Entry f : features.entrySet()) {
franta-hg@99: r.setFeature(f.getKey(), f.getValue());
franta-hg@99: }
franta-hg@99: return new AltSAXParser(r);
franta-hg@2: }
franta-hg@2:
franta-hg@2: @Override
franta-hg@2: public void setFeature(String name, boolean value) throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException {
franta-hg@99: features.put(name, value);
franta-hg@2: }
franta-hg@2:
franta-hg@2: @Override
franta-hg@2: public boolean getFeature(String name) throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException {
franta-hg@99: return features.get(name);
franta-hg@2: }
franta-hg@15: }