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) { }
+ }
}