/*
* Copyright 2017 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.builder;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.database.JdbcPagingItemReader;
import org.springframework.batch.item.database.Order;
import org.springframework.batch.item.database.support.AbstractSqlPagingQueryProvider;
import org.springframework.batch.item.database.support.HsqlPagingQueryProvider;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Michael Minella
*/
public class JdbcPagingItemReaderBuilderTests {
private DataSource dataSource;
private ConfigurableApplicationContext context;
@Before
public void setUp() {
this.context = new AnnotationConfigApplicationContext(TestDataSourceConfiguration.class);
this.dataSource = (DataSource) context.getBean("dataSource");
}
@After
public void tearDown() {
if(this.context != null) {
this.context.close();
}
}
@Test
public void testBasicConfigurationQueryProvider() throws Exception {
Map<String, Order> sortKeys = new HashMap<>(1);
sortKeys.put("ID", Order.DESCENDING);
AbstractSqlPagingQueryProvider provider = new HsqlPagingQueryProvider();
provider.setSelectClause("SELECT ID, FIRST, SECOND, THIRD");
provider.setFromClause("FOO");
provider.setSortKeys(sortKeys);
JdbcPagingItemReader<Foo> reader = new JdbcPagingItemReaderBuilder<Foo>()
.name("fooReader")
.currentItemCount(1)
.dataSource(this.dataSource)
.queryProvider(provider)
.fetchSize(2)
.maxItemCount(2)
.rowMapper((rs, rowNum) -> new Foo(rs.getInt(1),
rs.getInt(2),
rs.getString(3),
rs.getString(4)))
.build();
reader.afterPropertiesSet();
ExecutionContext executionContext = new ExecutionContext();
reader.open(executionContext);
Foo item1 = reader.read();
assertNull(reader.read());
reader.update(executionContext);
reader.close();
assertEquals(3, item1.getId());
assertEquals(10, item1.getFirst());
assertEquals("11", item1.getSecond());
assertEquals("12", item1.getThird());
assertTrue((int) ReflectionTestUtils.getField(reader, "fetchSize") == 2);
assertEquals(2, executionContext.size());
}
@Test
public void testBasicConfiguration() throws Exception {
Map<String, Order> sortKeys = new HashMap<>(1);
sortKeys.put("ID", Order.DESCENDING);
JdbcPagingItemReader<Foo> reader = new JdbcPagingItemReaderBuilder<Foo>()
.name("fooReader")
.currentItemCount(1)
.dataSource(this.dataSource)
.maxItemCount(2)
.selectClause("SELECT ID, FIRST, SECOND, THIRD")
.fromClause("FOO")
.sortKeys(sortKeys)
.rowMapper((rs, rowNum) -> new Foo(rs.getInt(1),
rs.getInt(2),
rs.getString(3),
rs.getString(4)))
.build();
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
Foo item1 = reader.read();
assertNull(reader.read());
assertEquals(3, item1.getId());
assertEquals(10, item1.getFirst());
assertEquals("11", item1.getSecond());
assertEquals("12", item1.getThird());
}
@Test
public void testPageSize() throws Exception {
Map<String, Order> sortKeys = new HashMap<>(1);
sortKeys.put("ID", Order.DESCENDING);
JdbcPagingItemReader<Foo> reader = new JdbcPagingItemReaderBuilder<Foo>()
.name("fooReader")
.dataSource(this.dataSource)
.pageSize(1)
.maxItemCount(2)
.selectClause("SELECT ID, FIRST, SECOND, THIRD")
.fromClause("FOO")
.sortKeys(sortKeys)
.rowMapper((rs, rowNum) -> new Foo(rs.getInt(1),
rs.getInt(2),
rs.getString(3),
rs.getString(4)))
.build();
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
Foo item1 = reader.read();
Foo item2 = reader.read();
assertNull(reader.read());
assertEquals(4, item1.getId());
assertEquals(13, item1.getFirst());
assertEquals("14", item1.getSecond());
assertEquals("15", item1.getThird());
assertEquals(3, item2.getId());
assertEquals(10, item2.getFirst());
assertEquals("11", item2.getSecond());
assertEquals("12", item2.getThird());
}
@Test
public void testSaveState() throws Exception {
Map<String, Order> sortKeys = new HashMap<>(1);
sortKeys.put("ID", Order.DESCENDING);
JdbcPagingItemReader<Foo> reader = new JdbcPagingItemReaderBuilder<Foo>()
.dataSource(this.dataSource)
.pageSize(1)
.maxItemCount(2)
.selectClause("SELECT ID, FIRST, SECOND, THIRD")
.fromClause("FOO")
.sortKeys(sortKeys)
.saveState(false)
.rowMapper((rs, rowNum) -> new Foo(rs.getInt(1),
rs.getInt(2),
rs.getString(3),
rs.getString(4)))
.build();
reader.afterPropertiesSet();
ExecutionContext executionContext = new ExecutionContext();
reader.open(executionContext);
Foo item1 = reader.read();
Foo item2 = reader.read();
assertNull(reader.read());
reader.update(executionContext);
reader.close();
assertEquals(4, item1.getId());
assertEquals(13, item1.getFirst());
assertEquals("14", item1.getSecond());
assertEquals("15", item1.getThird());
assertEquals(3, item2.getId());
assertEquals(10, item2.getFirst());
assertEquals("11", item2.getSecond());
assertEquals("12", item2.getThird());
assertEquals(0, executionContext.size());
}
@Test
public void testParameters() throws Exception {
Map<String, Order> sortKeys = new HashMap<>(1);
sortKeys.put("ID", Order.DESCENDING);
Map<String, Object> parameterValues = new HashMap<>();
parameterValues.put("min", 1);
parameterValues.put("max", 10);
JdbcPagingItemReader<Foo> reader = new JdbcPagingItemReaderBuilder<Foo>()
.name("fooReader")
.dataSource(this.dataSource)
.pageSize(1)
.maxItemCount(1)
.selectClause("SELECT ID, FIRST, SECOND, THIRD")
.fromClause("FOO")
.whereClause("FIRST > :min AND FIRST < :max")
.sortKeys(sortKeys)
.parameterValues(parameterValues)
.rowMapper((rs, rowNum) -> new Foo(rs.getInt(1),
rs.getInt(2),
rs.getString(3),
rs.getString(4)))
.build();
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
Foo item1 = reader.read();
assertNull(reader.read());
assertEquals(2, item1.getId());
assertEquals(7, item1.getFirst());
assertEquals("8", item1.getSecond());
assertEquals("9", item1.getThird());
}
@Test
public void testValidation() {
try {
new JdbcPagingItemReaderBuilder<Foo>().build();
fail();
}
catch (IllegalArgumentException iae) {
assertEquals("dataSource is required", iae.getMessage());
}
try {
new JdbcPagingItemReaderBuilder<Foo>()
.pageSize(-2)
.build();
fail();
}
catch (IllegalArgumentException iae) {
assertEquals("pageSize must be greater than zero", iae.getMessage());
}
try {
new JdbcPagingItemReaderBuilder<Foo>()
.pageSize(2)
.build();
fail();
}
catch (IllegalArgumentException ise) {
assertEquals("dataSource is required", ise.getMessage());
}
try {
new JdbcPagingItemReaderBuilder<Foo>()
.pageSize(2)
.dataSource(this.dataSource)
.build();
fail();
}
catch (IllegalArgumentException ise) {
assertEquals("A name is required when saveState is set to true", ise.getMessage());
}
try {
new JdbcPagingItemReaderBuilder<Foo>()
.saveState(false)
.pageSize(2)
.dataSource(this.dataSource)
.build();
fail();
}
catch (IllegalArgumentException ise) {
assertEquals("selectClause is required when not providing a PagingQueryProvider", ise.getMessage());
}
try {
new JdbcPagingItemReaderBuilder<Foo>()
.name("fooReader")
.pageSize(2)
.dataSource(this.dataSource)
.selectClause("SELECT *")
.build();
fail();
}
catch (IllegalArgumentException ise) {
assertEquals("fromClause is required when not providing a PagingQueryProvider", ise.getMessage());
}
try {
new JdbcPagingItemReaderBuilder<Foo>()
.saveState(false)
.pageSize(2)
.dataSource(this.dataSource)
.selectClause("SELECT *")
.fromClause("FOO")
.build();
fail();
}
catch (IllegalArgumentException ise) {
assertEquals("sortKeys are required when not providing a PagingQueryProvider", ise.getMessage());
}
}
public static class Foo {
private int id;
private int first;
private String second;
private String third;
public Foo(int id, int first, String second, String third) {
this.id = id;
this.first = first;
this.second = second;
this.third = third;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getFirst() {
return first;
}
public void setFirst(int first) {
this.first = first;
}
public String getSecond() {
return second;
}
public void setSecond(String second) {
this.second = second;
}
public String getThird() {
return third;
}
public void setThird(String third) {
this.third = third;
}
}
@Configuration
public static class TestDataSourceConfiguration {
private static final String CREATE_SQL = "CREATE TABLE FOO (\n" +
"\tID BIGINT IDENTITY NOT NULL PRIMARY KEY ,\n" +
"\tFIRST BIGINT ,\n" +
"\tSECOND VARCHAR(5) NOT NULL,\n" +
"\tTHIRD VARCHAR(5) NOT NULL) ;";
private static final String INSERT_SQL =
"INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (1, '2', '3');" +
"INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (4, '5', '6');" +
"INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (7, '8', '9');" +
"INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (10, '11', '12');" +
"INSERT INTO FOO (FIRST, SECOND, THIRD) VALUES (13, '14', '15');";
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseFactory().getDatabase();
}
@Bean
public DataSourceInitializer initializer(DataSource dataSource) {
DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
dataSourceInitializer.setDataSource(dataSource);
Resource create = new ByteArrayResource(CREATE_SQL.getBytes());
Resource insert = new ByteArrayResource(INSERT_SQL.getBytes());
dataSourceInitializer.setDatabasePopulator(new ResourceDatabasePopulator(create, insert));
return dataSourceInitializer;
}
}
}