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 new file mode 100644 index 000000000..bf283cf44 --- /dev/null +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactory.java @@ -0,0 +1,149 @@ +/* + * Copyright 2006-2008 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.text.DateFormat; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.Map.Entry; + +import org.springframework.batch.core.domain.JobParameters; +import org.springframework.batch.core.domain.JobParametersBuilder; +import org.springframework.batch.core.runtime.JobParametersFactory; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Factory for {@link JobParameters} instances using a simple naming convention + * for property keys. Key names ending with "(<type>)" where type is one + * of string, date, long are converted to the corresponding type. The default + * type is string. E.g. + * + *
+ * schedule.date(date)=2007/12/11
+ * department.id(long)=2345
+ * 
+ * + * The literal values are converted to the correct type using the default Spring + * strategies, augmented if necessary by the custom editors provided. + * + * @author Dave Syer + * + */ +public class DefaultJobParametersFactory implements JobParametersFactory { + + public static String DATE_TYPE = "(date)"; + + public static String STRING_TYPE = "(string)"; + + public static String LONG_TYPE = "(long)"; + + private DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); + + private NumberFormat numberFormat = new DecimalFormat("#"); + + /** + * Check for suffix on keys and use those to decide how to convert the + * value. + * + * @throws IllegalArgumentException if a number or date is passed in that + * cannot be parsed, or cast to the correct type. + * + * @see org.springframework.batch.core.runtime.JobParametersFactory#getJobParameters(java.util.Properties) + */ + public JobParameters getJobParameters(Properties props) { + + Assert.notNull(props, "Factory arguments must not be null."); + + JobParametersBuilder propertiesBuilder = new JobParametersBuilder(); + + for (Iterator it = props.entrySet().iterator(); it.hasNext();) { + Entry entry = (Entry) it.next(); + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + if (key.endsWith(DATE_TYPE)) { + Date date; + try { + date = dateFormat.parse(value); + } + catch (ParseException ex) { + throw new IllegalArgumentException("Date format is invalid: [" + value + "], use " + dateFormat, ex); + } + propertiesBuilder.addDate(StringUtils.replace(key, DATE_TYPE, ""), date); + } + else if (key.endsWith(LONG_TYPE)) { + Long result; + try { + result = (Long) numberFormat.parse(value); + } + catch (ParseException ex) { + throw new IllegalArgumentException( + "Number format is invalid: [" + value + "], use " + numberFormat, ex); + } + catch (ClassCastException ex) { + throw new IllegalArgumentException("Number format is invalid: [" + value + + "], use a format with no decimal places", ex); + } + propertiesBuilder.addLong(StringUtils.replace(key, LONG_TYPE, ""), result); + } + else if (StringUtils.endsWithIgnoreCase(key, STRING_TYPE)) { + propertiesBuilder.addString(StringUtils.replace(key, STRING_TYPE, ""), value); + } + else { + propertiesBuilder.addString(key.toString(), value.toString()); + } + } + + return propertiesBuilder.toJobParameters(); + } + + /** + * Use the same suffixes to create properties (omitting the string suffix + * because it is the default). + * + * @see org.springframework.batch.core.runtime.JobParametersFactory#getProperties(org.springframework.batch.core.domain.JobParameters) + */ + public Properties getProperties(JobParameters params) { + 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); + } + } + return result; + } + + /** + * Public setter for injecting a date format. + * @param dateFormat a {@link DateFormat}, defaults to "yyyy/MM/dd" + */ + public void setDateFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } +} diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/JobParametersPropertyEditor.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/JobParametersPropertyEditor.java index adcb01023..38890d0ba 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/JobParametersPropertyEditor.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/JobParametersPropertyEditor.java @@ -15,38 +15,24 @@ */ package org.springframework.batch.execution.bootstrap.support; +import java.beans.PropertyEditor; import java.beans.PropertyEditorSupport; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; import java.util.Properties; import org.springframework.batch.core.domain.JobParameters; -import org.springframework.batch.core.domain.JobParametersBuilder; +import org.springframework.batch.core.runtime.JobParametersFactory; +import org.springframework.batch.support.PropertiesConverter; import org.springframework.util.StringUtils; /** - * Factory for {@link JobParameters} instances using a simple naming convention - * for property keys. Key names ending with "(<type>)" where type is one - * of string, date, long are converted to the corresponding type. The default - * type is string. E.g. - * - *
- * schedule.date(date)=2007/12/11
- * department.id(long)=2345
- * 
- * - * The literal values are converted to the correct type using the default Spring - * strategies, augmented if necessary by the custom editors provided. - * - * TODO: finish this (only supports Strings so far). - * + * A {@link PropertyEditor} that delegates to a {@link JobParametersFactory}. * @author Dave Syer * */ public class JobParametersPropertyEditor extends PropertyEditorSupport { + private JobParametersFactory factory = new DefaultJobParametersFactory(); + /** * Accept properties in the form of name=value pairs, delimited by either * comma or new line (or both) and create {@link JobParameters}. @@ -54,15 +40,9 @@ public class JobParametersPropertyEditor extends PropertyEditorSupport { * @see java.beans.PropertyEditorSupport#setAsText(java.lang.String) */ public void setAsText(String text) throws IllegalArgumentException { - JobParametersBuilder builder = new JobParametersBuilder(); Properties properties = StringUtils.splitArrayElementsIntoProperties(StringUtils.tokenizeToStringArray(text, ",\n"), "="); - for (Iterator iterator = properties.keySet().iterator(); iterator.hasNext();) { - String key = (String) iterator.next(); - key = StringUtils.tokenizeToStringArray(key, "(")[0]; - builder.addString(key, properties.getProperty(key)); - } - setValue(builder.toJobParameters()); + setValue(factory.getJobParameters(properties)); } /** @@ -75,12 +55,15 @@ public class JobParametersPropertyEditor extends PropertyEditorSupport { if (params == null) { return null; } - List builder = new ArrayList(); - Map map = params.getStringParameters(); - for (Iterator iterator = map.keySet().iterator(); iterator.hasNext();) { - String key = (String) iterator.next(); - builder.add(key+"="+map.get(key)); - } - return StringUtils.collectionToCommaDelimitedString(builder); + Properties properties = factory.getProperties(params); + return PropertiesConverter.propertiesToString(properties); + } + + /** + * Public setter for the {@link JobParametersFactory}. + * @param factory the factory to set + */ + public void setFactory(JobParametersFactory factory) { + this.factory = factory; } } \ No newline at end of file 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 19ebe5b7a..9cdd89094 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 @@ -20,6 +20,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; +import java.util.Map; import java.util.Properties; import java.util.Map.Entry; @@ -30,45 +31,66 @@ import org.springframework.util.Assert; /** * @author Lucas Ward - * + * */ -public class ScheduledJobParametersFactory implements - JobParametersFactory { +public class ScheduledJobParametersFactory implements JobParametersFactory { public static String SCHEDULE_DATE_KEY = "schedule.date"; - public static String JOB_KEY = "job.key"; - + private DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); - - /* (non-Javadoc) + + /* + * (non-Javadoc) * @see org.springframework.batch.core.runtime.JobParametersFactory#getJobParameters(java.util.Properties) */ public JobParameters getJobParameters(Properties props) { - + Assert.notNull(props, "Factory arguments must not be null."); - + JobParametersBuilder propertiesBuilder = new JobParametersBuilder(); - for(Iterator it = props.entrySet().iterator(); it.hasNext();){ - Entry entry = (Entry)it.next(); - if(entry.getKey().equals(SCHEDULE_DATE_KEY)){ + for (Iterator it = props.entrySet().iterator(); it.hasNext();) { + Entry entry = (Entry) it.next(); + if (entry.getKey().equals(SCHEDULE_DATE_KEY)) { Date scheduleDate; - try{ + try { scheduleDate = dateFormat.parse(entry.getValue().toString()); } - catch(ParseException ex){ - throw new IllegalArgumentException("Schedule date format is invalid: [" + entry.getValue() + "]", ex); + catch (ParseException ex) { + throw new IllegalArgumentException("Schedule date format is invalid: [" + entry.getValue() + "]", + ex); } propertiesBuilder.addDate(entry.getKey().toString(), scheduleDate); } - else{ + else { propertiesBuilder.addString(entry.getKey().toString(), entry.getValue().toString()); } } - + return propertiesBuilder.toJobParameters(); } - + + /** + * Convert schedule date to Date, and assume all other parameters can be + * represented by their default string value. + * + * @see org.springframework.batch.core.runtime.JobParametersFactory#getProperties(org.springframework.batch.core.domain.JobParameters) + */ + public Properties getProperties(JobParameters params) { + 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 (key.equals(SCHEDULE_DATE_KEY)) { + result.setProperty(key, dateFormat.format(value)); + } else { + result.setProperty(key,""+value); + } + } + return result; + } + /** * Public setter for injecting a date format. * @param dateFormat a {@link DateFormat}, defaults to "yyyy/MM/dd" 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 bdcfeef39..6e139d63f 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 @@ -23,31 +23,32 @@ import java.util.Properties; import junit.framework.TestCase; import org.springframework.batch.core.domain.JobParameters; +import org.springframework.batch.core.domain.JobParametersBuilder; import org.springframework.util.StringUtils; /** * @author Lucas Ward - * + * */ public class ScheduledJobParametersFactoryTests extends TestCase { ScheduledJobParametersFactory factory; - + DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy"); - + protected void setUp() throws Exception { super.setUp(); - + factory = new ScheduledJobParametersFactory(); } - - public void testGetProperties() throws Exception{ - + + public void testGetParameters() throws Exception { + String jobKey = "job.key=myKey"; String scheduleDate = "schedule.date=2008/01/23"; String vendorId = "vendor.id=33243243"; - - String[] args = new String[]{jobKey, scheduleDate, vendorId}; + + String[] args = new String[] { jobKey, scheduleDate, vendorId }; JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "=")); assertNotNull(props); @@ -56,9 +57,21 @@ public class ScheduledJobParametersFactoryTests extends TestCase { Date date = dateFormat.parse("01/23/2008"); assertEquals(date, props.getDate("schedule.date")); } - - public void testEmptyArgs(){ - + + public void testGetProperties() throws Exception { + + JobParameters parameters = new JobParametersBuilder().addDate("schedule.date", dateFormat.parse("01/23/2008")) + .addString("job.key", "myKey").addString("vendor.id", "33243243").toJobParameters(); + + Properties props = factory.getProperties(parameters); + assertNotNull(props); + assertEquals("myKey", props.getProperty("job.key")); + assertEquals("33243243", props.getProperty("vendor.id")); + assertEquals("2008/01/23", props.getProperty("schedule.date")); + } + + public void testEmptyArgs() { + JobParameters props = factory.getJobParameters(new Properties()); assertTrue(props.getParameters().isEmpty()); }