/* * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.internal.jxc.gen.config; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Stack; import java.util.StringTokenizer; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; /** * Runtime Engine for RELAXNGCC execution. * * This class has the following functionalities: * *
* Auto-generated, do not edit. *
* @version $Id: NGCCRuntime.java,v 1.15 2002/09/29 02:55:48 okajima Exp $ * @author Kohsuke Kawaguchi (kk@kohsuke.org) */ public class NGCCRuntime implements ContentHandler, NGCCEventSource { public NGCCRuntime() { reset(); } /** * Sets the root handler, which will be used to parse the * root element. ** This method can be called right after the object is created * or the reset method is called. You can't replace the root * handler while parsing is in progress. *
* Usually a generated class that corresponds to the <start> * pattern will be used as the root handler, but any NGCCHandler * can be a root handler. * * @exception IllegalStateException * If this method is called but it doesn't satisfy the * pre-condition stated above. */ public void setRootHandler( NGCCHandler rootHandler ) { if(currentHandler!=null) throw new IllegalStateException(); currentHandler = rootHandler; } /** * Cleans up all the data structure so that the object can be reused later. * Normally, applications do not need to call this method directly, * * as the runtime resets itself after the endDocument method. */ public void reset() { attStack.clear(); currentAtts = null; currentHandler = null; indent=0; locator = null; namespaces.clear(); needIndent = true; redirect = null; redirectionDepth = 0; text = new StringBuffer(); // add a dummy attributes at the bottom as a "centinel." attStack.push(new AttributesImpl()); } // current content handler can be acccessed via set/getContentHandler. private Locator locator; public void setDocumentLocator( Locator _loc ) { this.locator=_loc; } /** * Gets the source location of the current event. * *
* One can call this method from RelaxNGCC handlers to access * the line number information. Note that to */ public Locator getLocator() { return locator; } /** stack of {@link Attributes}. */ private final Stack attStack = new Stack(); /** current attributes set. always equal to attStack.peek() */ private AttributesImpl currentAtts; /** * Attributes that belong to the current element. *
* It's generally not recommended for applications to use * this method. RelaxNGCC internally removes processed attributes, * so this doesn't correctly reflect all the attributes an element * carries. */ public Attributes getCurrentAttributes() { return currentAtts; } /** accumulated text. */ private StringBuffer text = new StringBuffer(); /** The current NGCCHandler. Always equals to handlerStack.peek() */ private NGCCEventReceiver currentHandler; public int replace( NGCCEventReceiver o, NGCCEventReceiver n ) { if(o!=currentHandler) throw new IllegalStateException(); // bug of RelaxNGCC currentHandler = n; return 0; // we only have one thread. } /** * Processes buffered text. * * This method will be called by the start/endElement event to process * buffered text as a text event. * *
* Whitespace handling is a tricky business. Consider the following * schema fragment: * *
* This is very difficult to solve in general, but one seemingly * easy solution is to use the type of next event. If a text is * followed by a start tag, it follows from the constraint on * RELAX NG that that text must be either whitespaces or a match * to <text/>. * *
* On the contrary, if a text is followed by a end tag, then it * cannot be whitespace unless the content model can accept empty, * in which case sending a text event will be harmlessly ignored * by the NGCCHandler. * *
* Thus this method take one parameter, which controls the * behavior of this method. * *
* TODO: according to the constraint of RELAX NG, if characters * follow an end tag, then they must be either whitespaces or * must match to <text/>. * * @param possiblyWhitespace * True if the buffered character can be ignorabale. False if * it needs to be consumed. */ private void processPendingText(boolean ignorable) throws SAXException { if(ignorable && text.toString().trim().length()==0) ; // ignore. See the above javadoc comment for the description else currentHandler.text(text.toString()); // otherwise consume this token // truncate StringBuffer, but avoid excessive allocation. if(text.length()>1024) text = new StringBuffer(); else text.setLength(0); } public void processList( String str ) throws SAXException { StringTokenizer t = new StringTokenizer(str, " \t\r\n"); while(t.hasMoreTokens()) currentHandler.text(t.nextToken()); } public void startElement(String uri, String localname, String qname, Attributes atts) throws SAXException { if(redirect!=null) { redirect.startElement(uri,localname,qname,atts); redirectionDepth++; } else { processPendingText(true); // System.out.println("startElement:"+localname+"->"+_attrStack.size()); currentHandler.enterElement(uri, localname, qname, atts); } } /** * Called by the generated handler code when an enter element * event is consumed. * *
* Pushes a new attribute set. * *
* Note that attributes are NOT pushed at the startElement method, * because the processing of the enterElement event can trigger * other attribute events and etc. *
* This method will be called from one of handlers when it truely
* consumes the enterElement event.
*/
public void onEnterElementConsumed(
String uri, String localName, String qname,Attributes atts) throws SAXException {
attStack.push(currentAtts=new AttributesImpl(atts));
nsEffectiveStack.push( new Integer(nsEffectivePtr) );
nsEffectivePtr = namespaces.size();
}
public void onLeaveElementConsumed(String uri, String localName, String qname) throws SAXException {
attStack.pop();
if(attStack.isEmpty())
currentAtts = null;
else
currentAtts = (AttributesImpl)attStack.peek();
nsEffectivePtr = ((Integer)nsEffectiveStack.pop()).intValue();
}
public void endElement(String uri, String localname, String qname)
throws SAXException {
if(redirect!=null) {
redirect.endElement(uri,localname,qname);
redirectionDepth--;
if(redirectionDepth!=0)
return;
// finished redirection.
for( int i=0; i
* Currently active NGCCHandler will only receive the leaveElement
* event of the newly started element.
*
* @param uri,local,qname
* Parameters passed to the enter element event. Used to
* simulate the startElement event for the new ContentHandler.
*/
public void redirectSubtree( ContentHandler child,
String uri, String local, String qname ) throws SAXException {
redirect = child;
redirect.setDocumentLocator(locator);
redirect.startDocument();
// TODO: when a prefix is re-bound to something else,
// the following code is potentially dangerous. It should be
// modified to report active bindings only.
for( int i=0; i
* For example, consider the following schema:
*
* Code fragment X is executed after we see a startElement event,
* but at this time the namespaces variable already include new
* namespace bindings declared on "bob".
*/
private int nsEffectivePtr=0;
/**
* Stack to preserve old nsEffectivePtr values.
*/
private final Stack nsEffectiveStack = new Stack();
public String resolveNamespacePrefix( String prefix ) {
for( int i = nsEffectivePtr-2; i>=0; i-=2 )
if( namespaces.get(i).equals(prefix) )
return (String)namespaces.get(i+1);
// no binding was found.
if(prefix.equals("")) return ""; // return the default no-namespace
if(prefix.equals("xml")) // pre-defined xml prefix
return "http://www.w3.org/XML/1998/namespace";
else return null; // prefix undefined
}
// error reporting
protected void unexpectedX(String token) throws SAXException {
throw new SAXParseException(MessageFormat.format(
"Unexpected {0} appears at line {1} column {2}",
new Object[]{
token,
new Integer(getLocator().getLineNumber()),
new Integer(getLocator().getColumnNumber()) }),
getLocator());
}
//
//
// trace functions
//
//
private int indent=0;
private boolean needIndent=true;
private void printIndent() {
for( int i=0; i