/* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * $Id$ */ package com.sun.faces.config; import org.apache.commons.digester.Digester; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.text.MessageFormat; import java.util.HashMap; /** *
A simple factory to hide Digester configuration
* details.
Xerces specific feature to enable both
* DTD and Schema validation.
Xerces specific feature to enable both
* DTD and Schema validation.
Custom EntityResolver.
Custom ErrorHandler.
Indicates whether or not document validation is * requested or not.
*/ private boolean validating; // ------------------------------------------------------------ Constructors /** *Creates a new DigesterFactory instance.
* @param isValidating -true if the Digester
* instance that is ultimately returned should be configured (if possible)
* for document validation. If validation is not desired, pass
* false.
*/
private DigesterFactory(boolean isValidating) {
validating = isValidating;
} // END DigesterFactory
// ---------------------------------------------------------- Public Methods
/**
* Returns a new DigesterFactory instance that will create
* a non-validating Digester instance.
Creates a new DigesterFactory instance that will
* create a Digester instance where validation depends
* on the value of isValidating.
true if the Digester
* instance that is ultimately returned should be configured (if possible)
* for document validation. If validation is not desired, pass
* false.
* @return a new DigesterFactory capable of creating
* Digesterinstances
*/
public static DigesterFactory newInstance(boolean isValidating) {
return new DigesterFactory(isValidating);
} // END newInstance
/**
* Creates a new Digester instance configured for use
* with JSF.
Configures the provided Digester instance appropriate
* for use with JSF.
Digester instance to configure
*/
private void configureDigester(Digester digester) {
digester.setNamespaceAware(true);
digester.setUseContextClassLoader(true);
digester.setErrorHandler(MESSAGE_LOGGER);
digester.setEntityResolver(RESOLVER);
if (validating) {
if (LOG.isDebugEnabled()) {
LOG.debug("Attempting to configure Digester to perform" +
" document validation.");
}
// In order to validate using *both* DTD and Schema, certain
// Xerces specific features are required. Try to set these
// features. If an exception is thrown trying to set these
// features, then disable validation.
XMLReader reader;
try {
reader = digester.getXMLReader();
} catch (SAXException e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Unable to obtain XMLReader from Digester. " +
"Disabling validation");
}
digester.setValidating(false);
return;
}
try {
reader.setFeature(APACHE_DYNAMIC_VALIDATION, true);
reader.setFeature(APACHE_SCHEMA_VALIDATION, true);
digester.setValidating(true);
} catch (SAXNotSupportedException e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Attempt to set supported feature on XMLReader, but" +
" the value provided was not accepted. " +
"Validation will be disabled.");
}
digester.setValidating(false);
} catch (SAXNotRecognizedException e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Attempt to set unsupported feature on XMLReader " +
"necessary for validation. Validation will be" +
"disabled.");
}
digester.setValidating(false);
}
} else {
digester.setValidating(false);
}
} // END configureDigester
// ----------------------------------------------------------- Inner Classes
private static class MessageLogger extends DefaultHandler {
/**
* Simple MessageFormat for displaying
* parser messages.
Contains associations between grammar name and the physical * resource.
*/ private static final String[][] DTD_SCHEMA_INFO = { { "web-facesconfig_1_0.dtd", "/com/sun/faces/web-facesconfig_1_0.dtd" }, { "web-facesconfig_1_1.dtd", "/com/sun/faces/web-facesconfig_1_1.dtd" }, { "web-facesconfig_1_2.xsd", "/com/sun/faces/web-facesconfig_1_2.xsd" }, { "j2ee_1_4.xsd", "/com/sun/faces/j2ee_1_4.xsd" }, { "j2ee_web_services_client_1_1.xsd", "/com/sun/faces/j2ee_web_services_client_1_1.xsd" }, { "xml.xsd", "/com/sun/faces/xml.xsd" } }; /** *Contains mapping between grammar name and the local URL to the * physical resource.
*/ private HashMap entities = new HashMap(); // -------------------------------------------------------- Constructors public JsfEntityResolver() { // Add mappings between last segment of system ID and // the expected local physical resource. If the resource // cannot be found, then rely on default entity resolution // and hope a firewall isn't in the way or a proxy has // been configured for (int i = 0; i < DTD_SCHEMA_INFO.length; i++) { URL url = this.getClass().getResource(DTD_SCHEMA_INFO[i][1]); if (url == null) { if (LOG.isWarnEnabled()) { LOG.warn("Unable to locate local resource '" + DTD_SCHEMA_INFO[i][1] + "'. Standard entity " + "resolution will be used when request are present " + "for '" + DTD_SCHEMA_INFO[i][0] + '\''); } } else { entities.put(DTD_SCHEMA_INFO[i][0], url.toString()); } } } // END JsfEntityResolver // ----------------------------------------- Methods from DefaultHandler /** *Resolves the physical resource using the last segment of
* the systemId (e.g. http://java.sun.com/dtds/web-facesconfig_1_1.dtd,
* the last segment would be web-facesconfig_1_1.dtd). If a mapping
* cannot be found for the segment, then defer to the
* DefaultHandler for resolution.