001 // 002 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v1.0.1-05/30/2003 05:06 AM(java_re)-fcs 003 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 004 // Any modifications to this file will be lost upon recompilation of the source schema. 005 // Generated on: 2004.10.11 at 12:13:34 EDT 006 // 007 008 /* 009 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 010 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 011 */ 012 013 /* 014 * @(#)$Id: SAXUnmarshallerHandlerImpl.java,v 1.9 2003/05/21 01:18:16 kk122374 Exp $ 015 */ 016 package astronomy.data.spectra.impl.runtime; 017 018 import java.util.ArrayList; 019 import java.util.Collections; 020 import java.util.Hashtable; 021 import java.util.Iterator; 022 import java.util.List; 023 import java.util.Stack; 024 025 import javax.xml.XMLConstants; 026 import javax.xml.bind.JAXBException; 027 import javax.xml.bind.UnmarshalException; 028 import javax.xml.bind.ValidationEvent; 029 import javax.xml.bind.ValidationEventHandler; 030 031 import org.xml.sax.Attributes; 032 import org.xml.sax.Locator; 033 import org.xml.sax.SAXException; 034 import org.xml.sax.SAXParseException; 035 036 import com.sun.xml.bind.unmarshaller.Messages; 037 import com.sun.xml.bind.unmarshaller.Tracer; 038 import com.sun.xml.bind.util.AttributesImpl; 039 040 /** 041 * Implementation of {@link UnmarshallerHandler}. 042 * 043 * This object converts SAX events into unmarshaller events and 044 * cooridnates the entire unmarshalling process. 045 * 046 * @author 047 * <a href="mailto:kohsuke.kawaguchi@sun.com>Kohsuke KAWAGUCHI</a> 048 */ 049 public class SAXUnmarshallerHandlerImpl 050 implements SAXUnmarshallerHandler, UnmarshallingContext 051 { 052 /** 053 * This flag is set to true at the startDocument event 054 * and false at the endDocument event. 055 * 056 * Until the first document is unmarshalled, we don't 057 * want to return an object. So this variable is initialized 058 * to true. 059 */ 060 private boolean isUnmarshalInProgress = true; 061 062 /** stack of collectText flag. False means text can be ignored. */ 063 private boolean[] collectText = new boolean[16]; 064 private int collectTextTop = 0; 065 066 067 public SAXUnmarshallerHandlerImpl( UnmarshallerImpl _parent, GrammarInfo _gi ) { 068 this.parent = _parent; 069 grammarInfo = _gi; 070 startPrefixMapping("",""); // by default, the default ns is bound to "". 071 } 072 073 private final GrammarInfo grammarInfo; 074 public GrammarInfo getGrammarInfo() { return grammarInfo; } 075 076 /** 077 * Returns true if we should be collecting characters in the current element. 078 */ 079 private final boolean shouldCollectText() { 080 return collectText[collectTextTop]; 081 } 082 083 public void startDocument() throws SAXException { 084 // reset the object 085 result = null; 086 handlerLen=0; 087 patchers=null; 088 patchersLen=0; 089 aborted = false; 090 isUnmarshalInProgress = true; 091 collectTextTop = 0; 092 093 attStack.clear(); 094 } 095 096 public void endDocument() throws SAXException { 097 runPatchers(); 098 isUnmarshalInProgress = false; 099 } 100 101 public void startElement( String uri, String local, String qname, Attributes atts ) 102 throws SAXException { 103 104 // symbolize 105 uri = uri.intern(); 106 local = local.intern(); 107 qname = qname.intern(); 108 109 if(result==null) { 110 // this is the root element. 111 // create a root object and start unmarshalling 112 UnmarshallingEventHandler unmarshaller = 113 grammarInfo.createUnmarshaller(uri,local,this); 114 if(unmarshaller==null) { 115 // the registry doesn't know about this element. 116 // 117 // the no.1 cause of this problem is that your application is configuring 118 // an XML parser by your self and you forgot to call 119 // the SAXParserFactory.setNamespaceAware(true). When this happens, you see 120 // the namespace URI is reported as empty whereas you expect something else. 121 throw new SAXParseException( 122 Messages.format( Messages.UNEXPECTED_ROOT_ELEMENT2, 123 uri, local, computeExpectedRootElements() ), 124 getLocator() ); 125 } 126 result = unmarshaller.owner(); 127 128 pushContentHandler(unmarshaller,0); 129 } 130 131 processText(true); 132 133 getCurrentHandler().enterElement(uri,local,qname,atts); 134 } 135 136 public final void endElement( String uri, String local, String qname ) 137 throws SAXException { 138 139 // symbolize 140 uri = uri.intern(); 141 local = local.intern(); 142 qname = qname.intern(); 143 144 processText(false); 145 getCurrentHandler().leaveElement(uri,local,qname); 146 } 147 148 149 150 151 152 /** Root object that is being unmarshalled. */ 153 private Object result; 154 public Object getResult() throws UnmarshalException { 155 if(isUnmarshalInProgress) 156 throw new IllegalStateException(); 157 158 if(!aborted) return result; 159 160 // there was an error. 161 throw new UnmarshalException((String)null); 162 } 163 164 165 166 // 167 // 168 // handler stack maintainance 169 // 170 // 171 private UnmarshallingEventHandler[] handlers = new UnmarshallingEventHandler[16]; 172 private int[] mementos = new int[16]; 173 private int handlerLen=0; 174 175 public void pushContentHandler( UnmarshallingEventHandler handler, int memento ) { 176 if(handlerLen==handlers.length) { 177 // expand buffer 178 UnmarshallingEventHandler[] h = new UnmarshallingEventHandler[handlerLen*2]; 179 int[] m = new int[handlerLen*2]; 180 System.arraycopy(handlers,0,h,0,handlerLen); 181 System.arraycopy(mementos,0,m,0,handlerLen); 182 handlers = h; 183 mementos = m; 184 } 185 handlers[handlerLen] = handler; 186 mementos[handlerLen] = memento; 187 handlerLen++; 188 } 189 190 public void popContentHandler() throws SAXException { 191 handlerLen--; 192 handlers[handlerLen]=null; // this handler is removed 193 getCurrentHandler().leaveChild(mementos[handlerLen]); 194 } 195 196 public UnmarshallingEventHandler getCurrentHandler() { 197 return handlers[handlerLen-1]; 198 } 199 200 201 // 202 // 203 // text handling 204 // 205 // 206 private StringBuffer buffer = new StringBuffer(); 207 208 protected void consumeText( String str, boolean ignorable ) throws SAXException { 209 if(ignorable && str.trim().length()==0) 210 // if we are allowed to ignore text and 211 // the text is ignorable, ignore. 212 return; 213 214 // otherwise perform a transition by this token. 215 getCurrentHandler().text(str); 216 } 217 private void processText( boolean ignorable ) throws SAXException { 218 if( shouldCollectText() ) 219 consumeText(buffer.toString(),ignorable); 220 221 // avoid excessive object allocation, but also avoid 222 // keeping a huge array inside StringBuffer. 223 if(buffer.length()<1024) buffer.setLength(0); 224 else buffer = new StringBuffer(); 225 } 226 227 public final void characters( char[] buf, int start, int len ) { 228 if( shouldCollectText() ) 229 buffer.append(buf,start,len); 230 } 231 232 public final void ignorableWhitespace( char[] buf, int start, int len ) { 233 characters(buf,start,len); 234 } 235 236 237 238 239 // 240 // 241 // namespace binding maintainance 242 // 243 // 244 private String[] nsBind = new String[16]; 245 private int nsLen=0; 246 247 // in the current scope, nsBind[0] - nsBind[idxStack[idxStackTop]-1] 248 // are active. 249 private int[] idxStack = new int[16]; 250 private int idxStackTop=0; 251 252 public void startPrefixMapping( String prefix, String uri ) { 253 if(nsBind.length==nsLen) { 254 // expand the buffer 255 String[] n = new String[nsLen*2]; 256 System.arraycopy(nsBind,0,n,0,nsLen); 257 nsBind=n; 258 } 259 nsBind[nsLen++] = prefix; 260 nsBind[nsLen++] = uri; 261 } 262 public void endPrefixMapping( String prefix ) { 263 nsLen-=2; 264 } 265 public String resolveNamespacePrefix( String prefix ) { 266 if(prefix.equals("xml")) 267 return "http://www.w3.org/XML/1998/namespace"; 268 269 for( int i=idxStack[idxStackTop]-2; i>=0; i-=2 ) { 270 if(prefix.equals(nsBind[i])) 271 return nsBind[i+1]; 272 } 273 return null; 274 } 275 // 276 // NamespaceContext2 implementation 277 // 278 public Iterator getPrefixes(String uri) { 279 // TODO: could be implemented much faster 280 // wrap it into unmodifiable list so that the remove method 281 // will throw UnsupportedOperationException. 282 return Collections.unmodifiableList( 283 getAllPrefixesInList(uri)).iterator(); 284 } 285 286 private List getAllPrefixesInList(String uri) { 287 List a = new ArrayList(); 288 289 if( uri.equals(XMLConstants.XML_NS_URI) ) { 290 a.add(XMLConstants.XML_NS_PREFIX); 291 return a; 292 } 293 if( uri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI) ) { 294 a.add(XMLConstants.XMLNS_ATTRIBUTE); 295 return a; 296 } 297 if( uri==null ) 298 throw new IllegalArgumentException(); 299 300 for( int i=nsLen-2; i>=0; i-=2 ) 301 if(uri.equals(nsBind[i+1])) 302 if( getNamespaceURI(nsBind[i]).equals(nsBind[i+1]) ) 303 // make sure that this prefix is still effective. 304 a.add(nsBind[i]); 305 306 return a; 307 } 308 309 public String getPrefix(String uri) { 310 if( uri.equals(XMLConstants.XML_NS_URI) ) 311 return XMLConstants.XML_NS_PREFIX; 312 if( uri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI) ) 313 return XMLConstants.XMLNS_ATTRIBUTE; 314 if( uri==null ) 315 throw new IllegalArgumentException(); 316 317 for( int i=idxStack[idxStackTop]-2; i>=0; i-=2 ) 318 if(uri.equals(nsBind[i+1])) 319 if( getNamespaceURI(nsBind[i]).equals(nsBind[i+1]) ) 320 // make sure that this prefix is still effective. 321 return nsBind[i]; 322 323 return null; 324 } 325 326 public String getNamespaceURI(String prefix) { 327 if( prefix.equals(XMLConstants.XMLNS_ATTRIBUTE) ) 328 return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; 329 if( prefix==null ) 330 throw new IllegalArgumentException(); 331 332 return resolveNamespacePrefix(prefix); 333 } 334 335 // 336 // 337 // Attribute handling 338 // 339 // 340 // TODO: implementation can be more efficient 341 private final Stack attStack = new Stack(); 342 343 public void pushAttributes( Attributes atts, boolean collectTextFlag ) { 344 // since Attributes object is mutable, it is criticall important 345 // to make a copy. 346 // also symbolize attribute names 347 AttributesImpl a = new AttributesImpl(); 348 for( int i=0; i<atts.getLength(); i++ ) 349 a.addAttribute( 350 atts.getURI(i).intern(), 351 atts.getLocalName(i).intern(), 352 atts.getQName(i).intern(), 353 atts.getType(i), 354 atts.getValue(i) ); 355 356 // <foo xsi:nil="false">some value</foo> is a valid fragment, however 357 // we need a look ahead to correctly handle this case. 358 // (because when we process @xsi:nil, we don't know what the value is, 359 // and by the time we read "false", we can't cancel this attribute anymore.) 360 // 361 // as a quick workaround, we remove @xsi:nil if the value is false. 362 int idx = a.getIndex("http://www.w3.org/2001/XMLSchema-instance","nil"); 363 if(idx!=-1) { 364 String v = a.getValue(idx).trim(); 365 if(v.equals("false") || v.equals("0")) 366 a.removeAttribute(idx); 367 } 368 369 attStack.push(a); 370 371 // start a new namespace scope 372 if( ++idxStackTop==idxStack.length ) { 373 // reallocation 374 int[] newBuf = new int[idxStack.length*2]; 375 System.arraycopy(idxStack,0,newBuf,0,idxStack.length); 376 idxStack = newBuf; 377 } 378 idxStack[idxStackTop] = nsLen; 379 380 if( ++collectTextTop==collectText.length ) { 381 // reallocation 382 boolean[] newBuf = new boolean[collectText.length*2]; 383 System.arraycopy(collectText,0,newBuf,0,collectText.length); 384 collectText = newBuf; 385 } 386 collectText[collectTextTop] = collectTextFlag; 387 } 388 public void popAttributes() { 389 attStack.pop(); 390 391 idxStackTop--; 392 collectTextTop--; 393 } 394 public Attributes getUnconsumedAttributes() { 395 return (Attributes)attStack.peek(); 396 } 397 /** 398 * @param uri,local 399 * has to be interned. 400 */ 401 public int getAttribute( String uri, String local ) { 402 // Consider a class that corresponds to the root element. 403 // if this class has a transition from final state by an attribute, 404 // then this attribute transitions are checked when the final 405 // leaveElement event is consumed. 406 // 407 // to handle this case, return "not found" if there is no active 408 // attribute scope 409 if(attStack.isEmpty()) return -1; 410 411 AttributesImpl a = (AttributesImpl)attStack.peek(); 412 413 return a.getIndexFast(uri,local); 414 } 415 public void consumeAttribute( int idx ) throws SAXException { 416 AttributesImpl a = (AttributesImpl)attStack.peek(); 417 418 String uri = a.getURI(idx); 419 String local = a.getLocalName(idx); 420 String qname = a.getQName(idx); 421 String value = a.getValue(idx); 422 423 // mark the attribute as consumed 424 // we need to remove the attribute before we process it 425 // because the event handler might access attributes. 426 a.removeAttribute(idx); 427 428 429 getCurrentHandler().enterAttribute(uri,local,qname); 430 consumeText(value,false); 431 getCurrentHandler().leaveAttribute(uri,local,qname); 432 } 433 public String eatAttribute( int idx ) throws SAXException { 434 AttributesImpl a = (AttributesImpl)attStack.peek(); 435 436 String value = a.getValue(idx); 437 438 // mark the attribute as consumed 439 a.removeAttribute(idx); 440 441 return value; 442 } 443 444 // 445 // 446 // ID/IDREF related code 447 // 448 // 449 /** 450 * Submitted patchers in the order they've submitted. 451 * Many XML vocabulary doesn't use ID/IDREF at all, so we 452 * initialize it with null. 453 */ 454 private Runnable[] patchers = null; 455 private int patchersLen = 0; 456 457 public void addPatcher( Runnable job ) { 458 // re-allocate buffer if necessary 459 if( patchers==null ) 460 patchers = new Runnable[32]; 461 if( patchers.length == patchersLen ) { 462 Runnable[] buf = new Runnable[patchersLen*2]; 463 System.arraycopy(patchers,0,buf,0,patchersLen); 464 patchers = buf; 465 } 466 patchers[patchersLen++] = job; 467 } 468 469 /** Executes all the patchers. */ 470 private void runPatchers() { 471 if( patchers!=null ) { 472 for( int i=0; i<patchersLen; i++ ) 473 patchers[i].run(); 474 } 475 } 476 477 /** Records ID->Object map. */ 478 private Hashtable idmap = null; 479 480 public String addToIdTable( String id ) { 481 if(idmap==null) idmap = new Hashtable(); 482 idmap.put( id, getCurrentHandler().owner() ); 483 return id; 484 } 485 486 public Object getObjectFromId( String id ) { 487 if(idmap==null) return null; 488 return idmap.get(id); 489 } 490 491 492 493 // 494 // 495 // Other SAX callbacks 496 // 497 // 498 public void skippedEntity( String name ) { 499 // TODO: throw an exception, perhaps? 500 } 501 public void processingInstruction( String target, String data ) { 502 // just ignore 503 } 504 public void setDocumentLocator( Locator loc ) { 505 locator = loc; 506 } 507 public Locator getLocator() { return locator; } 508 509 private Locator locator; 510 511 512 // 513 // 514 // error handling 515 // 516 // 517 private final UnmarshallerImpl parent; 518 private boolean aborted = false; 519 520 public void handleEvent(ValidationEvent event, boolean canRecover ) throws SAXException { 521 ValidationEventHandler eventHandler; 522 try { 523 eventHandler = parent.getEventHandler(); 524 } catch( JAXBException e ) { 525 // impossible. 526 throw new InternalError(); 527 } 528 529 boolean recover = eventHandler.handleEvent(event); 530 531 // if the handler says "abort", we will not return the object 532 // from the unmarshaller.getResult() 533 if(!recover) aborted = true; 534 535 if( !canRecover || !recover ) 536 throw new SAXException( new UnmarshalException( 537 event.getMessage(), 538 event.getLinkedException() ) ); 539 } 540 541 // 542 // 543 // ValidationContext implementation 544 // 545 // 546 public String getBaseUri() { return null; } 547 public boolean isUnparsedEntity(String s) { return true; } 548 public boolean isNotation(String s) { return true; } 549 550 551 // 552 // 553 // debug trace methods 554 // 555 // 556 private Tracer tracer; 557 public void setTracer( Tracer t ) { 558 this.tracer = t; 559 } 560 public Tracer getTracer() { 561 if(tracer==null) 562 tracer = new Tracer.Standard(); 563 return tracer; 564 } 565 566 /** 567 * Computes the names of possible root elements for a better error diagnosis. 568 */ 569 private String computeExpectedRootElements() { 570 String r = ""; 571 572 String[] probePoints = grammarInfo.getProbePoints(); 573 for( int i=0; i<probePoints.length; i+=2 ) { 574 if( grammarInfo.recognize(probePoints[i],probePoints[i+1]) ) { 575 if(r.length()!=0) r+=','; 576 r += "<{"+probePoints[i]+"}"+probePoints[i+1]+">"; 577 } 578 } 579 580 return r; 581 } 582 583 }