1 /*
   2  * Copyright (c) 2005, 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  * Copyright (C) 2004-2012
  27  *
  28  * Permission is hereby granted, free of charge, to any person obtaining a copy
  29  * of this software and associated documentation files (the "Software"), to deal
  30  * in the Software without restriction, including without limitation the rights
  31  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  32  * copies of the Software, and to permit persons to whom the Software is
  33  * furnished to do so, subject to the following conditions:
  34  *
  35  * The above copyright notice and this permission notice shall be included in
  36  * all copies or substantial portions of the Software.
  37  *
  38  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  39  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  40  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  41  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  42  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  43  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  44  * THE SOFTWARE.
  45  */
  46 package com.sun.xml.internal.rngom.binary;
  47 
  48 import java.util.Enumeration;
  49 import java.util.Hashtable;
  50 import java.util.List;
  51 
  52 import com.sun.xml.internal.rngom.ast.builder.Annotations;
  53 import com.sun.xml.internal.rngom.ast.builder.BuildException;
  54 import com.sun.xml.internal.rngom.ast.builder.CommentList;
  55 import com.sun.xml.internal.rngom.ast.builder.DataPatternBuilder;
  56 import com.sun.xml.internal.rngom.ast.builder.Div;
  57 import com.sun.xml.internal.rngom.ast.builder.ElementAnnotationBuilder;
  58 import com.sun.xml.internal.rngom.ast.builder.Grammar;
  59 import com.sun.xml.internal.rngom.ast.builder.GrammarSection;
  60 import com.sun.xml.internal.rngom.ast.builder.Include;
  61 import com.sun.xml.internal.rngom.ast.builder.IncludedGrammar;
  62 import com.sun.xml.internal.rngom.ast.builder.NameClassBuilder;
  63 import com.sun.xml.internal.rngom.ast.builder.SchemaBuilder;
  64 import com.sun.xml.internal.rngom.ast.builder.Scope;
  65 import com.sun.xml.internal.rngom.ast.om.Location;
  66 import com.sun.xml.internal.rngom.ast.om.ParsedElementAnnotation;
  67 import com.sun.xml.internal.rngom.ast.om.ParsedNameClass;
  68 import com.sun.xml.internal.rngom.ast.om.ParsedPattern;
  69 import com.sun.xml.internal.rngom.ast.util.LocatorImpl;
  70 import com.sun.xml.internal.rngom.dt.builtin.BuiltinDatatypeLibraryFactory;
  71 import com.sun.xml.internal.rngom.dt.CascadingDatatypeLibraryFactory;
  72 import com.sun.xml.internal.rngom.nc.NameClass;
  73 import com.sun.xml.internal.rngom.nc.NameClassBuilderImpl;
  74 import com.sun.xml.internal.rngom.parse.Context;
  75 import com.sun.xml.internal.rngom.parse.IllegalSchemaException;
  76 import com.sun.xml.internal.rngom.parse.Parseable;
  77 import com.sun.xml.internal.rngom.util.Localizer;
  78 import org.relaxng.datatype.Datatype;
  79 import org.relaxng.datatype.DatatypeBuilder;
  80 import org.relaxng.datatype.DatatypeException;
  81 import org.relaxng.datatype.DatatypeLibrary;
  82 import org.relaxng.datatype.DatatypeLibraryFactory;
  83 import org.relaxng.datatype.ValidationContext;
  84 import org.relaxng.datatype.helpers.DatatypeLibraryLoader;
  85 import org.xml.sax.ErrorHandler;
  86 import org.xml.sax.Locator;
  87 import org.xml.sax.SAXException;
  88 import org.xml.sax.SAXParseException;
  89 
  90 public class SchemaBuilderImpl implements SchemaBuilder, ElementAnnotationBuilder, CommentList {
  91 
  92     private final SchemaBuilderImpl parent;
  93     private boolean hadError = false;
  94     private final SchemaPatternBuilder pb;
  95     private final DatatypeLibraryFactory datatypeLibraryFactory;
  96     private final String inheritNs;
  97     private final ErrorHandler eh;
  98     private final OpenIncludes openIncludes;
  99     private final NameClassBuilder ncb = new NameClassBuilderImpl();
 100     static final Localizer localizer = new Localizer(SchemaBuilderImpl.class);
 101 
 102     static class OpenIncludes {
 103 
 104         final String uri;
 105         final OpenIncludes parent;
 106 
 107         OpenIncludes(String uri, OpenIncludes parent) {
 108             this.uri = uri;
 109             this.parent = parent;
 110         }
 111     }
 112 
 113     public ParsedPattern expandPattern(ParsedPattern _pattern)
 114             throws BuildException, IllegalSchemaException {
 115         Pattern pattern = (Pattern) _pattern;
 116         if (!hadError) {
 117             try {
 118                 pattern.checkRecursion(0);
 119                 pattern = pattern.expand(pb);
 120                 pattern.checkRestrictions(Pattern.START_CONTEXT, null, null);
 121                 if (!hadError) {
 122                     return pattern;
 123                 }
 124             } catch (SAXParseException e) {
 125                 error(e);
 126             } catch (SAXException e) {
 127                 throw new BuildException(e);
 128             } catch (RestrictionViolationException e) {
 129                 if (e.getName() != null) {
 130                     error(e.getMessageId(), e.getName().toString(), e
 131                             .getLocator());
 132                 } else {
 133                     error(e.getMessageId(), e.getLocator());
 134                 }
 135             }
 136         }
 137         throw new IllegalSchemaException();
 138     }
 139 
 140     /**
 141      *
 142      * @param eh Error handler to receive errors while building the schema.
 143      */
 144     public SchemaBuilderImpl(ErrorHandler eh) {
 145         this(eh,
 146                 new CascadingDatatypeLibraryFactory(new DatatypeLibraryLoader(),
 147                 new BuiltinDatatypeLibraryFactory(new DatatypeLibraryLoader())),
 148                 new SchemaPatternBuilder());
 149     }
 150 
 151     /**
 152      *
 153      * @param eh Error handler to receive errors while building the schema.
 154      * @param datatypeLibraryFactory This is consulted to locate datatype
 155      * libraries.
 156      * @param pb Used to build patterns.
 157      */
 158     public SchemaBuilderImpl(ErrorHandler eh,
 159             DatatypeLibraryFactory datatypeLibraryFactory,
 160             SchemaPatternBuilder pb) {
 161         this.parent = null;
 162         this.eh = eh;
 163         this.datatypeLibraryFactory = datatypeLibraryFactory;
 164         this.pb = pb;
 165         this.inheritNs = "";
 166         this.openIncludes = null;
 167     }
 168 
 169     private SchemaBuilderImpl(String inheritNs,
 170             String uri,
 171             SchemaBuilderImpl parent) {
 172         this.parent = parent;
 173         this.eh = parent.eh;
 174         this.datatypeLibraryFactory = parent.datatypeLibraryFactory;
 175         this.pb = parent.pb;
 176         this.inheritNs = inheritNs;
 177         this.openIncludes = new OpenIncludes(uri, parent.openIncludes);
 178     }
 179 
 180     public NameClassBuilder getNameClassBuilder() {
 181         return ncb;
 182     }
 183 
 184     public ParsedPattern makeChoice(List patterns, Location loc, Annotations anno)
 185             throws BuildException {
 186         if (patterns.isEmpty()) {
 187             throw new IllegalArgumentException();
 188         }
 189         Pattern result = (Pattern) patterns.get(0);
 190         for (int i = 1; i < patterns.size(); i++) {
 191             result = pb.makeChoice(result, (Pattern) patterns.get(i));
 192         }
 193         return result;
 194     }
 195 
 196     public ParsedPattern makeInterleave(List patterns, Location loc, Annotations anno)
 197             throws BuildException {
 198         if (patterns.isEmpty()) {
 199             throw new IllegalArgumentException();
 200         }
 201         Pattern result = (Pattern) patterns.get(0);
 202         for (int i = 1; i < patterns.size(); i++) {
 203             result = pb.makeInterleave(result, (Pattern) patterns.get(i));
 204         }
 205         return result;
 206     }
 207 
 208     public ParsedPattern makeGroup(List patterns, Location loc, Annotations anno)
 209             throws BuildException {
 210         if (patterns.isEmpty()) {
 211             throw new IllegalArgumentException();
 212         }
 213         Pattern result = (Pattern) patterns.get(0);
 214         for (int i = 1; i < patterns.size(); i++) {
 215             result = pb.makeGroup(result, (Pattern) patterns.get(i));
 216         }
 217         return result;
 218     }
 219 
 220     public ParsedPattern makeOneOrMore(ParsedPattern p, Location loc, Annotations anno)
 221             throws BuildException {
 222         return pb.makeOneOrMore((Pattern) p);
 223     }
 224 
 225     public ParsedPattern makeZeroOrMore(ParsedPattern p, Location loc, Annotations anno)
 226             throws BuildException {
 227         return pb.makeZeroOrMore((Pattern) p);
 228     }
 229 
 230     public ParsedPattern makeOptional(ParsedPattern p, Location loc, Annotations anno)
 231             throws BuildException {
 232         return pb.makeOptional((Pattern) p);
 233     }
 234 
 235     public ParsedPattern makeList(ParsedPattern p, Location loc, Annotations anno)
 236             throws BuildException {
 237         return pb.makeList((Pattern) p, (Locator) loc);
 238     }
 239 
 240     public ParsedPattern makeMixed(ParsedPattern p, Location loc, Annotations anno)
 241             throws BuildException {
 242         return pb.makeMixed((Pattern) p);
 243     }
 244 
 245     public ParsedPattern makeEmpty(Location loc, Annotations anno) {
 246         return pb.makeEmpty();
 247     }
 248 
 249     public ParsedPattern makeNotAllowed(Location loc, Annotations anno) {
 250         return pb.makeUnexpandedNotAllowed();
 251     }
 252 
 253     public ParsedPattern makeText(Location loc, Annotations anno) {
 254         return pb.makeText();
 255     }
 256 
 257     public ParsedPattern makeErrorPattern() {
 258         return pb.makeError();
 259     }
 260 
 261 //  public ParsedNameClass makeErrorNameClass() {
 262 //    return new ErrorNameClass();
 263 //  }
 264     public ParsedPattern makeAttribute(ParsedNameClass nc, ParsedPattern p, Location loc, Annotations anno)
 265             throws BuildException {
 266         return pb.makeAttribute((NameClass) nc, (Pattern) p, (Locator) loc);
 267     }
 268 
 269     public ParsedPattern makeElement(ParsedNameClass nc, ParsedPattern p, Location loc, Annotations anno)
 270             throws BuildException {
 271         return pb.makeElement((NameClass) nc, (Pattern) p, (Locator) loc);
 272     }
 273 
 274     private class DummyDataPatternBuilder implements DataPatternBuilder {
 275 
 276         public void addParam(String name, String value, Context context, String ns, Location loc, Annotations anno)
 277                 throws BuildException {
 278         }
 279 
 280         public ParsedPattern makePattern(Location loc, Annotations anno)
 281                 throws BuildException {
 282             return pb.makeError();
 283         }
 284 
 285         public ParsedPattern makePattern(ParsedPattern except, Location loc, Annotations anno)
 286                 throws BuildException {
 287             return pb.makeError();
 288         }
 289 
 290         public void annotation(ParsedElementAnnotation ea) {
 291         }
 292     }
 293 
 294     private static class ValidationContextImpl implements ValidationContext {
 295 
 296         private ValidationContext vc;
 297         private String ns;
 298 
 299         ValidationContextImpl(ValidationContext vc, String ns) {
 300             this.vc = vc;
 301             this.ns = ns.length() == 0 ? null : ns;
 302         }
 303 
 304         public String resolveNamespacePrefix(String prefix) {
 305             return prefix.length() == 0 ? ns : vc.resolveNamespacePrefix(prefix);
 306         }
 307 
 308         public String getBaseUri() {
 309             return vc.getBaseUri();
 310         }
 311 
 312         public boolean isUnparsedEntity(String entityName) {
 313             return vc.isUnparsedEntity(entityName);
 314         }
 315 
 316         public boolean isNotation(String notationName) {
 317             return vc.isNotation(notationName);
 318         }
 319     }
 320 
 321     private class DataPatternBuilderImpl implements DataPatternBuilder {
 322 
 323         private DatatypeBuilder dtb;
 324 
 325         DataPatternBuilderImpl(DatatypeBuilder dtb) {
 326             this.dtb = dtb;
 327         }
 328 
 329         public void addParam(String name, String value, Context context, String ns, Location loc, Annotations anno)
 330                 throws BuildException {
 331             try {
 332                 dtb.addParameter(name, value, new ValidationContextImpl(context, ns));
 333             } catch (DatatypeException e) {
 334                 String detail = e.getMessage();
 335                 int pos = e.getIndex();
 336                 String displayedParam;
 337                 if (pos == DatatypeException.UNKNOWN) {
 338                     displayedParam = null;
 339                 } else {
 340                     displayedParam = displayParam(value, pos);
 341                 }
 342                 if (displayedParam != null) {
 343                     if (detail != null) {
 344                         error("invalid_param_detail_display", detail, displayedParam, (Locator) loc);
 345                     } else {
 346                         error("invalid_param_display", displayedParam, (Locator) loc);
 347                     }
 348                 } else if (detail != null) {
 349                     error("invalid_param_detail", detail, (Locator) loc);
 350                 } else {
 351                     error("invalid_param", (Locator) loc);
 352                 }
 353             }
 354         }
 355 
 356         String displayParam(String value, int pos) {
 357             if (pos < 0) {
 358                 pos = 0;
 359             } else if (pos > value.length()) {
 360                 pos = value.length();
 361             }
 362             return localizer.message("display_param", value.substring(0, pos), value.substring(pos));
 363         }
 364 
 365         public ParsedPattern makePattern(Location loc, Annotations anno)
 366                 throws BuildException {
 367             try {
 368                 return pb.makeData(dtb.createDatatype());
 369             } catch (DatatypeException e) {
 370                 String detail = e.getMessage();
 371                 if (detail != null) {
 372                     error("invalid_params_detail", detail, (Locator) loc);
 373                 } else {
 374                     error("invalid_params", (Locator) loc);
 375                 }
 376                 return pb.makeError();
 377             }
 378         }
 379 
 380         public ParsedPattern makePattern(ParsedPattern except, Location loc, Annotations anno)
 381                 throws BuildException {
 382             try {
 383                 return pb.makeDataExcept(dtb.createDatatype(), (Pattern) except, (Locator) loc);
 384             } catch (DatatypeException e) {
 385                 String detail = e.getMessage();
 386                 if (detail != null) {
 387                     error("invalid_params_detail", detail, (Locator) loc);
 388                 } else {
 389                     error("invalid_params", (Locator) loc);
 390                 }
 391                 return pb.makeError();
 392             }
 393         }
 394 
 395         public void annotation(ParsedElementAnnotation ea) {
 396         }
 397     }
 398 
 399     public DataPatternBuilder makeDataPatternBuilder(String datatypeLibrary, String type, Location loc)
 400             throws BuildException {
 401         DatatypeLibrary dl = datatypeLibraryFactory.createDatatypeLibrary(datatypeLibrary);
 402         if (dl == null) {
 403             error("unrecognized_datatype_library", datatypeLibrary, (Locator) loc);
 404         } else {
 405             try {
 406                 return new DataPatternBuilderImpl(dl.createDatatypeBuilder(type));
 407             } catch (DatatypeException e) {
 408                 String detail = e.getMessage();
 409                 if (detail != null) {
 410                     error("unsupported_datatype_detail", datatypeLibrary, type, detail, (Locator) loc);
 411                 } else {
 412                     error("unrecognized_datatype", datatypeLibrary, type, (Locator) loc);
 413                 }
 414             }
 415         }
 416         return new DummyDataPatternBuilder();
 417     }
 418 
 419     public ParsedPattern makeValue(String datatypeLibrary, String type, String value, Context context, String ns,
 420             Location loc, Annotations anno) throws BuildException {
 421         DatatypeLibrary dl = datatypeLibraryFactory.createDatatypeLibrary(datatypeLibrary);
 422         if (dl == null) {
 423             error("unrecognized_datatype_library", datatypeLibrary, (Locator) loc);
 424         } else {
 425             try {
 426                 DatatypeBuilder dtb = dl.createDatatypeBuilder(type);
 427                 try {
 428                     Datatype dt = dtb.createDatatype();
 429                     Object obj = dt.createValue(value, new ValidationContextImpl(context, ns));
 430                     if (obj != null) {
 431                         return pb.makeValue(dt, obj);
 432                     }
 433                     error("invalid_value", value, (Locator) loc);
 434                 } catch (DatatypeException e) {
 435                     String detail = e.getMessage();
 436                     if (detail != null) {
 437                         error("datatype_requires_param_detail", detail, (Locator) loc);
 438                     } else {
 439                         error("datatype_requires_param", (Locator) loc);
 440                     }
 441                 }
 442             } catch (DatatypeException e) {
 443                 error("unrecognized_datatype", datatypeLibrary, type, (Locator) loc);
 444             }
 445         }
 446         return pb.makeError();
 447     }
 448 
 449     static class GrammarImpl implements Grammar, Div, IncludedGrammar {
 450 
 451         private final SchemaBuilderImpl sb;
 452         private final Hashtable defines;
 453         private final RefPattern startRef;
 454         private final Scope parent;
 455 
 456         private GrammarImpl(SchemaBuilderImpl sb, Scope parent) {
 457             this.sb = sb;
 458             this.parent = parent;
 459             this.defines = new Hashtable();
 460             this.startRef = new RefPattern(null);
 461         }
 462 
 463         protected GrammarImpl(SchemaBuilderImpl sb, GrammarImpl g) {
 464             this.sb = sb;
 465             parent = g.parent;
 466             startRef = g.startRef;
 467             defines = g.defines;
 468         }
 469 
 470         public ParsedPattern endGrammar(Location loc, Annotations anno) throws BuildException {
 471             for (Enumeration e = defines.keys();
 472                     e.hasMoreElements();) {
 473                 String name = (String) e.nextElement();
 474                 RefPattern rp = (RefPattern) defines.get(name);
 475                 if (rp.getPattern() == null) {
 476                     sb.error("reference_to_undefined", name, rp.getRefLocator());
 477                     rp.setPattern(sb.pb.makeError());
 478                 }
 479             }
 480             Pattern start = startRef.getPattern();
 481             if (start == null) {
 482                 sb.error("missing_start_element", (Locator) loc);
 483                 start = sb.pb.makeError();
 484             }
 485             return start;
 486         }
 487 
 488         public void endDiv(Location loc, Annotations anno) throws BuildException {
 489             // nothing to do
 490         }
 491 
 492         public ParsedPattern endIncludedGrammar(Location loc, Annotations anno) throws BuildException {
 493             return null;
 494         }
 495 
 496         public void define(String name, GrammarSection.Combine combine, ParsedPattern pattern, Location loc, Annotations anno)
 497                 throws BuildException {
 498             define(lookup(name), combine, pattern, loc);
 499         }
 500 
 501         private void define(RefPattern rp, GrammarSection.Combine combine, ParsedPattern pattern, Location loc)
 502                 throws BuildException {
 503             switch (rp.getReplacementStatus()) {
 504                 case RefPattern.REPLACEMENT_KEEP:
 505                     if (combine == null) {
 506                         if (rp.isCombineImplicit()) {
 507                             if (rp.getName() == null) {
 508                                 sb.error("duplicate_start", (Locator) loc);
 509                             } else {
 510                                 sb.error("duplicate_define", rp.getName(), (Locator) loc);
 511                             }
 512                         } else {
 513                             rp.setCombineImplicit();
 514                         }
 515                     } else {
 516                         byte combineType = (combine == COMBINE_CHOICE ? RefPattern.COMBINE_CHOICE : RefPattern.COMBINE_INTERLEAVE);
 517                         if (rp.getCombineType() != RefPattern.COMBINE_NONE
 518                                 && rp.getCombineType() != combineType) {
 519                             if (rp.getName() == null) {
 520                                 sb.error("conflict_combine_start", (Locator) loc);
 521                             } else {
 522                                 sb.error("conflict_combine_define", rp.getName(), (Locator) loc);
 523                             }
 524                         }
 525                         rp.setCombineType(combineType);
 526                     }
 527                     Pattern p = (Pattern) pattern;
 528                     if (rp.getPattern() == null) {
 529                         rp.setPattern(p);
 530                     } else if (rp.getCombineType() == RefPattern.COMBINE_INTERLEAVE) {
 531                         rp.setPattern(sb.pb.makeInterleave(rp.getPattern(), p));
 532                     } else {
 533                         rp.setPattern(sb.pb.makeChoice(rp.getPattern(), p));
 534                     }
 535                     break;
 536                 case RefPattern.REPLACEMENT_REQUIRE:
 537                     rp.setReplacementStatus(RefPattern.REPLACEMENT_IGNORE);
 538                     break;
 539                 case RefPattern.REPLACEMENT_IGNORE:
 540                     break;
 541             }
 542         }
 543 
 544         public void topLevelAnnotation(ParsedElementAnnotation ea) throws BuildException {
 545         }
 546 
 547         public void topLevelComment(CommentList comments) throws BuildException {
 548         }
 549 
 550         private RefPattern lookup(String name) {
 551             if (name == START) {
 552                 return startRef;
 553             }
 554             return lookup1(name);
 555         }
 556 
 557         private RefPattern lookup1(String name) {
 558             RefPattern p = (RefPattern) defines.get(name);
 559             if (p == null) {
 560                 p = new RefPattern(name);
 561                 defines.put(name, p);
 562             }
 563             return p;
 564         }
 565 
 566         public ParsedPattern makeRef(String name, Location loc, Annotations anno) throws BuildException {
 567             RefPattern p = lookup1(name);
 568             if (p.getRefLocator() == null && loc != null) {
 569                 p.setRefLocator((Locator) loc);
 570             }
 571             return p;
 572         }
 573 
 574         public ParsedPattern makeParentRef(String name, Location loc, Annotations anno) throws BuildException {
 575             // TODO: do this check by the caller
 576             if (parent == null) {
 577                 sb.error("parent_ref_outside_grammar", (Locator) loc);
 578                 return sb.makeErrorPattern();
 579             }
 580             return parent.makeRef(name, loc, anno);
 581         }
 582 
 583         public Div makeDiv() {
 584             return this;
 585         }
 586 
 587         public Include makeInclude() {
 588             return new IncludeImpl(sb, this);
 589         }
 590     }
 591 
 592     static class Override {
 593 
 594         Override(RefPattern prp, Override next) {
 595             this.prp = prp;
 596             this.next = next;
 597         }
 598         RefPattern prp;
 599         Override next;
 600         byte replacementStatus;
 601     }
 602 
 603     private static class IncludeImpl implements Include, Div {
 604 
 605         private SchemaBuilderImpl sb;
 606         private Override overrides;
 607         private GrammarImpl grammar;
 608 
 609         private IncludeImpl(SchemaBuilderImpl sb, GrammarImpl grammar) {
 610             this.sb = sb;
 611             this.grammar = grammar;
 612         }
 613 
 614         public void define(String name, GrammarSection.Combine combine, ParsedPattern pattern, Location loc, Annotations anno)
 615                 throws BuildException {
 616             RefPattern rp = grammar.lookup(name);
 617             overrides = new Override(rp, overrides);
 618             grammar.define(rp, combine, pattern, loc);
 619         }
 620 
 621         public void endDiv(Location loc, Annotations anno) throws BuildException {
 622             // nothing to do
 623         }
 624 
 625         public void topLevelAnnotation(ParsedElementAnnotation ea) throws BuildException {
 626             // nothing to do
 627         }
 628 
 629         public void topLevelComment(CommentList comments) throws BuildException {
 630         }
 631 
 632         public Div makeDiv() {
 633             return this;
 634         }
 635 
 636         public void endInclude(Parseable current, String uri, String ns,
 637                 Location loc, Annotations anno) throws BuildException {
 638             for (OpenIncludes inc = sb.openIncludes;
 639                     inc != null;
 640                     inc = inc.parent) {
 641                 if (inc.uri.equals(uri)) {
 642                     sb.error("recursive_include", uri, (Locator) loc);
 643                     return;
 644                 }
 645             }
 646 
 647             for (Override o = overrides; o != null; o = o.next) {
 648                 o.replacementStatus = o.prp.getReplacementStatus();
 649                 o.prp.setReplacementStatus(RefPattern.REPLACEMENT_REQUIRE);
 650             }
 651             try {
 652                 SchemaBuilderImpl isb = new SchemaBuilderImpl(ns, uri, sb);
 653                 current.parseInclude(uri, isb, new GrammarImpl(isb, grammar), ns);
 654                 for (Override o = overrides; o != null; o = o.next) {
 655                     if (o.prp.getReplacementStatus() == RefPattern.REPLACEMENT_REQUIRE) {
 656                         if (o.prp.getName() == null) {
 657                             sb.error("missing_start_replacement", (Locator) loc);
 658                         } else {
 659                             sb.error("missing_define_replacement", o.prp.getName(), (Locator) loc);
 660                         }
 661                     }
 662                 }
 663             } catch (IllegalSchemaException e) {
 664                 sb.noteError();
 665             } finally {
 666                 for (Override o = overrides; o != null; o = o.next) {
 667                     o.prp.setReplacementStatus(o.replacementStatus);
 668                 }
 669             }
 670         }
 671 
 672         public Include makeInclude() {
 673             return null;
 674         }
 675     }
 676 
 677     public Grammar makeGrammar(Scope parent) {
 678         return new GrammarImpl(this, parent);
 679     }
 680 
 681     public ParsedPattern annotate(ParsedPattern p, Annotations anno) throws BuildException {
 682         return p;
 683     }
 684 
 685     public ParsedPattern annotateAfter(ParsedPattern p, ParsedElementAnnotation e) throws BuildException {
 686         return p;
 687     }
 688 
 689     public ParsedPattern commentAfter(ParsedPattern p, CommentList comments) throws BuildException {
 690         return p;
 691     }
 692 
 693     public ParsedPattern makeExternalRef(Parseable current, String uri, String ns, Scope scope,
 694             Location loc, Annotations anno)
 695             throws BuildException {
 696         for (OpenIncludes inc = openIncludes;
 697                 inc != null;
 698                 inc = inc.parent) {
 699             if (inc.uri.equals(uri)) {
 700                 error("recursive_include", uri, (Locator) loc);
 701                 return pb.makeError();
 702             }
 703         }
 704         try {
 705             return current.parseExternal(uri, new SchemaBuilderImpl(ns, uri, this), scope, ns);
 706         } catch (IllegalSchemaException e) {
 707             noteError();
 708             return pb.makeError();
 709         }
 710     }
 711 
 712     public Location makeLocation(String systemId, int lineNumber, int columnNumber) {
 713         return new LocatorImpl(systemId, lineNumber, columnNumber);
 714     }
 715 
 716     public Annotations makeAnnotations(CommentList comments, Context context) {
 717         return this;
 718     }
 719 
 720     public ElementAnnotationBuilder makeElementAnnotationBuilder(String ns, String localName, String prefix,
 721             Location loc, CommentList comments, Context context) {
 722         return this;
 723     }
 724 
 725     public CommentList makeCommentList() {
 726         return this;
 727     }
 728 
 729     public void addComment(String value, Location loc) throws BuildException {
 730     }
 731 
 732     public void addAttribute(String ns, String localName, String prefix, String value, Location loc) {
 733         // nothing needed
 734     }
 735 
 736     public void addElement(ParsedElementAnnotation ea) {
 737         // nothing needed
 738     }
 739 
 740     public void addComment(CommentList comments) throws BuildException {
 741         // nothing needed
 742     }
 743 
 744     public void addLeadingComment(CommentList comments) throws BuildException {
 745         // nothing needed
 746     }
 747 
 748     public ParsedElementAnnotation makeElementAnnotation() {
 749         return null;
 750     }
 751 
 752     public void addText(String value, Location loc, CommentList comments) throws BuildException {
 753     }
 754 
 755     public boolean usesComments() {
 756         return false;
 757     }
 758 
 759     private void error(SAXParseException message) throws BuildException {
 760         noteError();
 761         try {
 762             if (eh != null) {
 763                 eh.error(message);
 764             }
 765         } catch (SAXException e) {
 766             throw new BuildException(e);
 767         }
 768     }
 769 
 770     private void error(String key, Locator loc) throws BuildException {
 771         error(new SAXParseException(localizer.message(key), loc));
 772     }
 773 
 774     private void error(String key, String arg, Locator loc) throws BuildException {
 775         error(new SAXParseException(localizer.message(key, arg), loc));
 776     }
 777 
 778     private void error(String key, String arg1, String arg2, Locator loc) throws BuildException {
 779         error(new SAXParseException(localizer.message(key, arg1, arg2), loc));
 780     }
 781 
 782     private void error(String key, String arg1, String arg2, String arg3, Locator loc) throws BuildException {
 783         error(new SAXParseException(localizer.message(key, new Object[]{arg1, arg2, arg3}), loc));
 784     }
 785 
 786     private void noteError() {
 787         if (!hadError && parent != null) {
 788             parent.noteError();
 789         }
 790         hadError = true;
 791     }
 792 }