src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCRuntime.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 397
b99d7e355d4b
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 2012, 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  */
    26 package com.sun.tools.internal.jxc.gen.config;
    28 import java.text.MessageFormat;
    29 import java.util.ArrayList;
    30 import java.util.Stack;
    31 import java.util.StringTokenizer;
    33 import org.xml.sax.Attributes;
    34 import org.xml.sax.ContentHandler;
    35 import org.xml.sax.Locator;
    36 import org.xml.sax.SAXException;
    37 import org.xml.sax.SAXParseException;
    39 /**
    40  * Runtime Engine for RELAXNGCC execution.
    41  *
    42  * This class has the following functionalities:
    43  *
    44  * <ol>
    45  *  <li>Managing a stack of NGCCHandler objects and
    46  *      switching between them appropriately.
    47  *
    48  *  <li>Keep track of all Attributes.
    49  *
    50  *  <li>manage mapping between namespace URIs and prefixes.
    51  *
    52  *  <li>TODO: provide support for interleaving.
    53  * <p><b>
    54  *     Auto-generated, do not edit.
    55  * </b></p>
    56  * @version $Id: NGCCRuntime.java,v 1.15 2002/09/29 02:55:48 okajima Exp $
    57  * @author Kohsuke Kawaguchi (kk@kohsuke.org)
    58  */
    59 public class NGCCRuntime implements ContentHandler, NGCCEventSource {
    61     public NGCCRuntime() {
    62         reset();
    63     }
    65     /**
    66      * Sets the root handler, which will be used to parse the
    67      * root element.
    68      * <p>
    69      * This method can be called right after the object is created
    70      * or the reset method is called. You can't replace the root
    71      * handler while parsing is in progress.
    72      * <p>
    73      * Usually a generated class that corresponds to the &lt;start>
    74      * pattern will be used as the root handler, but any NGCCHandler
    75      * can be a root handler.
    76      *
    77      * @exception IllegalStateException
    78      *      If this method is called but it doesn't satisfy the
    79      *      pre-condition stated above.
    80      */
    81     public void setRootHandler( NGCCHandler rootHandler ) {
    82         if(currentHandler!=null)
    83             throw new IllegalStateException();
    84         currentHandler = rootHandler;
    85     }
    88     /**
    89      * Cleans up all the data structure so that the object can be reused later.
    90      * Normally, applications do not need to call this method directly,
    91      *
    92      * as the runtime resets itself after the endDocument method.
    93      */
    94     public void reset() {
    95         attStack.clear();
    96         currentAtts = null;
    97         currentHandler = null;
    98         indent=0;
    99         locator = null;
   100         namespaces.clear();
   101         needIndent = true;
   102         redirect = null;
   103         redirectionDepth = 0;
   104         text = new StringBuffer();
   106         // add a dummy attributes at the bottom as a "centinel."
   107         attStack.push(new AttributesImpl());
   108     }
   110     // current content handler can be acccessed via set/getContentHandler.
   112     private Locator locator;
   113     public void setDocumentLocator( Locator _loc ) { this.locator=_loc; }
   114     /**
   115      * Gets the source location of the current event.
   116      *
   117      * <p>
   118      * One can call this method from RelaxNGCC handlers to access
   119      * the line number information. Note that to
   120      */
   121     public Locator getLocator() { return locator; }
   124     /** stack of {@link Attributes}. */
   125     private final Stack attStack = new Stack();
   126     /** current attributes set. always equal to attStack.peek() */
   127     private AttributesImpl currentAtts;
   129     /**
   130      * Attributes that belong to the current element.
   131      * <p>
   132      * It's generally not recommended for applications to use
   133      * this method. RelaxNGCC internally removes processed attributes,
   134      * so this doesn't correctly reflect all the attributes an element
   135      * carries.
   136      */
   137     public Attributes getCurrentAttributes() {
   138         return currentAtts;
   139     }
   141     /** accumulated text. */
   142     private StringBuffer text = new StringBuffer();
   147     /** The current NGCCHandler. Always equals to handlerStack.peek() */
   148     private NGCCEventReceiver currentHandler;
   150     public int replace( NGCCEventReceiver o, NGCCEventReceiver n ) {
   151         if(o!=currentHandler)
   152             throw new IllegalStateException();  // bug of RelaxNGCC
   153         currentHandler = n;
   155         return 0;   // we only have one thread.
   156     }
   158     /**
   159      * Processes buffered text.
   160      *
   161      * This method will be called by the start/endElement event to process
   162      * buffered text as a text event.
   163      *
   164      * <p>
   165      * Whitespace handling is a tricky business. Consider the following
   166      * schema fragment:
   167      *
   168      * <xmp>
   169      * <element name="foo">
   170      *   <choice>
   171      *     <element name="bar"><empty/></element>
   172      *     <text/>
   173      *   </choice>
   174      * </element>
   175      * </xmp>
   176      *
   177      * Assume we hit the following instance:
   178      * <xmp>
   179      * <foo> <bar/></foo>
   180      * </xmp>
   181      *
   182      * Then this first space needs to be ignored (for otherwise, we will
   183      * end up treating this space as the match to &lt;text/> and won't
   184      * be able to process &lt;bar>.)
   185      *
   186      * Now assume the following instance:
   187      * <xmp>
   188      * <foo/>
   189      * </xmp>
   190      *
   191      * This time, we need to treat this empty string as a text, for
   192      * otherwise we won't be able to accept this instance.
   193      *
   194      * <p>
   195      * This is very difficult to solve in general, but one seemingly
   196      * easy solution is to use the type of next event. If a text is
   197      * followed by a start tag, it follows from the constraint on
   198      * RELAX NG that that text must be either whitespaces or a match
   199      * to &lt;text/>.
   200      *
   201      * <p>
   202      * On the contrary, if a text is followed by a end tag, then it
   203      * cannot be whitespace unless the content model can accept empty,
   204      * in which case sending a text event will be harmlessly ignored
   205      * by the NGCCHandler.
   206      *
   207      * <p>
   208      * Thus this method take one parameter, which controls the
   209      * behavior of this method.
   210      *
   211      * <p>
   212      * TODO: according to the constraint of RELAX NG, if characters
   213      * follow an end tag, then they must be either whitespaces or
   214      * must match to &lt;text/>.
   215      *
   216      * @param   possiblyWhitespace
   217      *      True if the buffered character can be ignorabale. False if
   218      *      it needs to be consumed.
   219      */
   220     private void processPendingText(boolean ignorable) throws SAXException {
   221         if(ignorable && text.toString().trim().length()==0)
   222             ; // ignore. See the above javadoc comment for the description
   223         else
   224             currentHandler.text(text.toString());   // otherwise consume this token
   226         // truncate StringBuffer, but avoid excessive allocation.
   227         if(text.length()>1024)  text = new StringBuffer();
   228         else                    text.setLength(0);
   229     }
   231     public void processList( String str ) throws SAXException {
   232         StringTokenizer t = new StringTokenizer(str, " \t\r\n");
   233         while(t.hasMoreTokens())
   234             currentHandler.text(t.nextToken());
   235     }
   237     public void startElement(String uri, String localname, String qname, Attributes atts)
   238             throws SAXException {
   240         if(redirect!=null) {
   241             redirect.startElement(uri,localname,qname,atts);
   242             redirectionDepth++;
   243         } else {
   244             processPendingText(true);
   245     //        System.out.println("startElement:"+localname+"->"+_attrStack.size());
   246             currentHandler.enterElement(uri, localname, qname, atts);
   247         }
   248     }
   250     /**
   251      * Called by the generated handler code when an enter element
   252      * event is consumed.
   253      *
   254      * <p>
   255      * Pushes a new attribute set.
   256      *
   257      * <p>
   258      * Note that attributes are NOT pushed at the startElement method,
   259      * because the processing of the enterElement event can trigger
   260      * other attribute events and etc.
   261      * <p>
   262      * This method will be called from one of handlers when it truely
   263      * consumes the enterElement event.
   264      */
   265     public void onEnterElementConsumed(
   266         String uri, String localName, String qname,Attributes atts) throws SAXException {
   267         attStack.push(currentAtts=new AttributesImpl(atts));
   268         nsEffectiveStack.push( new Integer(nsEffectivePtr) );
   269         nsEffectivePtr = namespaces.size();
   270     }
   272     public void onLeaveElementConsumed(String uri, String localName, String qname) throws SAXException {
   273         attStack.pop();
   274         if(attStack.isEmpty())
   275             currentAtts = null;
   276         else
   277             currentAtts = (AttributesImpl)attStack.peek();
   278         nsEffectivePtr = ((Integer)nsEffectiveStack.pop()).intValue();
   279     }
   281     public void endElement(String uri, String localname, String qname)
   282             throws SAXException {
   284         if(redirect!=null) {
   285             redirect.endElement(uri,localname,qname);
   286             redirectionDepth--;
   288             if(redirectionDepth!=0)
   289                 return;
   291             // finished redirection.
   292             for( int i=0; i<namespaces.size(); i+=2 )
   293                 redirect.endPrefixMapping((String)namespaces.get(i));
   294             redirect.endDocument();
   296             redirect = null;
   297             // then process this element normally
   298         }
   300         processPendingText(false);
   302         currentHandler.leaveElement(uri, localname, qname);
   303 //        System.out.println("endElement:"+localname);
   304     }
   306     public void characters(char[] ch, int start, int length) throws SAXException {
   307         if(redirect!=null)
   308             redirect.characters(ch,start,length);
   309         else
   310             text.append(ch,start,length);
   311     }
   312     public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
   313         if(redirect!=null)
   314             redirect.ignorableWhitespace(ch,start,length);
   315         else
   316             text.append(ch,start,length);
   317     }
   319     public int getAttributeIndex(String uri, String localname) {
   320         return currentAtts.getIndex(uri, localname);
   321     }
   322     public void consumeAttribute(int index) throws SAXException {
   323         final String uri    = currentAtts.getURI(index);
   324         final String local  = currentAtts.getLocalName(index);
   325         final String qname  = currentAtts.getQName(index);
   326         final String value  = currentAtts.getValue(index);
   327         currentAtts.removeAttribute(index);
   329         currentHandler.enterAttribute(uri,local,qname);
   330         currentHandler.text(value);
   331         currentHandler.leaveAttribute(uri,local,qname);
   332     }
   335     public void startPrefixMapping( String prefix, String uri ) throws SAXException {
   336         if(redirect!=null)
   337             redirect.startPrefixMapping(prefix,uri);
   338         else {
   339             namespaces.add(prefix);
   340             namespaces.add(uri);
   341         }
   342     }
   344     public void endPrefixMapping( String prefix ) throws SAXException {
   345         if(redirect!=null)
   346             redirect.endPrefixMapping(prefix);
   347         else {
   348             namespaces.remove(namespaces.size()-1);
   349             namespaces.remove(namespaces.size()-1);
   350         }
   351     }
   353     public void skippedEntity( String name ) throws SAXException {
   354         if(redirect!=null)
   355             redirect.skippedEntity(name);
   356     }
   358     public void processingInstruction( String target, String data ) throws SAXException {
   359         if(redirect!=null)
   360             redirect.processingInstruction(target,data);
   361     }
   363     /** Impossible token. This value can never be a valid XML name. */
   364     static final String IMPOSSIBLE = "\u0000";
   366     public void endDocument() throws SAXException {
   367         // consume the special "end document" token so that all the handlers
   368         // currently at the stack will revert to their respective parents.
   369         //
   370         // this is necessary to handle a grammar like
   371         // <start><ref name="X"/></start>
   372         // <define name="X">
   373         //   <element name="root"><empty/></element>
   374         // </define>
   375         //
   376         // With this grammar, when the endElement event is consumed, two handlers
   377         // are on the stack (because a child object won't revert to its parent
   378         // unless it sees a next event.)
   380         // pass around an "impossible" token.
   381         currentHandler.leaveElement(IMPOSSIBLE,IMPOSSIBLE,IMPOSSIBLE);
   383         reset();
   384     }
   385     public void startDocument() {}
   390 //
   391 //
   392 // event dispatching methods
   393 //
   394 //
   396     public void sendEnterAttribute( int threadId,
   397         String uri, String local, String qname) throws SAXException {
   399         currentHandler.enterAttribute(uri,local,qname);
   400     }
   402     public void sendEnterElement( int threadId,
   403         String uri, String local, String qname, Attributes atts) throws SAXException {
   405         currentHandler.enterElement(uri,local,qname,atts);
   406     }
   408     public void sendLeaveAttribute( int threadId,
   409         String uri, String local, String qname) throws SAXException {
   411         currentHandler.leaveAttribute(uri,local,qname);
   412     }
   414     public void sendLeaveElement( int threadId,
   415         String uri, String local, String qname) throws SAXException {
   417         currentHandler.leaveElement(uri,local,qname);
   418     }
   420     public void sendText(int threadId, String value) throws SAXException {
   421         currentHandler.text(value);
   422     }
   425 //
   426 //
   427 // redirection of SAX2 events.
   428 //
   429 //
   430     /** When redirecting a sub-tree, this value will be non-null. */
   431     private ContentHandler redirect = null;
   433     /**
   434      * Counts the depth of the elements when we are re-directing
   435      * a sub-tree to another ContentHandler.
   436      */
   437     private int redirectionDepth = 0;
   439     /**
   440      * This method can be called only from the enterElement handler.
   441      * The sub-tree rooted at the new element will be redirected
   442      * to the specified ContentHandler.
   443      *
   444      * <p>
   445      * Currently active NGCCHandler will only receive the leaveElement
   446      * event of the newly started element.
   447      *
   448      * @param   uri,local,qname
   449      *      Parameters passed to the enter element event. Used to
   450      *      simulate the startElement event for the new ContentHandler.
   451      */
   452     public void redirectSubtree( ContentHandler child,
   453         String uri, String local, String qname ) throws SAXException {
   455         redirect = child;
   456         redirect.setDocumentLocator(locator);
   457         redirect.startDocument();
   459         // TODO: when a prefix is re-bound to something else,
   460         // the following code is potentially dangerous. It should be
   461         // modified to report active bindings only.
   462         for( int i=0; i<namespaces.size(); i+=2 )
   463             redirect.startPrefixMapping(
   464                 (String)namespaces.get(i),
   465                 (String)namespaces.get(i+1)
   466             );
   468         redirect.startElement(uri,local,qname,currentAtts);
   469         redirectionDepth=1;
   470     }
   472 //
   473 //
   474 // validation context implementation
   475 //
   476 //
   477     /** in-scope namespace mapping.
   478      * namespaces[2n  ] := prefix
   479      * namespaces[2n+1] := namespace URI */
   480     private final ArrayList namespaces = new ArrayList();
   481     /**
   482      * Index on the namespaces array, which points to
   483      * the top of the effective bindings. Because of the
   484      * timing difference between the startPrefixMapping method
   485      * and the execution of the corresponding actions,
   486      * this value can be different from <code>namespaces.size()</code>.
   487      * <p>
   488      * For example, consider the following schema:
   489      * <pre><xmp>
   490      *  <oneOrMore>
   491      *   <element name="foo"><empty/></element>
   492      *  </oneOrMore>
   493      *  code fragment X
   494      *  <element name="bob"/>
   495      * </xmp></pre>
   496      * Code fragment X is executed after we see a startElement event,
   497      * but at this time the namespaces variable already include new
   498      * namespace bindings declared on "bob".
   499      */
   500     private int nsEffectivePtr=0;
   502     /**
   503      * Stack to preserve old nsEffectivePtr values.
   504      */
   505     private final Stack nsEffectiveStack = new Stack();
   507     public String resolveNamespacePrefix( String prefix ) {
   508         for( int i = nsEffectivePtr-2; i>=0; i-=2 )
   509             if( namespaces.get(i).equals(prefix) )
   510                 return (String)namespaces.get(i+1);
   512         // no binding was found.
   513         if(prefix.equals(""))   return "";  // return the default no-namespace
   514         if(prefix.equals("xml"))    // pre-defined xml prefix
   515             return "http://www.w3.org/XML/1998/namespace";
   516         else    return null;    // prefix undefined
   517     }
   520 // error reporting
   521     protected void unexpectedX(String token) throws SAXException {
   522         throw new SAXParseException(MessageFormat.format(
   523             "Unexpected {0} appears at line {1} column {2}",
   524             new Object[]{
   525                 token,
   526                 new Integer(getLocator().getLineNumber()),
   527                 new Integer(getLocator().getColumnNumber()) }),
   528             getLocator());
   529     }
   534 //
   535 //
   536 // trace functions
   537 //
   538 //
   539     private int indent=0;
   540     private boolean needIndent=true;
   541     private void printIndent() {
   542         for( int i=0; i<indent; i++ )
   543             System.out.print("  ");
   544     }
   545     public void trace( String s ) {
   546         if(needIndent) {
   547             needIndent=false;
   548             printIndent();
   549         }
   550         System.out.print(s);
   551     }
   552     public void traceln( String s ) {
   553         trace(s);
   554         trace("\n");
   555         needIndent=true;
   556     }
   557 }

mercurial