1 package org.springframework.batch.item.xml;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertTrue;
5 import static org.junit.Assert.fail;
6
7 import java.io.File;
8 import java.io.IOException;
9 import java.util.Collections;
10 import java.util.List;
11
12 import javax.xml.stream.XMLEventFactory;
13 import javax.xml.stream.XMLEventWriter;
14 import javax.xml.stream.XMLStreamException;
15 import javax.xml.transform.Result;
16
17 import org.apache.commons.io.FileUtils;
18 import org.junit.Before;
19 import org.junit.Test;
20 import org.springframework.batch.item.ExecutionContext;
21 import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
22 import org.springframework.core.io.FileSystemResource;
23 import org.springframework.core.io.Resource;
24 import org.springframework.oxm.Marshaller;
25 import org.springframework.oxm.XmlMappingException;
26 import org.springframework.transaction.PlatformTransactionManager;
27 import org.springframework.transaction.TransactionStatus;
28 import org.springframework.transaction.support.TransactionCallback;
29 import org.springframework.transaction.support.TransactionTemplate;
30 import org.springframework.util.ClassUtils;
31 import org.springframework.util.StringUtils;
32
33
34
35
36 public class TransactionalStaxEventItemWriterTests {
37
38
39 private StaxEventItemWriter<Object> writer;
40
41 private PlatformTransactionManager transactionManager = new ResourcelessTransactionManager();
42
43
44 private Resource resource;
45
46 private ExecutionContext executionContext;
47
48
49 private Object item = new Object() {
50 public String toString() {
51 return ClassUtils.getShortName(StaxEventItemWriter.class) + "-testString";
52 }
53 };
54
55 private List<? extends Object> items = Collections.singletonList(item);
56
57 private static final String TEST_STRING = "<!--" + ClassUtils.getShortName(StaxEventItemWriter.class)
58 + "-testString-->";
59
60 @Before
61 public void setUp() throws Exception {
62 resource = new FileSystemResource(File.createTempFile("StaxEventWriterOutputSourceTests", ".xml"));
63 writer = createItemWriter();
64 executionContext = new ExecutionContext();
65 }
66
67
68
69
70 @Test
71 public void testWriteAndFlush() throws Exception {
72 writer.open(executionContext);
73 new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
74 public Object doInTransaction(TransactionStatus status) {
75 try {
76 writer.write(items);
77 }
78 catch ( Exception e) {
79 throw new RuntimeException(e);
80 }
81 return null;
82 }
83 });
84 writer.close();
85 String content = outputFileContent();
86 assertTrue("Wrong content: " + content, content.contains(TEST_STRING));
87 }
88
89
90
91
92 @Test
93 public void testWriteWithHeaderAfterRollback() throws Exception {
94 writer.setHeaderCallback(new StaxWriterCallback(){
95
96 public void write(XMLEventWriter writer) throws IOException {
97 XMLEventFactory factory = XMLEventFactory.newInstance();
98 try {
99 writer.add(factory.createStartElement("", "", "header"));
100 writer.add(factory.createEndElement("", "", "header"));
101 }
102 catch (XMLStreamException e) {
103 throw new RuntimeException(e);
104 }
105
106 }
107
108 });
109 writer.open(executionContext);
110 try {
111 new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
112 public Object doInTransaction(TransactionStatus status) {
113 try {
114 writer.write(items);
115 }
116 catch (Exception e) {
117 throw new RuntimeException(e);
118 }
119 throw new RuntimeException("Planned");
120 }
121 });
122 fail("Expected RuntimeException");
123 }
124 catch (RuntimeException e) {
125
126 }
127 writer.close();
128 writer.open(executionContext);
129 new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
130 public Object doInTransaction(TransactionStatus status) {
131 try {
132 writer.write(items);
133 }
134 catch (Exception e) {
135 throw new RuntimeException(e);
136 }
137 return null;
138 }
139 });
140 writer.close();
141 String content = outputFileContent();
142 assertEquals("Wrong content: " + content, 1, StringUtils.countOccurrencesOf(content, ("<header/>")));
143 assertEquals("Wrong content: " + content, 1, StringUtils.countOccurrencesOf(content, TEST_STRING));
144 }
145
146
147
148
149 @Test
150 public void testWriteWithHeaderAfterFlushAndRollback() throws Exception {
151 writer.setHeaderCallback(new StaxWriterCallback(){
152
153 public void write(XMLEventWriter writer) throws IOException {
154 XMLEventFactory factory = XMLEventFactory.newInstance();
155 try {
156 writer.add(factory.createStartElement("", "", "header"));
157 writer.add(factory.createEndElement("", "", "header"));
158 }
159 catch (XMLStreamException e) {
160 throw new RuntimeException(e);
161 }
162
163 }
164
165 });
166 writer.open(executionContext);
167 new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
168 public Object doInTransaction(TransactionStatus status) {
169 try {
170 writer.write(items);
171 }
172 catch (Exception e) {
173 throw new RuntimeException(e);
174 }
175 return null;
176 }
177 });
178 writer.update(executionContext);
179 writer.close();
180 writer.open(executionContext);
181 try {
182 new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
183 public Object doInTransaction(TransactionStatus status) {
184 try {
185 writer.write(items);
186 }
187 catch (Exception e) {
188 throw new RuntimeException(e);
189 }
190 throw new RuntimeException("Planned");
191 }
192 });
193 fail("Expected RuntimeException");
194 }
195 catch (RuntimeException e) {
196
197 }
198 writer.close();
199 String content = outputFileContent();
200 assertEquals("Wrong content: " + content, 1, StringUtils.countOccurrencesOf(content, ("<header/>")));
201 assertEquals("Wrong content: " + content, 1, StringUtils.countOccurrencesOf(content, TEST_STRING));
202 }
203
204
205
206
207 private String outputFileContent() throws IOException {
208 return FileUtils.readFileToString(resource.getFile(), null);
209 }
210
211
212
213
214 private static class SimpleMarshaller implements Marshaller {
215 public void marshal(Object graph, Result result) throws XmlMappingException, IOException {
216 try {
217 StaxUtils.getXmlEventWriter(result).add(XMLEventFactory.newInstance().createComment(graph.toString()));
218 }
219 catch ( Exception e) {
220 throw new RuntimeException("Exception while writing to output file", e);
221 }
222 }
223
224 @SuppressWarnings("rawtypes")
225 public boolean supports(Class clazz) {
226 return true;
227 }
228 }
229
230
231
232
233 private StaxEventItemWriter<Object> createItemWriter() throws Exception {
234 StaxEventItemWriter<Object> source = new StaxEventItemWriter<Object>();
235 source.setResource(resource);
236
237 Marshaller marshaller = new SimpleMarshaller();
238 source.setMarshaller(marshaller);
239
240 source.setEncoding("UTF-8");
241 source.setRootTagName("root");
242 source.setVersion("1.0");
243 source.setOverwriteOutput(true);
244 source.setSaveState(true);
245
246 source.afterPropertiesSet();
247
248 return source;
249 }
250 }