001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.components.validation.jing;
018:
019: import java.io.IOException;
020: import java.util.Stack;
021:
022: import org.apache.cocoon.components.validation.impl.ValidationResolver;
023: import org.apache.excalibur.source.SourceResolver;
024: import org.xml.sax.EntityResolver;
025: import org.xml.sax.InputSource;
026: import org.xml.sax.SAXException;
027: import org.xml.sax.XMLReader;
028:
029: import com.thaiopensource.xml.sax.XMLReaderCreator;
030:
031: /**
032: * <p>A simple resolver used when parsing RELAX NG schemas through the use of
033: * <a href="http://www.thaiopensource.com/relaxng/jing.html">JING</a>.</p>
034: *
035: * <p>This is not thread safe and not recyclable. Once used, it <b>must</b> be
036: * garbage collected.</p>
037: *
038: */
039: public class JingResolver extends ValidationResolver implements
040: XMLReaderCreator {
041:
042: /** <p>The current {@link Stack} of {@link InputSource}s being parsed. </p> */
043: private final Stack parsedSourceStack = new Stack();
044:
045: /**
046: * <p>Create a new {@link JingResolver} instance.</p>
047: */
048: public JingResolver(SourceResolver sourceResolver,
049: EntityResolver entityResolver) {
050: super (sourceResolver, entityResolver);
051: this .parsedSourceStack.push(null);
052: }
053:
054: /**
055: * <p>Push a new {@link InputSource} in the stack used for relative URIs
056: * resolution.</p>
057: */
058: public void pushInputSource(InputSource inputSource) {
059: this .parsedSourceStack.push(inputSource);
060: }
061:
062: /**
063: * <p>Pop the last {@link InputSource} from the stack used for relative URIs
064: * resolution.</p>
065: */
066: public InputSource popInputSource() {
067: if (this .parsedSourceStack.empty())
068: return null;
069: return (InputSource) this .parsedSourceStack.pop();
070: }
071:
072: /**
073: * <p>Return the {@link PropertyMap} associated with this instance and usable
074: * by <a href="http://www.thaiopensource.com/relaxng/jing.html">JING</a>.</p>
075: */
076: //public PropertyMap getProperties() {
077: // return this.validatorProperties;
078: //}
079: /* =========================================================================== */
080: /* SAX2 ENTITY RESOLVER INTERFACE IMPLEMENTATION */
081: /* =========================================================================== */
082:
083: /**
084: * <p>Resolve an {@link InputSource} from a public ID and/or a system ID.</p>
085: *
086: * <p>This method can be called only while a schema is being parsed and will
087: * resolve URIs against a dynamic {@link Stack} of {@link InputSource}s.</p>
088: *
089: * <p>Since <a href="http://www.thaiopensource.com/relaxng/jing.html">JING</a>
090: * doesn't offer a complete URI resolution contract, a {@link Stack} is kept
091: * for all the sources parsed while reading a schema. Keeping in mind that the
092: * last {@link InputSource} pushed in the {@link Stack} can be considered to be
093: * the "base URI" for the current resolution, full relative resolution of system
094: * IDs can be achieved this way.<p>
095: *
096: * <p>Note that this method of resolving URIs by keeping a {@link Stack} of
097: * processed URIs is a <i>sort of a hack</i>, but it mimics the internal state
098: * of <a href="http://www.thaiopensource.com/relaxng/jing.html">JING</a> itself:
099: * if URI resolution fails, the {@link Stack} analysis is the first part to
100: * look at.</p>
101: *
102: * <p>Resolution will use the {@link EntityResolver} specified at construction
103: * to resolve public IDs, and then the {@link SourceResolver} again specified at
104: * construction to resolve the system IDs and to access the underlying byte
105: * streams of the entities to be parsed.</p>
106: *
107: * @param publicId the public ID of the entity to resolve.
108: * @param systemId the system ID of the entity to resolve.
109: * @return a <b>non-null</b> {@link InputSource} instance.
110: * @throws IOException if an I/O error occurred resolving the entity.
111: * @throws SAXException if an XML error occurred resolving the entity.
112: */
113: public InputSource resolveEntity(String publicId, String systemId)
114: throws SAXException, IOException {
115: InputSource source = (InputSource) this .parsedSourceStack
116: .peek();
117: if (source == null) {
118: return super .resolveEntity(publicId, systemId);
119: } else {
120: return super .resolveEntity(source.getSystemId(), publicId,
121: systemId);
122: }
123: }
124:
125: /* =========================================================================== */
126: /* CALL JING TO ACCESS A CACHED OR FRESHLY PARSED SCHEMA INSTANCE */
127: /* =========================================================================== */
128:
129: /**
130: * <p>Create an {@link XMLReader} instance that can be used by
131: * <a href="http://www.thaiopensource.com/relaxng/jing.html">JING</a> for
132: * parsing schemas.</p>
133: *
134: * <p>The returned {@link XMLReader} will keep track of populating/clearing the
135: * {@link Stack} of {@link InputSource}s kept for URI resolution as explained
136: * in the description of the {@link #resolveEntity(String, String)} method.</p>
137: *
138: * @see JingReader
139: * @return a <b>non-null</b> {@link XMLReader} instance.
140: * @throws SAXException if an error occurrent creating the {@link XMLReader}.
141: */
142: public XMLReader createXMLReader() throws SAXException {
143: return new JingReader(this);
144: }
145: }
|