BATCH-851: Removed DrivingQueryItemReader and related classes.
This commit is contained in:
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.item.database;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Convenience class for driving query item readers. Item readers of this type
|
||||
* 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:
|
||||
*
|
||||
* <pre>
|
||||
* CREATE TABLE CUSTOMER (
|
||||
* ID BIGINT IDENTITY PRIMARY KEY,
|
||||
* NAME VARCHAR(45),
|
||||
* CREDIT FLOAT
|
||||
* );
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* 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()}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Mutability: Because this base class cannot guarantee that the keys returned
|
||||
* by subclasses are immutable, care should be taken to not modify a key value.
|
||||
* Doing so would cause issues if a rollback occurs. For example, if a call to
|
||||
* read() is made, and the returned key is modified, a rollback will cause the
|
||||
* next call to read() to return the same object that was originally returned,
|
||||
* since there is no way to create a defensive copy, and re-querying the
|
||||
* database for all the keys would be too resource intensive.
|
||||
* </p>
|
||||
*
|
||||
* The implementation is *not* thread-safe.
|
||||
*
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @deprecated The DrivingQueryItemReader approach is not supported going forward, use a PagingItemReader
|
||||
* implementation instead. See {@link org.springframework.batch.item.database.AbstractPagingItemReader}
|
||||
*/
|
||||
public class DrivingQueryItemReader<T> implements ItemReader<T>, InitializingBean, ItemStream {
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
private T currentKey = null;
|
||||
|
||||
private Iterator<T> keysIterator;
|
||||
|
||||
private int currentIndex = 0;
|
||||
|
||||
private KeyCollector<T> keyCollector;
|
||||
|
||||
private boolean saveState = false;
|
||||
|
||||
public DrivingQueryItemReader() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the input source with the provided keys list.
|
||||
*
|
||||
* @param keys
|
||||
*/
|
||||
public DrivingQueryItemReader(List<T> keys) {
|
||||
this.keysIterator = keys.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next key in the List.
|
||||
*
|
||||
* @return next key in the list if not index is not at the last element,
|
||||
* null otherwise.
|
||||
*/
|
||||
public T read() {
|
||||
|
||||
if (keysIterator.hasNext()) {
|
||||
currentIndex++;
|
||||
currentKey = keysIterator.next();
|
||||
return currentKey;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current key. This method will return the same object returned by
|
||||
* the last read() method. If no items have been read yet the ItemReader
|
||||
* yet, then null will be returned.
|
||||
*
|
||||
* @return the current key.
|
||||
*/
|
||||
protected T getCurrentKey() {
|
||||
return currentKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resource by setting the list of keys to null, allowing them to
|
||||
* be garbage collected.
|
||||
*/
|
||||
public void close() {
|
||||
initialized = false;
|
||||
currentIndex = 0;
|
||||
keysIterator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the item reader by delegating to the subclass in order to
|
||||
* retrieve the keys.
|
||||
*
|
||||
* @throws IllegalStateException if the keys list is null or initialized is
|
||||
* true.
|
||||
*/
|
||||
public void open(ExecutionContext executionContext) {
|
||||
|
||||
Assert.state(keysIterator == null && !initialized, "Cannot open an already opened item reader"
|
||||
+ ", call close() first.");
|
||||
List<T> keys = keyCollector.retrieveKeys(executionContext);
|
||||
Assert.notNull(keys, "Keys must not be null");
|
||||
keysIterator = keys.listIterator();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
public void update(ExecutionContext executionContext) {
|
||||
if (saveState) {
|
||||
Assert.notNull(executionContext, "ExecutionContext must not be null");
|
||||
if (getCurrentKey() != null) {
|
||||
keyCollector.updateContext(getCurrentKey(), executionContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(keyCollector, "The KeyGenerator must not be null.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the key generation strategy to use for this input source.
|
||||
*
|
||||
* @param keyCollector
|
||||
*/
|
||||
public void setKeyCollector(KeyCollector<T> keyCollector) {
|
||||
this.keyCollector = keyCollector;
|
||||
}
|
||||
|
||||
public void setSaveState(boolean saveState) {
|
||||
this.saveState = saveState;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.item.database;
|
||||
|
||||
import org.springframework.batch.item.database.support.IbatisKeyCollector;
|
||||
import org.springframework.orm.ibatis.SqlMapClientTemplate;
|
||||
|
||||
import com.ibatis.sqlmap.client.SqlMapClient;
|
||||
|
||||
/**
|
||||
* Extension of {@link DrivingQueryItemReader} that maps keys to objects. An
|
||||
* iBatis query id must be set to map and return each 'detail record'.
|
||||
*
|
||||
* The writer is thread safe after its properties are set (normal singleton
|
||||
* behaviour).
|
||||
*
|
||||
* TODO remove this class? It does not return keys so it shouldn't extend
|
||||
* DrivingQueryItemReader
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @see IbatisKeyCollector
|
||||
* @deprecated The DrivingQueryItemReader approach is not supported going forward, use a PagingItemReader
|
||||
* implementation instead. See {@link org.springframework.batch.item.database.AbstractPagingItemReader}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class IbatisDrivingQueryItemReader extends DrivingQueryItemReader {
|
||||
|
||||
private String detailsQueryId;
|
||||
|
||||
private SqlMapClientTemplate sqlMapClientTemplate;
|
||||
|
||||
/**
|
||||
* Overridden read() that uses the returned key as arguments to the details
|
||||
* query.
|
||||
*
|
||||
* @see org.springframework.batch.item.database.DrivingQueryItemReader#read()
|
||||
*/
|
||||
public Object read() {
|
||||
Object key = super.read();
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
return sqlMapClientTemplate.queryForObject(detailsQueryId, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param detailsQueryId id of the iBATIS select statement that will used to
|
||||
* retrieve an object for a single primary key from the list returned by
|
||||
* driving query
|
||||
*/
|
||||
public void setDetailsQueryId(String detailsQueryId) {
|
||||
this.detailsQueryId = detailsQueryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SqlMapClientTemplate} to use for this input source.
|
||||
*
|
||||
* @param sqlMapClient
|
||||
*/
|
||||
public void setSqlMapClient(SqlMapClient sqlMapClient) {
|
||||
this.sqlMapClientTemplate = new SqlMapClientTemplate(sqlMapClient);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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
|
||||
* @deprecated The DrivingQueryItemReader approach is not supported going forward, use a PagingItemReader
|
||||
* implementation instead. See {@link org.springframework.batch.item.database.AbstractPagingItemReader}
|
||||
*/
|
||||
public interface KeyCollector<T> {
|
||||
|
||||
/**
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>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.
|
||||
* </p>
|
||||
*
|
||||
* @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 (can be empty but not null)
|
||||
*/
|
||||
List<T> 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.
|
||||
* @throws IllegalArgumentException if key is null.
|
||||
* @throws IllegalArgumentException if key is an incompatible type.
|
||||
*/
|
||||
void updateContext(T key, ExecutionContext executionContext);
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.batch.item.database.support;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.database.DrivingQueryItemReader;
|
||||
import org.springframework.batch.item.database.KeyCollector;
|
||||
import org.springframework.batch.item.util.ExecutionContextUserSupport;
|
||||
import org.springframework.orm.ibatis.SqlMapClientTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.ibatis.sqlmap.client.SqlMapClient;
|
||||
|
||||
/**
|
||||
* {@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.</p>
|
||||
*
|
||||
* The writer is thread safe after its properties are set (normal singleton
|
||||
* behaviour).
|
||||
*
|
||||
* @author Robert Kasanicky
|
||||
* @author Lucas Ward
|
||||
* @see DrivingQueryItemReader
|
||||
* @deprecated The DrivingQueryItemReader approach is not supported going forward, use a PagingItemReader
|
||||
* implementation instead. See {@link org.springframework.batch.item.database.AbstractPagingItemReader}
|
||||
*/
|
||||
public class IbatisKeyCollector<T> extends ExecutionContextUserSupport implements KeyCollector<T> {
|
||||
|
||||
private static final String RESTART_KEY = "key.index";
|
||||
|
||||
private SqlMapClientTemplate sqlMapClientTemplate;
|
||||
|
||||
private String drivingQuery;
|
||||
|
||||
private String restartQueryId;
|
||||
|
||||
public IbatisKeyCollector() {
|
||||
setName(ClassUtils.getShortName(IbatisKeyCollector.class));
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the keys using the provided driving query id.
|
||||
*
|
||||
* @see KeyCollector#retrieveKeys()
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<T> retrieveKeys(ExecutionContext executionContext) {
|
||||
if (executionContext.containsKey(getKey(RESTART_KEY))) {
|
||||
Object key = executionContext.get(getKey(RESTART_KEY));
|
||||
return sqlMapClientTemplate.queryForList(restartQueryId, key);
|
||||
}
|
||||
else {
|
||||
return sqlMapClientTemplate.queryForList(drivingQuery);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see KeyCollector#saveState(Object, ExecutionContext)
|
||||
*/
|
||||
public void updateContext(T key, ExecutionContext executionContext) {
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
Assert.notNull(executionContext, "ExecutionContext must be null");
|
||||
executionContext.put(getKey(RESTART_KEY), key);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(sqlMapClientTemplate, "SqlMaperClientTemplate must not be null.");
|
||||
Assert.hasText(drivingQuery, "The DrivingQuery must not be null or empty.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sqlMapClient configured iBATIS client
|
||||
*/
|
||||
public void setSqlMapClient(SqlMapClient sqlMapClient) {
|
||||
this.sqlMapClientTemplate = new SqlMapClientTemplate();
|
||||
this.sqlMapClientTemplate.setSqlMapClient(sqlMapClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param drivingQueryId id of the iBATIS select statement that will be used
|
||||
* to retrieve the list of primary keys
|
||||
*/
|
||||
public void setDrivingQueryId(String drivingQueryId) {
|
||||
this.drivingQuery = drivingQueryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the id of the restart query.
|
||||
*
|
||||
* @param restartQueryId id of the iBatis select statement that will be used
|
||||
* to retrieve the list of primary keys after a restart.
|
||||
*/
|
||||
public void setRestartQueryId(String restartQueryId) {
|
||||
this.restartQueryId = restartQueryId;
|
||||
}
|
||||
|
||||
public final SqlMapClientTemplate getSqlMapClientTemplate() {
|
||||
return sqlMapClientTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.item.database.support;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.database.DrivingQueryItemReader;
|
||||
import org.springframework.batch.item.database.ItemPreparedStatementSetter;
|
||||
import org.springframework.batch.item.database.KeyCollector;
|
||||
import org.springframework.batch.item.util.ExecutionContextUserSupport;
|
||||
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 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 ItemPreparedStatementSetter} to map each
|
||||
* row in the result set to an Object must be set in order to work correctly.
|
||||
* </p>
|
||||
*
|
||||
* The implementation is thread-safe as long as the
|
||||
* {@link #setPreparedStatementSetter(ItemPreparedStatementSetter)} and
|
||||
* {@link #setKeyMapper(RowMapper)} are thread-safe (true for default values).
|
||||
*
|
||||
*
|
||||
* @author Lucas Ward
|
||||
*
|
||||
* @see DrivingQueryItemReader
|
||||
* @see ItemPreparedStatementSetter
|
||||
*
|
||||
* TODO this class has nothing to do with "multiple columns" other than default
|
||||
* values form keyMapper and preparedStatementSetter. This should be sorted out for 2.0
|
||||
* @deprecated The DrivingQueryItemReader approach is not supported going forward, use a PagingItemReader
|
||||
* implementation instead. See {@link org.springframework.batch.item.database.AbstractPagingItemReader}
|
||||
*/
|
||||
public class MultipleColumnJdbcKeyCollector<T> extends ExecutionContextUserSupport implements KeyCollector<T> {
|
||||
|
||||
private static final String CURRENT_KEY = "current.key";
|
||||
|
||||
private JdbcOperations jdbcTemplate;
|
||||
|
||||
private RowMapper keyMapper = new ColumnMapRowMapper();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ItemPreparedStatementSetter preparedStatementSetter = new ColumnMapItemPreparedStatementSetter();
|
||||
|
||||
private String sql;
|
||||
|
||||
private String restartSql;
|
||||
|
||||
public MultipleColumnJdbcKeyCollector() {
|
||||
setName(ClassUtils.getShortName(MultipleColumnJdbcKeyCollector.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new ItemReader.
|
||||
*
|
||||
* @param jdbcTemplate
|
||||
* @param sql - SQL statement that returns all keys to process. object.
|
||||
*/
|
||||
public MultipleColumnJdbcKeyCollector(JdbcOperations jdbcTemplate, String sql) {
|
||||
this();
|
||||
Assert.notNull(jdbcTemplate, "The JdbcTemplate must not be null.");
|
||||
Assert.hasText(sql, "The sql statement must not be null or empty.");
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.batch.io.sql.scratch.AbstractDrivingQueryItemReader
|
||||
* #retrieveKeys()
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<T> retrieveKeys(ExecutionContext executionContext) {
|
||||
|
||||
Assert.state(keyMapper != null, "KeyMapper must not be null.");
|
||||
Assert.state(StringUtils.hasText(restartSql), "The RestartQuery must not be null or empty"
|
||||
+ " in order to restart.");
|
||||
|
||||
if (executionContext.size() > 0) {
|
||||
T key = (T) executionContext.get(getKey(CURRENT_KEY));
|
||||
return jdbcTemplate.query(restartSql, new PreparedStatementSetterKeyWrapper(key, preparedStatementSetter),
|
||||
keyMapper);
|
||||
}
|
||||
else {
|
||||
return jdbcTemplate.query(sql, keyMapper);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.batch.io.driving.KeyGenerator#getKeyAsExecutionContext
|
||||
* (java.lang.Object)
|
||||
*/
|
||||
public void updateContext(T key, ExecutionContext executionContext) {
|
||||
Assert.notNull(key, "The key must not be null");
|
||||
Assert.notNull(executionContext, "The ExecutionContext must not be null");
|
||||
executionContext.put(getKey(CURRENT_KEY), key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the query to use to retrieve keys in order to restore the previous
|
||||
* state for restart.
|
||||
*
|
||||
* @param restartQuery
|
||||
*/
|
||||
public void setRestartSql(String restartQuery) {
|
||||
this.restartSql = restartQuery;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
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.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link RowMapper} to be used to map a result set to keys.
|
||||
*
|
||||
* @param keyMapper
|
||||
*/
|
||||
public void setKeyMapper(RowMapper keyMapper) {
|
||||
this.keyMapper = keyMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sql statement used to generate the keys list.
|
||||
*
|
||||
* @param sql
|
||||
*/
|
||||
public void setSql(String sql) {
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public void setJdbcTemplate(JdbcOperations jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
public void setPreparedStatementSetter(ItemPreparedStatementSetter<T> preparedStatementSetter) {
|
||||
this.preparedStatementSetter = preparedStatementSetter;
|
||||
}
|
||||
|
||||
private class PreparedStatementSetterKeyWrapper implements PreparedStatementSetter {
|
||||
|
||||
private T key;
|
||||
|
||||
private ItemPreparedStatementSetter<T> pss;
|
||||
|
||||
public PreparedStatementSetterKeyWrapper(T key, ItemPreparedStatementSetter<T> pss) {
|
||||
this.key = key;
|
||||
this.pss = pss;
|
||||
}
|
||||
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
pss.setValues(key, ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.item.database.support;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.database.KeyCollector;
|
||||
import org.springframework.batch.item.util.ExecutionContextUserSupport;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.SingleColumnRowMapper;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 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
|
||||
* keys into well known types at runtime. It is extremely important to note that
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Restartability: Because the key is only one column, restart is made much more
|
||||
* simple. Before each commit, the last processed key is returned to be stored
|
||||
* as restart data. Upon restart, that same key is given back to restore from,
|
||||
* using a separate 'RestartQuery'. This means that only the keys remaining to
|
||||
* be processed are returned, rather than returning the original list of keys
|
||||
* and iterating forward to that last committed point.
|
||||
* </p>
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @see SingleColumnRowMapper
|
||||
* @deprecated The DrivingQueryItemReader approach is not supported going forward, use a PagingItemReader
|
||||
* implementation instead. See {@link org.springframework.batch.item.database.AbstractPagingItemReader}
|
||||
*/
|
||||
public class SingleColumnJdbcKeyCollector<T> extends ExecutionContextUserSupport implements KeyCollector<T> {
|
||||
|
||||
private static final String RESTART_KEY = "key";
|
||||
|
||||
private JdbcOperations jdbcTemplate;
|
||||
|
||||
private String sql;
|
||||
|
||||
private String restartSql;
|
||||
|
||||
private RowMapper keyMapper = new SingleColumnRowMapper();
|
||||
|
||||
public SingleColumnJdbcKeyCollector() {
|
||||
setName(ClassUtils.getShortName(SingleColumnJdbcKeyCollector.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance using the provided jdbcTemplate and string
|
||||
* representing the sql statement that should be used to retrieve keys.
|
||||
*
|
||||
* @param jdbcTemplate
|
||||
* @param sql
|
||||
* @throws IllegalArgumentException if jdbcTemplate is null.
|
||||
* @throws IllegalArgumentException if sql string is empty or null.
|
||||
*/
|
||||
public SingleColumnJdbcKeyCollector(JdbcOperations jdbcTemplate, String sql) {
|
||||
this();
|
||||
Assert.notNull(jdbcTemplate, "JdbcTemplate must not be null.");
|
||||
Assert.hasText(sql, "The sql statement must not be null or empty.");
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.batch.io.driving.KeyGenerationStrategy#retrieveKeys()
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<T> retrieveKeys(ExecutionContext executionContext) {
|
||||
|
||||
Assert.notNull(executionContext, "The ExecutionContext must not be null");
|
||||
|
||||
if (executionContext.containsKey(getKey(RESTART_KEY))) {
|
||||
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.get(getKey(RESTART_KEY)) }, keyMapper);
|
||||
}
|
||||
else {
|
||||
return jdbcTemplate.query(sql, keyMapper);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the restart data representing the last processed key.
|
||||
*
|
||||
* @throws IllegalArgumentException if key is null.
|
||||
*/
|
||||
public void updateContext(T key, ExecutionContext executionContext) {
|
||||
Assert.notNull(key, "The key must not be null.");
|
||||
Assert.notNull(executionContext, "The ExecutionContext must not be null");
|
||||
executionContext.put(getKey(RESTART_KEY), key);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(jdbcTemplate, "JdbcTemplate must not be null.");
|
||||
Assert.hasText(sql, "The DrivingQuery must not be null or empty.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link RowMapper} to be used to map each key to an object.
|
||||
*
|
||||
* @param keyMapper
|
||||
*/
|
||||
public void setKeyMapper(RowMapper keyMapper) {
|
||||
this.keyMapper = keyMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SQL query to be used to return the remaining keys to be
|
||||
* processed.
|
||||
*
|
||||
* @param restartSql
|
||||
*/
|
||||
public void setRestartSql(String restartSql) {
|
||||
this.restartSql = restartSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SQL statement to be used to return the keys to be processed.
|
||||
*
|
||||
* @param sql
|
||||
*/
|
||||
public void setSql(String sql) {
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link JdbcOperations} to be used.
|
||||
*
|
||||
* @param jdbcTemplate
|
||||
*/
|
||||
public void setJdbcTemplate(JdbcOperations jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
package org.springframework.batch.item.database;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.batch.item.sample.Foo;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class DrivingQueryItemReaderTests extends TestCase {
|
||||
|
||||
DrivingQueryItemReader<Foo> itemReader;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
itemReader = createItemReader();
|
||||
}
|
||||
|
||||
private DrivingQueryItemReader<Foo> createItemReader() throws Exception {
|
||||
|
||||
DrivingQueryItemReader<Foo> inputSource = new DrivingQueryItemReader<Foo>();
|
||||
inputSource.setKeyCollector(new MockKeyGenerator());
|
||||
inputSource.setSaveState(true);
|
||||
|
||||
return inputSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular scenario - read all rows and eventually return null.
|
||||
*/
|
||||
public void testNormalProcessing() throws Exception {
|
||||
getAsInitializingBean(itemReader).afterPropertiesSet();
|
||||
getAsItemStream(itemReader).open(new ExecutionContext());
|
||||
|
||||
Foo foo1 = (Foo) itemReader.read();
|
||||
assertEquals(1, foo1.getValue());
|
||||
|
||||
Foo foo2 = (Foo) itemReader.read();
|
||||
assertEquals(2, foo2.getValue());
|
||||
|
||||
Foo foo3 = (Foo) itemReader.read();
|
||||
assertEquals(3, foo3.getValue());
|
||||
|
||||
Foo foo4 = (Foo) itemReader.read();
|
||||
assertEquals(4, foo4.getValue());
|
||||
|
||||
Foo foo5 = (Foo) itemReader.read();
|
||||
assertEquals(5, foo5.getValue());
|
||||
|
||||
assertNull(itemReader.read());
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart scenario.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testRestart() throws Exception {
|
||||
|
||||
ExecutionContext executionContext = new ExecutionContext();
|
||||
|
||||
getAsItemStream(itemReader).open(executionContext);
|
||||
|
||||
Foo foo1 = (Foo) itemReader.read();
|
||||
assertEquals(1, foo1.getValue());
|
||||
|
||||
Foo foo2 = (Foo) itemReader.read();
|
||||
assertEquals(2, foo2.getValue());
|
||||
|
||||
getAsItemStream(itemReader).update(executionContext);
|
||||
|
||||
// create new input source
|
||||
itemReader = createItemReader();
|
||||
|
||||
getAsItemStream(itemReader).open(executionContext);
|
||||
|
||||
Foo fooAfterRestart = (Foo) itemReader.read();
|
||||
assertEquals(3, fooAfterRestart.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading from an input source and then trying to restore causes an error.
|
||||
*/
|
||||
public void testInvalidRestore() throws Exception {
|
||||
|
||||
ExecutionContext executionContext = new ExecutionContext();
|
||||
|
||||
getAsItemStream(itemReader).open(executionContext);
|
||||
|
||||
Foo foo1 = (Foo) itemReader.read();
|
||||
assertEquals(1, foo1.getValue());
|
||||
|
||||
Foo foo2 = (Foo) itemReader.read();
|
||||
assertEquals(2, foo2.getValue());
|
||||
|
||||
getAsItemStream(itemReader).update(executionContext);
|
||||
|
||||
// create new input source
|
||||
itemReader = createItemReader();
|
||||
getAsItemStream(itemReader).open(new ExecutionContext());
|
||||
|
||||
Foo foo = (Foo) itemReader.read();
|
||||
assertEquals(1, foo.getValue());
|
||||
|
||||
try {
|
||||
getAsItemStream(itemReader).open(executionContext);
|
||||
fail();
|
||||
} catch (IllegalStateException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty restart data should be handled gracefully.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testRestoreFromEmptyData() throws Exception {
|
||||
ExecutionContext streamContext = new ExecutionContext(new ExecutionContext());
|
||||
|
||||
getAsItemStream(itemReader).open(streamContext);
|
||||
|
||||
Foo foo = (Foo) itemReader.read();
|
||||
assertEquals(1, foo.getValue());
|
||||
}
|
||||
|
||||
public void testRetriveZeroKeys() {
|
||||
|
||||
itemReader.setKeyCollector(new KeyCollector<Foo>() {
|
||||
|
||||
public List<Foo> retrieveKeys(ExecutionContext executionContext) {
|
||||
return new ArrayList<Foo>();
|
||||
}
|
||||
|
||||
public void updateContext(Foo key,
|
||||
ExecutionContext executionContext) {
|
||||
}
|
||||
});
|
||||
|
||||
itemReader.open(new ExecutionContext());
|
||||
|
||||
assertNull(itemReader.read());
|
||||
|
||||
}
|
||||
|
||||
private InitializingBean getAsInitializingBean(ItemReader<Foo> source) {
|
||||
return (InitializingBean) source;
|
||||
}
|
||||
|
||||
private ItemStream getAsItemStream(ItemReader<Foo> source) {
|
||||
return (ItemStream) source;
|
||||
}
|
||||
|
||||
private static class MockKeyGenerator implements KeyCollector<Foo> {
|
||||
|
||||
static ExecutionContext streamContext;
|
||||
List<Foo> keys;
|
||||
List<Foo> restartKeys;
|
||||
static final String RESTART_KEY = "restart.keys";
|
||||
|
||||
static {
|
||||
// restart data properties cannot be empty.
|
||||
streamContext = new ExecutionContext();
|
||||
streamContext.put("", "");
|
||||
}
|
||||
|
||||
public MockKeyGenerator() {
|
||||
|
||||
keys = new ArrayList<Foo>();
|
||||
keys.add(new Foo(1, "1", 1));
|
||||
keys.add(new Foo(2, "2", 2));
|
||||
keys.add(new Foo(3, "3", 3));
|
||||
keys.add(new Foo(4, "4", 4));
|
||||
keys.add(new Foo(5, "5", 5));
|
||||
|
||||
restartKeys = new ArrayList<Foo>();
|
||||
restartKeys.add(new Foo(3, "3", 3));
|
||||
restartKeys.add(new Foo(4, "4", 4));
|
||||
restartKeys.add(new Foo(5, "5", 5));
|
||||
}
|
||||
|
||||
public ExecutionContext saveState(Object key) {
|
||||
return streamContext;
|
||||
}
|
||||
|
||||
public List<Foo> retrieveKeys(ExecutionContext executionContext) {
|
||||
if (executionContext.containsKey(RESTART_KEY)) {
|
||||
return restartKeys;
|
||||
} else {
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateContext(Foo key, ExecutionContext executionContext) {
|
||||
executionContext.put(RESTART_KEY, restartKeys);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package org.springframework.batch.item.database;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.batch.item.sample.Foo;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
class FooItemReader implements ItemStream, ItemReader<Foo>, DisposableBean, InitializingBean {
|
||||
|
||||
DrivingQueryItemReader<?> itemReader;
|
||||
|
||||
public void setItemReader(DrivingQueryItemReader<?> itemReader) {
|
||||
this.itemReader = itemReader;
|
||||
}
|
||||
|
||||
FooDao fooDao = new SingleKeyFooDao();
|
||||
|
||||
public FooItemReader(DrivingQueryItemReader<?> inputSource, DataSource dataSource) {
|
||||
this.itemReader = inputSource;
|
||||
fooDao.setDataSource(dataSource);
|
||||
}
|
||||
|
||||
public Foo read() {
|
||||
Object key = itemReader.read();
|
||||
if (key != null) {
|
||||
return fooDao.getFoo(key);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void update(ExecutionContext executionContext) {
|
||||
itemReader.update(executionContext);
|
||||
}
|
||||
|
||||
public void destroy() throws Exception {
|
||||
itemReader.close();
|
||||
}
|
||||
|
||||
public void setFooDao(FooDao fooDao) {
|
||||
this.fooDao = fooDao;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
}
|
||||
|
||||
public void open(ExecutionContext executionContext) {
|
||||
itemReader.open(executionContext);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
itemReader.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package org.springframework.batch.item.database;
|
||||
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.database.support.IbatisKeyCollector;
|
||||
import org.springframework.batch.item.sample.Foo;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.orm.ibatis.SqlMapClientFactoryBean;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.internal.runners.JUnit4ClassRunner;
|
||||
|
||||
import com.ibatis.sqlmap.client.SqlMapClient;
|
||||
|
||||
@SuppressWarnings({"unchecked", "deprecation"})
|
||||
@RunWith(JUnit4ClassRunner.class)
|
||||
public class IbatisItemReaderCommonTests extends AbstractDatabaseItemStreamItemReaderTests {
|
||||
|
||||
protected ItemReader<Foo> getItemReader() throws Exception {
|
||||
SqlMapClientFactoryBean factory = new SqlMapClientFactoryBean();
|
||||
factory.setConfigLocation(new ClassPathResource("ibatis-config.xml", getClass()));
|
||||
factory.setDataSource(getDataSource());
|
||||
factory.afterPropertiesSet();
|
||||
SqlMapClient sqlMapClient = createSqlMapClient();
|
||||
|
||||
IbatisDrivingQueryItemReader reader = new IbatisDrivingQueryItemReader();
|
||||
IbatisKeyCollector<Long> keyGenerator = new IbatisKeyCollector<Long>();
|
||||
keyGenerator.setDrivingQueryId("getAllFooIds");
|
||||
reader.setDetailsQueryId("getFooById");
|
||||
keyGenerator.setRestartQueryId("getAllFooIdsRestart");
|
||||
keyGenerator.setSqlMapClient(sqlMapClient);
|
||||
reader.setSqlMapClient(sqlMapClient);
|
||||
reader.setKeyCollector(keyGenerator);
|
||||
reader.setSaveState(true);
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
private SqlMapClient createSqlMapClient() throws Exception {
|
||||
SqlMapClientFactoryBean factory = new SqlMapClientFactoryBean();
|
||||
factory.setConfigLocation(new ClassPathResource("ibatis-config.xml", getClass()));
|
||||
factory.setDataSource(getDataSource());
|
||||
factory.afterPropertiesSet();
|
||||
return (SqlMapClient) factory.getObject();
|
||||
}
|
||||
|
||||
protected void pointToEmptyInput(ItemReader<Foo> tested) throws Exception {
|
||||
IbatisDrivingQueryItemReader reader = (IbatisDrivingQueryItemReader) tested;
|
||||
reader.close();
|
||||
|
||||
IbatisKeyCollector<Long> keyCollector = new IbatisKeyCollector<Long>();
|
||||
keyCollector.setDrivingQueryId("getNoFoos");
|
||||
keyCollector.setSqlMapClient(createSqlMapClient());
|
||||
|
||||
reader.setKeyCollector(keyCollector);
|
||||
reader.afterPropertiesSet();
|
||||
|
||||
reader.open(new ExecutionContext());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package org.springframework.batch.item.database;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.database.support.IbatisKeyCollector;
|
||||
import org.springframework.batch.item.sample.Foo;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.orm.ibatis.SqlMapClientFactoryBean;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.ibatis.sqlmap.client.SqlMapClient;
|
||||
|
||||
/**
|
||||
* Tests for {@link IbatisDrivingQueryItemReader}
|
||||
*
|
||||
* @author Robert Kasanicky
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = "data-source-context.xml")
|
||||
public class IbatisItemReaderIntegrationTests extends AbstractDataSourceItemReaderIntegrationTests {
|
||||
|
||||
protected ItemReader<Foo> createItemReader() throws Exception {
|
||||
|
||||
SqlMapClientFactoryBean factory = new SqlMapClientFactoryBean();
|
||||
factory.setConfigLocation(new ClassPathResource("ibatis-config.xml", getClass()));
|
||||
factory.setDataSource(dataSource);
|
||||
factory.afterPropertiesSet();
|
||||
SqlMapClient sqlMapClient = (SqlMapClient) factory.getObject();
|
||||
|
||||
IbatisDrivingQueryItemReader inputSource = new IbatisDrivingQueryItemReader();
|
||||
IbatisKeyCollector<Long> keyGenerator = new IbatisKeyCollector<Long>();
|
||||
keyGenerator.setDrivingQueryId("getAllFooIds");
|
||||
inputSource.setDetailsQueryId("getFooById");
|
||||
keyGenerator.setRestartQueryId("getAllFooIdsRestart");
|
||||
keyGenerator.setSqlMapClient(sqlMapClient);
|
||||
inputSource.setSqlMapClient(sqlMapClient);
|
||||
inputSource.setKeyCollector(keyGenerator);
|
||||
inputSource.setSaveState(true);
|
||||
|
||||
return inputSource;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.item.database;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.database.support.MultipleColumnJdbcKeyCollector;
|
||||
import org.springframework.batch.item.sample.Foo;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Lucas Ward
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = "data-source-context.xml")
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MultipleColumnJdbcDrivingQueryItemReaderIntegrationTests extends
|
||||
AbstractJdbcItemReaderIntegrationTests {
|
||||
|
||||
protected ItemReader<Foo> createItemReader() throws Exception {
|
||||
|
||||
MultipleColumnJdbcKeyCollector<Map<?,?>> keyGenerator =
|
||||
new MultipleColumnJdbcKeyCollector<Map<?,?>>(simpleJdbcTemplate.getJdbcOperations(),
|
||||
"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<Map<?,?>> inputSource = new DrivingQueryItemReader<Map<?,?>>();
|
||||
inputSource.setSaveState(true);
|
||||
inputSource.setKeyCollector(keyGenerator);
|
||||
FooItemReader fooItemReader = new FooItemReader(inputSource, dataSource);
|
||||
fooItemReader.setFooDao(new CompositeKeyFooDao(dataSource));
|
||||
return fooItemReader;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package org.springframework.batch.item.database;
|
||||
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.database.support.SingleColumnJdbcKeyCollector;
|
||||
import org.springframework.batch.item.sample.Foo;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.internal.runners.JUnit4ClassRunner;
|
||||
|
||||
@RunWith(JUnit4ClassRunner.class)
|
||||
@SuppressWarnings("deprecation")
|
||||
public class SingleColumnJdbcDrivingQueryItemReaderCommonTests extends AbstractDatabaseItemStreamItemReaderTests {
|
||||
|
||||
protected ItemReader<Foo> getItemReader() throws Exception {
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
|
||||
SingleColumnJdbcKeyCollector<Long> keyCollector = new SingleColumnJdbcKeyCollector<Long>(jdbcTemplate,
|
||||
"SELECT ID from T_FOOS order by ID");
|
||||
keyCollector.setRestartSql("SELECT ID from T_FOOS where ID > ? order by ID");
|
||||
DrivingQueryItemReader<Long> reader = new DrivingQueryItemReader<Long>();
|
||||
reader.setKeyCollector(keyCollector);
|
||||
reader.setSaveState(true);
|
||||
return new FooItemReader(reader, getDataSource());
|
||||
}
|
||||
|
||||
protected void pointToEmptyInput(ItemReader<Foo> tested) throws Exception {
|
||||
FooItemReader fooReader = (FooItemReader) tested;
|
||||
fooReader.close();
|
||||
|
||||
DrivingQueryItemReader<Long> reader = new DrivingQueryItemReader<Long>();
|
||||
reader.close();
|
||||
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
|
||||
SingleColumnJdbcKeyCollector<Long> keyCollector = new SingleColumnJdbcKeyCollector<Long>(jdbcTemplate,
|
||||
"SELECT ID from T_FOOS where ID < 0");
|
||||
|
||||
reader.setKeyCollector(keyCollector);
|
||||
reader.afterPropertiesSet();
|
||||
|
||||
fooReader.setItemReader(reader);
|
||||
fooReader.open(new ExecutionContext());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package org.springframework.batch.item.database;
|
||||
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.database.support.SingleColumnJdbcKeyCollector;
|
||||
import org.springframework.batch.item.sample.Foo;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = "data-source-context.xml")
|
||||
@SuppressWarnings("deprecation")
|
||||
public class SingleColumnJdbcDrivingQueryItemReaderIntegrationTests extends AbstractJdbcItemReaderIntegrationTests {
|
||||
|
||||
protected ItemReader<Long> source;
|
||||
|
||||
/**
|
||||
* @return input source with all necessary dependencies set
|
||||
*/
|
||||
protected ItemReader<Foo> createItemReader() throws Exception {
|
||||
|
||||
SingleColumnJdbcKeyCollector<Long> keyStrategy =
|
||||
new SingleColumnJdbcKeyCollector<Long>(simpleJdbcTemplate.getJdbcOperations(),
|
||||
"SELECT ID from T_FOOS order by ID");
|
||||
keyStrategy.setRestartSql("SELECT ID from T_FOOS where ID > ? order by ID");
|
||||
DrivingQueryItemReader<Long> inputSource = new DrivingQueryItemReader<Long>();
|
||||
inputSource.setKeyCollector(keyStrategy);
|
||||
inputSource.setSaveState(true);
|
||||
return new FooItemReader(inputSource, dataSource);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.springframework.batch.item.database.support;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* @author Lucas Ward
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = "/org/springframework/batch/item/database/data-source-context.xml")
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MultipleColumnJdbcKeyGeneratorIntegrationTests {
|
||||
|
||||
MultipleColumnJdbcKeyCollector<Map<?,?>> keyStrategy;
|
||||
|
||||
ExecutionContext executionContext;
|
||||
|
||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void onSetUpBeforeTransaction() throws Exception {
|
||||
|
||||
keyStrategy = new MultipleColumnJdbcKeyCollector<Map<?,?>>(simpleJdbcTemplate.getJdbcOperations(),
|
||||
"SELECT ID, VALUE from T_FOOS order by ID");
|
||||
|
||||
keyStrategy.setRestartSql("SELECT ID, VALUE from T_FOOS where ID > ? and VALUE > ? order by ID");
|
||||
|
||||
executionContext = new ExecutionContext();
|
||||
}
|
||||
|
||||
@Transactional @Test
|
||||
public void testRetrieveKeys(){
|
||||
|
||||
List<Map<?,?>> keys = keyStrategy.retrieveKeys(executionContext);
|
||||
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
Map<?,?> id = keys.get(i);
|
||||
assertEquals(i + 1L, id.get("ID"));
|
||||
assertEquals(i + 1, id.get("VALUE"));
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional @Test
|
||||
public void testRestoreKeys(){
|
||||
|
||||
Map<String, String> keyMap = new LinkedHashMap<String, String>();
|
||||
keyMap.put("ID", "3");
|
||||
keyMap.put("VALUE", "3");
|
||||
executionContext.put(ClassUtils.getShortName(MultipleColumnJdbcKeyCollector.class)+ ".current.key", keyMap);
|
||||
|
||||
List<Map<?, ?>> keys = keyStrategy.retrieveKeys(executionContext);
|
||||
|
||||
assertEquals(2, keys.size());
|
||||
Map<?,?> key = keys.get(0);
|
||||
assertEquals(4L, key.get("ID"));
|
||||
assertEquals(4, key.get("VALUE"));
|
||||
key = keys.get(1);
|
||||
assertEquals(5L, key.get("ID"));
|
||||
assertEquals(5, key.get("VALUE"));
|
||||
}
|
||||
|
||||
@Transactional @Test
|
||||
public void testGetNullKeyAsStreamContext(){
|
||||
|
||||
try{
|
||||
keyStrategy.updateContext(null, null);
|
||||
fail();
|
||||
}catch(IllegalArgumentException ex){
|
||||
//expected
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package org.springframework.batch.item.database.support;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Lucas Ward
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = "/org/springframework/batch/item/database/data-source-context.xml")
|
||||
@SuppressWarnings("deprecation")
|
||||
public class SingleColumnJdbcKeyGeneratorIntegrationTests {
|
||||
|
||||
SingleColumnJdbcKeyCollector<Long> keyStrategy;
|
||||
|
||||
ExecutionContext executionContext;
|
||||
|
||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void onSetUpBeforeTransaction() throws Exception {
|
||||
|
||||
keyStrategy = new SingleColumnJdbcKeyCollector<Long>(simpleJdbcTemplate.getJdbcOperations(),
|
||||
"SELECT ID from T_FOOS order by ID");
|
||||
|
||||
keyStrategy.setRestartSql("SELECT ID from T_FOOS where ID > ? order by ID");
|
||||
|
||||
executionContext = new ExecutionContext();
|
||||
}
|
||||
|
||||
@Transactional @Test
|
||||
public void testRetrieveKeys(){
|
||||
|
||||
List<Long> keys = keyStrategy.retrieveKeys(new ExecutionContext());
|
||||
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
Long id = keys.get(i);
|
||||
assertEquals(Long.valueOf(i + 1), id);
|
||||
}
|
||||
for (Long key : keys) {
|
||||
System.out.println(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Transactional @Test
|
||||
public void testRestoreKeys(){
|
||||
|
||||
keyStrategy.updateContext(3L, executionContext);
|
||||
|
||||
List<Long> keys = keyStrategy.retrieveKeys(executionContext);
|
||||
|
||||
assertEquals(2, keys.size());
|
||||
assertEquals(Long.valueOf(4), keys.get(0));
|
||||
assertEquals(Long.valueOf(5), keys.get(1));
|
||||
|
||||
for (Long key : keys) {
|
||||
System.out.println(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional @Test
|
||||
public void testGetKeyAsStreamContext(){
|
||||
|
||||
keyStrategy.updateContext(3L, executionContext);
|
||||
|
||||
assertEquals(1, executionContext.size());
|
||||
assertEquals(3L, executionContext.get(ClassUtils.getShortName(SingleColumnJdbcKeyCollector.class) + ".key"));
|
||||
}
|
||||
|
||||
@Transactional @Test
|
||||
public void testGetNullKeyAsStreamContext(){
|
||||
|
||||
try{
|
||||
keyStrategy.updateContext(null, null);
|
||||
fail();
|
||||
}catch(IllegalArgumentException ex){
|
||||
//expected
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional @Test
|
||||
public void testRestoreKeysFromNull(){
|
||||
|
||||
try{
|
||||
keyStrategy.updateContext(null, null);
|
||||
}catch(IllegalArgumentException ex){
|
||||
//expected
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user