diff --git a/spring-batch-samples/README.md b/spring-batch-samples/README.md
index ec763cbcc..77eac1ef5 100644
--- a/spring-batch-samples/README.md
+++ b/spring-batch-samples/README.md
@@ -225,285 +225,10 @@ object
### Football Job
-This is a (American) Football statistics loading job. We gave it the
-id of `footballJob` in our configuration file. Before diving
-into the batch job, we'll examine the two input files that need to
-be loaded. First is `player.csv`, which can be found in the
-samples project under
-src/main/resources/data/footballjob/input/. Each line within this
-file represents a player, with a unique id, the player’s name,
-position, etc:
+This is a (American) Football statistics loading job. It loads two files containing players and games
+data into a database, and then combines them to summarise how each player performed for a particular year.
- AbduKa00,Abdul-Jabbar,Karim,rb,1974,1996
- AbduRa00,Abdullah,Rabih,rb,1975,1999
- AberWa00,Abercrombie,Walter,rb,1959,1982
- AbraDa00,Abramowicz,Danny,wr,1945,1967
- AdamBo00,Adams,Bob,te,1946,1969
- AdamCh00,Adams,Charlie,wr,1979,2003
- ...
-
-One of the first noticeable characteristics of the file is that each
-data element is separated by a comma, a format most are familiar
-with known as 'CSV'. Other separators such as pipes or semicolons
-could just as easily be used to delineate between unique
-elements. In general, it falls into one of two types of flat file
-formats: delimited or fixed length. (The fixed length case was
-covered in the `fixedLengthImportJob`.
-
-The second file, 'games.csv' is formatted the same as the previous
-example, and resides in the same directory:
-
- AbduKa00,1996,mia,10,nwe,0,0,0,0,0,29,104,,16,2
- AbduKa00,1996,mia,11,clt,0,0,0,0,0,18,70,,11,2
- AbduKa00,1996,mia,12,oti,0,0,0,0,0,18,59,,0,0
- AbduKa00,1996,mia,13,pit,0,0,0,0,0,16,57,,0,0
- AbduKa00,1996,mia,14,rai,0,0,0,0,0,18,39,,7,0
- AbduKa00,1996,mia,15,nyg,0,0,0,0,0,17,96,,14,0
- ...
-
-Each line in the file represents an individual player's performance
-in a particular game, containing such statistics as passing yards,
-receptions, rushes, and total touchdowns.
-
-Our example batch job is going to load both files into a database,
-and then combine each to summarise how each player performed for a
-particular year. Although this example is fairly trivial, it shows
-multiple types of input, and the general style is a common batch
-scenario. That is, summarising a very large dataset so that it can
-be more easily manipulated or viewed by an online web-based
-application. In an enterprise solution the third step, the reporting
-step, could be implemented through the use of Eclipse BIRT or one of
-the many Java Reporting Engines. Given this description, we can then
-easily divide our batch job up into 3 'steps': one to load the
-player data, one to load the game data, and one to produce a summary
-report:
-
-**Note:** One of the nice features of Spring is a project called
-Spring IDE. When you download the project you can install Spring
-IDE and add the Spring configurations to the IDE project. This is
-not a tutorial on Spring IDE but the visual view into Spring beans
-is helpful in understanding the structure of a Job
-Configuration. Spring IDE produces the following diagram:
-
-
-
-This corresponds exactly with the `footballJob.xml` job
-configuration file which can be found in the jobs folder under
-`src/main/resources`. When you drill down into the football job
-you will see that the configuration has a list of steps:
-
-
-
-
-
-
-
-
-
-A step is run until there is no more input to process, which in
-this case would mean that each file has been completely
-processed. To describe it in a more narrative form: the first step,
-playerLoad, begins executing by grabbing one line of input from the
-file, and parsing it into a domain object. That domain object is
-then passed to a dao, which writes it out to the PLAYERS table. This
-action is repeated until there are no more lines in the file,
-causing the playerLoad step to finish. Next, the gameLoad step does
-the same for the games input file, inserting into the GAMES
-table. Once finished, the playerSummarization step can begin. Unlike
-the first two steps, playerSummarization input comes from the
-database, using a Sql statement to combine the GAMES and PLAYERS
-table. Each returned row is packaged into a domain object and
-written out to the PLAYER_SUMMARY table.
-
-Now that we've discussed the entire flow of the batch job, we can
-dive deeper into the first step: playerLoad:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-The root bean in this case is a `SimpleStepFactoryBean`, which
-can be considered a 'blueprint' of sorts that tells the execution
-environment basic details about how the batch job should be
-executed. It contains four properties: (others have been removed for
-greater clarity) commitInterval, startLimit, itemReader and
-itemWriter . After performing all necessary startup, the framework
-will periodically delegate to the reader and writer. In this way,
-the developer can remain solely concerned with their business
-logic.
-
-* *ItemReader* – the item reader is the source of the information
-pipe. At the most basic level input is read in from an input
-source, parsed into a domain object and returned. In this way, the
-good batch architecture practice of ensuring all data has been
-read before beginning processing can be enforced, along with
-providing a possible avenue for reuse.
-
-* *ItemWriter* – this is the business logic. At a high level,
-the item writer takes the item returned from the reader
-and 'processes' it. In our case it's a data access object that is
-simply responsible for inserting a record into the PLAYERS
-table. As you can see the developer does very little.
-
-The application developer simply provides a job configuration with a
-configured number of steps, an ItemReader associated to some type
-of input source, and ItemWriter associated to some type of
-output source and a little mapping of data from flat records to
-objects and the pipe is ready wired for processing.
-
-Another property in the step configuration, the commitInterval,
-gives the framework vital information about how to control
-transactions during the batch run. Due to the large amount of data
-involved in batch processing, it is often advantageous to 'batch'
-together multiple logical units of work into one transaction, since
-starting and committing a transaction is extremely expensive. For
-example, in the playerLoad step, the framework calls read() on the
-item reader. The item reader reads one record from the file, and
-returns a domain object representation which is passed to the
-processor. The writer then writes the one record to the database. It
-can then be said that one iteration = one call to
-`ItemReader.read()` = one line of the file. Therefore, setting
-your commitInterval to 5 would result in the framework committing a
-transaction after 5 lines have been read from the file, with 5
-resultant entries in the PLAYERS table.
-
-Following the general flow of the batch job, the next step is to
-describe how each line of the file will be parsed from its string
-representation into a domain object. The first thing the provider
-will need is an `ItemReader`, which is provided as part of the Spring
-Batch infrastructure. Because the input is flat-file based, a
-`FlatFileItemReader` is used:
-
-
-
-
-
-
-
-
-
-
-
-
-
-There are three required dependencies of the item reader; the first
-is a resource to read in, which is the file to process. The second
-dependency is a `LineTokenizer`. The interface for a
-`LineTokenizer` is very simple, given a string; it will return a
-`FieldSet` that wraps the results from splitting the provided
-string. A `FieldSet` is Spring Batch's abstraction for flat file
-data. It allows developers to work with file input in much the same
-way as they would work with database input. All the developers need
-to provide is a `FieldSetMapper` (similar to a Spring
-`RowMapper`) that will map the provided `FieldSet` into an
-`Object`. Simply by providing the names of each token to the
-`LineTokenizer`, the `ItemReader` can pass the
-`FieldSet` into our `PlayerMapper`, which implements the
-`FieldSetMapper` interface. There is a single method,
-`mapLine()`, which maps `FieldSet`s the same way that
-developers are comfortable mapping `ResultSet`s into Java
-`Object`s, either by index or field name. This behaviour is by
-intention and design similar to the `RowMapper` passed into a
-`JdbcTemplate`. You can see this below:
-
- public class PlayerMapper implements FieldSetMapper {
-
- public Object mapLine(FieldSet fs) {
-
- if(fs == null){
- return null;
- }
-
- Player player = new Player();
- player.setID(fs.readString("ID"));
- player.setLastName(fs.readString("lastName"));
- player.setFirstName(fs.readString("firstName"));
- player.setPosition(fs.readString("position"));
- player.setDebutYear(fs.readInt("debutYear"));
- player.setBirthYear(fs.readInt("birthYear"));
-
- return player;
- }
- }
-
-The flow of the `ItemReader`, in this case, starts with a call
-to read the next line from the file. This is passed into the
-provided `LineTokenizer`. The `LineTokenizer` splits the
-line at every comma, and creates a `FieldSet` using the created
-`String` array and the array of names passed in.
-
-**Note:** it is only necessary to provide the names to create the
-`FieldSet` if you wish to access the field by name, rather
-than by index.
-
-Once the domain representation of the data has been returned by the
-provider, (i.e. a `Player` object in this case) it is passed to
-the `ItemWriter`, which is essentially a Dao that uses a Spring
-`JdbcTemplate` to insert a new row in the PLAYERS table.
-
-The next step, gameLoad, works almost exactly the same as the
-playerLoad step, except the games file is used.
-
-The final step, playerSummarization, is much like the previous two
-steps, in that it reads from a reader and returns a domain object to
-a writer. However, in this case, the input source is the database,
-not a file:
-
-
-
-
-
-
-
-
- SELECT games.player_id, games.year_no, SUM(COMPLETES),
- SUM(ATTEMPTS), SUM(PASSING_YARDS), SUM(PASSING_TD),
- SUM(INTERCEPTIONS), SUM(RUSHES), SUM(RUSH_YARDS),
- SUM(RECEPTIONS), SUM(RECEPTIONS_YARDS), SUM(TOTAL_TD)
- from games, players where players.player_id =
- games.player_id group by games.player_id, games.year_no
-
-
-
-
-The `JdbcCursorItemReader` has three dependences:
-
-* A `DataSource`
-* The `RowMapper` to use for each row.
-* The Sql statement used to create the cursor.
-
-When the step is first started, a query will be run against the
-database to open a cursor, and each call to `itemReader.read()`
-will move the cursor to the next row, using the provided
-`RowMapper` to return the correct object. As with the previous
-two steps, each record returned by the provider will be written out
-to the database in the PLAYER_SUMMARY table. Finally to run this
-sample application you can execute the JUnit test
-`FootballJobFunctionalTests`, and you'll see an output showing
-each of the records as they are processed. Please keep in mind that
-AoP is used to wrap the `ItemWriter` and output each record as it
-is processed to the logger, which may impact performance.
+[Football Job](./src/main/java/org/springframework/batch/sample/football/README.md)
### Header Footer Sample
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/FootballJobConfiguration.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/FootballJobConfiguration.java
new file mode 100644
index 000000000..0b1369953
--- /dev/null
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/FootballJobConfiguration.java
@@ -0,0 +1,150 @@
+package org.springframework.batch.sample.football;
+
+import javax.sql.DataSource;
+
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.Step;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.job.builder.JobBuilder;
+import org.springframework.batch.core.repository.JobRepository;
+import org.springframework.batch.core.step.builder.StepBuilder;
+import org.springframework.batch.item.database.JdbcCursorItemReader;
+import org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder;
+import org.springframework.batch.item.file.FlatFileItemReader;
+import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
+import org.springframework.batch.sample.football.internal.GameFieldSetMapper;
+import org.springframework.batch.sample.football.internal.JdbcGameDao;
+import org.springframework.batch.sample.football.internal.JdbcPlayerDao;
+import org.springframework.batch.sample.football.internal.JdbcPlayerSummaryDao;
+import org.springframework.batch.sample.football.internal.PlayerFieldSetMapper;
+import org.springframework.batch.sample.football.internal.PlayerItemWriter;
+import org.springframework.batch.sample.football.internal.PlayerSummaryMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+import org.springframework.jdbc.support.JdbcTransactionManager;
+
+@Configuration
+@EnableBatchProcessing
+public class FootballJobConfiguration {
+
+ // step 1 configuration
+
+ @Bean
+ public FlatFileItemReader playerFileItemReader() {
+ return new FlatFileItemReaderBuilder().name("playerFileItemReader")
+ .resource(new ClassPathResource("org/springframework/batch/sample/football/data/player-small1.csv"))
+ .delimited()
+ .names("ID", "lastName", "firstName", "position", "birthYear", "debutYear")
+ .fieldSetMapper(new PlayerFieldSetMapper())
+ .build();
+ }
+
+ @Bean
+ public PlayerItemWriter playerWriter() {
+ PlayerItemWriter playerItemWriter = new PlayerItemWriter();
+ JdbcPlayerDao playerDao = new JdbcPlayerDao();
+ playerDao.setDataSource(dataSource());
+ playerItemWriter.setPlayerDao(playerDao);
+ return playerItemWriter;
+ }
+
+ @Bean
+ public Step playerLoad(JobRepository jobRepository, JdbcTransactionManager transactionManager) {
+ return new StepBuilder("playerLoad", jobRepository).chunk(2, transactionManager)
+ .reader(playerFileItemReader())
+ .writer(playerWriter())
+ .build();
+ }
+
+ // step 2 configuration
+
+ @Bean
+ public FlatFileItemReader gameFileItemReader() {
+ return new FlatFileItemReaderBuilder().name("gameFileItemReader")
+ .resource(new ClassPathResource("org/springframework/batch/sample/football/data/games-small.csv"))
+ .delimited()
+ .names("id", "year", "team", "week", "opponent", "completes", "attempts", "passingYards", "passingTd",
+ "interceptions", "rushes", "rushYards", "receptions", "receptionYards", "totalTd")
+ .fieldSetMapper(new GameFieldSetMapper())
+ .build();
+ }
+
+ @Bean
+ public JdbcGameDao gameWriter() {
+ JdbcGameDao jdbcGameDao = new JdbcGameDao();
+ jdbcGameDao.setDataSource(dataSource());
+ return jdbcGameDao;
+ }
+
+ @Bean
+ public Step gameLoad(JobRepository jobRepository, JdbcTransactionManager transactionManager) {
+ return new StepBuilder("gameLoad", jobRepository).chunk(2, transactionManager)
+ .reader(gameFileItemReader())
+ .writer(gameWriter())
+ .build();
+ }
+
+ // step 3 configuration
+
+ @Bean
+ public JdbcCursorItemReader playerSummarizationSource() {
+ String sql = """
+ SELECT GAMES.player_id, GAMES.year_no, SUM(COMPLETES),
+ SUM(ATTEMPTS), SUM(PASSING_YARDS), SUM(PASSING_TD),
+ SUM(INTERCEPTIONS), SUM(RUSHES), SUM(RUSH_YARDS),
+ SUM(RECEPTIONS), SUM(RECEPTIONS_YARDS), SUM(TOTAL_TD)
+ from GAMES, PLAYERS where PLAYERS.player_id =
+ GAMES.player_id group by GAMES.player_id, GAMES.year_no
+ """;
+ return new JdbcCursorItemReaderBuilder().name("playerSummarizationSource")
+ .ignoreWarnings(true)
+ .sql(sql)
+ .dataSource(dataSource())
+ .rowMapper(new PlayerSummaryMapper())
+ .build();
+ }
+
+ @Bean
+ public JdbcPlayerSummaryDao summaryWriter() {
+ JdbcPlayerSummaryDao jdbcPlayerSummaryDao = new JdbcPlayerSummaryDao();
+ jdbcPlayerSummaryDao.setDataSource(dataSource());
+ return jdbcPlayerSummaryDao;
+ }
+
+ @Bean
+ public Step summarizationStep(JobRepository jobRepository, JdbcTransactionManager transactionManager) {
+ return new StepBuilder("summarizationStep", jobRepository)
+ .chunk(2, transactionManager)
+ .reader(playerSummarizationSource())
+ .writer(summaryWriter())
+ .build();
+ }
+
+ // job configuration
+
+ @Bean
+ public Job job(JobRepository jobRepository, Step playerLoad, Step gameLoad, Step summarizationStep) {
+ return new JobBuilder("footballJob", jobRepository).start(playerLoad)
+ .next(gameLoad)
+ .next(summarizationStep)
+ .build();
+ }
+
+ @Bean
+ public DataSource dataSource() {
+ return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
+ .addScript("/org/springframework/batch/core/schema-drop-hsqldb.sql")
+ .addScript("/org/springframework/batch/core/schema-hsqldb.sql")
+ .addScript("/org/springframework/batch/sample/football/sql/schema.sql")
+ .build();
+ }
+
+ @Bean
+ public JdbcTransactionManager transactionManager(DataSource dataSource) {
+ return new JdbcTransactionManager(dataSource);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Game.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/Game.java
similarity index 98%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Game.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/Game.java
index fc01d0d03..9f68bbe65 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Game.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/Game.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football;
+package org.springframework.batch.sample.football;
import java.io.Serializable;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Player.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/Player.java
similarity index 94%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Player.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/Player.java
index 92a2c6a7c..c89dc0c17 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Player.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/Player.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006-2007 the original author or authors.
+ * Copyright 2006-2023 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football;
+package org.springframework.batch.sample.football;
import java.io.Serializable;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerDao.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/PlayerDao.java
similarity index 92%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerDao.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/PlayerDao.java
index 4f72f8652..ff53ea975 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerDao.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/PlayerDao.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football;
+package org.springframework.batch.sample.football;
/**
* Interface for writing {@link Player} objects to arbitrary output.
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerSummary.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/PlayerSummary.java
similarity index 98%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerSummary.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/PlayerSummary.java
index e27775813..a2542e316 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerSummary.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/PlayerSummary.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football;
+package org.springframework.batch.sample.football;
/**
* Domain object representing the summary of a given Player's year.
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/README.md b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/README.md
new file mode 100644
index 000000000..905a3acdf
--- /dev/null
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/README.md
@@ -0,0 +1,301 @@
+# Football Job
+
+## About the sample
+
+This is a (American) Football statistics loading job. We gave it the
+id of `footballJob` in our configuration file. Before diving
+into the batch job, we'll examine the two input files that need to
+be loaded. First is `player.csv`, which can be found in the
+samples project under `src/main/resources/org/springframework/batch/sample/football/data`.
+Each line within this file represents a player, with a unique id, the player’s name, position, etc:
+
+```
+AbduKa00,Abdul-Jabbar,Karim,rb,1974,1996
+AbduRa00,Abdullah,Rabih,rb,1975,1999
+AberWa00,Abercrombie,Walter,rb,1959,1982
+AbraDa00,Abramowicz,Danny,wr,1945,1967
+AdamBo00,Adams,Bob,te,1946,1969
+AdamCh00,Adams,Charlie,wr,1979,2003
+...
+```
+
+One of the first noticeable characteristics of the file is that each
+data element is separated by a comma, a format most are familiar
+with known as 'CSV'. Other separators such as pipes or semicolons
+could just as easily be used to delineate between unique
+elements. In general, it falls into one of two types of flat file
+formats: delimited or fixed length. (The fixed length case was
+covered in the `fixedLengthImportJob`).
+
+The second file, 'games.csv' is formatted the same as the previous
+example, and resides in the same directory:
+
+```
+AbduKa00,1996,mia,10,nwe,0,0,0,0,0,29,104,,16,2
+AbduKa00,1996,mia,11,clt,0,0,0,0,0,18,70,,11,2
+AbduKa00,1996,mia,12,oti,0,0,0,0,0,18,59,,0,0
+AbduKa00,1996,mia,13,pit,0,0,0,0,0,16,57,,0,0
+AbduKa00,1996,mia,14,rai,0,0,0,0,0,18,39,,7,0
+AbduKa00,1996,mia,15,nyg,0,0,0,0,0,17,96,,14,0
+...
+```
+
+Each line in the file represents an individual player's performance
+in a particular game, containing such statistics as passing yards,
+receptions, rushes, and total touchdowns.
+
+Our example batch job is going to load both files into a database,
+and then combine each to summarise how each player performed for a
+particular year. Although this example is fairly trivial, it shows
+multiple types of input, and the general style is a common batch
+scenario. That is, summarising a very large dataset so that it can
+be more easily manipulated or viewed by an online web-based
+application. In an enterprise solution the third step, the reporting
+step, could be implemented through the use of Eclipse BIRT or one of
+the many Java Reporting Engines. Given this description, we can then
+easily divide our batch job up into 3 'steps': one to load the
+player data, one to load the game data, and one to produce a summary
+report:
+
+```mermaid
+graph LR
+ A(playerLoad) --> B(gameLoad)
+ B --> C(playerSummarization)
+```
+
+This corresponds exactly with the `footballJob.xml` job configuration file which can be found in
+`src/main/resources/org/springframework/batch/sample/football/job`.
+When you drill down into the football job you will see that the configuration has a list of steps:
+
+```xml
+
+
+
+
+
+
+
+```
+
+A step is run until there is no more input to process, which in
+this case would mean that each file has been completely
+processed. To describe it in a more narrative form: the first step,
+playerLoad, begins executing by grabbing one line of input from the
+file, and parsing it into a domain object. That domain object is
+then passed to a dao, which writes it out to the PLAYERS table. This
+action is repeated until there are no more lines in the file,
+causing the playerLoad step to finish. Next, the gameLoad step does
+the same for the games input file, inserting into the GAMES
+table. Once finished, the playerSummarization step can begin. Unlike
+the first two steps, playerSummarization input comes from the
+database, using a Sql statement to combine the GAMES and PLAYERS
+table. Each returned row is packaged into a domain object and
+written out to the PLAYER_SUMMARY table.
+
+Now that we've discussed the entire flow of the batch job, we can
+dive deeper into the first step: playerLoad:
+
+```xml
+
+
+
+
+
+
+
+
+```
+
+The root bean in this case is a `SimpleStepFactoryBean`, which
+can be considered a 'blueprint' of sorts that tells the execution
+environment basic details about how the batch job should be
+executed. It contains four properties: (others have been removed for
+greater clarity) commitInterval, startLimit, itemReader and
+itemWriter . After performing all necessary startup, the framework
+will periodically delegate to the reader and writer. In this way,
+the developer can remain solely concerned with their business
+logic.
+
+* *ItemReader* – the item reader is the source of the information
+ pipe. At the most basic level input is read in from an input
+ source, parsed into a domain object and returned. In this way, the
+ good batch architecture practice of ensuring all data has been
+ read before beginning processing can be enforced, along with
+ providing a possible avenue for reuse.
+
+* *ItemWriter* – this is the business logic. At a high level,
+ the item writer takes the item returned from the reader
+ and 'processes' it. In our case it's a data access object that is
+ simply responsible for inserting a record into the PLAYERS
+ table. As you can see the developer does very little.
+
+The application developer simply provides a job configuration with a
+configured number of steps, an ItemReader associated to some type
+of input source, and ItemWriter associated to some type of
+output source and a little mapping of data from flat records to
+objects and the pipe is ready wired for processing.
+
+Another property in the step configuration, the commitInterval,
+gives the framework vital information about how to control
+transactions during the batch run. Due to the large amount of data
+involved in batch processing, it is often advantageous to 'batch'
+together multiple logical units of work into one transaction, since
+starting and committing a transaction is extremely expensive. For
+example, in the playerLoad step, the framework calls read() on the
+item reader. The item reader reads one record from the file, and
+returns a domain object representation which is passed to the
+processor. The writer then writes the one record to the database. It
+can then be said that one iteration = one call to
+`ItemReader.read()` = one line of the file. Therefore, setting
+your commitInterval to 5 would result in the framework committing a
+transaction after 5 lines have been read from the file, with 5
+resultant entries in the PLAYERS table.
+
+Following the general flow of the batch job, the next step is to
+describe how each line of the file will be parsed from its string
+representation into a domain object. The first thing the provider
+will need is an `ItemReader`, which is provided as part of the Spring
+Batch infrastructure. Because the input is flat-file based, a
+`FlatFileItemReader` is used:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+There are three required dependencies of the item reader; the first
+is a resource to read in, which is the file to process. The second
+dependency is a `LineTokenizer`. The interface for a
+`LineTokenizer` is very simple, given a string; it will return a
+`FieldSet` that wraps the results from splitting the provided
+string. A `FieldSet` is Spring Batch's abstraction for flat file
+data. It allows developers to work with file input in much the same
+way as they would work with database input. All the developers need
+to provide is a `FieldSetMapper` (similar to a Spring
+`RowMapper`) that will map the provided `FieldSet` into an
+`Object`. Simply by providing the names of each token to the
+`LineTokenizer`, the `ItemReader` can pass the
+`FieldSet` into our `PlayerMapper`, which implements the
+`FieldSetMapper` interface. There is a single method,
+`mapLine()`, which maps `FieldSet`s the same way that
+developers are comfortable mapping `ResultSet`s into Java
+`Object`s, either by index or field name. This behaviour is by
+intention and design similar to the `RowMapper` passed into a
+`JdbcTemplate`. You can see this below:
+
+```java
+public class PlayerMapper implements FieldSetMapper {
+
+ public Object mapLine(FieldSet fs) {
+
+ if(fs == null){
+ return null;
+ }
+
+ Player player = new Player();
+ player.setID(fs.readString("ID"));
+ player.setLastName(fs.readString("lastName"));
+ player.setFirstName(fs.readString("firstName"));
+ player.setPosition(fs.readString("position"));
+ player.setDebutYear(fs.readInt("debutYear"));
+ player.setBirthYear(fs.readInt("birthYear"));
+
+ return player;
+ }
+}
+```
+
+The flow of the `ItemReader`, in this case, starts with a call
+to read the next line from the file. This is passed into the
+provided `LineTokenizer`. The `LineTokenizer` splits the
+line at every comma, and creates a `FieldSet` using the created
+`String` array and the array of names passed in.
+
+**Note:** it is only necessary to provide the names to create the
+`FieldSet` if you wish to access the field by name, rather
+than by index.
+
+Once the domain representation of the data has been returned by the
+provider, (i.e. a `Player` object in this case) it is passed to
+the `ItemWriter`, which is essentially a Dao that uses a Spring
+`JdbcTemplate` to insert a new row in the PLAYERS table.
+
+The next step, gameLoad, works almost exactly the same as the
+playerLoad step, except the games file is used.
+
+The final step, playerSummarization, is much like the previous two
+steps, in that it reads from a reader and returns a domain object to
+a writer. However, in this case, the input source is the database,
+not a file:
+
+```xml
+
+
+
+
+
+
+
+ SELECT games.player_id, games.year_no, SUM(COMPLETES),
+ SUM(ATTEMPTS), SUM(PASSING_YARDS), SUM(PASSING_TD),
+ SUM(INTERCEPTIONS), SUM(RUSHES), SUM(RUSH_YARDS),
+ SUM(RECEPTIONS), SUM(RECEPTIONS_YARDS), SUM(TOTAL_TD)
+ from games, players where players.player_id =
+ games.player_id group by games.player_id, games.year_no
+
+
+
+```
+
+The `JdbcCursorItemReader` has three dependencies:
+
+* A `DataSource`
+* The `RowMapper` to use for each row.
+* The Sql statement used to create the cursor.
+
+When the step is first started, a query will be run against the
+database to open a cursor, and each call to `itemReader.read()`
+will move the cursor to the next row, using the provided
+`RowMapper` to return the correct object. As with the previous
+two steps, each record returned by the provider will be written out
+to the database in the PLAYER_SUMMARY table.
+
+The equivalent Java configuration of the football job can be found in
+`org/springframework/batch/sample/football/FootballJobConfiguration.java`.
+
+## Run the sample
+
+You can run the sample from the command line as following:
+
+```
+$>cd spring-batch-samples
+# Launch the sample using the XML configuration
+$>../mvnw -Dtest=FootballJobFunctionalTests#testLaunchJobWithXmlConfiguration test
+# Launch the sample using the Java configuration
+$>../mvnw -Dtest=FootballJobFunctionalTests#testLaunchJobWithJavaConfiguration test
+```
\ No newline at end of file
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/FootballExceptionHandler.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/FootballExceptionHandler.java
similarity index 94%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/FootballExceptionHandler.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/FootballExceptionHandler.java
index 90f8861f0..5c96dab52 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/FootballExceptionHandler.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/FootballExceptionHandler.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football.internal;
+package org.springframework.batch.sample.football.internal;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/GameFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/GameFieldSetMapper.java
similarity index 92%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/GameFieldSetMapper.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/GameFieldSetMapper.java
index 4e0d44e24..2bb9287fb 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/GameFieldSetMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/GameFieldSetMapper.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football.internal;
+package org.springframework.batch.sample.football.internal;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
-import org.springframework.batch.sample.domain.football.Game;
+import org.springframework.batch.sample.football.Game;
public class GameFieldSetMapper implements FieldSetMapper {
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcGameDao.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/JdbcGameDao.java
similarity index 94%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcGameDao.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/JdbcGameDao.java
index dad2229df..809fb3a56 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcGameDao.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/JdbcGameDao.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football.internal;
+package org.springframework.batch.sample.football.internal;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
-import org.springframework.batch.sample.domain.football.Game;
+import org.springframework.batch.sample.football.Game;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerDao.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/JdbcPlayerDao.java
similarity index 88%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerDao.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/JdbcPlayerDao.java
index ecc0260b5..63d3b94f1 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerDao.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/JdbcPlayerDao.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football.internal;
+package org.springframework.batch.sample.football.internal;
import javax.sql.DataSource;
-import org.springframework.batch.sample.domain.football.Player;
-import org.springframework.batch.sample.domain.football.PlayerDao;
+import org.springframework.batch.sample.football.Player;
+import org.springframework.batch.sample.football.PlayerDao;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerSummaryDao.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/JdbcPlayerSummaryDao.java
similarity index 94%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerSummaryDao.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/JdbcPlayerSummaryDao.java
index 45b407bee..388348847 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerSummaryDao.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/JdbcPlayerSummaryDao.java
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football.internal;
+package org.springframework.batch.sample.football.internal;
import javax.sql.DataSource;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
-import org.springframework.batch.sample.domain.football.PlayerSummary;
+import org.springframework.batch.sample.football.PlayerSummary;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerFieldSetMapper.java
similarity index 90%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerFieldSetMapper.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerFieldSetMapper.java
index 8b9a545db..406135c29 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerFieldSetMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerFieldSetMapper.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football.internal;
+package org.springframework.batch.sample.football.internal;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
-import org.springframework.batch.sample.domain.football.Player;
+import org.springframework.batch.sample.football.Player;
public class PlayerFieldSetMapper implements FieldSetMapper {
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerItemWriter.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerItemWriter.java
similarity index 84%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerItemWriter.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerItemWriter.java
index c3b2b99fe..2bdc5e151 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerItemWriter.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerItemWriter.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football.internal;
+package org.springframework.batch.sample.football.internal;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
-import org.springframework.batch.sample.domain.football.Player;
-import org.springframework.batch.sample.domain.football.PlayerDao;
+import org.springframework.batch.sample.football.Player;
+import org.springframework.batch.sample.football.PlayerDao;
public class PlayerItemWriter implements ItemWriter {
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerSummaryMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerSummaryMapper.java
similarity index 86%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerSummaryMapper.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerSummaryMapper.java
index 1dc5b0078..9eb2557a8 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerSummaryMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerSummaryMapper.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football.internal;
+package org.springframework.batch.sample.football.internal;
import java.sql.ResultSet;
import java.sql.SQLException;
-import org.springframework.batch.sample.domain.football.PlayerSummary;
+import org.springframework.batch.sample.football.PlayerSummary;
import org.springframework.jdbc.core.RowMapper;
/**
- * RowMapper used to map a ResultSet to a
- * {@link org.springframework.batch.sample.domain.football.PlayerSummary}
+ * RowMapper used to map a ResultSet to a {@link PlayerSummary}
*
* @author Lucas Ward
* @author Mahmoud Ben Hassine
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerSummaryRowMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerSummaryRowMapper.java
similarity index 86%
rename from spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerSummaryRowMapper.java
rename to spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerSummaryRowMapper.java
index 33eb01cd4..61292c041 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerSummaryRowMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/football/internal/PlayerSummaryRowMapper.java
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.batch.sample.domain.football.internal;
+package org.springframework.batch.sample.football.internal;
import java.sql.ResultSet;
import java.sql.SQLException;
-import org.springframework.batch.sample.domain.football.PlayerSummary;
+import org.springframework.batch.sample.football.PlayerSummary;
import org.springframework.jdbc.core.RowMapper;
/**
- * RowMapper used to map a ResultSet to a
- * {@link org.springframework.batch.sample.domain.football.PlayerSummary}
+ * RowMapper used to map a ResultSet to a {@link PlayerSummary}
*
* @author Lucas Ward
* @author Mahmoud Ben Hassine
diff --git a/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football-job-context.xml b/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football-job-context.xml
deleted file mode 100644
index 4939869e4..000000000
--- a/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football-job-context.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
diff --git a/spring-batch-samples/src/main/resources/data/footballjob/input/games-small.csv b/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/games-small.csv
similarity index 100%
rename from spring-batch-samples/src/main/resources/data/footballjob/input/games-small.csv
rename to spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/games-small.csv
diff --git a/spring-batch-samples/src/main/resources/data/footballjob/input/games.csv b/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/games.csv
similarity index 100%
rename from spring-batch-samples/src/main/resources/data/footballjob/input/games.csv
rename to spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/games.csv
diff --git a/spring-batch-samples/src/main/resources/data/footballjob/input/player-containsBadRecords.csv b/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/player-containsBadRecords.csv
similarity index 100%
rename from spring-batch-samples/src/main/resources/data/footballjob/input/player-containsBadRecords.csv
rename to spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/player-containsBadRecords.csv
diff --git a/spring-batch-samples/src/main/resources/data/footballjob/input/player-small1.csv b/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/player-small1.csv
similarity index 100%
rename from spring-batch-samples/src/main/resources/data/footballjob/input/player-small1.csv
rename to spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/player-small1.csv
diff --git a/spring-batch-samples/src/main/resources/data/footballjob/input/player-small2.csv b/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/player-small2.csv
similarity index 100%
rename from spring-batch-samples/src/main/resources/data/footballjob/input/player-small2.csv
rename to spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/player-small2.csv
diff --git a/spring-batch-samples/src/main/resources/data/footballjob/input/player.csv b/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/player.csv
similarity index 100%
rename from spring-batch-samples/src/main/resources/data/footballjob/input/player.csv
rename to spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/data/player.csv
diff --git a/spring-batch-samples/src/main/resources/jobs/footballJob.xml b/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/job/footballJob.xml
similarity index 65%
rename from spring-batch-samples/src/main/resources/jobs/footballJob.xml
rename to spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/job/footballJob.xml
index 9cd3bab22..5a66eee45 100644
--- a/spring-batch-samples/src/main/resources/jobs/footballJob.xml
+++ b/spring-batch-samples/src/main/resources/org/springframework/batch/sample/football/job/footballJob.xml
@@ -1,13 +1,11 @@