View Javadoc

1   /*
2    * Copyright 2002-2007 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  
17  package org.springframework.batch.core.repository.support;
18  
19  import static org.springframework.batch.support.DatabaseType.SYBASE;
20  
21  import java.sql.Types;
22  
23  import javax.sql.DataSource;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.springframework.batch.core.repository.ExecutionContextSerializer;
28  import org.springframework.batch.core.repository.dao.AbstractJdbcBatchMetadataDao;
29  import org.springframework.batch.core.repository.dao.ExecutionContextDao;
30  import org.springframework.batch.core.repository.dao.JdbcExecutionContextDao;
31  import org.springframework.batch.core.repository.dao.JdbcJobExecutionDao;
32  import org.springframework.batch.core.repository.dao.JdbcJobInstanceDao;
33  import org.springframework.batch.core.repository.dao.JdbcStepExecutionDao;
34  import org.springframework.batch.core.repository.dao.JobExecutionDao;
35  import org.springframework.batch.core.repository.dao.JobInstanceDao;
36  import org.springframework.batch.core.repository.dao.StepExecutionDao;
37  import org.springframework.batch.core.repository.dao.XStreamExecutionContextStringSerializer;
38  import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
39  import org.springframework.batch.item.database.support.DefaultDataFieldMaxValueIncrementerFactory;
40  import org.springframework.batch.support.DatabaseType;
41  import org.springframework.beans.factory.FactoryBean;
42  import org.springframework.beans.factory.InitializingBean;
43  import org.springframework.jdbc.core.JdbcOperations;
44  import org.springframework.jdbc.core.JdbcTemplate;
45  import org.springframework.jdbc.support.lob.LobHandler;
46  import org.springframework.jdbc.support.lob.OracleLobHandler;
47  import org.springframework.util.Assert;
48  import org.springframework.util.StringUtils;
49  
50  /**
51   * A {@link FactoryBean} that automates the creation of a
52   * {@link SimpleJobRepository} using JDBC DAO implementations which persist
53   * batch metadata in database. Requires the user to describe what kind of
54   * database they are using.
55   *
56   * @author Ben Hale
57   * @author Lucas Ward
58   * @author Dave Syer
59   * @author Michael Minella
60   */
61  public class JobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean implements InitializingBean {
62  
63  	protected static final Log logger = LogFactory.getLog(JobRepositoryFactoryBean.class);
64  
65  	private DataSource dataSource;
66  
67  	private JdbcOperations jdbcTemplate;
68  
69  	private String databaseType;
70  
71  	private String tablePrefix = AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX;
72  
73  	private DataFieldMaxValueIncrementerFactory incrementerFactory;
74  
75  	private int maxVarCharLength = AbstractJdbcBatchMetadataDao.DEFAULT_EXIT_MESSAGE_LENGTH;
76  
77  	private LobHandler lobHandler;
78  
79  	private ExecutionContextSerializer serializer;
80  
81  	/**
82  	 * A custom implementation of the {@link ExecutionContextSerializer}.
83  	 * The default, if not injected, is the {@link XStreamExecutionContextStringSerializer}.
84  	 *
85  	 * @param serializer
86  	 * @see ExecutionContextSerializer
87  	 */
88  	public void setSerializer(ExecutionContextSerializer serializer) {
89  		this.serializer = serializer;
90  	}
91  
92  	/**
93  	 * A special handler for large objects. The default is usually fine, except
94  	 * for some (usually older) versions of Oracle. The default is determined
95  	 * from the data base type.
96  	 *
97  	 * @param lobHandler the {@link LobHandler} to set
98  	 *
99  	 * @see LobHandler
100 	 */
101 	public void setLobHandler(LobHandler lobHandler) {
102 		this.lobHandler = lobHandler;
103 	}
104 
105 	/**
106 	 * Public setter for the length of long string columns in database. Do not
107 	 * set this if you haven't modified the schema. Note this value will be used
108 	 * for the exit message in both {@link JdbcJobExecutionDao} and
109 	 * {@link JdbcStepExecutionDao} and also the short version of the execution
110 	 * context in {@link JdbcExecutionContextDao} . For databases with
111 	 * multi-byte character sets this number can be smaller (by up to a factor
112 	 * of 2 for 2-byte characters) than the declaration of the column length in
113 	 * the DDL for the tables.
114 	 *
115 	 * @param maxVarCharLength the exitMessageLength to set
116 	 */
117 	public void setMaxVarCharLength(int maxVarCharLength) {
118 		this.maxVarCharLength = maxVarCharLength;
119 	}
120 
121 	/**
122 	 * Public setter for the {@link DataSource}.
123 	 * @param dataSource a {@link DataSource}
124 	 */
125 	public void setDataSource(DataSource dataSource) {
126 		this.dataSource = dataSource;
127 	}
128 
129 	/**
130 	 * Sets the database type.
131 	 * @param dbType as specified by
132 	 * {@link DefaultDataFieldMaxValueIncrementerFactory}
133 	 */
134 	public void setDatabaseType(String dbType) {
135 		this.databaseType = dbType;
136 	}
137 
138 	/**
139 	 * Sets the table prefix for all the batch meta-data tables.
140 	 * @param tablePrefix
141 	 */
142 	public void setTablePrefix(String tablePrefix) {
143 		this.tablePrefix = tablePrefix;
144 	}
145 
146 	public void setIncrementerFactory(DataFieldMaxValueIncrementerFactory incrementerFactory) {
147 		this.incrementerFactory = incrementerFactory;
148 	}
149 
150 	@Override
151 	public void afterPropertiesSet() throws Exception {
152 
153 		Assert.notNull(dataSource, "DataSource must not be null.");
154 
155 		jdbcTemplate = new JdbcTemplate(dataSource);
156 
157 		if (incrementerFactory == null) {
158 			incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(dataSource);
159 		}
160 
161 		if (databaseType == null) {
162 			databaseType = DatabaseType.fromMetaData(dataSource).name();
163 			logger.info("No database type set, using meta data indicating: " + databaseType);
164 		}
165 
166 		if (lobHandler == null && databaseType.equalsIgnoreCase(DatabaseType.ORACLE.toString())) {
167 			lobHandler = new OracleLobHandler();
168 		}
169 
170 		if(serializer == null) {
171 			XStreamExecutionContextStringSerializer defaultSerializer = new XStreamExecutionContextStringSerializer();
172 			defaultSerializer.afterPropertiesSet();
173 
174 			serializer = defaultSerializer;
175 		}
176 
177 		Assert.isTrue(incrementerFactory.isSupportedIncrementerType(databaseType), "'" + databaseType
178 				+ "' is an unsupported database type.  The supported database types are "
179 				+ StringUtils.arrayToCommaDelimitedString(incrementerFactory.getSupportedIncrementerTypes()));
180 
181 		super.afterPropertiesSet();
182 	}
183 
184 	@Override
185 	protected JobInstanceDao createJobInstanceDao() throws Exception {
186 		JdbcJobInstanceDao dao = new JdbcJobInstanceDao();
187 		dao.setJdbcTemplate(jdbcTemplate);
188 		dao.setJobIncrementer(incrementerFactory.getIncrementer(databaseType, tablePrefix + "JOB_SEQ"));
189 		dao.setTablePrefix(tablePrefix);
190 		dao.afterPropertiesSet();
191 		return dao;
192 	}
193 
194 	@Override
195 	protected JobExecutionDao createJobExecutionDao() throws Exception {
196 		JdbcJobExecutionDao dao = new JdbcJobExecutionDao();
197 		dao.setJdbcTemplate(jdbcTemplate);
198 		dao.setJobExecutionIncrementer(incrementerFactory.getIncrementer(databaseType, tablePrefix
199 				+ "JOB_EXECUTION_SEQ"));
200 		dao.setTablePrefix(tablePrefix);
201 		dao.setClobTypeToUse(determineClobTypeToUse(this.databaseType));
202 		dao.setExitMessageLength(maxVarCharLength);
203 		dao.afterPropertiesSet();
204 		return dao;
205 	}
206 
207 	@Override
208 	protected StepExecutionDao createStepExecutionDao() throws Exception {
209 		JdbcStepExecutionDao dao = new JdbcStepExecutionDao();
210 		dao.setJdbcTemplate(jdbcTemplate);
211 		dao.setStepExecutionIncrementer(incrementerFactory.getIncrementer(databaseType, tablePrefix
212 				+ "STEP_EXECUTION_SEQ"));
213 		dao.setTablePrefix(tablePrefix);
214 		dao.setClobTypeToUse(determineClobTypeToUse(this.databaseType));
215 		dao.setExitMessageLength(maxVarCharLength);
216 		dao.afterPropertiesSet();
217 		return dao;
218 	}
219 
220 	@Override
221 	protected ExecutionContextDao createExecutionContextDao() throws Exception {
222 		JdbcExecutionContextDao dao = new JdbcExecutionContextDao();
223 		dao.setJdbcTemplate(jdbcTemplate);
224 		dao.setTablePrefix(tablePrefix);
225 		dao.setClobTypeToUse(determineClobTypeToUse(this.databaseType));
226 		dao.setSerializer(serializer);
227 
228 		if (lobHandler != null) {
229 			dao.setLobHandler(lobHandler);
230 		}
231 
232 		dao.afterPropertiesSet();
233 		// Assume the same length.
234 		dao.setShortContextLength(maxVarCharLength);
235 		return dao;
236 	}
237 
238 	private int determineClobTypeToUse(String databaseType) {
239 		if (SYBASE == DatabaseType.valueOf(databaseType.toUpperCase())) {
240 			return Types.LONGVARCHAR;
241 		}
242 		else {
243 			return Types.CLOB;
244 		}
245 	}
246 
247 }