package org.orbeon.oxf.xml.xerces;
import org.orbeon.oxf.common.OXFException;
import org.orbeon.oxf.xml.XMLParsing;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
* Boasts a couple of improvements over the 'stock' xerces parser factory.
*
* o Doesn't create a new parser every time one calls setFeature or getFeature. Stock one
* has to do this because valid feature set is encapsulated in the parser code.
*
* o Creates a XercesJAXPSAXParser instead of SaxParserImpl. See XercesJAXPSAXParser for
* why this is an improvement.
*
* o The improvements cut the time it takes to a SAX parser via JAXP in
* half and reduce the amount of garbage created when accessing '/' in
* the examples app from 9019216 bytes to 8402880 bytes.
*/
public class XercesSAXParserFactoryImpl extends SAXParserFactory {
private final Map<String, Boolean> features;
private final Set<String> recognizedFeatures;
private final XMLParsing.ParserConfiguration parserConfiguration;
public XercesSAXParserFactoryImpl() {
this(XMLParsing.ParserConfiguration.PLAIN);
}
public XercesSAXParserFactoryImpl(XMLParsing.ParserConfiguration parserConfiguration) {
this.parserConfiguration = parserConfiguration;
// NOTE: Creating a configuration can be expensive, so callers should create factories sparingly
final OrbeonParserConfiguration configuration = XercesSAXParser.makeConfig(parserConfiguration);
this.recognizedFeatures = Collections.unmodifiableSet(configuration.getRecognizedFeatures());
this.features = configuration.getFeatures();
setNamespaceAware(true); // this is needed by some tools in addition to the feature
setValidating(parserConfiguration.validating);
}
public boolean getFeature(final String key) throws SAXNotRecognizedException {
if (!recognizedFeatures.contains(key)) throw new SAXNotRecognizedException(key);
return features.get(key) == Boolean.TRUE;
}
public void setFeature(final String key, final boolean val) throws SAXNotRecognizedException {
if (!recognizedFeatures.contains(key)) throw new SAXNotRecognizedException(key);
features.put(key, val ? Boolean.TRUE : Boolean.FALSE);
}
public SAXParser newSAXParser() {
try {
final SAXParser result = new XercesJAXPSAXParser(this, features, parserConfiguration);
// Set security manager before returning the parser
result.setProperty("http://apache.org/xml/properties/security-manager", new orbeon.apache.xerces.util.SecurityManager());
return result;
} catch (final SAXException se) {
// Translate to ParserConfigurationException
throw new OXFException(se); // so we see a decent stack trace!
}
}
}