All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.msv.reader.trex.ng.RELAXNGReader Maven / Gradle / Ivy

There is a newer version: 2.3.0
Show newest version
/*
 * Copyright (c) 2001-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.sun.msv.reader.trex.ng;

import java.text.MessageFormat;
import java.util.Iterator;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.Stack;
import java.util.Vector;

import javax.xml.parsers.SAXParserFactory;

import org.iso_relax.verifier.Schema;
import org.relaxng.datatype.Datatype;
import org.relaxng.datatype.DatatypeException;
import org.relaxng.datatype.DatatypeLibrary;
import org.relaxng.datatype.DatatypeLibraryFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

import com.sun.msv.datatype.ErrorDatatypeLibrary;
import com.sun.msv.grammar.Expression;
import com.sun.msv.grammar.ExpressionPool;
import com.sun.msv.grammar.ReferenceExp;
import com.sun.msv.grammar.trex.TREXGrammar;
import com.sun.msv.reader.ChoiceState;
import com.sun.msv.reader.GrammarReaderController;
import com.sun.msv.reader.State;
import com.sun.msv.reader.TerminalState;
import com.sun.msv.reader.trex.DivInGrammarState;
import com.sun.msv.reader.trex.IncludePatternState;
import com.sun.msv.reader.trex.NameClassChoiceState;
import com.sun.msv.reader.trex.RootState;
import com.sun.msv.reader.trex.TREXBaseReader;
import com.sun.msv.reader.trex.TREXSequencedStringChecker;
import com.sun.msv.util.LightStack;
import com.sun.msv.util.StartTagInfo;
import com.sun.msv.util.Util;

/**
 * reads RELAX NG grammar from SAX2 and constructs abstract grammar model.
 * 
 * @author Kohsuke KAWAGUCHI
 */
public class RELAXNGReader extends TREXBaseReader {
    
    /** loads RELAX NG pattern */
    public static TREXGrammar parse( String grammarURL,
        SAXParserFactory factory, GrammarReaderController controller )
    {
        RELAXNGReader reader = new RELAXNGReader(controller,factory);
        reader.parse(grammarURL);
        
        return reader.getResult();
    }
    
    /** loads RELAX NG pattern */
    public static TREXGrammar parse( InputSource grammar,
        SAXParserFactory factory, GrammarReaderController controller )
    {
        RELAXNGReader reader = new RELAXNGReader(controller,factory);
        reader.parse(grammar);
        
        return reader.getResult();
    }

    /** easy-to-use constructor. */
    public RELAXNGReader( GrammarReaderController controller ) {
        this(controller,createParserFactory());
    }
    
    /** easy-to-use constructor. */
    public RELAXNGReader(
        GrammarReaderController controller,
        SAXParserFactory parserFactory) {
        // TODO: add s4s
        this(controller,parserFactory,new StateFactory(),new ExpressionPool());
    }
    
    /** full constructor */
    public RELAXNGReader(
        GrammarReaderController controller,
        SAXParserFactory parserFactory,
        StateFactory stateFactory,
        ExpressionPool pool ) {
        
        super( controller, parserFactory, pool, stateFactory, new RootState() );
    }
    
    

    
    /**
     * Schema for schema of RELAX NG.
     */
    protected static Schema relaxNGSchema4Schema = null;
    
    public static Schema getRELAXNGSchema4Schema() {
        
        // under the multi-thread environment, more than once s4s could be loaded.
        // it's a waste of resource, but by no means fatal.
        if(relaxNGSchema4Schema==null) {
            try {
                relaxNGSchema4Schema =
                    new com.sun.msv.verifier.jarv.RELAXNGFactoryImpl().compileSchema(
                        RELAXNGReader.class.getResourceAsStream("relaxng.rng"));
            } catch( Exception e ) {
                e.printStackTrace();
                throw new Error("unable to load schema-for-schema for RELAX NG");
            }
        }
        
        return relaxNGSchema4Schema;
    }
    
    
    
    
    protected String localizeMessage( String propertyName, Object[] args ) {
        String format;
        
        try {
            format = ResourceBundle.getBundle("com.sun.msv.reader.trex.ng.Messages").getString(propertyName);
        } catch( Exception e ) {
            return super.localizeMessage(propertyName,args);
        }
        
        return MessageFormat.format(format, args );
    }
    
    protected TREXGrammar getGrammar() {
        return grammar;
    }
    
    /** Map from ReferenceExps to RefExpParseInfos. */
    private final Map refExpParseInfos = new java.util.HashMap();
    
    /** Gets RefExpParseInfo object for the specified ReferenceExp. */
    protected RefExpParseInfo getRefExpParseInfo( ReferenceExp exp ) {
        RefExpParseInfo r = (RefExpParseInfo)refExpParseInfos.get(exp);
        if(r==null)
            refExpParseInfos.put(exp, r = new RefExpParseInfo());
        return r;
    }
    
    /**
     * Info about the current ReferenceExp object which is being defined.
     * This field is maintained by DefineState.
     * 

* This field is set to null when there is an error, or the pattern being * defined is being re-defined. * *

* This is a part of the process of the recursive self reference error detection. */ protected RefExpParseInfo currentNamedPattern = null; /** * Flag to indicate whether we saw <element> or not. If we don't see * any <element> between <define>/<start> and <ref>/<parentRef>, * then that reference will go to currentNamedPattern.refs. * *

* This is a part of the process of the recursive self reference error detection. */ protected boolean directRefernce = true; /** * information necessary to correctly parse pattern definitions. */ protected static class RefExpParseInfo { /** * This field is set to true once the head declaration is found. * A head declaration is a define element without the combine attribute. * It is an error that two head declarations share the same name. */ public boolean haveHead = false; /** * The combine method which is used to combine this pattern. * this field is set to null if combine attribute is not yet used. */ public String combineMethod = null; public static class RedefinitionStatus {} /** * This named pattern is not being redefined. * So it will be a part of the grammar. */ public static RedefinitionStatus notBeingRedefined = new RedefinitionStatus(); /** * This named pattern is being redefined. So even if we'll see some * <define> with this name, it will not be a part of the grammar. * This state means that we don't yet see the definition of the original. * We need to issue an error if the pattern is redefined but there is no original * in the included grammar. */ public static RedefinitionStatus originalNotFoundYet = new RedefinitionStatus(); /** * The same as {@link #originalNotFoundYet}, but we saw the original definition. */ public static RedefinitionStatus originalFound = new RedefinitionStatus(); /** * Current redefinition status. */ public RedefinitionStatus redefinition = notBeingRedefined; /** * Copies the contents of rhs into this object. */ public void set( RefExpParseInfo rhs ) { this.haveHead = rhs.haveHead; this.combineMethod = rhs.combineMethod; this.redefinition = rhs.redefinition; } /** * ReferenceExps which are referenced from this pattern directly * (without having ElementExp in between.) * *

* This is used to detect recursive self reference errors. */ public final Vector directRefs = new Vector(); /** * ReferenceExps which are referenced from this pattern indirectly * (with ElementExp in between.) */ public final Vector indirectRefs = new Vector(); } /** Namespace URI of RELAX NG */ public static final String RELAXNGNamespace = "http://relaxng.org/ns/structure/1.0"; protected boolean isGrammarElement( StartTagInfo tag ) { return RELAXNGNamespace.equals(tag.namespaceURI) // allow old namespace URI for now. || "http://relaxng.org/ns/structure/0.9".equals(tag.namespaceURI); } /** * DatatypeLibrary factory object. */ private DatatypeLibraryFactory datatypeLibraryFactory = new DefaultDatatypeLibraryFactory(); /** * Returns the datatypeLibraryFactory. */ public DatatypeLibraryFactory getDatatypeLibraryFactory() { return datatypeLibraryFactory; } /** * Sets the datatypeLibraryFactory. */ public void setDatatypeLibraryFactory(DatatypeLibraryFactory datatypeLibraryFactory) { this.datatypeLibraryFactory = datatypeLibraryFactory; } /** * creates various State object, which in turn parses grammar. * parsing behavior can be customized by implementing custom StateFactory. */ public static class StateFactory extends TREXBaseReader.StateFactory { public State nsAnyName ( State parent, StartTagInfo tag ) { return new NGNameState.AnyNameState(); } public State nsNsName ( State parent, StartTagInfo tag ) { return new NGNameState.NsNameState(); } public State nsExcept ( State parent, StartTagInfo tag ) { return new NameClassChoiceState(); } public State text ( State parent, StartTagInfo tag ) { return new TerminalState(Expression.anyString); } public State data ( State parent, StartTagInfo tag ) { return new DataState(); } public State dataParam ( State parent, StartTagInfo tag ) { return new DataParamState(); } public State value ( State parent, StartTagInfo tag ) { return new ValueState(); } public State list ( State parent, StartTagInfo tag ) { return new ListState(); } public State define ( State parent, StartTagInfo tag ) { return new DefineState(); } public State start ( State parent, StartTagInfo tag ) { return new StartState(); } public State redefine ( State parent, StartTagInfo tag ) { return new DefineState(); } public State redefineStart ( State parent, StartTagInfo tag ) { return new StartState(); } public State includeGrammar ( State parent, StartTagInfo tag ) { return new IncludeMergeState(); } public State externalRef ( State parent, StartTagInfo tag ) { return new IncludePatternState(); } public State divInGrammar ( State parent, StartTagInfo tag ) { return new DivInGrammarState(); } public State dataExcept ( State parent, StartTagInfo tag ) { return new ChoiceState(); } public State attribute ( State parent, StartTagInfo tag ) { return new AttributeState(); } public State element ( State parent, StartTagInfo tag ) { return new ElementState(); } public State grammar ( State parent, StartTagInfo tag ) { return new GrammarState(); } public State ref ( State parent, StartTagInfo tag ) { return new RefState(false); } public State parentRef ( State parent, StartTagInfo tag ) { return new RefState(true); } /** * to cause errors if someone is deriving this method. * this method is no longer used. * * @deprecated */ protected final DatatypeLibrary getDatatypeLibrary( String namespaceURI ) throws Exception { // unused throw new UnsupportedOperationException(); } } protected StateFactory getStateFactory() { return (StateFactory)super.sfactory; } protected State createNameClassChildState( State parent, StartTagInfo tag ) { if(tag.localName.equals("name")) return sfactory.nsName(parent,tag); if(tag.localName.equals("anyName")) return sfactory.nsAnyName(parent,tag); if(tag.localName.equals("nsName")) return sfactory.nsNsName(parent,tag); if(tag.localName.equals("choice")) return sfactory.nsChoice(parent,tag); return null; // unknown element. let the default error be thrown. } public State createExpressionChildState( State parent, StartTagInfo tag ) { if(tag.localName.equals("text")) return getStateFactory().text(parent,tag); if(tag.localName.equals("data")) return getStateFactory().data(parent,tag); if(tag.localName.equals("value")) return getStateFactory().value(parent,tag); if(tag.localName.equals("list")) return getStateFactory().list(parent,tag); if(tag.localName.equals("externalRef")) return getStateFactory().externalRef(parent,tag); if(tag.localName.equals("parentRef")) return getStateFactory().parentRef(parent,tag); return super.createExpressionChildState(parent,tag); } /** obtains a named DataType object referenced by a local name. */ public Datatype resolveDataType( String localName ) { try { return getCurrentDatatypeLibrary().createDatatype(localName); } catch( DatatypeException dte ) { reportError( ERR_UNDEFINED_DATATYPE_1, localName, dte.getMessage() ); return com.sun.msv.datatype.xsd.StringType.theInstance; } } /** * obtains the DataTypeLibrary that represents the specified namespace URI. * * If the specified URI is undefined, then this method issues an error to * the user and must return a dummy datatype library. */ public DatatypeLibrary resolveDataTypeLibrary( String uri ) { try { DatatypeLibrary lib = datatypeLibraryFactory.createDatatypeLibrary(uri); if(lib!=null) return lib; // issue an error reportError( ERR_UNKNOWN_DATATYPE_VOCABULARY, uri ); } catch( Throwable e ) { reportError( ERR_UNKNOWN_DATATYPE_VOCABULARY_1, uri, e.toString() ); } return ErrorDatatypeLibrary.theInstance; } private static class AbortException extends Exception {} private void checkRunawayExpression( ReferenceExp node, Stack items, Set visitedExps ) throws AbortException { if( !visitedExps.add(node) ) return; // this ReferenceExp has already been processed. items.push(node); // test direct references Iterator itr = getRefExpParseInfo(node).directRefs.iterator(); while( itr.hasNext() ) { ReferenceExp child = (ReferenceExp)itr.next(); int idx = items.lastIndexOf(child); if(idx!=-1) { // find a cycle. String s = ""; Vector locs = new Vector(); for( ; idx=0 ) reportError( ERR_FRAGMENT_IDENTIFIER, datatypeLibURI ); } // if nothing specified, datatype library stays the same. super.startElement(a,b,c,d); } public void endElement( String a, String b, String c ) throws SAXException { super.endElement(a,b,c); datatypeLib = (DatatypeLibrary)dtLibStack.pop(); datatypeLibURI = (String)dtLibURIStack.pop(); } // error messages public static final String ERR_BAD_FACET = // arg:2 "RELAXNGReader.BadFacet"; public static final String ERR_INVALID_PARAMETERS = // arg:1 "RELAXNGReader.InvalidParameters"; public static final String ERR_BAD_DATA_VALUE = // arg:2 "RELAXNGReader.BadDataValue"; public static final String ERR_UNDEFINED_KEY = // arg:1 "RELAXNGReader.UndefinedKey"; public static final String ERR_UNDEFINED_DATATYPE_1 = // arg:2 "RELAXNGReader.UndefinedDataType1"; public static final String ERR_INCONSISTENT_KEY_TYPE = // arg:1 "RELAXNGReader.InconsistentKeyType"; public static final String ERR_INCONSISTENT_COMBINE = // arg:1 "RELAXNGReader.InconsistentCombine"; public static final String ERR_REDEFINING_UNDEFINED = // arg:1 "RELAXNGReader.RedefiningUndefined"; public static final String ERR_UNKNOWN_DATATYPE_VOCABULARY_1 = // arg:2 "RELAXNGReader.UnknownDatatypeVocabulary1"; public static final String ERR_MULTIPLE_EXCEPT = // arg:0 "RELAXNGReader.MultipleExcept"; public static final String ERR_NOT_ABSOLUTE_URI = // arg:1 "RELAXNGReader.NotAbsoluteURI"; public static final String ERR_INFOSET_URI_ATTRIBUTE = // arg:0 "RELAXNGReader.InfosetUriAttribute"; public static final String ERR_XMLNS_ATTRIBUTE = // arg:0 "RELAXNGReader.XmlnsAttribute"; public static final String ERR_NAKED_INFINITE_ATTRIBUTE_NAMECLASS = //arg:0 "RELAXNGReader.NakedInfiniteAttributeNameClass"; }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy