ohair@286: /* ohair@286: * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. ohair@286: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ohair@286: * ohair@286: * This code is free software; you can redistribute it and/or modify it ohair@286: * under the terms of the GNU General Public License version 2 only, as ohair@286: * published by the Free Software Foundation. Oracle designates this ohair@286: * particular file as subject to the "Classpath" exception as provided ohair@286: * by Oracle in the LICENSE file that accompanied this code. ohair@286: * ohair@286: * This code is distributed in the hope that it will be useful, but WITHOUT ohair@286: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ohair@286: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ohair@286: * version 2 for more details (a copy is included in the LICENSE file that ohair@286: * accompanied this code). ohair@286: * ohair@286: * You should have received a copy of the GNU General Public License version ohair@286: * 2 along with this work; if not, write to the Free Software Foundation, ohair@286: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ohair@286: * ohair@286: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@286: * or visit www.oracle.com if you need additional information or have any ohair@286: * questions. ohair@286: */ ohair@286: /* mkos@408: * Copyright (C) 2004-2012 ohair@286: * ohair@286: * Permission is hereby granted, free of charge, to any person obtaining a copy ohair@286: * of this software and associated documentation files (the "Software"), to deal ohair@286: * in the Software without restriction, including without limitation the rights ohair@286: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ohair@286: * copies of the Software, and to permit persons to whom the Software is ohair@286: * furnished to do so, subject to the following conditions: ohair@286: * ohair@286: * The above copyright notice and this permission notice shall be included in ohair@286: * all copies or substantial portions of the Software. ohair@286: * ohair@286: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ohair@286: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ohair@286: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ohair@286: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ohair@286: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ohair@286: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ohair@286: * THE SOFTWARE. ohair@286: */ ohair@286: package com.sun.xml.internal.rngom.binary; ohair@286: ohair@286: import java.util.Enumeration; ohair@286: import java.util.Hashtable; ohair@286: import java.util.List; ohair@286: ohair@286: import com.sun.xml.internal.rngom.ast.builder.Annotations; ohair@286: import com.sun.xml.internal.rngom.ast.builder.BuildException; ohair@286: import com.sun.xml.internal.rngom.ast.builder.CommentList; ohair@286: import com.sun.xml.internal.rngom.ast.builder.DataPatternBuilder; ohair@286: import com.sun.xml.internal.rngom.ast.builder.Div; ohair@286: import com.sun.xml.internal.rngom.ast.builder.ElementAnnotationBuilder; ohair@286: import com.sun.xml.internal.rngom.ast.builder.Grammar; ohair@286: import com.sun.xml.internal.rngom.ast.builder.GrammarSection; ohair@286: import com.sun.xml.internal.rngom.ast.builder.Include; ohair@286: import com.sun.xml.internal.rngom.ast.builder.IncludedGrammar; ohair@286: import com.sun.xml.internal.rngom.ast.builder.NameClassBuilder; ohair@286: import com.sun.xml.internal.rngom.ast.builder.SchemaBuilder; ohair@286: import com.sun.xml.internal.rngom.ast.builder.Scope; ohair@286: import com.sun.xml.internal.rngom.ast.om.Location; ohair@286: import com.sun.xml.internal.rngom.ast.om.ParsedElementAnnotation; ohair@286: import com.sun.xml.internal.rngom.ast.om.ParsedNameClass; ohair@286: import com.sun.xml.internal.rngom.ast.om.ParsedPattern; ohair@286: import com.sun.xml.internal.rngom.ast.util.LocatorImpl; ohair@286: import com.sun.xml.internal.rngom.dt.builtin.BuiltinDatatypeLibraryFactory; ohair@286: import com.sun.xml.internal.rngom.dt.CascadingDatatypeLibraryFactory; ohair@286: import com.sun.xml.internal.rngom.nc.NameClass; ohair@286: import com.sun.xml.internal.rngom.nc.NameClassBuilderImpl; ohair@286: import com.sun.xml.internal.rngom.parse.Context; ohair@286: import com.sun.xml.internal.rngom.parse.IllegalSchemaException; ohair@286: import com.sun.xml.internal.rngom.parse.Parseable; ohair@286: import com.sun.xml.internal.rngom.util.Localizer; ohair@286: import org.relaxng.datatype.Datatype; ohair@286: import org.relaxng.datatype.DatatypeBuilder; ohair@286: import org.relaxng.datatype.DatatypeException; ohair@286: import org.relaxng.datatype.DatatypeLibrary; ohair@286: import org.relaxng.datatype.DatatypeLibraryFactory; ohair@286: import org.relaxng.datatype.ValidationContext; ohair@286: import org.relaxng.datatype.helpers.DatatypeLibraryLoader; ohair@286: import org.xml.sax.ErrorHandler; ohair@286: import org.xml.sax.Locator; ohair@286: import org.xml.sax.SAXException; ohair@286: import org.xml.sax.SAXParseException; ohair@286: ohair@286: public class SchemaBuilderImpl implements SchemaBuilder, ElementAnnotationBuilder, CommentList { ohair@286: mkos@408: private final SchemaBuilderImpl parent; mkos@408: private boolean hadError = false; mkos@408: private final SchemaPatternBuilder pb; mkos@408: private final DatatypeLibraryFactory datatypeLibraryFactory; mkos@408: private final String inheritNs; mkos@408: private final ErrorHandler eh; mkos@408: private final OpenIncludes openIncludes; mkos@408: private final NameClassBuilder ncb = new NameClassBuilderImpl(); mkos@408: static final Localizer localizer = new Localizer(SchemaBuilderImpl.class); ohair@286: mkos@408: static class OpenIncludes { mkos@408: mkos@408: final String uri; mkos@408: final OpenIncludes parent; mkos@408: mkos@408: OpenIncludes(String uri, OpenIncludes parent) { mkos@408: this.uri = uri; mkos@408: this.parent = parent; mkos@408: } ohair@286: } ohair@286: mkos@408: public ParsedPattern expandPattern(ParsedPattern _pattern) mkos@408: throws BuildException, IllegalSchemaException { ohair@286: Pattern pattern = (Pattern) _pattern; ohair@286: if (!hadError) { ohair@286: try { ohair@286: pattern.checkRecursion(0); ohair@286: pattern = pattern.expand(pb); ohair@286: pattern.checkRestrictions(Pattern.START_CONTEXT, null, null); mkos@408: if (!hadError) { mkos@408: return pattern; mkos@408: } ohair@286: } catch (SAXParseException e) { ohair@286: error(e); ohair@286: } catch (SAXException e) { ohair@286: throw new BuildException(e); ohair@286: } catch (RestrictionViolationException e) { mkos@408: if (e.getName() != null) { ohair@286: error(e.getMessageId(), e.getName().toString(), e mkos@408: .getLocator()); mkos@408: } else { ohair@286: error(e.getMessageId(), e.getLocator()); mkos@408: } ohair@286: } ohair@286: } ohair@286: throw new IllegalSchemaException(); ohair@286: } ohair@286: mkos@408: /** mkos@408: * mkos@408: * @param eh Error handler to receive errors while building the schema. mkos@408: */ mkos@408: public SchemaBuilderImpl(ErrorHandler eh) { mkos@408: this(eh, mkos@408: new CascadingDatatypeLibraryFactory(new DatatypeLibraryLoader(), mkos@408: new BuiltinDatatypeLibraryFactory(new DatatypeLibraryLoader())), mkos@408: new SchemaPatternBuilder()); mkos@408: } ohair@286: mkos@408: /** mkos@408: * mkos@408: * @param eh Error handler to receive errors while building the schema. mkos@408: * @param datatypeLibraryFactory This is consulted to locate datatype mkos@408: * libraries. mkos@408: * @param pb Used to build patterns. mkos@408: */ mkos@408: public SchemaBuilderImpl(ErrorHandler eh, mkos@408: DatatypeLibraryFactory datatypeLibraryFactory, mkos@408: SchemaPatternBuilder pb) { mkos@408: this.parent = null; mkos@408: this.eh = eh; mkos@408: this.datatypeLibraryFactory = datatypeLibraryFactory; mkos@408: this.pb = pb; mkos@408: this.inheritNs = ""; mkos@408: this.openIncludes = null; mkos@408: } ohair@286: mkos@408: private SchemaBuilderImpl(String inheritNs, mkos@408: String uri, mkos@408: SchemaBuilderImpl parent) { mkos@408: this.parent = parent; mkos@408: this.eh = parent.eh; mkos@408: this.datatypeLibraryFactory = parent.datatypeLibraryFactory; mkos@408: this.pb = parent.pb; mkos@408: this.inheritNs = inheritNs; mkos@408: this.openIncludes = new OpenIncludes(uri, parent.openIncludes); mkos@408: } ohair@286: mkos@408: public NameClassBuilder getNameClassBuilder() { mkos@408: return ncb; mkos@408: } ohair@286: mkos@408: public ParsedPattern makeChoice(List patterns, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: if (patterns.isEmpty()) { mkos@408: throw new IllegalArgumentException(); mkos@408: } mkos@408: Pattern result = (Pattern) patterns.get(0); mkos@408: for (int i = 1; i < patterns.size(); i++) { mkos@408: result = pb.makeChoice(result, (Pattern) patterns.get(i)); mkos@408: } mkos@408: return result; mkos@408: } ohair@286: mkos@408: public ParsedPattern makeInterleave(List patterns, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: if (patterns.isEmpty()) { mkos@408: throw new IllegalArgumentException(); mkos@408: } mkos@408: Pattern result = (Pattern) patterns.get(0); mkos@408: for (int i = 1; i < patterns.size(); i++) { mkos@408: result = pb.makeInterleave(result, (Pattern) patterns.get(i)); mkos@408: } mkos@408: return result; mkos@408: } ohair@286: mkos@408: public ParsedPattern makeGroup(List patterns, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: if (patterns.isEmpty()) { mkos@408: throw new IllegalArgumentException(); mkos@408: } mkos@408: Pattern result = (Pattern) patterns.get(0); mkos@408: for (int i = 1; i < patterns.size(); i++) { mkos@408: result = pb.makeGroup(result, (Pattern) patterns.get(i)); mkos@408: } mkos@408: return result; mkos@408: } ohair@286: mkos@408: public ParsedPattern makeOneOrMore(ParsedPattern p, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: return pb.makeOneOrMore((Pattern) p); mkos@408: } ohair@286: mkos@408: public ParsedPattern makeZeroOrMore(ParsedPattern p, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: return pb.makeZeroOrMore((Pattern) p); mkos@408: } ohair@286: mkos@408: public ParsedPattern makeOptional(ParsedPattern p, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: return pb.makeOptional((Pattern) p); mkos@408: } ohair@286: mkos@408: public ParsedPattern makeList(ParsedPattern p, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: return pb.makeList((Pattern) p, (Locator) loc); mkos@408: } ohair@286: mkos@408: public ParsedPattern makeMixed(ParsedPattern p, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: return pb.makeMixed((Pattern) p); mkos@408: } ohair@286: mkos@408: public ParsedPattern makeEmpty(Location loc, Annotations anno) { mkos@408: return pb.makeEmpty(); mkos@408: } ohair@286: mkos@408: public ParsedPattern makeNotAllowed(Location loc, Annotations anno) { mkos@408: return pb.makeUnexpandedNotAllowed(); mkos@408: } ohair@286: mkos@408: public ParsedPattern makeText(Location loc, Annotations anno) { mkos@408: return pb.makeText(); mkos@408: } ohair@286: mkos@408: public ParsedPattern makeErrorPattern() { mkos@408: return pb.makeError(); mkos@408: } ohair@286: ohair@286: // public ParsedNameClass makeErrorNameClass() { ohair@286: // return new ErrorNameClass(); ohair@286: // } mkos@408: public ParsedPattern makeAttribute(ParsedNameClass nc, ParsedPattern p, Location loc, Annotations anno) ohair@286: throws BuildException { mkos@408: return pb.makeAttribute((NameClass) nc, (Pattern) p, (Locator) loc); ohair@286: } ohair@286: mkos@408: public ParsedPattern makeElement(ParsedNameClass nc, ParsedPattern p, Location loc, Annotations anno) ohair@286: throws BuildException { mkos@408: return pb.makeElement((NameClass) nc, (Pattern) p, (Locator) loc); ohair@286: } ohair@286: mkos@408: private class DummyDataPatternBuilder implements DataPatternBuilder { mkos@408: mkos@408: public void addParam(String name, String value, Context context, String ns, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: } mkos@408: mkos@408: public ParsedPattern makePattern(Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: return pb.makeError(); mkos@408: } mkos@408: mkos@408: public ParsedPattern makePattern(ParsedPattern except, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: return pb.makeError(); mkos@408: } mkos@408: mkos@408: public void annotation(ParsedElementAnnotation ea) { mkos@408: } ohair@286: } ohair@286: mkos@408: private static class ValidationContextImpl implements ValidationContext { ohair@286: mkos@408: private ValidationContext vc; mkos@408: private String ns; ohair@286: mkos@408: ValidationContextImpl(ValidationContext vc, String ns) { mkos@408: this.vc = vc; mkos@408: this.ns = ns.length() == 0 ? null : ns; mkos@408: } mkos@408: mkos@408: public String resolveNamespacePrefix(String prefix) { mkos@408: return prefix.length() == 0 ? ns : vc.resolveNamespacePrefix(prefix); mkos@408: } mkos@408: mkos@408: public String getBaseUri() { mkos@408: return vc.getBaseUri(); mkos@408: } mkos@408: mkos@408: public boolean isUnparsedEntity(String entityName) { mkos@408: return vc.isUnparsedEntity(entityName); mkos@408: } mkos@408: mkos@408: public boolean isNotation(String notationName) { mkos@408: return vc.isNotation(notationName); mkos@408: } ohair@286: } ohair@286: mkos@408: private class DataPatternBuilderImpl implements DataPatternBuilder { mkos@408: mkos@408: private DatatypeBuilder dtb; mkos@408: mkos@408: DataPatternBuilderImpl(DatatypeBuilder dtb) { mkos@408: this.dtb = dtb; mkos@408: } mkos@408: mkos@408: public void addParam(String name, String value, Context context, String ns, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: try { mkos@408: dtb.addParameter(name, value, new ValidationContextImpl(context, ns)); mkos@408: } catch (DatatypeException e) { mkos@408: String detail = e.getMessage(); mkos@408: int pos = e.getIndex(); mkos@408: String displayedParam; mkos@408: if (pos == DatatypeException.UNKNOWN) { mkos@408: displayedParam = null; mkos@408: } else { mkos@408: displayedParam = displayParam(value, pos); mkos@408: } mkos@408: if (displayedParam != null) { mkos@408: if (detail != null) { mkos@408: error("invalid_param_detail_display", detail, displayedParam, (Locator) loc); mkos@408: } else { mkos@408: error("invalid_param_display", displayedParam, (Locator) loc); mkos@408: } mkos@408: } else if (detail != null) { mkos@408: error("invalid_param_detail", detail, (Locator) loc); mkos@408: } else { mkos@408: error("invalid_param", (Locator) loc); mkos@408: } mkos@408: } mkos@408: } mkos@408: mkos@408: String displayParam(String value, int pos) { mkos@408: if (pos < 0) { mkos@408: pos = 0; mkos@408: } else if (pos > value.length()) { mkos@408: pos = value.length(); mkos@408: } mkos@408: return localizer.message("display_param", value.substring(0, pos), value.substring(pos)); mkos@408: } mkos@408: mkos@408: public ParsedPattern makePattern(Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: try { mkos@408: return pb.makeData(dtb.createDatatype()); mkos@408: } catch (DatatypeException e) { mkos@408: String detail = e.getMessage(); mkos@408: if (detail != null) { mkos@408: error("invalid_params_detail", detail, (Locator) loc); mkos@408: } else { mkos@408: error("invalid_params", (Locator) loc); mkos@408: } mkos@408: return pb.makeError(); mkos@408: } mkos@408: } mkos@408: mkos@408: public ParsedPattern makePattern(ParsedPattern except, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: try { mkos@408: return pb.makeDataExcept(dtb.createDatatype(), (Pattern) except, (Locator) loc); mkos@408: } catch (DatatypeException e) { mkos@408: String detail = e.getMessage(); mkos@408: if (detail != null) { mkos@408: error("invalid_params_detail", detail, (Locator) loc); mkos@408: } else { mkos@408: error("invalid_params", (Locator) loc); mkos@408: } mkos@408: return pb.makeError(); mkos@408: } mkos@408: } mkos@408: mkos@408: public void annotation(ParsedElementAnnotation ea) { mkos@408: } ohair@286: } ohair@286: mkos@408: public DataPatternBuilder makeDataPatternBuilder(String datatypeLibrary, String type, Location loc) mkos@408: throws BuildException { mkos@408: DatatypeLibrary dl = datatypeLibraryFactory.createDatatypeLibrary(datatypeLibrary); mkos@408: if (dl == null) { mkos@408: error("unrecognized_datatype_library", datatypeLibrary, (Locator) loc); mkos@408: } else { mkos@408: try { mkos@408: return new DataPatternBuilderImpl(dl.createDatatypeBuilder(type)); mkos@408: } catch (DatatypeException e) { mkos@408: String detail = e.getMessage(); mkos@408: if (detail != null) { mkos@408: error("unsupported_datatype_detail", datatypeLibrary, type, detail, (Locator) loc); mkos@408: } else { mkos@408: error("unrecognized_datatype", datatypeLibrary, type, (Locator) loc); mkos@408: } mkos@408: } mkos@408: } mkos@408: return new DummyDataPatternBuilder(); ohair@286: } ohair@286: mkos@408: public ParsedPattern makeValue(String datatypeLibrary, String type, String value, Context context, String ns, mkos@408: Location loc, Annotations anno) throws BuildException { mkos@408: DatatypeLibrary dl = datatypeLibraryFactory.createDatatypeLibrary(datatypeLibrary); mkos@408: if (dl == null) { mkos@408: error("unrecognized_datatype_library", datatypeLibrary, (Locator) loc); mkos@408: } else { mkos@408: try { mkos@408: DatatypeBuilder dtb = dl.createDatatypeBuilder(type); mkos@408: try { mkos@408: Datatype dt = dtb.createDatatype(); mkos@408: Object obj = dt.createValue(value, new ValidationContextImpl(context, ns)); mkos@408: if (obj != null) { mkos@408: return pb.makeValue(dt, obj); mkos@408: } mkos@408: error("invalid_value", value, (Locator) loc); mkos@408: } catch (DatatypeException e) { mkos@408: String detail = e.getMessage(); mkos@408: if (detail != null) { mkos@408: error("datatype_requires_param_detail", detail, (Locator) loc); mkos@408: } else { mkos@408: error("datatype_requires_param", (Locator) loc); mkos@408: } mkos@408: } mkos@408: } catch (DatatypeException e) { mkos@408: error("unrecognized_datatype", datatypeLibrary, type, (Locator) loc); mkos@408: } mkos@408: } mkos@408: return pb.makeError(); ohair@286: } ohair@286: mkos@408: static class GrammarImpl implements Grammar, Div, IncludedGrammar { ohair@286: mkos@408: private final SchemaBuilderImpl sb; mkos@408: private final Hashtable defines; mkos@408: private final RefPattern startRef; mkos@408: private final Scope parent; mkos@408: mkos@408: private GrammarImpl(SchemaBuilderImpl sb, Scope parent) { mkos@408: this.sb = sb; mkos@408: this.parent = parent; mkos@408: this.defines = new Hashtable(); mkos@408: this.startRef = new RefPattern(null); mkos@408: } mkos@408: mkos@408: protected GrammarImpl(SchemaBuilderImpl sb, GrammarImpl g) { mkos@408: this.sb = sb; mkos@408: parent = g.parent; mkos@408: startRef = g.startRef; mkos@408: defines = g.defines; mkos@408: } mkos@408: mkos@408: public ParsedPattern endGrammar(Location loc, Annotations anno) throws BuildException { mkos@408: for (Enumeration e = defines.keys(); mkos@408: e.hasMoreElements();) { mkos@408: String name = (String) e.nextElement(); mkos@408: RefPattern rp = (RefPattern) defines.get(name); mkos@408: if (rp.getPattern() == null) { mkos@408: sb.error("reference_to_undefined", name, rp.getRefLocator()); mkos@408: rp.setPattern(sb.pb.makeError()); mkos@408: } mkos@408: } mkos@408: Pattern start = startRef.getPattern(); mkos@408: if (start == null) { mkos@408: sb.error("missing_start_element", (Locator) loc); mkos@408: start = sb.pb.makeError(); mkos@408: } mkos@408: return start; mkos@408: } mkos@408: mkos@408: public void endDiv(Location loc, Annotations anno) throws BuildException { mkos@408: // nothing to do mkos@408: } mkos@408: mkos@408: public ParsedPattern endIncludedGrammar(Location loc, Annotations anno) throws BuildException { mkos@408: return null; mkos@408: } mkos@408: mkos@408: public void define(String name, GrammarSection.Combine combine, ParsedPattern pattern, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: define(lookup(name), combine, pattern, loc); mkos@408: } mkos@408: mkos@408: private void define(RefPattern rp, GrammarSection.Combine combine, ParsedPattern pattern, Location loc) mkos@408: throws BuildException { mkos@408: switch (rp.getReplacementStatus()) { mkos@408: case RefPattern.REPLACEMENT_KEEP: mkos@408: if (combine == null) { mkos@408: if (rp.isCombineImplicit()) { mkos@408: if (rp.getName() == null) { mkos@408: sb.error("duplicate_start", (Locator) loc); mkos@408: } else { mkos@408: sb.error("duplicate_define", rp.getName(), (Locator) loc); mkos@408: } mkos@408: } else { mkos@408: rp.setCombineImplicit(); mkos@408: } mkos@408: } else { mkos@408: byte combineType = (combine == COMBINE_CHOICE ? RefPattern.COMBINE_CHOICE : RefPattern.COMBINE_INTERLEAVE); mkos@408: if (rp.getCombineType() != RefPattern.COMBINE_NONE mkos@408: && rp.getCombineType() != combineType) { mkos@408: if (rp.getName() == null) { mkos@408: sb.error("conflict_combine_start", (Locator) loc); mkos@408: } else { mkos@408: sb.error("conflict_combine_define", rp.getName(), (Locator) loc); mkos@408: } mkos@408: } mkos@408: rp.setCombineType(combineType); mkos@408: } mkos@408: Pattern p = (Pattern) pattern; mkos@408: if (rp.getPattern() == null) { mkos@408: rp.setPattern(p); mkos@408: } else if (rp.getCombineType() == RefPattern.COMBINE_INTERLEAVE) { mkos@408: rp.setPattern(sb.pb.makeInterleave(rp.getPattern(), p)); mkos@408: } else { mkos@408: rp.setPattern(sb.pb.makeChoice(rp.getPattern(), p)); mkos@408: } mkos@408: break; mkos@408: case RefPattern.REPLACEMENT_REQUIRE: mkos@408: rp.setReplacementStatus(RefPattern.REPLACEMENT_IGNORE); mkos@408: break; mkos@408: case RefPattern.REPLACEMENT_IGNORE: mkos@408: break; mkos@408: } mkos@408: } mkos@408: mkos@408: public void topLevelAnnotation(ParsedElementAnnotation ea) throws BuildException { mkos@408: } mkos@408: mkos@408: public void topLevelComment(CommentList comments) throws BuildException { mkos@408: } mkos@408: mkos@408: private RefPattern lookup(String name) { mkos@408: if (name == START) { mkos@408: return startRef; mkos@408: } mkos@408: return lookup1(name); mkos@408: } mkos@408: mkos@408: private RefPattern lookup1(String name) { mkos@408: RefPattern p = (RefPattern) defines.get(name); mkos@408: if (p == null) { mkos@408: p = new RefPattern(name); mkos@408: defines.put(name, p); mkos@408: } mkos@408: return p; mkos@408: } mkos@408: mkos@408: public ParsedPattern makeRef(String name, Location loc, Annotations anno) throws BuildException { mkos@408: RefPattern p = lookup1(name); mkos@408: if (p.getRefLocator() == null && loc != null) { mkos@408: p.setRefLocator((Locator) loc); mkos@408: } mkos@408: return p; mkos@408: } mkos@408: mkos@408: public ParsedPattern makeParentRef(String name, Location loc, Annotations anno) throws BuildException { mkos@408: // TODO: do this check by the caller mkos@408: if (parent == null) { mkos@408: sb.error("parent_ref_outside_grammar", (Locator) loc); mkos@408: return sb.makeErrorPattern(); mkos@408: } mkos@408: return parent.makeRef(name, loc, anno); mkos@408: } mkos@408: mkos@408: public Div makeDiv() { mkos@408: return this; mkos@408: } mkos@408: mkos@408: public Include makeInclude() { mkos@408: return new IncludeImpl(sb, this); mkos@408: } ohair@286: } ohair@286: mkos@408: static class Override { mkos@408: mkos@408: Override(RefPattern prp, Override next) { mkos@408: this.prp = prp; mkos@408: this.next = next; ohair@286: } mkos@408: RefPattern prp; mkos@408: Override next; mkos@408: byte replacementStatus; ohair@286: } ohair@286: mkos@408: private static class IncludeImpl implements Include, Div { mkos@408: mkos@408: private SchemaBuilderImpl sb; mkos@408: private Override overrides; mkos@408: private GrammarImpl grammar; mkos@408: mkos@408: private IncludeImpl(SchemaBuilderImpl sb, GrammarImpl grammar) { mkos@408: this.sb = sb; mkos@408: this.grammar = grammar; mkos@408: } mkos@408: mkos@408: public void define(String name, GrammarSection.Combine combine, ParsedPattern pattern, Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: RefPattern rp = grammar.lookup(name); mkos@408: overrides = new Override(rp, overrides); mkos@408: grammar.define(rp, combine, pattern, loc); mkos@408: } mkos@408: mkos@408: public void endDiv(Location loc, Annotations anno) throws BuildException { mkos@408: // nothing to do mkos@408: } mkos@408: mkos@408: public void topLevelAnnotation(ParsedElementAnnotation ea) throws BuildException { mkos@408: // nothing to do mkos@408: } mkos@408: mkos@408: public void topLevelComment(CommentList comments) throws BuildException { mkos@408: } mkos@408: mkos@408: public Div makeDiv() { mkos@408: return this; mkos@408: } mkos@408: mkos@408: public void endInclude(Parseable current, String uri, String ns, mkos@408: Location loc, Annotations anno) throws BuildException { mkos@408: for (OpenIncludes inc = sb.openIncludes; mkos@408: inc != null; mkos@408: inc = inc.parent) { mkos@408: if (inc.uri.equals(uri)) { mkos@408: sb.error("recursive_include", uri, (Locator) loc); mkos@408: return; mkos@408: } mkos@408: } mkos@408: mkos@408: for (Override o = overrides; o != null; o = o.next) { mkos@408: o.replacementStatus = o.prp.getReplacementStatus(); mkos@408: o.prp.setReplacementStatus(RefPattern.REPLACEMENT_REQUIRE); mkos@408: } mkos@408: try { mkos@408: SchemaBuilderImpl isb = new SchemaBuilderImpl(ns, uri, sb); mkos@408: current.parseInclude(uri, isb, new GrammarImpl(isb, grammar), ns); mkos@408: for (Override o = overrides; o != null; o = o.next) { mkos@408: if (o.prp.getReplacementStatus() == RefPattern.REPLACEMENT_REQUIRE) { mkos@408: if (o.prp.getName() == null) { mkos@408: sb.error("missing_start_replacement", (Locator) loc); mkos@408: } else { mkos@408: sb.error("missing_define_replacement", o.prp.getName(), (Locator) loc); mkos@408: } mkos@408: } mkos@408: } mkos@408: } catch (IllegalSchemaException e) { mkos@408: sb.noteError(); mkos@408: } finally { mkos@408: for (Override o = overrides; o != null; o = o.next) { mkos@408: o.prp.setReplacementStatus(o.replacementStatus); mkos@408: } mkos@408: } mkos@408: } mkos@408: mkos@408: public Include makeInclude() { mkos@408: return null; mkos@408: } ohair@286: } ohair@286: mkos@408: public Grammar makeGrammar(Scope parent) { mkos@408: return new GrammarImpl(this, parent); ohair@286: } ohair@286: mkos@408: public ParsedPattern annotate(ParsedPattern p, Annotations anno) throws BuildException { mkos@408: return p; ohair@286: } ohair@286: mkos@408: public ParsedPattern annotateAfter(ParsedPattern p, ParsedElementAnnotation e) throws BuildException { mkos@408: return p; ohair@286: } ohair@286: mkos@408: public ParsedPattern commentAfter(ParsedPattern p, CommentList comments) throws BuildException { mkos@408: return p; ohair@286: } ohair@286: mkos@408: public ParsedPattern makeExternalRef(Parseable current, String uri, String ns, Scope scope, mkos@408: Location loc, Annotations anno) mkos@408: throws BuildException { mkos@408: for (OpenIncludes inc = openIncludes; mkos@408: inc != null; mkos@408: inc = inc.parent) { mkos@408: if (inc.uri.equals(uri)) { mkos@408: error("recursive_include", uri, (Locator) loc); mkos@408: return pb.makeError(); mkos@408: } ohair@286: } mkos@408: try { mkos@408: return current.parseExternal(uri, new SchemaBuilderImpl(ns, uri, this), scope, ns); mkos@408: } catch (IllegalSchemaException e) { mkos@408: noteError(); mkos@408: return pb.makeError(); mkos@408: } ohair@286: } ohair@286: mkos@408: public Location makeLocation(String systemId, int lineNumber, int columnNumber) { mkos@408: return new LocatorImpl(systemId, lineNumber, columnNumber); ohair@286: } ohair@286: mkos@408: public Annotations makeAnnotations(CommentList comments, Context context) { mkos@408: return this; mkos@408: } mkos@408: mkos@408: public ElementAnnotationBuilder makeElementAnnotationBuilder(String ns, String localName, String prefix, mkos@408: Location loc, CommentList comments, Context context) { mkos@408: return this; mkos@408: } mkos@408: mkos@408: public CommentList makeCommentList() { mkos@408: return this; mkos@408: } mkos@408: mkos@408: public void addComment(String value, Location loc) throws BuildException { mkos@408: } mkos@408: mkos@408: public void addAttribute(String ns, String localName, String prefix, String value, Location loc) { mkos@408: // nothing needed mkos@408: } mkos@408: mkos@408: public void addElement(ParsedElementAnnotation ea) { mkos@408: // nothing needed mkos@408: } mkos@408: mkos@408: public void addComment(CommentList comments) throws BuildException { mkos@408: // nothing needed mkos@408: } mkos@408: mkos@408: public void addLeadingComment(CommentList comments) throws BuildException { mkos@408: // nothing needed mkos@408: } mkos@408: mkos@408: public ParsedElementAnnotation makeElementAnnotation() { ohair@286: return null; ohair@286: } ohair@286: mkos@408: public void addText(String value, Location loc, CommentList comments) throws BuildException { ohair@286: } ohair@286: mkos@408: public boolean usesComments() { mkos@408: return false; ohair@286: } ohair@286: mkos@408: private void error(SAXParseException message) throws BuildException { mkos@408: noteError(); mkos@408: try { mkos@408: if (eh != null) { mkos@408: eh.error(message); mkos@408: } mkos@408: } catch (SAXException e) { mkos@408: throw new BuildException(e); mkos@408: } ohair@286: } ohair@286: mkos@408: private void error(String key, Locator loc) throws BuildException { mkos@408: error(new SAXParseException(localizer.message(key), loc)); ohair@286: } ohair@286: mkos@408: private void error(String key, String arg, Locator loc) throws BuildException { mkos@408: error(new SAXParseException(localizer.message(key, arg), loc)); ohair@286: } ohair@286: mkos@408: private void error(String key, String arg1, String arg2, Locator loc) throws BuildException { mkos@408: error(new SAXParseException(localizer.message(key, arg1, arg2), loc)); ohair@286: } ohair@286: mkos@408: private void error(String key, String arg1, String arg2, String arg3, Locator loc) throws BuildException { mkos@408: error(new SAXParseException(localizer.message(key, new Object[]{arg1, arg2, arg3}), loc)); ohair@286: } ohair@286: mkos@408: private void noteError() { mkos@408: if (!hadError && parent != null) { mkos@408: parent.noteError(); mkos@408: } mkos@408: hadError = true; ohair@286: } ohair@286: }