View Javadoc

1   /*
2    * Copyright 2006-2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.springframework.batch.item.database.support;
17  
18  import static org.springframework.batch.support.DatabaseType.DB2;
19  import static org.springframework.batch.support.DatabaseType.DB2ZOS;
20  import static org.springframework.batch.support.DatabaseType.DERBY;
21  import static org.springframework.batch.support.DatabaseType.H2;
22  import static org.springframework.batch.support.DatabaseType.HSQL;
23  import static org.springframework.batch.support.DatabaseType.MYSQL;
24  import static org.springframework.batch.support.DatabaseType.ORACLE;
25  import static org.springframework.batch.support.DatabaseType.POSTGRES;
26  import static org.springframework.batch.support.DatabaseType.SQLSERVER;
27  import static org.springframework.batch.support.DatabaseType.SYBASE;
28  
29  import java.util.HashMap;
30  import java.util.LinkedHashMap;
31  import java.util.Map;
32  
33  import javax.sql.DataSource;
34  
35  import org.springframework.batch.item.database.Order;
36  import org.springframework.batch.item.database.PagingQueryProvider;
37  import org.springframework.batch.support.DatabaseType;
38  import org.springframework.beans.factory.FactoryBean;
39  import org.springframework.jdbc.support.MetaDataAccessException;
40  import org.springframework.util.Assert;
41  import org.springframework.util.StringUtils;
42  
43  /**
44   * Factory bean for {@link PagingQueryProvider} interface. The database type
45   * will be determined from the data source if not provided explicitly. Valid
46   * types are given by the {@link DatabaseType} enum.
47   * 
48   * @author Dave Syer
49   * @author Michael Minella
50   */
51  @SuppressWarnings("rawtypes")
52  public class SqlPagingQueryProviderFactoryBean implements FactoryBean {
53  
54  	private DataSource dataSource;
55  
56  	private String databaseType;
57  
58  	private String fromClause;
59  
60  	private String whereClause;
61  
62  	private String selectClause;
63  	
64  	private String groupClause;
65  
66  	private Map<String, Order> sortKeys;
67  
68  	private Map<DatabaseType, AbstractSqlPagingQueryProvider> providers = new HashMap<DatabaseType, AbstractSqlPagingQueryProvider>();
69  
70  
71  	{
72  		providers.put(DB2, new Db2PagingQueryProvider());
73  		providers.put(DB2ZOS, new Db2PagingQueryProvider());
74  		providers.put(DERBY,new DerbyPagingQueryProvider());
75  		providers.put(HSQL,new HsqlPagingQueryProvider());
76  		providers.put(H2,new H2PagingQueryProvider());
77  		providers.put(MYSQL,new MySqlPagingQueryProvider());
78  		providers.put(ORACLE,new OraclePagingQueryProvider());
79  		providers.put(POSTGRES,new PostgresPagingQueryProvider());
80  		providers.put(SQLSERVER,new SqlServerPagingQueryProvider());
81  		providers.put(SYBASE,new SybasePagingQueryProvider());
82  	}
83  	
84  	/**
85  	 * @param groupClause SQL GROUP BY clause part of the SQL query string
86  	 */
87  	public void setGroupClause(String groupClause) {
88  		this.groupClause = groupClause;
89  	}
90  
91  	/**
92  	 * @param databaseType the databaseType to set
93  	 */
94  	public void setDatabaseType(String databaseType) {
95  		this.databaseType = databaseType;
96  	}
97  
98  	/**
99  	 * @param dataSource the dataSource to set
100 	 */
101 	public void setDataSource(DataSource dataSource) {
102 		this.dataSource = dataSource;
103 	}
104 
105 	/**
106 	 * @param fromClause the fromClause to set
107 	 */
108 	public void setFromClause(String fromClause) {
109 		this.fromClause = fromClause;
110 	}
111 
112 	/**
113 	 * @param whereClause the whereClause to set
114 	 */
115 	public void setWhereClause(String whereClause) {
116 		this.whereClause = whereClause;
117 	}
118 
119 	/**
120 	 * @param selectClause the selectClause to set
121 	 */
122 	public void setSelectClause(String selectClause) {
123 		this.selectClause = selectClause;
124 	}
125 
126 	/**
127 	 * @param sortKeys the sortKeys to set
128 	 */
129 	public void setSortKeys(Map<String, Order> sortKeys) {
130 		this.sortKeys = sortKeys;
131 	}
132 	
133 	public void setSortKey(String key) {
134 		Assert.doesNotContain(key, ",", "String setter is valid for a single ASC key only");
135 		
136 		Map<String, Order> keys = new LinkedHashMap<String, Order>();
137 		keys.put(key, Order.ASCENDING);
138 		
139 		this.sortKeys = keys;
140 	}
141 
142 	/**
143 	 * Get a {@link PagingQueryProvider} instance using the provided properties
144 	 * and appropriate for the given database type.
145 	 * 
146 	 * @see FactoryBean#getObject()
147 	 */
148     @Override
149 	public Object getObject() throws Exception {
150 
151 		DatabaseType type;
152 		try {
153 			type = databaseType != null ? DatabaseType.valueOf(databaseType.toUpperCase()) : DatabaseType
154 					.fromMetaData(dataSource);
155 		}
156 		catch (MetaDataAccessException e) {
157 			throw new IllegalArgumentException(
158 					"Could not inspect meta data for database type.  You have to supply it explicitly.", e);
159 		}
160 
161 		AbstractSqlPagingQueryProvider provider = providers.get(type);
162 		Assert.state(provider!=null, "Should not happen: missing PagingQueryProvider for DatabaseType="+type);
163 
164 		provider.setFromClause(fromClause);
165 		provider.setWhereClause(whereClause);
166 		provider.setSortKeys(sortKeys);
167 		if (StringUtils.hasText(selectClause)) {
168 			provider.setSelectClause(selectClause);
169 		}
170 		if(StringUtils.hasText(groupClause)) {
171 			provider.setGroupClause(groupClause);
172 		}
173 
174 		provider.init(dataSource);
175 
176 		return provider;
177 
178 	}
179 
180 	/**
181 	 * Always returns {@link PagingQueryProvider}.
182 	 * 
183 	 * @see FactoryBean#getObjectType()
184 	 */
185     @Override
186 	public Class<PagingQueryProvider> getObjectType() {
187 		return PagingQueryProvider.class;
188 	}
189 
190 	/**
191 	 * Always returns true.
192 	 * @see FactoryBean#isSingleton()
193 	 */
194     @Override
195 	public boolean isSingleton() {
196 		return true;
197 	}
198 
199 }