RESOLVED - issue BATCH-986: Provide factory bean for SqlPagingQueryProvider
This commit is contained in:
@@ -25,15 +25,13 @@ import org.springframework.batch.core.repository.dao.JdbcStepExecutionDao;
|
||||
import org.springframework.batch.core.repository.dao.JobExecutionDao;
|
||||
import org.springframework.batch.core.repository.dao.JobInstanceDao;
|
||||
import org.springframework.batch.core.repository.dao.StepExecutionDao;
|
||||
import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
|
||||
import org.springframework.batch.item.database.support.DefaultDataFieldMaxValueIncrementerFactory;
|
||||
import org.springframework.batch.support.DatabaseType;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcOperations;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
|
||||
import org.springframework.jdbc.support.incrementer.AbstractDataFieldMaxValueIncrementer;
|
||||
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link FactoryBean} that automates the creation of a
|
||||
@@ -48,11 +46,14 @@ public class JobExplorerFactoryBean extends AbstractJobExplorerFactoryBean imple
|
||||
|
||||
private SimpleJdbcOperations jdbcTemplate;
|
||||
|
||||
private String databaseType;
|
||||
|
||||
private String tablePrefix = AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX;
|
||||
|
||||
private DataFieldMaxValueIncrementerFactory incrementerFactory;
|
||||
private DataFieldMaxValueIncrementer incrementer = new AbstractDataFieldMaxValueIncrementer() {
|
||||
@Override
|
||||
protected long getNextKey() {
|
||||
throw new IllegalStateException("JobExplorer is read only.");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Public setter for the {@link DataSource}.
|
||||
@@ -62,15 +63,6 @@ public class JobExplorerFactoryBean extends AbstractJobExplorerFactoryBean imple
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database type.
|
||||
* @param dbType as specified by
|
||||
* {@link DefaultDataFieldMaxValueIncrementerFactory}
|
||||
*/
|
||||
public void setDatabaseType(String dbType) {
|
||||
this.databaseType = dbType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the table prefix for all the batch meta-data tables.
|
||||
* @param tablePrefix
|
||||
@@ -79,28 +71,12 @@ public class JobExplorerFactoryBean extends AbstractJobExplorerFactoryBean imple
|
||||
this.tablePrefix = tablePrefix;
|
||||
}
|
||||
|
||||
public void setIncrementerFactory(DataFieldMaxValueIncrementerFactory incrementerFactory) {
|
||||
this.incrementerFactory = incrementerFactory;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
Assert.notNull(dataSource, "DataSource must not be null.");
|
||||
|
||||
jdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||||
|
||||
if (incrementerFactory == null) {
|
||||
incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(dataSource);
|
||||
}
|
||||
|
||||
if (databaseType == null) {
|
||||
databaseType = DatabaseType.fromMetaData(dataSource).name();
|
||||
}
|
||||
|
||||
Assert.isTrue(incrementerFactory.isSupportedIncrementerType(databaseType), "'" + databaseType
|
||||
+ "' is an unsupported database type. The supported database types are "
|
||||
+ StringUtils.arrayToCommaDelimitedString(incrementerFactory.getSupportedIncrementerTypes()));
|
||||
|
||||
}
|
||||
|
||||
private Object getTarget() throws Exception {
|
||||
@@ -111,7 +87,7 @@ public class JobExplorerFactoryBean extends AbstractJobExplorerFactoryBean imple
|
||||
protected JobInstanceDao createJobInstanceDao() throws Exception {
|
||||
JdbcJobInstanceDao dao = new JdbcJobInstanceDao();
|
||||
dao.setJdbcTemplate(jdbcTemplate);
|
||||
dao.setJobIncrementer(incrementerFactory.getIncrementer(databaseType, tablePrefix + "JOB_SEQ"));
|
||||
dao.setJobIncrementer(incrementer);
|
||||
dao.setTablePrefix(tablePrefix);
|
||||
dao.afterPropertiesSet();
|
||||
return dao;
|
||||
@@ -121,8 +97,7 @@ public class JobExplorerFactoryBean extends AbstractJobExplorerFactoryBean imple
|
||||
protected JobExecutionDao createJobExecutionDao() throws Exception {
|
||||
JdbcJobExecutionDao dao = new JdbcJobExecutionDao();
|
||||
dao.setJdbcTemplate(jdbcTemplate);
|
||||
dao.setJobExecutionIncrementer(incrementerFactory.getIncrementer(databaseType, tablePrefix
|
||||
+ "JOB_EXECUTION_SEQ"));
|
||||
dao.setJobExecutionIncrementer(incrementer);
|
||||
dao.setTablePrefix(tablePrefix);
|
||||
dao.afterPropertiesSet();
|
||||
return dao;
|
||||
@@ -131,8 +106,7 @@ public class JobExplorerFactoryBean extends AbstractJobExplorerFactoryBean imple
|
||||
protected StepExecutionDao createStepExecutionDao() throws Exception {
|
||||
JdbcStepExecutionDao dao = new JdbcStepExecutionDao();
|
||||
dao.setJdbcTemplate(jdbcTemplate);
|
||||
dao.setStepExecutionIncrementer(incrementerFactory.getIncrementer(databaseType, tablePrefix
|
||||
+ "STEP_EXECUTION_SEQ"));
|
||||
dao.setStepExecutionIncrementer(incrementer);
|
||||
dao.setTablePrefix(tablePrefix);
|
||||
dao.afterPropertiesSet();
|
||||
return dao;
|
||||
|
||||
@@ -87,7 +87,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
super.afterPropertiesSet();
|
||||
Assert.notNull(jobExecutionIncrementer);
|
||||
Assert.notNull(jobExecutionIncrementer, "The jobExecutionIncrementer must not be null.");
|
||||
}
|
||||
|
||||
public List<JobExecution> findJobExecutions(final JobInstance job) {
|
||||
@@ -271,7 +271,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
private static class JobExecutionRowMapper implements ParameterizedRowMapper<JobExecution> {
|
||||
protected static class JobExecutionRowMapper implements ParameterizedRowMapper<JobExecution> {
|
||||
|
||||
private JobInstance jobInstance;
|
||||
|
||||
|
||||
@@ -18,32 +18,23 @@ package org.springframework.batch.core.exlore.support;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.Assert.fail;
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
|
||||
import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
|
||||
|
||||
/**
|
||||
* @author Lucas Ward
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JobExplorerFactoryBeanTests {
|
||||
|
||||
private JobExplorerFactoryBean factory;
|
||||
|
||||
private DataFieldMaxValueIncrementerFactory incrementerFactory;
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
private String tablePrefix = "TEST_BATCH_PREFIX_";
|
||||
@@ -54,55 +45,10 @@ public class JobExplorerFactoryBeanTests {
|
||||
factory = new JobExplorerFactoryBean();
|
||||
dataSource = createMock(DataSource.class);
|
||||
factory.setDataSource(dataSource);
|
||||
incrementerFactory = createMock(DataFieldMaxValueIncrementerFactory.class);
|
||||
factory.setIncrementerFactory(incrementerFactory);
|
||||
factory.setTablePrefix(tablePrefix);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectDatabaseType() throws Exception {
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(dataSource.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("Oracle");
|
||||
expect(incrementerFactory.isSupportedIncrementerType("ORACLE")).andReturn(true);
|
||||
expect(incrementerFactory.getSupportedIncrementerTypes()).andReturn(new String[0]);
|
||||
expect(incrementerFactory.getIncrementer("ORACLE", tablePrefix + "JOB_SEQ")).andReturn(new StubIncrementer());
|
||||
expect(incrementerFactory.getIncrementer("ORACLE", tablePrefix + "JOB_EXECUTION_SEQ")).andReturn(
|
||||
new StubIncrementer());
|
||||
expect(incrementerFactory.getIncrementer("ORACLE", tablePrefix + "STEP_EXECUTION_SEQ")).andReturn(
|
||||
new StubIncrementer());
|
||||
replay(dataSource, con, dmd, incrementerFactory);
|
||||
factory.afterPropertiesSet();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoDatabaseType() throws Exception {
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(dataSource.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("foo");
|
||||
try {
|
||||
expect(incrementerFactory.isSupportedIncrementerType(null)).andReturn(false);
|
||||
expect(incrementerFactory.getSupportedIncrementerTypes()).andReturn(new String[0]);
|
||||
replay(dataSource, con, dmd, incrementerFactory);
|
||||
factory.afterPropertiesSet();
|
||||
fail();
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
String message = ex.getMessage();
|
||||
assertTrue("Wrong message: " + message, message.indexOf("DatabaseType") >= 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingDataSource() throws Exception {
|
||||
|
||||
@@ -119,60 +65,12 @@ public class JobExplorerFactoryBeanTests {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidDatabaseType() throws Exception {
|
||||
|
||||
factory.setDatabaseType("foo");
|
||||
try {
|
||||
expect(incrementerFactory.isSupportedIncrementerType("foo")).andReturn(false);
|
||||
expect(incrementerFactory.getSupportedIncrementerTypes()).andReturn(new String[0]);
|
||||
replay(incrementerFactory);
|
||||
factory.afterPropertiesSet();
|
||||
fail();
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
String message = ex.getMessage();
|
||||
assertTrue("Wrong message: " + message, message.indexOf("foo") >= 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateExplorer() throws Exception {
|
||||
String databaseType = "foo";
|
||||
factory.setDatabaseType(databaseType);
|
||||
|
||||
expect(incrementerFactory.isSupportedIncrementerType("foo")).andReturn(true);
|
||||
expect(incrementerFactory.getSupportedIncrementerTypes()).andReturn(new String[0]);
|
||||
expect(incrementerFactory.getIncrementer(databaseType, tablePrefix + "JOB_SEQ")).andReturn(
|
||||
new StubIncrementer());
|
||||
expect(incrementerFactory.getIncrementer(databaseType, tablePrefix + "JOB_EXECUTION_SEQ")).andReturn(
|
||||
new StubIncrementer());
|
||||
expect(incrementerFactory.getIncrementer(databaseType, tablePrefix + "STEP_EXECUTION_SEQ")).andReturn(
|
||||
new StubIncrementer());
|
||||
replay(incrementerFactory);
|
||||
|
||||
factory.afterPropertiesSet();
|
||||
factory.getObject();
|
||||
|
||||
verify(incrementerFactory);
|
||||
|
||||
}
|
||||
|
||||
private static class StubIncrementer implements DataFieldMaxValueIncrementer {
|
||||
|
||||
public int nextIntValue() throws DataAccessException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long nextLongValue() throws DataAccessException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String nextStringValue() throws DataAccessException {
|
||||
return null;
|
||||
}
|
||||
JobExplorer explorer = (JobExplorer) factory.getObject();
|
||||
assertNotNull(explorer);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
|
||||
}
|
||||
|
||||
/**
|
||||
* The sort key placegholder will vary depending on whether named parameters or traditional placeholders
|
||||
* The sort key placeholder will vary depending on whether named parameters or traditional placeholders
|
||||
* are used in query strings.
|
||||
*
|
||||
* @return place holder for sortKey.
|
||||
|
||||
@@ -15,7 +15,15 @@
|
||||
*/
|
||||
package org.springframework.batch.item.database.support;
|
||||
|
||||
import static org.springframework.batch.support.DatabaseType.*;
|
||||
import static org.springframework.batch.support.DatabaseType.DB2;
|
||||
import static org.springframework.batch.support.DatabaseType.DB2ZOS;
|
||||
import static org.springframework.batch.support.DatabaseType.DERBY;
|
||||
import static org.springframework.batch.support.DatabaseType.HSQL;
|
||||
import static org.springframework.batch.support.DatabaseType.MYSQL;
|
||||
import static org.springframework.batch.support.DatabaseType.ORACLE;
|
||||
import static org.springframework.batch.support.DatabaseType.POSTGRES;
|
||||
import static org.springframework.batch.support.DatabaseType.SQLSERVER;
|
||||
import static org.springframework.batch.support.DatabaseType.SYBASE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -23,6 +31,7 @@ import java.util.List;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.batch.support.DatabaseType;
|
||||
import org.springframework.jdbc.support.incrementer.DB2MainframeSequenceMaxValueIncrementer;
|
||||
import org.springframework.jdbc.support.incrementer.DB2SequenceMaxValueIncrementer;
|
||||
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
|
||||
import org.springframework.jdbc.support.incrementer.DerbyMaxValueIncrementer;
|
||||
@@ -32,25 +41,10 @@ import org.springframework.jdbc.support.incrementer.OracleSequenceMaxValueIncrem
|
||||
import org.springframework.jdbc.support.incrementer.PostgreSQLSequenceMaxValueIncrementer;
|
||||
import org.springframework.jdbc.support.incrementer.SqlServerMaxValueIncrementer;
|
||||
import org.springframework.jdbc.support.incrementer.SybaseMaxValueIncrementer;
|
||||
import org.springframework.jdbc.support.incrementer.DB2MainframeSequenceMaxValueIncrementer;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link DataFieldMaxValueIncrementerFactory}
|
||||
* interface. Valid types are:
|
||||
*
|
||||
* Valid values are:
|
||||
*
|
||||
* <ul>
|
||||
* <li>db2</li>
|
||||
* <li>db2zos</li>
|
||||
* <li>derby</li>
|
||||
* <li>hsql</li>
|
||||
* <li>mysql</li>
|
||||
* <li>oracle</li>
|
||||
* <li>postgres</li>
|
||||
* <li>sqlserver</li>
|
||||
* <li>sybase</li>
|
||||
* </ul>
|
||||
* interface. Valid database types are given by the {@link DatabaseType} enum.
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @see DatabaseType
|
||||
@@ -64,8 +58,8 @@ public class DefaultDataFieldMaxValueIncrementerFactory implements DataFieldMaxV
|
||||
/**
|
||||
* Public setter for the column name (defaults to "ID") in the incrementer.
|
||||
* Only used by some platforms (Derby, HSQL, MySQL, SQL Server and Sybase),
|
||||
* and should be fine for use with Spring Batch meta data as long as the default
|
||||
* batch schema hasn't been changed.
|
||||
* and should be fine for use with Spring Batch meta data as long as the
|
||||
* default batch schema hasn't been changed.
|
||||
*
|
||||
* @param incrementerColumnName the primary key column name to set
|
||||
*/
|
||||
@@ -79,7 +73,7 @@ public class DefaultDataFieldMaxValueIncrementerFactory implements DataFieldMaxV
|
||||
|
||||
public DataFieldMaxValueIncrementer getIncrementer(String incrementerType, String incrementerName) {
|
||||
DatabaseType databaseType = DatabaseType.valueOf(incrementerType.toUpperCase());
|
||||
|
||||
|
||||
if (databaseType == DB2) {
|
||||
return new DB2SequenceMaxValueIncrementer(dataSource, incrementerName);
|
||||
}
|
||||
@@ -112,20 +106,20 @@ public class DefaultDataFieldMaxValueIncrementerFactory implements DataFieldMaxV
|
||||
}
|
||||
|
||||
public boolean isSupportedIncrementerType(String incrementerType) {
|
||||
for(DatabaseType type : DatabaseType.values()){
|
||||
if(type.name().equals(incrementerType.toUpperCase())){
|
||||
for (DatabaseType type : DatabaseType.values()) {
|
||||
if (type.name().equals(incrementerType.toUpperCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String[] getSupportedIncrementerTypes() {
|
||||
|
||||
|
||||
List<String> types = new ArrayList<String>();
|
||||
|
||||
for(DatabaseType type : DatabaseType.values()){
|
||||
for (DatabaseType type : DatabaseType.values()) {
|
||||
types.add(type.name());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2006-2008 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 static org.springframework.batch.support.DatabaseType.DB2;
|
||||
import static org.springframework.batch.support.DatabaseType.DB2ZOS;
|
||||
import static org.springframework.batch.support.DatabaseType.DERBY;
|
||||
import static org.springframework.batch.support.DatabaseType.HSQL;
|
||||
import static org.springframework.batch.support.DatabaseType.MYSQL;
|
||||
import static org.springframework.batch.support.DatabaseType.ORACLE;
|
||||
import static org.springframework.batch.support.DatabaseType.POSTGRES;
|
||||
import static org.springframework.batch.support.DatabaseType.SQLSERVER;
|
||||
import static org.springframework.batch.support.DatabaseType.SYBASE;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.batch.item.database.PagingQueryProvider;
|
||||
import org.springframework.batch.support.DatabaseType;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Factory bean for {@link PagingQueryProvider} interface. The database type
|
||||
* will be determined from the data source if not provided explicitly. Valid
|
||||
* types are given by the {@link DatabaseType} enum.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class SqlPagingQueryProviderFactoryBean implements FactoryBean {
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
private String databaseType;
|
||||
|
||||
private String fromClause;
|
||||
|
||||
private String whereClause;
|
||||
|
||||
private String selectClause;
|
||||
|
||||
private String sortKey;
|
||||
|
||||
private Map<DatabaseType, AbstractSqlPagingQueryProvider> providers = new HashMap<DatabaseType, AbstractSqlPagingQueryProvider>();
|
||||
{
|
||||
providers.put(DB2, new Db2PagingQueryProvider());
|
||||
providers.put(DB2ZOS, new Db2PagingQueryProvider());
|
||||
providers.put(DERBY,new DerbyPagingQueryProvider());
|
||||
providers.put(HSQL,new HsqlPagingQueryProvider());
|
||||
providers.put(MYSQL,new MySqlPagingQueryProvider());
|
||||
providers.put(ORACLE,new OraclePagingQueryProvider());
|
||||
providers.put(POSTGRES,new PostgresPagingQueryProvider());
|
||||
providers.put(SQLSERVER,new SqlServerPagingQueryProvider());
|
||||
providers.put(SYBASE,new SybasePagingQueryProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param databaseType the databaseType to set
|
||||
*/
|
||||
public void setDatabaseType(String databaseType) {
|
||||
this.databaseType = databaseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dataSource the dataSource to set
|
||||
*/
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fromClause the fromClause to set
|
||||
*/
|
||||
public void setFromClause(String fromClause) {
|
||||
this.fromClause = fromClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param whereClause the whereClause to set
|
||||
*/
|
||||
public void setWhereClause(String whereClause) {
|
||||
this.whereClause = whereClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param selectClause the selectClause to set
|
||||
*/
|
||||
public void setSelectClause(String selectClause) {
|
||||
this.selectClause = selectClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sortKey the sortKey to set
|
||||
*/
|
||||
public void setSortKey(String sortKey) {
|
||||
this.sortKey = sortKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link PagingQueryProvider} instance using the provided properties
|
||||
* and appropriate for the given database type.
|
||||
*
|
||||
* @see FactoryBean#getObject()
|
||||
*/
|
||||
public Object getObject() throws Exception {
|
||||
|
||||
DatabaseType type;
|
||||
try {
|
||||
type = databaseType != null ? DatabaseType.valueOf(databaseType.toUpperCase()) : DatabaseType
|
||||
.fromMetaData(dataSource);
|
||||
}
|
||||
catch (MetaDataAccessException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not inspect meta data for database type. You have to supply it explicitly.");
|
||||
}
|
||||
|
||||
AbstractSqlPagingQueryProvider provider = providers.get(type);
|
||||
Assert.state(provider!=null, "Should not happen: missing PagingQueryProvider for DatabaseType="+type);
|
||||
|
||||
provider.setFromClause(fromClause);
|
||||
provider.setWhereClause(whereClause);
|
||||
provider.setSortKey(sortKey);
|
||||
if (StringUtils.hasText(selectClause)) {
|
||||
provider.setSelectClause(selectClause);
|
||||
}
|
||||
|
||||
provider.init(dataSource);
|
||||
|
||||
return provider;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@link PagingQueryProvider}.
|
||||
*
|
||||
* @see FactoryBean#getObjectType()
|
||||
*/
|
||||
public Class<PagingQueryProvider> getObjectType() {
|
||||
return PagingQueryProvider.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns true.
|
||||
* @see FactoryBean#isSingleton()
|
||||
*/
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public enum DatabaseType {
|
||||
* @return DatabaseType
|
||||
* @throws MetaDataAccessException
|
||||
*/
|
||||
public static DatabaseType fromMetaData(DataSource dataSource) throws MetaDataAccessException{
|
||||
public static DatabaseType fromMetaData(DataSource dataSource) throws MetaDataAccessException {
|
||||
String databaseProductName =
|
||||
JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName").toString();
|
||||
if ("DB2".equals(databaseProductName)) {
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2006-2008 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 static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.item.database.PagingQueryProvider;
|
||||
import org.springframework.batch.support.DatabaseType;
|
||||
import org.springframework.batch.support.DatabaseTypeTestUtils;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class SqlPagingQueryProviderFactoryBeanTests {
|
||||
|
||||
private SqlPagingQueryProviderFactoryBean factory = new SqlPagingQueryProviderFactoryBean();
|
||||
|
||||
public SqlPagingQueryProviderFactoryBeanTests() throws Exception {
|
||||
factory.setSelectClause("id, name, age");
|
||||
factory.setFromClause("foo");
|
||||
factory.setWhereClause("bar = 1");
|
||||
factory.setSortKey("id");
|
||||
DataSource dataSource = DatabaseTypeTestUtils.getMockDataSource(DatabaseType.HSQL.getProductName(), "100.0.0");
|
||||
factory.setDataSource(dataSource);
|
||||
EasyMock.replay(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFactory() throws Exception {
|
||||
PagingQueryProvider provider = (PagingQueryProvider) factory.getObject();
|
||||
assertNotNull(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testType() throws Exception {
|
||||
assertEquals(PagingQueryProvider.class, factory.getObjectType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleton() throws Exception {
|
||||
assertEquals(true, factory.isSingleton());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testNoDataSource() throws Exception {
|
||||
factory.setDataSource(null);
|
||||
PagingQueryProvider provider = (PagingQueryProvider) factory.getObject();
|
||||
assertNotNull(provider);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testNoSortKey() throws Exception {
|
||||
factory.setSortKey(null);
|
||||
PagingQueryProvider provider = (PagingQueryProvider) factory.getObject();
|
||||
assertNotNull(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhereClause() throws Exception {
|
||||
factory.setWhereClause("x=y");
|
||||
PagingQueryProvider provider = (PagingQueryProvider) factory.getObject();
|
||||
String query = provider.generateFirstPageQuery(100);
|
||||
assertTrue("Wrong query: "+query, query.contains("x=y"));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testWrongDatabaseType() throws Exception {
|
||||
factory.setDatabaseType("NoSuchDb");
|
||||
PagingQueryProvider provider = (PagingQueryProvider) factory.getObject();
|
||||
assertNotNull(provider);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testMissingMetaData() throws Exception {
|
||||
factory.setDataSource(DatabaseTypeTestUtils.getMockDataSource(new MetaDataAccessException("foo")));
|
||||
PagingQueryProvider provider = (PagingQueryProvider) factory.getObject();
|
||||
assertNotNull(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllDatabaseTypes() throws Exception {
|
||||
for (DatabaseType type : DatabaseType.values()) {
|
||||
factory.setDatabaseType(type.name());
|
||||
PagingQueryProvider provider = (PagingQueryProvider) factory.getObject();
|
||||
assertNotNull(provider);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import static org.easymock.EasyMock.createNiceMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class DatabaseTypeTestUtils {
|
||||
|
||||
public static DataSource getMockDataSource() throws Exception {
|
||||
return getMockDataSource(DatabaseType.HSQL.getProductName());
|
||||
}
|
||||
|
||||
public static DataSource getMockDataSource(String databaseProductName) throws Exception {
|
||||
return getMockDataSource(databaseProductName, null);
|
||||
}
|
||||
|
||||
public static DataSource getMockDataSource(String databaseProductName, String databaseVersion) throws Exception {
|
||||
DatabaseMetaData dmd = createNiceMock(DatabaseMetaData.class);
|
||||
DataSource ds = createNiceMock(DataSource.class);
|
||||
Connection con = createNiceMock(Connection.class);
|
||||
expect(ds.getConnection()).andReturn(con).anyTimes();
|
||||
expect(con.getMetaData()).andReturn(dmd).anyTimes();
|
||||
expect(dmd.getDatabaseProductName()).andReturn(databaseProductName).anyTimes();
|
||||
if (databaseVersion!=null) {
|
||||
expect(dmd.getDatabaseProductVersion()).andReturn(databaseVersion).anyTimes();
|
||||
}
|
||||
replay(dmd, con);
|
||||
return ds;
|
||||
}
|
||||
|
||||
public static DataSource getMockDataSource(Exception e) throws Exception {
|
||||
DataSource ds = createNiceMock(DataSource.class);
|
||||
expect(ds.getConnection()).andReturn(null).anyTimes();
|
||||
return ds;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +1,33 @@
|
||||
package org.springframework.batch.support;
|
||||
|
||||
import static org.springframework.batch.support.DatabaseType.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.easymock.EasyMock.*;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.batch.support.DatabaseType.DB2;
|
||||
import static org.springframework.batch.support.DatabaseType.DB2ZOS;
|
||||
import static org.springframework.batch.support.DatabaseType.DERBY;
|
||||
import static org.springframework.batch.support.DatabaseType.HSQL;
|
||||
import static org.springframework.batch.support.DatabaseType.MYSQL;
|
||||
import static org.springframework.batch.support.DatabaseType.ORACLE;
|
||||
import static org.springframework.batch.support.DatabaseType.POSTGRES;
|
||||
import static org.springframework.batch.support.DatabaseType.SQLSERVER;
|
||||
import static org.springframework.batch.support.DatabaseType.SYBASE;
|
||||
import static org.springframework.batch.support.DatabaseType.fromProductName;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Lucas Ward
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class DatabaseTypeTests {
|
||||
|
||||
@Test
|
||||
public void testFromProductName(){
|
||||
public void testFromProductName() {
|
||||
assertEquals(DERBY, fromProductName("Apache Derby"));
|
||||
assertEquals(DB2, fromProductName("DB2"));
|
||||
assertEquals(DB2ZOS, fromProductName("DB2ZOS"));
|
||||
@@ -30,157 +38,91 @@ public class DatabaseTypeTests {
|
||||
assertEquals(POSTGRES, fromProductName("PostgreSQL"));
|
||||
assertEquals(SYBASE, fromProductName("Sybase"));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testInvalidProductName(){
|
||||
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testInvalidProductName() {
|
||||
|
||||
fromProductName("bad product name");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFromMetaDataForDerby() throws Exception{
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
DataSource ds = createMock(DataSource.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(ds.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("Apache Derby");
|
||||
replay(dmd,ds,con);
|
||||
|
||||
public void testFromMetaDataForDerby() throws Exception {
|
||||
DataSource ds = DatabaseTypeTestUtils.getMockDataSource("Apache Derby");
|
||||
replay(ds);
|
||||
assertEquals(DERBY, DatabaseType.fromMetaData(ds));
|
||||
|
||||
verify(dmd,ds,con);
|
||||
verify(ds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromMetaDataForDB2() throws Exception{
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
DataSource ds = createMock(DataSource.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(ds.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("DB2/Linux");
|
||||
replay(dmd,ds,con);
|
||||
|
||||
public void testFromMetaDataForDB2() throws Exception {
|
||||
DataSource ds = DatabaseTypeTestUtils.getMockDataSource("DB2/Linux");
|
||||
replay(ds);
|
||||
assertEquals(DB2, DatabaseType.fromMetaData(ds));
|
||||
|
||||
verify(dmd,ds,con);
|
||||
verify(ds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromMetaDataForDB2ZOS() throws Exception{
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
DataSource ds = createMock(DataSource.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(ds.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("DB2");
|
||||
expect(ds.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductVersion()).andReturn("DSN08015");
|
||||
replay(dmd,ds,con);
|
||||
|
||||
public void testFromMetaDataForDB2ZOS() throws Exception {
|
||||
DataSource ds = DatabaseTypeTestUtils.getMockDataSource("DB2", "DSN08015");
|
||||
replay(ds);
|
||||
assertEquals(DB2ZOS, DatabaseType.fromMetaData(ds));
|
||||
|
||||
verify(dmd,ds,con);
|
||||
verify(ds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromMetaDataForHsql() throws Exception{
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
DataSource ds = createMock(DataSource.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(ds.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("HSQL Database Engine");
|
||||
replay(dmd,ds,con);
|
||||
|
||||
public void testFromMetaDataForHsql() throws Exception {
|
||||
DataSource ds = DatabaseTypeTestUtils.getMockDataSource("HSQL Database Engine");
|
||||
replay(ds);
|
||||
assertEquals(HSQL, DatabaseType.fromMetaData(ds));
|
||||
|
||||
verify(dmd,ds,con);
|
||||
verify(ds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromMetaDataForSqlServer() throws Exception{
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
DataSource ds = createMock(DataSource.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(ds.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("Microsoft SQL Server");
|
||||
replay(dmd,ds,con);
|
||||
|
||||
public void testFromMetaDataForSqlServer() throws Exception {
|
||||
DataSource ds = DatabaseTypeTestUtils.getMockDataSource("Microsoft SQL Server");
|
||||
replay(ds);
|
||||
assertEquals(SQLSERVER, DatabaseType.fromMetaData(ds));
|
||||
|
||||
verify(dmd,ds,con);
|
||||
verify(ds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromMetaDataForMySql() throws Exception{
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
DataSource ds = createMock(DataSource.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(ds.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("MySQL");
|
||||
replay(dmd,ds,con);
|
||||
|
||||
public void testFromMetaDataForMySql() throws Exception {
|
||||
DataSource ds = DatabaseTypeTestUtils.getMockDataSource("MySQL");
|
||||
replay(ds);
|
||||
assertEquals(MYSQL, DatabaseType.fromMetaData(ds));
|
||||
|
||||
verify(dmd,ds,con);
|
||||
verify(ds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromMetaDataForOracle() throws Exception{
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
DataSource ds = createMock(DataSource.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(ds.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("Oracle");
|
||||
replay(dmd,ds,con);
|
||||
|
||||
public void testFromMetaDataForOracle() throws Exception {
|
||||
DataSource ds = DatabaseTypeTestUtils.getMockDataSource("Oracle");
|
||||
replay(ds);
|
||||
assertEquals(ORACLE, DatabaseType.fromMetaData(ds));
|
||||
|
||||
verify(dmd,ds,con);
|
||||
verify(ds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromMetaDataForPostgres() throws Exception{
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
DataSource ds = createMock(DataSource.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(ds.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("PostgreSQL");
|
||||
replay(dmd,ds,con);
|
||||
|
||||
public void testFromMetaDataForPostgres() throws Exception {
|
||||
DataSource ds = DatabaseTypeTestUtils.getMockDataSource("PostgreSQL");
|
||||
replay(ds);
|
||||
assertEquals(POSTGRES, DatabaseType.fromMetaData(ds));
|
||||
|
||||
verify(dmd,ds,con);
|
||||
verify(ds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromMetaDataForSybase() throws Exception{
|
||||
|
||||
DatabaseMetaData dmd = createMock(DatabaseMetaData.class);
|
||||
DataSource ds = createMock(DataSource.class);
|
||||
Connection con = createMock(Connection.class);
|
||||
expect(ds.getConnection()).andReturn(con);
|
||||
expect(con.getMetaData()).andReturn(dmd);
|
||||
expect(dmd.getDatabaseProductName()).andReturn("Adaptive Server Enterprise");
|
||||
replay(dmd,ds,con);
|
||||
|
||||
public void testFromMetaDataForSybase() throws Exception {
|
||||
DataSource ds = DatabaseTypeTestUtils.getMockDataSource("Adaptive Server Enterprise");
|
||||
replay(ds);
|
||||
assertEquals(SYBASE, DatabaseType.fromMetaData(ds));
|
||||
|
||||
verify(dmd,ds,con);
|
||||
verify(ds);
|
||||
}
|
||||
|
||||
@Test(expected=MetaDataAccessException.class)
|
||||
public void testBadMetaData() throws Exception {
|
||||
DataSource ds = DatabaseTypeTestUtils.getMockDataSource(new MetaDataAccessException("Bad!"));
|
||||
replay(ds);
|
||||
assertEquals(SYBASE, DatabaseType.fromMetaData(ds));
|
||||
verify(ds);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user