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

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 368
0989ad8c0860
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

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

mercurial