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 }