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