SCT-6 Support RDBMS & Map Repositories

* `DefaultTaskConfigurer` returns only one `SimpleTaskRepository` all others have been removed
* `SimpleTaskRepository` can use `JdbcTaskExecutionDao` or a `MapTaskExecutionDao`
* Add `Jdbc` and Map` `TaskRepositoryFactoryBeans` to support the creation of the correct type of `SimpleTaskRepository`
* `TaskDatabaseInitializer` will initialize a database if a datasource is found and if they have not disabled it using the `spring.task.initialize.enable`
* Add tests
* Added Transaction Support
* Re-add the samples to `pom.xml`
* Samples pom skips install and deploy lifecycle targets.
This commit is contained in:
Glenn Renfro
2015-12-01 17:45:57 -05:00
committed by Gunnar Hillert
parent 96fab303ae
commit a9f882f24b
36 changed files with 1738 additions and 153 deletions

View File

@@ -54,7 +54,7 @@ import org.springframework.context.annotation.Import;
* You will also be able to <code>&#064;Autowired</code> some useful stuff into your context:
*
* <ul>
* <li>a {@link TaskRepository} (bean name "taskRepository").</li>
* <li>a {@link TaskRepository} (bean name "taskRepository").
* </ul>
*
* @author Glenn Renfro

View File

@@ -0,0 +1,4 @@
/**
* Annotations for spring cloud task.
*/
package org.springframework.cloud.task.annotation;

View File

@@ -16,27 +16,68 @@
package org.springframework.cloud.task.configuration;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.task.repository.TaskExplorer;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.cloud.task.repository.support.LoggerTaskRepository;
import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao;
import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;
import org.springframework.cloud.task.repository.support.JdbcTaskRepositoryFactoryBean;
import org.springframework.cloud.task.repository.support.MapTaskRepositoryFactoryBean;
import org.springframework.cloud.task.repository.support.SimpleTaskRepository;
/**
* If no {@link TaskConfigurer} is present, then this configuration will be used.
* Default implementation of the TaskConfigurer interface. If no {@link TaskConfigurer}
* implementation is present, then this configuration will be used.
* The following defaults will be used:
*
* <ul>
* <li>{@link LoggerTaskRepository} will be the default {@link TaskRepository}.</li>
* <li>{@link SimpleTaskRepository} is the default {@link TaskRepository} returned.
* If a data source is present then a data will be stored in the database {@link JdbcTaskExecutionDao} else it will
* be stored in a map {@link MapTaskExecutionDao}.
* </ul>
*
*
* @author Glenn Renfro
*/
public class DefaultTaskConfigurer implements TaskConfigurer{
public class DefaultTaskConfigurer implements TaskConfigurer {
private final static Logger logger = LoggerFactory.getLogger(DefaultTaskConfigurer.class);
private DataSource dataSource;
private TaskRepository taskRepository;
public DefaultTaskConfigurer(){
initialize();
}
public DefaultTaskConfigurer(DataSource dataSource) {
this.dataSource = dataSource;
initialize();
}
public TaskRepository getTaskRepository() {
return new LoggerTaskRepository();
return taskRepository;
}
public TaskExplorer getTaskExplorer() {
throw new UnsupportedOperationException("method not implemented");
//TODO if datasource != null use TaskRepositoryFactoryBean from above like initialize method in DefaultBatchConfigurer
}
private void initialize(){
logger.debug("Initializing TaskRepository");
if (dataSource == null) {
MapTaskRepositoryFactoryBean mapTaskRepositoryFactoryBean =
new MapTaskRepositoryFactoryBean();
taskRepository = mapTaskRepositoryFactoryBean.getObject();
}
else {
JdbcTaskRepositoryFactoryBean jdbcTaskRepositoryFactoryBean =
new JdbcTaskRepositoryFactoryBean(dataSource);
taskRepository = jdbcTaskRepositoryFactoryBean.getObject();
}
}
}

View File

@@ -19,13 +19,20 @@ package org.springframework.cloud.task.configuration;
import java.util.Collection;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.cloud.task.repository.support.TaskDatabaseInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.ResourceLoader;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* Base {@code Configuration} class providing common structure for enabling and using
@@ -34,12 +41,25 @@ import org.springframework.context.annotation.Scope;
*
* @author Glenn Renfro
*/
@EnableTransactionManagement
@Configuration
public class SimpleTaskConfiguration {
protected static final Log logger = LogFactory.getLog(SimpleTaskConfiguration.class);
@Autowired
private ApplicationContext context;
@Autowired(required = false)
private Collection<DataSource> dataSources;
@Autowired
private ResourceLoader resourceLoader;
@Value("${spring.class.initialize.enable:true}")
private boolean taskInitializationEnable;
private boolean initialized = false;
private TaskRepository taskRepository;
@@ -56,7 +76,7 @@ public class SimpleTaskConfiguration {
public TaskRepository taskRepository(){
return taskRepository;
}
/**
* Sets up the basic components by extracting them from the {@link TaskConfigurer}, defaulting to some
* sensible values as long as a unique DataSource is available.
@@ -66,6 +86,7 @@ public class SimpleTaskConfiguration {
if (initialized) {
return;
}
logger.debug("Getting Task Configurer");
TaskConfigurer configurer = getConfigurer(context.getBeansOfType(TaskConfigurer.class).values());
taskRepository = configurer.getTaskRepository();
initialized = true;
@@ -73,12 +94,32 @@ public class SimpleTaskConfiguration {
private TaskConfigurer getConfigurer(Collection<TaskConfigurer> configurers) {
if (this.configurer != null) {
logger.debug(String.format("Using %s TaskConfigurer",
configurer.getClass().getName()));
return this.configurer;
}
if (configurers == null || configurers.isEmpty()) {
DefaultTaskConfigurer configurer = new DefaultTaskConfigurer();
this.configurer = configurer;
return configurer;
if (dataSources == null || dataSources.isEmpty()) {
this.configurer = new DefaultTaskConfigurer();
logger.debug(String.format("Using %s TaskConfigurer, with no datasource",
configurer.getClass().getName()));
return this.configurer;
}
else if (dataSources != null && dataSources.size() == 1) {
DataSource dataSource = dataSources.iterator().next();
if(taskInitializationEnable) {
logger.debug("Initializing Task Schema");
TaskDatabaseInitializer.initializeDatabase(dataSource, resourceLoader);
}
this.configurer = new DefaultTaskConfigurer(dataSource);
logger.debug(String.format("Using %s TaskConfigurer, with datasource",
configurer.getClass().getName()));
return this.configurer;
}
else {
throw new IllegalStateException("To use the default TaskConfigurer the context must contain no more than" +
"one DataSource, found " + dataSources.size());
}
}
if (configurers.size() > 1) {
throw new IllegalStateException(
@@ -86,6 +127,9 @@ public class SimpleTaskConfiguration {
+ configurers.size());
}
this.configurer = configurers.iterator().next();
logger.debug(String.format("More than one Task Configurer available. Using"
+ " first in list: %s TaskConfigurer",
configurer.getClass().getName()));
return this.configurer;
}
}

View File

@@ -0,0 +1,4 @@
/**
* Interfaces for configuring Spring Cloud Task and a default implementations.
*/
package org.springframework.cloud.task.configuration;

View File

@@ -0,0 +1,4 @@
/**
* Base package for spring cloud task.
*/
package org.springframework.cloud.task;

View File

@@ -16,9 +16,12 @@
package org.springframework.cloud.task.repository;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.util.Assert;
/**
* Represents the state of the Task for each execution.
*
@@ -26,23 +29,6 @@ import java.util.List;
*/
public class TaskExecution {
public TaskExecution() {
}
public TaskExecution(String executionId, int exitCode, String taskName,
Date startTime, Date endTime, String statusCode,
String exitMessage, List<String> parameters) {
this.executionId = executionId;
this.exitCode = exitCode;
this.taskName = taskName;
this.startTime = startTime;
this.endTime = endTime;
this.statusCode = statusCode;
this.exitMessage = exitMessage;
this.parameters = parameters;
}
/**
* The unique id associated with the task execution.
*/
@@ -83,6 +69,27 @@ public class TaskExecution {
*/
private List<String> parameters;
public TaskExecution() {
parameters = new ArrayList<>();
}
public TaskExecution(String executionId, int exitCode, String taskName,
Date startTime, Date endTime, String statusCode,
String exitMessage, List<String> parameters) {
Assert.hasText(executionId, "executionId must not be null nor empty");
Assert.notNull(parameters, "parameters must not be null");
Assert.notNull(startTime, "startTime must not be null");
this.executionId = executionId;
this.exitCode = exitCode;
this.taskName = taskName;
this.startTime = startTime;
this.endTime = endTime;
this.statusCode = statusCode;
this.exitMessage = exitMessage;
this.parameters = parameters;
}
public String getExecutionId() {
return executionId;
}

View File

@@ -16,6 +16,8 @@
package org.springframework.cloud.task.repository;
import org.springframework.transaction.annotation.Transactional;
/**
* TaskRepository interface offers methods that create and update task execution
* information.
@@ -36,5 +38,6 @@ public interface TaskRepository {
*
* @param taskExecution taskExecution to be recorded
*/
@Transactional
public void createTaskExecution(TaskExecution taskExecution);
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright 2015 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.cloud.task.repository.dao;
import java.sql.Types;
import java.util.Date;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Stores Task Execution Information to a JDBC DataSource.
*
* @author Glenn Renfro
*/
public class JdbcTaskExecutionDao implements TaskExecutionDao {
private static final String SAVE_TASK_EXECUTION = "INSERT into %PREFIX%EXECUTION"
+ "(TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, EXIT_CODE, "
+ "EXIT_MESSAGE, LAST_UPDATED, STATUS_CODE) values (?, ?, ?, ?, ?, ?, ?, ?)";
private static final String CREATE_TASK_PARAMETER = "INSERT into "
+ "%PREFIX%EXECUTION_PARAMS(TASK_EXECUTION_ID, TASK_PARAM ) values (?, ?)";
private static final String CHECK_TASK_EXECUTION_EXISTS = "SELECT COUNT(*) FROM "
+ "%PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = ?";
private static final String UPDATE_TASK_EXECUTION = "UPDATE %PREFIX%EXECUTION set "
+ "START_TIME = ?, END_TIME = ?, TASK_NAME = ?, EXIT_CODE = ?, "
+ "EXIT_MESSAGE = ?, LAST_UPDATED = ?, STATUS_CODE = ? "
+ "where TASK_EXECUTION_ID = ?";
private static final String DEFAULT_TABLE_PREFIX = "TASK_";
private String tablePrefix = DEFAULT_TABLE_PREFIX;
private JdbcOperations jdbcTemplate;
public JdbcTaskExecutionDao(DataSource dataSource) {
Assert.notNull(dataSource);
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
public void saveTaskExecution(TaskExecution taskExecution) {
Object[] parameters = new Object[]{ taskExecution.getExecutionId(),
taskExecution.getStartTime(), taskExecution.getEndTime(),
taskExecution.getTaskName(), taskExecution.getExitCode(),
taskExecution.getExitMessage(), new Date(),
taskExecution.getStatusCode() };
int addCount = jdbcTemplate.update(
getQuery(SAVE_TASK_EXECUTION),
parameters,
new int[]{ Types.VARCHAR, Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR,
Types.INTEGER, Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR });
insertJobParameters(taskExecution.getExecutionId(), taskExecution.getParameters());
}
@Override
public void updateTaskExecution(TaskExecution taskExecution) {
// Check if given TaskExecution's Id already exists, if none is found
// it is invalid and an exception should be thrown.
if (jdbcTemplate.queryForObject(getQuery(CHECK_TASK_EXECUTION_EXISTS), Integer.class,
new Object[]{ taskExecution.getExecutionId() }) != 1) {
throw new IllegalStateException("Invalid TaskExecution, ID " + taskExecution.getExecutionId() + " not found.");
}
Object[] parameters = new Object[]{ taskExecution.getStartTime(), taskExecution.getEndTime(),
taskExecution.getTaskName(), taskExecution.getExitCode(),
taskExecution.getExitMessage(), new Date(), taskExecution.getStatusCode(),
taskExecution.getExecutionId() };
int count = jdbcTemplate.update(
getQuery(UPDATE_TASK_EXECUTION),
parameters,
new int[]{ Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR, Types.INTEGER,
Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR });
}
/**
* Public setter for the table prefix property. This will be prefixed to all
* the table names before queries are executed. Defaults to
* {@link #DEFAULT_TABLE_PREFIX}.
*
* @param tablePrefix the tablePrefix to set
*/
public void setTablePrefix(String tablePrefix) {
this.tablePrefix = tablePrefix;
}
private String getQuery(String base) {
return StringUtils.replace(base, "%PREFIX%", tablePrefix);
}
/**
* Convenience method that inserts all parameters from the provided
* task parameters.
*
* @param executionId The executionId to which the params are associated.
* @param taskParameters The parameters to be stored.
*/
private void insertJobParameters(String executionId, List<String> taskParameters) {
for (String param : taskParameters) {
insertParameter(executionId, param);
}
}
/**
* Convenience method that inserts an individual records into the
* TASK_EXECUTION_PARAMS table.
*/
private void insertParameter(String executionId, String param) {
Object[] args = new Object[0];
int[] argTypes = new int[]{ Types.VARCHAR, Types.VARCHAR };
args = new Object[]{ executionId, param };
jdbcTemplate.update(getQuery(CREATE_TASK_PARAMETER), args, argTypes);
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2015 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.cloud.task.repository.dao;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.springframework.cloud.task.repository.TaskExecution;
/**
* Stores Task Execution Information to a in-memory map.
*
* @author Glenn Renfro
*/
public class MapTaskExecutionDao implements TaskExecutionDao {
private ConcurrentMap<String, TaskExecution> taskExecutions;
public MapTaskExecutionDao() {
taskExecutions = new ConcurrentHashMap<>();
}
@Override
public void saveTaskExecution(TaskExecution taskExecution) {
taskExecutions.put(taskExecution.getExecutionId(), taskExecution);
}
@Override
public void updateTaskExecution(TaskExecution taskExecution) {
taskExecutions.put(taskExecution.getExecutionId(), taskExecution);
}
public Map<String, TaskExecution> getTaskExecutions(){
return Collections.unmodifiableMap(taskExecutions);
}
}

View File

@@ -14,30 +14,28 @@
* limitations under the License.
*/
package org.springframework.cloud.task.repository.support;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package org.springframework.cloud.task.repository.dao;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.cloud.task.repository.TaskRepository;
/**
* {@link TaskRepository} implementation that will log the task execution information.
* Data Access Object for task executions.
*
* @author Glenn Renfro
*/
public class LoggerTaskRepository implements TaskRepository {
private final static Logger logger = LoggerFactory.getLogger(LoggerTaskRepository.class);
public interface TaskExecutionDao {
@Override
public void update(TaskExecution taskExecution) {
logger.info("Updating: " + taskExecution.toString());
}
/**
* Save a new {@link TaskExecution}.
*
* @param taskExecution the taskExecution to be stored.
*/
void saveTaskExecution(TaskExecution taskExecution);
@Override
public void createTaskExecution(TaskExecution taskExecution) {
logger.info("Creating: " + taskExecution.toString());
}
/**
* Update and existing {@link TaskExecution}.
*
* @param taskExecution the taskExecution to be updated.
*/
void updateTaskExecution(TaskExecution taskExecution);
}

View File

@@ -0,0 +1,5 @@
/**
* Interface DAO and default implementations for storing and retrieving data for tasks
* from a repository.
*/
package org.springframework.cloud.task.repository.dao;

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2015 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.cloud.task.repository.support;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.util.StringUtils;
/**
* Enum representing a database type, such as DB2 or oracle. The type also
* contains a product name, which is expected to be the same as the product name
* provided by the database driver's metadata.
*
* @author Glenn Renfro
*/
public enum DatabaseType {
HSQL("HSQL Database Engine"),
ORACLE("Oracle"),
POSTGRES("PostgreSQL");
private static final Map<String, DatabaseType> dbNameMap;
private final String productName;
private DatabaseType(String productName) {
this.productName = productName;
}
static{
dbNameMap = new HashMap<String, DatabaseType>();
for(DatabaseType type: values()){
dbNameMap.put(type.getProductName(), type);
}
}
/**
* Convenience method that pulls a database product name from the DataSource's metadata.
*
* @param dataSource the datasource used to extact metadata.
* @return DatabaseType The database type associated with the datasource.
* @throws MetaDataAccessException thrown if failure occurs on metadata lookup.
*/
public static DatabaseType fromMetaData(DataSource dataSource) throws MetaDataAccessException {
String databaseProductName =
JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName").toString();
if (StringUtils.hasText(databaseProductName) && !databaseProductName.equals("DB2/Linux") && databaseProductName.startsWith("DB2")) {
String databaseProductVersion =
JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductVersion").toString();
if (!databaseProductVersion.startsWith("SQL")) {
databaseProductName = "DB2ZOS";
}
else {
databaseProductName = JdbcUtils.commonDatabaseName(databaseProductName);
}
}
else {
databaseProductName = JdbcUtils.commonDatabaseName(databaseProductName);
}
return fromProductName(databaseProductName);
}
/**
* Static method to obtain a DatabaseType from the provided product name.
*
* @param productName the name of the database.
* @return DatabaseType for given product name.
* @throws IllegalArgumentException if none is found.
*/
public static DatabaseType fromProductName(String productName){
if(!dbNameMap.containsKey(productName)){
throw new IllegalArgumentException("DatabaseType not found for product name: [" +
productName + "]");
}
else{
return dbNameMap.get(productName);
}
}
private String getProductName() {
return productName;
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2015 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.cloud.task.repository.support;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao;
import org.springframework.cloud.task.repository.dao.TaskExecutionDao;
/**
* Automates the creation of a {@link SimpleTaskRepository} which will persist task
* execution data into a database. Requires the user to describe what kind of database
* they are using.
*
* @author Glenn Renfro
*/
public class JdbcTaskRepositoryFactoryBean {
public static final String DEFAULT_TABLE_PREFIX = "TASK_";
private static final Log logger = LogFactory.getLog(JdbcTaskRepositoryFactoryBean.class);
private DataSource dataSource;
private String tablePrefix = DEFAULT_TABLE_PREFIX;
public JdbcTaskRepositoryFactoryBean(){
}
public JdbcTaskRepositoryFactoryBean(DataSource dataSource) {
if(dataSource != null) {
this.dataSource = dataSource;
}
}
/**
* Sets the table prefix for all the batch meta-data tables.
* @param tablePrefix prefix prepended to batch meta-data tables
*/
public void setTablePrefix(String tablePrefix) {
this.tablePrefix = tablePrefix;
}
/**
* Returns the a simpleTaskRepository that utilizes a MapTaskExecutionDao
* @return instance of task repository.
*/
public TaskRepository getObject(){
TaskRepository taskRepository = null;
logger.debug(String.format("Creating SimpleTaskRepository that will use a %s",
JdbcTaskExecutionDao.class.getName()));
taskRepository = new SimpleTaskRepository(createJdbcTaskExecutionDao());
return taskRepository;
}
private TaskExecutionDao createJdbcTaskExecutionDao() {
JdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(dataSource);
dao.setTablePrefix(tablePrefix);
return dao;
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2015 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.cloud.task.repository.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;
/**
* Automates the creation of a {@link SimpleTaskRepository} which will persist task
* execution data into an in memory map. This is meant for development
* purposes and not for production use.
*
* @author Glenn Renfro
*/
public class MapTaskRepositoryFactoryBean {
private static final Log logger = LogFactory.getLog(MapTaskRepositoryFactoryBean.class);
private TaskRepository taskRepository;
public MapTaskRepositoryFactoryBean(){
logger.debug(String.format("Creating SimpleTaskRepository that will use a %s",
MapTaskExecutionDao.class.getName()));
taskRepository = new SimpleTaskRepository(new MapTaskExecutionDao());
}
/**
* Returns the a simpleTaskRepository that utilizes a MapTaskExecutionDao
* @return instance of task repository.
*/
public TaskRepository getObject(){
return taskRepository;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2015 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.cloud.task.repository.support;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.cloud.task.repository.dao.TaskExecutionDao;
import org.springframework.util.Assert;
/**
* Records the task execution information to the log and to TaskExecutionDao provided.
* @author Glenn Renfro
*/
public class SimpleTaskRepository implements TaskRepository {
private final static Logger logger = LoggerFactory.getLogger(SimpleTaskRepository.class);
private TaskExecutionDao taskExecutionDao;
public SimpleTaskRepository(TaskExecutionDao taskExecutionDao){
this.taskExecutionDao = taskExecutionDao;
}
@Override
public void update(TaskExecution taskExecution) {
validateTaskExecution(taskExecution);
taskExecutionDao.updateTaskExecution(taskExecution);
logger.info("Updating: " + taskExecution.toString());
}
@Override
public void createTaskExecution(TaskExecution taskExecution) {
validateTaskExecution(taskExecution);
taskExecutionDao.saveTaskExecution(taskExecution);
logger.info("Creating: " + taskExecution.toString());
}
/**
* Retrieves the taskExecutionDao associated with this repository.
* @return the taskExecutionDao
*/
public TaskExecutionDao getTaskExecutionDao() {
return taskExecutionDao;
}
/**
* Validate TaskExecution. At a minimum a startTime.
*
* @param taskExecution the taskExecution to be evaluagted.
*/
private void validateTaskExecution(TaskExecution taskExecution) {
Assert.notNull(taskExecution, "taskExecution should not be null");
Assert.notNull(taskExecution.getExecutionId(), "taskExecutionId should not be null");
Assert.notNull(taskExecution.getStartTime(), "TaskExecution start time cannot be null.");
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2015 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.cloud.task.repository.support;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.jdbc.support.MetaDataAccessException;
/**
* @author Glenn Renfro
*/
public class TaskDatabaseInitializer {
private static final Log logger = LogFactory.getLog(TaskDatabaseInitializer.class);
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/"
+ "cloud/task/schema-@@platform@@.sql";
/**
* Path to the SQL file to use to initialize the database schema.
*/
private static String schema = DEFAULT_SCHEMA_LOCATION;
public static void initializeDatabase(DataSource dataSource, ResourceLoader resourceLoader) {
if (dataSource != null) {
String platform = getDatabaseType(dataSource);
if ("hsql".equals(platform)) {
platform = "hsqldb";
}
if ("postgres".equals(platform)) {
platform = "postgresql";
}
if ("oracle".equals(platform)) {
platform = "oracle10g";
}
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
String schemaLocation = schema;
schemaLocation = schemaLocation.replace("@@platform@@", platform);
populator.addScript(resourceLoader.getResource(schemaLocation));
populator.setContinueOnError(false);
logger.debug(String.format("Initializing task schema for %s database",
platform));
DatabasePopulatorUtils.execute(populator, dataSource);
}
}
private static String getDatabaseType(DataSource dataSource) {
try {
return DatabaseType.fromMetaData(dataSource).toString().toLowerCase();
}
catch (MetaDataAccessException ex) {
throw new IllegalStateException("Unable to detect database type", ex);
}
}
}

View File

@@ -0,0 +1,4 @@
/**
* Classes used for setting up and supporting a task repositories.
*/
package org.springframework.cloud.task.repository.support;

View File

@@ -0,0 +1,18 @@
CREATE TABLE TASK_EXECUTION (
TASK_EXECUTION_ID VARCHAR(100) NOT NULL PRIMARY KEY ,
START_TIME TIMESTAMP DEFAULT NULL ,
END_TIME TIMESTAMP DEFAULT NULL ,
TASK_NAME VARCHAR(100) ,
EXIT_CODE INTEGER ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP ,
STATUS_CODE VARCHAR(10)
);
CREATE TABLE TASK_EXECUTION_PARAMS (
TASK_EXECUTION_ID VARCHAR(100) NOT NULL ,
TASK_PARAM VARCHAR(250) ,
constraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)
references TASK_EXECUTION(TASK_EXECUTION_ID)
) ;