dev@javaserverfaces.java.net

Re: [REVIEW] Fine tuning of parsing/validation code for _05

From: Roger Kitain <Roger.Kitain_at_Sun.COM>
Date: Tue, 15 May 2007 20:25:27 -0400

r=rogerk

Ryan Lubke wrote:

>
>------------------------------------------------------------------------
>
>
>Fine tuning of new parsing/validation code.
>
>
>SECTION: Modified Files
>----------------------------
>M conf/xslt/jsf1_0-1_1to1_2.xsl
> - removed the xslt for handing JSF 1.2 to 1.2 - it's not needed
>M src/com/sun/faces/config/ConfigManager.java
> - If validating:
> * document represents a JSF 1.2 faces-config.xml, do not
> transform, instead use the cached Schema from DbfFactory
> to validate and return.
> * document represents a JSF 1.0 or 1.1 faces-config.xml,
> transform to 1.2, validate using the cached Schema from
> DbfFactory and return.
>
>M src/com/sun/faces/config/DbfFactory.java
> - Leverage the JAXP 1.3 Schema caching feature. This elimatings
> the double parse that we were doing before (one to parse and transform,
> and another validating parse *after* the transform
>
>
>SECTION: Diffs
>----------------------------
>Index: conf/xslt/jsf1_0-1_1to1_2.xsl
>===================================================================
>RCS file: /cvs/javaserverfaces-sources/jsf-ri/conf/xslt/jsf1_0-1_1to1_2.xsl,v
>retrieving revision 1.1
>diff -u -r1.1 jsf1_0-1_1to1_2.xsl
>--- conf/xslt/jsf1_0-1_1to1_2.xsl 24 Apr 2007 19:04:22 -0000 1.1
>+++ conf/xslt/jsf1_0-1_1to1_2.xsl 15 May 2007 21:16:38 -0000
>@@ -41,8 +41,7 @@
> -->
>
> <xsl:stylesheet version="1.0"
>- xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>- xmlns:new="http://java.sun.com/xml/ns/javaee"
>+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> xmlns:old="http://java.sun.com/JSF/Configuration">
> <xsl:output method="xml"/>
> <xsl:template match="/old:faces-config">
>@@ -66,15 +65,4 @@
> </xsl:element>
> </xsl:template>
>
>- <!--
>- We may be processing a 1.2 document, just copy the elements.
>- -->
>- <xsl:template match="new:*">
>- <xsl:element name="{local-name()}"
>- namespace="http://java.sun.com/xml/ns/javaee">
>- <xsl:copy-of select="@*"/>
>- <xsl:apply-templates/>
>- </xsl:element>
>- </xsl:template>
>-
> </xsl:stylesheet>
>\ No newline at end of file
>Index: src/com/sun/faces/config/ConfigManager.java
>===================================================================
>RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/config/ConfigManager.java,v
>retrieving revision 1.7
>diff -u -r1.7 ConfigManager.java
>--- src/com/sun/faces/config/ConfigManager.java 9 May 2007 05:04:14 -0000 1.7
>+++ src/com/sun/faces/config/ConfigManager.java 15 May 2007 21:16:38 -0000
>@@ -63,15 +63,10 @@
> import javax.xml.parsers.DocumentBuilderFactory;
> import javax.xml.transform.Transformer;
> import javax.xml.transform.TransformerFactory;
>-import javax.xml.transform.URIResolver;
>-import javax.xml.transform.Source;
>-import javax.xml.transform.TransformerException;
> import javax.xml.transform.dom.DOMSource;
>-import javax.xml.transform.stream.StreamResult;
>+import javax.xml.transform.dom.DOMResult;
> import javax.xml.transform.stream.StreamSource;
> import java.io.BufferedInputStream;
>-import java.io.ByteArrayInputStream;
>-import java.io.ByteArrayOutputStream;
> import java.io.IOException;
> import java.io.InputStream;
> import java.net.URL;
>@@ -102,7 +97,7 @@
> * </p>
> */
> private static final List<ConfigurationResourceProvider> RESOURCE_PROVIDERS
>- = new ArrayList(3);
>+ = new ArrayList<ConfigurationResourceProvider>(3);
>
> /**
> * <p>
>@@ -130,7 +125,7 @@
> */
> @SuppressWarnings({"CollectionWithoutInitialCapacity"})
> private List<ServletContext> initializedContexts =
>- new CopyOnWriteArrayList();
>+ new CopyOnWriteArrayList<ServletContext>();
>
> /**
> * <p>
>@@ -270,22 +265,19 @@
> docTasks.add(d);
> executor.execute(d);
> }
>- } catch (InterruptedException e) {
>- ;
>+ } catch (InterruptedException ignored) {
> } catch (Exception e) {
> throw new ConfigurationException(e);
> }
> }
>
>- List<Document> docs = new ArrayList(docTasks.size());
>+ List<Document> docs = new ArrayList<Document>(docTasks.size());
> for (FutureTask<Document> t : docTasks) {
> try {
> docs.add(t.get());
> } catch (ExecutionException e) {
> throw new ConfigurationException(e);
>- } catch (InterruptedException e) {
>- ;
>- }
>+ } catch (InterruptedException ignored) { }
> }
>
> executor.shutdown();
>@@ -306,7 +298,8 @@
> * </p>
> */
> private static class ParseTask implements Callable<Document> {
>-
>+ private static final String FACES_SCHEMA_DEFAULT_NS =
>+ "http://java.sun.com/xml/ns/javaee";
> private URL documentURL;
> private DocumentBuilder builder;
>
>@@ -320,6 +313,7 @@
> * @param factory a DocumentBuilderFactory configured with the desired
> * parse settings
> * @param documentURL a URL to the configuration resource to be parsed
>+ * @throws Exception general error
> */
> public ParseTask(DocumentBuilderFactory factory,
> URL documentURL)
>@@ -342,14 +336,13 @@
> */
> public Document call() throws Exception {
>
>- InputStream stream = getInputStream(documentURL);
> try {
> Timer timer = Timer.getInstance();
> if (timer != null) {
> timer.startTiming();
> }
>
>- Document d = builder.parse(getParseSource());
>+ Document d = getDocument();
>
> if (timer != null) {
> timer.stopTiming();
>@@ -362,14 +355,6 @@
> "Unable to parse document ''{0}'': {1}",
> documentURL.toExternalForm(),
> e.getMessage()));
>- } finally {
>- if (stream != null) {
>- try {
>- stream.close();
>- } catch (IOException ioe) {
>- ;
>- }
>- }
> }
> }
>
>@@ -377,6 +362,38 @@
> // ----------------------------------------------------- Private Methods
>
>
>+ private Document getDocument() throws Exception {
>+ if (builder.getSchema() != null) { // the Schema won't be null if validation is enabled.
>+ DocumentBuilder db = getNonValidatingBuilder();
>+ DOMSource domSource
>+ = new DOMSource(db.parse(getInputStream(documentURL),
>+ documentURL.toExternalForm()));
>+
>+ /*
>+ * If the Document in question is 1.2 (i.e. it has a namespace matching
>+ * FACES_SCHEMA_DEFAULT_NS, then perform validation using the cached schema
>+ * and return. Otherwise we assume a 1.0 or 1.1 faces-config in which case
>+ * we need to transform it to 1.2 before validating using the cached schema.
>+ */
>+ if (FACES_SCHEMA_DEFAULT_NS.equals(((Document) domSource.getNode()).getDocumentElement().getNamespaceURI())) {
>+ builder.getSchema().newValidator().validate(domSource);
>+ return ((Document) domSource.getNode());
>+ } else {
>+ DOMResult domResult = new DOMResult();
>+ Transformer transformer = getTransformer();
>+ transformer.transform(domSource, domResult);
>+ builder.getSchema().newValidator().validate(new DOMSource(domResult.getNode()));
>+ return (Document) domResult.getNode();
>+ }
>+ } else {
>+ // validation isn't required, parse and return
>+ InputSource is = new InputSource(getInputStream(documentURL));
>+ is.setSystemId(documentURL.toExternalForm());
>+ return builder.parse(is);
>+ }
>+ }
>+
>+
> /**
> * Obtain a <code>Transformer</code> using the style sheet
> * referenced by the <code>XSL</code> constant.
>@@ -387,15 +404,6 @@
> private static Transformer getTransformer() throws Exception {
>
> TransformerFactory factory = TransformerFactory.newInstance();
>- factory.setURIResolver(new URIResolver() {
>-
>- public Source resolve(String href, String base)
>- throws TransformerException {
>- System.out.println("URI Resolver href: " + href);
>- System.out.println("URI Resolver base: " + base);
>- return null; //To change body of implemented methods use File | Settings | File Templates.
>- }
>- });
> return factory
> .newTransformer(new StreamSource(getInputStream(ConfigManager
> .class.getResource(XSL))));
>@@ -406,6 +414,7 @@
> /**
> * @return an <code>InputStream</code> to the resource referred to by
> * <code>url</code>
>+ * @param url source <code>URL</code>
> * @throws IOException if an error occurs
> */
> private static InputStream getInputStream(URL url) throws IOException {
>@@ -414,33 +423,10 @@
> conn.setUseCaches(false);
> return new BufferedInputStream(conn.getInputStream());
>
>- }
>-
>- private InputSource getParseSource() throws Exception {
>-
>- if (builder.isValidating()) {
>- // if we're validating, we need to apply xslt transformations
>- // to convert all documents to 1.2
>- ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
>- StreamResult sResult = new StreamResult(baos);
>- DocumentBuilder tBuilder = getNonValidatingBuilder();
>- DOMSource domSource
>- = new DOMSource(tBuilder.parse(getInputStream(documentURL),
>- documentURL.toExternalForm()));
>- Transformer transformer = getTransformer();
>- transformer.transform(domSource, sResult);
>- InputSource is = new InputSource(new ByteArrayInputStream(baos.toByteArray()));
>- is.setSystemId(documentURL.toExternalForm());
>- return is;
>- } else {
>- InputSource is = new InputSource(getInputStream(documentURL));
>- is.setSystemId(documentURL.toExternalForm());
>- return is;
>- }
>-
> }
>
>
>+
> private DocumentBuilder getNonValidatingBuilder() throws Exception {
>
> DocumentBuilderFactory tFactory = DbfFactory.getFactory(false);
>Index: src/com/sun/faces/config/DbfFactory.java
>===================================================================
>RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/config/DbfFactory.java,v
>retrieving revision 1.5
>diff -u -r1.5 DbfFactory.java
>--- src/com/sun/faces/config/DbfFactory.java 27 Apr 2007 22:00:55 -0000 1.5
>+++ src/com/sun/faces/config/DbfFactory.java 15 May 2007 21:16:38 -0000
>@@ -36,38 +36,46 @@
>
> package com.sun.faces.config;
>
>-import com.sun.faces.util.FacesLogger;
>-import org.xml.sax.EntityResolver;
>-import org.xml.sax.InputSource;
>-import org.xml.sax.SAXException;
>-import org.xml.sax.ErrorHandler;
>-import org.xml.sax.SAXParseException;
>+import org.xml.sax.*;
> import org.xml.sax.helpers.DefaultHandler;
>+import org.w3c.dom.ls.LSResourceResolver;
>+import org.w3c.dom.ls.LSInput;
>
>+import javax.xml.XMLConstants;
> import javax.xml.parsers.DocumentBuilderFactory;
>+import javax.xml.transform.stream.StreamSource;
>+import javax.xml.validation.Schema;
>+import javax.xml.validation.SchemaFactory;
>+import javax.xml.validation.Validator;
>+import java.io.InputStream;
>+import java.io.Reader;
> import java.net.URL;
>-import java.util.Collections;
>+import java.net.URLConnection;
> import java.util.HashMap;
>+import java.util.Collections;
> import java.util.Map;
>-import java.util.logging.Level;
> import java.util.logging.Logger;
>+import java.util.logging.Level;
>+
>+import com.sun.faces.util.FacesLogger;
>
> /**
> * <p>Create and configure DocumentBuilderFactory instances.</p>
> */
> public class DbfFactory {
>
>- private static final Logger LOGGER =FacesLogger.CONFIG.getLogger();
>+ private static final Logger LOGGER = FacesLogger.CONFIG.getLogger();
>
>- private static final String JAXP_SCHEMA_LANGUAGE =
>- "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
>- private static final String W3C_XML_SCHEMA =
>- "http://www.w3.org/2001/XMLSchema";
>- private static final String JAXP_SCHEMA_SOURCE =
>- "http://java.sun.com/xml/jaxp/properties/schemaSource";
>- private static final String FACES_1_2_SCHEMA =
>+ /**
>+ * Location of the Faces 1.2 Schema
>+ */
>+ private static final String FACES_1_2_XSD =
> "/com/sun/faces/web-facesconfig_1_2.xsd";
>
>+ /**
>+ * Our cached Schema object for validation
>+ */
>+ private static Schema FACES_SCHEMA;
>
> /**
> * EntityResolver
>@@ -75,10 +83,19 @@
> public static final EntityResolver FACES_ENTITY_RESOLVER =
> new FacesEntityResolver();
>
>+
>+ /**
>+ * ErrorHandler
>+ */
> public static final FacesErrorHandler FACES_ERROR_HANDLER =
> new FacesErrorHandler();
>
>
>+ static {
>+ initSchema();
>+ }
>+
>+
>
> // ---------------------------------------------------------- Public Methods
>
>@@ -86,23 +103,42 @@
> public static DocumentBuilderFactory getFactory(boolean validating) {
>
> DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
>- factory.setValidating(validating);
>+ if (validating) {
>+ factory.setSchema(FACES_SCHEMA);
>+ }
> factory.setNamespaceAware(true);
> factory.setIgnoringComments(true);
> factory.setIgnoringElementContentWhitespace(true);
>- factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
>- factory.setAttribute(JAXP_SCHEMA_SOURCE,
>- FacesEntityResolver.class.getResource(
>- FACES_1_2_SCHEMA).toExternalForm());
> return factory;
>
>- }
>+ }
>
>
>- // ----------------------------------------------------------- Inner Classes
>+ /**
>+ * Init our cache objects.
>+ */
>+ private static void initSchema() {
>+
>+ // First, cache the various files
>+ try {
>+ URL url = DbfFactory.class.getResource(FACES_1_2_XSD);
>+ URLConnection conn = url.openConnection();
>+ conn.setUseCaches(false);
>+ InputStream in = conn.getInputStream();
>+
>+ // next, cache the schema
>+ SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
>+ factory.setResourceResolver((LSResourceResolver) DbfFactory.FACES_ENTITY_RESOLVER);
>+ FACES_SCHEMA = factory.newSchema(new StreamSource(in));
>+ } catch (Exception e) {
>+ throw new ConfigurationException(e);
>+ }
>+
>+ }
>
>+ // ----------------------------------------------------------- Inner Classes
>
>- private static class FacesEntityResolver extends DefaultHandler {
>+ private static class FacesEntityResolver extends DefaultHandler implements LSResourceResolver {
>
> /**
> * <p>Contains associations between grammar name and the physical
>@@ -119,7 +155,7 @@
> },
> {
> "web-facesconfig_1_2.xsd",
>- FACES_1_2_SCHEMA
>+ FACES_1_2_XSD
> },
> {
> "javaee_5.xsd",
>@@ -132,6 +168,14 @@
> {
> "xml.xsd",
> "/com/sun/faces/xml.xsd"
>+ },
>+ {
>+ "datatypes.dtd",
>+ "/com/sun/faces/datatypes.dtd"
>+ },
>+ {
>+ "XMLSchema.dtd",
>+ "/com/sun/faces/XMLSchema.dtd"
> }
> };
>
>@@ -171,7 +215,7 @@
>
> } // END JsfEntityResolver
>
>-
>+
> // ----------------------------------------- Methods from DefaultHandler
>
>
>@@ -246,8 +290,19 @@
>
> } // END resolveEntity
>
>+ public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
>+ try {
>+ InputSource source = resolveEntity(publicId, systemId);
>+ if (source != null) {
>+ return new Input(source.getByteStream());
>+ }
>+ } catch (Exception e) {
>+ throw new ConfigurationException(e);
>+ }
>+ return null;
>+ }
>
>- // ------------------------------------------------------ Public Methods
>+ // ------------------------------------------------------ Public Methods
>
> public Map<String,String> getKnownEntities() {
>
>@@ -270,4 +325,59 @@
> throw exception;
> }
> } // END FacesErrorHandler
>+
>+
>+ private static final class Input implements LSInput {
>+ InputStream in;
>+ public Input(InputStream in) {
>+ this.in = in;
>+ }
>+ public Reader getCharacterStream() {
>+ return null;
>+ }
>+
>+ public void setCharacterStream(Reader characterStream) { }
>+
>+ public InputStream getByteStream() {
>+ return in;
>+ }
>+
>+ public void setByteStream(InputStream byteStream) { }
>+
>+ public String getStringData() {
>+ return null;
>+ }
>+
>+ public void setStringData(String stringData) { }
>+
>+ public String getSystemId() {
>+ return null;
>+ }
>+
>+ public void setSystemId(String systemId) { }
>+
>+ public String getPublicId() {
>+ return null;
>+ }
>+
>+ public void setPublicId(String publicId) { }
>+
>+ public String getBaseURI() {
>+ return null;
>+ }
>+
>+ public void setBaseURI(String baseURI) { }
>+
>+ public String getEncoding() {
>+ return null;
>+ }
>+
>+ public void setEncoding(String encoding) { }
>+
>+ public boolean getCertifiedText() {
>+ return false;
>+ }
>+
>+ public void setCertifiedText(boolean certifiedText) { }
>+ }
> }
>
>
>
>
>
>------------------------------------------------------------------------
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: dev-unsubscribe_at_javaserverfaces.dev.java.net
>For additional commands, e-mail: dev-help_at_javaserverfaces.dev.java.net
>
>