You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by pi...@apache.org on 2005/09/09 14:28:14 UTC

svn commit: r279753 - in /cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation: Validator.java impl/AutomaticSchemaParser.java

Author: pier
Date: Fri Sep  9 05:28:10 2005
New Revision: 279753

URL: http://svn.apache.org/viewcvs?rev=279753&view=rev
Log:
Implementation of an automatic schema parser (automatically detect grammars)

Added:
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation/impl/AutomaticSchemaParser.java
Modified:
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation/Validator.java

Modified: cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation/Validator.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation/Validator.java?rev=279753&r1=279752&r2=279753&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation/Validator.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation/Validator.java Fri Sep  9 05:28:10 2005
@@ -32,6 +32,12 @@
     /** <p>Role name to use when this component is accessed via a selector.</p> */
     public static final String ROLE = Validator.class.getName();
 
+    /** 
+     * <p>An grammar identifer specifying tht the {@link SchemaParser} can
+     * automatically detect the grammar while parsing.</p>
+     */
+    public static final String GRAMMAR_AUTOMATIC = "http://apache.org/cocoon/validation/grammars/automatic/1.0";
+
     /** <p>The <a href="http://www.relaxng.org/">RELAX NG</a/> grammar identifer.</p> */
     public static final String GRAMMAR_RELAX_NG = "http://relaxng.org/ns/structure/0.9";
     /** <p>The <a href="http://www.xml.gr.jp/relax">RELAX CORE</a/> grammar identifer.</p> */

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation/impl/AutomaticSchemaParser.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation/impl/AutomaticSchemaParser.java?rev=279753&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation/impl/AutomaticSchemaParser.java (added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/org/apache/cocoon/components/validation/impl/AutomaticSchemaParser.java Fri Sep  9 05:28:10 2005
@@ -0,0 +1,182 @@
+/* ========================================================================== *
+ * Copyright (C) 2004-2005 Pier Fumagalli <http://www.betaversion.org/~pier/> *
+ *                            All rights reserved.                            *
+ * ========================================================================== *
+ *                                                                            *
+ * 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 org.apache.cocoon.components.validation.impl;
+
+import java.io.IOException;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.cocoon.components.validation.Schema;
+import org.apache.cocoon.components.validation.SchemaParser;
+import org.apache.cocoon.components.validation.Validator;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.xml.sax.NOPContentHandler;
+import org.apache.excalibur.xml.sax.SAXParser;
+import org.apache.excalibur.xml.sax.XMLizable;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * <p>The {@link AutomaticSchemaParser} is a {@link SchemaParser} implementation
+ * automatically detecting the grammar used by the supplied grammar file.</p>
+ * 
+ * <p>Although detection might not be perfect, the detection algorithm implemented
+ *  in the {@link #parseSchema(String)} method should be usable enough for normal
+ *  operation.</p> 
+ *
+ * @author <a href="mailto:pier@betaversion.org">Pier Fumagalli</a>
+ */
+public class AutomaticSchemaParser extends CachingSchemaParser {
+
+    /** <p>The grammars identified by this {@link SchemaParser}.</p> */
+    private static final String GRAMMARS [] = 
+                                        new String[] { Validator.GRAMMAR_AUTOMATIC }; 
+
+    /** <p>The {@link Validator} providing access to grammar parsers.</p> */
+    protected Validator validator = null;
+    
+    /**
+     * <p>Initialize this component instance.</p>
+     * 
+     * <p>A this point component resolution will happen.</p>
+     */
+    public void initialize()
+    throws Exception {
+        super.initialize();
+        this.validator = (Validator) this.serviceManager.lookup(Validator.ROLE);
+    }
+
+    /**
+     * <p>Dispose this component instance.</p>
+     */
+    public void dispose() {
+        try {
+            super.dispose();
+        } finally {
+            if (this.validator != null) this.serviceManager.release(this.validator);
+        }
+    }
+
+    /**
+     * <p>Freshly parsed a brand new {@link Schema} instance.</p>
+     * 
+     * <p>This method will first try to identify the grammar used in the schema from
+     * the namespace of the root element, or (in case of a {@link SAXParseException})
+     * it will assume it to be an {@link Validator#GRAMMAR_XML_DTD XML DTD}.</p>
+     * 
+     * <p>It will then return the schema parsed by the appropriate schema parser
+     * registered in the {@link Validator}, so that it can be cached again.</p>
+     * 
+     * <p>Note that the implementation of the caching algorithm in the
+     * {@link CachingSchemaParser} will create an extra entry in the current
+     * configured {@link CachingSchemaParser#transientStore Store}, but it will
+     * map simply a new name with the same {@link Schema} instance (so, there
+     * shouldn't be major memory problems here).</p>
+     */
+    public Schema parseSchema(String uri)
+    throws SAXException, IOException {
+        SAXParser xmlParser = null;
+        Source source = null;
+        String grammar = null;
+
+        try {
+            ContentHandler handler = new DetectionHandler();
+
+            source = this.sourceResolver.resolveURI(uri);
+            
+            if (source instanceof XMLizable) {
+                XMLizable xmlizable = (XMLizable) source;
+                xmlizable.toSAX(handler);
+            } else {
+                xmlParser = (SAXParser) this.serviceManager.lookup((SAXParser.ROLE)); 
+                InputSource input = new InputSource();
+                input.setSystemId(source.getURI());
+                input.setByteStream(source.getInputStream());
+                xmlParser.parse(input, handler);
+            }
+        } catch (DetectionException exception) {
+            grammar = exception.grammar;
+        } catch (SAXParseException exception) {
+            grammar = Validator.GRAMMAR_XML_DTD;
+        } catch (ServiceException exception) {
+            throw new SAXException("Unable to locate XML parser", exception);
+        } finally {
+            if (source != null) this.sourceResolver.release(source);
+            if (xmlParser != null) this.serviceManager.release(xmlParser);
+        }
+        
+        if (grammar == null) throw new SAXException("Unable to detect grammar");
+        
+        SchemaParser schemaParser = null;
+        try {
+            schemaParser = (SchemaParser) this.validator.select(grammar);
+            return schemaParser.getSchema(uri);
+        } catch (ServiceException exception) {
+            throw new SAXException("Unsupported grammar " + grammar, exception);
+        } finally {
+            if (schemaParser != null) this.validator.release(schemaParser);
+        }
+    }
+
+    /**
+     * <p>This {@link SchemaParser} supports the {@link Validator#GRAMMAR_AUTOMATIC}
+     * grammar.</p>
+     */
+    public String[] getSupportedGrammars() {
+        return GRAMMARS;
+    }
+
+    /**
+     * <p>A simple implementation of a {@link ContentHandler} detecting schemas
+     * based on the namespace of the root element.</p>
+     */
+    private static final class DetectionHandler extends NOPContentHandler {
+        
+        /**
+         * <p>Detect the namespace of the root element and always throw a
+         * {@link SAXException} or a {@link DetectionException}.</p>
+         */
+        public void startElement(String ns, String lnam, String qnam, Attributes a)
+        throws SAXException {
+            if ((Validator.GRAMMAR_RELAX_CORE.equals(ns)) || 
+                (Validator.GRAMMAR_RELAX_NG.equals(ns)) ||
+                (Validator.GRAMMAR_RELAX_NS.equals(ns)) ||
+                (Validator.GRAMMAR_TREX.equals(ns)) ||
+                (Validator.GRAMMAR_XML_SCHEMA.equals(ns))) {
+                throw new DetectionException(ns);
+            }
+            throw new SAXException("Unknown validation grammar");
+        }
+    }
+
+    /**
+     * <p>An exception thrown by {@link DetectionHandler} representing  simple implementation of a {@link ContentHandler} detecting schemas
+     * based on the namespace of the root element.</p>
+     */
+    private static final class DetectionException extends SAXException {
+
+        private final String grammar;
+
+        private DetectionException(String grammar) {
+            super ("Grammar detected: " + grammar);
+            this.grammar = grammar;
+        }
+    }
+}