11/*
2- * Copyright 2006-2020 the original author or authors.
2+ * Copyright 2006-2022 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
5252import org .springframework .batch .support .transaction .TransactionAwareBufferedWriter ;
5353import org .springframework .beans .factory .InitializingBean ;
5454import org .springframework .core .io .Resource ;
55- import org .springframework .dao .DataAccessResourceFailureException ;
5655import org .springframework .oxm .Marshaller ;
5756import org .springframework .oxm .XmlMappingException ;
5857import org .springframework .util .Assert ;
6463/**
6564 * An implementation of {@link ItemWriter} which uses StAX and
6665 * {@link Marshaller} for serializing object to XML.
67- *
66+ *
6867 * This item writer also provides restart, statistics and transaction features
6968 * by implementing corresponding interfaces.
70- *
69+ *
7170 * The implementation is <b>not</b> thread-safe.
72- *
71+ *
7372 * @author Peter Zozom
7473 * @author Robert Kasanicky
7574 * @author Michael Minella
@@ -98,7 +97,7 @@ public class StaxEventItemWriter<T> extends AbstractItemStreamItemWriter<T> impl
9897
9998 // unclosed header callback elements property name
10099 private static final String UNCLOSED_HEADER_CALLBACK_ELEMENTS_NAME = "unclosedHeaderCallbackElements" ;
101-
100+
102101 // restart data property name
103102 private static final String WRITE_STATISTICS_NAME = "record.count" ;
104103
@@ -159,11 +158,11 @@ public class StaxEventItemWriter<T> extends AbstractItemStreamItemWriter<T> impl
159158 private boolean forceSync ;
160159
161160 private boolean shouldDeleteIfEmpty = false ;
162-
161+
163162 private boolean restarted = false ;
164163
165164 private boolean initialized = false ;
166-
165+
167166 // List holding the QName of elements that were opened in the header callback, but not closed
168167 private List <QName > unclosedHeaderCallbackElements = Collections .emptyList ();
169168
@@ -173,7 +172,7 @@ public StaxEventItemWriter() {
173172
174173 /**
175174 * Set output file.
176- *
175+ *
177176 * @param resource the output file
178177 */
179178 @ Override
@@ -183,7 +182,7 @@ public void setResource(Resource resource) {
183182
184183 /**
185184 * Set Object to XML marshaller.
186- *
185+ *
187186 * @param marshaller the Object to XML marshaller
188187 */
189188 public void setMarshaller (Marshaller marshaller ) {
@@ -212,7 +211,7 @@ public void setFooterCallback(StaxWriterCallback footerCallback) {
212211 /**
213212 * Flag to indicate that writes should be deferred to the end of a
214213 * transaction if present. Defaults to true.
215- *
214+ *
216215 * @param transactional the flag to set
217216 */
218217 public void setTransactional (boolean transactional ) {
@@ -225,7 +224,7 @@ public void setTransactional(boolean transactional) {
225224 * be lost if the OS crashes in between a write and a cache flush. Setting
226225 * to true may result in slower performance for usage patterns involving
227226 * many frequent writes.
228- *
227+ *
229228 * @param forceSync the flag value to set
230229 */
231230 public void setForceSync (boolean forceSync ) {
@@ -235,7 +234,7 @@ public void setForceSync(boolean forceSync) {
235234 /**
236235 * Flag to indicate that the target file should be deleted if no items have
237236 * been written (other than header and footer) on close. Defaults to false.
238- *
237+ *
239238 * @param shouldDeleteIfEmpty the flag value to set
240239 */
241240 public void setShouldDeleteIfEmpty (boolean shouldDeleteIfEmpty ) {
@@ -244,7 +243,7 @@ public void setShouldDeleteIfEmpty(boolean shouldDeleteIfEmpty) {
244243
245244 /**
246245 * Get used encoding.
247- *
246+ *
248247 * @return the encoding used
249248 */
250249 public String getEncoding () {
@@ -253,7 +252,7 @@ public String getEncoding() {
253252
254253 /**
255254 * Set encoding to be used for output file.
256- *
255+ *
257256 * @param encoding the encoding to be used
258257 */
259258 public void setEncoding (String encoding ) {
@@ -271,7 +270,7 @@ public String getVersion() {
271270
272271 /**
273272 * Set XML version to be used for output XML.
274- *
273+ *
275274 * @param version the XML version to be used
276275 */
277276 public void setVersion (String version ) {
@@ -303,7 +302,7 @@ public void setStandalone(Boolean standalone) {
303302
304303 /**
305304 * Get the tag name of the root element.
306- *
305+ *
307306 * @return the root element tag name
308307 */
309308 public String getRootTagName () {
@@ -314,16 +313,16 @@ public String getRootTagName() {
314313 * Set the tag name of the root element. If not set, default name is used
315314 * ("root"). Namespace URI and prefix can also be set optionally using the
316315 * notation:
317- *
316+ *
318317 * <pre>
319318 * {uri}prefix:root
320319 * </pre>
321- *
320+ *
322321 * The prefix is optional (defaults to empty), but if it is specified then
323322 * the uri must be provided. In addition you might want to declare other
324323 * namespaces using the {@link #setRootElementAttributes(Map) root
325324 * attributes}.
326- *
325+ *
327326 * @param rootTagName the tag name to be used for the root element
328327 */
329328 public void setRootTagName (String rootTagName ) {
@@ -332,7 +331,7 @@ public void setRootTagName(String rootTagName) {
332331
333332 /**
334333 * Get the namespace prefix of the root element. Empty by default.
335- *
334+ *
336335 * @return the rootTagNamespacePrefix
337336 */
338337 public String getRootTagNamespacePrefix () {
@@ -341,7 +340,7 @@ public String getRootTagNamespacePrefix() {
341340
342341 /**
343342 * Get the namespace of the root element.
344- *
343+ *
345344 * @return the rootTagNamespace
346345 */
347346 public String getRootTagNamespace () {
@@ -350,7 +349,7 @@ public String getRootTagNamespace() {
350349
351350 /**
352351 * Get attributes of the root element.
353- *
352+ *
354353 * @return attributes of the root element
355354 */
356355 public Map <String , String > getRootElementAttributes () {
@@ -360,7 +359,7 @@ public Map<String, String> getRootElementAttributes() {
360359 /**
361360 * Set the root element attributes to be written. If any of the key names
362361 * begin with "xmlns:" then they are treated as namespace declarations.
363- *
362+ *
364363 * @param rootElementAttributes attributes of the root element
365364 */
366365 public void setRootElementAttributes (Map <String , String > rootElementAttributes ) {
@@ -370,7 +369,7 @@ public void setRootElementAttributes(Map<String, String> rootElementAttributes)
370369 /**
371370 * Set "overwrite" flag for the output file. Flag is ignored when output
372371 * file processing is restarted.
373- *
372+ *
374373 * @param overwriteOutput If set to true, output file will be overwritten
375374 * (this flag is ignored when processing is restart).
376375 */
@@ -403,7 +402,7 @@ public void afterPropertiesSet() throws Exception {
403402 * Open the output source
404403 *
405404 * @param executionContext the batch context.
406- *
405+ *
407406 * @see org.springframework.batch.item.ItemStream#open(ExecutionContext)
408407 */
409408 @ SuppressWarnings ("unchecked" )
@@ -414,7 +413,7 @@ public void open(ExecutionContext executionContext) {
414413 Assert .notNull (resource , "The resource must be set" );
415414
416415 long startAtPosition = 0 ;
417-
416+
418417 // if restart data is provided, restart from provided offset
419418 // otherwise start from beginning
420419 if (executionContext .containsKey (getExecutionContextKey (RESTART_DATA_NAME ))) {
@@ -424,7 +423,7 @@ public void open(ExecutionContext executionContext) {
424423 unclosedHeaderCallbackElements = (List <QName >) executionContext
425424 .get (getExecutionContextKey (UNCLOSED_HEADER_CALLBACK_ELEMENTS_NAME ));
426425 }
427-
426+
428427 restarted = true ;
429428 if (shouldDeleteIfEmpty && currentRecordCount == 0 ) {
430429 // previous execution deleted the output file because no items were written
@@ -476,7 +475,7 @@ private void open(long position) {
476475 setPosition (position );
477476 }
478477 catch (IOException ioe ) {
479- throw new DataAccessResourceFailureException ("Unable to write to file resource: [" + resource + "]" , ioe );
478+ throw new ItemStreamException ("Unable to write to file resource: [" + resource + "]" , ioe );
480479 }
481480
482481 XMLOutputFactory outputFactory = createXmlOutputFactory ();
@@ -524,14 +523,14 @@ public void run() {
524523 }
525524 }
526525 catch (XMLStreamException xse ) {
527- throw new DataAccessResourceFailureException ("Unable to write to file resource: [" + resource + "]" , xse );
526+ throw new ItemStreamException ("Unable to write to file resource: [" + resource + "]" , xse );
528527 }
529528 catch (UnsupportedEncodingException e ) {
530- throw new DataAccessResourceFailureException ("Unable to write to file resource: [" + resource
529+ throw new ItemStreamException ("Unable to write to file resource: [" + resource
531530 + "] with encoding=[" + encoding + "]" , e );
532- }
531+ }
533532 catch (IOException e ) {
534- throw new DataAccessResourceFailureException ("Unable to write to file resource: [" + resource + "]" , e );
533+ throw new ItemStreamException ("Unable to write to file resource: [" + resource + "]" , e );
535534 }
536535 }
537536
@@ -588,7 +587,7 @@ protected Result createStaxResult() {
588587 * <li>rootTagNamespacePrefix for rootTagName</li>
589588 * <li>any other xmlns namespace prefix declarations in the root element attributes</li>
590589 * </ul>
591- *
590+ *
592591 * @param writer XML event writer
593592 *
594593 * @throws XMLStreamException thrown if error occurs while setting the
@@ -627,7 +626,7 @@ protected void initNamespaceContext(XMLEventWriter writer) throws XMLStreamExcep
627626 * </ul>
628627 * If this is not sufficient for you, simply override this method. Encoding,
629628 * version and root tag name can be retrieved with corresponding getters.
630- *
629+ *
631630 * @param writer XML event writer
632631 *
633632 * @throws XMLStreamException thrown if error occurs.
@@ -685,7 +684,7 @@ protected void startDocument(XMLEventWriter writer) throws XMLStreamException {
685684
686685 /**
687686 * Writes the EndDocument tag manually.
688- *
687+ *
689688 * @param writer XML event writer
690689 *
691690 * @throws XMLStreamException thrown if error occurs.
@@ -700,13 +699,13 @@ protected void endDocument(XMLEventWriter writer) throws XMLStreamException {
700699 bufferedWriter .write ("</" + nsPrefix + getRootTagName () + ">" );
701700 }
702701 catch (IOException ioe ) {
703- throw new DataAccessResourceFailureException ("Unable to close file resource: [" + resource + "]" , ioe );
702+ throw new XMLStreamException ("Unable to close file resource: [" + resource + "]" , ioe );
704703 }
705704 }
706705
707706 /**
708707 * Flush and close the output source.
709- *
708+ *
710709 * @see org.springframework.batch.item.ItemStream#close()
711710 */
712711 @ Override
@@ -727,7 +726,7 @@ public void close() {
727726 if (restarted && !unclosedHeaderCallbackElements .isEmpty ()) {
728727 footerCallbackWriter = new UnopenedElementClosingEventWriter (
729728 delegateEventWriter , bufferedWriter , unclosedHeaderCallbackElements );
730- }
729+ }
731730 footerCallback .write (footerCallbackWriter );
732731 }
733732 delegateEventWriter .flush ();
@@ -784,7 +783,7 @@ private void closeStream() {
784783
785784 /**
786785 * Write the value objects and flush them to the file.
787- *
786+ *
788787 * @param items the value object
789788 *
790789 * @throws IOException thrown if general error occurs.
@@ -809,18 +808,18 @@ public void write(List<? extends T> items) throws XmlMappingException, IOExcepti
809808 eventWriter .flush ();
810809 if (forceSync ) {
811810 channel .force (false );
812- }
811+ }
813812 }
814813 catch (XMLStreamException | IOException e ) {
815814 throw new WriteFailedException ("Failed to flush the events" , e );
816- }
815+ }
817816 }
818817
819818 /**
820819 * Get the restart data.
821820 *
822821 * @param executionContext the batch context.
823- *
822+ *
824823 * @see org.springframework.batch.item.ItemStream#update(ExecutionContext)
825824 */
826825 @ Override
@@ -833,14 +832,14 @@ public void update(ExecutionContext executionContext) {
833832 if (!unclosedHeaderCallbackElements .isEmpty ()) {
834833 executionContext .put (getExecutionContextKey (UNCLOSED_HEADER_CALLBACK_ELEMENTS_NAME ),
835834 unclosedHeaderCallbackElements );
836- }
835+ }
837836 }
838837 }
839838
840839 /*
841840 * Get the actual position in file channel. This method flushes any buffered
842841 * data before position is read.
843- *
842+ *
844843 * @return byte offset in file channel
845844 */
846845 private long getPosition () {
@@ -855,15 +854,15 @@ private long getPosition() {
855854 }
856855 }
857856 catch (Exception e ) {
858- throw new DataAccessResourceFailureException ("Unable to write to file resource: [" + resource + "]" , e );
857+ throw new ItemStreamException ("Unable to write to file resource: [" + resource + "]" , e );
859858 }
860859
861860 return position ;
862861 }
863862
864863 /**
865864 * Set the file channel position.
866- *
865+ *
867866 * @param newPosition new file channel position
868867 */
869868 private void setPosition (long newPosition ) {
@@ -873,7 +872,7 @@ private void setPosition(long newPosition) {
873872 channel .position (newPosition );
874873 }
875874 catch (IOException e ) {
876- throw new DataAccessResourceFailureException ("Unable to write to file resource: [" + resource + "]" , e );
875+ throw new ItemStreamException ("Unable to write to file resource: [" + resource + "]" , e );
877876 }
878877
879878 }
0 commit comments