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