spring-batch DefaultFragmentEventReader 源码
spring-batch DefaultFragmentEventReader 代码
文件路径:/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/DefaultFragmentEventReader.java
/*
* Copyright 2006-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item.xml.stax;
import java.util.NoSuchElementException;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.EndDocument;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartDocument;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.springframework.batch.item.ItemStreamException;
/**
* Default implementation of {@link FragmentEventReader}
*
* @author Robert Kasanicky
*/
public class DefaultFragmentEventReader extends AbstractEventReaderWrapper implements FragmentEventReader {
// true when the next event is the StartElement of next fragment
private boolean startFragmentFollows = false;
// true when the next event is the EndElement of current fragment
private boolean endFragmentFollows = false;
// true while cursor is inside fragment
private boolean insideFragment = false;
// true when reader should behave like the cursor was at the end of document
private boolean fakeDocumentEnd = false;
private StartDocument startDocumentEvent = null;
private EndDocument endDocumentEvent = null;
// fragment root name is remembered so that the matching closing element can
// be identified
private QName fragmentRootName = null;
// counts the occurrences of current fragmentRootName (increased for
// StartElement, decreased for EndElement)
private int matchCounter = 0;
/**
* Caches the StartDocument event for later use.
* @param wrappedEventReader the original wrapped event reader
*/
public DefaultFragmentEventReader(XMLEventReader wrappedEventReader) {
super(wrappedEventReader);
try {
startDocumentEvent = (StartDocument) wrappedEventReader.peek();
}
catch (XMLStreamException e) {
throw new ItemStreamException("Error reading start document from event reader", e);
}
endDocumentEvent = XMLEventFactory.newInstance().createEndDocument();
}
@Override
public void markStartFragment() {
startFragmentFollows = true;
fragmentRootName = null;
}
@Override
public boolean hasNext() {
try {
if (peek() != null) {
return true;
}
}
catch (XMLStreamException e) {
throw new ItemStreamException("Error reading XML stream", e);
}
return false;
}
@Override
public Object next() {
try {
return nextEvent();
}
catch (XMLStreamException e) {
throw new ItemStreamException("Error reading XML stream", e);
}
}
@Override
public XMLEvent nextEvent() throws XMLStreamException {
if (fakeDocumentEnd) {
throw new NoSuchElementException();
}
XMLEvent event = wrappedEventReader.peek();
XMLEvent proxyEvent = alterEvent(event, false);
checkFragmentEnd(proxyEvent);
if (event == proxyEvent) {
wrappedEventReader.nextEvent();
}
return proxyEvent;
}
/**
* Sets the endFragmentFollows flag to true if next event is the last event of the
* fragment.
* @param event peek() from wrapped event reader
*/
private void checkFragmentEnd(XMLEvent event) {
if (event.isStartElement() && ((StartElement) event).getName().equals(fragmentRootName)) {
matchCounter++;
}
else if (event.isEndElement() && ((EndElement) event).getName().equals(fragmentRootName)) {
matchCounter--;
if (matchCounter == 0) {
endFragmentFollows = true;
}
}
}
/**
* @param event peek() from wrapped event reader
* @param peek if true do not change the internal state
* @return StartDocument event if peek() points to beginning of fragment EndDocument
* event if cursor is right behind the end of fragment original event otherwise
*/
private XMLEvent alterEvent(XMLEvent event, boolean peek) {
if (startFragmentFollows) {
fragmentRootName = ((StartElement) event).getName();
if (!peek) {
startFragmentFollows = false;
insideFragment = true;
}
return startDocumentEvent;
}
else if (endFragmentFollows) {
if (!peek) {
endFragmentFollows = false;
insideFragment = false;
fakeDocumentEnd = true;
}
return endDocumentEvent;
}
return event;
}
@Override
public XMLEvent peek() throws XMLStreamException {
if (fakeDocumentEnd) {
return null;
}
return alterEvent(wrappedEventReader.peek(), true);
}
/**
* Finishes reading the fragment in case the fragment was processed without being read
* until the end.
*/
@Override
public void markFragmentProcessed() {
if (insideFragment || startFragmentFollows) {
try {
while (!(nextEvent() instanceof EndDocument)) {
// just read all events until EndDocument
}
}
catch (XMLStreamException e) {
throw new ItemStreamException("Error reading XML stream", e);
}
}
fakeDocumentEnd = false;
}
@Override
public void reset() {
insideFragment = false;
startFragmentFollows = false;
endFragmentFollows = false;
fakeDocumentEnd = false;
fragmentRootName = null;
matchCounter = 0;
}
}
相关信息
相关文章
spring-batch AbstractEventReaderWrapper 源码
spring-batch AbstractEventWriterWrapper 源码
spring-batch FragmentEventReader 源码
spring-batch NoStartEndDocumentStreamWriter 源码
spring-batch UnclosedElementCollectingEventWriter 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦