1 /* 2 * Copyright (c) 2013, 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 */ 25 26 package com.sun.xml.internal.ws.util.xml; 27 28 import java.util.Iterator; 29 import java.util.List; 30 31 import javax.xml.namespace.NamespaceContext; 32 import javax.xml.namespace.QName; 33 import javax.xml.stream.Location; 34 import javax.xml.stream.XMLStreamException; 35 import javax.xml.stream.XMLStreamReader; 36 37 import com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx; 38 import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx; 39 40 import com.sun.xml.internal.ws.encoding.TagInfoset; 41 42 /** 43 * XMLReaderComposite 44 * 45 * @author shih-chang.chen@oracle.com 46 */ 47 public class XMLReaderComposite implements XMLStreamReaderEx { 48 49 static public enum State { StartTag, Payload, EndTag } 50 51 protected State state = State.StartTag; 52 protected ElemInfo elemInfo; 53 protected TagInfoset tagInfo; 54 protected XMLStreamReader[] children; 55 protected int payloadIndex = -1; 56 protected XMLStreamReader payloadReader; 57 58 static public class ElemInfo implements NamespaceContext { 59 ElemInfo ancestor; 60 TagInfoset tagInfo; 61 public ElemInfo(TagInfoset tag, ElemInfo parent) { tagInfo = tag; ancestor = parent; } 62 public String getNamespaceURI(String prefix) { 63 String n = tagInfo.getNamespaceURI(prefix); 64 return (n != null) ? n : (ancestor != null) ? ancestor.getNamespaceURI(prefix) : null; 65 } 66 public String getPrefix(String uri) { 67 String p = tagInfo.getPrefix(uri); 68 return (p != null) ? p : (ancestor != null) ? ancestor.getPrefix(uri) : null; 69 } 70 //Who wants this? 71 public List<String> allPrefixes(String namespaceURI) { 72 List<String> l = tagInfo.allPrefixes(namespaceURI); 73 if (ancestor != null) { 74 List<String> p = ancestor.allPrefixes(namespaceURI); 75 p.addAll(l); 76 return p; 77 } 78 return l; 79 } 80 public Iterator<String> getPrefixes(String namespaceURI) { 81 return allPrefixes(namespaceURI).iterator(); 82 } 83 } 84 85 public XMLReaderComposite(final ElemInfo elem, XMLStreamReader[] wrapees) { 86 elemInfo = elem; 87 tagInfo = elem.tagInfo; 88 children = wrapees; 89 if (children != null && children.length > 0) { 90 payloadIndex = 0; 91 payloadReader = children[payloadIndex]; 92 } 93 } 94 95 96 @Override 97 public int next() throws XMLStreamException { 98 switch (state) { 99 case StartTag: 100 if (payloadReader != null) { 101 state = State.Payload; 102 return payloadReader.getEventType(); 103 } else { 104 state = State.EndTag; 105 return XMLStreamReader.END_ELEMENT; 106 } 107 case EndTag: return XMLStreamReader.END_DOCUMENT; 108 case Payload: 109 default: 110 int next = XMLStreamReader.END_DOCUMENT; 111 if (payloadReader != null && payloadReader.hasNext()) { 112 next = payloadReader.next(); 113 } 114 if (next != XMLStreamReader.END_DOCUMENT) return next; 115 else { 116 if (payloadIndex+1 < children.length ) { 117 payloadIndex++; 118 payloadReader = children[payloadIndex]; 119 return payloadReader.getEventType(); 120 } else { 121 state = State.EndTag; 122 return XMLStreamReader.END_ELEMENT; 123 } 124 } 125 } 126 } 127 128 @Override 129 public boolean hasNext() throws XMLStreamException { 130 switch (state) { 131 case EndTag: return false; 132 case StartTag: 133 case Payload: 134 default: return true; 135 } 136 } 137 138 @Override 139 public String getElementText() throws XMLStreamException { 140 switch (state) { 141 case StartTag: 142 if (payloadReader.isCharacters()) return payloadReader.getText(); 143 return ""; 144 case Payload: 145 default: 146 return payloadReader.getElementText(); 147 } 148 } 149 150 @Override 151 public int nextTag() throws XMLStreamException { 152 int e = next(); 153 if (e == XMLStreamReader.END_DOCUMENT) return e; 154 while (e != XMLStreamReader.END_DOCUMENT) { 155 if (e == XMLStreamReader.START_ELEMENT) return e; 156 if (e == XMLStreamReader.END_ELEMENT) return e; 157 e = next(); 158 } 159 return e; 160 } 161 162 @Override 163 public Object getProperty(String name) throws IllegalArgumentException { 164 return (payloadReader != null) ? payloadReader.getProperty(name) : null; 165 } 166 167 @Override 168 public void require(int type, String namespaceURI, String localName) throws XMLStreamException { 169 if (payloadReader!=null) payloadReader.require(type, namespaceURI, localName); 170 } 171 172 @Override 173 public void close() throws XMLStreamException { 174 if (payloadReader!=null) payloadReader.close(); 175 } 176 177 @Override 178 public String getNamespaceURI(String prefix) { 179 switch (state) { 180 case StartTag: 181 case EndTag: 182 return elemInfo.getNamespaceURI(prefix); 183 case Payload: 184 default: 185 return payloadReader.getNamespaceURI(prefix); 186 } 187 } 188 189 @Override 190 public boolean isStartElement() { 191 switch (state) { 192 case StartTag: return true; 193 case EndTag: return false; 194 case Payload: 195 default: 196 return payloadReader.isStartElement(); 197 } 198 } 199 200 @Override 201 public boolean isEndElement() { 202 switch (state) { 203 case StartTag: return false; 204 case EndTag: return true; 205 case Payload: 206 default: 207 return payloadReader.isEndElement(); 208 } 209 } 210 211 @Override 212 public boolean isCharacters() { 213 switch (state) { 214 case StartTag: 215 case EndTag: return false; 216 case Payload: 217 default: 218 return payloadReader.isCharacters(); 219 } 220 } 221 222 @Override 223 public boolean isWhiteSpace() { 224 switch (state) { 225 case StartTag: 226 case EndTag: return false; 227 case Payload: 228 default: 229 return payloadReader.isWhiteSpace(); 230 } 231 } 232 233 @Override 234 public String getAttributeValue(String uri, String localName) { 235 switch (state) { 236 case StartTag: 237 case EndTag: return tagInfo.atts.getValue(uri, localName); 238 case Payload: 239 default: 240 return payloadReader.getAttributeValue(uri, localName); 241 } 242 } 243 244 @Override 245 public int getAttributeCount() { 246 switch (state) { 247 case StartTag: 248 case EndTag: return tagInfo.atts.getLength(); 249 case Payload: 250 default: 251 return payloadReader.getAttributeCount(); 252 } 253 } 254 255 @Override 256 public QName getAttributeName(int i) { 257 switch (state) { 258 case StartTag: 259 case EndTag: return new QName(tagInfo.atts.getURI(i),tagInfo.atts.getLocalName(i),getPrfix(tagInfo.atts.getQName(i))); 260 case Payload: 261 default: 262 return payloadReader.getAttributeName(i); 263 } 264 } 265 266 @Override 267 public String getAttributeNamespace(int index) { 268 switch (state) { 269 case StartTag: 270 case EndTag: return tagInfo.atts.getURI(index); 271 case Payload: 272 default: 273 return payloadReader.getAttributeNamespace(index); 274 } 275 } 276 277 @Override 278 public String getAttributeLocalName(int index) { 279 switch (state) { 280 case StartTag: 281 case EndTag: return tagInfo.atts.getLocalName(index); 282 case Payload: 283 default: 284 return payloadReader.getAttributeLocalName(index); 285 } 286 } 287 288 @Override 289 public String getAttributePrefix(int index) { 290 switch (state) { 291 case StartTag: 292 case EndTag: return getPrfix(tagInfo.atts.getQName(index)); 293 case Payload: 294 default: 295 return payloadReader.getAttributePrefix(index); 296 } 297 } 298 299 static private String getPrfix(String qName) { 300 if (qName == null) return null; 301 int i = qName.indexOf(":"); 302 return (i > 0)? qName.substring(0, i) : ""; 303 } 304 305 306 @Override 307 public String getAttributeType(int index) { 308 switch (state) { 309 case StartTag: 310 case EndTag: return tagInfo.atts.getType(index); 311 case Payload: 312 default: 313 return payloadReader.getAttributeType(index); 314 } 315 } 316 317 @Override 318 public String getAttributeValue(int index) { 319 switch (state) { 320 case StartTag: 321 case EndTag: return tagInfo.atts.getValue(index); 322 case Payload: 323 default: 324 return payloadReader.getAttributeValue(index); 325 } 326 } 327 328 @Override 329 public boolean isAttributeSpecified(int index) { 330 switch (state) { 331 case StartTag: 332 case EndTag: return (index < tagInfo.atts.getLength()) ? tagInfo.atts.getLocalName(index) != null : false; 333 case Payload: 334 default: 335 return payloadReader.isAttributeSpecified(index); 336 } 337 } 338 339 @Override 340 public int getNamespaceCount() { 341 switch (state) { 342 case StartTag: 343 case EndTag: return (tagInfo.ns.length/2); 344 case Payload: 345 default: 346 return payloadReader.getNamespaceCount(); 347 } 348 } 349 350 @Override 351 public String getNamespacePrefix(int index) { 352 switch (state) { 353 case StartTag: 354 case EndTag: return tagInfo.ns[2*index]; 355 case Payload: 356 default: 357 return payloadReader.getNamespacePrefix(index); 358 } 359 } 360 361 @Override 362 public String getNamespaceURI(int index) { 363 switch (state) { 364 case StartTag: 365 case EndTag: return tagInfo.ns[2*index+1]; 366 case Payload: 367 default: 368 return payloadReader.getNamespaceURI(index); 369 } 370 } 371 372 @Override 373 public NamespaceContextEx getNamespaceContext() { 374 switch (state) { 375 case StartTag: 376 case EndTag: return new NamespaceContextExAdaper(elemInfo); 377 case Payload: 378 default: 379 return isPayloadReaderEx()? 380 payloadReaderEx().getNamespaceContext() : 381 new NamespaceContextExAdaper(payloadReader.getNamespaceContext()); 382 } 383 } 384 385 private boolean isPayloadReaderEx() { return (payloadReader instanceof XMLStreamReaderEx); } 386 387 private XMLStreamReaderEx payloadReaderEx() { return (XMLStreamReaderEx)payloadReader; } 388 389 @Override 390 public int getEventType() { 391 switch (state) { 392 case StartTag: return XMLStreamReader.START_ELEMENT; 393 case EndTag: return XMLStreamReader.END_ELEMENT; 394 case Payload: 395 default: 396 return payloadReader.getEventType(); 397 } 398 } 399 400 @Override 401 public String getText() { 402 switch (state) { 403 case StartTag: 404 case EndTag: return null; 405 case Payload: 406 default: 407 return payloadReader.getText(); 408 } 409 } 410 411 @Override 412 public char[] getTextCharacters() { 413 switch (state) { 414 case StartTag: 415 case EndTag: return null; 416 case Payload: 417 default: 418 return payloadReader.getTextCharacters(); 419 } 420 } 421 422 @Override 423 public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException { 424 switch (state) { 425 case StartTag: 426 case EndTag: return -1; 427 case Payload: 428 default: 429 return payloadReader.getTextCharacters(sourceStart, target, targetStart, length); 430 } 431 } 432 433 @Override 434 public int getTextStart() { 435 switch (state) { 436 case StartTag: 437 case EndTag: return 0; 438 case Payload: 439 default: 440 return payloadReader.getTextStart(); 441 } 442 } 443 444 @Override 445 public int getTextLength() { 446 switch (state) { 447 case StartTag: 448 case EndTag: return 0; 449 case Payload: 450 default: 451 return payloadReader.getTextLength(); 452 } 453 } 454 455 @Override 456 public String getEncoding() { 457 switch (state) { 458 case StartTag: 459 case EndTag: return null; 460 case Payload: 461 default: 462 return payloadReader.getEncoding(); 463 } 464 } 465 466 @Override 467 public boolean hasText() { 468 switch (state) { 469 case StartTag: 470 case EndTag: return false; 471 case Payload: 472 default: 473 return payloadReader.hasText(); 474 } 475 } 476 477 @Override 478 public Location getLocation() { 479 switch (state) { 480 case StartTag: 481 case EndTag: return new Location() { 482 483 @Override 484 public int getLineNumber() { 485 // TODO Auto-generated method stub 486 return 0; 487 } 488 489 @Override 490 public int getColumnNumber() { 491 // TODO Auto-generated method stub 492 return 0; 493 } 494 495 @Override 496 public int getCharacterOffset() { 497 // TODO Auto-generated method stub 498 return 0; 499 } 500 501 @Override 502 public String getPublicId() { 503 // TODO Auto-generated method stub 504 return null; 505 } 506 507 @Override 508 public String getSystemId() { 509 // TODO Auto-generated method stub 510 return null; 511 } 512 513 }; 514 case Payload: 515 default: 516 return payloadReader.getLocation(); 517 } 518 } 519 520 @Override 521 public QName getName() { 522 switch (state) { 523 case StartTag: 524 case EndTag: return new QName(tagInfo.nsUri, tagInfo.localName, tagInfo.prefix); 525 case Payload: 526 default: 527 return payloadReader.getName(); 528 } 529 } 530 531 @Override 532 public String getLocalName() { 533 switch (state) { 534 case StartTag: 535 case EndTag: return tagInfo.localName; 536 case Payload: 537 default: 538 return payloadReader.getLocalName(); 539 } 540 } 541 542 @Override 543 public boolean hasName() { 544 switch (state) { 545 case StartTag: 546 case EndTag: return true; 547 case Payload: 548 default: 549 return payloadReader.hasName(); 550 } 551 } 552 553 @Override 554 public String getNamespaceURI() { 555 switch (state) { 556 case StartTag: 557 case EndTag: return tagInfo.nsUri; 558 case Payload: 559 default: 560 return payloadReader.getNamespaceURI(); 561 } 562 } 563 564 @Override 565 public String getPrefix() { 566 switch (state) { 567 case StartTag: 568 case EndTag: return tagInfo.prefix; 569 case Payload: 570 default: 571 return payloadReader.getPrefix(); 572 } 573 } 574 575 @Override 576 public String getVersion() { 577 switch (state) { 578 case StartTag: 579 case EndTag: return null; 580 case Payload: 581 default: 582 return payloadReader.getVersion(); 583 } 584 } 585 586 @Override 587 public boolean isStandalone() { 588 switch (state) { 589 case StartTag: 590 case EndTag: return true; 591 case Payload: 592 default: 593 return payloadReader.isStandalone(); 594 } 595 } 596 597 @Override 598 public boolean standaloneSet() { 599 switch (state) { 600 case StartTag: 601 case EndTag: return true; 602 case Payload: 603 default: 604 return payloadReader.standaloneSet(); 605 } 606 } 607 608 @Override 609 public String getCharacterEncodingScheme() { 610 switch (state) { 611 case StartTag: 612 case EndTag: return null; 613 case Payload: 614 default: 615 return payloadReader.getCharacterEncodingScheme(); 616 } 617 } 618 619 @Override 620 public String getPITarget() { 621 switch (state) { 622 case StartTag: 623 case EndTag: return null; 624 case Payload: 625 default: 626 return payloadReader.getPITarget(); 627 } 628 } 629 630 @Override 631 public String getPIData() { 632 switch (state) { 633 case StartTag: 634 case EndTag: return null; 635 case Payload: 636 default: 637 return payloadReader.getPIData(); 638 } 639 } 640 641 @Override 642 public String getElementTextTrim() throws XMLStreamException { 643 switch (state) { 644 case StartTag: 645 case EndTag: return null; 646 case Payload: 647 default: 648 return isPayloadReaderEx()? payloadReaderEx().getElementTextTrim() : payloadReader.getElementText().trim(); 649 } 650 } 651 652 @Override 653 public CharSequence getPCDATA() throws XMLStreamException { 654 switch (state) { 655 case StartTag: 656 case EndTag: return null; 657 case Payload: 658 default: 659 return isPayloadReaderEx()? payloadReaderEx().getPCDATA() : payloadReader.getElementText(); 660 } 661 } 662 }