Merge pull request #204 from mminella/BATCH-2007

This commit is contained in:
Michael Minella
2013-08-04 11:59:18 -05:00
63 changed files with 2056 additions and 289 deletions

View File

@@ -41,7 +41,7 @@ public class StepExecutionSerializationUtilsTests {
@Test
public void testCycle() throws Exception {
StepExecution stepExecution = new StepExecution("step", new JobExecution(new JobInstance(123L,
"job"), 321L, new JobParameters()), 11L);
"job"), 321L, new JobParameters(), null), 11L);
stepExecution.getExecutionContext().put("foo.bar.spam", 123);
StepExecution result = getCopy(stepExecution);
assertEquals(stepExecution, result);
@@ -58,9 +58,10 @@ public class StepExecutionSerializationUtilsTests {
CompletionService<StepExecution> completionService = new ExecutorCompletionService<StepExecution>(executor);
for (int i = 0; i < repeats; i++) {
final JobExecution jobExecution = new JobExecution(new JobInstance(123L, "job"), 321L, new JobParameters());
final JobExecution jobExecution = new JobExecution(new JobInstance(123L, "job"), 321L, new JobParameters(), null);
for (int j = 0; j < threads; j++) {
completionService.submit(new Callable<StepExecution>() {
@Override
public StepExecution call() throws Exception {
final StepExecution stepExecution = jobExecution.createStepExecution("step");
stepExecution.getExecutionContext().put("foo.bar.spam", 123);

View File

@@ -62,16 +62,27 @@ public class JobExecution extends Entity {
private transient volatile List<Throwable> failureExceptions = new CopyOnWriteArrayList<Throwable>();
private final String jobConfigurationName;
/**
* Because a JobExecution isn't valid unless the job is set, this
* constructor is the only valid one from a modeling point of view.
*
* @param job the job of which this execution is a part
*/
public JobExecution(JobInstance job, Long id, JobParameters jobParameters) {
public JobExecution(JobInstance job, Long id, JobParameters jobParameters, String jobConfigurationName) {
super(id);
this.jobInstance = job;
this.jobParameters = jobParameters == null ? new JobParameters() : jobParameters;
this.jobConfigurationName = jobConfigurationName;
}
public JobExecution(JobInstance job, JobParameters jobParameters, String jobConfigurationName) {
this(job, null, jobParameters, jobConfigurationName);
}
public JobExecution(Long id, JobParameters jobParameters, String jobConfigurationName) {
this(null, id, jobParameters, jobConfigurationName);
}
/**
@@ -80,15 +91,15 @@ public class JobExecution extends Entity {
* @param job the enclosing {@link JobInstance}
*/
public JobExecution(JobInstance job, JobParameters jobParameters) {
this(job, null, jobParameters);
this(job, null, jobParameters, null);
}
public JobExecution(Long id, JobParameters jobParameters) {
this(null, id, jobParameters);
this(null, id, jobParameters, null);
}
public JobExecution(Long id) {
this(null, id, null);
this(null, id, null, null);
}
public JobParameters getJobParameters() {
@@ -256,6 +267,10 @@ public class JobExecution extends Entity {
this.createTime = createTime;
}
public String getJobConfigurationName() {
return this.jobConfigurationName;
}
/**
* Package private method for re-constituting the step executions from
* existing instances.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2013 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.
@@ -21,15 +21,17 @@ import java.util.Set;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.item.ExecutionContext;
/**
* Entry point for browsing executions of running or historical jobs and steps.
* Since the data may be re-hydrated from persistent storage, it may not contain
* volatile fields that would have been present when the execution was active.
*
*
* @author Dave Syer
*
* @author Michael Minella
*
* @since 2.0
*/
public interface JobExplorer {
@@ -37,7 +39,7 @@ public interface JobExplorer {
/**
* Fetch {@link JobInstance} values in descending order of creation (and
* therefore usually of first execution).
*
*
* @param jobName the name of the job to query
* @param start the start index of the instances to return
* @param count the maximum number of instances to return
@@ -51,7 +53,7 @@ public interface JobExplorer {
* the parent {@link JobInstance} and associated {@link ExecutionContext}
* and {@link StepExecution} instances (also including their execution
* contexts).
*
*
* @param executionId the job execution id
* @return the {@link JobExecution} with this id, or null if not found
*/
@@ -62,11 +64,11 @@ public interface JobExplorer {
* {@link JobExecution} id. The execution context for the step should be
* available in the result, and the parent job execution should have its
* primitive properties, but may not contain the job instance information.
*
*
* @param jobExecutionId the parent job execution id
* @param stepExecutionId the step execution id
* @return the {@link StepExecution} with this id, or null if not found
*
*
* @see #getJobExecution(Long)
*/
StepExecution getStepExecution(Long jobExecutionId, Long stepExecutionId);
@@ -82,7 +84,7 @@ public interface JobExplorer {
* executions may not be fully hydrated (e.g. their execution context may be
* missing), depending on the implementation. Use
* {@link #getStepExecution(Long, Long)} to hydrate them in that case.
*
*
* @param jobInstance the {@link JobInstance} to query
* @return the set of all executions for the specified {@link JobInstance}
*/
@@ -93,7 +95,7 @@ public interface JobExplorer {
* not be fully hydrated (e.g. their execution context may be missing),
* depending on the implementation. Use
* {@link #getStepExecution(Long, Long)} to hydrate them in that case.
*
*
* @param jobName the name of the job
* @return the set of running executions for jobs with the specified name
*/
@@ -102,9 +104,20 @@ public interface JobExplorer {
/**
* Query the repository for all unique {@link JobInstance} names (sorted
* alphabetically).
*
*
* @return the set of job names that have been executed
*/
List<String> getJobNames();
/**
* Query the repository for the number of unique {@link JobInstance}s
* associated with the supplied job name.
*
* @param jobName the name of the job to query for
* @return the number of {@link JobInstance}s that exist within the
* associated job repository
* @throws NoSuchJobException
*/
int getJobInstanceCount(String jobName) throws NoSuchJobException;
}

View File

@@ -23,6 +23,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.repository.dao.ExecutionContextDao;
import org.springframework.batch.core.repository.dao.JobExecutionDao;
import org.springframework.batch.core.repository.dao.JobInstanceDao;
@@ -33,6 +34,7 @@ import org.springframework.batch.core.repository.dao.StepExecutionDao;
*
* @author Dave Syer
* @author Lucas Ward
* @author Michael Minella
*
* @see JobExplorer
* @see JobInstanceDao
@@ -180,6 +182,14 @@ public class SimpleJobExplorer implements JobExplorer {
return jobInstanceDao.getJobNames();
}
/* (non-Javadoc)
* @see org.springframework.batch.core.explore.JobExplorer#getJobInstanceCount(java.lang.String)
*/
@Override
public int getJobInstanceCount(String jobName) throws NoSuchJobException {
return jobInstanceDao.getJobInstanceCount(jobName);
}
/*
* Find all dependencies for a JobExecution, including JobInstance (which
* requires JobParameters) plus StepExecutions
@@ -198,5 +208,4 @@ public class SimpleJobExplorer implements JobExplorer {
stepExecution.setExecutionContext(ecDao.getExecutionContext(stepExecution));
}
}
}

View File

@@ -21,6 +21,7 @@ import javax.batch.runtime.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.util.Assert;
/**
@@ -35,56 +36,86 @@ public class JobContext implements javax.batch.runtime.context.JobContext {
private JobExecution jobExecution;
private Object transientUserData;
private JobParametersConverter jobParametersConverter;
/**
* @param jobExecution for the related job
*/
public JobContext(JobExecution jobExecution) {
public JobContext(JobExecution jobExecution, JobParametersConverter jobParametersConverter) {
Assert.notNull(jobExecution, "A JobExecution is required");
Assert.notNull(jobParametersConverter, "A ParametersConverter is required");
this.jobExecution = jobExecution;
this.jobParametersConverter = jobParametersConverter;
}
/* (non-Javadoc)
* @see javax.batch.runtime.context.JobContext#getJobName()
*/
@Override
public String getJobName() {
return jobExecution.getJobInstance().getJobName();
}
/* (non-Javadoc)
* @see javax.batch.runtime.context.JobContext#getTransientUserData()
*/
@Override
public Object getTransientUserData() {
return transientUserData;
}
/* (non-Javadoc)
* @see javax.batch.runtime.context.JobContext#setTransientUserData(java.lang.Object)
*/
@Override
public void setTransientUserData(Object data) {
transientUserData = data;
}
/* (non-Javadoc)
* @see javax.batch.runtime.context.JobContext#getInstanceId()
*/
@Override
public long getInstanceId() {
return jobExecution.getJobInstance().getId();
}
/* (non-Javadoc)
* @see javax.batch.runtime.context.JobContext#getExecutionId()
*/
@Override
public long getExecutionId() {
return jobExecution.getId();
}
/* (non-Javadoc)
* @see javax.batch.runtime.context.JobContext#getProperties()
*/
@Override
public Properties getProperties() {
return jobExecution.getJobParameters().toProperties();
return jobParametersConverter.getProperties(this.jobExecution.getJobParameters());
}
/* (non-Javadoc)
* @see javax.batch.runtime.context.JobContext#getBatchStatus()
*/
@Override
public BatchStatus getBatchStatus() {
return jobExecution.getStatus().getBatchStatus();
}
/* (non-Javadoc)
* @see javax.batch.runtime.context.JobContext#getExitStatus()
*/
@Override
public String getExitStatus() {
return jobExecution.getExitStatus().getExitCode();
}
/* (non-Javadoc)
* @see javax.batch.runtime.context.JobContext#setExitStatus(java.lang.String)
*/
@Override
public void setExitStatus(String status) {
jobExecution.setExitStatus(new ExitStatus(status));

View File

@@ -20,6 +20,7 @@ import java.util.Properties;
import javax.batch.runtime.BatchStatus;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.util.Assert;
/**
@@ -32,57 +33,87 @@ import org.springframework.util.Assert;
public class JobExecution implements javax.batch.runtime.JobExecution {
private org.springframework.batch.core.JobExecution execution;
private JobParametersConverter parametersConverter;
/**
* @param execution for all information to be delegated from
*/
public JobExecution(org.springframework.batch.core.JobExecution execution) {
public JobExecution(org.springframework.batch.core.JobExecution execution, JobParametersConverter parametersConverter) {
Assert.notNull(execution, "A JobExecution is required");
this.execution = execution;
this.parametersConverter = parametersConverter;
}
/* (non-Javadoc)
* @see javax.batch.runtime.JobExecution#getExecutionId()
*/
@Override
public long getExecutionId() {
return this.execution.getId();
}
/* (non-Javadoc)
* @see javax.batch.runtime.JobExecution#getJobName()
*/
@Override
public String getJobName() {
return this.execution.getJobInstance().getJobName();
}
/* (non-Javadoc)
* @see javax.batch.runtime.JobExecution#getBatchStatus()
*/
@Override
public BatchStatus getBatchStatus() {
return this.execution.getStatus().getBatchStatus();
}
/* (non-Javadoc)
* @see javax.batch.runtime.JobExecution#getStartTime()
*/
@Override
public Date getStartTime() {
return this.execution.getStartTime();
}
/* (non-Javadoc)
* @see javax.batch.runtime.JobExecution#getEndTime()
*/
@Override
public Date getEndTime() {
return this.execution.getEndTime();
}
/* (non-Javadoc)
* @see javax.batch.runtime.JobExecution#getExitStatus()
*/
@Override
public String getExitStatus() {
return this.execution.getExitStatus().getExitCode();
}
/* (non-Javadoc)
* @see javax.batch.runtime.JobExecution#getCreateTime()
*/
@Override
public Date getCreateTime() {
return this.execution.getCreateTime();
}
/* (non-Javadoc)
* @see javax.batch.runtime.JobExecution#getLastUpdatedTime()
*/
@Override
public Date getLastUpdatedTime() {
return this.execution.getLastUpdated();
}
/* (non-Javadoc)
* @see javax.batch.runtime.JobExecution#getJobParameters()
*/
@Override
public Properties getJobParameters() {
return this.execution.getJobParameters().toProperties();
return parametersConverter.getProperties(this.execution.getJobParameters());
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright 2013 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.core.jsr;
import java.util.Map;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.AbstractJdbcBatchMetadataDao;
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.InitializingBean;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
import org.springframework.util.Assert;
/**
* Provides default conversion methodology for JSR-352's implementation.
*
* Since Spring Batch uses job parameters as a way of identifying a job
* instance, this converter will add an additional identifying parameter if
* it does not exist already in the list. The id for the identifying parameter
* will come from the JOB_SEQ sequence as used to generate the unique ids
* for BATCH_JOB_INSTANCE records.
*
* @author Michael Minella
* @since 3.0
*/
public class JsrJobParametersConverter implements JobParametersConverter, InitializingBean {
public static final String JOB_RUN_ID = "jsr_batch_run_id";
public DataFieldMaxValueIncrementer incremeter;
public String tablePrefix = AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX;
public DataSource dataSource;
/**
* Main constructor.
*
* @param dataSource used to gain access to the database to get unique ids.
*/
public JsrJobParametersConverter(DataSource dataSource) {
Assert.notNull(dataSource, "A DataSource is required");
this.dataSource = dataSource;
}
/**
* The table prefix used in the current {@link JobRepository}
*
* @param tablePrefix the table prefix used for the job repository tables
*/
public void setTablePrefix(String tablePrefix) {
this.tablePrefix = tablePrefix;
}
@Override
public void afterPropertiesSet() throws Exception {
DataFieldMaxValueIncrementerFactory factory = new DefaultDataFieldMaxValueIncrementerFactory(dataSource);
this.incremeter = factory.getIncrementer(DatabaseType.fromMetaData(dataSource).name(), tablePrefix + "JOB_SEQ");
}
/* (non-Javadoc)
* @see org.springframework.batch.core.converter.JobParametersConverter#getJobParameters(java.util.Properties)
*/
@Override
public JobParameters getJobParameters(Properties properties) {
JobParametersBuilder builder = new JobParametersBuilder();
boolean runIdFound = false;
if(properties != null) {
for (Map.Entry<Object, Object> curParameter : properties.entrySet()) {
if(curParameter.getValue() != null) {
if(curParameter.getKey().equals(JOB_RUN_ID)) {
runIdFound = true;
builder.addLong(curParameter.getKey().toString(), Long.valueOf((String) curParameter.getValue()), true);
} else {
builder.addString(curParameter.getKey().toString(), curParameter.getValue().toString(), false);
}
}
}
}
if(!runIdFound) {
builder.addLong(JOB_RUN_ID, incremeter.nextLongValue());
}
return builder.toJobParameters();
}
/* (non-Javadoc)
* @see org.springframework.batch.core.converter.JobParametersConverter#getProperties(org.springframework.batch.core.JobParameters)
*/
@Override
public Properties getProperties(JobParameters params) {
Properties properties = new Properties();
boolean runIdFound = false;
if(params != null) {
for(Map.Entry<String, JobParameter> curParameter: params.getParameters().entrySet()) {
if(curParameter.getKey().equals(JOB_RUN_ID)) {
runIdFound = true;
}
properties.setProperty(curParameter.getKey(), curParameter.getValue().getValue().toString());
}
}
if(!runIdFound) {
properties.setProperty(JOB_RUN_ID, String.valueOf(incremeter.nextLongValue()));
}
return properties;
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2013 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.core.jsr;
import javax.batch.runtime.Metric;
import org.springframework.util.Assert;
/**
* Simple implementation of the {@link Metric} interface as required by JSR-352.
*
* @author Michael Minella
* @since 3.0
*/
public class SimpleMetric implements Metric {
private final MetricType type;
private final long value;
/**
* Basic constructor. The attributes are immutable so this class is
* threadsafe.
*
* @param type as defined by JSR-352
* @param value the count of the times the related type has occured.
*/
public SimpleMetric(MetricType type, long value) {
Assert.notNull(type, "A MetricType is required");
this.type = type;
this.value = value;
}
/* (non-Javadoc)
* @see javax.batch.runtime.Metric#getType()
*/
@Override
public MetricType getType() {
return type;
}
/* (non-Javadoc)
* @see javax.batch.runtime.Metric#getValue()
*/
@Override
public long getValue() {
return value;
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright 2013 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.core.jsr;
import java.io.Serializable;
import java.util.Properties;
import javax.batch.runtime.BatchStatus;
import javax.batch.runtime.Metric;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.util.Assert;
public class StepContext implements javax.batch.runtime.context.StepContext {
private StepExecution stepExecution;
private Object transientUserData;
private JobParametersConverter jobParametersConveter;
public StepContext(StepExecution stepExecution, JobParametersConverter jobParametersConveter) {
Assert.notNull(stepExecution, "A StepExecution is required");
Assert.notNull(jobParametersConveter, "A ParametersConverter is required");
this.stepExecution = stepExecution;
this.jobParametersConveter = jobParametersConveter;
}
@Override
public String getStepName() {
return stepExecution.getStepName();
}
@Override
public Object getTransientUserData() {
return transientUserData;
}
@Override
public void setTransientUserData(Object data) {
this.transientUserData = data;
}
@Override
public long getStepExecutionId() {
return stepExecution.getId();
}
@Override
public Properties getProperties() {
return jobParametersConveter.getProperties(this.stepExecution.getJobParameters());
}
@Override
public Serializable getPersistentUserData() {
return null;
}
@Override
public void setPersistentUserData(Serializable data) {
}
@Override
public BatchStatus getBatchStatus() {
return stepExecution.getStatus().getBatchStatus();
}
@Override
public String getExitStatus() {
return stepExecution.getExitStatus().getExitCode();
}
@Override
public void setExitStatus(String status) {
stepExecution.setExitStatus(new ExitStatus(status));
}
@Override
public Exception getException() {
return null;
}
@Override
public Metric[] getMetrics() {
Metric[] metrics = new Metric[8];
metrics[0] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.COMMIT_COUNT, stepExecution.getCommitCount());
metrics[1] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.FILTER_COUNT, stepExecution.getFilterCount());
metrics[2] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.PROCESS_SKIP_COUNT, stepExecution.getProcessSkipCount());
metrics[3] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.READ_COUNT, stepExecution.getReadCount());
metrics[4] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.READ_SKIP_COUNT, stepExecution.getReadSkipCount());
metrics[5] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.ROLLBACK_COUNT, stepExecution.getRollbackCount());
metrics[6] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.WRITE_COUNT, stepExecution.getWriteCount());
metrics[7] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.WRITE_SKIP_COUNT, stepExecution.getWriteSkipCount());
return metrics;
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2013 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.core.jsr;
import java.io.Serializable;
import java.util.Date;
import javax.batch.runtime.BatchStatus;
import javax.batch.runtime.Metric;
import org.springframework.batch.core.ExitStatus;
import org.springframework.util.Assert;
/**
*
* @author Michael Minella
* @since 3.0
*/
public class StepExecution implements javax.batch.runtime.StepExecution{
private final org.springframework.batch.core.StepExecution stepExecution;
public StepExecution(org.springframework.batch.core.StepExecution stepExecution) {
Assert.notNull(stepExecution, "A StepExecution is required");
this.stepExecution = stepExecution;
}
@Override
public long getStepExecutionId() {
return stepExecution.getId();
}
@Override
public String getStepName() {
return stepExecution.getStepName();
}
@Override
public BatchStatus getBatchStatus() {
return stepExecution.getStatus().getBatchStatus();
}
@Override
public Date getStartTime() {
return stepExecution.getStartTime();
}
@Override
public Date getEndTime() {
return stepExecution.getEndTime();
}
@Override
public String getExitStatus() {
ExitStatus status = stepExecution.getExitStatus();
if(status == null) {
return null;
} else {
return status.getExitCode();
}
}
//TODO: Implement this
@Override
public Serializable getPersistentUserData() {
return null;
}
@Override
public Metric[] getMetrics() {
Metric[] metrics = new Metric[8];
metrics[0] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.COMMIT_COUNT, stepExecution.getCommitCount());
metrics[1] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.FILTER_COUNT, stepExecution.getFilterCount());
metrics[2] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.PROCESS_SKIP_COUNT, stepExecution.getProcessSkipCount());
metrics[3] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.READ_COUNT, stepExecution.getReadCount());
metrics[4] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.READ_SKIP_COUNT, stepExecution.getReadSkipCount());
metrics[5] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.ROLLBACK_COUNT, stepExecution.getRollbackCount());
metrics[6] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.WRITE_COUNT, stepExecution.getWriteCount());
metrics[7] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.WRITE_SKIP_COUNT, stepExecution.getWriteSkipCount());
return metrics;
}
}

View File

@@ -16,12 +16,12 @@
package org.springframework.batch.core.jsr.launch;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.batch.operations.BatchRuntimeException;
import javax.batch.operations.JobExecutionAlreadyCompleteException;
import javax.batch.operations.JobExecutionIsRunningException;
import javax.batch.operations.JobExecutionNotMostRecentException;
@@ -33,148 +33,278 @@ import javax.batch.operations.JobStartException;
import javax.batch.operations.NoSuchJobException;
import javax.batch.operations.NoSuchJobExecutionException;
import javax.batch.operations.NoSuchJobInstanceException;
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.JobExecution;
import javax.batch.runtime.JobInstance;
import javax.batch.runtime.StepExecution;
import javax.sql.DataSource;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.launch.support.SimpleJobOperator;
import org.springframework.batch.core.jsr.JobContext;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.util.Assert;
/**
* The entrance for executing batch jobs as defined by JSR-352. This class provides
* a base {@link ApplicationContext} that is the equivalent to the following:
* a single base {@link ApplicationContext} that is the equivalent to the following:
*
* <pre class="code">
* &#064;Configuration
* &#064;EnableBatchProcessing
* public static class BaseConfiguration extends DefaultBatchConfigurer {
* &lt;beans&gt;
* &lt;batch:job-repository id="jobRepository" ... /&gt;
*
* &#064;Bean
* JobLauncher jobLauncher() { ... }
* &lt;bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"&gt;
* ...
* &lt;/bean&gt;
*
* &#064;Bean
* org.springframework.batch.core.launch.JobOperator batchJobOperator(JobExplorer jobExplorer,
* JobLauncher jobLauncher,
* JobRepository jobRepository,
* JobRegistry jobRegistry) { ... }
* &lt;bean id="batchJobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator"&gt;
* ...
* &lt;/bean&gt;
*
* &#064;Bean
* JobExplorerFactoryBean jobExplorer(final DataSource dataSource) { ... }
* &lt;bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean"&gt;
* ...
* &lt;/bean&gt;
*
* &#064;Bean
* DataSource dataSource() { ... }
* }
* </pre>
* &lt;bean id="dataSource"
* class="org.apache.commons.dbcp.BasicDataSource"&gt;
* ...
* &lt;/bean&gt;
*
* &lt;bean id="transactionManager"
* class="org.springframework.jdbc.datasource.DataSourceTransactionManager"&gt;
* ...
* &lt;/bean&gt;
*
* &lt;bean id="jobParametersConverter" class="org.springframework.batch.core.jsr.JsrJobParametersConverter"/&gt;
*
* &lt;bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry"/&gt;
*
* &lt;bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&gt;
* ...
* &lt;/bean&gt;
* &lt;/beans&gt;
*
* Calls to {@link JobOperator#start(String, Properties)} will provide a child context to the above context
* using the job definition and batch.xml if provided.
*
* By default, calls to start/restart will result in synchronous execution of the batch job (via a synchronous {@link TaskExecutor}.
* For asynchronous behavior, a different {@link TaskExecutor} implementation is required to be provided.
*
* <em>Note</em>: This class is intended to only be used for JSR-352 configured jobs. Use of
* this {@link JobOperator} to start/stop/restart Spring Batch jobs may result in unexpected behaviors due to
* how job instances are identified differently.
*
* @author Michael Minella
* @since 3.0
* @see EnableBatchProcessing
*/
public class JsrJobOperator implements JobOperator {
private org.springframework.batch.core.launch.JobOperator batchJobOperator;
private JobExplorer jobExplorer;
private JobLauncher jobLauncher;
private GenericApplicationContext baseContext;
private JobRepository jobRepository;
private TaskExecutor taskExecutor;
private JobParametersConverter jobParametersConverter;
private static ApplicationContext baseContext;
/**
* Public constructor used by {@link BatchRuntime#getJobOperator()}. This will bootstrap a
* singleton ApplicationContext if one has not already been created (and will utilize the existing
* one if it has) to populate itself.
*/
public JsrJobOperator() {
baseContext = new AnnotationConfigApplicationContext(BaseConfiguration.class);
jobLauncher = baseContext.getBean(JobLauncher.class);
jobExplorer = baseContext.getBean(JobExplorer.class);
batchJobOperator = baseContext.getBean(org.springframework.batch.core.launch.JobOperator.class);
try {
((SimpleJobLauncher) jobLauncher).afterPropertiesSet();
((SimpleJobOperator) batchJobOperator).afterPropertiesSet();
} catch (Exception e) {
throw new BatchRuntimeException("Unable to bootstrap JobOperator", e);
BeanFactoryLocator beanFactoryLocactor = ContextSingletonBeanFactoryLocator.getInstance();
BeanFactoryReference ref = beanFactoryLocactor.useBeanFactory("baseContext");
baseContext = (ApplicationContext) ref.getFactory();
baseContext.getAutowireCapableBeanFactory().autowireBeanProperties(this,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
if(taskExecutor == null) {
taskExecutor = new SyncTaskExecutor();
}
}
/**
* The no-arg constructor is used by the {@link BatchRuntime#getJobOperator()} and so bootstraps
* an {@link ApplicationContext}. This constructor does not and is therefore dependency injection
* friendly. Also useful for unit testing.
*
* @param jobExplorer an instance of Spring Batch's {@link JobExplorer}
* @param jobRepository an instance of Spring Batch's {@link JobOperator}
* @param jobOperator an instance of Spring Batch's {@link org.springframework.batch.core.launch.JobOperator}
*/
public JsrJobOperator(JobExplorer jobExplorer, JobRepository jobRepository, org.springframework.batch.core.launch.JobOperator jobOperator, JobParametersConverter jobParametersConverter) {
Assert.notNull(jobExplorer, "A JobExplorer is required");
Assert.notNull(jobRepository, "A JobRepository is required");
Assert.notNull(jobOperator, "A JobOperator is required");
Assert.notNull(jobParametersConverter, "A ParametersConverter is required");
this.jobExplorer = jobExplorer;
this.jobRepository = jobRepository;
this.batchJobOperator = jobOperator;
this.jobParametersConverter = jobParametersConverter;
}
public void setJobExplorer(JobExplorer jobExplorer) {
Assert.notNull(jobExplorer, "A JobExplorer is required");
this.jobExplorer = jobExplorer;
}
public void setJobRepository(JobRepository jobRepository) {
Assert.notNull(jobRepository, "A JobRepository is required");
this.jobRepository = jobRepository;
}
public void setJobOperator(org.springframework.batch.core.launch.JobOperator jobOperator) {
Assert.notNull(jobOperator, "A JobOperator is required");
this.batchJobOperator = jobOperator;
}
/**
* Used to convert the {@link Properties} objects used by JSR-352 to the {@link JobParameters}
* objects used in Spring Batch. The default implementation used will configure all parameters
* to be non-identifying (per the JSR).
*
* @param converter A {@link Converter} implementation used to convert {@link Properties} to
* {@link JobParameters}
*/
public void setJobParametersConverter(JobParametersConverter converter) {
Assert.notNull(converter, "A Converter is required");
this.jobParametersConverter = converter;
}
/* (non-Javadoc)
* @see javax.batch.operations.JobOperator#abandon(long)
*/
@Override
public void abandon(long jobExecutionId) throws NoSuchJobExecutionException,
JobExecutionIsRunningException, JobSecurityException {
try {
batchJobOperator.abandon(jobExecutionId);
} catch (org.springframework.batch.core.launch.NoSuchJobExecutionException e) {
throw new NoSuchJobException(e);
throw new NoSuchJobExecutionException(e);
} catch (JobExecutionAlreadyRunningException e) {
throw new JobExecutionIsRunningException(e);
}
}
/* (non-Javadoc)
* @see javax.batch.operations.JobOperator#getJobExecution(long)
*/
@Override
public JobExecution getJobExecution(long executionId)
throws NoSuchJobExecutionException, JobSecurityException {
org.springframework.batch.core.JobExecution jobExecution = jobExplorer.getJobExecution(executionId);
if(jobExecution == null) {
throw new NoSuchJobException("No execution was found for executionId " + executionId);
throw new NoSuchJobExecutionException("No execution was found for executionId " + executionId);
}
return new org.springframework.batch.core.jsr.JobExecution(jobExecution);
return new org.springframework.batch.core.jsr.JobExecution(jobExecution, jobParametersConverter);
}
/* (non-Javadoc)
* @see javax.batch.operations.JobOperator#getJobExecutions(javax.batch.runtime.JobInstance)
*/
@Override
public List<JobExecution> getJobExecutions(JobInstance jobInstance)
throws NoSuchJobInstanceException, JobSecurityException {
if(jobInstance == null) {
throw new NoSuchJobInstanceException("A null JobInstance was provided");
}
org.springframework.batch.core.JobInstance instance = (org.springframework.batch.core.JobInstance) jobInstance;
List<org.springframework.batch.core.JobExecution> batchExecutions = jobExplorer.getJobExecutions(instance);
if(batchExecutions == null) {
if(batchExecutions == null || batchExecutions.size() == 0) {
throw new NoSuchJobInstanceException("Unable to find JobInstance " + jobInstance.getInstanceId());
}
List<JobExecution> results = new ArrayList<JobExecution>(batchExecutions.size());
for (org.springframework.batch.core.JobExecution jobExecution : batchExecutions) {
results.add(new org.springframework.batch.core.jsr.JobExecution(jobExecution));
results.add(new org.springframework.batch.core.jsr.JobExecution(jobExecution, jobParametersConverter));
}
return results;
}
/* (non-Javadoc)
* @see javax.batch.operations.JobOperator#getJobInstance(long)
*/
@Override
public JobInstance getJobInstance(long instanceId)
public JobInstance getJobInstance(long executionId)
throws NoSuchJobExecutionException, JobSecurityException {
return jobExplorer.getJobInstance(instanceId);
org.springframework.batch.core.JobExecution execution = jobExplorer.getJobExecution(executionId);
if(execution == null) {
throw new NoSuchJobExecutionException("The JobExecution was not found");
}
return jobExplorer.getJobInstance(execution.getJobInstance().getId());
}
/* (non-Javadoc)
* @see javax.batch.operations.JobOperator#getJobInstanceCount(java.lang.String)
*/
@Override
public int getJobInstanceCount(String arg0) throws NoSuchJobException,
public int getJobInstanceCount(String jobName) throws NoSuchJobException,
JobSecurityException {
return 0;
try {
return jobExplorer.getJobInstanceCount(jobName);
} catch (org.springframework.batch.core.launch.NoSuchJobException e) {
throw new NoSuchJobException("No job instances were found for job name " + jobName);
}
}
/* (non-Javadoc)
* @see javax.batch.operations.JobOperator#getJobInstances(java.lang.String, int, int)
*/
@Override
public List<JobInstance> getJobInstances(String arg0, int arg1, int arg2)
public List<JobInstance> getJobInstances(String jobName, int start, int count)
throws NoSuchJobException, JobSecurityException {
return null;
List<org.springframework.batch.core.JobInstance> jobInstances = jobExplorer.getJobInstances(jobName, start, count);
if(jobInstances == null || jobInstances.size() == 0) {
throw new NoSuchJobException("The job was not found");
}
return new ArrayList<JobInstance>(jobInstances);
}
/* (non-Javadoc)
* @see javax.batch.operations.JobOperator#getJobNames()
*/
@Override
public Set<String> getJobNames() throws JobSecurityException {
return new HashSet<String>(jobExplorer.getJobNames());
}
/* (non-Javadoc)
* @see javax.batch.operations.JobOperator#getParameters(long)
*/
@Override
public Properties getParameters(long executionId)
throws NoSuchJobExecutionException, JobSecurityException {
@@ -184,13 +314,17 @@ public class JsrJobOperator implements JobOperator {
throw new NoSuchJobExecutionException("Unable to find the JobExecution for id " + executionId);
}
return execution.getJobParameters().toProperties();
return jobParametersConverter.getProperties(execution.getJobParameters());
}
/* (non-Javadoc)
* @see javax.batch.operations.JobOperator#getRunningExecutions(java.lang.String)
*/
@Override
public List<Long> getRunningExecutions(String name)
throws NoSuchJobException, JobSecurityException {
Set<org.springframework.batch.core.JobExecution> findRunningJobExecutions = jobExplorer.findRunningJobExecutions(name);
List<Long> results = new ArrayList<Long>(findRunningJobExecutions.size());
for (org.springframework.batch.core.JobExecution jobExecution : findRunningJobExecutions) {
@@ -200,6 +334,9 @@ public class JsrJobOperator implements JobOperator {
return results;
}
/* (non-Javadoc)
* @see javax.batch.operations.JobOperator#getStepExecutions(long)
*/
@Override
public List<StepExecution> getStepExecutions(long executionId)
throws NoSuchJobExecutionException, JobSecurityException {
@@ -209,39 +346,200 @@ public class JsrJobOperator implements JobOperator {
throw new NoSuchJobException("JobExecution with the id " + executionId + " was not found");
}
return null;
// return execution.getStepExecutions();
Collection<org.springframework.batch.core.StepExecution> executions = execution.getStepExecutions();
List<StepExecution> batchExecutions = new ArrayList<StepExecution>();
if(executions != null) {
for (org.springframework.batch.core.StepExecution stepExecution : executions) {
batchExecutions.add(new org.springframework.batch.core.jsr.StepExecution(stepExecution));
}
}
return batchExecutions;
}
/**
* Creates a child {@link ApplicationContext} for the job being requested based upon
* the /META-INF/batch.xml (if exists) and the /META-INF/batch-jobs/&lt;jobName&gt;.xml
* configuration and restart the job.
*
* @param executionId the database id of the job execution to be restarted.
* @param params any job parameters to be used during the execution of this job.
* @throws JobExecutionAlreadyCompleteException thrown if the requested job execution has
* a status of COMPLETE
* @throws NoSuchJobExecutionException throw if the requested job execution does not exist
* in the repository
* @throws JobExecutionNotMostRecentException thrown if the requested job execution is not
* the most recent attempt for the job instance it's related to.
* @throws JobRestartException thrown for any general errors during the job restart process
*/
@Override
public long restart(long arg0, Properties arg1)
@SuppressWarnings("resource")
public long restart(long executionId, Properties params)
throws JobExecutionAlreadyCompleteException,
NoSuchJobExecutionException, JobExecutionNotMostRecentException,
JobRestartException, JobSecurityException {
return 0;
org.springframework.batch.core.JobExecution previousJobExecution = jobExplorer.getJobExecution(executionId);
if (previousJobExecution == null) {
throw new NoSuchJobExecutionException("No JobExecution found for id: [" + executionId + "]");
} else if(previousJobExecution.getStatus().equals(BatchStatus.COMPLETED)) {
throw new JobExecutionAlreadyCompleteException("The requested job has already completed");
}
String jobName = previousJobExecution.getJobInstance().getJobName();
GenericXmlApplicationContext batchContext = new GenericXmlApplicationContext();
batchContext.setValidating(false);
Resource batchXml = new ClassPathResource("/META-INF/batch.xml");
Resource jobXml = new ClassPathResource(previousJobExecution.getJobConfigurationName());
if(batchXml.exists()) {
batchContext.load(batchXml);
}
if(jobXml.exists()) {
batchContext.load(jobXml);
}
batchContext.setParent(baseContext);
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(AutowiredAnnotationBeanPostProcessor.class);
batchContext.registerBeanDefinition("postProcessor", bd);
batchContext.refresh();
final Job job = batchContext.getBean(Job.class);
if(!job.isRestartable()) {
throw new JobRestartException("Job " + jobName + " is not restartable");
}
final org.springframework.batch.core.JobExecution jobExecution;
try {
JobParameters jobParameters = jobParametersConverter.getJobParameters(params);
jobExecution = jobRepository.createJobExecution(previousJobExecution.getJobInstance(), jobParameters, previousJobExecution.getJobConfigurationName());
} catch (Exception e) {
throw new JobRestartException(e);
}
try {
ConfigurableListableBeanFactory factory = ((ConfigurableApplicationContext)batchContext).getBeanFactory();
factory.registerSingleton(job.getName() + "_" + jobExecution.getId() + "_jobContext", new JobContext(jobExecution, jobParametersConverter));
taskExecutor.execute(new Runnable() {
@Override
public void run() {
try {
job.execute(jobExecution);
}
catch (Throwable t) {
throw new JobRestartException(t);
}
}
});
}
catch (TaskRejectedException e) {
jobExecution.upgradeStatus(BatchStatus.FAILED);
if (jobExecution.getExitStatus().equals(ExitStatus.UNKNOWN)) {
jobExecution.setExitStatus(ExitStatus.FAILED.addExitDescription(e));
}
jobRepository.update(jobExecution);
}
batchContext.close();
return jobExecution.getId();
}
/**
* Creates a child {@link ApplicationContext} for the job being requested based upon
* the /META-INF/batch.xml (if exists) and the /META-INF/batch-jobs/&lt;jobName&gt;.xml
* configuration and launches the job. Per JSR-352, calls to this method will always
* create a new {@link JobInstance} (and related {@link JobExecution}).
*
* @param jobName the name of the job XML file without the .xml that is located within the
* /META-INF/batch-jobs directory.
* @param params any job parameters to be used during the execution of this job.
*/
@Override
@SuppressWarnings("resource")
public long start(String jobName, Properties params) throws JobStartException,
JobSecurityException {
GenericXmlApplicationContext batchContext = new GenericXmlApplicationContext();
batchContext.setValidating(false);
batchContext.load(new String[] {"/META-INF/batch.xml", "META-INF/batch-jobs/" + jobName + ".xml"});
Resource batchXml = new ClassPathResource("/META-INF/batch.xml");
String jobConfigurationLocation = "/META-INF/batch-jobs/" + jobName + ".xml";
Resource jobXml = new ClassPathResource(jobConfigurationLocation);
if(batchXml.exists()) {
batchContext.load(batchXml);
}
if(jobXml.exists()) {
batchContext.load(jobXml);
}
batchContext.setParent(baseContext);
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(AutowiredAnnotationBeanPostProcessor.class);
batchContext.registerBeanDefinition("postProcessor", bd);
batchContext.refresh();
Job job = batchContext.getBean(jobName, Job.class);
final Job job = batchContext.getBean(Job.class);
Assert.notNull(jobName, "The job name must not be null.");
final org.springframework.batch.core.JobExecution jobExecution;
try {
return jobLauncher.run(job, new JobParametersBuilder(params).toJobParameters()).getId();
JobParameters jobParameters = jobParametersConverter.getJobParameters(params);
org.springframework.batch.core.JobInstance jobInstance = jobRepository.createJobInstance(job.getName(), jobParameters);
jobExecution = jobRepository.createJobExecution(jobInstance, jobParameters, jobConfigurationLocation);
} catch (Exception e) {
e.printStackTrace();
throw new JobStartException(e);
}
try {
ConfigurableListableBeanFactory factory = ((ConfigurableApplicationContext)batchContext).getBeanFactory();
factory.registerSingleton(job.getName() + "_" + jobExecution.getId() + "_jobContext", new JobContext(jobExecution, jobParametersConverter));
taskExecutor.execute(new Runnable() {
@Override
public void run() {
try {
job.execute(jobExecution);
}
catch (Throwable t) {
throw new JobStartException(t);
}
}
});
}
catch (TaskRejectedException e) {
jobExecution.upgradeStatus(BatchStatus.FAILED);
if (jobExecution.getExitStatus().equals(ExitStatus.UNKNOWN)) {
jobExecution.setExitStatus(ExitStatus.FAILED.addExitDescription(e));
}
jobRepository.update(jobExecution);
}
batchContext.close();
return jobExecution.getId();
}
/**
* Delegates to {@link org.springframework.batch.core.launch.JobOperator#stop(long)}
*
* @param executionId the database id for the {@link JobExecution} to be stopped.
* @throws NoSuchJobExecutionException
* @throws JobExecutionNotRunningException
*/
@Override
public void stop(long executionId) throws NoSuchJobExecutionException,
JobExecutionNotRunningException, JobSecurityException {
@@ -253,48 +551,4 @@ public class JsrJobOperator implements JobOperator {
throw new JobExecutionNotRunningException(e);
}
}
@Configuration
@EnableBatchProcessing
public static class BaseConfiguration extends DefaultBatchConfigurer {
@Bean
JobLauncher jobLauncher() {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(super.getJobRepository());
try {
jobLauncher.afterPropertiesSet();
} catch (Exception e) {
e.printStackTrace();
}
return jobLauncher;
}
@Bean
org.springframework.batch.core.launch.JobOperator batchJobOperator(JobExplorer jobExplorer, JobLauncher jobLauncher, JobRepository jobRepository, JobRegistry jobRegistry) {
SimpleJobOperator operator = new SimpleJobOperator();
operator.setJobExplorer(jobExplorer);
operator.setJobLauncher(jobLauncher);
operator.setJobRepository(jobRepository);
operator.setJobRegistry(jobRegistry);
return operator;
}
@Bean
JobExplorerFactoryBean jobExplorer(final DataSource dataSource) {
return new JobExplorerFactoryBean() {{
setDataSource(dataSource);
}};
}
@Bean
DataSource dataSource() {
return new EmbeddedDatabaseBuilder().
addScript("classpath:org/springframework/batch/core/schema-drop-hsqldb.sql").
addScript("classpath:org/springframework/batch/core/schema-hsqldb.sql").
build();
}
}
}

View File

@@ -25,18 +25,12 @@ import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.jsr.JobContext;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.task.TaskRejectedException;
@@ -68,7 +62,7 @@ import org.springframework.util.Assert;
* @see JobRepository
* @see TaskExecutor
*/
public class SimpleJobLauncher implements JobLauncher, InitializingBean, ApplicationContextAware {
public class SimpleJobLauncher implements JobLauncher, InitializingBean {
protected static final Log logger = LogFactory.getLog(SimpleJobLauncher.class);
@@ -76,8 +70,6 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean, Applica
private TaskExecutor taskExecutor;
private ApplicationContext context;
/**
* Run the provided job with the given {@link JobParameters}. The
* {@link JobParameters} will be used to determine if this is an execution
@@ -132,11 +124,6 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean, Applica
*/
jobExecution = jobRepository.createJobExecution(job.getName(), jobParameters);
if(context != null && context instanceof ConfigurableApplicationContext) {
ConfigurableListableBeanFactory factory = ((ConfigurableApplicationContext)context).getBeanFactory();
factory.registerSingleton(job.getName() + "_" + jobExecution.getId() + "_jobContext", new JobContext(jobExecution));
}
try {
taskExecutor.execute(new Runnable() {
@@ -209,10 +196,4 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean, Applica
taskExecutor = new SyncTaskExecutor();
}
}
@Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
this.context = context;
}
}

View File

@@ -178,7 +178,8 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
@Override
public List<Long> getJobInstances(String jobName, int start, int count) throws NoSuchJobException {
List<Long> list = new ArrayList<Long>();
for (JobInstance jobInstance : jobExplorer.getJobInstances(jobName, start, count)) {
List<JobInstance> jobInstances = jobExplorer.getJobInstances(jobName, start, count);
for (JobInstance jobInstance : jobInstances) {
list.add(jobInstance.getId());
}
if (list.isEmpty() && !jobRegistry.getJobNames().contains(jobName)) {

View File

@@ -33,22 +33,23 @@ import org.springframework.transaction.annotation.Isolation;
* <p>
* Repository responsible for persistence of batch meta-data entities.
* </p>
*
*
* @see JobInstance
* @see JobExecution
* @see StepExecution
*
*
* @author Lucas Ward
* @author Dave Syer
* @author Robert Kasanicky
* @author David Turanski
* @author Michael Minella
*/
public interface JobRepository {
/**
* Check if an instance of this job already exists with the parameters
* provided.
*
*
* @param jobName the name of the job
* @param jobParameters the parameters to match
* @return true if a {@link JobInstance} already exists for this job name
@@ -56,6 +57,27 @@ public interface JobRepository {
*/
boolean isJobInstanceExists(String jobName, JobParameters jobParameters);
/**
* Create a new {@link JobInstance} with the name and job parameters provided.
*
* @param jobName logical name of the job
* @param jobParameters parameters used to execute the job
* @return the new {@link JobInstance}
*/
JobInstance createJobInstance(String jobName, JobParameters jobParameters);
/**
* Create a new {@link JobExecution} based upon the {@link JobInstance} it's associated
* with, the {@link JobParameters} used to execute it with and the location of the configuration
* file that defines the job.
*
* @param jobInstance
* @param jobParameters
* @param jobConfigurationLocation
* @return the new {@link JobExecution}
*/
JobExecution createJobExecution(JobInstance jobInstance, JobParameters jobParameters, String jobConfigurationLocation);
/**
* <p>
* Create a {@link JobExecution} for a given {@link Job} and
@@ -64,7 +86,7 @@ public interface JobRepository {
* completed. If matching {@link JobInstance} does not exist yet it will be
* created.
* </p>
*
*
* <p>
* If this method is run in a transaction (as it normally would be) with
* isolation level at {@link Isolation#REPEATABLE_READ} or better, then this
@@ -77,11 +99,11 @@ public interface JobRepository {
* (e.g. if using a non-relational data-store, or if the platform does not
* support the higher isolation levels).
* </p>
*
*
* @param jobName the name of the job that is to be executed </p>
*
*
* @param jobParameters the runtime parameters for the job
*
*
* @return a valid {@link JobExecution} for the arguments provided
* @throws JobExecutionAlreadyRunningException if there is a
* {@link JobExecution} already running for the job instance with the
@@ -91,17 +113,17 @@ public interface JobRepository {
* false.
* @throws JobInstanceAlreadyCompleteException if a {@link JobInstance} is
* found and was already completed successfully.
*
*
*/
JobExecution createJobExecution(String jobName, JobParameters jobParameters)
throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException;
/**
* Update the {@link JobExecution} (but not its {@link ExecutionContext}).
*
*
* Preconditions: {@link JobExecution} must contain a valid
* {@link JobInstance} and be saved (have an id assigned).
*
*
* @param jobExecution
*/
void update(JobExecution jobExecution);
@@ -111,9 +133,9 @@ public interface JobRepository {
* be assigned - it is not permitted that an ID be assigned before calling
* this method. Instead, it should be left blank, to be assigned by a
* {@link JobRepository}.
*
*
* Preconditions: {@link StepExecution} must have a valid {@link Step}.
*
*
* @param stepExecution
*/
void add(StepExecution stepExecution);
@@ -122,18 +144,18 @@ public interface JobRepository {
* Save a collection of {@link StepExecution}s and each {@link ExecutionContext}. The
* StepExecution ID will be assigned - it is not permitted that an ID be assigned before calling
* this method. Instead, it should be left blank, to be assigned by {@link JobRepository}.
*
*
* Preconditions: {@link StepExecution} must have a valid {@link Step}.
*
*
* @param stepExecution
*/
void addAll(Collection<StepExecution> stepExecutions);
/**
* Update the {@link StepExecution} (but not its {@link ExecutionContext}).
*
*
* Preconditions: {@link StepExecution} must be saved (have an id assigned).
*
*
* @param stepExecution
*/
void update(StepExecution stepExecution);
@@ -141,7 +163,7 @@ public interface JobRepository {
/**
* Persist the updated {@link ExecutionContext}s of the given
* {@link StepExecution}.
*
*
* @param stepExecution
*/
void updateExecutionContext(StepExecution stepExecution);

View File

@@ -63,7 +63,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
private static final Log logger = LogFactory.getLog(JdbcJobExecutionDao.class);
private static final String SAVE_JOB_EXECUTION = "INSERT into %PREFIX%JOB_EXECUTION(JOB_EXECUTION_ID, JOB_INSTANCE_ID, START_TIME, "
+ "END_TIME, STATUS, EXIT_CODE, EXIT_MESSAGE, VERSION, CREATE_TIME, LAST_UPDATED) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ "END_TIME, STATUS, EXIT_CODE, EXIT_MESSAGE, VERSION, CREATE_TIME, LAST_UPDATED, JOB_CONFIGURATION_LOCATION) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
private static final String CHECK_JOB_EXECUTION_EXISTS = "SELECT COUNT(*) FROM %PREFIX%JOB_EXECUTION WHERE JOB_EXECUTION_ID = ?";
@@ -72,17 +72,17 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
private static final String UPDATE_JOB_EXECUTION = "UPDATE %PREFIX%JOB_EXECUTION set START_TIME = ?, END_TIME = ?, "
+ " STATUS = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, CREATE_TIME = ?, LAST_UPDATED = ? where JOB_EXECUTION_ID = ? and VERSION = ?";
private static final String FIND_JOB_EXECUTIONS = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, LAST_UPDATED, VERSION"
private static final String FIND_JOB_EXECUTIONS = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, LAST_UPDATED, VERSION, JOB_CONFIGURATION_LOCATION"
+ " from %PREFIX%JOB_EXECUTION where JOB_INSTANCE_ID = ? order by JOB_EXECUTION_ID desc";
private static final String GET_LAST_EXECUTION = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, LAST_UPDATED, VERSION "
private static final String GET_LAST_EXECUTION = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, LAST_UPDATED, VERSION, JOB_CONFIGURATION_LOCATION "
+ "from %PREFIX%JOB_EXECUTION E where JOB_INSTANCE_ID = ? and JOB_EXECUTION_ID in (SELECT max(JOB_EXECUTION_ID) from %PREFIX%JOB_EXECUTION E2 where E2.JOB_INSTANCE_ID = ?)";
private static final String GET_EXECUTION_BY_ID = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, LAST_UPDATED, VERSION"
private static final String GET_EXECUTION_BY_ID = "SELECT JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, EXIT_CODE, EXIT_MESSAGE, CREATE_TIME, LAST_UPDATED, VERSION, JOB_CONFIGURATION_LOCATION"
+ " from %PREFIX%JOB_EXECUTION where JOB_EXECUTION_ID = ?";
private static final String GET_RUNNING_EXECUTIONS = "SELECT E.JOB_EXECUTION_ID, E.START_TIME, E.END_TIME, E.STATUS, E.EXIT_CODE, E.EXIT_MESSAGE, E.CREATE_TIME, E.LAST_UPDATED, E.VERSION, "
+ "E.JOB_INSTANCE_ID from %PREFIX%JOB_EXECUTION E, %PREFIX%JOB_INSTANCE I where E.JOB_INSTANCE_ID=I.JOB_INSTANCE_ID and I.JOB_NAME=? and E.END_TIME is NULL order by E.JOB_EXECUTION_ID desc";
+ "E.JOB_INSTANCE_ID, E.JOB_CONFIGURATION_LOCATION from %PREFIX%JOB_EXECUTION E, %PREFIX%JOB_INSTANCE I where E.JOB_INSTANCE_ID=I.JOB_INSTANCE_ID and I.JOB_NAME=? and E.END_TIME is NULL order by E.JOB_EXECUTION_ID desc";
private static final String CURRENT_VERSION_JOB_EXECUTION = "SELECT VERSION FROM %PREFIX%JOB_EXECUTION WHERE JOB_EXECUTION_ID=?";
@@ -151,12 +151,13 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
Object[] parameters = new Object[] { jobExecution.getId(), jobExecution.getJobId(),
jobExecution.getStartTime(), jobExecution.getEndTime(), jobExecution.getStatus().toString(),
jobExecution.getExitStatus().getExitCode(), jobExecution.getExitStatus().getExitDescription(),
jobExecution.getVersion(), jobExecution.getCreateTime(), jobExecution.getLastUpdated() };
jobExecution.getVersion(), jobExecution.getCreateTime(), jobExecution.getLastUpdated(),
jobExecution.getJobConfigurationName() };
getJdbcTemplate().update(
getQuery(SAVE_JOB_EXECUTION),
parameters,
new int[] { Types.BIGINT, Types.BIGINT, Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR,
Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP, Types.TIMESTAMP });
Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR });
insertJobParameters(jobExecution.getId(), jobExecution.getJobParameters());
}
@@ -405,16 +406,17 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
@Override
public JobExecution mapRow(ResultSet rs, int rowNum) throws SQLException {
Long id = rs.getLong(1);
String jobConfigurationLocation = rs.getString(10);
JobExecution jobExecution;
if (jobParameters == null) {
jobParameters = getJobParameters(id);
}
if (jobInstance == null) {
jobExecution = new JobExecution(id, jobParameters);
jobExecution = new JobExecution(id, jobParameters, jobConfigurationLocation);
}
else {
jobExecution = new JobExecution(jobInstance, id, jobParameters);
jobExecution = new JobExecution(jobInstance, id, jobParameters, jobConfigurationLocation);
}
jobExecution.setStartTime(rs.getTimestamp(2));

View File

@@ -27,6 +27,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobKeyGenerator;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
@@ -61,6 +62,8 @@ JobInstanceDao, InitializingBean {
private static final String FIND_JOBS_WITH_KEY = FIND_JOBS_WITH_NAME
+ " and JOB_KEY = ?";
private static final String COUNT_JOBS_WITH_NAME = "SELECT COUNT(*) from %PREFIX%JOB_INSTANCE where JOB_NAME = ?";
private static final String FIND_JOBS_WITH_EMPTY_KEY = "SELECT JOB_INSTANCE_ID, JOB_NAME from %PREFIX%JOB_INSTANCE where JOB_NAME = ? and (JOB_KEY = ? OR JOB_KEY is NULL)";
private static final String GET_JOB_FROM_ID = "SELECT JOB_INSTANCE_ID, JOB_NAME, JOB_KEY, VERSION from %PREFIX%JOB_INSTANCE where JOB_INSTANCE_ID = ?";
@@ -244,6 +247,21 @@ JobInstanceDao, InitializingBean {
}
}
/* (non-Javadoc)
* @see org.springframework.batch.core.repository.dao.JobInstanceDao#getJobInstanceCount(java.lang.String)
*/
@Override
public int getJobInstanceCount(String jobName) throws NoSuchJobException {
try {
return getJdbcTemplate().queryForInt(
getQuery(COUNT_JOBS_WITH_NAME),
jobName);
} catch (EmptyResultDataAccessException e) {
throw new NoSuchJobException("No job instances were found for job name " + jobName);
}
}
/**
* Setter for {@link DataFieldMaxValueIncrementer} to be used when
* generating primary keys for {@link JobInstance} instances.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2013 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.
@@ -21,25 +21,27 @@ import java.util.List;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.NoSuchJobException;
/**
* Data Access Object for job instances.
*
*
* @author Lucas Ward
* @author Robert Kasanicky
*
* @author Michael Minella
*
*/
public interface JobInstanceDao {
/**
* Create a JobInstance with given name and parameters.
*
*
* PreConditions: JobInstance for given name and parameters must not already
* exist
*
*
* PostConditions: A valid job instance will be returned which has been
* persisted and contains an unique Id.
*
*
* @param jobName
* @param jobParameters
* @return JobInstance
@@ -49,7 +51,7 @@ public interface JobInstanceDao {
/**
* Find the job instance that matches the given name and parameters. If no
* matching job instances are found, then returns null.
*
*
* @param jobName the name of the job
* @param jobParameters the parameters with which the job was executed
* @return {@link JobInstance} object matching the job name and
@@ -59,7 +61,7 @@ public interface JobInstanceDao {
/**
* Fetch the job instance with the provided identifier.
*
*
* @param instanceId the job identifier
* @return the job instance with this identifier or null if it doesn't exist
*/
@@ -67,17 +69,17 @@ public interface JobInstanceDao {
/**
* Fetch the JobInstance for the provided JobExecution.
*
*
* @param jobExecution the JobExecution
* @return the JobInstance for the provided execution or null if it doesn't exist.
*/
JobInstance getJobInstance(JobExecution jobExecution);
/**
* Fetch the last job instances with the provided name, sorted backwards by
* primary key.
*
*
*
*
* @param jobName the job name
* @param start the start index of the instances to return
* @param count the maximum number of objects to return
@@ -92,4 +94,16 @@ public interface JobInstanceDao {
*/
List<String> getJobNames();
/**
* Query the repository for the number of unique {@link JobInstance}s
* associated with the supplied job name.
*
* @param jobName the name of the job to query for
* @return the number of {@link JobInstance}s that exist within the
* associated job repository
* @throws NoSuchJobException
*/
int getJobInstanceCount(String jobName) throws NoSuchJobException;
}

View File

@@ -29,6 +29,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobKeyGenerator;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.util.Assert;
/**
@@ -38,7 +39,6 @@ public class MapJobInstanceDao implements JobInstanceDao {
// JDK6 Make a ConcurrentSkipListSet: tends to add on end
private final Map<String, JobInstance> jobInstances = new ConcurrentHashMap<String, JobInstance>();
// private final Set<JobInstance> jobInstances = new CopyOnWriteArraySet<JobInstance>();
private JobKeyGenerator<JobParameters> jobKeyGenerator = new DefaultJobKeyGenerator();
@@ -55,14 +55,14 @@ public class MapJobInstanceDao implements JobInstanceDao {
JobInstance jobInstance = new JobInstance(currentId.getAndIncrement(), jobName);
jobInstance.incrementVersion();
jobInstances.put(jobName + jobKeyGenerator.generateKey(jobParameters), jobInstance);
jobInstances.put(jobName + "|" + jobKeyGenerator.generateKey(jobParameters), jobInstance);
return jobInstance;
}
@Override
public JobInstance getJobInstance(String jobName, JobParameters jobParameters) {
return jobInstances.get(jobName + jobKeyGenerator.generateKey(jobParameters));
return jobInstances.get(jobName + "|" + jobKeyGenerator.generateKey(jobParameters));
}
@Override
@@ -113,4 +113,23 @@ public class MapJobInstanceDao implements JobInstanceDao {
return jobExecution.getJobInstance();
}
@Override
public int getJobInstanceCount(String jobName) throws NoSuchJobException {
int count = 0;
for (Map.Entry<String, JobInstance> instanceEntry : jobInstances.entrySet()) {
String key = instanceEntry.getKey();
String curJobName = key.substring(0, key.lastIndexOf("|"));
if(curJobName.equals(jobName)) {
count++;
}
}
if(count == 0) {
throw new NoSuchJobException("No job instances for job name " + jobName + " were found");
} else {
return count;
}
}
}

View File

@@ -122,7 +122,7 @@ public class SimpleJobRepository implements JobRepository {
}
BatchStatus status = execution.getStatus();
if (status == BatchStatus.COMPLETED || status == BatchStatus.ABANDONED) {
if (execution.getJobParameters().getParameters().size() > 0 && (status == BatchStatus.COMPLETED || status == BatchStatus.ABANDONED)) {
throw new JobInstanceAlreadyCompleteException(
"A job instance already exists and is complete for parameters=" + jobParameters
+ ". If you want to run this job again, change the parameters.");
@@ -136,7 +136,7 @@ public class SimpleJobRepository implements JobRepository {
executionContext = new ExecutionContext();
}
JobExecution jobExecution = new JobExecution(jobInstance, jobParameters);
JobExecution jobExecution = new JobExecution(jobInstance, jobParameters, null);
jobExecution.setExecutionContext(executionContext);
jobExecution.setLastUpdated(new Date(System.currentTimeMillis()));
@@ -258,7 +258,7 @@ public class SimpleJobRepository implements JobRepository {
return count;
}
/*
/**
* Check to determine whether or not the JobExecution that is the parent of
* the provided StepExecution has been interrupted. If, after synchronizing
* the status with the database, the status has been updated to STOPPING,
@@ -289,4 +289,34 @@ public class SimpleJobRepository implements JobRepository {
return jobExecution;
}
@Override
public JobInstance createJobInstance(String jobName, JobParameters jobParameters) {
Assert.notNull(jobName, "A job name is required to create a JobInstance");
Assert.notNull(jobParameters, "Job parameters are required to create a JobInstance");
JobInstance jobInstance = jobInstanceDao.createJobInstance(jobName, jobParameters);
return jobInstance;
}
@Override
public JobExecution createJobExecution(JobInstance jobInstance,
JobParameters jobParameters, String jobConfigurationLocation) {
Assert.notNull(jobInstance, "A JobInstance is required to associate the JobExecution with");
Assert.notNull(jobParameters, "A JobParameters object is required to create a JobExecution");
JobExecution jobExecution = new JobExecution(jobInstance, jobParameters, jobConfigurationLocation);
ExecutionContext executionContext = new ExecutionContext();
jobExecution.setExecutionContext(executionContext);
jobExecution.setLastUpdated(new Date(System.currentTimeMillis()));
// Save the JobExecution so that it picks up an ID (useful for clients
// monitoring asynchronous executions):
jobExecutionDao.saveJobExecution(jobExecution);
ecDao.saveExecutionContext(jobExecution);
return jobExecution;
}
}

View File

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<batch:job-repository data-source="dataSource" id="jobRepository"
transaction-manager="transactionManager" table-prefix="BATCH_"/>
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository"/>
</bean>
<bean id="batchJobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator">
<property name="jobExplorer" ref="jobExplorer"/>
<property name="jobLauncher" ref="jobLauncher"/>
<property name="jobRepository" ref="jobRepository"/>
<property name="jobRegistry" ref="jobRegistry"/>
</bean>
<bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${batch.jdbc.driver}" />
<property name="url" value="${batch.jdbc.url}" />
<property name="username" value="${batch.jdbc.user}" />
<property name="password" value="${batch.jdbc.password}" />
<property name="testWhileIdle" value="${batch.jdbc.testWhileIdle}"/>
<property name="validationQuery" value="${batch.jdbc.validationQuery}"/>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Initialise the database if enabled: -->
<jdbc:initialize-database data-source="dataSource" enabled="${batch.data.source.init}" ignore-failures="DROPS">
<jdbc:script location="${batch.drop.script}"/>
<jdbc:script location="${batch.schema.script}"/>
</jdbc:initialize-database>
<bean id="jobParametersConverter" class="org.springframework.batch.core.jsr.JsrJobParametersConverter">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry"/>
<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:batch-${ENVIRONMENT:hsql}.properties</value>
</list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
<property name="order" value="1" />
</bean>
</beans>

View File

@@ -0,0 +1,19 @@
# Placeholders batch.*
# for HSQLDB:
batch.jdbc.driver=org.hsqldb.jdbcDriver
batch.jdbc.url=jdbc:hsqldb:mem:testdb;sql.enforce_strict_size=true
# Override and use this one in for a separate server process so you can inspect
# the results (or add it to system properties with -D to override at run time).
# batch.jdbc.url=jdbc:hsqldb:hsql://localhost:9005/samples
batch.jdbc.user=sa
batch.jdbc.password=
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.HsqlMaxValueIncrementer
batch.schema.script=classpath*:/org/springframework/batch/core/schema-hsqldb.sql
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-hsqldb.sql
batch.business.schema.script=
batch.jdbc.testWhileIdle=true
batch.jdbc.validationQuery=
# Non-platform dependent settings that you might like to change
batch.data.source.init=true

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!--
<context:annotation-config/>
first, define your individual @Configuration classes as beans
<bean class="org.springframework.batch.core.jsr.launch.JsrJobOperator.BaseConfiguration"/>
-->
<bean id="baseContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>baseContext.xml</value>
</list>
</constructor-arg>
</bean>
</beans>

View File

@@ -19,6 +19,7 @@ CREATE TABLE BATCH_JOB_EXECUTION (
EXIT_CODE VARCHAR(100) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

View File

@@ -19,6 +19,7 @@ CREATE TABLE BATCH_JOB_EXECUTION (
EXIT_CODE VARCHAR(100) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

View File

@@ -19,6 +19,7 @@ CREATE TABLE BATCH_JOB_EXECUTION (
EXIT_CODE VARCHAR(100) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

View File

@@ -19,6 +19,7 @@ CREATE TABLE BATCH_JOB_EXECUTION (
EXIT_CODE VARCHAR(100) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

View File

@@ -19,6 +19,7 @@ CREATE TABLE BATCH_JOB_EXECUTION (
EXIT_CODE VARCHAR(100) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED DATETIME,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ENGINE=InnoDB;

View File

@@ -19,6 +19,7 @@ CREATE TABLE BATCH_JOB_EXECUTION (
EXIT_CODE VARCHAR2(100) ,
EXIT_MESSAGE VARCHAR2(2500) ,
LAST_UPDATED TIMESTAMP,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

View File

@@ -19,6 +19,7 @@ CREATE TABLE BATCH_JOB_EXECUTION (
EXIT_CODE VARCHAR(100) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

View File

@@ -19,6 +19,7 @@ CREATE TABLE BATCH_JOB_EXECUTION (
EXIT_CODE VARCHAR(100) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

View File

@@ -19,6 +19,7 @@ CREATE TABLE BATCH_JOB_EXECUTION (
EXIT_CODE VARCHAR(100) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED DATETIME,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

View File

@@ -19,6 +19,7 @@ CREATE TABLE BATCH_JOB_EXECUTION (
EXIT_CODE VARCHAR(100) NULL,
EXIT_MESSAGE VARCHAR(2500) NULL,
LAST_UPDATED DATETIME,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

View File

@@ -35,7 +35,7 @@ import org.springframework.batch.support.SerializationUtils;
public class JobExecutionTests {
private JobExecution execution = new JobExecution(new JobInstance(new Long(11), "foo"),
new Long(12), new JobParameters());
new Long(12), new JobParameters(), null);
@Test
public void testJobExecution() {
@@ -53,6 +53,12 @@ public class JobExecutionTests {
assertEquals(100L, execution.getEndTime().getTime());
}
@Test
public void testGetJobConfigurationName() {
execution = new JobExecution(new JobInstance(null, "foo"), null, "/META-INF/batch-jobs/someJob.xml");
assertEquals("/META-INF/batch-jobs/someJob.xml", execution.getJobConfigurationName());
}
/**
* Test method for
* {@link org.springframework.batch.core.JobExecution#getEndTime()}.
@@ -126,7 +132,7 @@ public class JobExecutionTests {
@Test
public void testGetJobId() {
assertEquals(11, execution.getJobId().longValue());
execution = new JobExecution(new JobInstance(new Long(23), "testJob"), null, new JobParameters());
execution = new JobExecution(new JobInstance(new Long(23), "testJob"), null, new JobParameters(), null);
assertEquals(23, execution.getJobId().longValue());
}

View File

@@ -6,7 +6,6 @@ import static org.junit.Assert.assertFalse;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.junit.Test;
@@ -21,30 +20,6 @@ public class JobParametersBuilderTests {
Date date = new Date(System.currentTimeMillis());
@Test
public void testFromProperties() {
Properties props = new Properties();
props.put("SCHEDULE_DATE", date.toString());
props.put("LONG", "1");
props.put("STRING", "string value");
JobParametersBuilder builder = new JobParametersBuilder(props);
JobParameters parameters = builder.toJobParameters();
assertEquals(date.toString(), parameters.getString("SCHEDULE_DATE"));
assertEquals("1", parameters.getString("LONG").toString());
assertEquals("string value", parameters.getString("STRING"));
assertFalse(parameters.getParameters().get("SCHEDULE_DATE").isIdentifying());
assertFalse(parameters.getParameters().get("LONG").isIdentifying());
assertFalse(parameters.getParameters().get("STRING").isIdentifying());
}
@Test
public void testFromNullProperties() {
JobParametersBuilder builder = new JobParametersBuilder((Properties) null);
JobParameters parameters = builder.toJobParameters();
assertEquals(0, parameters.getParameters().size());
}
@Test
public void testNonIdentifyingParameters() {
parametersBuilder.addDate("SCHEDULE_DATE", date, false);

View File

@@ -10,7 +10,6 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import org.junit.Before;
import org.junit.Test;
@@ -213,18 +212,4 @@ public class JobParametersTests {
public void testDateReturnsNullWhenKeyDoesntExit(){
assertNull(new JobParameters().getDate("keythatdoesntexist"));
}
@Test
public void testToProperties() {
Properties results = parameters.toProperties();
assertEquals(results.get("string.key1"), "value1");
assertEquals(results.get("string.key2"), "value2");
assertEquals(results.get("long.key1"), "1");
assertEquals(results.get("long.key2"), "2");
assertEquals(results.get("double.key1"), "1.1");
assertEquals(results.get("double.key2"), "2.2");
assertEquals(results.get("date.key1"), String.valueOf(date1.getTime()));
assertEquals(results.get("date.key2"), String.valueOf(date2.getTime()));
}
}

View File

@@ -305,7 +305,7 @@ public class StepExecutionTests {
private StepExecution newStepExecution(Step step, Long jobExecutionId, long stepExecutionId) {
JobInstance job = new JobInstance(3L, "testJob");
StepExecution execution = new StepExecution(step.getName(), new JobExecution(job, jobExecutionId, new JobParameters()), stepExecutionId);
StepExecution execution = new StepExecution(step.getName(), new JobExecution(job, jobExecutionId, new JobParameters(), null), stepExecutionId);
return execution;
}

View File

@@ -22,7 +22,7 @@ import java.util.ArrayList;
import org.junit.Before;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
@@ -42,7 +42,7 @@ public abstract class AbstractJobParserTests {
@Autowired
private JobRepository jobRepository;
@Autowired
private MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean;
@@ -59,8 +59,8 @@ public abstract class AbstractJobParserTests {
* @return JobExecution
*/
protected JobExecution createJobExecution() throws JobInstanceAlreadyCompleteException, JobRestartException,
JobExecutionAlreadyRunningException {
return jobRepository.createJobExecution(job.getName(), new JobParameters());
JobExecutionAlreadyRunningException {
return jobRepository.createJobExecution(job.getName(), new JobParametersBuilder().addLong("key1", 1l).toJobParameters());
}
/**

View File

@@ -95,4 +95,15 @@ public class DummyJobRepository implements JobRepository, BeanNameAware {
public void addAll(Collection<StepExecution> stepExecutions) {
}
@Override
public JobInstance createJobInstance(String jobName,
JobParameters jobParameters) {
return null;
}
@Override
public JobExecution createJobExecution(JobInstance jobInstance,
JobParameters jobParameters, String jobConfigurationLocation) {
return null;
}
}

View File

@@ -0,0 +1,42 @@
package org.springframework.batch.core.converter;
import java.util.Map;
import java.util.Properties;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
public class JobParametersConverterSupport implements JobParametersConverter {
@Override
public JobParameters getJobParameters(Properties properties) {
JobParametersBuilder builder = new JobParametersBuilder();
if(properties != null) {
for (Map.Entry<Object, Object> curParameter : properties.entrySet()) {
if(curParameter.getValue() != null) {
builder.addString(curParameter.getKey().toString(), curParameter.getValue().toString(), false);
}
}
}
return builder.toJobParameters();
}
/* (non-Javadoc)
* @see org.springframework.batch.core.converter.JobParametersConverter#getProperties(org.springframework.batch.core.JobParameters)
*/
@Override
public Properties getProperties(JobParameters params) {
Properties properties = new Properties();
if(params != null) {
for(Map.Entry<String, JobParameter> curParameter: params.getParameters().entrySet()) {
properties.setProperty(curParameter.getKey(), curParameter.getValue().getValue().toString());
}
}
return properties;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2013 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.
@@ -16,11 +16,11 @@
package org.springframework.batch.core.explore.support;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
@@ -30,6 +30,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.repository.dao.ExecutionContextDao;
import org.springframework.batch.core.repository.dao.JobExecutionDao;
import org.springframework.batch.core.repository.dao.JobInstanceDao;
@@ -40,7 +41,7 @@ import org.springframework.batch.core.repository.dao.StepExecutionDao;
*
* @author Dave Syer
* @author Will Schipp
*
* @author Michael Minella
*
*/
public class SimpleJobExplorerTests {
@@ -57,7 +58,7 @@ public class SimpleJobExplorerTests {
private ExecutionContextDao ecDao;
private JobExecution jobExecution = new JobExecution(jobInstance, 1234L, new JobParameters());
private JobExecution jobExecution = new JobExecution(jobInstance, 1234L, new JobParameters(), null);
@Before
public void setUp() throws Exception {
@@ -93,13 +94,13 @@ public class SimpleJobExplorerTests {
when(jobInstanceDao.getJobInstance(jobExecution)).thenReturn(jobInstance);
StepExecution stepExecution = jobExecution.createStepExecution("foo");
when(stepExecutionDao.getStepExecution(jobExecution, 123L))
.thenReturn(stepExecution);
.thenReturn(stepExecution);
when(ecDao.getExecutionContext(stepExecution)).thenReturn(null);
stepExecution = jobExplorer.getStepExecution(jobExecution.getId(), 123L);
assertEquals(jobInstance,
stepExecution.getJobExecution().getJobInstance());
assertEquals(jobInstance,
stepExecution.getJobExecution().getJobInstance());
verify(jobInstanceDao).getJobInstance(jobExecution);
}
@@ -107,7 +108,7 @@ public class SimpleJobExplorerTests {
public void testGetStepExecutionMissing() throws Exception {
when(jobExecutionDao.getJobExecution(jobExecution.getId())).thenReturn(jobExecution);
when(stepExecutionDao.getStepExecution(jobExecution, 123L))
.thenReturn(null);
.thenReturn(null);
assertNull(jobExplorer.getStepExecution(jobExecution.getId(), 123L));
}
@@ -161,4 +162,17 @@ public class SimpleJobExplorerTests {
jobExplorer.getJobNames();
}
@Test
public void testGetJobInstanceCount() throws Exception {
when(jobInstanceDao.getJobInstanceCount("myJob")).thenReturn(4);
assertEquals(4, jobExplorer.getJobInstanceCount("myJob"));
}
@Test(expected=NoSuchJobException.class)
public void testGetJobInstanceCountException() throws Exception {
when(jobInstanceDao.getJobInstanceCount("throwException")).thenThrow(new NoSuchJobException("expected"));
jobExplorer.getJobInstanceCount("throwException");
}
}

View File

@@ -16,6 +16,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.converter.JobParametersConverter;
public class JobContextTests {
@@ -24,17 +25,19 @@ public class JobContextTests {
private JobExecution execution;
@Mock
private JobInstance instance;
@Mock
private JobParametersConverter converter;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
context = new JobContext(execution);
context = new JobContext(execution, converter);
when(execution.getJobInstance()).thenReturn(instance);
}
@Test(expected=IllegalArgumentException.class)
public void testCreateWithNull() {
context = new JobContext(null);
context = new JobContext(null, null);
}
@Test
@@ -69,8 +72,11 @@ public class JobContextTests {
JobParameters params = new JobParametersBuilder()
.addString("key1", "value1")
.toJobParameters();
Properties results = new Properties();
results.put("key1", "value1");
when(execution.getJobParameters()).thenReturn(params);
when(converter.getProperties(params)).thenReturn(results);
Properties props = context.getProperties();

View File

@@ -12,6 +12,7 @@ import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.converter.JobParametersConverterSupport;
public class JobExecutionTests {
@@ -34,12 +35,12 @@ public class JobExecutionTests {
execution.setStatus(BatchStatus.FAILED);
execution.setVersion(21);
adapter = new JobExecution(execution);
adapter = new JobExecution(execution, new JobParametersConverterSupport());
}
@Test(expected=IllegalArgumentException.class)
public void testCreateWithNull() {
adapter = new JobExecution(null);
adapter = new JobExecution(null, new JobParametersConverterSupport());
}
@Test

View File

@@ -0,0 +1,110 @@
package org.springframework.batch.core.jsr;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import javax.sql.DataSource;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
public class JsrJobParametersConverterTests {
private JsrJobParametersConverter converter;
private static DataSource dataSource;
@BeforeClass
public static void setupDatabase() {
dataSource = new EmbeddedDatabaseBuilder().
addScript("classpath:org/springframework/batch/core/schema-drop-hsqldb.sql").
addScript("classpath:org/springframework/batch/core/schema-hsqldb.sql").
build();
}
@Before
public void setUp() throws Exception {
converter = new JsrJobParametersConverter(dataSource);
converter.afterPropertiesSet();
}
@Test
public void testNullJobParameters() {
Properties props = converter.getProperties((JobParameters) null);
assertNotNull(props);
Set<Entry<Object, Object>> properties = props.entrySet();
assertEquals(1, properties.size());
assertTrue(props.containsKey(JsrJobParametersConverter.JOB_RUN_ID));
}
@Test
public void testStringJobParameters() {
JobParameters parameters = new JobParametersBuilder().addString("key", "value", false).toJobParameters();
Properties props = converter.getProperties(parameters);
assertNotNull(props);
Set<Entry<Object, Object>> properties = props.entrySet();
assertEquals(2, properties.size());
assertTrue(props.containsKey(JsrJobParametersConverter.JOB_RUN_ID));
assertEquals("value", props.getProperty("key"));
}
@Test
public void testNonStringJobParameters() {
JobParameters parameters = new JobParametersBuilder().addLong("key", 5l, false).toJobParameters();
Properties props = converter.getProperties(parameters);
assertNotNull(props);
Set<Entry<Object, Object>> properties = props.entrySet();
assertEquals(2, properties.size());
assertTrue(props.containsKey(JsrJobParametersConverter.JOB_RUN_ID));
assertEquals("5", props.getProperty("key"));
}
@Test
public void testJobParametersWithRunId() {
JobParameters parameters = new JobParametersBuilder().addLong("key", 5l, false).addLong(JsrJobParametersConverter.JOB_RUN_ID, 2l).toJobParameters();
Properties props = converter.getProperties(parameters);
assertNotNull(props);
Set<Entry<Object, Object>> properties = props.entrySet();
assertEquals(2, properties.size());
assertEquals("2", props.getProperty(JsrJobParametersConverter.JOB_RUN_ID));
assertEquals("5", props.getProperty("key"));
}
@Test
public void testNullProperties() {
JobParameters parameters = converter.getJobParameters((Properties)null);
assertNotNull(parameters);
assertEquals(1, parameters.getParameters().size());
assertTrue(parameters.getParameters().containsKey(JsrJobParametersConverter.JOB_RUN_ID));
}
@Test
public void testProperties() {
Properties properties = new Properties();
properties.put("key", "value");
JobParameters parameters = converter.getJobParameters(properties);
assertEquals(2, parameters.getParameters().size());
assertEquals("value", parameters.getString("key"));
assertTrue(parameters.getParameters().containsKey(JsrJobParametersConverter.JOB_RUN_ID));
}
@Test
public void testPropertiesWithRunId() {
Properties properties = new Properties();
properties.put("key", "value");
properties.put(JsrJobParametersConverter.JOB_RUN_ID, "3");
JobParameters parameters = converter.getJobParameters(properties);
assertEquals(2, parameters.getParameters().size());
assertEquals("value", parameters.getString("key"));
assertEquals(Long.valueOf(3l), parameters.getLong(JsrJobParametersConverter.JOB_RUN_ID));
assertTrue(parameters.getParameters().get(JsrJobParametersConverter.JOB_RUN_ID).isIdentifying());
}
}

View File

@@ -0,0 +1,24 @@
package org.springframework.batch.core.jsr;
import static org.junit.Assert.assertEquals;
import javax.batch.runtime.Metric;
import javax.batch.runtime.Metric.MetricType;
import org.junit.Test;
public class SimpleMetricTests {
@Test(expected=IllegalArgumentException.class)
public void testNullType() {
Metric metric = new SimpleMetric(null, 0);
}
@Test
public void test() {
Metric metric = new SimpleMetric(MetricType.FILTER_COUNT, 3);
assertEquals(3, metric.getValue());
assertEquals(MetricType.FILTER_COUNT, metric.getType());
}
}

View File

@@ -0,0 +1,95 @@
package org.springframework.batch.core.jsr;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.Properties;
import javax.batch.runtime.Metric;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.converter.JobParametersConverterSupport;
public class StepContextTests {
private StepExecution stepExecution;
private StepContext stepContext;
@Before
public void setUp() throws Exception {
JobExecution jobExecution = new JobExecution(1l, new JobParametersBuilder().addString("key", "value").toJobParameters());
stepExecution = new StepExecution("testStep", jobExecution);
stepExecution.setId(5l);
stepExecution.setStatus(BatchStatus.STARTED);
stepExecution.setExitStatus(new ExitStatus("customExitStatus"));
stepExecution.setCommitCount(1);
stepExecution.setFilterCount(2);
stepExecution.setProcessSkipCount(3);
stepExecution.setReadCount(4);
stepExecution.setReadSkipCount(5);
stepExecution.setRollbackCount(6);
stepExecution.setWriteCount(7);
stepExecution.setWriteSkipCount(8);
stepContext = new StepContext(stepExecution, new JobParametersConverterSupport());
stepContext.setTransientUserData("This is my transient data");
}
@Test
public void testBasicProperties() {
assertEquals(javax.batch.runtime.BatchStatus.STARTED, stepContext.getBatchStatus());
assertEquals("customExitStatus", stepContext.getExitStatus());
assertEquals(5l, stepContext.getStepExecutionId());
assertEquals("testStep", stepContext.getStepName());
assertEquals("This is my transient data", stepContext.getTransientUserData());
Properties params = stepContext.getProperties();
assertEquals("value", params.get("key"));
Metric[] metrics = stepContext.getMetrics();
for (Metric metric : metrics) {
switch (metric.getType()) {
case COMMIT_COUNT:
assertEquals(1, metric.getValue());
break;
case FILTER_COUNT:
assertEquals(2, metric.getValue());
break;
case PROCESS_SKIP_COUNT:
assertEquals(3, metric.getValue());
break;
case READ_COUNT:
assertEquals(4, metric.getValue());
break;
case READ_SKIP_COUNT:
assertEquals(5, metric.getValue());
break;
case ROLLBACK_COUNT:
assertEquals(6, metric.getValue());
break;
case WRITE_COUNT:
assertEquals(7, metric.getValue());
break;
case WRITE_SKIP_COUNT:
assertEquals(8, metric.getValue());
break;
default:
fail("Invalid metric type");
}
}
}
@Test
public void testSetExitStatus() {
stepContext.setExitStatus("new Exit Status");
assertEquals("new Exit Status", stepExecution.getExitStatus().getExitCode());
}
}

View File

@@ -0,0 +1,100 @@
package org.springframework.batch.core.jsr;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import java.util.Date;
import javax.batch.runtime.Metric;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.StepExecution;
public class StepExecutionTests {
private StepExecution stepExecution;
private javax.batch.runtime.StepExecution jsrStepExecution;
@Before
public void setUp() throws Exception {
JobExecution jobExecution = new JobExecution(1l, new JobParametersBuilder().addString("key", "value").toJobParameters());
stepExecution = new StepExecution("testStep", jobExecution);
stepExecution.setId(5l);
stepExecution.setStatus(BatchStatus.STARTED);
stepExecution.setExitStatus(new ExitStatus("customExitStatus"));
stepExecution.setCommitCount(1);
stepExecution.setFilterCount(2);
stepExecution.setProcessSkipCount(3);
stepExecution.setReadCount(4);
stepExecution.setReadSkipCount(5);
stepExecution.setRollbackCount(6);
stepExecution.setWriteCount(7);
stepExecution.setWriteSkipCount(8);
stepExecution.setStartTime(new Date(0));
stepExecution.setEndTime(new Date(10000000));
jsrStepExecution = new org.springframework.batch.core.jsr.StepExecution(stepExecution);
}
@Test(expected=IllegalArgumentException.class)
public void testWithNullStepExecution() {
new org.springframework.batch.core.jsr.StepExecution(null);
}
@Test
public void testNullExitStatus() {
stepExecution.setExitStatus(null);
assertNull(jsrStepExecution.getExitStatus());
}
@Test
public void testBaseValues() {
assertEquals(5l, jsrStepExecution.getStepExecutionId());
assertEquals("testStep", jsrStepExecution.getStepName());
assertEquals(javax.batch.runtime.BatchStatus.STARTED, jsrStepExecution.getBatchStatus());
assertEquals(new Date(0), jsrStepExecution.getStartTime());
assertEquals(new Date(10000000), jsrStepExecution.getEndTime());
assertEquals("customExitStatus", jsrStepExecution.getExitStatus());
Metric[] metrics = jsrStepExecution.getMetrics();
for (Metric metric : metrics) {
switch (metric.getType()) {
case COMMIT_COUNT:
assertEquals(1, metric.getValue());
break;
case FILTER_COUNT:
assertEquals(2, metric.getValue());
break;
case PROCESS_SKIP_COUNT:
assertEquals(3, metric.getValue());
break;
case READ_COUNT:
assertEquals(4, metric.getValue());
break;
case READ_SKIP_COUNT:
assertEquals(5, metric.getValue());
break;
case ROLLBACK_COUNT:
assertEquals(6, metric.getValue());
break;
case WRITE_COUNT:
assertEquals(7, metric.getValue());
break;
case WRITE_SKIP_COUNT:
assertEquals(8, metric.getValue());
break;
default:
fail("Invalid metric type");
}
}
}
}

View File

@@ -0,0 +1,340 @@
package org.springframework.batch.core.jsr.launch;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.batch.operations.JobExecutionIsRunningException;
import javax.batch.operations.JobOperator;
import javax.batch.operations.NoSuchJobException;
import javax.batch.operations.NoSuchJobExecutionException;
import javax.batch.operations.NoSuchJobInstanceException;
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.BatchStatus;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.converter.JobParametersConverterSupport;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.explore.support.SimpleJobExplorer;
import org.springframework.batch.core.launch.support.SimpleJobOperator;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.JobRepositorySupport;
public class JsrJobOperatorTests {
private JobOperator jsrJobOperator;
@Mock
private org.springframework.batch.core.launch.JobOperator jobOperator;
@Mock
private JobExplorer jobExplorer;
@Mock
private JobRepository jobRepository;
private JobParametersConverter parameterConverter;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
parameterConverter = new JobParametersConverterSupport();
jsrJobOperator = new JsrJobOperator(jobExplorer, jobRepository, jobOperator, parameterConverter);
}
@Test
public void testLoadingWithBatchRuntime() {
jsrJobOperator = BatchRuntime.getJobOperator();
assertNotNull(jsrJobOperator);
}
@Test
public void testNullsInConstructor() {
try {
new JsrJobOperator(null, new JobRepositorySupport(), new SimpleJobOperator(), parameterConverter);
fail("JobExplorer should be required");
} catch (IllegalArgumentException correct) {
}
try {
new JsrJobOperator(new SimpleJobExplorer(null, null, null, null), null, new SimpleJobOperator(), parameterConverter);
fail("JobRepository should be required");
} catch (IllegalArgumentException correct) {
}
try {
new JsrJobOperator(new SimpleJobExplorer(null, null, null, null), new JobRepositorySupport(), null, parameterConverter);
fail("JobOperator should be required");
} catch (IllegalArgumentException correct) {
}
try {
new JsrJobOperator(new SimpleJobExplorer(null, null, null, null), new JobRepositorySupport(), new SimpleJobOperator(), null);
fail("ParameterConverter should be required");
} catch (IllegalArgumentException correct) {
}
new JsrJobOperator(new SimpleJobExplorer(null, null, null, null), new JobRepositorySupport(), new SimpleJobOperator(), parameterConverter);
}
@Test
public void testAbandonRoseyScenario() throws Exception {
jsrJobOperator.abandon(5l);
verify(jobOperator).abandon(5l);
}
@Test(expected=NoSuchJobExecutionException.class)
public void testAbandonNoSuchJob() throws Exception {
when(jobOperator.abandon(5l)).thenThrow(new org.springframework.batch.core.launch.NoSuchJobExecutionException("expected"));
jsrJobOperator.abandon(5l);
}
@Test(expected=JobExecutionIsRunningException.class)
public void testAbandonJobRunning() throws Exception {
when(jobOperator.abandon(5l)).thenThrow(new JobExecutionAlreadyRunningException("expected"));
jsrJobOperator.abandon(5l);
}
@Test
public void testGetJobExecutionRoseyScenario() {
when(jobExplorer.getJobExecution(5l)).thenReturn(new JobExecution(5l));
assertEquals(5l, jsrJobOperator.getJobExecution(5l).getExecutionId());
}
@Test(expected=NoSuchJobExecutionException.class)
public void testGetJobExecutionNoExecutionFound() {
jsrJobOperator.getJobExecution(5l);
}
@Test
public void testGetJobExecutionsRoseyScenario() {
org.springframework.batch.core.JobInstance jobInstance = new org.springframework.batch.core.JobInstance(5l, "my job");
List<JobExecution> executions = new ArrayList<JobExecution>();
executions.add(new JobExecution(2l));
when(jobExplorer.getJobExecutions(jobInstance)).thenReturn(executions);
List<javax.batch.runtime.JobExecution> jobExecutions = jsrJobOperator.getJobExecutions(jobInstance);
assertEquals(1, jobExecutions.size());
assertEquals(2l, executions.get(0).getId().longValue());
}
@Test(expected=NoSuchJobInstanceException.class)
public void testGetJobExecutionsNullJobInstance() {
jsrJobOperator.getJobExecutions(null);
}
@Test(expected=NoSuchJobInstanceException.class)
public void testGetJobExecutionsNullReturned() {
org.springframework.batch.core.JobInstance jobInstance = new org.springframework.batch.core.JobInstance(5l, "my job");
jsrJobOperator.getJobExecutions(jobInstance);
}
@Test(expected=NoSuchJobInstanceException.class)
public void testGetJobExecutionsNoneReturned() {
org.springframework.batch.core.JobInstance jobInstance = new org.springframework.batch.core.JobInstance(5l, "my job");
List<JobExecution> executions = new ArrayList<JobExecution>();
when(jobExplorer.getJobExecutions(jobInstance)).thenReturn(executions);
jsrJobOperator.getJobExecutions(jobInstance);
}
@Test
public void testGetJobInstanceRoseyScenario() {
JobInstance instance = new JobInstance(1l, "my job");
JobExecution execution = new JobExecution(5l);
execution.setJobInstance(instance);
when(jobExplorer.getJobExecution(5l)).thenReturn(execution);
when(jobExplorer.getJobInstance(1l)).thenReturn(instance);
javax.batch.runtime.JobInstance jobInstance = jsrJobOperator.getJobInstance(5l);
assertEquals(1l, jobInstance.getInstanceId());
assertEquals("my job", jobInstance.getJobName());
}
@Test(expected=NoSuchJobExecutionException.class)
public void testGetJobInstanceNoExecution() {
JobInstance instance = new JobInstance(1l, "my job");
JobExecution execution = new JobExecution(5l);
execution.setJobInstance(instance);
jsrJobOperator.getJobInstance(5l);
}
@Test
public void testGetJobInstanceCount() throws Exception {
when(jobExplorer.getJobInstanceCount("myJob")).thenReturn(4);
assertEquals(4, jsrJobOperator.getJobInstanceCount("myJob"));
}
@Test(expected=NoSuchJobException.class)
public void testGetJobInstanceCountNoSuchJob() throws Exception {
when(jobExplorer.getJobInstanceCount("myJob")).thenThrow(new org.springframework.batch.core.launch.NoSuchJobException("expected"));
jsrJobOperator.getJobInstanceCount("myJob");
}
@Test
public void testGetJobInstancesRoseyScenario() {
List<JobInstance> instances = new ArrayList<JobInstance>();
instances.add(new JobInstance(1l, "myJob"));
instances.add(new JobInstance(2l, "myJob"));
instances.add(new JobInstance(3l, "myJob"));
when(jobExplorer.getJobInstances("myJob", 0, 3)).thenReturn(instances);
List<javax.batch.runtime.JobInstance> jobInstances = jsrJobOperator.getJobInstances("myJob", 0, 3);
assertEquals(3, jobInstances.size());
assertEquals(1l, jobInstances.get(0).getInstanceId());
assertEquals(2l, jobInstances.get(1).getInstanceId());
assertEquals(3l, jobInstances.get(2).getInstanceId());
}
@Test(expected=NoSuchJobException.class)
public void testGetJobInstancesNullInstancesReturned() {
jsrJobOperator.getJobInstances("myJob", 0, 3);
}
@Test(expected=NoSuchJobException.class)
public void testGetJobInstancesZeroInstancesReturned() {
List<JobInstance> instances = new ArrayList<JobInstance>();
when(jobExplorer.getJobInstances("myJob", 0, 3)).thenReturn(instances);
jsrJobOperator.getJobInstances("myJob", 0, 3);
}
@Test
public void testGetJobNames() {
List<String> jobNames = new ArrayList<String>();
jobNames.add("job1");
jobNames.add("job2");
when(jobExplorer.getJobNames()).thenReturn(jobNames);
Set<String> result = jsrJobOperator.getJobNames();
assertEquals(2, result.size());
assertTrue(result.contains("job1"));
assertTrue(result.contains("job2"));
}
@Test
public void testGetParametersRoseyScenario() {
JobExecution jobExecution = new JobExecution(5l, new JobParametersBuilder().addString("key1", "value1").toJobParameters());
when(jobExplorer.getJobExecution(5l)).thenReturn(jobExecution);
Properties params = jsrJobOperator.getParameters(5l);
assertEquals("value1", params.get("key1"));
}
@Test(expected=NoSuchJobExecutionException.class)
public void testGetParametersNoExecution() {
jsrJobOperator.getParameters(5l);
}
@Test
public void testGetRunningExecutions() {
Set<JobExecution> executions = new HashSet<JobExecution>();
executions.add(new JobExecution(5l));
when(jobExplorer.findRunningJobExecutions("myJob")).thenReturn(executions);
assertEquals(5l, jsrJobOperator.getRunningExecutions("myJob").get(0).longValue());
}
@Test
public void testGetStepExecutionsRoseyScenario() {
JobExecution jobExecution = new JobExecution(5l);
List<StepExecution> stepExecutions = new ArrayList<StepExecution>();
stepExecutions.add(new StepExecution("step1", jobExecution));
stepExecutions.add(new StepExecution("step2", jobExecution));
jobExecution.addStepExecutions(stepExecutions);
when(jobExplorer.getJobExecution(5l)).thenReturn(jobExecution);
List<javax.batch.runtime.StepExecution> results = jsrJobOperator.getStepExecutions(5l);
assertEquals("step1", results.get(0).getStepName());
assertEquals("step2", results.get(1).getStepName());
}
@Test(expected=NoSuchJobException.class)
public void testGetStepExecutionsNoExecutionReturned() {
jsrJobOperator.getStepExecutions(5l);
}
@Test
public void testGetStepExecutionsNoStepExecutions() {
JobExecution jobExecution = new JobExecution(5l);
when(jobExplorer.getJobExecution(5l)).thenReturn(jobExecution);
List<javax.batch.runtime.StepExecution> results = jsrJobOperator.getStepExecutions(5l);
assertEquals(0, results.size());
}
@Test
public void testStartRoseyScenario() {
jsrJobOperator = BatchRuntime.getJobOperator();
long executionId = jsrJobOperator.start("jsrJobOperatorTestJob", null);
assertEquals(BatchStatus.COMPLETED, jsrJobOperator.getJobExecution(executionId).getBatchStatus());
}
@Test
public void testStartMultipleTimesSameParameters() {
jsrJobOperator = BatchRuntime.getJobOperator();
long run1 = jsrJobOperator.start("jsrJobOperatorTestJob", null);
long run2 = jsrJobOperator.start("jsrJobOperatorTestJob", null);
long run3 = jsrJobOperator.start("jsrJobOperatorTestJob", null);
assertEquals(BatchStatus.COMPLETED, jsrJobOperator.getJobExecution(run1).getBatchStatus());
assertEquals(BatchStatus.COMPLETED, jsrJobOperator.getJobExecution(run2).getBatchStatus());
assertEquals(BatchStatus.COMPLETED, jsrJobOperator.getJobExecution(run3).getBatchStatus());
assertTrue(3 >= jsrJobOperator.getJobInstanceCount("jsrJobOperatorTestJob"));
}
@Test
public void testRestartRoseyScenario() {
jsrJobOperator = BatchRuntime.getJobOperator();
long executionId = jsrJobOperator.start("jsrJobOperatorTestRestartJob", null);
assertEquals(BatchStatus.FAILED, jsrJobOperator.getJobExecution(executionId).getBatchStatus());
long finalExecutionId = jsrJobOperator.restart(executionId, null);
assertEquals(BatchStatus.COMPLETED, jsrJobOperator.getJobExecution(finalExecutionId).getBatchStatus());
}
}

View File

@@ -0,0 +1,23 @@
package org.springframework.batch.core.jsr.step.batchlet;
import javax.batch.api.Batchlet;
public class RestartBatchlet implements Batchlet {
private static int runCount = 0;
@Override
public String process() throws Exception {
runCount++;
if(runCount == 1) {
throw new RuntimeException("This is expected");
}
return null;
}
@Override
public void stop() throws Exception {
}
}

View File

@@ -42,6 +42,7 @@ import org.springframework.batch.core.converter.DefaultJobParametersConverter;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.step.JobRepositorySupport;
import org.springframework.util.ClassUtils;
@@ -69,7 +70,7 @@ public class CommandLineJobRunnerTests {
@Before
public void setUp() throws Exception {
JobExecution jobExecution = new JobExecution(null, new Long(1), null);
JobExecution jobExecution = new JobExecution(null, new Long(1), null, null);
ExitStatus exitStatus = ExitStatus.COMPLETED;
jobExecution.setExitStatus(exitStatus);
StubJobLauncher.jobExecution = jobExecution;
@@ -284,7 +285,7 @@ public class CommandLineJobRunnerTests {
public void testRestartExecution() throws Throwable {
String[] args = new String[] { jobPath, "-restart", "11" };
JobParameters jobParameters = new JobParametersBuilder().addString("foo", "bar").toJobParameters();
JobExecution jobExecution = new JobExecution(new JobInstance(0L, jobName), 11L, jobParameters);
JobExecution jobExecution = new JobExecution(new JobInstance(0L, jobName), 11L, jobParameters, null);
jobExecution.setStatus(BatchStatus.FAILED);
StubJobExplorer.jobExecution = jobExecution;
CommandLineJobRunner.main(args);
@@ -296,7 +297,7 @@ public class CommandLineJobRunnerTests {
public void testRestartExecutionNotFailed() throws Throwable {
String[] args = new String[] { jobPath, "-restart", "11" };
JobParameters jobParameters = new JobParametersBuilder().addString("foo", "bar").toJobParameters();
JobExecution jobExecution = new JobExecution(new JobInstance(0L, jobName), 11L, jobParameters);
JobExecution jobExecution = new JobExecution(new JobInstance(0L, jobName), 11L, jobParameters, null);
jobExecution.setStatus(BatchStatus.COMPLETED);
StubJobExplorer.jobExecution = jobExecution;
CommandLineJobRunner.main(args);
@@ -451,7 +452,7 @@ public class CommandLineJobRunnerTests {
}
private JobExecution createJobExecution(JobInstance jobInstance, BatchStatus status) {
JobExecution jobExecution = new JobExecution(jobInstance, 1L, jobParameters);
JobExecution jobExecution = new JobExecution(jobInstance, 1L, jobParameters, null);
jobExecution.setStatus(status);
jobExecution.setStartTime(new Date());
if (status != BatchStatus.STARTED) {
@@ -485,6 +486,24 @@ public class CommandLineJobRunnerTests {
throw new UnsupportedOperationException();
}
@Override
public int getJobInstanceCount(String jobName)
throws NoSuchJobException {
int count = 0;
for (JobInstance jobInstance : jobInstances) {
if(jobInstance.getJobName().equals(jobName)) {
count++;
}
}
if(count == 0) {
throw new NoSuchJobException("Unable to find job instances for " + jobName);
} else {
return count;
}
}
}
public static class StubJobParametersConverter implements JobParametersConverter {

View File

@@ -15,13 +15,12 @@
*/
package org.springframework.batch.core.launch.support;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
@@ -112,7 +111,7 @@ public class SimpleJobOperatorTests {
@Override
public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException,
JobRestartException, JobInstanceAlreadyCompleteException {
return new JobExecution(new JobInstance(123L, job.getName()), 999L, jobParameters);
return new JobExecution(new JobInstance(123L, job.getName()), 999L, jobParameters, null);
}
});
@@ -192,7 +191,7 @@ public class SimpleJobOperatorTests {
@Test
public void testResumeSunnyDay() throws Exception {
jobParameters = new JobParameters();
when(jobExplorer.getJobExecution(111l)).thenReturn(new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters));
when(jobExplorer.getJobExecution(111l)).thenReturn(new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters, null));
jobExplorer.getJobExecution(111L);
Long value = jobOperator.restart(111L);
assertEquals(999, value.longValue());
@@ -201,7 +200,7 @@ public class SimpleJobOperatorTests {
@Test
public void testGetSummarySunnyDay() throws Exception {
jobParameters = new JobParameters();
JobExecution jobExecution = new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters);
JobExecution jobExecution = new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters, null);
when(jobExplorer.getJobExecution(111L)).thenReturn(jobExecution);
jobExplorer.getJobExecution(111L);
String value = jobOperator.getSummary(111L);
@@ -224,7 +223,7 @@ public class SimpleJobOperatorTests {
public void testGetStepExecutionSummariesSunnyDay() throws Exception {
jobParameters = new JobParameters();
JobExecution jobExecution = new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters);
JobExecution jobExecution = new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters, null);
jobExecution.createStepExecution("step1");
jobExecution.createStepExecution("step2");
jobExecution.getStepExecutions().iterator().next().setId(21L);
@@ -248,7 +247,7 @@ public class SimpleJobOperatorTests {
@Test
public void testFindRunningExecutionsSunnyDay() throws Exception {
jobParameters = new JobParameters();
JobExecution jobExecution = new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters);
JobExecution jobExecution = new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters, null);
when(jobExplorer.findRunningJobExecutions("foo")).thenReturn(Collections.singleton(jobExecution));
Set<Long> value = jobOperator.getRunningExecutions("foo");
assertEquals(111L, value.iterator().next().longValue());
@@ -269,7 +268,7 @@ public class SimpleJobOperatorTests {
@Test
public void testGetJobParametersSunnyDay() throws Exception {
final JobParameters jobParameters = new JobParameters();
when(jobExplorer.getJobExecution(111L)).thenReturn(new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters));
when(jobExplorer.getJobExecution(111L)).thenReturn(new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters, null));
String value = jobOperator.getParameters(111L);
assertEquals("a=b", value);
}
@@ -319,8 +318,8 @@ public class SimpleJobOperatorTests {
public void testGetExecutionsSunnyDay() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
when(jobExplorer.getJobInstance(123L)).thenReturn(jobInstance);
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters);
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
when(jobExplorer.getJobExecutions(jobInstance)).thenReturn(Collections.singletonList(jobExecution));
List<Long> value = jobOperator.getExecutions(123L);
assertEquals(111L, value.iterator().next().longValue());
@@ -341,7 +340,7 @@ public class SimpleJobOperatorTests {
@Test
public void testStop() throws Exception{
JobInstance jobInstance = new JobInstance(123L, job.getName());
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters);
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
when(jobExplorer.getJobExecution(111L)).thenReturn(jobExecution);
jobExplorer.getJobExecution(111L);
jobRepository.update(jobExecution);
@@ -352,7 +351,7 @@ public class SimpleJobOperatorTests {
@Test
public void testAbort() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters);
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
jobExecution.setStatus(BatchStatus.STOPPING);
when(jobExplorer.getJobExecution(123L)).thenReturn(jobExecution);
jobRepository.update(jobExecution);
@@ -364,7 +363,7 @@ public class SimpleJobOperatorTests {
@Test(expected = JobExecutionAlreadyRunningException.class)
public void testAbortNonStopping() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters);
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
jobExecution.setStatus(BatchStatus.STARTED);
when(jobExplorer.getJobExecution(123L)).thenReturn(jobExecution);
jobRepository.update(jobExecution);

View File

@@ -84,7 +84,6 @@ public abstract class AbstractJobDaoTests {
@Before
public void onSetUpInTransaction() throws Exception {
// Create job.
jobInstance = jobInstanceDao.createJobInstance(jobName, jobParameters);
@@ -119,7 +118,6 @@ public abstract class AbstractJobDaoTests {
@Transactional @Test
public void testFindJob() {
JobInstance instance = jobInstanceDao.getJobInstance(jobName, jobParameters);
assertNotNull(instance);
assertTrue(jobInstance.equals(instance));
@@ -187,7 +185,7 @@ public abstract class AbstractJobDaoTests {
public void testUpdateInvalidJobExecution() {
// id is invalid
JobExecution execution = new JobExecution(jobInstance, (long) 29432, jobParameters);
JobExecution execution = new JobExecution(jobInstance, (long) 29432, jobParameters, null);
execution.incrementVersion();
try {
jobExecutionDao.updateJobExecution(execution);

View File

@@ -188,7 +188,7 @@ public abstract class AbstractStepExecutionDaoTests extends AbstractTransactiona
@Transactional
@Test
public void testGetForNotExistingJobExecution() {
assertNull(dao.getStepExecution(new JobExecution(jobInstance, (long) 777, new JobParameters()), 11L));
assertNull(dao.getStepExecution(new JobExecution(jobInstance, (long) 777, new JobParameters(), null), 11L));
}
/**

View File

@@ -39,7 +39,7 @@ public class JdbcJobInstanceDaoTests extends AbstractJobInstanceDaoTests {
@Override
protected JobInstanceDao getJobInstanceDao() {
JdbcTestUtils.deleteFromTables(jdbcTemplate, "BATCH_JOB_EXECUTION_CONTEXT",
"BATCH_STEP_EXECUTION_CONTEXT", "BATCH_STEP_EXECUTION", "BATCH_JOB_EXECUTION_PARAMS",
"BATCH_STEP_EXECUTION_CONTEXT", "BATCH_STEP_EXECUTION", "BATCH_JOB_EXECUTION_PARAMS",
"BATCH_JOB_EXECUTION", "BATCH_JOB_INSTANCE");
return jobInstanceDao;
}
@@ -51,7 +51,7 @@ public class JdbcJobInstanceDaoTests extends AbstractJobInstanceDaoTests {
JobParameters jobParameters = new JobParameters();
JobInstance jobInstance = dao.createJobInstance("testInstance",
jobParameters);
JobExecution jobExecution = new JobExecution(jobInstance, 2L, jobParameters);
JobExecution jobExecution = new JobExecution(jobInstance, 2L, jobParameters, null);
jobExecutionDao.saveJobExecution(jobExecution);
JobInstance returnedInstance = dao.getJobInstance(jobExecution);

View File

@@ -50,7 +50,7 @@ import org.springframework.batch.core.step.StepSupport;
*
* @author Lucas Ward
* @author Will Schipp
*
*
*/
public class SimpleJobRepositoryTests {
@@ -117,7 +117,7 @@ public class SimpleJobRepositoryTests {
steps.add(databaseStep1);
steps.add(databaseStep2);
jobExecution = new JobExecution(new JobInstance(1L, job.getName()), 1L, jobParameters);
jobExecution = new JobExecution(new JobInstance(1L, job.getName()), 1L, jobParameters, null);
}
@Test
@@ -137,7 +137,7 @@ public class SimpleJobRepositoryTests {
@Test
public void testUpdateValidJobExecution() throws Exception {
JobExecution jobExecution = new JobExecution(new JobInstance(1L, job.getName()), 1L, jobParameters);
JobExecution jobExecution = new JobExecution(new JobInstance(1L, job.getName()), 1L, jobParameters, null);
// new execution - call update on job dao
jobExecutionDao.updateJobExecution(jobExecution);
jobRepository.update(jobExecution);

View File

@@ -35,7 +35,7 @@ import org.springframework.batch.core.JobParameters;
public class ChunkContextTests {
private ChunkContext context = new ChunkContext(new StepContext(new JobExecution(new JobInstance(0L,
"job"), 1L, new JobParameters(Collections.singletonMap("foo", new JobParameter("bar"))))
"job"), 1L, new JobParameters(Collections.singletonMap("foo", new JobParameter("bar"))), null)
.createStepExecution("foo")));
@Test

View File

@@ -40,7 +40,7 @@ public class StepContextTests {
private List<String> list = new ArrayList<String>();
private StepExecution stepExecution = new StepExecution("step", new JobExecution(new JobInstance(2L, "job"), 0L, null), 1L);
private StepExecution stepExecution = new StepExecution("step", new JobExecution(new JobInstance(2L, "job"), 0L, null, null), 1L);
private StepContext context = new StepContext(stepExecution);

View File

@@ -36,7 +36,7 @@ public class JobRepositorySupport implements JobRepository {
@Override
public JobExecution createJobExecution(String jobName, JobParameters jobParameters) {
JobInstance jobInstance = new JobInstance(0L, jobName);
return new JobExecution(jobInstance, 11L, jobParameters);
return new JobExecution(jobInstance, 11L, jobParameters, null);
}
/* (non-Javadoc)
@@ -103,4 +103,15 @@ public class JobRepositorySupport implements JobRepository {
public void addAll(Collection<StepExecution> stepExecutions) {
}
@Override
public JobInstance createJobInstance(String jobName,
JobParameters jobParameters) {
return null;
}
@Override
public JobExecution createJobExecution(JobInstance jobInstance,
JobParameters jobParameters, String jobConfigurationLocation) {
return null;
}
}

View File

@@ -471,6 +471,18 @@ public class TaskletStepExceptionTests {
@Override
public void addAll(Collection<StepExecution> stepExecutions) {
}
@Override
public JobInstance createJobInstance(String jobName,
JobParameters jobParameters) {
return null;
}
@Override
public JobExecution createJobExecution(JobInstance jobInstance,
JobParameters jobParameters, String jobConfigurationLocation) {
return null;
}
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<job id="myJob3" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
<step id="step1" >
<batchlet ref="testBatchlet" />
</step>
</job>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<job id="myJob3" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
<step id="step1" >
<batchlet ref="restartBatchlet" />
</step>
</job>

View File

@@ -0,0 +1,4 @@
<batch-artifacts xmlns="http://xmlns.jcp.org/xml/ns/javaee">
<ref id="testBatchlet" class="org.springframework.batch.core.jsr.step.batchlet.BatchletSupport" />
<ref id="restartBatchlet" class="org.springframework.batch.core.jsr.step.batchlet.RestartBatchlet" />
</batch-artifacts>

View File

@@ -28,6 +28,7 @@ CREATE TABLE PREFIX_JOB_EXECUTION (
EXIT_CODE VARCHAR(20) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
JOB_CONFIGURATION_LOCATION VARCHAR(500) NULL,
constraint PREFIX_JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references PREFIX_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;

View File

@@ -138,7 +138,7 @@ public class MetaDataInstanceFactory {
*/
public static JobExecution createJobExecution(String jobName, Long instanceId, Long executionId,
JobParameters jobParameters) {
return new JobExecution(createJobInstance(jobName, instanceId), executionId, jobParameters);
return new JobExecution(createJobInstance(jobName, instanceId), executionId, jobParameters, null);
}
/**