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: }