diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactory.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactory.java
index c866803ef..8d313217f 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactory.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactory.java
@@ -71,7 +71,7 @@ public class DefaultJobParametersFactory implements JobParametersFactory {
*/
public JobParameters getJobParameters(Properties props) {
- if(props == null || props.isEmpty()){
+ if (props == null || props.isEmpty()) {
return new JobParameters();
}
@@ -87,7 +87,9 @@ public class DefaultJobParametersFactory implements JobParametersFactory {
date = dateFormat.parse(value);
}
catch (ParseException ex) {
- throw new IllegalArgumentException("Date format is invalid: [" + value + "], use " + dateFormat, ex);
+ String suffix = (dateFormat instanceof SimpleDateFormat) ? ", use "
+ + ((SimpleDateFormat) dateFormat).toPattern() : "";
+ throw new IllegalArgumentException("Date format is invalid: [" + value + "]" + suffix, ex);
}
propertiesBuilder.addDate(StringUtils.replace(key, DATE_TYPE, ""), date);
}
@@ -97,8 +99,10 @@ public class DefaultJobParametersFactory implements JobParametersFactory {
result = (Long) numberFormat.parse(value);
}
catch (ParseException ex) {
+ String suffix = (numberFormat instanceof DecimalFormat) ? ", use "
+ + ((DecimalFormat) numberFormat).toPattern() : "";
throw new IllegalArgumentException(
- "Number format is invalid: [" + value + "], use " + numberFormat, ex);
+ "Number format is invalid: [" + value + "], use " + suffix, ex);
}
catch (ClassCastException ex) {
throw new IllegalArgumentException("Number format is invalid: [" + value
@@ -124,22 +128,24 @@ public class DefaultJobParametersFactory implements JobParametersFactory {
* @see org.springframework.batch.core.runtime.JobParametersFactory#getProperties(org.springframework.batch.core.domain.JobParameters)
*/
public Properties getProperties(JobParameters params) {
-
- if(params == null || params.isEmpty()){
+
+ if (params == null || params.isEmpty()) {
return new Properties();
}
-
+
Map parameters = params.getParameters();
Properties result = new Properties();
for (Iterator iterator = parameters.keySet().iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
Object value = parameters.get(key);
if (value instanceof Date) {
- result.setProperty(key+DATE_TYPE, dateFormat.format(value));
- } else if (value instanceof Long) {
- result.setProperty(key+LONG_TYPE, numberFormat.format(value));
- } else {
- result.setProperty(key,""+value);
+ result.setProperty(key + DATE_TYPE, dateFormat.format(value));
+ }
+ else if (value instanceof Long) {
+ result.setProperty(key + LONG_TYPE, numberFormat.format(value));
+ }
+ else {
+ result.setProperty(key, "" + value);
}
}
return result;
@@ -152,4 +158,14 @@ public class DefaultJobParametersFactory implements JobParametersFactory {
public void setDateFormat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
}
+
+ /**
+ * Public setter for the {@link NumberFormat}. Used to parse longs, so must
+ * not contain decimal place (e.g. use "#" or "#,###").
+ *
+ * @param numberFormat the {@link NumberFormat} to set
+ */
+ public void setNumberFormat(NumberFormat numberFormat) {
+ this.numberFormat = numberFormat;
+ }
}
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactory.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactory.java
index 4711ae0f5..356435ab4 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactory.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactory.java
@@ -58,7 +58,7 @@ public class ScheduledJobParametersFactory implements JobParametersFactory {
scheduleDate = dateFormat.parse(entry.getValue().toString());
}
catch (ParseException ex) {
- throw new IllegalArgumentException("Schedule date format is invalid: [" + entry.getValue() + "]",
+ throw new IllegalArgumentException("Date format is invalid: [" + entry.getValue() + "]",
ex);
}
propertiesBuilder.addDate(entry.getKey().toString(), scheduleDate);
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java
index a2cdb9949..d89d85034 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java
@@ -151,8 +151,9 @@ public abstract class AbstractStep extends StepSupport {
if (streamManager == null) {
manager = new SimpleStreamManager(transactionManager);
}
- SimpleStepExecutor executor = new SimpleStepExecutor(manager, this);
+ SimpleStepExecutor executor = new SimpleStepExecutor(this);
executor.setRepository(jobRepository);
+ executor.setStreamManager(manager);
executor.applyConfiguration(this);
executor.setTasklet(tasklet);
return executor;
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java
index b70ecb56e..d6cfff9da 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java
@@ -90,9 +90,8 @@ public class SimpleStepExecutor {
/**
* Package private constructor so the step can create a the executor.
*/
- SimpleStepExecutor(StreamManager streamManager, AbstractStep abstractStep) {
+ SimpleStepExecutor(AbstractStep abstractStep) {
this.step = abstractStep;
- this.streamManager = streamManager;
}
/**
@@ -393,16 +392,6 @@ public class SimpleStepExecutor {
/**
* Apply the configuration by inspecting it to see if it has any relevant
* policy information.
- *
- * - If the configuration is a {@link RepeatOperationsHolder} then we use
- * the provided {@link RepeatOperations} instances for chunk and step.
- * - If the configuration is a {@link SimpleStep} then we apply the
- * commit interval at the chunk level and the exception handler at the step
- * level, provided the existing repeat operations are instances of
- * {@link RepeatTemplate}. In addition if there is a non-zero skip limit
- * and no {@link ExceptionHandler} then we inject a
- * {@link SimpleLimitExceptionHandler} with that limit.
- *
*
* @param step a step
*/
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactoryTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactoryTests.java
index c082a3c85..5d76f5e46 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactoryTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactoryTests.java
@@ -16,6 +16,7 @@
package org.springframework.batch.execution.bootstrap.support;
import java.text.DateFormat;
+import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
@@ -52,6 +53,67 @@ public class DefaultJobParametersFactoryTests extends TestCase {
assertEquals(date, props.getDate("schedule.date"));
}
+ public void testGetParametersWithDateFormat() throws Exception {
+
+ String[] args = new String[] { "schedule.date(date)=2008/23/01" };
+
+ factory.setDateFormat(new SimpleDateFormat("yyyy/dd/MM"));
+ JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
+ assertNotNull(props);
+ Date date = dateFormat.parse("01/23/2008");
+ assertEquals(date, props.getDate("schedule.date"));
+ }
+
+ public void testGetParametersWithBogusDate() throws Exception {
+
+ String[] args = new String[] { "schedule.date(date)=20080123" };
+
+ try {
+ factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
+ } catch (IllegalArgumentException e) {
+ String message = e.getMessage();
+ assertTrue("Message should contain wrong date: "+message, message.contains("20080123"));
+ assertTrue("Message should contain format: "+message, message.contains("yyyy/MM/dd"));
+ }
+ }
+
+ public void testGetParametersWithNumberFormat() throws Exception {
+
+ String[] args = new String[] { "value(long)=1,000" };
+
+ factory.setNumberFormat(new DecimalFormat("#,###"));
+ JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
+ assertNotNull(props);
+ assertEquals(1000L, props.getLong("value").longValue());
+ }
+
+ public void testGetParametersWithBogusLong() throws Exception {
+
+ String[] args = new String[] { "value(long)=foo" };
+
+ try {
+ factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
+ } catch (IllegalArgumentException e) {
+ String message = e.getMessage();
+ assertTrue("Message should contain wrong number: "+message, message.contains("foo"));
+ assertTrue("Message should contain format: "+message, message.contains("#"));
+ }
+ }
+
+ public void testGetParametersWithDouble() throws Exception {
+
+ String[] args = new String[] { "value(long)=1.03" };
+ factory.setNumberFormat(new DecimalFormat("#.#"));
+
+ try {
+ factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
+ } catch (IllegalArgumentException e) {
+ String message = e.getMessage();
+ assertTrue("Message should contain wrong number: "+message, message.contains("1.03"));
+ assertTrue("Message should contain 'decimal': "+message, message.contains("decimal"));
+ }
+ }
+
public void testGetProperties() throws Exception {
JobParameters parameters = new JobParametersBuilder().addDate("schedule.date", dateFormat.parse("01/23/2008"))
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactoryTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactoryTests.java
index 50338ea23..ac6dc6fcf 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactoryTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactoryTests.java
@@ -80,4 +80,28 @@ public class ScheduledJobParametersFactoryTests extends TestCase {
assertEquals(new JobParameters(), factory.getJobParameters(null));
assertEquals(new Properties(), factory.getProperties(null));
}
+
+ public void testGetParametersWithDateFormat() throws Exception {
+
+ String[] args = new String[] { "schedule.date=2008/23/01" };
+
+ factory.setDateFormat(new SimpleDateFormat("yyyy/dd/MM"));
+ JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
+ assertNotNull(props);
+ Date date = dateFormat.parse("01/23/2008");
+ assertEquals(date, props.getDate("schedule.date"));
+ }
+
+ public void testGetParametersWithBogusDate() throws Exception {
+
+ String[] args = new String[] { "schedule.date=20080123" };
+
+ try {
+ factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
+ } catch (IllegalArgumentException e) {
+ String message = e.getMessage();
+ assertTrue("Message should contain wrong date: "+message, message.contains("20080123"));
+ }
+ }
+
}
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/SimpleExportedJobLauncherTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/SimpleExportedJobLauncherTests.java
new file mode 100644
index 000000000..b613bbb80
--- /dev/null
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/SimpleExportedJobLauncherTests.java
@@ -0,0 +1,208 @@
+/*
+ * 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.execution.bootstrap.support;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import org.springframework.batch.core.domain.Job;
+import org.springframework.batch.core.domain.JobExecution;
+import org.springframework.batch.core.domain.JobParameters;
+import org.springframework.batch.core.domain.JobParametersBuilder;
+import org.springframework.batch.core.domain.JobSupport;
+import org.springframework.batch.core.domain.StepExecution;
+import org.springframework.batch.core.domain.StepInstance;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.runtime.JobParametersFactory;
+import org.springframework.batch.execution.configuration.MapJobRegistry;
+import org.springframework.batch.execution.launch.JobLauncher;
+import org.springframework.batch.item.StreamContext;
+import org.springframework.batch.support.PropertiesConverter;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public class SimpleExportedJobLauncherTests extends TestCase {
+
+ private SimpleExportedJobLauncher launcher = new SimpleExportedJobLauncher();
+
+ private MapJobRegistry jobLocator;
+
+ private List list = new ArrayList();
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ launcher.setLauncher(new JobLauncher() {
+ public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException {
+ JobExecution result = new JobExecution(null);
+ StepExecution stepExecution = result.createStepExecution(new StepInstance(null, "step"));
+ stepExecution.setStreamContext(new StreamContext(PropertiesConverter.stringToProperties("foo=bar")));
+ list.add(jobParameters);
+ return result;
+ }
+ });
+ jobLocator = new MapJobRegistry();
+ launcher.setJobLocator(jobLocator);
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.bootstrap.support.SimpleExportedJobLauncher#afterPropertiesSet()}.
+ * @throws Exception
+ */
+ public void testAfterPropertiesSet() throws Exception {
+ launcher = new SimpleExportedJobLauncher();
+ try {
+ launcher.afterPropertiesSet();
+ fail("Expected IllegalArgumentException");
+ }
+ catch (IllegalArgumentException e) {
+ String message = e.getMessage();
+ assertTrue("Message does not contain 'launcher': " + message, message.toLowerCase().contains("joblauncher"));
+ }
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.bootstrap.support.SimpleExportedJobLauncher#afterPropertiesSet()}.
+ * @throws Exception
+ */
+ public void testAfterPropertiesSetWithLauncher() throws Exception {
+ launcher = new SimpleExportedJobLauncher();
+ launcher.setLauncher(new JobLauncher() {
+ public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException {
+ return null;
+ }
+ });
+ try {
+ launcher.afterPropertiesSet();
+ fail("Expected IllegalArgumentException");
+ }
+ catch (IllegalArgumentException e) {
+ String message = e.getMessage();
+ assertTrue("Message does not contain 'locator': " + message, message.toLowerCase().contains("joblocator"));
+ }
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.bootstrap.support.SimpleExportedJobLauncher#getStatistics()}.
+ */
+ public void testGetStatistics() {
+ Properties props = launcher.getStatistics();
+ assertNotNull(props);
+ assertEquals(0, props.entrySet().size());
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.bootstrap.support.SimpleExportedJobLauncher#getStatistics()}.
+ * @throws Exception
+ */
+ public void testGetStatisticsWithContent() throws Exception {
+ jobLocator.register(new JobSupport("foo"));
+ launcher.run("foo");
+ Properties props = launcher.getStatistics();
+ assertNotNull(props);
+ assertEquals(1, props.entrySet().size());
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.bootstrap.support.SimpleExportedJobLauncher#isRunning()}.
+ * @throws Exception
+ */
+ public void testIsRunning() throws Exception {
+ jobLocator.register(new JobSupport("foo"));
+ launcher.run("foo");
+ assertTrue(launcher.isRunning());
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.bootstrap.support.SimpleExportedJobLauncher#isRunning()}.
+ * @throws Exception
+ */
+ public void testAlreadyRunning() throws Exception {
+ jobLocator.register(new JobSupport("foo"));
+ launcher.setLauncher(new JobLauncher() {
+ public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException {
+ throw new JobExecutionAlreadyRunningException("Bad!");
+ }
+ });
+ String value = launcher.run("foo");
+ assertTrue("Return value was not an exception: " + value, value.contains("JobExecutionAlreadyRunningException"));
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.bootstrap.support.SimpleExportedJobLauncher#run(java.lang.String)}.
+ */
+ public void testRunNonExistentJob() {
+ String value = launcher.run("foo");
+ assertTrue("Return value was not an exception: " + value, value.contains("NoSuchJobException"));
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.bootstrap.support.SimpleExportedJobLauncher#run(java.lang.String)}.
+ * @throws Exception
+ */
+ public void testRunJobWithParameters() throws Exception {
+ jobLocator.register(new JobSupport("foo"));
+ String value = launcher.run("foo", "bar=spam,bucket=crap");
+ assertTrue(launcher.isRunning());
+ assertTrue("Return value was not a JobExecution: " + value, value.contains("JobExecution"));
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.bootstrap.support.SimpleExportedJobLauncher#run(java.lang.String)}.
+ * @throws Exception
+ */
+ public void testRunJobWithParametersAndFactory() throws Exception {
+ jobLocator.register(new JobSupport("foo"));
+ launcher.setJobParametersFactory(new JobParametersFactory() {
+ public JobParameters getJobParameters(Properties properties) {
+ return new JobParametersBuilder().addString("foo", "spam").toJobParameters();
+ }
+ public Properties getProperties(JobParameters params) {
+ return null;
+ }
+ });
+ launcher.run("foo", "bar=spam,bucket=crap");
+ assertEquals(1, list.size());
+ assertEquals("spam", ((JobParameters) list.get(0)).getString("foo"));
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.bootstrap.support.SimpleExportedJobLauncher#stop()}.
+ * @throws Exception
+ */
+ public void testStop() throws Exception {
+ jobLocator.register(new JobSupport("foo"));
+ launcher.run("foo");
+ assertTrue(launcher.isRunning());
+ launcher.stop();
+ assertFalse(launcher.isRunning());
+ }
+
+}