OPEN - issue BATCH-773: Refactor and extend ExportedJobLauncher to JobOperator

More thorough tests and changed parameter values to long (not Long)
This commit is contained in:
dsyer
2008-08-18 08:29:58 +00:00
parent 2357b89b58
commit 2da35c8f00
9 changed files with 244 additions and 31 deletions

View File

@@ -38,18 +38,18 @@ import org.springframework.batch.core.repository.JobRestartException;
*/
public interface JobOperator {
List<Long> getExecutions(Long instanceId) throws NoSuchJobException;
List<Long> getExecutions(long instanceId) throws NoSuchJobInstanceException;
List<Long> getLastInstances(String jobName, int count) throws NoSuchJobException;
Set<Long> getRunningExecutions(String jobName) throws NoSuchJobException;
String getParameters(Long executionId) throws NoSuchJobExecutionException;
String getParameters(long executionId) throws NoSuchJobExecutionException;
Long start(String jobName, String parameters) throws NoSuchJobException, JobInstanceAlreadyExistsException,
JobRestartException;
Long resume(Long executionId) throws JobInstanceAlreadyCompleteException, NoSuchJobExecutionException,
Long resume(long executionId) throws JobInstanceAlreadyCompleteException, NoSuchJobExecutionException,
NoSuchJobException, JobRestartException;
/**
@@ -73,11 +73,11 @@ public interface JobOperator {
Long startNextInstance(String jobName) throws NoSuchJobException, JobParametersNotFoundException,
JobRestartException, JobExecutionAlreadyRunningException, JobInstanceAlreadyCompleteException;
boolean stop(Long executionId) throws NoSuchJobExecutionException;
boolean stop(long executionId) throws NoSuchJobExecutionException;
String getSummary(Long executionId) throws NoSuchJobExecutionException;
String getSummary(long executionId) throws NoSuchJobExecutionException;
Map<Long, String> getStepExecutionSummaries(Long executionId) throws NoSuchJobExecutionException;
Map<Long, String> getStepExecutionSummaries(long executionId) throws NoSuchJobExecutionException;
Set<String> getJobNames();

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2006-2007 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.launch.support;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* @author Dave Syer
*
*/
public class RuntimeExceptionTranslator implements MethodInterceptor {
/* (non-Javadoc)
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
try {
return invocation.proceed();
} catch (Exception e) {
if (e.getClass().getName().startsWith("java")) {
throw e;
}
throw new RuntimeException(e.getClass().getSimpleName()+ ": " + e.getMessage());
}
}
}

View File

@@ -42,6 +42,7 @@ import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.launch.JobParametersNotFoundException;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.launch.NoSuchJobExecutionException;
import org.springframework.batch.core.launch.NoSuchJobInstanceException;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
@@ -121,10 +122,10 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
* org.springframework.batch.core.launch.JobOperator#getExecutions(java.
* lang.Long)
*/
public List<Long> getExecutions(Long instanceId) throws NoSuchJobException {
public List<Long> getExecutions(long instanceId) throws NoSuchJobInstanceException {
JobInstance jobInstance = jobExplorer.getJobInstance(instanceId);
if (jobInstance == null) {
throw new NoSuchJobException(String.format("No job instance with id=%d", instanceId));
throw new NoSuchJobInstanceException(String.format("No job instance with id=%d", instanceId));
}
List<Long> list = new ArrayList<Long>();
for (JobExecution jobExecution : jobExplorer.findJobExecutions(jobInstance)) {
@@ -154,6 +155,9 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
for (JobInstance jobInstance : jobExplorer.getLastJobInstances(jobName, count)) {
list.add(jobInstance.getId());
}
if (list.isEmpty() && !jobRegistry.getJobNames().contains(jobName)) {
throw new NoSuchJobException("No such job (either in registry or in historical data): "+jobName);
}
return list;
}
@@ -164,7 +168,7 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
* org.springframework.batch.core.launch.JobOperator#getParameters(java.
* lang.Long)
*/
public String getParameters(Long executionId) throws NoSuchJobExecutionException {
public String getParameters(long executionId) throws NoSuchJobExecutionException {
JobExecution jobExecution = jobExplorer.getJobExecution(executionId);
if (jobExecution == null) {
throw new NoSuchJobExecutionException(String.format("No job execution with id=%d", executionId));
@@ -185,6 +189,9 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
for (JobExecution jobExecution : jobExplorer.findRunningJobExecutions(jobName)) {
set.add(jobExecution.getId());
}
if (set.isEmpty() && !jobRegistry.getJobNames().contains(jobName)) {
throw new NoSuchJobException("No such job (either in registry or in historical data): "+jobName);
}
return set;
}
@@ -195,7 +202,7 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
* org.springframework.batch.core.launch.JobOperator#getStepExecutionSummaries
* (java.lang.Long)
*/
public Map<Long, String> getStepExecutionSummaries(Long executionId) throws NoSuchJobExecutionException {
public Map<Long, String> getStepExecutionSummaries(long executionId) throws NoSuchJobExecutionException {
JobExecution jobExecution = jobExplorer.getJobExecution(executionId);
if (jobExecution == null) {
throw new NoSuchJobExecutionException(String.format("No job execution with id=%d", executionId));
@@ -214,7 +221,7 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
* org.springframework.batch.core.launch.JobOperator#getSummary(java.lang
* .Long)
*/
public String getSummary(Long executionId) throws NoSuchJobExecutionException {
public String getSummary(long executionId) throws NoSuchJobExecutionException {
JobExecution jobExecution = jobExplorer.getJobExecution(executionId);
if (jobExecution == null) {
throw new NoSuchJobExecutionException(String.format("No job execution with id=%d", executionId));
@@ -228,7 +235,7 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
* @see
* org.springframework.batch.core.launch.JobOperator#resume(java.lang.Long)
*/
public Long resume(Long executionId) throws JobInstanceAlreadyCompleteException, NoSuchJobExecutionException,
public Long resume(long executionId) throws JobInstanceAlreadyCompleteException, NoSuchJobExecutionException,
NoSuchJobException, JobRestartException {
logger.info("Checking status of job execution with id=" + executionId);
@@ -348,7 +355,7 @@ public class SimpleJobOperator implements JobOperator, InitializingBean {
* @see
* org.springframework.batch.core.launch.JobOperator#stop(java.lang.Long)
*/
public boolean stop(Long executionId) throws NoSuchJobExecutionException {
public boolean stop(long executionId) throws NoSuchJobExecutionException {
throw new UnsupportedOperationException("See BATCH-453 for implementation.");
}

View File

@@ -14,6 +14,7 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
@@ -224,20 +225,29 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
/*
* (non-Javadoc)
* @see org.springframework.batch.core.repository.dao.JobExecutionDao#getLastJobExecution(java.lang.String)
*
* @seeorg.springframework.batch.core.repository.dao.JobExecutionDao#
* getLastJobExecution(java.lang.String)
*/
public JobExecution getJobExecution(Long executionId) {
Long instanceId = getJdbcTemplate().queryForLong(getQuery(GET_INSTANCE_BY_EXECUTION_ID), executionId);
JobInstance jobInstance = jobInstanceDao.getJobInstance(instanceId);
JobExecution jobExecution = getJdbcTemplate().queryForObject(getQuery(GET_EXECUTION_BY_ID), new JobExecutionRowMapper(jobInstance),
executionId);
stepExecutionDao.getStepExecutions(jobExecution);
return jobExecution;
try {
Long instanceId = getJdbcTemplate().queryForLong(getQuery(GET_INSTANCE_BY_EXECUTION_ID), executionId);
JobInstance jobInstance = jobInstanceDao.getJobInstance(instanceId);
JobExecution jobExecution = getJdbcTemplate().queryForObject(getQuery(GET_EXECUTION_BY_ID),
new JobExecutionRowMapper(jobInstance), executionId);
stepExecutionDao.getStepExecutions(jobExecution);
return jobExecution;
}
catch (EmptyResultDataAccessException e) {
return null;
}
}
/*
* (non-Javadoc)
* @see org.springframework.batch.core.repository.dao.JobExecutionDao#findRunningJobExecutions(java.lang.String)
*
* @seeorg.springframework.batch.core.repository.dao.JobExecutionDao#
* findRunningJobExecutions(java.lang.String)
*/
public Set<JobExecution> findRunningJobExecutions(String jobName) {
@@ -251,7 +261,7 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements
}
};
getJdbcTemplate().getJdbcOperations().query(getQuery(GET_RUNNING_EXECUTIONS), handler);
for (JobExecution jobExecution : result) {
stepExecutionDao.getStepExecutions(jobExecution);
}

View File

@@ -16,6 +16,7 @@ import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParameter.ParameterType;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
@@ -183,7 +184,12 @@ public class JdbcJobInstanceDao extends AbstractJdbcBatchMetadataDao implements
final JobParameters jobParameters = getJobParameters(instanceId);
ParameterizedRowMapper<JobInstance> rowMapper = new JobInstanceRowMapper(jobParameters);
return getJdbcTemplate().queryForObject(getQuery(GET_JOB_FROM_ID), rowMapper, instanceId);
try {
return getJdbcTemplate().queryForObject(getQuery(GET_JOB_FROM_ID), rowMapper, instanceId);
}
catch (EmptyResultDataAccessException e) {
return null;
}
}

View File

@@ -42,6 +42,8 @@ import org.springframework.batch.core.job.JobSupport;
import org.springframework.batch.core.launch.JobInstanceAlreadyExistsException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.launch.NoSuchJobExecutionException;
import org.springframework.batch.core.launch.NoSuchJobInstanceException;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
@@ -89,9 +91,10 @@ public class SimpleJobOperatorTests {
}
throw new NoSuchJobException("foo");
}
@Override
public Collection<String> getJobNames() {
return Arrays.asList(new String[] {"foo", "bar"});
return Arrays.asList(new String[] { "foo", "bar" });
}
});
@@ -214,6 +217,21 @@ public class SimpleJobOperatorTests {
EasyMock.verify(jobExplorer);
}
@Test
public void testGetSummaryNoSuchExecution() throws Exception {
jobParameters = new JobParameters();
jobExplorer.getJobExecution(111L);
EasyMock.expectLastCall().andReturn(null);
EasyMock.replay(jobExplorer);
try {
jobOperator.getSummary(111L);
fail("Expected NoSuchJobExecutionException");
} catch (NoSuchJobExecutionException e) {
// expected
}
EasyMock.verify(jobExplorer);
}
@Test
public void testGetStepExecutionSummariesSunnyDay() throws Exception {
jobParameters = new JobParameters();
@@ -229,6 +247,21 @@ public class SimpleJobOperatorTests {
EasyMock.verify(jobExplorer);
}
@Test
public void testGetStepExecutionSummariesNoSuchExecution() throws Exception {
jobParameters = new JobParameters();
jobExplorer.getJobExecution(111L);
EasyMock.expectLastCall().andReturn(null);
EasyMock.replay(jobExplorer);
try {
jobOperator.getStepExecutionSummaries(111L);
fail("Expected NoSuchJobExecutionException");
} catch (NoSuchJobExecutionException e) {
// expected
}
EasyMock.verify(jobExplorer);
}
@Test
public void testFindRunningExecutionsSunnyDay() throws Exception {
jobParameters = new JobParameters();
@@ -241,6 +274,21 @@ public class SimpleJobOperatorTests {
EasyMock.verify(jobExplorer);
}
@Test
public void testFindRunningExecutionsNoSuchJob() throws Exception {
jobParameters = new JobParameters();
jobExplorer.findRunningJobExecutions("no-such-job");
EasyMock.expectLastCall().andReturn(Collections.emptySet());
EasyMock.replay(jobExplorer);
try {
jobOperator.getRunningExecutions("no-such-job");
fail("Expected NoSuchJobException");
} catch (NoSuchJobException e) {
// expected
}
EasyMock.verify(jobExplorer);
}
@Test
public void testGetJobParametersSunnyDay() throws Exception {
final JobParameters jobParameters = new JobParameters();
@@ -253,23 +301,53 @@ public class SimpleJobOperatorTests {
EasyMock.verify(jobExplorer);
}
@Test
public void testGetJobParametersNoSuchExecution() throws Exception {
jobExplorer.getJobExecution(111L);
EasyMock.expectLastCall().andReturn(null);
EasyMock.replay(jobExplorer);
try {
jobOperator.getParameters(111L);
fail("Expected NoSuchJobExecutionException");
} catch (NoSuchJobExecutionException e) {
// expected
}
EasyMock.verify(jobExplorer);
}
@Test
public void testGetLastInstancesSunnyDay() throws Exception {
jobParameters = new JobParameters();
jobExplorer.getLastJobInstances("foo",2);
jobExplorer.getLastJobInstances("foo", 2);
JobInstance jobInstance = new JobInstance(123L, jobParameters, job.getName());
EasyMock.expectLastCall().andReturn(Collections.singletonList(jobInstance));
EasyMock.replay(jobExplorer);
List<Long> value = jobOperator.getLastInstances("foo",2);
List<Long> value = jobOperator.getLastInstances("foo", 2);
assertEquals(123L, value.get(0).longValue());
EasyMock.verify(jobExplorer);
}
@Test
public void testGetLastInstancesNoSuchJob() throws Exception {
jobParameters = new JobParameters();
jobExplorer.getLastJobInstances("no-such-job", 2);
EasyMock.expectLastCall().andReturn(Collections.emptyList());
EasyMock.replay(jobExplorer);
try {
jobOperator.getLastInstances("no-such-job", 2);
fail("Expected NoSuchJobException");
}
catch (NoSuchJobException e) {
// expected
}
EasyMock.verify(jobExplorer);
}
@Test
public void testGetJobNames() throws Exception {
Set<String> names = jobOperator.getJobNames();
assertEquals(2, names.size());
assertTrue("Wrong names: "+names, names.contains("foo"));
assertTrue("Wrong names: " + names, names.contains("foo"));
}
@Test
@@ -286,4 +364,19 @@ public class SimpleJobOperatorTests {
EasyMock.verify(jobExplorer);
}
@Test
public void testGetExecutionsNoSuchInstance() throws Exception {
jobExplorer.getJobInstance(123L);
EasyMock.expectLastCall().andReturn(null);
EasyMock.replay(jobExplorer);
try {
jobOperator.getExecutions(123L);
fail("Expected NoSuchJobInstanceException");
}
catch (NoSuchJobInstanceException e) {
// expected
}
EasyMock.verify(jobExplorer);
}
}

View File

@@ -52,10 +52,20 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional
dao.saveJobExecution(execution);
List<JobExecution> executions = dao.findJobExecutions(jobInstance);
assertTrue(executions.size() == 1);
assertEquals(1, executions.size());
assertEquals(execution, executions.get(0));
}
/**
* Save and find a job execution.
*/
@Transactional
@Test
public void testFindNonExistentExecutions() {
List<JobExecution> executions = dao.findJobExecutions(jobInstance);
assertEquals(0, executions.size());
}
/**
* Saving sets id to the entity.
*/
@@ -107,6 +117,16 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional
assertEquals(exec2, last);
}
/**
* Check the execution is returned
*/
@Transactional
@Test
public void testGetMissingLastExecution() {
JobExecution value = dao.getLastJobExecution(jobInstance);
assertNull(value);
}
/**
* Check the execution is returned
*/
@@ -134,6 +154,16 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional
assertEquals(1, value.getStepExecutions().size());
}
/**
* Check the execution is returned
*/
@Transactional
@Test
public void testNoRunningExecutions() {
Set<JobExecution> values = dao.findRunningJobExecutions("no-such-job");
assertEquals(0, values.size());
}
/**
* Check the execution is returned
*/
@@ -157,4 +187,13 @@ public abstract class AbstractJobExecutionDaoTests extends AbstractTransactional
assertEquals(1, value.getStepExecutions().size());
}
/**
* Check the execution is returned
*/
@Transactional
@Test
public void testGetMissingExecution() {
JobExecution value = dao.getJobExecution(54321L);
assertNull(value);
}
}

View File

@@ -83,6 +83,17 @@ public abstract class AbstractJobInstanceDaoTests extends AbstractTransactionalJ
assertEquals(new Date(DATE), retrievedParams.getDate("dateKey"));
}
/*
* Create and retrieve a job instance.
*/
@Transactional @Test
public void testGetMissingById() throws Exception {
JobInstance retrievedInstance = dao.getJobInstance(1111111L);
assertNull(retrievedInstance);
}
/*
* Create and retrieve a job instance.
*/

View File

@@ -9,7 +9,12 @@
<bean class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="spring:service=batch,bean=jobOperator" value-ref="jobOperator" />
<entry key="spring:service=batch,bean=jobOperator">
<bean class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="jobOperator" />
<property name="interceptorNames" value="exceptionTranslator" />
</bean>
</entry>
<entry key="spring:service=batch,bean=notificationPublisher" value-ref="notificationPublisher" />
<entry key="spring:service=batch,bean=jobLoader" value-ref="loader" />
</map>
@@ -18,7 +23,7 @@
<bean class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
<property name="interfaceMappings">
<map>
<entry key="spring:service=batch,bean=jobLauncher" value="org.springframework.batch.core.launch.JobOperator" />
<entry key="spring:service=batch,bean=jobOperator" value="org.springframework.batch.core.launch.JobOperator" />
<entry key="spring:service=batch,bean=jobLoader" value="org.springframework.batch.sample.launch.JobLoader" />
</map>
</property>
@@ -43,6 +48,7 @@
</bean>
</property>
</bean>
<bean id="exceptionTranslator" class="org.springframework.batch.core.launch.support.RuntimeExceptionTranslator" />
<bean id="loader" class="org.springframework.batch.sample.launch.DefaultJobLoader">
<property name="registry" ref="jobRegistry" />
</bean>