/* * eXist Open Source Native XML Database * Copyright (C) 2009 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * $Id$ */ package org.exist.util; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.commons.pool.BasePoolableObjectFactory; import org.apache.log4j.Logger; import org.exist.Namespaces; import org.exist.storage.BrokerPool; import org.exist.validation.GrammarPool; import org.exist.validation.resolver.eXistXMLCatalogResolver; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.XMLReader; /** * Factory to create new XMLReader objects on demand. The factory is used * by {@link org.exist.util.XMLReaderPool}. * * @author wolf */ public class XMLReaderObjectFactory extends BasePoolableObjectFactory { private final static Logger LOG = Logger.getLogger(XMLReaderObjectFactory.class); public final static int VALIDATION_UNKNOWN = -1; public final static int VALIDATION_ENABLED = 0; public final static int VALIDATION_AUTO = 1; public final static int VALIDATION_DISABLED = 2; public final static String CONFIGURATION_ENTITY_RESOLVER_ELEMENT_NAME = "entity-resolver"; public final static String CONFIGURATION_CATALOG_ELEMENT_NAME = "catalog"; public final static String CONFIGURATION_ELEMENT_NAME = "validation"; //TOO : move elsewhere ? public final static String VALIDATION_MODE_ATTRIBUTE = "mode"; public final static String PROPERTY_VALIDATION_MODE = "validation.mode"; public final static String CATALOG_RESOLVER = "validation.resolver"; public final static String CATALOG_URIS = "validation.catalog_uris"; public final static String GRAMMER_POOL = "validation.grammar_pool"; // Xerces feature and property names public final static String APACHE_FEATURES_VALIDATION_SCHEMA ="http://apache.org/xml/features/validation/schema"; public final static String APACHE_PROPERTIES_INTERNAL_GRAMMARPOOL ="http://apache.org/xml/properties/internal/grammar-pool"; public final static String APACHE_PROPERTIES_LOAD_EXT_DTD ="http://apache.org/xml/features/nonvalidating/load-external-dtd"; public final static String APACHE_PROPERTIES_ENTITYRESOLVER ="http://apache.org/xml/properties/internal/entity-resolver"; public final static String APACHE_PROPERTIES_NONAMESPACESCHEMALOCATION ="http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"; private BrokerPool pool; /** * */ public XMLReaderObjectFactory(BrokerPool pool) { super(); this.pool = pool; } /** * @see org.apache.commons.pool.BasePoolableObjectFactory#makeObject() */ public Object makeObject() throws Exception { Configuration config = pool.getConfiguration(); // Get validation settings String option = (String) config.getProperty(PROPERTY_VALIDATION_MODE); int validation = convertValidationMode(option); GrammarPool grammarPool = (GrammarPool) config.getProperty(XMLReaderObjectFactory.GRAMMER_POOL); eXistXMLCatalogResolver resolver = (eXistXMLCatalogResolver) config.getProperty(CATALOG_RESOLVER); XMLReader xmlReader = createXmlReader(validation, grammarPool, resolver); setReaderValidationMode(validation, xmlReader); return xmlReader; } /** * Create Xmlreader and setup validation */ public static XMLReader createXmlReader(int validation, GrammarPool grammarPool, eXistXMLCatalogResolver resolver) throws ParserConfigurationException, SAXException{ // Create a xmlreader SAXParserFactory saxFactory = ExistSAXParserFactory.getSAXParserFactory(); if (validation == VALIDATION_AUTO || validation == VALIDATION_ENABLED){ saxFactory.setValidating(true); } else { saxFactory.setValidating(false); } saxFactory.setNamespaceAware(true); SAXParser saxParser = saxFactory.newSAXParser(); XMLReader xmlReader = saxParser.getXMLReader(); // Setup grammar cache if(grammarPool!=null){ setReaderProperty(xmlReader,APACHE_PROPERTIES_INTERNAL_GRAMMARPOOL, grammarPool); } // Setup xml catalog resolver if(resolver!=null){ setReaderProperty(xmlReader,APACHE_PROPERTIES_ENTITYRESOLVER, resolver); } return xmlReader; } /** * Convert configuration text (yes,no,true,false,auto) into a magic number. */ public static int convertValidationMode(String option) { int validation = VALIDATION_AUTO; if (option != null) { if (option.equals("true") || option.equals("yes")) { validation = VALIDATION_ENABLED; } else if (option.equals("auto")) { validation = VALIDATION_AUTO; } else { validation = VALIDATION_DISABLED; } } return validation; } /** * Setup validation mode of xml reader. */ public static void setReaderValidationMode(int validation, XMLReader xmlReader) { if (validation == VALIDATION_UNKNOWN) { return; } // Configure xmlreader see http://xerces.apache.org/xerces2-j/features.html setReaderFeature(xmlReader, Namespaces.SAX_NAMESPACES_PREFIXES, true); setReaderFeature(xmlReader, Namespaces.SAX_VALIDATION, validation == VALIDATION_AUTO || validation == VALIDATION_ENABLED); setReaderFeature(xmlReader, Namespaces.SAX_VALIDATION_DYNAMIC, validation == VALIDATION_AUTO); setReaderFeature(xmlReader, APACHE_FEATURES_VALIDATION_SCHEMA, (validation == VALIDATION_AUTO || validation == VALIDATION_ENABLED) ); setReaderFeature(xmlReader, APACHE_PROPERTIES_LOAD_EXT_DTD, (validation == VALIDATION_AUTO || validation == VALIDATION_ENABLED) ); // Attempt to make validation function equal to insert mode //saxFactory.setFeature(Namespaces.SAX_NAMESPACES_PREFIXES, true); } private static void setReaderFeature(XMLReader xmlReader, String featureName, boolean value){ try { xmlReader.setFeature(featureName, value); } catch (SAXNotRecognizedException ex) { LOG.error("SAXNotRecognizedException: " + ex.getMessage()); } catch (SAXNotSupportedException ex) { LOG.error("SAXNotSupportedException:" + ex.getMessage()); } } private static void setReaderProperty(XMLReader xmlReader, String propertyName, Object object){ try { xmlReader.setProperty(propertyName, object); } catch (SAXNotRecognizedException ex) { LOG.error("SAXNotRecognizedException: " + ex.getMessage()); } catch (SAXNotSupportedException ex) { LOG.error("SAXNotSupportedException:" + ex.getMessage()); } } }