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 public void markStartFragment() {
81 startFragmentFollows = true;
82 fragmentRootName = null;
83 }
84
85 public boolean hasNext() {
86 try {
87 if (peek() != null) {
88 return true;
89 }
90 }
91 catch (XMLStreamException e) {
92 throw new DataAccessResourceFailureException("Error reading XML stream", e);
93 }
94 return false;
95 }
96
97 public Object next() {
98 try {
99 return nextEvent();
100 }
101 catch (XMLStreamException e) {
102 throw new DataAccessResourceFailureException("Error reading XML stream", e);
103 }
104 }
105
106 public XMLEvent nextEvent() throws XMLStreamException {
107 if (fakeDocumentEnd) {
108 throw new NoSuchElementException();
109 }
110 XMLEvent event = wrappedEventReader.peek();
111 XMLEvent proxyEvent = alterEvent(event, false);
112 checkFragmentEnd(proxyEvent);
113 if (event == proxyEvent) {
114 wrappedEventReader.nextEvent();
115 }
116
117 return proxyEvent;
118 }
119
120
121
122
123
124
125 private void checkFragmentEnd(XMLEvent event) {
126 if (event.isStartElement() && ((StartElement) event).getName().equals(fragmentRootName)) {
127 matchCounter++;
128 }
129 else if (event.isEndElement() && ((EndElement) event).getName().equals(fragmentRootName)) {
130 matchCounter--;
131 if (matchCounter == 0) {
132 endFragmentFollows = true;
133 }
134 }
135 }
136
137
138
139
140
141
142
143
144 private XMLEvent alterEvent(XMLEvent event, boolean peek) {
145 if (startFragmentFollows) {
146 fragmentRootName = ((StartElement) event).getName();
147 if (!peek) {
148 startFragmentFollows = false;
149 insideFragment = true;
150 }
151 return startDocumentEvent;
152 }
153 else if (endFragmentFollows) {
154 if (!peek) {
155 endFragmentFollows = false;
156 insideFragment = false;
157 fakeDocumentEnd = true;
158 }
159 return endDocumentEvent;
160 }
161 return event;
162 }
163
164 public XMLEvent peek() throws XMLStreamException {
165 if (fakeDocumentEnd) {
166 return null;
167 }
168 return alterEvent(wrappedEventReader.peek(), true);
169 }
170
171
172
173
174
175 public void markFragmentProcessed() {
176 if (insideFragment|| startFragmentFollows) {
177 try {
178 while (!(nextEvent() instanceof EndDocument)) {
179
180 }
181 }
182 catch (XMLStreamException e) {
183 throw new DataAccessResourceFailureException("Error reading XML stream", e);
184 }
185 }
186 fakeDocumentEnd = false;
187 }
188
189 public void reset() {
190 insideFragment = false;
191 startFragmentFollows = false;
192 endFragmentFollows = false;
193 fakeDocumentEnd = false;
194 fragmentRootName = null;
195 matchCounter = 0;
196 }
197
198 }