You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-dev@db.apache.org by Craig L Russell <Cr...@Sun.COM> on 2006/03/06 00:42:30 UTC
Re: JDO-319 patch
Hi Michael,
A few comments.
1. The main method should print a usage message, e.g.
System.err.println("No commandline arguments and system property
metadata not defined; nothing to be tested.\nUsage: XMLTest
<directories>\n\tAll .jdo, .orm, and .jdoquery files in the directory
(recursively) will be tested.");
As a future enhancement we might consider the "standard" -r flag to
mean recursively search the directory.
2. Perhaps the name of the metadata system property should be more
specific, like javax.jdo.test.metadata
3. I added a convenience method to JDO_Test: void failOnError() that
checks if messages is null and if not, fails with the error message
text. You can see it in the checkin
+ /**
+ * Fail the test if there are any error messages.
+ */
+ protected void failOnError() {
+ String errors = retrieveMessages();
+ if (errors != null) {
+ fail (errors);
+ }
+ }
Craig
On Mar 5, 2006, at 2:33 PM, Michael Bouschen wrote:
> Hi,
>
> attached you find a patch for review. JIRA is down, because of a
> system maintenance, so I send the patch to the jdo-dev alias. It
> factors out the code from the existing api20 test class XMLTest
> running an xml parser on .jdo, .orm and .jdoquery files into an
> utility class. The XMLTest class now uese the utility class for
> testing the metadata files under test/schema. There is a new goal
> in maven.xml allowing to run the utility class as a standalone tool
> to check JDO metadata files specified by a system property called
> metadata.
>
> Regards Michael
>
> --
> Michael Bouschen Tech@Spree Engineering GmbH
> mailto:mbo.tech@spree.de http://www.tech.spree.de/
> Tel.:++49/30/235 520-33 Buelowstr. 66
> Fax.:++49/30/2175 2012 D-10783 Berlin
>
> Index: test/java/javax/jdo/schema/XMLTest.java
> ===================================================================
> --- test/java/javax/jdo/schema/XMLTest.java (Revision 383084)
> +++ test/java/javax/jdo/schema/XMLTest.java (Arbeitskopie)
> @@ -16,23 +16,17 @@
>
> package javax.jdo.schema;
>
> -import java.io.BufferedReader;
> import java.io.File;
> -import java.io.FileReader;
> -import java.io.InputStream;
> -import java.io.InputStreamReader;
> import java.io.IOException;
> import java.io.FilenameFilter;
>
> -import java.security.AccessController;
> -import java.security.PrivilegedAction;
> -import java.util.ArrayList;
> -import java.util.HashMap;
> -import java.util.Map;
> +import java.util.Arrays;
> +import java.util.List;
>
> import javax.jdo.JDOFatalException;
> import javax.jdo.util.AbstractTest;
> import javax.jdo.util.BatchTestRunner;
> +import javax.jdo.util.XMLTestUtil;
>
> import javax.xml.parsers.*;
> import org.w3c.dom.Document;
> @@ -48,31 +42,10 @@
> /** */
> protected static String BASEDIR = System.getProperty
> ("basedir", ".");
>
> - /** "http://www.w3.org/2001/XMLSchema" */
> - protected static final String XSD_TYPE =
> - "http://www.w3.org/2001/XMLSchema";
> + /** File prefix */
> + protected static final String FILE_PREFIX = BASEDIR + "/test/
> schema/";
>
> /** */
> - protected static final String SCHEMA_LANGUAGE_PROP =
> - "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
> -
> - /** */
> - protected static final String SCHEMA_LOCATION_PROP =
> - "http://apache.org/xml/properties/schema/external-
> schemaLocation";
> -
> - /** jdo namespace */
> - protected static final String JDO_XSD_NS =
> - "http://java.sun.com/xml/ns/jdo/jdo";
> -
> - /** orm namespace */
> - protected static final String ORM_XSD_NS =
> - "http://java.sun.com/xml/ns/jdo/orm";
> -
> - /** jdoquery namespace */
> - protected static final String JDOQL_XSD_NS =
> - "http://java.sun.com/xml/ns/jdo/jdoquery";
> -
> - /** */
> protected static final File JDO_XSD_FILE =
> new File(BASEDIR + "/target/classes/javax/jdo/jdo.xsd");
>
> @@ -81,39 +54,29 @@
> new File(BASEDIR + "/target/classes/javax/jdo/orm.xsd");
>
> /** */
> - protected static final File JDOQL_XSD_FILE =
> + protected static final File JDOQUERY_XSD_FILE =
> new File(BASEDIR + "/target/classes/javax/jdo/jdoquery.xsd");
>
> - /** File prefix */
> - protected static final String FILE_PREFIX = BASEDIR + "/test/
> schema/";
> -
> - /** Entity resolver */
> - protected static final EntityResolver resolver = new
> JDOEntityResolver();
> -
> - /** Error handler */
> - protected static final Handler handler = new Handler();
> -
> /** .xsd files */
> - protected static final File[] XSD_FILES = {
> - JDO_XSD_FILE, ORM_XSD_FILE, JDOQL_XSD_FILE
> - };
> + protected static final File[] XSD_FILES =
> + new File[] {JDO_XSD_FILE, ORM_XSD_FILE, JDOQUERY_XSD_FILE};
>
> /** XSD metadata files. */
> protected static File[] positiveXSDJDO = getFiles("Positive",
> "-xsd.jdo");
> protected static File[] negativeXSDJDO = getFiles("Negative",
> "-xsd.jdo");
> protected static File[] positiveXSDORM = getFiles("Positive",
> "-xsd.orm");
> protected static File[] negativeXSDORM = getFiles("Negative",
> "-xsd.orm");
> - protected static File[] positiveXSDJDOQL = getFiles
> ("Positive", "-xsd.jdoquery");
> - protected static File[] negativeXSDJDOQL = getFiles
> ("Negative", "-xsd.jdoquery");
> -
> + protected static File[] positiveXSDJDOQUERY = getFiles
> ("Positive", "-xsd.jdoquery");
> + protected static File[] negativeXSDJDOQUERY = getFiles
> ("Negative", "-xsd.jdoquery");
> +
> /** DTD metadata files. */
> protected static File[] positiveDTDJDO = getFiles("Positive",
> "-dtd.jdo");
> protected static File[] negativeDTDJDO = getFiles("Negative",
> "-dtd.jdo");
> protected static File[] positiveDTDORM = getFiles("Positive",
> "-dtd.orm");
> protected static File[] negativeDTDORM = getFiles("Negative",
> "-dtd.orm");
> - protected static File[] positiveDTDJDOQL = getFiles
> ("Positive", "-dtd.jdoquery");
> - protected static File[] negativeDTDJDOQL = getFiles
> ("Negative", "-dtd.jdoquery");
> -
> + protected static File[] positiveDTDJDOQUERY = getFiles
> ("Positive", "-dtd.jdoquery");
> + protected static File[] negativeDTDJDOQUERY = getFiles
> ("Negative", "-dtd.jdoquery");
> +
> /** Returns array of files of matching file names. */
> protected static File[] getFiles(final String prefix, final
> String suffix) {
> FilenameFilter filter = new FilenameFilter () {
> @@ -121,22 +84,13 @@
> return (name.startsWith(prefix) && name.endsWith
> (suffix));
> }
> };
> - File dir = new File(FILE_PREFIX);
> - return dir.listFiles(filter);
> + return new File(FILE_PREFIX).listFiles(filter);
> }
>
> - /** */
> - public static void main(String args[]) {
> - BatchTestRunner.run(XMLTest.class);
> - }
> -
> /** Test XSD files jdo.xsd, orm.xsd, and jdoquery.xsd. */
> - public void testXSD() throws SAXException, IOException {
> - DocumentBuilder builder = null;
> - DocumentBuilderFactory factory =
> DocumentBuilderFactory.newInstance();
> - factory.setNamespaceAware(true);
> - builder = getParser(factory);
> - checkXML(builder, XSD_FILES, true);
> + public void testXSD() {
> + XMLTestUtil util = new XMLTestUtil();
> + util.checkXMLNonValidating(XSD_FILES);
> String messages = retrieveMessages();
> if (messages != null) {
> fail(messages);
> @@ -145,17 +99,13 @@
>
> /** Test XSD based .jdo, .orm and .jdoquery files. */
> public void testXSDBased() {
> - // create XSD parser
> - DocumentBuilder builder = null;
> - builder = createBuilder(JDO_XSD_NS + " " +
> JDO_XSD_FILE.toURI().toString());
> - checkXML(builder, positiveXSDJDO, true);
> - checkXML(builder, negativeXSDJDO, false);
> - builder = createBuilder(ORM_XSD_NS + " " +
> ORM_XSD_FILE.toURI().toString());
> - checkXML(builder, positiveXSDORM, true);
> - checkXML(builder, negativeXSDORM, false);
> - builder = createBuilder(JDOQL_XSD_NS + " " +
> JDOQL_XSD_FILE.toURI().toString());
> - checkXML(builder, positiveXSDJDOQL, true);
> - checkXML(builder, negativeXSDJDOQL, false);
> + XMLTestUtil util = new XMLTestUtil();
> + util.checkXML(positiveXSDJDO, true);
> + util.checkXML(negativeXSDJDO, false);
> + util.checkXML(positiveXSDORM, true);
> + util.checkXML(negativeXSDORM, false);
> + util.checkXML(positiveXSDJDOQUERY, true);
> + util.checkXML(negativeXSDJDOQUERY, false);
> String messages = retrieveMessages();
> if (messages != null) {
> fail(messages);
> @@ -164,251 +114,18 @@
>
> /** Test DTD based .jdo, .orm and .jdoquery files. */
> public void testDTDBased() {
> - // create DTD parser
> - DocumentBuilder builder = createBuilder();
> - checkXML(builder, positiveDTDJDO, true);
> - checkXML(builder, negativeDTDJDO, false);
> - checkXML(builder, positiveDTDORM, true);
> - checkXML(builder, negativeDTDORM, false);
> - checkXML(builder, positiveDTDJDOQL, true);
> - checkXML(builder, negativeDTDJDOQL, false);
> + XMLTestUtil util = new XMLTestUtil();
> + util.checkXML(positiveDTDJDO, true);
> + util.checkXML(negativeDTDJDO, false);
> + util.checkXML(positiveDTDORM, true);
> + util.checkXML(negativeDTDORM, false);
> + util.checkXML(positiveDTDJDOQUERY, true);
> + util.checkXML(negativeDTDJDOQUERY, false);
> String messages = retrieveMessages();
> if (messages != null) {
> fail(messages);
> }
> }
>
> - /** Create XSD builder.
> - */
> - private DocumentBuilder createBuilder(String location) {
> - DocumentBuilderFactory factory =
> DocumentBuilderFactory.newInstance();
> - factory.setValidating(true);
> - factory.setNamespaceAware(true);
> - factory.setAttribute(SCHEMA_LANGUAGE_PROP, XSD_TYPE);
> - factory.setAttribute(SCHEMA_LOCATION_PROP, location);
> - return getParser(factory);
> - }
> -
> - /** Create DTD builder.
> - */
> - private DocumentBuilder createBuilder() {
> - DocumentBuilderFactory factory =
> DocumentBuilderFactory.newInstance();
> - factory.setValidating(true);
> - factory.setNamespaceAware(true);
> - return getParser(factory);
> - }
> -
> - /** Returns a parser obtained from specified factroy. */
> - private DocumentBuilder getParser(DocumentBuilderFactory
> factory) {
> - try {
> - DocumentBuilder builder = factory.newDocumentBuilder();
> - builder.setEntityResolver(resolver);
> - builder.setErrorHandler(handler);
> - return builder;
> - } catch (ParserConfigurationException ex) {
> - throw new JDOFatalException("Cannot create XML
> parser", ex);
> - }
> - }
> -
> - /** Parse the specified files using the specified builder. The
> valid
> - * parameter determines whether the specified files are valid
> JDO metadata
> - * files. The method does not throw an exception on an error,
> instead it
> - * appends any error message to the global message handler.
> - */
> - private void checkXML(DocumentBuilder builder, File[] files,
> boolean valid) {
> - for (int i = 0; i < files.length; i++) {
> - File file = files[i];
> - handler.init(file);
> - try {
> - builder.parse(file);
> - } catch (SAXParseException ex) {
> - handler.error(ex);
> - } catch (Exception ex) {
> - throw new JDOFatalException("Fatal error
> processing " +
> - file.getName(), ex);
> - }
> - String messages = handler.getMessages();
> - if (valid && (messages != null)) {
> - appendMessage(messages);
> - } else if (!valid && (messages == null)) {
> - appendMessage(file.getName() + " is not valid, " +
> - "but the parser did not catch the
> error.");
> - }
> - }
> - }
> -
> - /** ErrorHandler implementation. */
> - private static class Handler implements ErrorHandler {
> -
> - private File fileUnderTest;
> - private String[] lines;
> - private StringBuffer messages;
> -
> - public void error(SAXParseException ex) {
> - append("Handler.error: ", ex);
> - }
> -
> - public void fatalError(SAXParseException ex) {
> - append("Handler.fatalError: ", ex);
> - }
> -
> - public void warning(SAXParseException ex) {
> - append("Handler.warning: ", ex);
> - }
> -
> - public void init(File file) {
> - this.fileUnderTest = file;
> - this.messages = new StringBuffer();
> - this.lines = null;
> - }
> -
> - public String getMessages() {
> - return (messages.length() == 0) ? null :
> messages.toString();
> - }
> -
> - private void append(String prefix, SAXParseException ex) {
> - int lineNumber = ex.getLineNumber();
> - int columnNumber = ex.getColumnNumber();
> - messages.append("------------------------").append(NL);
> - messages.append(prefix).append(fileUnderTest.getName());
> - messages.append(" [line=").append(lineNumber);
> - messages.append(", col=").append(columnNumber).append
> ("]: ");
> - messages.append(ex.getMessage()).append(NL);
> - messages.append(getErrorLocation(lineNumber,
> columnNumber));
> - }
> -
> - private String[] getLines() {
> - if (lines == null) {
> - try {
> - BufferedReader bufferedReader =
> - new BufferedReader(new FileReader
> (fileUnderTest));
> - ArrayList tmp = new ArrayList();
> - while (bufferedReader.ready()) {
> - tmp.add(bufferedReader.readLine());
> - }
> - lines = (String[])tmp.toArray(new String
> [tmp.size()]);
> - } catch (IOException ex) {
> - throw new JDOFatalException("getLines: caught
> IOException", ex);
> - }
> - }
> - return lines;
> - }
> -
> - /** Return the error location for the file under test.
> - */
> - private String getErrorLocation(int lineNumber, int
> columnNumber) {
> - String[] lines = getLines();
> - int length = lines.length;
> - if (lineNumber > length) {
> - return "Line number " + lineNumber +
> - " exceeds the number of lines in the file (" +
> - lines.length + ")";
> - } else if (lineNumber < 1) {
> - return "Line number " + lineNumber +
> - " does not allow retriving the error location.";
> - }
> - StringBuffer buf = new StringBuffer();
> - if (lineNumber > 2) {
> - buf.append(lines[lineNumber-3]);
> - buf.append(NL);
> - buf.append(lines[lineNumber-2]);
> - buf.append(NL);
> - }
> - buf.append(lines[lineNumber-1]);
> - buf.append(NL);
> - for (int i = 1; i < columnNumber; ++i) {
> - buf.append(' ');
> - }
> - buf.append("^\n");
> - if (lineNumber + 1 < length) {
> - buf.append(lines[lineNumber]);
> - buf.append(NL);
> - buf.append(lines[lineNumber+1]);
> - buf.append(NL);
> - }
> - return buf.toString();
> - }
> - }
> -
> - /** Implementation of EntityResolver interface to check the
> jdo.dtd location
> - **/
> - private static class JDOEntityResolver
> - implements EntityResolver {
> -
> - private static final String RECOGNIZED_JDO_PUBLIC_ID =
> - "-//Sun Microsystems, Inc.//DTD Java Data Objects
> Metadata 2.0//EN";
> - private static final String RECOGNIZED_JDO_SYSTEM_ID =
> - "file:/javax/jdo/jdo.dtd";
> - private static final String RECOGNIZED_JDO_SYSTEM_ID2 =
> - "http://java.sun.com/dtd/jdo_2_0.dtd";
> - private static final String RECOGNIZED_ORM_PUBLIC_ID =
> - "-//Sun Microsystems, Inc.//DTD Java Data Objects
> Mapping Metadata 2.0//EN";
> - private static final String RECOGNIZED_ORM_SYSTEM_ID =
> - "file:/javax/jdo/orm.dtd";
> - private static final String RECOGNIZED_ORM_SYSTEM_ID2 =
> - "http://java.sun.com/dtd/orm_2_0.dtd";
> - private static final String RECOGNIZED_JDOQUERY_PUBLIC_ID =
> - "-//Sun Microsystems, Inc.//DTD Java Data Objects
> Query Metadata 2.0//EN";
> - private static final String RECOGNIZED_JDOQUERY_SYSTEM_ID =
> - "file:/javax/jdo/jdoquery.dtd";
> - private static final String RECOGNIZED_JDOQUERY_SYSTEM_ID2 =
> - "http://java.sun.com/dtd/jdoquery_2_0.dtd";
> - private static final String JDO_DTD_FILENAME =
> - "javax/jdo/jdo.dtd";
> - private static final String ORM_DTD_FILENAME =
> - "javax/jdo/orm.dtd";
> - private static final String JDOQUERY_DTD_FILENAME =
> - "javax/jdo/jdoquery.dtd";
> -
> - static Map publicIds = new HashMap();
> - static Map systemIds = new HashMap();
> - static {
> - publicIds.put(RECOGNIZED_JDO_PUBLIC_ID,
> JDO_DTD_FILENAME);
> - publicIds.put(RECOGNIZED_ORM_PUBLIC_ID,
> ORM_DTD_FILENAME);
> - publicIds.put(RECOGNIZED_JDOQUERY_PUBLIC_ID,
> JDOQUERY_DTD_FILENAME);
> - systemIds.put(RECOGNIZED_JDO_SYSTEM_ID,
> JDO_DTD_FILENAME);
> - systemIds.put(RECOGNIZED_ORM_SYSTEM_ID,
> ORM_DTD_FILENAME);
> - systemIds.put(RECOGNIZED_JDOQUERY_SYSTEM_ID,
> JDOQUERY_DTD_FILENAME);
> - systemIds.put(RECOGNIZED_JDO_SYSTEM_ID2,
> JDO_DTD_FILENAME);
> - systemIds.put(RECOGNIZED_ORM_SYSTEM_ID2,
> ORM_DTD_FILENAME);
> - systemIds.put(RECOGNIZED_JDOQUERY_SYSTEM_ID2,
> JDOQUERY_DTD_FILENAME);
> - }
> - public InputSource resolveEntity(String publicId, final
> String systemId)
> - throws SAXException, IOException
> - {
> - // check for recognized ids
> - String filename = (String)publicIds.get(publicId);
> - if (filename == null) {
> - filename = (String)systemIds.get(systemId);
> - }
> - final String finalName = filename;
> - if (finalName == null) {
> - return null;
> - } else {
> - // Substitute the dtd with the one from
> javax.jdo.jdo.dtd,
> - // but only if the publicId is equal to
> RECOGNIZED_PUBLIC_ID
> - // or there is no publicID and the systemID is
> equal to
> - // RECOGNIZED_SYSTEM_ID.
> - InputStream stream = (InputStream)
> AccessController.doPrivileged (
> - new PrivilegedAction () {
> - public Object run () {
> - return getClass().getClassLoader().
> - getResourceAsStream(finalName);
> - }
> - }
> - );
> - if (stream == null) {
> - // TDB: error handling + I18N
> - throw new JDOFatalException("Cannot load " +
> - finalName +
> - ", because the file does not exist in
> the jdo.jar file, " +
> - "or the JDOParser class is not granted
> permission to read this file. " +
> - "The metadata .xml file contained
> PUBLIC=" + publicId +
> - " SYSTEM=" + systemId + ".");
> - }
> - return new InputSource(new InputStreamReader
> (stream));
> - }
> - }
> - }
> }
>
> Index: test/java/javax/jdo/util/XMLTestUtil.java
> ===================================================================
> --- test/java/javax/jdo/util/XMLTestUtil.java (Revision 0)
> +++ test/java/javax/jdo/util/XMLTestUtil.java (Revision 0)
> @@ -0,0 +1,503 @@
> +/*
> + * Copyright 2006 The Apache Software Foundation.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing,
> software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> + * See the License for the specific language governing permissions
> and
> + * limitations under the License.
> + */
> +
> +package javax.jdo.util;
> +
> +import java.io.BufferedReader;
> +import java.io.File;
> +import java.io.FileReader;
> +import java.io.InputStream;
> +import java.io.InputStreamReader;
> +import java.io.IOException;
> +import java.io.FilenameFilter;
> +
> +import java.security.AccessController;
> +import java.security.PrivilegedAction;
> +import java.util.Arrays;
> +import java.util.ArrayList;
> +import java.util.HashMap;
> +import java.util.Iterator;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.StringTokenizer;
> +
> +import javax.jdo.JDOFatalException;
> +import javax.jdo.util.AbstractTest;
> +import javax.jdo.util.BatchTestRunner;
> +
> +import javax.xml.parsers.*;
> +import org.w3c.dom.Document;
> +import org.xml.sax.*;
> +import org.xml.sax.helpers.*;
> +
> +/**
> + * Tests schema files.
> + * <p>
> + */
> +public class XMLTestUtil {
> +
> + /** */
> + protected static String BASEDIR = System.getProperty
> ("basedir", ".");
> +
> + /** "http://www.w3.org/2001/XMLSchema" */
> + protected static final String XSD_TYPE =
> + "http://www.w3.org/2001/XMLSchema";
> +
> + /** */
> + protected static final String SCHEMA_LANGUAGE_PROP =
> + "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
> +
> + /** */
> + protected static final String SCHEMA_LOCATION_PROP =
> + "http://apache.org/xml/properties/schema/external-
> schemaLocation";
> +
> + /** jdo namespace */
> + protected static final String JDO_XSD_NS =
> + "http://java.sun.com/xml/ns/jdo/jdo";
> +
> + /** orm namespace */
> + protected static final String ORM_XSD_NS =
> + "http://java.sun.com/xml/ns/jdo/orm";
> +
> + /** jdoquery namespace */
> + protected static final String JDOQUERY_XSD_NS =
> + "http://java.sun.com/xml/ns/jdo/jdoquery";
> +
> + /** jdo xsd file */
> + protected static final File JDO_XSD_FILE =
> + new File(BASEDIR + "/target/classes/javax/jdo/jdo.xsd");
> +
> + /** orm xsd file */
> + protected static final File ORM_XSD_FILE =
> + new File(BASEDIR + "/target/classes/javax/jdo/orm.xsd");
> +
> + /** jdoquery xsd file */
> + protected static final File JDOQUERY_XSD_FILE =
> + new File(BASEDIR + "/target/classes/javax/jdo/jdoquery.xsd");
> +
> + /** Entity resolver */
> + protected static final EntityResolver resolver = new
> JDOEntityResolver();
> +
> + /** Error handler */
> + protected static final Handler handler = new Handler();
> +
> + /** Name of the metadata property, a comma separated list of
> JDO metadata
> + * file or directories containing such files. */
> + protected static String METADATA_PROP = "metadata";
> +
> + /** Separator character for the metadata property. */
> + protected static String DELIM = ",;";
> +
> + /** XSD builder for jdo namespace. */
> + private final DocumentBuilder jdoXsdBuilder =
> + createBuilder(JDO_XSD_NS + " " + JDO_XSD_FILE.toURI
> ().toString());
> +
> + /** XSD builder for orm namespace. */
> + private final DocumentBuilder ormXsdBuilder =
> + createBuilder(ORM_XSD_NS + " " + ORM_XSD_FILE.toURI
> ().toString());
> +
> + /** XSD builder for jdoquery namespace. */
> + private final DocumentBuilder jdoqueryXsdBuilder =
> + createBuilder(JDOQUERY_XSD_NS + " " +
> JDOQUERY_XSD_FILE.toURI().toString());
> +
> + /** DTD builder. */
> + private final DocumentBuilder dtdBuilder = createBuilder(true);
> +
> + /** Non validating builder. */
> + private final DocumentBuilder nonValidatingBuilder =
> createBuilder(false);
> +
> + /** Create XSD builder. */
> + private DocumentBuilder createBuilder(String location) {
> + DocumentBuilderFactory factory =
> DocumentBuilderFactory.newInstance();
> + factory.setValidating(true);
> + factory.setNamespaceAware(true);
> + factory.setAttribute(SCHEMA_LANGUAGE_PROP, XSD_TYPE);
> + factory.setAttribute(SCHEMA_LOCATION_PROP, location);
> + return getParser(factory);
> + }
> +
> + /** Create builder. */
> + private DocumentBuilder createBuilder(boolean validating) {
> + DocumentBuilderFactory factory =
> DocumentBuilderFactory.newInstance();
> + factory.setValidating(validating);
> + factory.setNamespaceAware(true);
> + return getParser(factory);
> + }
> +
> + /** Returns a parser obtained from specified factroy. */
> + private DocumentBuilder getParser(DocumentBuilderFactory
> factory) {
> + try {
> + DocumentBuilder builder = factory.newDocumentBuilder();
> + builder.setEntityResolver(resolver);
> + builder.setErrorHandler(handler);
> + return builder;
> + } catch (ParserConfigurationException ex) {
> + throw new JDOFatalException("Cannot create XML
> parser", ex);
> + }
> + }
> +
> + /** Parse the specified files. The valid parameter determines
> whether the
> + * specified files are valid JDO metadata files. The method
> does not throw
> + * an exception on an error, instead it appends any error
> message to the
> + * global message handler.
> + */
> + public void checkXML(File[] files, boolean valid) {
> + for (int i = 0; i < files.length; i++) {
> + String messages = checkXML(files[i], valid);
> + if (messages != null) {
> + AbstractTest.appendMessage(messages);
> + }
> + }
> + }
> +
> + /** Parse the specified files using a non validating parser.
> The method
> + * does not throw an exception on an error, instead it appends
> any error
> + * message to the global message handler.
> + */
> + public void checkXMLNonValidating(File[] files) {
> + for (int i = 0; i < files.length; i++) {
> + String messages = checkXML(nonValidatingBuilder, files
> [i], true);
> + if (messages != null) {
> + AbstractTest.appendMessage(messages);
> + }
> + }
> + }
> +
> + /** Parse the specified file. The method checks whether it is
> a XSD or
> + * DTD base file and parses the file using a builder according
> to the file
> + * name suffix. The valid parameter determines whether the
> specified files
> + * are valid JDO metadata files. The method does not throw an
> exception on
> + * an error, instead it returns the error message as string.
> + */
> + private String checkXML(File file, boolean valid) {
> + String messages = null;
> + String fileName = file.getName();
> + try {
> + if (isDTDBased(file)) {
> + messages = checkXML(dtdBuilder, file, valid);
> + } else if (fileName.endsWith(".jdo")) {
> + messages = checkXML(jdoXsdBuilder, file, valid);
> + } else if (fileName.endsWith(".orm")) {
> + messages = checkXML(ormXsdBuilder, file, valid);
> + } else if (fileName.endsWith(".jdoquery")) {
> + messages = checkXML(jdoqueryXsdBuilder, file, valid);
> + }
> + } catch (SAXException ex) {
> + messages = ex.getMessage();
> + }
> + return messages;
> + }
> +
> + /** Parse the specified file using the specified builder. The
> valid
> + * parameter determines whether the specified files are valid
> JDO metadata
> + * files. The method does not throw an exception on an error,
> instead it
> + * returns the error message as string.
> + */
> + private String checkXML(DocumentBuilder builder, File file,
> boolean valid) {
> + handler.init(file);
> + try {
> + builder.parse(file);
> + } catch (SAXParseException ex) {
> + handler.error(ex);
> + } catch (Exception ex) {
> + throw new JDOFatalException("Fatal error processing " +
> + file.getName(), ex);
> + }
> + String messages = handler.getMessages();
> + if (!valid) {
> + if (messages != null) {
> + // expected error for negative test
> + messages = null;
> + } else {
> + messages = file.getName() + " is not valid, " +
> + "but the parser did not catch the error.";
> + }
> + }
> + return messages;
> + }
> +
> + /** Checks whether the specifeid file is DTD or XSD based. The
> method
> + * throws a SAXException if the file has syntax errors. */
> + private boolean isDTDBased(File file) throws SAXException {
> + handler.init(file);
> + try {
> + Document document = nonValidatingBuilder.parse(file);
> + return document.getDoctype() != null;
> + } catch (SAXParseException ex) {
> + handler.error(ex);
> + throw new SAXException(handler.getMessages());
> + } catch (Exception ex) {
> + throw new SAXException("Fatal error processing " +
> file.getName() +
> + ": " + ex.getMessage());
> + }
> + }
> +
> + /** ErrorHandler implementation. */
> + private static class Handler implements ErrorHandler {
> +
> + private File fileUnderTest;
> + private String[] lines;
> + private StringBuffer messages;
> +
> + public void error(SAXParseException ex) {
> + append("Handler.error: ", ex);
> + }
> +
> + public void fatalError(SAXParseException ex) {
> + append("Handler.fatalError: ", ex);
> + }
> +
> + public void warning(SAXParseException ex) {
> + append("Handler.warning: ", ex);
> + }
> +
> + public void init(File file) {
> + this.fileUnderTest = file;
> + this.messages = new StringBuffer();
> + this.lines = null;
> + }
> +
> + public String getMessages() {
> + return (messages.length() == 0) ? null :
> messages.toString();
> + }
> +
> + private void append(String prefix, SAXParseException ex) {
> + int lineNumber = ex.getLineNumber();
> + int columnNumber = ex.getColumnNumber();
> + messages.append("------------------------").append
> (AbstractTest.NL);
> + messages.append(prefix).append(fileUnderTest.getName());
> + messages.append(" [line=").append(lineNumber);
> + messages.append(", col=").append(columnNumber).append
> ("]: ");
> + messages.append(ex.getMessage()).append(AbstractTest.NL);
> + messages.append(getErrorLocation(lineNumber,
> columnNumber));
> + }
> +
> + private String[] getLines() {
> + if (lines == null) {
> + try {
> + BufferedReader bufferedReader =
> + new BufferedReader(new FileReader
> (fileUnderTest));
> + ArrayList tmp = new ArrayList();
> + while (bufferedReader.ready()) {
> + tmp.add(bufferedReader.readLine());
> + }
> + lines = (String[])tmp.toArray(new String
> [tmp.size()]);
> + } catch (IOException ex) {
> + throw new JDOFatalException("getLines: caught
> IOException", ex);
> + }
> + }
> + return lines;
> + }
> +
> + /** Return the error location for the file under test.
> + */
> + private String getErrorLocation(int lineNumber, int
> columnNumber) {
> + String[] lines = getLines();
> + int length = lines.length;
> + if (lineNumber > length) {
> + return "Line number " + lineNumber +
> + " exceeds the number of lines in the file (" +
> + lines.length + ")";
> + } else if (lineNumber < 1) {
> + return "Line number " + lineNumber +
> + " does not allow retriving the error location.";
> + }
> + StringBuffer buf = new StringBuffer();
> + if (lineNumber > 2) {
> + buf.append(lines[lineNumber-3]);
> + buf.append(AbstractTest.NL);
> + buf.append(lines[lineNumber-2]);
> + buf.append(AbstractTest.NL);
> + }
> + buf.append(lines[lineNumber-1]);
> + buf.append(AbstractTest.NL);
> + for (int i = 1; i < columnNumber; ++i) {
> + buf.append(' ');
> + }
> + buf.append("^\n");
> + if (lineNumber + 1 < length) {
> + buf.append(lines[lineNumber]);
> + buf.append(AbstractTest.NL);
> + buf.append(lines[lineNumber+1]);
> + buf.append(AbstractTest.NL);
> + }
> + return buf.toString();
> + }
> + }
> +
> + /** Implementation of EntityResolver interface to check the
> jdo.dtd location
> + **/
> + private static class JDOEntityResolver
> + implements EntityResolver {
> +
> + private static final String RECOGNIZED_JDO_PUBLIC_ID =
> + "-//Sun Microsystems, Inc.//DTD Java Data Objects
> Metadata 2.0//EN";
> + private static final String RECOGNIZED_JDO_SYSTEM_ID =
> + "file:/javax/jdo/jdo.dtd";
> + private static final String RECOGNIZED_JDO_SYSTEM_ID2 =
> + "http://java.sun.com/dtd/jdo_2_0.dtd";
> + private static final String RECOGNIZED_ORM_PUBLIC_ID =
> + "-//Sun Microsystems, Inc.//DTD Java Data Objects
> Mapping Metadata 2.0//EN";
> + private static final String RECOGNIZED_ORM_SYSTEM_ID =
> + "file:/javax/jdo/orm.dtd";
> + private static final String RECOGNIZED_ORM_SYSTEM_ID2 =
> + "http://java.sun.com/dtd/orm_2_0.dtd";
> + private static final String RECOGNIZED_JDOQUERY_PUBLIC_ID =
> + "-//Sun Microsystems, Inc.//DTD Java Data Objects
> Query Metadata 2.0//EN";
> + private static final String RECOGNIZED_JDOQUERY_SYSTEM_ID =
> + "file:/javax/jdo/jdoquery.dtd";
> + private static final String RECOGNIZED_JDOQUERY_SYSTEM_ID2 =
> + "http://java.sun.com/dtd/jdoquery_2_0.dtd";
> + private static final String JDO_DTD_FILENAME =
> + "javax/jdo/jdo.dtd";
> + private static final String ORM_DTD_FILENAME =
> + "javax/jdo/orm.dtd";
> + private static final String JDOQUERY_DTD_FILENAME =
> + "javax/jdo/jdoquery.dtd";
> +
> + static Map publicIds = new HashMap();
> + static Map systemIds = new HashMap();
> + static {
> + publicIds.put(RECOGNIZED_JDO_PUBLIC_ID,
> JDO_DTD_FILENAME);
> + publicIds.put(RECOGNIZED_ORM_PUBLIC_ID,
> ORM_DTD_FILENAME);
> + publicIds.put(RECOGNIZED_JDOQUERY_PUBLIC_ID,
> JDOQUERY_DTD_FILENAME);
> + systemIds.put(RECOGNIZED_JDO_SYSTEM_ID,
> JDO_DTD_FILENAME);
> + systemIds.put(RECOGNIZED_ORM_SYSTEM_ID,
> ORM_DTD_FILENAME);
> + systemIds.put(RECOGNIZED_JDOQUERY_SYSTEM_ID,
> JDOQUERY_DTD_FILENAME);
> + systemIds.put(RECOGNIZED_JDO_SYSTEM_ID2,
> JDO_DTD_FILENAME);
> + systemIds.put(RECOGNIZED_ORM_SYSTEM_ID2,
> ORM_DTD_FILENAME);
> + systemIds.put(RECOGNIZED_JDOQUERY_SYSTEM_ID2,
> JDOQUERY_DTD_FILENAME);
> + }
> + public InputSource resolveEntity(String publicId, final
> String systemId)
> + throws SAXException, IOException
> + {
> + // check for recognized ids
> + String filename = (String)publicIds.get(publicId);
> + if (filename == null) {
> + filename = (String)systemIds.get(systemId);
> + }
> + final String finalName = filename;
> + if (finalName == null) {
> + return null;
> + } else {
> + // Substitute the dtd with the one from
> javax.jdo.jdo.dtd,
> + // but only if the publicId is equal to
> RECOGNIZED_PUBLIC_ID
> + // or there is no publicID and the systemID is
> equal to
> + // RECOGNIZED_SYSTEM_ID.
> + InputStream stream = (InputStream)
> AccessController.doPrivileged (
> + new PrivilegedAction () {
> + public Object run () {
> + return getClass().getClassLoader().
> + getResourceAsStream(finalName);
> + }
> + }
> + );
> + if (stream == null) {
> + // TDB: error handling + I18N
> + throw new JDOFatalException("Cannot load " +
> + finalName +
> + ", because the file does not exist in
> the jdo.jar file, " +
> + "or the JDOParser class is not granted
> permission to read this file. " +
> + "The metadata .xml file contained
> PUBLIC=" + publicId +
> + " SYSTEM=" + systemId + ".");
> + }
> + return new InputSource(new InputStreamReader
> (stream));
> + }
> + }
> + }
> +
> + /** Helper class to find all test JDO metadata files. */
> + public static class XMLFinder {
> +
> + private List metadataFiles = new ArrayList();
> +
> + /** Constructor. */
> + public XMLFinder(String[] fileNames) {
> + if (fileNames == null) return;
> + for (int i = 0; i < fileNames.length; i++) {
> + appendTestFiles(fileNames[i]);
> + }
> + }
> +
> + /** Returns array of files of matching file names. */
> + private File[] getFiles(File dir, final String suffix) {
> + FilenameFilter filter = new FilenameFilter () {
> + public boolean accept(File file, String name) {
> + return name.endsWith(suffix);
> + }
> + };
> + return dir.listFiles(filter);
> + }
> +
> + /** */
> + private void appendTestFiles(String fileName) {
> + File file = new File(fileName);
> + if (file.isDirectory()) {
> + metadataFiles.addAll(Arrays.asList(getFiles(file,
> ".jdo")));
> + metadataFiles.addAll(Arrays.asList(getFiles(file,
> ".orm")));
> + metadataFiles.addAll(Arrays.asList(getFiles(file,
> ".jdoquery")));
> + } else if (fileName.endsWith(".jdo") ||
> + fileName.endsWith(".orm") ||
> + fileName.endsWith(".jdoquery")) {
> + metadataFiles.add(new File(fileName));
> + }
> + }
> +
> + /** Returns an array of test files with suffix .jdo, .orm
> or .jdoquery. */
> + public File[] getMetadataFiles() {
> + return (File[])metadataFiles.toArray(new File
> [metadataFiles.size()]);
> + }
> +
> + }
> +
> + /** */
> + private static String[] checkMetadataSystemProperty() {
> + String[] ret = null;
> + String metadata = System.getProperty(METADATA_PROP);
> + if ((metadata != null) && (metadata.length() > 0)) {
> + List entries = new ArrayList();
> + StringTokenizer st = new StringTokenizer(metadata,
> DELIM);
> + while (st.hasMoreTokens()) {
> + entries.add(st.nextToken());
> + }
> + ret = (String[])entries.toArray(new String[entries.size
> ()]);
> + }
> + return ret;
> + }
> +
> + /** */
> + public static void main(String args[]) {
> + String[] fromProp = checkMetadataSystemProperty();
> + if ((args.length == 0) && (fromProp == null)) {
> + System.err.println("No commandline arguments and
> system property metadata not defined; nothing to be tested.");
> + } else if ((args.length == 0) && (fromProp != null)) {
> + // use metadata system property
> + args = fromProp;
> + } else if ((args.length != 0) && (fromProp != null)) {
> + System.err.println("Commandline arguments specified
> and system property metadata defined; ignoring system property
> metadata.");
> + }
> + XMLTestUtil xmlTest = new XMLTestUtil();
> + File[] files = new XMLFinder(args).getMetadataFiles();
> + for (int i = 0; i < files.length; i++) {
> + File file = files[i];
> + System.out.print("Checking " + file.getName() + ": ");
> + String messages = xmlTest.checkXML(file, true);
> + messages = (messages == null) ? "OK" :
> AbstractTest.NL + messages;
> + System.out.println(messages);
> + }
> + }
> +}
> +
> Index: project.properties
> ===================================================================
> --- project.properties (Revision 383084)
> +++ project.properties (Arbeitskopie)
> @@ -16,5 +16,9 @@
> maven.junit.sysproperties =
> javax.xml.parsers.DocumentBuilderFactory basedir
>
> javax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.Docume
> ntBuilderFactoryImpl
>
> +xmlapis.jarfile = ${pom.getDependencyPath('xml-apis:xml-apis')}
> +xerces.jarfile = ${pom.getDependencyPath('xerces:xerces')}
> +junit.jarfile = ${pom.getDependencyPath('junit:junit')}
> +
> # Manifest seed file
> maven.jar.manifest = ${basedir}/../JDO20.MF
> Index: maven.xml
> ===================================================================
> --- maven.xml (Revision 383084)
> +++ maven.xml (Arbeitskopie)
> @@ -45,4 +45,26 @@
> </delete>
> </goal>
>
> + <!-- ======== -->
> + <!-- XML test -->
> + <!-- ======== -->
> +
> + <!-- Run XML parser on JDO metadata files (suffix .jdo, .orm
> or .jdoquery). -->
> + <!-- The tool uses the following system
> properties: -->
> + <!-- metadata: a comma separated list of JDO metadata files
> or directories. -->
> + <goal name="xmltest" prereqs="test:compile">
> + <java classname="javax.jdo.util.XMLTestUtil" fork="true">
> + <classpath>
> + <pathelement location="${xmlapis.jarfile}"/>
> + <pathelement location="${xerces.jarfile}"/>
> + <pathelement location="${junit.jarfile}"/>
> + <pathelement location="${maven.build.dir}/classes"/>
> + <pathelement location="${maven.build.dir}/test-
> classes"/>
> + </classpath>
> + <sysproperty key="metadata" value="${metadata}"/>
> + <sysproperty
> key="javax.xml.parsers.DocumentBuilderFactory"
> + value="$
> {javax.xml.parsers.DocumentBuilderFactory}"/>
> + </java>
> + </goal>
> +
> </project>
> Index: project.xml
> ===================================================================
> --- project.xml (Revision 383084)
> +++ project.xml (Arbeitskopie)
> @@ -42,14 +42,19 @@
> </dependency>
> <dependency>
> <groupId>xerces</groupId>
> - <artifactId>xercesImpl</artifactId>
> - <version>2.7.1</version>
> + <artifactId>xerces</artifactId>
> + <version>2.4.0</version>
> </dependency>
> <dependency>
> - <groupId>xerces</groupId>
> - <artifactId>xmlParserAPIs</artifactId>
> - <version>2.6.2</version>
> + <groupId>xml-apis</groupId>
> + <artifactId>xml-apis</artifactId>
> + <version>1.0.b2</version>
> </dependency>
> + <dependency>
> + <groupId>junit</groupId>
> + <artifactId>junit</artifactId>
> + <version>3.8.1</version>
> + </dependency>
> </dependencies>
> <!-- =================== -->
> <!-- Build Specification -->
> Index: test/schema/Positive99-xsd.jdoquery
> ===================================================================
> --- test/schema/Positive99-xsd.jdoquery (Revision 383084)
> +++ test/schema/Positive99-xsd.jdoquery (Arbeitskopie)
> @@ -1,5 +1,4 @@
> <?xml version="1.0" encoding="UTF-8"?>
> -<!DOCTYPE jdoquery SYSTEM "file:/javax/jdo/jdoquery.dtd">
> <jdoquery xmlns="http://java.sun.com/xml/ns/jdo/jdoquery"
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
> xsi:schemaLocation="http://java.sun.com/xml/ns/jdo/jdoquery
Craig Russell
Architect, Sun Java Enterprise System http://java.sun.com/products/jdo
408 276-5638 mailto:Craig.Russell@sun.com
P.S. A good JDO? O, Gasp!