1 /*
2  * Copyright (c) 2005, 2006, 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.org.apache.xerces.internal.impl;
27 
28 import javax.xml.stream.XMLStreamReader;
29 import javax.xml.stream.StreamFilter;
30 import javax.xml.stream.XMLStreamException;
31 import javax.xml.namespace.QName;
32 import javax.xml.stream.events.XMLEvent;
33 
34 
35 /**
36  *
37  * @author Joe Wang:
38  * This is a rewrite of the original class. The focus is on removing caching, and make the filtered
39  * stream reader more compatible with those in other implementations. Note however, that this version
40  * will not solve all the issues related to the undefined condition in the spec. The priority is
41  * to pass the TCK. Issues arising due to the requirement, that is, (1) should it initiate at BEGIN_DOCUMENT
42  * or an accepted event; (2) should hasNext() advance the underlining stream in order to find an acceptable
43  * event, would have to wait until 1.1 of StAX in which the filtered stream reader would be defined more clearly.
44  */
45 
46 public class XMLStreamFilterImpl implements javax.xml.stream.XMLStreamReader {
47 
48     private StreamFilter fStreamFilter = null;
49     private XMLStreamReader fStreamReader = null;
50     private int fCurrentEvent;
51     private boolean fEventAccepted = false;
52 
53     /**the very issue around a long discussion. but since we must pass the TCK, we have to allow
54      * hasNext() to advance the underlining stream in order to find the next acceptable event
55      */
56     private boolean fStreamAdvancedByHasNext = false;
57 
58     /**
59      * Creates a new instance of XMLStreamFilterImpl, advancing the reader to
60      * the next event accepted by the filter, if not already positioned on an
61      * accepted event.
62      *
63      * @param reader
64      *            the reader to filter
65      * @param filter
66      *            the filter to apply to the reader
67      * @throws XMLStreamException
68      *             when an {@code XMLStreamException} is thrown when
69      *             advancing the reader to an accepted event.
70      **/
XMLStreamFilterImpl(XMLStreamReader reader,StreamFilter filter)71     public XMLStreamFilterImpl(XMLStreamReader reader,StreamFilter filter) throws XMLStreamException {
72         fStreamReader = reader;
73         this.fStreamFilter = filter;
74 
75         //this is debatable to initiate at an acceptable event,
76         //but it's neccessary in order to pass the TCK and yet avoid skipping element
77         if (fStreamFilter.accept(fStreamReader)) {
78             fEventAccepted = true;
79         } else {
80             findNextEvent();
81         }
82     }
83 
84     /**
85      *
86      * @param sf
87      */
setStreamFilter(StreamFilter sf)88     protected void setStreamFilter(StreamFilter sf){
89         this.fStreamFilter = sf;
90     }
91 
92     /**
93      *
94      * @return
95      * @throws XMLStreamException
96      */
next()97     public int next() throws XMLStreamException {
98         if (fStreamAdvancedByHasNext && fEventAccepted) {
99             fStreamAdvancedByHasNext = false;
100             return fCurrentEvent;
101         }
102         int event = findNextEvent();
103         if (event != -1) {
104             return event;
105         }
106 
107         throw new IllegalStateException("The stream reader has reached the end of the document, or there are no more "+
108                                     " items to return");
109     }
110     /**
111      *
112      * @throws XMLStreamException
113      * @return
114      */
nextTag()115     public int nextTag() throws XMLStreamException {
116         if (fStreamAdvancedByHasNext && fEventAccepted &&
117                 (fCurrentEvent == XMLEvent.START_ELEMENT || fCurrentEvent == XMLEvent.START_ELEMENT)) {
118             fStreamAdvancedByHasNext = false;
119             return fCurrentEvent;
120         }
121 
122         int event = findNextTag();
123         if (event != -1) {
124             return event;
125         }
126         throw new IllegalStateException("The stream reader has reached the end of the document, or there are no more "+
127                                     " items to return");
128     }
129 
130     /**
131      *
132      * @throws XMLStreamException
133      * @return
134      */
hasNext()135     public boolean hasNext() throws XMLStreamException {
136         if (fStreamReader.hasNext()) {
137             if (!fEventAccepted) {
138                 if ((fCurrentEvent = findNextEvent()) == -1) {
139                     return false;
140                 } else {
141                     fStreamAdvancedByHasNext = true;
142                 }
143             }
144             return true;
145         }
146         return false;
147     }
148 
findNextEvent()149     private int findNextEvent() throws XMLStreamException {
150         fStreamAdvancedByHasNext = false;
151         while(fStreamReader.hasNext()){
152             fCurrentEvent = fStreamReader.next();
153             if(fStreamFilter.accept(fStreamReader)){
154                 fEventAccepted = true;
155                 return fCurrentEvent;
156             }
157         }
158         //although it seems that IllegalStateException should be thrown when next() is called
159         //on a stream that has no more items, we have to assume END_DOCUMENT is always accepted
160         //in order to pass the TCK
161         if (fCurrentEvent == XMLEvent.END_DOCUMENT)
162             return fCurrentEvent;
163         else
164             return -1;
165     }
findNextTag()166     private int findNextTag() throws XMLStreamException {
167         fStreamAdvancedByHasNext = false;
168         while(fStreamReader.hasNext()){
169             fCurrentEvent = fStreamReader.nextTag();
170             if(fStreamFilter.accept(fStreamReader)){
171                 fEventAccepted = true;
172                 return fCurrentEvent;
173             }
174         }
175         if (fCurrentEvent == XMLEvent.END_DOCUMENT)
176             return fCurrentEvent;
177         else
178             return -1;
179     }
180     /**
181      *
182      * @throws XMLStreamException
183      */
close()184     public void close() throws XMLStreamException {
185         fStreamReader.close();
186     }
187 
188     /**
189      *
190      * @return
191      */
getAttributeCount()192     public int getAttributeCount() {
193         return fStreamReader.getAttributeCount();
194     }
195 
196     /**
197      *
198      * @param index
199      * @return
200      */
getAttributeName(int index)201     public QName getAttributeName(int index) {
202         return fStreamReader.getAttributeName(index);
203     }
204 
205     /**
206      *
207      * @param index
208      * @return
209      */
getAttributeNamespace(int index)210     public String getAttributeNamespace(int index) {
211         return fStreamReader.getAttributeNamespace(index);
212     }
213 
214     /**
215      *
216      * @param index
217      * @return
218      */
getAttributePrefix(int index)219     public String getAttributePrefix(int index) {
220         return fStreamReader.getAttributePrefix(index);
221     }
222 
223     /**
224      *
225      * @param index
226      * @return
227      */
getAttributeType(int index)228     public String getAttributeType(int index) {
229         return fStreamReader.getAttributeType(index);
230     }
231 
232     /**
233      *
234      * @param index
235      * @return
236      */
getAttributeValue(int index)237     public String getAttributeValue(int index) {
238         return fStreamReader.getAttributeValue(index);
239     }
240 
241     /**
242      *
243      * @param namespaceURI
244      * @param localName
245      * @return
246      */
getAttributeValue(String namespaceURI, String localName)247     public String getAttributeValue(String namespaceURI, String localName) {
248         return fStreamReader.getAttributeValue(namespaceURI,localName);
249     }
250 
251     /**
252      *
253      * @return
254      */
getCharacterEncodingScheme()255     public String getCharacterEncodingScheme() {
256         return fStreamReader.getCharacterEncodingScheme();
257     }
258 
259     /**
260      *
261      * @throws XMLStreamException
262      * @return
263      */
getElementText()264     public String getElementText() throws XMLStreamException {
265         return fStreamReader.getElementText();
266     }
267 
268     /**
269      *
270      * @return
271      */
getEncoding()272     public String getEncoding() {
273         return fStreamReader.getEncoding();
274     }
275 
276     /**
277      *
278      * @return
279      */
getEventType()280     public int getEventType() {
281         return fStreamReader.getEventType();
282     }
283 
284     /**
285      *
286      * @return
287      */
getLocalName()288     public String getLocalName() {
289         return fStreamReader.getLocalName();
290     }
291 
292     /**
293      *
294      * @return
295      */
getLocation()296     public javax.xml.stream.Location getLocation() {
297         return fStreamReader.getLocation();
298     }
299 
300     /**
301      *
302      * @return
303      */
getName()304     public javax.xml.namespace.QName getName() {
305         return fStreamReader.getName();
306     }
307 
308     /**
309      *
310      * @return
311      */
getNamespaceContext()312     public javax.xml.namespace.NamespaceContext getNamespaceContext() {
313         return fStreamReader.getNamespaceContext();
314     }
315 
316     /**
317      *
318      * @return
319      */
getNamespaceCount()320     public int getNamespaceCount() {
321         return fStreamReader.getNamespaceCount();
322     }
323 
324     /**
325      *
326      * @param index
327      * @return
328      */
getNamespacePrefix(int index)329     public String getNamespacePrefix(int index) {
330         return fStreamReader.getNamespacePrefix(index);
331     }
332 
333     /**
334      *
335      * @return
336      */
getNamespaceURI()337     public String getNamespaceURI() {
338         return fStreamReader.getNamespaceURI();
339     }
340 
341     /**
342      *
343      * @param index
344      * @return
345      */
getNamespaceURI(int index)346     public String getNamespaceURI(int index) {
347         return fStreamReader.getNamespaceURI(index);
348     }
349 
350     /**
351      *
352      * @param prefix
353      * @return
354      */
getNamespaceURI(String prefix)355     public String getNamespaceURI(String prefix) {
356         return fStreamReader.getNamespaceURI(prefix);
357     }
358 
359     /**
360      *
361      * @return
362      */
getPIData()363     public String getPIData() {
364         return fStreamReader.getPIData();
365     }
366 
367     /**
368      *
369      * @return
370      */
getPITarget()371     public String getPITarget() {
372         return fStreamReader.getPITarget();
373     }
374 
375     /**
376      *
377      * @return
378      */
getPrefix()379     public String getPrefix() {
380         return fStreamReader.getPrefix();
381     }
382 
383     /**
384      *
385      * @param name
386      * @throws IllegalArgumentException
387      * @return
388      */
getProperty(java.lang.String name)389     public Object getProperty(java.lang.String name) throws java.lang.IllegalArgumentException {
390         return fStreamReader.getProperty(name);
391     }
392 
393     /**
394      *
395      * @return
396      */
getText()397     public String getText() {
398         return fStreamReader.getText();
399     }
400 
401     /**
402      *
403      * @return
404      */
getTextCharacters()405     public char[] getTextCharacters() {
406         return fStreamReader.getTextCharacters();
407     }
408 
409     /**
410      *
411      * @param sourceStart
412      * @param target
413      * @param targetStart
414      * @param length
415      * @throws XMLStreamException
416      * @return
417      */
getTextCharacters(int sourceStart, char[] target, int targetStart, int length)418     public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException {
419         return fStreamReader.getTextCharacters(sourceStart, target,targetStart,length);
420     }
421 
422     /**
423      *
424      * @return
425      */
getTextLength()426     public int getTextLength() {
427         return fStreamReader.getTextLength();
428     }
429 
430     /**
431      *
432      * @return
433      */
getTextStart()434     public int getTextStart() {
435         return fStreamReader.getTextStart();
436     }
437 
438     /**
439      *
440      * @return
441      */
getVersion()442     public String getVersion() {
443         return fStreamReader.getVersion();
444     }
445 
446     /**
447      *
448      * @return
449      */
hasName()450     public boolean hasName() {
451         return fStreamReader.hasName();
452     }
453 
454     /**
455      *
456      * @return
457      */
hasText()458     public boolean hasText() {
459         return fStreamReader.hasText();
460     }
461 
462     /**
463      *
464      * @return
465      * @param index
466      */
isAttributeSpecified(int index)467     public boolean isAttributeSpecified(int index) {
468         return fStreamReader.isAttributeSpecified(index);
469     }
470 
471     /**
472      *
473      * @return
474      */
isCharacters()475     public boolean isCharacters() {
476         return fStreamReader.isCharacters();
477     }
478 
479     /**
480      *
481      * @return
482      */
isEndElement()483     public boolean isEndElement() {
484         return fStreamReader.isEndElement();
485     }
486 
487     /**
488      *
489      * @return
490      */
isStandalone()491     public boolean isStandalone() {
492         return fStreamReader.isStandalone();
493     }
494 
495     /**
496      *
497      * @return
498      */
isStartElement()499     public boolean isStartElement() {
500         return fStreamReader.isStartElement();
501     }
502 
503     /**
504      *
505      * @return
506      */
isWhiteSpace()507     public boolean isWhiteSpace() {
508         return fStreamReader.isWhiteSpace();
509     }
510 
511 
512     /**
513      *
514      * @param type
515      * @param namespaceURI
516      * @param localName
517      * @throws XMLStreamException
518      */
require(int type, String namespaceURI, String localName)519     public void require(int type, String namespaceURI, String localName) throws XMLStreamException {
520         fStreamReader.require(type,namespaceURI,localName);
521     }
522 
523     /**
524      *
525      * @return
526      */
standaloneSet()527     public boolean standaloneSet() {
528         return fStreamReader.standaloneSet();
529     }
530 
531     /**
532      *
533      * @param index
534      * @return
535      */
getAttributeLocalName(int index)536     public String getAttributeLocalName(int index){
537         return fStreamReader.getAttributeLocalName(index);
538     }
539 }
540