1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.batch.item.xml.stax;
18
19 import java.util.NoSuchElementException;
20
21 import javax.xml.namespace.QName;
22 import javax.xml.stream.XMLEventFactory;
23 import javax.xml.stream.XMLEventReader;
24 import javax.xml.stream.XMLStreamException;
25 import javax.xml.stream.events.EndDocument;
26 import javax.xml.stream.events.EndElement;
27 import javax.xml.stream.events.StartDocument;
28 import javax.xml.stream.events.StartElement;
29 import javax.xml.stream.events.XMLEvent;
30
31 import org.springframework.dao.DataAccessResourceFailureException;
32
33
34
35
36
37
38 public class DefaultFragmentEventReader extends AbstractEventReaderWrapper implements FragmentEventReader {
39
40
41 private boolean startFragmentFollows = false;
42
43
44 private boolean endFragmentFollows = false;
45
46
47 private boolean insideFragment = false;
48
49
50 private boolean fakeDocumentEnd = false;
51
52 private StartDocument startDocumentEvent = null;
53
54 private EndDocument endDocumentEvent = null;
55
56
57
58 private QName fragmentRootName = null;
59
60
61
62 private int matchCounter = 0;
63
64
65
66
67
68 public DefaultFragmentEventReader(XMLEventReader wrappedEventReader) {
69 super(wrappedEventReader);
70 try {
71 startDocumentEvent = (StartDocument) wrappedEventReader.peek();
72 }
73 catch (XMLStreamException e) {
74 throw new DataAccessResourceFailureException("Error reading start document from event reader", e);
75 }
76
77 endDocumentEvent = XMLEventFactory.newInstance().createEndDocument();
78 }
79
80 @Override
81 public void markStartFragment() {
82 startFragmentFollows = true;
83 fragmentRootName = null;
84 }
85
86 @Override
87 public boolean hasNext() {
88 try {
89 if (peek() != null) {
90 return true;
91 }
92 }
93 catch (XMLStreamException e) {
94 throw new DataAccessResourceFailureException("Error reading XML stream", e);
95 }
96 return false;
97 }
98
99 @Override
100 public Object next() {
101 try {
102 return nextEvent();
103 }
104 catch (XMLStreamException e) {
105 throw new DataAccessResourceFailureException("Error reading XML stream", e);
106 }
107 }
108
109 @Override
110 public XMLEvent nextEvent() throws XMLStreamException {
111 if (fakeDocumentEnd) {
112 throw new NoSuchElementException();
113 }
114 XMLEvent event = wrappedEventReader.peek();
115 XMLEvent proxyEvent = alterEvent(event, false);
116 checkFragmentEnd(proxyEvent);
117 if (event == proxyEvent) {
118 wrappedEventReader.nextEvent();
119 }
120
121 return proxyEvent;
122 }
123
124
125
126
127
128
129 private void checkFragmentEnd(XMLEvent event) {
130 if (event.isStartElement() && ((StartElement) event).getName().equals(fragmentRootName)) {
131 matchCounter++;
132 }
133 else if (event.isEndElement() && ((EndElement) event).getName().equals(fragmentRootName)) {
134 matchCounter--;
135 if (matchCounter == 0) {
136 endFragmentFollows = true;
137 }
138 }
139 }
140
141
142
143
144
145
146
147
148 private XMLEvent alterEvent(XMLEvent event, boolean peek) {
149 if (startFragmentFollows) {
150 fragmentRootName = ((StartElement) event).getName();
151 if (!peek) {
152 startFragmentFollows = false;
153 insideFragment = true;
154 }
155 return startDocumentEvent;
156 }
157 else if (endFragmentFollows) {
158 if (!peek) {
159 endFragmentFollows = false;
160 insideFragment = false;
161 fakeDocumentEnd = true;
162 }
163 return endDocumentEvent;
164 }
165 return event;
166 }
167
168 @Override
169 public XMLEvent peek() throws XMLStreamException {
170 if (fakeDocumentEnd) {
171 return null;
172 }
173 return alterEvent(wrappedEventReader.peek(), true);
174 }
175
176
177
178
179
180 @Override
181 public void markFragmentProcessed() {
182 if (insideFragment|| startFragmentFollows) {
183 try {
184 while (!(nextEvent() instanceof EndDocument)) {
185
186 }
187 }
188 catch (XMLStreamException e) {
189 throw new DataAccessResourceFailureException("Error reading XML stream", e);
190 }
191 }
192 fakeDocumentEnd = false;
193 }
194
195 @Override
196 public void reset() {
197 insideFragment = false;
198 startFragmentFollows = false;
199 endFragmentFollows = false;
200 fakeDocumentEnd = false;
201 fragmentRootName = null;
202 matchCounter = 0;
203 }
204
205 }