cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From p...@apache.org
Subject svn commit: r265572 - in /cocoon/branches/BRANCH_2_1_X: ./ legal/ lib/ lib/optional/ src/blocks/validation/ src/blocks/validation/conf/ src/blocks/validation/java/ src/blocks/validation/java/java/ src/blocks/validation/java/java/org/ src/blocks/validat...
Date Wed, 31 Aug 2005 20:18:25 GMT
Author: pier
Date: Wed Aug 31 13:18:11 2005
New Revision: 265572

URL: http://svn.apache.org/viewcvs?rev=265572&view=rev
Log:
Adding Validation block for Validation transformers

Added:
    cocoon/branches/BRANCH_2_1_X/legal/isorelax-20041111.jar.license.txt
    cocoon/branches/BRANCH_2_1_X/lib/optional/isorelax-20041111.jar   (with props)
    cocoon/branches/BRANCH_2_1_X/lib/optional/jing-20030619.jar
      - copied unchanged from r265036, cocoon/branches/BRANCH_2_1_X/tools/lib/jing-20030619.jar
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/conf/
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/JarvTransformer.java
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/JingTransformer.java
    cocoon/branches/BRANCH_2_1_X/src/blocks/validation/samples/
Modified:
    cocoon/branches/BRANCH_2_1_X/blocks.properties
    cocoon/branches/BRANCH_2_1_X/gump.xml
    cocoon/branches/BRANCH_2_1_X/lib/jars.xml

Modified: cocoon/branches/BRANCH_2_1_X/blocks.properties
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/blocks.properties?rev=265572&r1=265571&r2=265572&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/blocks.properties (original)
+++ cocoon/branches/BRANCH_2_1_X/blocks.properties Wed Aug 31 13:18:11 2005
@@ -168,6 +168,7 @@
 #include.block.taglib=false
 #-----[dependency]: "tour" depends on "batik", "fop", "forms", "slop".
 #include.block.tour=false
+#include.block.validation=false
 #-----[dependency]: "webdav" depends on "repository".
 #include.block.webdav=false
 #include.block.xsltal=false

Modified: cocoon/branches/BRANCH_2_1_X/gump.xml
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/gump.xml?rev=265572&r1=265571&r2=265572&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/gump.xml (original)
+++ cocoon/branches/BRANCH_2_1_X/gump.xml Wed Aug 31 13:18:11 2005
@@ -1597,6 +1597,31 @@
     <nag from="Gump &lt;general@gump.apache.org&gt;" to="dev@cocoon.apache.org"/>
   </project>
 
+  <project name="cocoon-block-validation" status="unstable" dir="src/blocks/validation">
+    <package>org.apache.cocoon</package>
+
+    <description>In-pipeline validation of document using JING or JARV</description>
+
+    <ant target="gump-block">
+      <property name="block-name" value="validation"/>
+      <property name="version" value="@@DATE@@"/>
+    </ant>
+
+    <depend project="cocoon" inherit="all"/>
+    <depend project="jing"/>
+    <depend project="isorelax"/>
+
+    <library name="jing"/>
+    <library name="isorelax"/>
+
+    <work nested="tools/anttasks"/>
+    <home nested="build/cocoon-@@DATE@@"/>
+
+    <jar name="blocks/validation-block.jar"/>
+
+    <nag from="Gump &lt;general@gump.apache.org&gt;" to="dev@cocoon.apache.org"/>
+  </project>
+
   <!--
     ********************************************
     ********  COCOON SUPPLIED PROJECTS  ********
@@ -1624,7 +1649,7 @@
   </project>
 
   <project name="jing">
-    <package>com/thaiopensource</package>
+    <package>com.thaiopensource</package>
     <url href="http://www.thaiopensource.com/relaxng/jing.html"/>
     <description>
       Jing performs XML Validation using RelaxNG schemas
@@ -1765,4 +1790,11 @@
     <jar name="lib/optional/wsrp4j-shared-0.3-dev.jar"/>
     <jar name="lib/optional/wsrp4j-consumer-0.3-dev.jar"/>
   </project>
+
+  <project name="isorelax">
+    <url href="http://iso-relax.sourceforge.net/"/>
+    <package>org.iso_relax</package>
+    <jar name="lib/optional/isorelax-20041111.jar"/>
+  </project>
+
 </module>

Added: cocoon/branches/BRANCH_2_1_X/legal/isorelax-20041111.jar.license.txt
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/legal/isorelax-20041111.jar.license.txt?rev=265572&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/legal/isorelax-20041111.jar.license.txt (added)
+++ cocoon/branches/BRANCH_2_1_X/legal/isorelax-20041111.jar.license.txt Wed Aug 31 13:18:11
2005
@@ -0,0 +1,7 @@
+Copyright (c) 2001-2002, SourceForge ISO-RELAX Project (ASAMI Tomoharu, Daisuke Okajima,
Kohsuke Kawaguchi, and MURATA Makoto)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Modified: cocoon/branches/BRANCH_2_1_X/lib/jars.xml
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/lib/jars.xml?rev=265572&r1=265571&r2=265572&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/lib/jars.xml (original)
+++ cocoon/branches/BRANCH_2_1_X/lib/jars.xml Wed Aug 31 13:18:11 2005
@@ -755,15 +755,14 @@
     <homepage>http://castor.codehaus.org/</homepage>
   </file>
 
-  <!-- Currently only used by the build
+  <!-- Build uses this jar from tools/lib/jing-20030619.jar -->
   <file>
     <title>Jing</title>
     <description>RELAX NG validator</description>
-    <used-by>build</used-by>
-    <lib>tools/lib/jing-20030619.jar</lib>
+    <used-by>JARV transformer (validation block) and build</used-by>
+    <lib>optional/jing-20030619.jar</lib>
     <homepage>http://www.thaiopensource.com/relaxng/jing.html</homepage>
   </file>
-  -->
 
   <file>
     <title>Cocoon Serializers Block Encodings</title>
@@ -1276,4 +1275,13 @@
     <lib>optional/wsrp4j-consumer-0.3-dev.jar</lib>
     <homepage>http://ws.apache.org/wsrp4j/</homepage>
   </file>
+
+  <file>
+    <title>ISO-RELAX Validation API</title>
+    <description>Validate documents in a provider-independent fashion.</description>
+    <used-by>JARV transformer (validation block)</used-by>
+    <lib>optional/isorelax-20041111.jar</lib>
+    <homepage>http://iso-relax.sourceforge.net/</homepage>
+  </file>
+
 </jars>

Added: cocoon/branches/BRANCH_2_1_X/lib/optional/isorelax-20041111.jar
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/lib/optional/isorelax-20041111.jar?rev=265572&view=auto
==============================================================================
Binary file - no diff available.

Propchange: cocoon/branches/BRANCH_2_1_X/lib/optional/isorelax-20041111.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/JarvTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/JarvTransformer.java?rev=265572&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/JarvTransformer.java
(added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/JarvTransformer.java
Wed Aug 31 13:18:11 2005
@@ -0,0 +1,282 @@
+/*
+ * Copyright 1999-2005 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 org.apache.cocoon.transformation;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.caching.CacheableProcessingComponent;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.xml.ContentHandlerWrapper;
+import org.apache.cocoon.xml.XMLConsumer;
+import org.apache.cocoon.xml.XMLMulticaster;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceValidity;
+import org.apache.excalibur.source.impl.validity.AggregatedValidity;
+import org.apache.excalibur.store.Store;
+import org.apache.excalibur.xml.EntityResolver;
+import org.iso_relax.verifier.Schema;
+import org.iso_relax.verifier.Verifier;
+import org.iso_relax.verifier.VerifierConfigurationException;
+import org.iso_relax.verifier.VerifierFactory;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * <p>TODO: ...</p>
+ *
+ * @author <a href="mailto:pier@betaversion.org">Pier Fumagalli</a>
+ */
+public class JarvTransformer extends AbstractTransformer
+implements Configurable, Serviceable, Disposable,
+           CacheableProcessingComponent, ErrorHandler, EntityResolver {
+    
+    /** <p>The class name of the MSV verifier factory.</p> */
+    private static final String MSV = "com.sun.msv.verifier.jarv.TheFactoryImpl";
+
+    /* VARIABLES CREATED BY SERVICE() OR CONFIGURE() AND DESTROYED BY DISPOSE() */
+
+    /** <p>The {@link ServiceManager} associated with this instance.</p> */
+    private ServiceManager serviceManager = null;
+    /** <p>Cocoon's global {@link EntityResolver} for catalog resolution.</p>
*/
+    private EntityResolver entityResolver = null;
+    /** <p>Cocoon's global temporary cache {@link Store} for parsed schemas.</p>
*/
+    private Store transientStore = null;
+    /** <p>The {@link VerifierFactory} configured for this instance.</p> */
+    private VerifierFactory verifierFactory = null; 
+    /** <p>The language of the configured {@link VerifierFactory}.</p> */
+    private String verifierLanguage = null;
+    /** <p>A {@link String} for unique IDs stored into caches.</p> */
+    private String uniqueIdentifier = null;
+    /** <p>A flag indicating whether caching is enabled or not.</p> */
+    private boolean cachingEnabled = true;
+
+    /* TEMPORARY VARIABLES SET BY SETUP() AND RESET BY RECYCLE() */
+
+    /** <p>The {@link InputSource} associated with the current schema.</p> */
+    private InputSource inputSource = null;
+    /** <p>The {@link SourceValidity} associated with the schema.</p> */
+    private AggregatedValidity sourceValidity = null;
+    /** <p>The {@link SourceResolver} to use for resolving URIs.</p> */
+    private SourceResolver sourceResolver = null;
+    /** <p>The {@link XMLConsumer} of the validator.</p> */
+    private XMLConsumer validationHandler = null;
+
+
+    /* =========================================================================== */
+    /* COMPONENT LIFECYCLE METHODS: CONFIGURE(), SERVICE() AND DISPOSE()           */
+    /* =========================================================================== */
+
+    public void service(ServiceManager manager)
+    throws ServiceException {
+        this.serviceManager = manager;
+        this.transientStore = (Store) manager.lookup(Store.TRANSIENT_STORE);
+        this.entityResolver = (EntityResolver) manager.lookup(EntityResolver.ROLE);
+    }
+
+    public void configure(Configuration configuration)
+    throws ConfigurationException {
+        boolean c = configuration.getChild("enable-caching").getValueAsBoolean(true);
+        String l = configuration.getChild("verifier-language").getValue(null);
+        String x = configuration.getChild("verifier-factory").getValue(MSV);
+        try {
+            /* Creation of the verifier on a language-or-factory basis */
+            if (l != null) { 
+                this.verifierFactory = VerifierFactory.newInstance(l);
+                this.verifierLanguage = l;
+            } else {
+                Class clazz = Class.forName(x);
+                this.verifierFactory = (VerifierFactory) clazz.newInstance();
+                this.verifierLanguage = "java:" + x;
+            }
+
+            /* Normal stuff for all factories */ 
+            this.verifierFactory.setEntityResolver(this);
+            this.cachingEnabled = c;
+        } catch (Exception exception) {
+            String message = "Unable to configure verifier for language " + l;
+            throw new ConfigurationException(message, configuration, exception);
+        }
+    }
+
+    public void dispose() {
+        this.serviceManager.release(this.entityResolver);
+        this.serviceManager.release(this.transientStore);
+        this.serviceManager = null;
+        this.verifierFactory = null;
+        this.verifierLanguage = null;
+        this.cachingEnabled = true;
+    }
+
+
+    /* =========================================================================== */
+    /* REQUEST LIFECYCLE METHODS: SETUP() AND RECYCLE()                            */
+    /* =========================================================================== */
+
+    public void setup(SourceResolver resolver, Map objectModel, String source,
+                      Parameters parameters)
+    throws ProcessingException, SAXException, IOException {
+        this.sourceValidity = new AggregatedValidity();
+        this.sourceResolver = resolver;
+        this.inputSource = this.resolveEntity(null, source);
+        
+        try {
+            /* This will throw an NPE, unless you're using Sun's MSV */
+            Verifier verifier = this.schema().newVerifier();
+            ContentHandler handler = verifier.getVerifierHandler();
+            this.validationHandler = new ContentHandlerWrapper(handler);
+        } catch (NullPointerException exception) {
+            String message = "Apparently JARV does not work with JING";
+            throw new ProcessingException(message, exception);
+        } catch (VerifierConfigurationException exception) {
+            String message = "Unable to retrieve validation handler for " + source;
+            throw new ProcessingException(message, exception);
+        }
+    }
+
+    public void setConsumer(XMLConsumer consumer) {
+        super.setConsumer(new XMLMulticaster(this.validationHandler, consumer));
+    }
+
+    public Serializable getKey() {
+        if (this.uniqueIdentifier == null) {
+            StringBuffer buffer = new StringBuffer();
+            buffer.append(this.getClass().getName());
+            buffer.append(':');
+            buffer.append(this.verifierLanguage);
+            buffer.append(':');
+            buffer.append(this.inputSource.getSystemId());
+            this.uniqueIdentifier = buffer.toString();
+        }
+        return this.uniqueIdentifier;
+    }
+
+    public SourceValidity getValidity() {
+        return this.sourceValidity;
+    }
+
+    public void recycle() {
+        this.validationHandler = null;
+        this.sourceResolver = null;
+        this.sourceValidity = null;
+        this.inputSource = null;
+
+        super.recycle();
+    }
+
+    /* =========================================================================== */
+    /* SAX2 ERROR HANDLER INTERFACE IMPLEMENTATION                                 */
+    /* =========================================================================== */
+
+    public void warning(SAXParseException exception)
+    throws SAXException {
+        throw exception;
+    }
+
+    public void error(SAXParseException exception)
+    throws SAXException {
+        throw exception;
+    }
+
+    public void fatalError(SAXParseException exception)
+    throws SAXException {
+        throw exception;
+    }
+
+    /* =========================================================================== */
+    /* SAX2 ENTITY RESOLVER INTERFACE IMPLEMENTATION                               */
+    /* =========================================================================== */
+
+    public InputSource resolveEntity(String publicId, String systemId)
+    throws SAXException, IOException {
+        if (this.sourceResolver == null) throw new IllegalStateException();
+
+        /* Try to resolve the public id if we don't have a system id */
+        if (systemId == null) {
+            InputSource source = this.entityResolver.resolveEntity(publicId, null);
+            if ((source == null) || (source.getSystemId() == null)) {
+                throw new IOException("Can't resolve \"" + publicId + "\"");
+            } else {
+                systemId = source.getSystemId();
+            }
+        }
+
+        /* Use Cocoon's SourceResolver to resolve the system id */
+        Source source = this.sourceResolver.resolveURI(systemId);
+        try {
+            this.sourceValidity.add(source.getValidity());
+            InputSource inputSource = new InputSource();
+            inputSource.setSystemId(source.getURI());
+            inputSource.setPublicId(publicId);
+            inputSource.setByteStream(source.getInputStream());
+            return inputSource;
+        } finally {
+            this.sourceResolver.release(source);
+        }
+    }
+
+
+    /* =========================================================================== */
+    /* CALL JARV TO ACCESS A CACHED OR FRESHLY PARSED SCHEMA INSTANCE              */
+    /* =========================================================================== */
+
+    private Schema schema()
+    throws SAXException, IOException, VerifierConfigurationException {
+        if (this.cachingEnabled) {
+            Entry entry = (Entry) this.transientStore.get(this.getKey());
+            if ((entry == null) || (entry.expired())) {
+                Schema schema = this.verifierFactory.compileSchema(this.inputSource);
+                entry = new Entry(schema, this.getValidity());
+                this.transientStore.store(this.getKey(), entry);
+            }
+            return entry.schema;
+        }
+        
+        return this.verifierFactory.compileSchema(this.inputSource);
+    }
+
+    /* =========================================================================== */
+    /* INNER CLASSES USED TO WRAP JARV SCHEMA AND VALIDITY IN CACHES               */
+    /* =========================================================================== */
+
+    private static final class Entry {
+
+        private final Schema schema;
+        private final SourceValidity validity;
+        
+        private Entry(Schema schema, SourceValidity validity) {
+            this.validity = validity;
+            this.schema = schema;
+        }
+        
+        private boolean expired() {
+            return (this.validity.isValid() != SourceValidity.VALID);
+        }
+    }
+}

Added: cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/JingTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/JingTransformer.java?rev=265572&view=auto
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/JingTransformer.java
(added)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/validation/java/java/org/apache/cocoon/transformation/JingTransformer.java
Wed Aug 31 13:18:11 2005
@@ -0,0 +1,271 @@
+/*
+ * Copyright 1999-2005 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 org.apache.cocoon.transformation;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.caching.CacheableProcessingComponent;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.xml.ContentHandlerWrapper;
+import org.apache.cocoon.xml.XMLConsumer;
+import org.apache.cocoon.xml.XMLMulticaster;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceValidity;
+import org.apache.excalibur.source.impl.validity.AggregatedValidity;
+import org.apache.excalibur.store.Store;
+import org.apache.excalibur.xml.EntityResolver;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import com.thaiopensource.util.PropertyMap;
+import com.thaiopensource.util.PropertyMapBuilder;
+import com.thaiopensource.validate.IncorrectSchemaException;
+import com.thaiopensource.validate.Schema;
+import com.thaiopensource.validate.SchemaReader;
+import com.thaiopensource.validate.ValidateProperty;
+import com.thaiopensource.validate.Validator;
+import com.thaiopensource.validate.rng.SAXSchemaReader;
+import com.thaiopensource.xml.sax.Sax2XMLReaderCreator;
+
+/**
+ * <p>TODO: ...</p>
+ *
+ * @author <a href="mailto:pier@betaversion.org">Pier Fumagalli</a>
+ */
+public class JingTransformer extends AbstractTransformer
+implements Configurable, Serviceable, Disposable,
+           CacheableProcessingComponent, ErrorHandler, EntityResolver {
+
+    /** <p>The {@link SchemaReader} to use for reading RNG schemas.</p> */
+    private final SchemaReader schemaReader = SAXSchemaReader.getInstance();
+
+    /* VARIABLES CREATED BY SERVICE() OR CONFIGURE() AND DESTROYED BY DISPOSE() */
+
+    /** <p>The {@link ServiceManager} associated with this instance.</p> */
+    private ServiceManager serviceManager = null;
+    /** <p>Cocoon's global {@link EntityResolver} for catalog resolution.</p>
*/
+    private EntityResolver entityResolver = null;
+    /** <p>Cocoon's global temporary cache {@link Store} for parsed schemas.</p>
*/
+    private Store transientStore = null;
+    /** <p>The {@link PropertyMap} to use with JING's factories.</p> */
+    private PropertyMap validatorProperties = null;
+    /** <p>A {@link String} for unique IDs stored into caches.</p> */
+    private String uniqueIdentifier = null;
+    /** <p>A flag indicating whether caching is enabled or not.</p> */
+    private boolean cachingEnabled = true;
+
+    /* TEMPORARY VARIABLES SET BY SETUP() AND RESET BY RECYCLE() */
+
+    /** <p>The {@link InputSource} associated with the current schema.</p> */
+    private InputSource inputSource = null;
+    /** <p>The {@link SourceValidity} associated with the schema.</p> */
+    private AggregatedValidity sourceValidity = null;
+    /** <p>The {@link SourceResolver} to use for resolving URIs.</p> */
+    private SourceResolver sourceResolver = null;
+    /** <p>The {@link XMLConsumer} of the validator.</p> */
+    private XMLConsumer validationHandler = null;
+
+
+    /* =========================================================================== */
+    /* COMPONENT LIFECYCLE METHODS: CONFIGURE(), SERVICE() AND DISPOSE()           */
+    /* =========================================================================== */
+
+    public void service(ServiceManager manager)
+    throws ServiceException {
+        this.serviceManager = manager;
+        this.transientStore = (Store) manager.lookup(Store.TRANSIENT_STORE);
+        this.entityResolver = (EntityResolver) manager.lookup(EntityResolver.ROLE);
+
+        PropertyMapBuilder builder = new PropertyMapBuilder();
+        Sax2XMLReaderCreator creator = new Sax2XMLReaderCreator();
+        ValidateProperty.ENTITY_RESOLVER.put(builder, this);
+        ValidateProperty.ERROR_HANDLER.put(builder, this);
+        ValidateProperty.XML_READER_CREATOR.put(builder, creator);
+        this.validatorProperties = builder.toPropertyMap();
+    }
+
+    public void configure(Configuration configuration)
+    throws ConfigurationException {
+        configuration = configuration.getChild("enable-caching");
+        this.cachingEnabled = configuration.getValueAsBoolean(true);
+    }
+
+    public void dispose() {
+        this.serviceManager.release(this.entityResolver);
+        this.serviceManager.release(this.transientStore);
+        this.serviceManager = null;
+        this.validatorProperties = null;
+        this.cachingEnabled = true;
+    }
+
+
+    /* =========================================================================== */
+    /* REQUEST LIFECYCLE METHODS: SETUP() AND RECYCLE()                            */
+    /* =========================================================================== */
+
+    public void setup(SourceResolver resolver, Map objectModel, String source,
+                      Parameters parameters)
+    throws ProcessingException, SAXException, IOException {
+        this.sourceValidity = new AggregatedValidity();
+        this.sourceResolver = resolver;
+        this.inputSource = this.resolveEntity(null, source);
+        
+        ContentHandler handler = this.newValidator().getContentHandler();
+        this.validationHandler = new ContentHandlerWrapper(handler);
+    }
+
+    public void setConsumer(XMLConsumer consumer) {
+        super.setConsumer(new XMLMulticaster(this.validationHandler, consumer));
+    }
+
+    public Serializable getKey() {
+        if (this.uniqueIdentifier == null) {
+            StringBuffer buffer = new StringBuffer();
+            buffer.append(this.getClass().getName());
+            buffer.append(':');
+            buffer.append(this.inputSource.getSystemId());
+            this.uniqueIdentifier = buffer.toString();
+        }
+        return this.uniqueIdentifier;
+    }
+
+    public SourceValidity getValidity() {
+        return this.sourceValidity;
+    }
+
+    public void recycle() {
+        this.validationHandler = null;
+        this.sourceResolver = null;
+        this.sourceValidity = null;
+        this.inputSource = null;
+
+        super.recycle();
+    }
+
+    /* =========================================================================== */
+    /* SAX2 ERROR HANDLER INTERFACE IMPLEMENTATION                                 */
+    /* =========================================================================== */
+
+    public void warning(SAXParseException exception)
+    throws SAXException {
+        throw exception;
+    }
+
+    public void error(SAXParseException exception)
+    throws SAXException {
+        throw exception;
+    }
+
+    public void fatalError(SAXParseException exception)
+    throws SAXException {
+        throw exception;
+    }
+
+    /* =========================================================================== */
+    /* SAX2 ENTITY RESOLVER INTERFACE IMPLEMENTATION                               */
+    /* =========================================================================== */
+
+    public InputSource resolveEntity(String publicId, String systemId)
+    throws SAXException, IOException {
+        if (this.sourceResolver == null) throw new IllegalStateException();
+
+        /* Try to resolve the public id if we don't have a system id */
+        if (systemId == null) {
+            InputSource source = this.entityResolver.resolveEntity(publicId, null);
+            if ((source == null) || (source.getSystemId() == null)) {
+                throw new IOException("Can't resolve \"" + publicId + "\"");
+            } else {
+                systemId = source.getSystemId();
+            }
+        }
+
+        /* Use Cocoon's SourceResolver to resolve the system id */
+        Source source = this.sourceResolver.resolveURI(systemId);
+        try {
+            this.sourceValidity.add(source.getValidity());
+            InputSource inputSource = new InputSource();
+            inputSource.setSystemId(source.getURI());
+            inputSource.setPublicId(publicId);
+            inputSource.setByteStream(source.getInputStream());
+            return inputSource;
+        } finally {
+            this.sourceResolver.release(source);
+        }
+    }
+
+
+    /* =========================================================================== */
+    /* CALL JARV TO ACCESS A CACHED OR FRESHLY PARSED SCHEMA INSTANCE              */
+    /* =========================================================================== */
+
+    private Validator newValidator()
+    throws SAXException, IOException, ProcessingException {
+        if (this.cachingEnabled) {
+            Entry entry = (Entry) this.transientStore.get(this.getKey());
+            if ((entry == null) || (entry.expired())) {
+                Schema schema = this.newSchema();
+                entry = new Entry(schema, this.getValidity());
+                this.transientStore.store(this.getKey(), entry);
+            }
+            return entry.schema.createValidator(this.validatorProperties);
+        }
+        return this.newSchema().createValidator(this.validatorProperties);
+    }
+
+    private Schema newSchema()
+    throws SAXException, IOException, ProcessingException {
+        try {
+            return this.schemaReader.createSchema(this.inputSource,
+                                                  this.validatorProperties);
+        } catch (IncorrectSchemaException exception) {
+            String message = "Incorrect schema " + this.inputSource.getSystemId();
+            throw new ProcessingException(message, exception);
+        }
+    }
+
+    /* =========================================================================== */
+    /* INNER CLASSES USED TO WRAP JARV SCHEMA AND VALIDITY IN CACHES               */
+    /* =========================================================================== */
+
+    private static final class Entry {
+
+        private final Schema schema;
+        private final SourceValidity validity;
+        
+        private Entry(Schema schema, SourceValidity validity) {
+            this.validity = validity;
+            this.schema = schema;
+        }
+        
+        private boolean expired() {
+            return (this.validity.isValid() != SourceValidity.VALID);
+        }
+    }
+}



Mime
View raw message