1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCRuntime.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,557 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.internal.jxc.gen.config; 1.30 + 1.31 +import java.text.MessageFormat; 1.32 +import java.util.ArrayList; 1.33 +import java.util.Stack; 1.34 +import java.util.StringTokenizer; 1.35 + 1.36 +import org.xml.sax.Attributes; 1.37 +import org.xml.sax.ContentHandler; 1.38 +import org.xml.sax.Locator; 1.39 +import org.xml.sax.SAXException; 1.40 +import org.xml.sax.SAXParseException; 1.41 + 1.42 +/** 1.43 + * Runtime Engine for RELAXNGCC execution. 1.44 + * 1.45 + * This class has the following functionalities: 1.46 + * 1.47 + * <ol> 1.48 + * <li>Managing a stack of NGCCHandler objects and 1.49 + * switching between them appropriately. 1.50 + * 1.51 + * <li>Keep track of all Attributes. 1.52 + * 1.53 + * <li>manage mapping between namespace URIs and prefixes. 1.54 + * 1.55 + * <li>TODO: provide support for interleaving. 1.56 + * <p><b> 1.57 + * Auto-generated, do not edit. 1.58 + * </b></p> 1.59 + * @version $Id: NGCCRuntime.java,v 1.15 2002/09/29 02:55:48 okajima Exp $ 1.60 + * @author Kohsuke Kawaguchi (kk@kohsuke.org) 1.61 + */ 1.62 +public class NGCCRuntime implements ContentHandler, NGCCEventSource { 1.63 + 1.64 + public NGCCRuntime() { 1.65 + reset(); 1.66 + } 1.67 + 1.68 + /** 1.69 + * Sets the root handler, which will be used to parse the 1.70 + * root element. 1.71 + * <p> 1.72 + * This method can be called right after the object is created 1.73 + * or the reset method is called. You can't replace the root 1.74 + * handler while parsing is in progress. 1.75 + * <p> 1.76 + * Usually a generated class that corresponds to the <start> 1.77 + * pattern will be used as the root handler, but any NGCCHandler 1.78 + * can be a root handler. 1.79 + * 1.80 + * @exception IllegalStateException 1.81 + * If this method is called but it doesn't satisfy the 1.82 + * pre-condition stated above. 1.83 + */ 1.84 + public void setRootHandler( NGCCHandler rootHandler ) { 1.85 + if(currentHandler!=null) 1.86 + throw new IllegalStateException(); 1.87 + currentHandler = rootHandler; 1.88 + } 1.89 + 1.90 + 1.91 + /** 1.92 + * Cleans up all the data structure so that the object can be reused later. 1.93 + * Normally, applications do not need to call this method directly, 1.94 + * 1.95 + * as the runtime resets itself after the endDocument method. 1.96 + */ 1.97 + public void reset() { 1.98 + attStack.clear(); 1.99 + currentAtts = null; 1.100 + currentHandler = null; 1.101 + indent=0; 1.102 + locator = null; 1.103 + namespaces.clear(); 1.104 + needIndent = true; 1.105 + redirect = null; 1.106 + redirectionDepth = 0; 1.107 + text = new StringBuffer(); 1.108 + 1.109 + // add a dummy attributes at the bottom as a "centinel." 1.110 + attStack.push(new AttributesImpl()); 1.111 + } 1.112 + 1.113 + // current content handler can be acccessed via set/getContentHandler. 1.114 + 1.115 + private Locator locator; 1.116 + public void setDocumentLocator( Locator _loc ) { this.locator=_loc; } 1.117 + /** 1.118 + * Gets the source location of the current event. 1.119 + * 1.120 + * <p> 1.121 + * One can call this method from RelaxNGCC handlers to access 1.122 + * the line number information. Note that to 1.123 + */ 1.124 + public Locator getLocator() { return locator; } 1.125 + 1.126 + 1.127 + /** stack of {@link Attributes}. */ 1.128 + private final Stack attStack = new Stack(); 1.129 + /** current attributes set. always equal to attStack.peek() */ 1.130 + private AttributesImpl currentAtts; 1.131 + 1.132 + /** 1.133 + * Attributes that belong to the current element. 1.134 + * <p> 1.135 + * It's generally not recommended for applications to use 1.136 + * this method. RelaxNGCC internally removes processed attributes, 1.137 + * so this doesn't correctly reflect all the attributes an element 1.138 + * carries. 1.139 + */ 1.140 + public Attributes getCurrentAttributes() { 1.141 + return currentAtts; 1.142 + } 1.143 + 1.144 + /** accumulated text. */ 1.145 + private StringBuffer text = new StringBuffer(); 1.146 + 1.147 + 1.148 + 1.149 + 1.150 + /** The current NGCCHandler. Always equals to handlerStack.peek() */ 1.151 + private NGCCEventReceiver currentHandler; 1.152 + 1.153 + public int replace( NGCCEventReceiver o, NGCCEventReceiver n ) { 1.154 + if(o!=currentHandler) 1.155 + throw new IllegalStateException(); // bug of RelaxNGCC 1.156 + currentHandler = n; 1.157 + 1.158 + return 0; // we only have one thread. 1.159 + } 1.160 + 1.161 + /** 1.162 + * Processes buffered text. 1.163 + * 1.164 + * This method will be called by the start/endElement event to process 1.165 + * buffered text as a text event. 1.166 + * 1.167 + * <p> 1.168 + * Whitespace handling is a tricky business. Consider the following 1.169 + * schema fragment: 1.170 + * 1.171 + * <xmp> 1.172 + * <element name="foo"> 1.173 + * <choice> 1.174 + * <element name="bar"><empty/></element> 1.175 + * <text/> 1.176 + * </choice> 1.177 + * </element> 1.178 + * </xmp> 1.179 + * 1.180 + * Assume we hit the following instance: 1.181 + * <xmp> 1.182 + * <foo> <bar/></foo> 1.183 + * </xmp> 1.184 + * 1.185 + * Then this first space needs to be ignored (for otherwise, we will 1.186 + * end up treating this space as the match to <text/> and won't 1.187 + * be able to process <bar>.) 1.188 + * 1.189 + * Now assume the following instance: 1.190 + * <xmp> 1.191 + * <foo/> 1.192 + * </xmp> 1.193 + * 1.194 + * This time, we need to treat this empty string as a text, for 1.195 + * otherwise we won't be able to accept this instance. 1.196 + * 1.197 + * <p> 1.198 + * This is very difficult to solve in general, but one seemingly 1.199 + * easy solution is to use the type of next event. If a text is 1.200 + * followed by a start tag, it follows from the constraint on 1.201 + * RELAX NG that that text must be either whitespaces or a match 1.202 + * to <text/>. 1.203 + * 1.204 + * <p> 1.205 + * On the contrary, if a text is followed by a end tag, then it 1.206 + * cannot be whitespace unless the content model can accept empty, 1.207 + * in which case sending a text event will be harmlessly ignored 1.208 + * by the NGCCHandler. 1.209 + * 1.210 + * <p> 1.211 + * Thus this method take one parameter, which controls the 1.212 + * behavior of this method. 1.213 + * 1.214 + * <p> 1.215 + * TODO: according to the constraint of RELAX NG, if characters 1.216 + * follow an end tag, then they must be either whitespaces or 1.217 + * must match to <text/>. 1.218 + * 1.219 + * @param possiblyWhitespace 1.220 + * True if the buffered character can be ignorabale. False if 1.221 + * it needs to be consumed. 1.222 + */ 1.223 + private void processPendingText(boolean ignorable) throws SAXException { 1.224 + if(ignorable && text.toString().trim().length()==0) 1.225 + ; // ignore. See the above javadoc comment for the description 1.226 + else 1.227 + currentHandler.text(text.toString()); // otherwise consume this token 1.228 + 1.229 + // truncate StringBuffer, but avoid excessive allocation. 1.230 + if(text.length()>1024) text = new StringBuffer(); 1.231 + else text.setLength(0); 1.232 + } 1.233 + 1.234 + public void processList( String str ) throws SAXException { 1.235 + StringTokenizer t = new StringTokenizer(str, " \t\r\n"); 1.236 + while(t.hasMoreTokens()) 1.237 + currentHandler.text(t.nextToken()); 1.238 + } 1.239 + 1.240 + public void startElement(String uri, String localname, String qname, Attributes atts) 1.241 + throws SAXException { 1.242 + 1.243 + if(redirect!=null) { 1.244 + redirect.startElement(uri,localname,qname,atts); 1.245 + redirectionDepth++; 1.246 + } else { 1.247 + processPendingText(true); 1.248 + // System.out.println("startElement:"+localname+"->"+_attrStack.size()); 1.249 + currentHandler.enterElement(uri, localname, qname, atts); 1.250 + } 1.251 + } 1.252 + 1.253 + /** 1.254 + * Called by the generated handler code when an enter element 1.255 + * event is consumed. 1.256 + * 1.257 + * <p> 1.258 + * Pushes a new attribute set. 1.259 + * 1.260 + * <p> 1.261 + * Note that attributes are NOT pushed at the startElement method, 1.262 + * because the processing of the enterElement event can trigger 1.263 + * other attribute events and etc. 1.264 + * <p> 1.265 + * This method will be called from one of handlers when it truely 1.266 + * consumes the enterElement event. 1.267 + */ 1.268 + public void onEnterElementConsumed( 1.269 + String uri, String localName, String qname,Attributes atts) throws SAXException { 1.270 + attStack.push(currentAtts=new AttributesImpl(atts)); 1.271 + nsEffectiveStack.push( new Integer(nsEffectivePtr) ); 1.272 + nsEffectivePtr = namespaces.size(); 1.273 + } 1.274 + 1.275 + public void onLeaveElementConsumed(String uri, String localName, String qname) throws SAXException { 1.276 + attStack.pop(); 1.277 + if(attStack.isEmpty()) 1.278 + currentAtts = null; 1.279 + else 1.280 + currentAtts = (AttributesImpl)attStack.peek(); 1.281 + nsEffectivePtr = ((Integer)nsEffectiveStack.pop()).intValue(); 1.282 + } 1.283 + 1.284 + public void endElement(String uri, String localname, String qname) 1.285 + throws SAXException { 1.286 + 1.287 + if(redirect!=null) { 1.288 + redirect.endElement(uri,localname,qname); 1.289 + redirectionDepth--; 1.290 + 1.291 + if(redirectionDepth!=0) 1.292 + return; 1.293 + 1.294 + // finished redirection. 1.295 + for( int i=0; i<namespaces.size(); i+=2 ) 1.296 + redirect.endPrefixMapping((String)namespaces.get(i)); 1.297 + redirect.endDocument(); 1.298 + 1.299 + redirect = null; 1.300 + // then process this element normally 1.301 + } 1.302 + 1.303 + processPendingText(false); 1.304 + 1.305 + currentHandler.leaveElement(uri, localname, qname); 1.306 +// System.out.println("endElement:"+localname); 1.307 + } 1.308 + 1.309 + public void characters(char[] ch, int start, int length) throws SAXException { 1.310 + if(redirect!=null) 1.311 + redirect.characters(ch,start,length); 1.312 + else 1.313 + text.append(ch,start,length); 1.314 + } 1.315 + public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { 1.316 + if(redirect!=null) 1.317 + redirect.ignorableWhitespace(ch,start,length); 1.318 + else 1.319 + text.append(ch,start,length); 1.320 + } 1.321 + 1.322 + public int getAttributeIndex(String uri, String localname) { 1.323 + return currentAtts.getIndex(uri, localname); 1.324 + } 1.325 + public void consumeAttribute(int index) throws SAXException { 1.326 + final String uri = currentAtts.getURI(index); 1.327 + final String local = currentAtts.getLocalName(index); 1.328 + final String qname = currentAtts.getQName(index); 1.329 + final String value = currentAtts.getValue(index); 1.330 + currentAtts.removeAttribute(index); 1.331 + 1.332 + currentHandler.enterAttribute(uri,local,qname); 1.333 + currentHandler.text(value); 1.334 + currentHandler.leaveAttribute(uri,local,qname); 1.335 + } 1.336 + 1.337 + 1.338 + public void startPrefixMapping( String prefix, String uri ) throws SAXException { 1.339 + if(redirect!=null) 1.340 + redirect.startPrefixMapping(prefix,uri); 1.341 + else { 1.342 + namespaces.add(prefix); 1.343 + namespaces.add(uri); 1.344 + } 1.345 + } 1.346 + 1.347 + public void endPrefixMapping( String prefix ) throws SAXException { 1.348 + if(redirect!=null) 1.349 + redirect.endPrefixMapping(prefix); 1.350 + else { 1.351 + namespaces.remove(namespaces.size()-1); 1.352 + namespaces.remove(namespaces.size()-1); 1.353 + } 1.354 + } 1.355 + 1.356 + public void skippedEntity( String name ) throws SAXException { 1.357 + if(redirect!=null) 1.358 + redirect.skippedEntity(name); 1.359 + } 1.360 + 1.361 + public void processingInstruction( String target, String data ) throws SAXException { 1.362 + if(redirect!=null) 1.363 + redirect.processingInstruction(target,data); 1.364 + } 1.365 + 1.366 + /** Impossible token. This value can never be a valid XML name. */ 1.367 + static final String IMPOSSIBLE = "\u0000"; 1.368 + 1.369 + public void endDocument() throws SAXException { 1.370 + // consume the special "end document" token so that all the handlers 1.371 + // currently at the stack will revert to their respective parents. 1.372 + // 1.373 + // this is necessary to handle a grammar like 1.374 + // <start><ref name="X"/></start> 1.375 + // <define name="X"> 1.376 + // <element name="root"><empty/></element> 1.377 + // </define> 1.378 + // 1.379 + // With this grammar, when the endElement event is consumed, two handlers 1.380 + // are on the stack (because a child object won't revert to its parent 1.381 + // unless it sees a next event.) 1.382 + 1.383 + // pass around an "impossible" token. 1.384 + currentHandler.leaveElement(IMPOSSIBLE,IMPOSSIBLE,IMPOSSIBLE); 1.385 + 1.386 + reset(); 1.387 + } 1.388 + public void startDocument() {} 1.389 + 1.390 + 1.391 + 1.392 + 1.393 +// 1.394 +// 1.395 +// event dispatching methods 1.396 +// 1.397 +// 1.398 + 1.399 + public void sendEnterAttribute( int threadId, 1.400 + String uri, String local, String qname) throws SAXException { 1.401 + 1.402 + currentHandler.enterAttribute(uri,local,qname); 1.403 + } 1.404 + 1.405 + public void sendEnterElement( int threadId, 1.406 + String uri, String local, String qname, Attributes atts) throws SAXException { 1.407 + 1.408 + currentHandler.enterElement(uri,local,qname,atts); 1.409 + } 1.410 + 1.411 + public void sendLeaveAttribute( int threadId, 1.412 + String uri, String local, String qname) throws SAXException { 1.413 + 1.414 + currentHandler.leaveAttribute(uri,local,qname); 1.415 + } 1.416 + 1.417 + public void sendLeaveElement( int threadId, 1.418 + String uri, String local, String qname) throws SAXException { 1.419 + 1.420 + currentHandler.leaveElement(uri,local,qname); 1.421 + } 1.422 + 1.423 + public void sendText(int threadId, String value) throws SAXException { 1.424 + currentHandler.text(value); 1.425 + } 1.426 + 1.427 + 1.428 +// 1.429 +// 1.430 +// redirection of SAX2 events. 1.431 +// 1.432 +// 1.433 + /** When redirecting a sub-tree, this value will be non-null. */ 1.434 + private ContentHandler redirect = null; 1.435 + 1.436 + /** 1.437 + * Counts the depth of the elements when we are re-directing 1.438 + * a sub-tree to another ContentHandler. 1.439 + */ 1.440 + private int redirectionDepth = 0; 1.441 + 1.442 + /** 1.443 + * This method can be called only from the enterElement handler. 1.444 + * The sub-tree rooted at the new element will be redirected 1.445 + * to the specified ContentHandler. 1.446 + * 1.447 + * <p> 1.448 + * Currently active NGCCHandler will only receive the leaveElement 1.449 + * event of the newly started element. 1.450 + * 1.451 + * @param uri,local,qname 1.452 + * Parameters passed to the enter element event. Used to 1.453 + * simulate the startElement event for the new ContentHandler. 1.454 + */ 1.455 + public void redirectSubtree( ContentHandler child, 1.456 + String uri, String local, String qname ) throws SAXException { 1.457 + 1.458 + redirect = child; 1.459 + redirect.setDocumentLocator(locator); 1.460 + redirect.startDocument(); 1.461 + 1.462 + // TODO: when a prefix is re-bound to something else, 1.463 + // the following code is potentially dangerous. It should be 1.464 + // modified to report active bindings only. 1.465 + for( int i=0; i<namespaces.size(); i+=2 ) 1.466 + redirect.startPrefixMapping( 1.467 + (String)namespaces.get(i), 1.468 + (String)namespaces.get(i+1) 1.469 + ); 1.470 + 1.471 + redirect.startElement(uri,local,qname,currentAtts); 1.472 + redirectionDepth=1; 1.473 + } 1.474 + 1.475 +// 1.476 +// 1.477 +// validation context implementation 1.478 +// 1.479 +// 1.480 + /** in-scope namespace mapping. 1.481 + * namespaces[2n ] := prefix 1.482 + * namespaces[2n+1] := namespace URI */ 1.483 + private final ArrayList namespaces = new ArrayList(); 1.484 + /** 1.485 + * Index on the namespaces array, which points to 1.486 + * the top of the effective bindings. Because of the 1.487 + * timing difference between the startPrefixMapping method 1.488 + * and the execution of the corresponding actions, 1.489 + * this value can be different from <code>namespaces.size()</code>. 1.490 + * <p> 1.491 + * For example, consider the following schema: 1.492 + * <pre><xmp> 1.493 + * <oneOrMore> 1.494 + * <element name="foo"><empty/></element> 1.495 + * </oneOrMore> 1.496 + * code fragment X 1.497 + * <element name="bob"/> 1.498 + * </xmp></pre> 1.499 + * Code fragment X is executed after we see a startElement event, 1.500 + * but at this time the namespaces variable already include new 1.501 + * namespace bindings declared on "bob". 1.502 + */ 1.503 + private int nsEffectivePtr=0; 1.504 + 1.505 + /** 1.506 + * Stack to preserve old nsEffectivePtr values. 1.507 + */ 1.508 + private final Stack nsEffectiveStack = new Stack(); 1.509 + 1.510 + public String resolveNamespacePrefix( String prefix ) { 1.511 + for( int i = nsEffectivePtr-2; i>=0; i-=2 ) 1.512 + if( namespaces.get(i).equals(prefix) ) 1.513 + return (String)namespaces.get(i+1); 1.514 + 1.515 + // no binding was found. 1.516 + if(prefix.equals("")) return ""; // return the default no-namespace 1.517 + if(prefix.equals("xml")) // pre-defined xml prefix 1.518 + return "http://www.w3.org/XML/1998/namespace"; 1.519 + else return null; // prefix undefined 1.520 + } 1.521 + 1.522 + 1.523 +// error reporting 1.524 + protected void unexpectedX(String token) throws SAXException { 1.525 + throw new SAXParseException(MessageFormat.format( 1.526 + "Unexpected {0} appears at line {1} column {2}", 1.527 + new Object[]{ 1.528 + token, 1.529 + new Integer(getLocator().getLineNumber()), 1.530 + new Integer(getLocator().getColumnNumber()) }), 1.531 + getLocator()); 1.532 + } 1.533 + 1.534 + 1.535 + 1.536 + 1.537 +// 1.538 +// 1.539 +// trace functions 1.540 +// 1.541 +// 1.542 + private int indent=0; 1.543 + private boolean needIndent=true; 1.544 + private void printIndent() { 1.545 + for( int i=0; i<indent; i++ ) 1.546 + System.out.print(" "); 1.547 + } 1.548 + public void trace( String s ) { 1.549 + if(needIndent) { 1.550 + needIndent=false; 1.551 + printIndent(); 1.552 + } 1.553 + System.out.print(s); 1.554 + } 1.555 + public void traceln( String s ) { 1.556 + trace(s); 1.557 + trace("\n"); 1.558 + needIndent=true; 1.559 + } 1.560 +}