src/share/jaxws_classes/com/sun/tools/internal/xjc/ModelLoader.java

Wed, 27 Apr 2016 01:27:09 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:27:09 +0800
changeset 0
373ffda63c9a
child 637
9c07ef4934dd
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/jaxws/
changeset: 657:d47a47f961ee
tag: jdk8u25-b17

     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  */
    26 package com.sun.tools.internal.xjc;
    28 import java.io.IOException;
    29 import java.io.StringReader;
    31 import com.sun.codemodel.internal.JCodeModel;
    32 import com.sun.tools.internal.xjc.model.Model;
    33 import com.sun.tools.internal.xjc.reader.Const;
    34 import com.sun.tools.internal.xjc.reader.ExtensionBindingChecker;
    35 import com.sun.tools.internal.xjc.reader.dtd.TDTDReader;
    36 import com.sun.tools.internal.xjc.reader.internalizer.DOMForest;
    37 import com.sun.tools.internal.xjc.reader.internalizer.DOMForestScanner;
    38 import com.sun.tools.internal.xjc.reader.internalizer.InternalizationLogic;
    39 import com.sun.tools.internal.xjc.reader.internalizer.SCDBasedBindingSet;
    40 import com.sun.tools.internal.xjc.reader.internalizer.VersionChecker;
    41 import com.sun.tools.internal.xjc.reader.relaxng.RELAXNGCompiler;
    42 import com.sun.tools.internal.xjc.reader.relaxng.RELAXNGInternalizationLogic;
    43 import com.sun.tools.internal.xjc.reader.xmlschema.BGMBuilder;
    44 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.AnnotationParserFactoryImpl;
    45 import com.sun.tools.internal.xjc.reader.xmlschema.parser.CustomizationContextChecker;
    46 import com.sun.tools.internal.xjc.reader.xmlschema.parser.IncorrectNamespaceURIChecker;
    47 import com.sun.tools.internal.xjc.reader.xmlschema.parser.SchemaConstraintChecker;
    48 import com.sun.tools.internal.xjc.reader.xmlschema.parser.XMLSchemaInternalizationLogic;
    49 import com.sun.tools.internal.xjc.util.ErrorReceiverFilter;
    50 import com.sun.xml.internal.bind.v2.util.XmlFactory;
    51 import com.sun.xml.internal.xsom.XSSchemaSet;
    52 import com.sun.xml.internal.xsom.parser.JAXPParser;
    53 import com.sun.xml.internal.xsom.parser.XMLParser;
    54 import com.sun.xml.internal.xsom.parser.XSOMParser;
    55 import javax.xml.XMLConstants;
    57 import com.sun.xml.internal.rngom.ast.builder.SchemaBuilder;
    58 import com.sun.xml.internal.rngom.ast.util.CheckingSchemaBuilder;
    59 import com.sun.xml.internal.rngom.digested.DPattern;
    60 import com.sun.xml.internal.rngom.digested.DSchemaBuilderImpl;
    61 import com.sun.xml.internal.rngom.parse.IllegalSchemaException;
    62 import com.sun.xml.internal.rngom.parse.Parseable;
    63 import com.sun.xml.internal.rngom.parse.compact.CompactParseable;
    64 import com.sun.xml.internal.rngom.parse.xml.SAXParseable;
    65 import com.sun.xml.internal.rngom.xml.sax.XMLReaderCreator;
    66 import org.w3c.dom.Document;
    67 import org.w3c.dom.Element;
    68 import org.w3c.dom.NodeList;
    69 import org.xml.sax.Attributes;
    70 import org.xml.sax.ContentHandler;
    71 import org.xml.sax.EntityResolver;
    72 import org.xml.sax.ErrorHandler;
    73 import org.xml.sax.InputSource;
    74 import org.xml.sax.SAXException;
    75 import org.xml.sax.SAXParseException;
    76 import org.xml.sax.XMLFilter;
    77 import org.xml.sax.XMLReader;
    78 import org.xml.sax.helpers.XMLFilterImpl;
    80 /**
    81  * Builds a {@link Model} object.
    82  *
    83  * This is an utility class that makes it easy to load a grammar object
    84  * from various sources.
    85  *
    86  * @author
    87  *     Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
    88  */
    89 public final class ModelLoader {
    91     private final Options opt;
    92     private final ErrorReceiverFilter errorReceiver;
    93     private final JCodeModel codeModel;
    94     /**
    95      * {@link DOMForest#transform(boolean)} creates this on the side.
    96      */
    97     private SCDBasedBindingSet scdBasedBindingSet;
   100     /**
   101      * A convenience method to load schemas into a {@link Model}.
   102      */
   103     public static Model load( Options opt, JCodeModel codeModel, ErrorReceiver er ) {
   104         return new ModelLoader(opt,codeModel,er).load();
   105     }
   108     public ModelLoader(Options _opt, JCodeModel _codeModel, ErrorReceiver er) {
   109         this.opt = _opt;
   110         this.codeModel = _codeModel;
   111         this.errorReceiver = new ErrorReceiverFilter(er);
   112     }
   114     @SuppressWarnings("CallToThreadDumpStack")
   115     private Model load() {
   116         Model grammar;
   118         if(!sanityCheck())
   119             return null;
   122         try {
   123             switch (opt.getSchemaLanguage()) {
   124             case DTD :
   125                 // TODO: make sure that bindFiles,size()<=1
   126                 InputSource bindFile = null;
   127                 if (opt.getBindFiles().length > 0)
   128                     bindFile = opt.getBindFiles()[0];
   129                 // if there is no binding file, make a dummy one.
   130                 if (bindFile == null) {
   131                     // if no binding information is specified, provide a default
   132                     bindFile =
   133                         new InputSource(
   134                             new StringReader(
   135                                 "<?xml version='1.0'?><xml-java-binding-schema><options package='"
   136                                     + (opt.defaultPackage==null?"generated":opt.defaultPackage)
   137                                     + "'/></xml-java-binding-schema>"));
   138                 }
   140                 checkTooManySchemaErrors();
   141                 grammar = loadDTD(opt.getGrammars()[0], bindFile );
   142                 break;
   144             case RELAXNG :
   145                 checkTooManySchemaErrors();
   146                 grammar = loadRELAXNG();
   147                 break;
   149             case RELAXNG_COMPACT :
   150                 checkTooManySchemaErrors();
   151                 grammar = loadRELAXNGCompact();
   152                 break;
   154             case WSDL:
   155                 grammar = annotateXMLSchema( loadWSDL() );
   156                 break;
   158             case XMLSCHEMA:
   159                 grammar = annotateXMLSchema( loadXMLSchema() );
   160                 break;
   162             default :
   163                 throw new AssertionError(); // assertion failed
   164             }
   166             if (errorReceiver.hadError()) {
   167                 grammar = null;
   168             } else {
   169                 grammar.setPackageLevelAnnotations(opt.packageLevelAnnotations);
   170             }
   172             return grammar;
   174         } catch (SAXException e) {
   175             // parsing error in the input document.
   176             // this error must have been reported to the user vis error handler
   177             // so don't print it again.
   178             if (opt.verbose) {
   179                 // however, a bug in XJC might throw unexpected SAXException.
   180                 // thus when one is debugging, it is useful to print what went
   181                 // wrong.
   182                 if (e.getException() != null)
   183                     e.getException().printStackTrace();
   184                 else
   185                     e.printStackTrace();
   186             }
   187             return null;
   188         } catch (AbortException e) {
   189             // error should have been reported already, since this is requested by the error receiver
   190             return null;
   191         }
   192     }
   196     /**
   197      * Do some extra checking and return false if the compilation
   198      * should abort.
   199      */
   200     private boolean sanityCheck() {
   201         if( opt.getSchemaLanguage()==Language.XMLSCHEMA ) {
   202             Language guess = opt.guessSchemaLanguage();
   204             String[] msg = null;
   205             switch(guess) {
   206             case DTD:
   207                 msg = new String[]{"DTD","-dtd"};
   208                 break;
   209             case RELAXNG:
   210                 msg = new String[]{"RELAX NG","-relaxng"};
   211                 break;
   212             case RELAXNG_COMPACT:
   213                 msg = new String[]{"RELAX NG compact syntax","-relaxng-compact"};
   214                 break;
   215             case WSDL:
   216                 msg = new String[]{"WSDL","-wsdl"};
   217                 break;
   218             }
   219             if( msg!=null )
   220                 errorReceiver.warning( null,
   221                     Messages.format(
   222                     Messages.EXPERIMENTAL_LANGUAGE_WARNING,
   223                     msg[0], msg[1] ));
   224         }
   225         return true;
   226     }
   229     /**
   230      * {@link XMLParser} implementation that adds additional processors into the chain.
   231      *
   232      * <p>
   233      * This parser will parse a DOM forest as:
   234      * DOMForestParser -->
   235      *   ExtensionBindingChecker -->
   236      *     ProhibitedFeatureFilter -->
   237      *       XSOMParser
   238      */
   239     private class XMLSchemaParser implements XMLParser {
   240         private final XMLParser baseParser;
   242         private XMLSchemaParser(XMLParser baseParser) {
   243             this.baseParser = baseParser;
   244         }
   246         public void parse(InputSource source, ContentHandler handler,
   247             ErrorHandler errorHandler, EntityResolver entityResolver ) throws SAXException, IOException {
   248             // set up the chain of handlers.
   249             handler = wrapBy( new ExtensionBindingChecker(XMLConstants.W3C_XML_SCHEMA_NS_URI,opt,errorReceiver), handler );
   250             handler = wrapBy( new IncorrectNamespaceURIChecker(errorReceiver), handler );
   251             handler = wrapBy( new CustomizationContextChecker(errorReceiver), handler );
   252 //          handler = wrapBy( new VersionChecker(controller), handler );
   254             baseParser.parse( source, handler, errorHandler, entityResolver );
   255         }
   256         /**
   257          * Wraps the specified content handler by a filter.
   258          * It is little awkward to use a helper implementation class like XMLFilterImpl
   259          * as the method parameter, but this simplifies the code.
   260          */
   261         private ContentHandler wrapBy( XMLFilterImpl filter, ContentHandler handler ) {
   262             filter.setContentHandler(handler);
   263             return filter;
   264         }
   265     }
   267     private void checkTooManySchemaErrors() {
   268         if( opt.getGrammars().length!=1 )
   269             errorReceiver.error(null,Messages.format(Messages.ERR_TOO_MANY_SCHEMA));
   270     }
   272     /**
   273      * Parses a DTD file into an annotated grammar.
   274      *
   275      * @param   source
   276      *      DTD file
   277      * @param   bindFile
   278      *      External binding file.
   279      */
   280     private Model loadDTD( InputSource source, InputSource bindFile) {
   282         // parse the schema as a DTD.
   283         return TDTDReader.parse(
   284             source,
   285             bindFile,
   286             errorReceiver,
   287             opt);
   288     }
   290     /**
   291      * Builds DOMForest and performs the internalization.
   292      *
   293      * @throws SAXException
   294      *      when a fatal error happens
   295      */
   296     public DOMForest buildDOMForest( InternalizationLogic logic )
   297         throws SAXException {
   299         // parse into DOM forest
   300         DOMForest forest = new DOMForest(logic, opt);
   302         forest.setErrorHandler(errorReceiver);
   303         if(opt.entityResolver!=null)
   304         forest.setEntityResolver(opt.entityResolver);
   306         // parse source grammars
   307         for (InputSource value : opt.getGrammars()) {
   308             errorReceiver.pollAbort();
   309             forest.parse(value, true);
   310         }
   312         // parse external binding files
   313         for (InputSource value : opt.getBindFiles()) {
   314             errorReceiver.pollAbort();
   315             Document dom = forest.parse(value, true);
   316             if(dom==null)       continue;   // error must have been reported
   317             Element root = dom.getDocumentElement();
   318             // TODO: it somehow doesn't feel right to do a validation in the Driver class.
   319             // think about moving it to somewhere else.
   320             if (!fixNull(root.getNamespaceURI()).equals(Const.JAXB_NSURI)
   321                     || !root.getLocalName().equals("bindings"))
   322                 errorReceiver.error(new SAXParseException(Messages.format(Messages.ERR_NOT_A_BINDING_FILE,
   323                         root.getNamespaceURI(),
   324                         root.getLocalName()),
   325                         null,
   326                         value.getSystemId(),
   327                         -1, -1));
   328         }
   330         scdBasedBindingSet = forest.transform(opt.isExtensionMode());
   332         return forest;
   333     }
   335     private String fixNull(String s) {
   336         if(s==null) return "";
   337         else        return s;
   338     }
   340     /**
   341      * Parses a set of XML Schema files into an annotated grammar.
   342      */
   343     public XSSchemaSet loadXMLSchema() throws SAXException {
   345         if( opt.strictCheck && !SchemaConstraintChecker.check(opt.getGrammars(),errorReceiver,opt.entityResolver, opt.disableXmlSecurity)) {
   346             // schema error. error should have been reported
   347             return null;
   348         }
   350         if(opt.getBindFiles().length==0) {
   351             // no external binding. try the speculative no DOMForest execution,
   352             // which is faster if the speculation succeeds.
   353             try {
   354                 return createXSOMSpeculative();
   355             } catch( SpeculationFailure e) {
   356                 // failed. go the slow way
   357             }
   358         }
   360         // the default slower way is to parse everything into DOM first.
   361         // so that we can take external annotations into account.
   362         DOMForest forest = buildDOMForest( new XMLSchemaInternalizationLogic() );
   363         return createXSOM(forest, scdBasedBindingSet);
   364     }
   366     /**
   367      * Parses a set of schemas inside a WSDL file.
   368      *
   369      * A WSDL file may contain multiple &lt;xsd:schema> elements.
   370      */
   371     private XSSchemaSet loadWSDL()
   372         throws SAXException {
   375         // build DOMForest just like we handle XML Schema
   376         DOMForest forest = buildDOMForest( new XMLSchemaInternalizationLogic() );
   378         DOMForestScanner scanner = new DOMForestScanner(forest);
   380         XSOMParser xsomParser = createXSOMParser( forest );
   382         // find <xsd:schema>s and parse them individually
   383         for( InputSource grammar : opt.getGrammars() ) {
   384             Document wsdlDom = forest.get( grammar.getSystemId() );
   385             if (wsdlDom == null) {
   386                 String systemId = Options.normalizeSystemId(grammar.getSystemId());
   387                 if (forest.get(systemId) != null) {
   388                     grammar.setSystemId(systemId);
   389                     wsdlDom = forest.get( grammar.getSystemId() );
   390                 }
   391             }
   393             NodeList schemas = wsdlDom.getElementsByTagNameNS(XMLConstants.W3C_XML_SCHEMA_NS_URI,"schema");
   394             for( int i=0; i<schemas.getLength(); i++ )
   395                 scanner.scan( (Element)schemas.item(i), xsomParser.getParserHandler() );
   396         }
   397         return xsomParser.getResult();
   398     }
   400     /**
   401      * Annotates the obtained schema set.
   402      *
   403      * @return
   404      *      null if an error happens. In that case, the error messages
   405      *      will be properly reported to the controller by this method.
   406      */
   407     public Model annotateXMLSchema(XSSchemaSet xs) {
   408         if (xs == null)
   409             return null;
   410         return BGMBuilder.build(xs, codeModel, errorReceiver, opt);
   411     }
   413     /**
   414      * Potentially problematic - make sure the parser instance passed is initialized
   415      * with proper security feature.
   416      *
   417      * @param parser
   418      * @return
   419      */
   420     public XSOMParser createXSOMParser(XMLParser parser) {
   421         // set up other parameters to XSOMParser
   422         XSOMParser reader = new XSOMParser(new XMLSchemaParser(parser));
   423         reader.setAnnotationParser(new AnnotationParserFactoryImpl(opt));
   424         reader.setErrorHandler(errorReceiver);
   425         reader.setEntityResolver(opt.entityResolver);
   426         return reader;
   427     }
   429     public XSOMParser createXSOMParser(final DOMForest forest) {
   430         XSOMParser p = createXSOMParser(forest.createParser());
   431         p.setEntityResolver(new EntityResolver() {
   432             public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
   433                 // DOMForest only parses documents that are reachable through systemIds,
   434                 // and it won't pick up references like <xs:import namespace="..." /> without
   435                 // @schemaLocation. So we still need to use an entity resolver here to resolve
   436                 // these references, yet we don't want to just run them blindly, since if we do that
   437                 // DOMForestParser always get the translated system ID when catalog is used
   438                 // (where DOMForest records trees with their original system IDs.)
   439                 if(systemId!=null && forest.get(systemId)!=null)
   440                     return new InputSource(systemId);
   441                 if(opt.entityResolver!=null)
   442                     return opt.entityResolver.resolveEntity(publicId,systemId);
   444                 return null;
   445             }
   446         });
   447         return p;
   448     }
   451     private static final class SpeculationFailure extends Error {}
   453     private static final class SpeculationChecker extends XMLFilterImpl {
   454         @Override
   455         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
   456             if(localName.equals("bindings") && uri.equals(Const.JAXB_NSURI))
   457                 throw new SpeculationFailure();
   458             super.startElement(uri,localName,qName,attributes);
   459         }
   460     }
   462     /**
   463      * Parses schemas directly into XSOM by assuming that there's
   464      * no external annotations.
   465      * <p>
   466      * When an external annotation is found, a {@link SpeculationFailure} is thrown,
   467      * and we will do it all over again by using the slow way.
   468      */
   469     private XSSchemaSet createXSOMSpeculative() throws SAXException, SpeculationFailure {
   471         // check if the schema contains external binding files. If so, speculation is a failure.
   473         XMLParser parser = new XMLParser() {
   474             private final JAXPParser base = new JAXPParser(XmlFactory.createParserFactory(opt.disableXmlSecurity));
   476             public void parse(InputSource source, ContentHandler handler,
   477                 ErrorHandler errorHandler, EntityResolver entityResolver ) throws SAXException, IOException {
   478                 // set up the chain of handlers.
   479                 handler = wrapBy( new SpeculationChecker(), handler );
   480                 handler = wrapBy( new VersionChecker(null,errorReceiver,entityResolver), handler );
   482                 base.parse( source, handler, errorHandler, entityResolver );
   483             }
   484             /**
   485              * Wraps the specified content handler by a filter.
   486              * It is little awkward to use a helper implementation class like XMLFilterImpl
   487              * as the method parameter, but this simplifies the code.
   488              */
   489             private ContentHandler wrapBy( XMLFilterImpl filter, ContentHandler handler ) {
   490                 filter.setContentHandler(handler);
   491                 return filter;
   492             }
   493         };
   495         XSOMParser reader = createXSOMParser(parser);
   497         // parse source grammars
   498         for (InputSource value : opt.getGrammars())
   499             reader.parse(value);
   501         return reader.getResult();
   502     }
   504     /**
   505      * Parses a {@link DOMForest} into a {@link XSSchemaSet}.
   506      *
   507      * @return
   508      *      null if the parsing failed.
   509      */
   510     public XSSchemaSet createXSOM(DOMForest forest, SCDBasedBindingSet scdBasedBindingSet) throws SAXException {
   511         // set up other parameters to XSOMParser
   512         XSOMParser reader = createXSOMParser(forest);
   514         // re-parse the transformed schemas
   515         for (String systemId : forest.getRootDocuments()) {
   516             errorReceiver.pollAbort();
   517             Document dom = forest.get(systemId);
   518             if (!dom.getDocumentElement().getNamespaceURI().equals(Const.JAXB_NSURI)) {
   519                 reader.parse(systemId);
   520             }
   521         }
   523         XSSchemaSet result = reader.getResult();
   525         if(result!=null)
   526             scdBasedBindingSet.apply(result,errorReceiver);
   528         return result;
   529     }
   531     /**
   532      * Parses a RELAX NG grammar into an annotated grammar.
   533      */
   534     private Model loadRELAXNG() throws SAXException {
   536         // build DOM forest
   537         final DOMForest forest = buildDOMForest( new RELAXNGInternalizationLogic() );
   539         // use JAXP masquerading to validate the input document.
   540         // DOMForest -> ExtensionBindingChecker -> RNGOM
   542         XMLReaderCreator xrc = new XMLReaderCreator() {
   543             public XMLReader createXMLReader() {
   545                 // foreset parser cannot change the receivers while it's working,
   546                 // so we need to have one XMLFilter that works as a buffer
   547                 XMLFilter buffer = new XMLFilterImpl() {
   548                     @Override
   549                     public void parse(InputSource source) throws IOException, SAXException {
   550                         forest.createParser().parse( source, this, this, this );
   551                     }
   552                 };
   554                 XMLFilter f = new ExtensionBindingChecker(Const.RELAXNG_URI,opt,errorReceiver);
   555                 f.setParent(buffer);
   557                 f.setEntityResolver(opt.entityResolver);
   559                 return f;
   560             }
   561         };
   563         Parseable p = new SAXParseable( opt.getGrammars()[0], errorReceiver, xrc );
   565         return loadRELAXNG(p);
   567     }
   569     /**
   570      * Loads RELAX NG compact syntax
   571      */
   572     private Model loadRELAXNGCompact() {
   573         if(opt.getBindFiles().length>0)
   574             errorReceiver.error(new SAXParseException(
   575                 Messages.format(Messages.ERR_BINDING_FILE_NOT_SUPPORTED_FOR_RNC),null));
   577         // TODO: entity resolver?
   578         Parseable p = new CompactParseable( opt.getGrammars()[0], errorReceiver );
   580         return loadRELAXNG(p);
   582     }
   584     /**
   585      * Common part between the XML syntax and the compact syntax.
   586      */
   587     private Model loadRELAXNG(Parseable p) {
   588         SchemaBuilder sb = new CheckingSchemaBuilder(new DSchemaBuilderImpl(),errorReceiver);
   590         try {
   591             DPattern out = (DPattern)p.parse(sb);
   592             return RELAXNGCompiler.build(out,codeModel,opt);
   593         } catch (IllegalSchemaException e) {
   594             errorReceiver.error(e.getMessage(),e);
   595             return null;
   596         }
   597     }
   598 }

mercurial