1 package org.springframework.batch.item.file;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertNull;
6 import static org.junit.Assert.assertTrue;
7 import static org.junit.Assert.fail;
8
9 import java.io.IOException;
10 import java.io.InputStream;
11
12 import org.junit.Before;
13 import org.junit.Test;
14 import org.springframework.batch.item.ExecutionContext;
15 import org.springframework.batch.item.ItemStreamException;
16 import org.springframework.batch.item.file.mapping.PassThroughLineMapper;
17 import org.springframework.batch.item.file.separator.RecordSeparatorPolicy;
18 import org.springframework.core.io.AbstractResource;
19 import org.springframework.core.io.ByteArrayResource;
20 import org.springframework.core.io.FileSystemResource;
21 import org.springframework.core.io.Resource;
22 import org.springframework.util.ClassUtils;
23 import org.springframework.util.StringUtils;
24
25
26
27
28 public class FlatFileItemReaderTests {
29
30
31 private String TEST_STRING = "FlatFileInputTemplate-TestData";
32
33 private FlatFileItemReader<String> reader = new FlatFileItemReader<String>();
34
35 private ExecutionContext executionContext = new ExecutionContext();
36
37 @Before
38 public void setUp() {
39
40 reader.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6"));
41 reader.setLineMapper(new PassThroughLineMapper());
42 }
43
44 @Test
45 public void testRestartWithCustomRecordSeparatorPolicy() throws Exception {
46
47 reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() {
48
49 boolean pair = true;
50
51 public boolean isEndOfRecord(String line) {
52 pair = !pair;
53 return pair;
54 }
55
56 public String postProcess(String record) {
57 return record;
58 }
59
60 public String preProcess(String record) {
61 return record;
62 }
63 });
64
65 reader.open(executionContext);
66
67 assertEquals("testLine1testLine2", reader.read());
68 assertEquals("testLine3testLine4", reader.read());
69
70 reader.update(executionContext);
71
72 reader.close();
73
74 reader.open(executionContext);
75
76 assertEquals("testLine5testLine6", reader.read());
77 }
78
79 @Test
80 public void testCustomRecordSeparatorPolicyEndOfFile() throws Exception {
81
82 reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() {
83
84 boolean pair = true;
85
86 public boolean isEndOfRecord(String line) {
87 pair = !pair;
88 return pair;
89 }
90
91 public String postProcess(String record) {
92 return record;
93 }
94
95 public String preProcess(String record) {
96 return record;
97 }
98 });
99
100 reader.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\n"));
101 reader.open(executionContext);
102
103 assertEquals("testLine1testLine2", reader.read());
104
105 try {
106 reader.read();
107 fail("Expected Exception");
108 }
109 catch (FlatFileParseException e) {
110
111 assertEquals(3, e.getLineNumber());
112 assertEquals("testLine3", e.getInput());
113 }
114
115 }
116
117 @Test
118 public void testCustomRecordSeparatorBlankLine() throws Exception {
119
120 reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() {
121
122 public boolean isEndOfRecord(String line) {
123 return StringUtils.hasText(line);
124 }
125
126 public String postProcess(String record) {
127 return StringUtils.hasText(record) ? record : null;
128 }
129
130 public String preProcess(String record) {
131 return record;
132 }
133 });
134
135 reader.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\n\n"));
136 reader.open(executionContext);
137
138 assertEquals("testLine1", reader.read());
139 assertEquals("testLine2", reader.read());
140 assertEquals("testLine3", reader.read());
141 assertEquals(null, reader.read());
142
143 }
144
145 @Test
146 public void testCustomRecordSeparatorMultilineBlankLineAfterEnd() throws Exception {
147
148 reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() {
149
150
151 boolean pair = true;
152
153 public boolean isEndOfRecord(String line) {
154 if (StringUtils.hasText(line)) {
155 pair = !pair;
156 }
157 return pair;
158 }
159
160 public String postProcess(String record) {
161 return StringUtils.hasText(record) ? record : null;
162 }
163
164 public String preProcess(String record) {
165 return record;
166 }
167 });
168
169 reader.setResource(getInputResource("testLine1\ntestLine2\n\n"));
170 reader.open(executionContext);
171
172 assertEquals("testLine1testLine2", reader.read());
173 assertEquals(null, reader.read());
174
175 }
176
177 @Test
178 public void testRestartWithSkippedLines() throws Exception {
179
180 reader.setLinesToSkip(2);
181 reader.open(executionContext);
182
183
184 reader.read();
185 reader.read();
186
187 reader.update(executionContext);
188
189 reader.read();
190 reader.read();
191
192 assertEquals(2, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count"));
193
194 reader.close();
195
196 reader.setResource(getInputResource("header\nignoreme\ntestLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6"));
197
198
199 reader.open(executionContext);
200
201
202 assertEquals("testLine3", reader.read());
203 assertEquals("testLine4", reader.read());
204
205 reader.update(executionContext);
206 assertEquals(4, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count"));
207 }
208
209 @Test
210 public void testCurrentItemCount() throws Exception {
211
212 reader.setCurrentItemCount(2);
213 reader.open(executionContext);
214
215
216 reader.read();
217 reader.read();
218
219 reader.update(executionContext);
220
221 assertEquals(4, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count"));
222
223 reader.close();
224
225 }
226
227 @Test
228 public void testMaxItemCount() throws Exception {
229
230 reader.setMaxItemCount(2);
231 reader.open(executionContext);
232
233
234 reader.read();
235 reader.read();
236
237 reader.update(executionContext);
238 assertNull(reader.read());
239
240 assertEquals(2, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count"));
241
242 reader.close();
243
244 }
245
246 @Test
247 public void testMaxItemCountFromContext() throws Exception {
248
249 reader.setMaxItemCount(2);
250 executionContext.putInt(reader.getClass().getSimpleName() + ".read.count.max", Integer.MAX_VALUE);
251 reader.open(executionContext);
252
253 reader.read();
254 reader.read();
255 assertNotNull(reader.read());
256
257 reader.close();
258
259 }
260
261 @Test
262 public void testCurrentItemCountFromContext() throws Exception {
263
264 reader.setCurrentItemCount(2);
265 executionContext.putInt(reader.getClass().getSimpleName() + ".read.count", 3);
266 reader.open(executionContext);
267
268 assertEquals("testLine4", reader.read());
269
270 reader.close();
271
272 }
273
274 @Test
275 public void testMaxAndCurrentItemCount() throws Exception {
276
277 reader.setMaxItemCount(2);
278 reader.setCurrentItemCount(2);
279 reader.open(executionContext);
280
281 assertNull(reader.read());
282
283 reader.close();
284
285 }
286
287 @Test
288 public void testNonExistentResource() throws Exception {
289
290 Resource resource = new NonExistentResource();
291
292 reader.setResource(resource);
293
294
295
296 reader.afterPropertiesSet();
297
298 reader.setStrict(false);
299 reader.open(executionContext);
300 assertNull(reader.read());
301 reader.close();
302 }
303
304 @Test
305 public void testOpenBadIOInput() throws Exception {
306
307 reader.setResource(new AbstractResource() {
308 public String getDescription() {
309 return null;
310 }
311
312 public InputStream getInputStream() throws IOException {
313 throw new IOException();
314 }
315
316 public boolean exists() {
317 return true;
318 }
319 });
320
321 try {
322 reader.open(executionContext);
323 fail();
324 }
325 catch (ItemStreamException ex) {
326
327 }
328
329
330 assertNull(reader.read());
331 reader.close();
332
333 }
334
335 @Test
336 public void testDirectoryResource() throws Exception {
337
338 FileSystemResource resource = new FileSystemResource("target/data");
339 resource.getFile().mkdirs();
340 assertTrue(resource.getFile().isDirectory());
341 reader.setResource(resource);
342 reader.afterPropertiesSet();
343
344 reader.setStrict(false);
345 reader.open(executionContext);
346 assertNull(reader.read());
347
348 }
349
350 @Test
351 public void testRuntimeFileCreation() throws Exception {
352
353 Resource resource = new NonExistentResource();
354
355 reader.setResource(resource);
356
357
358
359 reader.afterPropertiesSet();
360
361
362 reader.setResource(getInputResource(TEST_STRING));
363 reader.open(executionContext);
364 assertEquals(TEST_STRING, reader.read());
365 }
366
367
368
369
370 @Test(expected = ItemStreamException.class)
371 public void testStrictness() throws Exception {
372
373 Resource resource = new NonExistentResource();
374
375 reader.setResource(resource);
376 reader.setStrict(true);
377
378 reader.afterPropertiesSet();
379
380 reader.open(executionContext);
381 }
382
383
384
385
386
387 @Test
388 public void testMappingExceptionWrapping() throws Exception {
389 LineMapper<String> exceptionLineMapper = new LineMapper<String>() {
390 public String mapLine(String line, int lineNumber) throws Exception {
391 if (lineNumber == 2) {
392 throw new Exception("Couldn't map line 2");
393 }
394 return line;
395 }
396 };
397 reader.setLineMapper(exceptionLineMapper);
398 reader.afterPropertiesSet();
399
400 reader.open(executionContext);
401 assertNotNull(reader.read());
402
403 try {
404 reader.read();
405 fail();
406 }
407 catch (FlatFileParseException expected) {
408 assertEquals(2, expected.getLineNumber());
409 assertEquals("testLine2", expected.getInput());
410 assertEquals("Couldn't map line 2", expected.getCause().getMessage());
411 assertEquals("Parsing error at line: 2 in resource=[resource loaded from byte array], input=[testLine2]", expected.getMessage());
412 }
413 }
414
415 private Resource getInputResource(String input) {
416 return new ByteArrayResource(input.getBytes());
417 }
418
419 private static class NonExistentResource extends AbstractResource {
420
421 public NonExistentResource() {
422 }
423
424 public boolean exists() {
425 return false;
426 }
427
428 public String getDescription() {
429 return "NonExistentResource";
430 }
431
432 public InputStream getInputStream() throws IOException {
433 return null;
434 }
435 }
436 }