| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.jing; |
| |
| import java.io.IOException; |
| import java.util.Stack; |
| |
| import org.apache.cocoon.components.validation.impl.ValidationResolver; |
| import org.apache.excalibur.source.SourceResolver; |
| import org.xml.sax.EntityResolver; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.XMLReader; |
| |
| import com.thaiopensource.xml.sax.XMLReaderCreator; |
| |
| /** |
| * <p>A simple resolver used when parsing RELAX NG schemas through the use of |
| * <a href="http://www.thaiopensource.com/relaxng/jing.html">JING</a>.</p> |
| * |
| * <p>This is not thread safe and not recyclable. Once used, it <b>must</b> be |
| * garbage collected.</p> |
| * |
| */ |
| public class JingResolver extends ValidationResolver implements XMLReaderCreator { |
| |
| /** <p>The current {@link Stack} of {@link InputSource}s being parsed. </p> */ |
| private final Stack parsedSourceStack = new Stack(); |
| |
| /** |
| * <p>Create a new {@link JingResolver} instance.</p> |
| */ |
| public JingResolver(SourceResolver sourceResolver, |
| EntityResolver entityResolver) { |
| super(sourceResolver, entityResolver); |
| this.parsedSourceStack.push(null); |
| } |
| |
| /** |
| * <p>Push a new {@link InputSource} in the stack used for relative URIs |
| * resolution.</p> |
| */ |
| public void pushInputSource(InputSource inputSource) { |
| this.parsedSourceStack.push(inputSource); |
| } |
| |
| /** |
| * <p>Pop the last {@link InputSource} from the stack used for relative URIs |
| * resolution.</p> |
| */ |
| public InputSource popInputSource() { |
| if (this.parsedSourceStack.empty()) return null; |
| return (InputSource) this.parsedSourceStack.pop(); |
| } |
| |
| /** |
| * <p>Return the {@link PropertyMap} associated with this instance and usable |
| * by <a href="http://www.thaiopensource.com/relaxng/jing.html">JING</a>.</p> |
| */ |
| //public PropertyMap getProperties() { |
| // return this.validatorProperties; |
| //} |
| |
| /* =========================================================================== */ |
| /* SAX2 ENTITY RESOLVER INTERFACE IMPLEMENTATION */ |
| /* =========================================================================== */ |
| |
| /** |
| * <p>Resolve an {@link InputSource} from a public ID and/or a system ID.</p> |
| * |
| * <p>This method can be called only while a schema is being parsed and will |
| * resolve URIs against a dynamic {@link Stack} of {@link InputSource}s.</p> |
| * |
| * <p>Since <a href="http://www.thaiopensource.com/relaxng/jing.html">JING</a> |
| * doesn't offer a complete URI resolution contract, a {@link Stack} is kept |
| * for all the sources parsed while reading a schema. Keeping in mind that the |
| * last {@link InputSource} pushed in the {@link Stack} can be considered to be |
| * the "base URI" for the current resolution, full relative resolution of system |
| * IDs can be achieved this way.<p> |
| * |
| * <p>Note that this method of resolving URIs by keeping a {@link Stack} of |
| * processed URIs is a <i>sort of a hack</i>, but it mimics the internal state |
| * of <a href="http://www.thaiopensource.com/relaxng/jing.html">JING</a> itself: |
| * if URI resolution fails, the {@link Stack} analysis is the first part to |
| * look at.</p> |
| * |
| * <p>Resolution will use the {@link EntityResolver} specified at construction |
| * to resolve public IDs, and then the {@link SourceResolver} again specified at |
| * construction to resolve the system IDs and to access the underlying byte |
| * streams of the entities to be parsed.</p> |
| * |
| * @param publicId the public ID of the entity to resolve. |
| * @param systemId the system ID of the entity to resolve. |
| * @return a <b>non-null</b> {@link InputSource} instance. |
| * @throws IOException if an I/O error occurred resolving the entity. |
| * @throws SAXException if an XML error occurred resolving the entity. |
| */ |
| public InputSource resolveEntity(String publicId, String systemId) |
| throws SAXException, IOException { |
| InputSource source = (InputSource) this.parsedSourceStack.peek(); |
| if (source == null) { |
| return super.resolveEntity(publicId, systemId); |
| } else { |
| return super.resolveEntity(source.getSystemId(), publicId, systemId); |
| } |
| } |
| |
| |
| /* =========================================================================== */ |
| /* CALL JING TO ACCESS A CACHED OR FRESHLY PARSED SCHEMA INSTANCE */ |
| /* =========================================================================== */ |
| |
| /** |
| * <p>Create an {@link XMLReader} instance that can be used by |
| * <a href="http://www.thaiopensource.com/relaxng/jing.html">JING</a> for |
| * parsing schemas.</p> |
| * |
| * <p>The returned {@link XMLReader} will keep track of populating/clearing the |
| * {@link Stack} of {@link InputSource}s kept for URI resolution as explained |
| * in the description of the {@link #resolveEntity(String, String)} method.</p> |
| * |
| * @see JingReader |
| * @return a <b>non-null</b> {@link XMLReader} instance. |
| * @throws SAXException if an error occurrent creating the {@link XMLReader}. |
| */ |
| public XMLReader createXMLReader() |
| throws SAXException { |
| return new JingReader(this); |
| } |
| } |