From 7cd8bfdef6f71952b9c6c19eea2ca9c6fed011a6 Mon Sep 17 00:00:00 2001 From: lucasward Date: Mon, 10 Mar 2008 19:38:56 +0000 Subject: [PATCH] BATCH-335 and BATCH-316: As part of the documentation efforts of RC1, the DrivingQueryItemReader has had javadoc updates. Specifically, the MultipleColumnJdbcKeyGenerator, which has been a source of confusion, has had it's javadocs beefed up. The KeyGenerator interface was also renamed to KeyCollector. The issue was raised that it's not actually generating keys, but rather collecting them from the database. --- .../item/database/DrivingQueryItemReader.java | 37 ++++++++----- .../IbatisDrivingQueryItemReader.java | 4 +- .../batch/item/database/KeyCollector.java | 47 ++++++++++++++++ .../batch/item/database/KeyGenerator.java | 30 ---------- .../ColumnMapExecutionContextRowMapper.java | 5 +- .../support/ExecutionContextRowMapper.java | 55 ++++++++++++++----- ...Generator.java => IbatisKeyCollector.java} | 24 ++++---- ...va => MultipleColumnJdbcKeyCollector.java} | 16 +++--- ...java => SingleColumnJdbcKeyCollector.java} | 27 ++++----- .../database/DrivingQueryItemReaderTests.java | 6 +- .../IbatisItemReaderIntegrationTests.java | 6 +- ...rivingQueryItemReaderIntegrationTests.java | 8 +-- ...rivingQueryItemReaderIntegrationTests.java | 6 +- ...olumnJdbcKeyGeneratorIntegrationTests.java | 4 +- ...olumnJdbcKeyGeneratorIntegrationTests.java | 4 +- 15 files changed, 168 insertions(+), 111 deletions(-) create mode 100644 spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyCollector.java delete mode 100644 spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyGenerator.java rename spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/{IbatisKeyGenerator.java => IbatisKeyCollector.java} (76%) rename spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/{MultipleColumnJdbcKeyGenerator.java => MultipleColumnJdbcKeyCollector.java} (89%) rename spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/{SingleColumnJdbcKeyGenerator.java => SingleColumnJdbcKeyCollector.java} (83%) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/DrivingQueryItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/DrivingQueryItemReader.java index cdbe3092d..d9fef770b 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/DrivingQueryItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/DrivingQueryItemReader.java @@ -28,10 +28,26 @@ import org.springframework.util.Assert; /** *

* Convenience class for driving query input sources. Input Sources of this type - * use a 'driving query' to return back a list of keys. Upon each call to read, - * a new key is returned. To use the input source, inject a key generation - * strategy. - *

+ * use a 'driving query' to return back a list of keys. A key can be defined + * as anything that can uniquely identify a record so that a more detailed + * record can be retrieved for each object. This allows a much smaller footprint + * to be stored in memory for processing. The following 'Customer' example table + * will help illustrate this: + * + *
+ * CREATE TABLE CUSTOMER (
+ *   ID BIGINT IDENTITY PRIMARY KEY,  
+ *   NAME VARCHAR(45),
+ *   CREDIT FLOAT
+ * );
+ * 
+ * + *

A cursor based solution would simply open up a cursor over ID, NAME, and CREDIT, + * and move it from one to the next. This can cause issues on databases with + * pessimistic locking strategies. A 'driving query' approach would be to + * return only the ID of the customer, then use a separate DAO to retrieve the + * name and credit for each ID. This means that there will be a call to a + * separate DAO for each call to {@link ItemReader#read()}.

* *

* Mutability: Because this base class cannot guarantee that the keys returned @@ -45,7 +61,6 @@ import org.springframework.util.Assert; * * * @author Lucas Ward - * @since 1.0 */ public class DrivingQueryItemReader implements ItemReader, InitializingBean, ItemStream { @@ -60,7 +75,7 @@ public class DrivingQueryItemReader implements ItemReader, InitializingBean, private int lastCommitIndex = 0; - private KeyGenerator keyGenerator; + private KeyCollector keyGenerator; private boolean saveState = false; @@ -165,18 +180,10 @@ public class DrivingQueryItemReader implements ItemReader, InitializingBean, * * @param keyGenerator */ - public void setKeyGenerator(KeyGenerator keyGenerator) { + public void setKeyCollector(KeyCollector keyGenerator) { this.keyGenerator = keyGenerator; } - protected void transactionCommitted() { - mark(); - } - - protected void transactionRolledBack() { - reset(); - } - /** * Mark is supported as long as this {@link ItemStream} is used in a * single-threaded environment. The state backing the mark is a single diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/IbatisDrivingQueryItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/IbatisDrivingQueryItemReader.java index f093543aa..718da123b 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/IbatisDrivingQueryItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/IbatisDrivingQueryItemReader.java @@ -15,7 +15,7 @@ */ package org.springframework.batch.item.database; -import org.springframework.batch.item.database.support.IbatisKeyGenerator; +import org.springframework.batch.item.database.support.IbatisKeyCollector; import org.springframework.orm.ibatis.SqlMapClientTemplate; import com.ibatis.sqlmap.client.SqlMapClient; @@ -25,7 +25,7 @@ import com.ibatis.sqlmap.client.SqlMapClient; * objects. An iBatis query id must be set to map and return each 'detail record'. * * @author Lucas Ward - * @see IbatisKeyGenerator + * @see IbatisKeyCollector */ public class IbatisDrivingQueryItemReader extends DrivingQueryItemReader { diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyCollector.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyCollector.java new file mode 100644 index 000000000..da29e636f --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyCollector.java @@ -0,0 +1,47 @@ +package org.springframework.batch.item.database; + +import java.util.List; + +import org.springframework.batch.item.ExecutionContext; + +/** + * Strategy interface used to collect keys in driving query input. + * + * @author Lucas Ward + * @see DrivingQueryItemReader + */ +public interface KeyCollector { + + /** + *

Retrieve the keys to be iterated over. If the ExecutionContext + * provided includes any state relevant to this collector (because it was + * stored as part of saveState()) then it should start from the point + * indicated by that state.

+ * + *

In the case of a restart, (i.e. the ExecutionContext contains relevant state) + * this method should return only the keys that are remaining to be processed. For + * example, if the are 1,000 keys, and the 500th is processed before the batch job + * terminates unexpectedly, upon restart keys 501 through 1,000 should be returned. + *

+ * + * @param executionContext ExecutionContext containing any potential initial state + * that could potentially be used to retrieve the correct keys. + * @return list of keys returned by the driving query + */ + List retrieveKeys(ExecutionContext executionContext); + + /** + * Given the provided key, store it in the provided ExecutionContext. This + * is necessary because retrieveKeys() will be called with the ExecutionContext + * that is provided as a result of this method. Since only the KeyCollector + * can know what format the ExecutionContext should be in, it should also + * save the state, as opposed to the {@link DrivingQueryItemReader} doing it + * for all KeyCollector implementations. + * + * @param key to be converted to restart data. + * @return {@link ExecutionContext} representation of the key. + * @throws IllegalArgumentException if key is null. + * @throws IllegalArgumentException if key is an incompatible type. + */ + void saveState(Object key, ExecutionContext executionContext); +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyGenerator.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyGenerator.java deleted file mode 100644 index 515c092b5..000000000 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyGenerator.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.springframework.batch.item.database; - -import java.util.List; - -import org.springframework.batch.item.ExecutionContext; - -/** - * Strategy interface used to generate keys in driving query input. - * - * @author Lucas Ward - * @since 1.0 - */ -public interface KeyGenerator { - - /** - * @param executionContext TODO - * @return list of keys returned by the driving query - */ - List retrieveKeys(ExecutionContext executionContext); - - /** - * Return the provided key as restart data. - * - * @param key to be converted to restart data. - * @return {@link ExecutionContext} representation of the key. - * @throws IllegalArgumentException if key is null. - * @throws IllegalArgumentException if key is an incompatible type. - */ - void saveState(Object key, ExecutionContext executionContext); -} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ColumnMapExecutionContextRowMapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ColumnMapExecutionContextRowMapper.java index b9b4d90ed..21cced4fd 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ColumnMapExecutionContextRowMapper.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ColumnMapExecutionContextRowMapper.java @@ -21,16 +21,17 @@ import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** - *

Extension of the ColumnMapRowMapper that converts a column map to {@link ExecutionContext} and allows + *

Extension of the {@link ColumnMapRowMapper} that converts a column map to {@link ExecutionContext} and allows * {@link ExecutionContext} to be converted back as a PreparedStatementSetter. This is useful in a restart * scenario, as it allows for the standard functionality of the ColumnMapRowMapper to be used to * create a map representing the columns returned by a query. It should be noted that this column ordering - * is preserved in the map using a link list version of Map. + * is preserved in the map using a link list version of Map.

* * * @author Lucas Ward * @author Dave Syer * @see ExecutionContextRowMapper + * @see ColumnMapRowMapper */ public class ColumnMapExecutionContextRowMapper extends ColumnMapRowMapper implements ExecutionContextRowMapper { diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ExecutionContextRowMapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ExecutionContextRowMapper.java index a4836e4fc..865d40281 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ExecutionContextRowMapper.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ExecutionContextRowMapper.java @@ -16,38 +16,67 @@ package org.springframework.batch.item.database.support; import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.database.DrivingQueryItemReader; +import org.springframework.batch.item.database.KeyCollector; import org.springframework.jdbc.core.PreparedStatementSetter; import org.springframework.jdbc.core.RowMapper; /** - * {@link ExecutionContextRowMapper} extends the standard {@link RowMapper} interface to provide for - * converting an object returned from a RowMapper to {@link ExecutionContext} and back again. One - * of the most common use cases for this type of functionality is the DrivingQuery approach - * to sql processing. Using a {@link ExecutionContextRowMapper}, developers can create each unique key - * to suite their specific needs, and also describe how such a key would be converted to - * {@link ExecutionContext}, so that it can be serialized and stored. - * + *

+ * Extension of the standard {@link RowMapper} interface to provide for + * converting an object returned from a RowMapper to {@link ExecutionContext} + * and back again. This interface serves three purposes: + *

+ * + * + * + * The most common use case for this interface is the need to map multiple + * columns to a key, as is necessary by the + * {@link MultipleColumnJdbcKeyCollector}. In general, it's much simpler to use + * one key as a column, and if the data itself allows this, then it should be + * used. However, in certain cases there is no choice and multiple columns must + * be used. Using a {@link ExecutionContextRowMapper}, developers can create + * each unique key to suite their specific needs, and also describe how such a + * key would be converted to {@link ExecutionContext}, so that it can be + * serialized and stored. + * * @author Lucas Ward * @see RowMapper + * @see MultipleColumnJdbcKeyCollector + * @see KeyCollector * @since 1.0 */ public interface ExecutionContextRowMapper extends RowMapper { /** - * Given the provided composite key, return a {@link ExecutionContext} representation. - * + * Given the provided composite key, return a {@link ExecutionContext} + * representation. + * * @param key * @return ExecutionContext representing the composite key. - * @throws IllegalArgumentException if key is null or of an unsupported type. + * @throws IllegalArgumentException + * if key is null or of an unsupported type. */ public void mapKeys(Object key, ExecutionContext executionContext); /** * Given the provided restart data, return a PreparedStatementSeter that can * be used as parameters to a JdbcTemplate. - * + * * @param executionContext - * @return an array of objects that can be used as arguments to a JdbcTemplate. + * @return an array of objects that can be used as arguments to a + * JdbcTemplate. */ - public PreparedStatementSetter createSetter(ExecutionContext executionContext); + public PreparedStatementSetter createSetter( + ExecutionContext executionContext); } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/IbatisKeyGenerator.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/IbatisKeyCollector.java similarity index 76% rename from spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/IbatisKeyGenerator.java rename to spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/IbatisKeyCollector.java index a6776cd5a..bc869bc5d 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/IbatisKeyGenerator.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/IbatisKeyCollector.java @@ -5,22 +5,24 @@ import java.util.List; import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.item.ExecutionContextUserSupport; import org.springframework.batch.item.database.DrivingQueryItemReader; -import org.springframework.batch.item.database.KeyGenerator; +import org.springframework.batch.item.database.KeyCollector; import org.springframework.orm.ibatis.SqlMapClientTemplate; import org.springframework.util.Assert; import com.ibatis.sqlmap.client.SqlMapClient; /** - * {@link KeyGenerator} based on iBATIS ORM framework. It is functionally - * similar to {@link SingleColumnJdbcKeyGenerator} but does not make assumptions - * about the primary key structure. + * {@link KeyCollector} based on iBATIS ORM framework. It is functionally + * similar to {@link SingleColumnJdbcKeyCollector} but does not make assumptions + * about the primary key structure. A separate restart query is necessary to + * ensure that only the required keys remaining for processing are returned, rather + * than the entire original list.

* * @author Robert Kasanicky * @author Lucas Ward * @see DrivingQueryItemReader */ -public class IbatisKeyGenerator extends ExecutionContextUserSupport implements KeyGenerator { +public class IbatisKeyCollector extends ExecutionContextUserSupport implements KeyCollector { private static final String RESTART_KEY = "key.index"; @@ -30,18 +32,18 @@ public class IbatisKeyGenerator extends ExecutionContextUserSupport implements K private String restartQueryId; - public IbatisKeyGenerator() { - setName(IbatisKeyGenerator.class.getSimpleName()); + public IbatisKeyCollector() { + setName(IbatisKeyCollector.class.getSimpleName()); } /* * Retrieve the keys using the provided driving query id. * - * @see org.springframework.batch.io.support.AbstractDrivingQueryItemReader#retrieveKeys() + * @see KeyCollector#retrieveKeys() */ public List retrieveKeys(ExecutionContext executionContext) { if (executionContext.containsKey(getKey(RESTART_KEY))) { - Object key = executionContext.getString(getKey(RESTART_KEY)); + Object key = executionContext.get(getKey(RESTART_KEY)); return sqlMapClientTemplate.queryForList(restartQueryId, key); } else { @@ -51,12 +53,12 @@ public class IbatisKeyGenerator extends ExecutionContextUserSupport implements K /* * (non-Javadoc) - * @see org.springframework.batch.io.driving.KeyGenerator#getKeyAsExecutionContext(java.lang.Object) + * @see KeyCollector#saveState(Object, ExecutionContext) */ public void saveState(Object key, ExecutionContext executionContext) { Assert.notNull(key, "Key must not be null"); Assert.notNull(executionContext, "ExecutionContext must be null"); - executionContext.putString(getKey(RESTART_KEY), key.toString()); + executionContext.put(getKey(RESTART_KEY), key); } /* diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MultipleColumnJdbcKeyGenerator.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MultipleColumnJdbcKeyCollector.java similarity index 89% rename from spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MultipleColumnJdbcKeyGenerator.java rename to spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MultipleColumnJdbcKeyCollector.java index c65feece1..5c8527af1 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MultipleColumnJdbcKeyGenerator.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MultipleColumnJdbcKeyCollector.java @@ -19,14 +19,14 @@ import java.util.List; import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.item.database.DrivingQueryItemReader; -import org.springframework.batch.item.database.KeyGenerator; +import org.springframework.batch.item.database.KeyCollector; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** *

- * Jdbc implementation of the {@link KeyGenerator} interface that works for + * Jdbc implementation of the {@link KeyCollector} interface that works for * composite keys. (i.e. keys represented by multiple columns) A sql query to be * used to return the keys and a {@link ExecutionContextRowMapper} to map each * row in the resultset to an Object must be set in order to work correctly. @@ -34,9 +34,9 @@ import org.springframework.util.StringUtils; * * @author Lucas Ward * @see DrivingQueryItemReader - * @since 1.0 + * @see ExecutionContextRowMapper */ -public class MultipleColumnJdbcKeyGenerator implements KeyGenerator { +public class MultipleColumnJdbcKeyCollector implements KeyCollector { private JdbcTemplate jdbcTemplate; @@ -46,7 +46,7 @@ public class MultipleColumnJdbcKeyGenerator implements KeyGenerator { private String restartSql; - public MultipleColumnJdbcKeyGenerator() { + public MultipleColumnJdbcKeyCollector() { } /** @@ -57,11 +57,10 @@ public class MultipleColumnJdbcKeyGenerator implements KeyGenerator { * @param keyMapper - RowMapper that maps each row of the ResultSet to an * object. */ - public MultipleColumnJdbcKeyGenerator(JdbcTemplate jdbcTemplate, String sql) { + public MultipleColumnJdbcKeyCollector(JdbcTemplate jdbcTemplate, String sql) { this(); Assert.notNull(jdbcTemplate, "The JdbcTemplate must not be null."); - Assert.hasText(sql, "The DrivingQuery must not be null or empty."); - Assert.notNull(keyMapper, "The key RowMapper must not be null."); + Assert.hasText(sql, "The sql statement must not be null or empty."); this.jdbcTemplate = jdbcTemplate; this.sql = sql; } @@ -90,6 +89,7 @@ public class MultipleColumnJdbcKeyGenerator implements KeyGenerator { */ public void saveState(Object key, ExecutionContext executionContext) { Assert.state(keyMapper != null, "Key mapper must not be null."); + Assert.notNull(key, "The key must not be null"); keyMapper.mapKeys(key, executionContext); } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SingleColumnJdbcKeyGenerator.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SingleColumnJdbcKeyCollector.java similarity index 83% rename from spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SingleColumnJdbcKeyGenerator.java rename to spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SingleColumnJdbcKeyCollector.java index 035fe14df..8687131a1 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SingleColumnJdbcKeyGenerator.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SingleColumnJdbcKeyCollector.java @@ -19,7 +19,7 @@ import java.util.List; import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.item.ExecutionContextUserSupport; -import org.springframework.batch.item.database.KeyGenerator; +import org.springframework.batch.item.database.KeyCollector; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.SingleColumnRowMapper; @@ -28,7 +28,7 @@ import org.springframework.util.StringUtils; /** *

- * Jdbc {@link KeyGenerator} implementation that only works for a single column + * Jdbc {@link KeyCollector} implementation that only works for a single column * key. A sql query must be passed in which will be used to return a list of * keys. Each key will be mapped by a {@link RowMapper} that returns a mapped * key. By default, the {@link SingleColumnRowMapper} is used, and will convert @@ -36,7 +36,7 @@ import org.springframework.util.StringUtils; * only one column should be mapped to an object and returned as a key. If * multiple columns are returned as a key in this strategy, then restart will * not function properly. Instead a strategy that supports keys comprised of - * multiple columns should be used. + * multiple columns should be used.

* *

* Restartability: Because the key is only one column, restart is made much more @@ -48,9 +48,9 @@ import org.springframework.util.StringUtils; *

* * @author Lucas Ward - * @since 1.0 + * @see SingleColumnRowMapper */ -public class SingleColumnJdbcKeyGenerator extends ExecutionContextUserSupport implements KeyGenerator { +public class SingleColumnJdbcKeyCollector extends ExecutionContextUserSupport implements KeyCollector { private static final String RESTART_KEY = "key"; @@ -62,8 +62,8 @@ public class SingleColumnJdbcKeyGenerator extends ExecutionContextUserSupport im private RowMapper keyMapper = new SingleColumnRowMapper(); - public SingleColumnJdbcKeyGenerator() { - setName(SingleColumnJdbcKeyGenerator.class.getSimpleName()); + public SingleColumnJdbcKeyCollector() { + setName(SingleColumnJdbcKeyCollector.class.getSimpleName()); } /** @@ -75,7 +75,7 @@ public class SingleColumnJdbcKeyGenerator extends ExecutionContextUserSupport im * @throws IllegalArgumentException if jdbcTemplate is null. * @throws IllegalArgumentException if sql string is empty or null. */ - public SingleColumnJdbcKeyGenerator(JdbcTemplate jdbcTemplate, String sql) { + public SingleColumnJdbcKeyCollector(JdbcTemplate jdbcTemplate, String sql) { this(); Assert.notNull(jdbcTemplate, "JdbcTemplate must not be null."); Assert.hasText(sql, "The sql statement must not be null or empty."); @@ -89,12 +89,12 @@ public class SingleColumnJdbcKeyGenerator extends ExecutionContextUserSupport im */ public List retrieveKeys(ExecutionContext executionContext) { - Assert.notNull(executionContext, "The restart data must not be null."); + Assert.notNull(executionContext, "The ExecutionContext must not be null"); if (executionContext.containsKey(RESTART_KEY)) { - Assert.state(StringUtils.hasText(restartSql), "The RestartQuery must not be null or empty" + Assert.state(StringUtils.hasText(restartSql), "The restart sql query must not be null or empty" + " in order to restart."); - return jdbcTemplate.query(restartSql, new Object[] { executionContext.getString(RESTART_KEY) }, keyMapper); + return jdbcTemplate.query(restartSql, new Object[] { executionContext.get(RESTART_KEY) }, keyMapper); } else{ return jdbcTemplate.query(sql, keyMapper); @@ -104,12 +104,13 @@ public class SingleColumnJdbcKeyGenerator extends ExecutionContextUserSupport im /** * Get the restart data representing the last processed key. * - * @see KeyGenerator#saveState(Object) + * @see KeyCollector#saveState(Object) * @throws IllegalArgumentException if key is null. */ public void saveState(Object key, ExecutionContext executionContext) { Assert.notNull(key, "The key must not be null."); - executionContext.putString(RESTART_KEY, key.toString()); + Assert.notNull(executionContext, "The ExecutionContext must not be null"); + executionContext.put(RESTART_KEY, key); } /* diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/DrivingQueryItemReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/DrivingQueryItemReaderTests.java index 6daa708da..bc0da8a3d 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/DrivingQueryItemReaderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/DrivingQueryItemReaderTests.java @@ -32,7 +32,7 @@ public class DrivingQueryItemReaderTests extends TestCase { private DrivingQueryItemReader createItemReader() throws Exception{ DrivingQueryItemReader inputSource = new DrivingQueryItemReader(); - inputSource.setKeyGenerator(new MockKeyGenerator()); + inputSource.setKeyCollector(new MockKeyGenerator()); inputSource.setSaveState(true); return inputSource; @@ -157,7 +157,7 @@ public class DrivingQueryItemReaderTests extends TestCase { public void testRetriveZeroKeys(){ - itemReader.setKeyGenerator(new KeyGenerator(){ + itemReader.setKeyCollector(new KeyCollector(){ public List retrieveKeys(ExecutionContext executionContext) { return new ArrayList(); @@ -192,7 +192,7 @@ public class DrivingQueryItemReaderTests extends TestCase { return (ItemStream) source; } - private static class MockKeyGenerator implements KeyGenerator{ + private static class MockKeyGenerator implements KeyCollector{ static ExecutionContext streamContext; List keys; diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/IbatisItemReaderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/IbatisItemReaderIntegrationTests.java index d23cf5c59..e76564d53 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/IbatisItemReaderIntegrationTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/IbatisItemReaderIntegrationTests.java @@ -1,7 +1,7 @@ package org.springframework.batch.item.database; import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.database.support.IbatisKeyGenerator; +import org.springframework.batch.item.database.support.IbatisKeyCollector; import org.springframework.core.io.ClassPathResource; import org.springframework.orm.ibatis.SqlMapClientFactoryBean; @@ -23,13 +23,13 @@ public class IbatisItemReaderIntegrationTests extends AbstractDataSourceItemRead SqlMapClient sqlMapClient = (SqlMapClient) factory.getObject(); IbatisDrivingQueryItemReader inputSource = new IbatisDrivingQueryItemReader(); - IbatisKeyGenerator keyGenerator = new IbatisKeyGenerator(); + IbatisKeyCollector keyGenerator = new IbatisKeyCollector(); keyGenerator.setDrivingQueryId("getAllFooIds"); inputSource.setDetailsQueryId("getFooById"); keyGenerator.setRestartQueryId("getAllFooIdsRestart"); keyGenerator.setSqlMapClient(sqlMapClient); inputSource.setSqlMapClient(sqlMapClient); - inputSource.setKeyGenerator(keyGenerator); + inputSource.setKeyCollector(keyGenerator); inputSource.setSaveState(true); return inputSource; diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/MultipleColumnJdbcDrivingQueryItemReaderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/MultipleColumnJdbcDrivingQueryItemReaderIntegrationTests.java index aa6a8a567..9c930c89d 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/MultipleColumnJdbcDrivingQueryItemReaderIntegrationTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/MultipleColumnJdbcDrivingQueryItemReaderIntegrationTests.java @@ -16,7 +16,7 @@ package org.springframework.batch.item.database; import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.database.support.MultipleColumnJdbcKeyGenerator; +import org.springframework.batch.item.database.support.MultipleColumnJdbcKeyCollector; /** * @author Lucas Ward @@ -27,14 +27,14 @@ public class MultipleColumnJdbcDrivingQueryItemReaderIntegrationTests extends protected ItemReader createItemReader() throws Exception { - MultipleColumnJdbcKeyGenerator keyGenerator = - new MultipleColumnJdbcKeyGenerator(getJdbcTemplate(), + MultipleColumnJdbcKeyCollector keyGenerator = + new MultipleColumnJdbcKeyCollector(getJdbcTemplate(), "SELECT ID, VALUE from T_FOOS order by ID, VALUE"); keyGenerator.setRestartSql("SELECT ID, VALUE from T_FOOS where ID > ? and VALUE > ? order by ID"); DrivingQueryItemReader inputSource = new DrivingQueryItemReader(); inputSource.setSaveState(true); - inputSource.setKeyGenerator(keyGenerator); + inputSource.setKeyCollector(keyGenerator); FooItemReader fooItemReader = new FooItemReader(inputSource, getJdbcTemplate()); fooItemReader.setFooDao(new CompositeKeyFooDao(getJdbcTemplate())); return fooItemReader; diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/SingleColumnJdbcDrivingQueryItemReaderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/SingleColumnJdbcDrivingQueryItemReaderIntegrationTests.java index 3052e6846..58f4ac5bc 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/SingleColumnJdbcDrivingQueryItemReaderIntegrationTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/SingleColumnJdbcDrivingQueryItemReaderIntegrationTests.java @@ -1,7 +1,7 @@ package org.springframework.batch.item.database; import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.database.support.SingleColumnJdbcKeyGenerator; +import org.springframework.batch.item.database.support.SingleColumnJdbcKeyCollector; public class SingleColumnJdbcDrivingQueryItemReaderIntegrationTests extends AbstractJdbcItemReaderIntegrationTests { @@ -13,11 +13,11 @@ public class SingleColumnJdbcDrivingQueryItemReaderIntegrationTests extends Abst */ protected ItemReader createItemReader() throws Exception { - SingleColumnJdbcKeyGenerator keyStrategy = new SingleColumnJdbcKeyGenerator(getJdbcTemplate(), + SingleColumnJdbcKeyCollector keyStrategy = new SingleColumnJdbcKeyCollector(getJdbcTemplate(), "SELECT ID from T_FOOS order by ID"); keyStrategy.setRestartSql("SELECT ID from T_FOOS where ID > ? order by ID"); DrivingQueryItemReader inputSource = new DrivingQueryItemReader(); - inputSource.setKeyGenerator(keyStrategy); + inputSource.setKeyCollector(keyStrategy); inputSource.setSaveState(true); return new FooItemReader(inputSource, getJdbcTemplate()); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MultipleColumnJdbcKeyGeneratorIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MultipleColumnJdbcKeyGeneratorIntegrationTests.java index 2431082db..91621d0cc 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MultipleColumnJdbcKeyGeneratorIntegrationTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MultipleColumnJdbcKeyGeneratorIntegrationTests.java @@ -22,7 +22,7 @@ import org.springframework.test.AbstractTransactionalDataSourceSpringContextTest */ public class MultipleColumnJdbcKeyGeneratorIntegrationTests extends AbstractTransactionalDataSourceSpringContextTests { - MultipleColumnJdbcKeyGenerator keyStrategy; + MultipleColumnJdbcKeyCollector keyStrategy; ExecutionContext executionContext; @@ -33,7 +33,7 @@ public class MultipleColumnJdbcKeyGeneratorIntegrationTests extends AbstractTran protected void onSetUpBeforeTransaction() throws Exception { super.onSetUpBeforeTransaction(); - keyStrategy = new MultipleColumnJdbcKeyGenerator(getJdbcTemplate(), + keyStrategy = new MultipleColumnJdbcKeyCollector(getJdbcTemplate(), "SELECT ID, VALUE from T_FOOS order by ID"); keyStrategy.setRestartSql("SELECT ID, VALUE from T_FOOS where ID > ? and VALUE > ? order by ID"); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/SingleColumnJdbcKeyGeneratorIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/SingleColumnJdbcKeyGeneratorIntegrationTests.java index 34939aa61..5b5101145 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/SingleColumnJdbcKeyGeneratorIntegrationTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/SingleColumnJdbcKeyGeneratorIntegrationTests.java @@ -12,7 +12,7 @@ import org.springframework.test.AbstractTransactionalDataSourceSpringContextTest */ public class SingleColumnJdbcKeyGeneratorIntegrationTests extends AbstractTransactionalDataSourceSpringContextTests { - SingleColumnJdbcKeyGenerator keyStrategy; + SingleColumnJdbcKeyCollector keyStrategy; ExecutionContext executionContext; @@ -24,7 +24,7 @@ public class SingleColumnJdbcKeyGeneratorIntegrationTests extends AbstractTransa protected void onSetUpBeforeTransaction() throws Exception { super.onSetUpBeforeTransaction(); - keyStrategy = new SingleColumnJdbcKeyGenerator(getJdbcTemplate(), + keyStrategy = new SingleColumnJdbcKeyCollector(getJdbcTemplate(), "SELECT ID from T_FOOS order by ID"); keyStrategy.setRestartSql("SELECT ID from T_FOOS where ID > ? order by ID");