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

com.sun.msv.reader.trex.classic.TREXGrammarReader 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.classic;

import java.text.MessageFormat;
import java.util.ResourceBundle;

import javax.xml.parsers.SAXParserFactory;

import org.relaxng.datatype.Datatype;
import org.relaxng.datatype.DatatypeException;
import org.xml.sax.InputSource;

import com.sun.msv.datatype.xsd.StringType;
import com.sun.msv.datatype.xsd.XSDatatype;
import com.sun.msv.grammar.Expression;
import com.sun.msv.grammar.ExpressionPool;
import com.sun.msv.grammar.trex.TREXGrammar;
import com.sun.msv.reader.GrammarReaderController;
import com.sun.msv.reader.IgnoreState;
import com.sun.msv.reader.RunAwayExpressionChecker;
import com.sun.msv.reader.State;
import com.sun.msv.reader.TerminalState;
import com.sun.msv.reader.datatype.DataTypeVocabulary;
import com.sun.msv.reader.datatype.xsd.XSDatatypeExp;
import com.sun.msv.reader.datatype.xsd.XSDatatypeResolver;
import com.sun.msv.reader.trex.IncludePatternState;
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.StartTagInfo;

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

    
    /** easy-to-use constructor. */
    public TREXGrammarReader( GrammarReaderController controller) {
        this(controller,createParserFactory(),new ExpressionPool());
    }

    /** easy-to-use constructor. */
    public TREXGrammarReader(
        GrammarReaderController controller,
        SAXParserFactory parserFactory,
        ExpressionPool pool ) {
        this(controller,parserFactory,new StateFactory(),pool);
    }
    
    /** full constructor */
    public TREXGrammarReader(
        GrammarReaderController controller,
        SAXParserFactory parserFactory,
        StateFactory stateFactory,
        ExpressionPool pool ) {
        
        super( controller, parserFactory, pool, stateFactory, new RootState() );
    }
    
    protected String localizeMessage( String propertyName, Object[] args ) {
        String format;
        
        try {
            format = ResourceBundle.getBundle("com.sun.msv.reader.trex.classic.Messages").getString(propertyName);
        } catch( Exception e ) {
            return super.localizeMessage(propertyName,args);
        }
        
        return MessageFormat.format(format, args );
    }
    
    
    /**
     * TREX allows either
     *    (1) the predefined namespace for TREX or
     *    (2) default namespace ""
     * 
     *  as its namespace. This variable holds which namespace is currently in use.
     */
    protected String currentGrammarURI;
    
    
    protected TREXGrammar getGrammar() {
        return grammar;
    }
    
    /** Namespace URI of TREX */
    public static final String TREXNamespace = "http://www.thaiopensource.com/trex";

    protected boolean isGrammarElement( StartTagInfo tag ) {
        if( currentGrammarURI==null ) {
            // first time.
            if( tag.namespaceURI.equals(TREXNamespace) ) {
                currentGrammarURI = TREXNamespace;
                return true;
            }
            if( tag.namespaceURI.equals("") ) {
                currentGrammarURI = "";
                return true;
            }
            return false;
        } else {
            if(currentGrammarURI.equals(tag.namespaceURI))    return true;
            if(tag.containsAttribute(TREXNamespace,"role"))    return true;
            
            return false;
        }
    }
    
    /**
     * 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 concur        ( State parent, StartTagInfo tag )    { return new ConcurState(); }
        public State anyString    ( State parent, StartTagInfo tag )    { return new TerminalState(Expression.anyString); }
        public State string        ( State parent, StartTagInfo tag )    { return new StringState(); }
        public State data        ( State parent, StartTagInfo tag )    { return new DataState(); }
        public State define        ( State parent, StartTagInfo tag )    { return new DefineState(); }
        public State includePattern( State parent, StartTagInfo tag ) { return new IncludePatternState(); }
    }
    protected StateFactory getStateFactory() {
        return (StateFactory)super.sfactory;
    }
    
    private boolean issueObsoletedXMLSchemaNamespace = false;
    /**
     * maps obsoleted XML Schema namespace to the current one.
     */
    private String mapNamespace( String namespace ) {
        if(namespace.equals("http://www.w3.org/2000/10/XMLSchema")
        || namespace.equals("http://www.w3.org/2000/10/XMLSchema-datatypes")) {
            // namespace of CR version.
            if( !issueObsoletedXMLSchemaNamespace )
                // report warning only once.
                reportWarning(WRN_OBSOLETED_XMLSCHEMA_NAMSPACE,namespace);
            issueObsoletedXMLSchemaNamespace = true;
            return com.sun.msv.reader.datatype.xsd.XSDVocabulary.XMLSchemaNamespace;
        }
        return namespace;
    }
    
    public State createExpressionChildState( State parent, StartTagInfo tag )
    {
        if(tag.localName.equals("concur"))        return getStateFactory().concur(parent,tag);
        if(tag.localName.equals("anyString"))    return getStateFactory().anyString(parent,tag);
        if(tag.localName.equals("string"))        return getStateFactory().string(parent,tag);
        if(tag.localName.equals("data"))        return getStateFactory().data(parent,tag);
        if(tag.localName.equals("include"))        return getStateFactory().includePattern(parent,tag);

        final String role = tag.getAttribute(TREXNamespace,"role");
        if("datatype".equals(role)) {
            String namespaceURI = mapNamespace(tag.namespaceURI);
            DataTypeVocabulary v = grammar.dataTypes.get(namespaceURI);
        
            if(v==null) {
                reportError( ERR_UNKNOWN_DATATYPE_VOCABULARY, tag.namespaceURI );
                // put a dummy vocabulary into the map
                // so that user will never receive the same error again.
                grammar.dataTypes.put( tag.namespaceURI, new UndefinedDataTypeVocabulary() );
                return new IgnoreState();    // recover by ignoring this element.
            }            
            
            return v.createTopLevelReaderState(tag);
        }
            
        
        return super.createExpressionChildState(parent,tag);
    }

    public XSDatatypeExp resolveXSDatatype( String qName ) {
        return new XSDatatypeExp( (XSDatatype)resolveDatatype(qName),pool);
    }
    
    /** obtains a named DataType object referenced by a QName.
     */
    public Datatype resolveDatatype( String qName ) {
        String[] s = splitQName(qName);
        if(s==null) {
            reportError( ERR_UNDECLARED_PREFIX, qName );
            // recover by using a dummy DataType
            return StringType.theInstance;
        }
        
        s[0] = mapNamespace(s[0]);    // s[0] == namespace URI
        
        DataTypeVocabulary v = grammar.dataTypes.get(s[0]);
        if(v==null) {
            reportError( ERR_UNKNOWN_DATATYPE_VOCABULARY, s[0] );
            // put a dummy vocabulary into the map
            // so that user will never receive the same error again.
            grammar.dataTypes.put( s[0], new UndefinedDataTypeVocabulary() );
        } else {
            try {
                return v.getType( s[1] );    // s[1] == local name
            } catch( DatatypeException e ) {
                reportError( ERR_UNDEFINED_DATATYPE, qName );
            }
        }
        // recover by using a dummy DataType
        return StringType.theInstance;
    }


    
    public void wrapUp() {
        
        // make sure that there is no recurisve patterns.
        RunAwayExpressionChecker.check(this,grammar);
        
        if( !controller.hadError() )
            // make sure that there is no sequenced string.
            // when run-away expression is found, calling this method results in
            // stack overflow.
            grammar.visit( new TREXSequencedStringChecker(this,false) );
    }
    
    
    /**
     * Dummy DataTypeVocabulary for better error recovery.
     * 
     * If DataTypeVocabulary is not found, the error is reported
     * and this class is used to prevent further repetitive error messages.
     */
    private static class UndefinedDataTypeVocabulary implements DataTypeVocabulary
    {
        public State createTopLevelReaderState( StartTagInfo tag )
        { return new IgnoreState(); }    // ignore everything
        public Datatype getType( String localTypeName )
        { return StringType.theInstance; }    // accepts any type name

    }

    // error messages
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy