001/* 002 * Copyright 2006-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.springframework.batch.item.database.support; 017 018import static org.springframework.batch.support.DatabaseType.DB2; 019import static org.springframework.batch.support.DatabaseType.DB2VSE; 020import static org.springframework.batch.support.DatabaseType.DB2ZOS; 021import static org.springframework.batch.support.DatabaseType.DB2AS400; 022import static org.springframework.batch.support.DatabaseType.DERBY; 023import static org.springframework.batch.support.DatabaseType.H2; 024import static org.springframework.batch.support.DatabaseType.HSQL; 025import static org.springframework.batch.support.DatabaseType.MYSQL; 026import static org.springframework.batch.support.DatabaseType.ORACLE; 027import static org.springframework.batch.support.DatabaseType.POSTGRES; 028import static org.springframework.batch.support.DatabaseType.SQLITE; 029import static org.springframework.batch.support.DatabaseType.SQLSERVER; 030import static org.springframework.batch.support.DatabaseType.SYBASE; 031 032import java.util.HashMap; 033import java.util.LinkedHashMap; 034import java.util.Map; 035 036import javax.sql.DataSource; 037 038import org.springframework.batch.item.database.Order; 039import org.springframework.batch.item.database.PagingQueryProvider; 040import org.springframework.batch.support.DatabaseType; 041import org.springframework.beans.factory.FactoryBean; 042import org.springframework.jdbc.support.MetaDataAccessException; 043import org.springframework.util.Assert; 044import org.springframework.util.StringUtils; 045 046/** 047 * Factory bean for {@link PagingQueryProvider} interface. The database type 048 * will be determined from the data source if not provided explicitly. Valid 049 * types are given by the {@link DatabaseType} enum. 050 * 051 * @author Dave Syer 052 * @author Michael Minella 053 */ 054public class SqlPagingQueryProviderFactoryBean implements FactoryBean<PagingQueryProvider> { 055 056 private DataSource dataSource; 057 058 private String databaseType; 059 060 private String fromClause; 061 062 private String whereClause; 063 064 private String selectClause; 065 066 private String groupClause; 067 068 private Map<String, Order> sortKeys; 069 070 private Map<DatabaseType, AbstractSqlPagingQueryProvider> providers = new HashMap<DatabaseType, AbstractSqlPagingQueryProvider>(); 071 072 073 { 074 providers.put(DB2, new Db2PagingQueryProvider()); 075 providers.put(DB2VSE, new Db2PagingQueryProvider()); 076 providers.put(DB2ZOS, new Db2PagingQueryProvider()); 077 providers.put(DB2AS400, new Db2PagingQueryProvider()); 078 providers.put(DERBY,new DerbyPagingQueryProvider()); 079 providers.put(HSQL,new HsqlPagingQueryProvider()); 080 providers.put(H2,new H2PagingQueryProvider()); 081 providers.put(MYSQL,new MySqlPagingQueryProvider()); 082 providers.put(ORACLE,new OraclePagingQueryProvider()); 083 providers.put(POSTGRES,new PostgresPagingQueryProvider()); 084 providers.put(SQLITE, new SqlitePagingQueryProvider()); 085 providers.put(SQLSERVER,new SqlServerPagingQueryProvider()); 086 providers.put(SYBASE,new SybasePagingQueryProvider()); 087 } 088 089 /** 090 * @param groupClause SQL GROUP BY clause part of the SQL query string 091 */ 092 public void setGroupClause(String groupClause) { 093 this.groupClause = groupClause; 094 } 095 096 /** 097 * @param databaseType the databaseType to set 098 */ 099 public void setDatabaseType(String databaseType) { 100 this.databaseType = databaseType; 101 } 102 103 /** 104 * @param dataSource the dataSource to set 105 */ 106 public void setDataSource(DataSource dataSource) { 107 this.dataSource = dataSource; 108 } 109 110 /** 111 * @param fromClause the fromClause to set 112 */ 113 public void setFromClause(String fromClause) { 114 this.fromClause = fromClause; 115 } 116 117 /** 118 * @param whereClause the whereClause to set 119 */ 120 public void setWhereClause(String whereClause) { 121 this.whereClause = whereClause; 122 } 123 124 /** 125 * @param selectClause the selectClause to set 126 */ 127 public void setSelectClause(String selectClause) { 128 this.selectClause = selectClause; 129 } 130 131 /** 132 * @param sortKeys the sortKeys to set 133 */ 134 public void setSortKeys(Map<String, Order> sortKeys) { 135 this.sortKeys = sortKeys; 136 } 137 138 public void setSortKey(String key) { 139 Assert.doesNotContain(key, ",", "String setter is valid for a single ASC key only"); 140 141 Map<String, Order> keys = new LinkedHashMap<String, Order>(); 142 keys.put(key, Order.ASCENDING); 143 144 this.sortKeys = keys; 145 } 146 147 /** 148 * Get a {@link PagingQueryProvider} instance using the provided properties 149 * and appropriate for the given database type. 150 * 151 * @see FactoryBean#getObject() 152 */ 153 @Override 154 public PagingQueryProvider getObject() throws Exception { 155 156 DatabaseType type; 157 try { 158 type = databaseType != null ? DatabaseType.valueOf(databaseType.toUpperCase()) : DatabaseType 159 .fromMetaData(dataSource); 160 } 161 catch (MetaDataAccessException e) { 162 throw new IllegalArgumentException( 163 "Could not inspect meta data for database type. You have to supply it explicitly.", e); 164 } 165 166 AbstractSqlPagingQueryProvider provider = providers.get(type); 167 Assert.state(provider!=null, "Should not happen: missing PagingQueryProvider for DatabaseType="+type); 168 169 provider.setFromClause(fromClause); 170 provider.setWhereClause(whereClause); 171 provider.setSortKeys(sortKeys); 172 if (StringUtils.hasText(selectClause)) { 173 provider.setSelectClause(selectClause); 174 } 175 if(StringUtils.hasText(groupClause)) { 176 provider.setGroupClause(groupClause); 177 } 178 179 provider.init(dataSource); 180 181 return provider; 182 183 } 184 185 /** 186 * Always returns {@link PagingQueryProvider}. 187 * 188 * @see FactoryBean#getObjectType() 189 */ 190 @Override 191 public Class<PagingQueryProvider> getObjectType() { 192 return PagingQueryProvider.class; 193 } 194 195 /** 196 * Always returns true. 197 * @see FactoryBean#isSingleton() 198 */ 199 @Override 200 public boolean isSingleton() { 201 return true; 202 } 203 204}