dev@glassfish.java.net

Help needed with schema validation in web container

From: Jan Luehe <Jan.Luehe_at_Sun.COM>
Date: Wed, 08 Mar 2006 18:09:59 -0800

I'm trying to add schema validation to the Servlet and JSP containers
by leveraging the javax.xml.validation package.

Both containers need to be able to validate a given deployment or tag
library descriptor file against its underlying schema.

A given descriptor file may adhere to one of the following schemas:
"web-jsptaglibrary_2_0.xsd", "web-jsptaglibrary_2_1.xsd",
"web-app_2_4.xsd", or "web-app_2_5.xsd".

I'm using

    javax.xml.validation.SchemaFactory.newSchema(Source[] schemas)

and pass it the above schemas (see attached source).

I can construct "schema1" just fine, but when I use it to validate a
Servlet 2.4 based deployment descriptor, I get this error:

   Document is invalid: no grammar found.

which makes we wonder if the "web-app_2_4.xsd" schema was parsed at all.

When I try to construct "schema2" from just "web-app_2_4.xsd", I get
this error:


Exception in thread "main" org.xml.sax.SAXParseException:
sch-props-correct.2: A schema cannot contain two global components
with the same name; this schema contains two occurrences of
'http://java.sun.com/xml/ns/j2ee,descriptionGroup'.
        at
com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:236)
        at
com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:172)
        at
com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:382)
        at
com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:2241)
        at
com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.checkForDuplicateNames(XSDHandler.java:1918)
        at
com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.buildGlobalNameRegistries(XSDHandler.java:983)
        at
com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:478)
        at
com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:556)
        at
com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:523)
        at
com.sun.org.apache.xerces.internal.jaxp.validation.xs.SchemaFactoryImpl.newSchema(SchemaFactoryImpl.java:206)
        at javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:489)
        at SchemaTester.main(SchemaTester.java:34)


"j2ee:descriptionGroup" is declared by both jsp_2_0.xsd and
j2ee_1_4.xsd, both of which are included by "web-app_2_4.xsd".
Does this make "web-app_2_4.xsd" invalid, or is there a way to avoid the
above error?

You can reproduce the error by compiling the attached source file and
running:

  java -classpath {S1AS_HOME}/lib:. SchemaTester

(The -classpath argument is necessary for the program to be able to
retrieve the various schema resources, which are located under
{S1AS_HOME}/lib/schemas/.)

Thank you for any pointers you may have.


Jan


import java.io.InputStream;
import java.io.Reader;
import javax.xml.XMLConstants;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.ls.LSResourceResolver;
import org.w3c.dom.ls.LSInput;

public class SchemaTester {

    public static void main(String[] args) throws Exception {

        SchemaFactory schemaFactory = SchemaFactory.newInstance(
                XMLConstants.W3C_XML_SCHEMA_NS_URI);
        schemaFactory.setResourceResolver(new MyLSResourceResolver());

        Schema schema1 = schemaFactory.newSchema(new Source[] {
            new StreamSource(
                SchemaTester.class.getResourceAsStream(
                    "/schemas/web-jsptaglibrary_2_0.xsd")),
            new StreamSource(
                SchemaTester.class.getResourceAsStream(
                    "/schemas/web-jsptaglibrary_2_1.xsd")),
            new StreamSource(
                SchemaTester.class.getResourceAsStream(
                    "/schemas/web-app_2_4.xsd")),
            new StreamSource(
                SchemaTester.class.getResourceAsStream(
                    "/schemas/web-app_2_5.xsd"))
        });

        Schema schema2 = schemaFactory.newSchema(
            new StreamSource(
                SchemaTester.class.getResourceAsStream(
                    "/schemas/web-app_2_4.xsd")));
    }
}

class MyLSResourceResolver implements LSResourceResolver {

    private static final String SCHEMA_RESOURCE_PREFIX = "/schemas/";

    public LSInput resolveResource(String type,
                                   String namespaceURI,
                                   String publicId,
                                   String systemId,
                                   String baseURI) {

        String resourceName = systemId;
        int index = systemId.lastIndexOf('/');
        if (index != -1) {
            resourceName = systemId.substring(index+1);
        }
        String resourcePath = SCHEMA_RESOURCE_PREFIX + resourceName;
        InputStream is = MyLSResourceResolver.class.getResourceAsStream(
                                        resourcePath);
        MyLSInput ls = new MyLSInput();
        ls.setByteStream(is);

        return ls;
    }
}

class MyLSInput implements LSInput {

    private Reader charStream;
    private InputStream byteStream;
    private String stringData;
    private String systemId;
    private String publicId;
    private String baseURI;
    private String encoding;
    private boolean certifiedText;

    public Reader getCharacterStream() {
        return charStream;
    }

    public void setCharacterStream(Reader charStream) {
        this.charStream = charStream;
    }

    public InputStream getByteStream() {
        return byteStream;
    }

    public void setByteStream(InputStream byteStream) {
        this.byteStream = byteStream;
    }

    public String getStringData() {
        return stringData;
    }

    public void setStringData(String stringData) {
        this.stringData = stringData;
    }

    public String getSystemId() {
        return systemId;
    }

    public void setSystemId(String systemId) {
        this.systemId = systemId;
    }

    public String getPublicId() {
        return publicId;
    }

    public void setPublicId(String publicId) {
        this.publicId = publicId;
    }

    public String getBaseURI() {
        return baseURI;
    }

    public void setBaseURI(String baseURI) {
        this.baseURI = baseURI;
    }

    public String getEncoding() {
        return encoding;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public boolean getCertifiedText() {
        return certifiedText;
    }

    public void setCertifiedText(boolean certifiedText) {
        this.certifiedText = certifiedText;
    }
}