1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.xsom.parser;
  27 
  28 import java.io.File;
  29 import java.io.IOException;
  30 import java.io.InputStream;
  31 import java.io.Reader;
  32 import java.net.URL;
  33 import java.util.Set;
  34 import java.util.HashSet;
  35 
  36 import javax.xml.parsers.SAXParserFactory;
  37 
  38 import org.xml.sax.ContentHandler;
  39 import org.xml.sax.EntityResolver;
  40 import org.xml.sax.ErrorHandler;
  41 import org.xml.sax.InputSource;
  42 import org.xml.sax.SAXException;
  43 
  44 import com.sun.xml.internal.xsom.XSSchemaSet;
  45 import com.sun.xml.internal.xsom.impl.parser.NGCCRuntimeEx;
  46 import com.sun.xml.internal.xsom.impl.parser.ParserContext;
  47 import com.sun.xml.internal.xsom.impl.parser.state.Schema;
  48 
  49 /**
  50  * Parses possibly multiple W3C XML Schema files and compose
  51  * them into one grammar.
  52  *
  53  * @author
  54  *     Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
  55  */
  56 public final class XSOMParser {
  57 
  58     private EntityResolver entityResolver;
  59     private ErrorHandler userErrorHandler;
  60 
  61     private AnnotationParserFactory apFactory;
  62 
  63     private final ParserContext context;
  64 
  65     /**
  66     * Creates a new XSOMParser by using a SAX parser from JAXP.
  67      * @deprecated Unsafe, use XSOMParser(factory) instead with
  68      * security features initialized by setting
  69      * XMLConstants.FEATURE_SECURE_PROCESSING feature.
  70     */
  71    public XSOMParser() {
  72        this(new JAXPParser());
  73    }
  74 
  75    /**
  76     * Creates a new XSOMParser that uses the given SAXParserFactory
  77     * for creating new SAX parsers.
  78     *
  79     * The caller needs to configure
  80     * it properly. Don't forget to call <code>setNamespaceAware(true)</code>
  81     * or you'll see some strange errors.
  82     */
  83    public XSOMParser( SAXParserFactory factory ) {
  84        this( new JAXPParser(factory) );
  85    }
  86 
  87    /**
  88     * Creates a new XSOMParser that reads XML Schema from non-standard
  89     * inputs.
  90     *
  91     * By implementing the {@link XMLParser} interface, XML Schema
  92     * can be read from something other than XML.
  93     *
  94     * @param   parser
  95     *      This parser will be called to parse XML Schema documents.
  96     */
  97     public XSOMParser(XMLParser parser) {
  98         context = new ParserContext(this,parser);
  99     }
 100 
 101     /**
 102      * Parses a new XML Schema document.
 103      *
 104      * <p>
 105      * When using this method, XSOM does not know the system ID of
 106      * this document, therefore, when this stream contains relative
 107      * references to other schemas, XSOM will fail to resolve them.
 108      * To specify an system ID with a stream, use {@link InputSource}
 109      */
 110     public void parse( InputStream is ) throws SAXException {
 111         parse(new InputSource(is));
 112     }
 113 
 114     /**
 115      * Parses a new XML Schema document.
 116      *
 117      * <p>
 118      * When using this method, XSOM does not know the system ID of
 119      * this document, therefore, when this reader contains relative
 120      * references to other schemas, XSOM will fail to resolve them.
 121      * To specify an system ID with a reader, use {@link InputSource}
 122      */
 123     public void parse( Reader reader ) throws SAXException {
 124         parse(new InputSource(reader));
 125     }
 126 
 127     /**
 128      * Parses a new XML Schema document.
 129      */
 130     public void parse( File schema ) throws SAXException, IOException {
 131         parse(schema.toURL());
 132     }
 133 
 134     /**
 135      * Parses a new XML Schema document.
 136      */
 137     public void parse( URL url ) throws SAXException {
 138         parse( url.toExternalForm() );
 139     }
 140 
 141     /**
 142      * Parses a new XML Schema document.
 143      */
 144     public void parse( String systemId ) throws SAXException {
 145         parse(new InputSource(systemId));
 146     }
 147 
 148     /**
 149      * Parses a new XML Schema document.
 150      *
 151      * <p>
 152      * Note that if the {@link InputSource} does not have a system ID,
 153      * XSOM will fail to resolve them.
 154      */
 155     public void parse( InputSource source ) throws SAXException {
 156         context.parse(source);
 157     }
 158 
 159 
 160 
 161     /**
 162      * Gets the parser implemented as a ContentHandler.
 163      *
 164      * One can feed XML Schema as SAX events to this interface to
 165      * parse a schema. To parse multiple schema files, feed multiple
 166      * sets of events.
 167      *
 168      * <p>
 169      * If you don't send a complete event sequence from a startDocument
 170      * event to an endDocument event, the state of XSOMParser can become
 171      * unstable. This sometimes happen when you encounter an error while
 172      * generating SAX events. Don't call the getResult method in that case.
 173      *
 174      * <p>
 175      * This way of reading XML Schema can be useful when XML Schema is
 176      * not available as a stand-alone XML document.
 177      * For example, one can feed XML Schema inside a WSDL document.
 178      */
 179     public ContentHandler getParserHandler() {
 180         NGCCRuntimeEx runtime = context.newNGCCRuntime();
 181         Schema s = new Schema(runtime,false,null);
 182         runtime.setRootHandler(s);
 183         return runtime;
 184     }
 185 
 186     /**
 187      * Gets the parsed result. Don't call this method until
 188      * you parse all the schemas.
 189      *
 190      * @return
 191      *      If there was any parse error, this method returns null.
 192      *      To receive error information, specify your error handler
 193      *      through the setErrorHandler method.
 194      * @exception SAXException
 195      *      This exception will never be thrown unless it is thrown
 196      *      by an error handler.
 197      */
 198     public XSSchemaSet getResult() throws SAXException {
 199         return context.getResult();
 200     }
 201 
 202     /**
 203      * Gets the set of {@link SchemaDocument} that represents
 204      * parsed documents so far.
 205      *
 206      * @return
 207      *      can be empty but never null.
 208      */
 209     public Set<SchemaDocument> getDocuments() {
 210         return new HashSet<SchemaDocument>(context.parsedDocuments.keySet());
 211     }
 212 
 213     public EntityResolver getEntityResolver() {
 214         return entityResolver;
 215     }
 216     /**
 217      * Set an entity resolver that is used to resolve things
 218      * like &lt;xsd:import> and &lt;xsd:include>.
 219      */
 220     public void setEntityResolver( EntityResolver resolver ) {
 221         this.entityResolver = resolver;
 222     }
 223     public ErrorHandler getErrorHandler() {
 224         return userErrorHandler;
 225     }
 226     /**
 227      * Set an error handler that receives all the errors encountered
 228      * during the parsing.
 229      */
 230     public void setErrorHandler(ErrorHandler errorHandler) {
 231         this.userErrorHandler = errorHandler;
 232     }
 233 
 234     /**
 235      * Sets the annotation parser.
 236      *
 237      * Annotation parser can be used to parse application-specific
 238      * annotations inside a schema.
 239      *
 240      * <p>
 241      * For each annotation, new instance of this class will be
 242      * created and used to parse &lt;xs:annotation>.
 243      */
 244     public void setAnnotationParser( final Class annParser ) {
 245         setAnnotationParser( new AnnotationParserFactory() {
 246             public AnnotationParser create() {
 247                 try {
 248                     return (AnnotationParser)annParser.newInstance();
 249                 } catch( InstantiationException e ) {
 250                     throw new InstantiationError(e.getMessage());
 251                 } catch( IllegalAccessException e ) {
 252                     throw new IllegalAccessError(e.getMessage());
 253                 }
 254             }
 255         });
 256     }
 257 
 258     /**
 259      * Sets the annotation parser factory.
 260      *
 261      * <p>
 262      * The specified factory will be used to create AnnotationParsers.
 263      */
 264     public void setAnnotationParser( AnnotationParserFactory factory ) {
 265         this.apFactory = factory;
 266     }
 267 
 268     public AnnotationParserFactory getAnnotationParserFactory() {
 269         return apFactory;
 270     }
 271 }