diff --git a/spring-batch-core/.project b/spring-batch-core/.project
index 0dfc18b4e..aee145583 100644
--- a/spring-batch-core/.project
+++ b/spring-batch-core/.project
@@ -1,30 +1,30 @@
-
-
- spring-batch-core
- Core domain for batch processing, expressing a domain of Jobs, Steps, Chunks, etc.
-
- spring-batch-infrastructure
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- org.springframework.ide.eclipse.core.springbuilder
-
-
-
-
- org.devzuz.q.maven.jdt.core.mavenIncrementalBuilder
-
-
-
-
-
- org.springframework.ide.eclipse.core.springnature
- org.eclipse.jdt.core.javanature
- org.devzuz.q.maven.jdt.core.mavenNature
-
-
+
+
+ spring-batch-core
+ Core domain for batch processing, expressing a domain of Jobs, Steps, Chunks, etc.
+
+ spring-batch-infrastructure
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.springframework.ide.eclipse.core.springbuilder
+
+
+
+
+ org.devzuz.q.maven.jdt.core.mavenIncrementalBuilder
+
+
+
+
+
+ org.springframework.ide.eclipse.core.springnature
+ org.eclipse.jdt.core.javanature
+ org.devzuz.q.maven.jdt.core.mavenNature
+
+
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobIdentifier.java b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobIdentifier.java
index cc3e0e6d1..686cdab8b 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobIdentifier.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobIdentifier.java
@@ -16,15 +16,15 @@
package org.springframework.batch.core.domain;
+
/**
* Identifier strategy for {@link JobInstance}. Different batch projects can
* have different approaches and requirements regarding the identity of a job.
- * The minimum requirement is to provide a unique name to identify a job. Other
- * applications or projects might add other properties like a schedule date, or
- * an additional label (code).
+ * The minimum requirement is to provide a unique name to identify a job and JobRuntimeParameters.
*
* @author Dave Syer
- *
+ * @author Lucas Ward
+ * @since 1.0
*/
public interface JobIdentifier {
@@ -34,5 +34,13 @@ public interface JobIdentifier {
* @return the name of the job
*/
public String getName();
+
+ /**
+ * A simple getter for the {@link JobRuntimeParameters} that also identify
+ * this job.
+ *
+ * @return JobRuntimeParameters
+ */
+ public JobRuntimeParameters getRuntimeParameters();
}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobRuntimeParameters.java b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobRuntimeParameters.java
new file mode 100644
index 000000000..2f2d52d91
--- /dev/null
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobRuntimeParameters.java
@@ -0,0 +1,178 @@
+/**
+ *
+ */
+package org.springframework.batch.core.domain;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.springframework.util.Assert;
+
+/**
+ * Value object representing runtime parameters to a batch job. Because
+ * the parameters have no individual meaning outside of the JobIdentifier they
+ * are contained within, it is a value object rather than an entity. It is also
+ * extremely important that a parameters object can be reliably compared to another
+ * for equality, in order to determine if one JobIdentifier equals another.
+ * Furthermore, because these parameters will need to be persisted, it is vital
+ * that the types added are restricted.
+ *
+ * @author Lucas Ward
+ * @since 1.0
+ */
+public class JobRuntimeParameters {
+
+ private final Map stringMap;
+
+ private final Map longMap;
+
+ private final Map dateMap;
+
+ /**
+ * Default constructor. Creates a new empty JobRuntimeParameters. It should be noted
+ * that this constructor should only be used if an empty parameters is needed, since
+ * JobRuntimeParameters is immutable.
+ */
+ public JobRuntimeParameters(){
+ this.stringMap = new HashMap();
+ this.longMap = new HashMap();
+ this.dateMap = new HashMap();
+ }
+
+ /**
+ * Create a new parameters object based upon three maps for each of the three
+ * data types. See {@link JobRuntimeParametersBuilder} for an easier way to
+ * create paramters.
+ *
+ * @param stringMap
+ * @param longMap
+ * @param dateMap
+ */
+ public JobRuntimeParameters(Map stringMap, Map longMap, Map dateMap){
+ super();
+
+ validateMap(stringMap, String.class);
+ validateMap(longMap, Long.class);
+ validateMap(dateMap, Date.class);
+ this.stringMap = stringMap;
+ this.longMap = longMap;
+ this.dateMap = copyDateMap(dateMap);
+ }
+
+ /**
+ * Typesafe Getter for the String represented by the provided key.
+ *
+ * @param key
+ * @return
+ */
+ public String getString(String key){
+ return (String)stringMap.get(key);
+ }
+
+ /**
+ * Typesafe Getter for the Long represented by the provided key.
+ *
+ * @param key
+ * @return
+ */
+ public Long getLong(String key){
+ return (Long)longMap.get(key);
+ }
+
+ /**
+ * Typesafe Getter for the Date represented by the provided key.
+ *
+ * @param key
+ * @return
+ */
+ public Date getDate(String key){
+ return (Date)dateMap.get(key);
+ }
+
+ /**
+ * Get a map of all parameters, including string, long, and date. It should be noted
+ * that a Collections$UnmodifiableMap is returned, ensuring immutability.
+ *
+ * @return an unmodifiable map containing all parameters.
+ */
+ public Map getParameters(){
+ Map tempMap = new HashMap(stringMap);
+ tempMap.putAll(longMap);
+ tempMap.putAll(dateMap);
+ return Collections.unmodifiableMap(tempMap);
+ }
+
+ /*
+ * Convenience method for validating that a the provided map only contains a particular
+ * type as a value, with only a String as a key.
+ */
+ private void validateMap(Map map, Class type){
+
+ for(Iterator it = map.entrySet().iterator();it.hasNext();){
+
+ Entry entry = (Entry)it.next();
+ if(entry.getKey() instanceof String == false){
+ throw new IllegalArgumentException("All parameter keys must be strings.");
+ }
+ if(entry.getValue().getClass() != type){
+ throw new IllegalArgumentException("The values in this map must be of type:[" + type +
+ "].");
+ }
+ }
+ }
+
+ /*
+ * Convenience method for copying Date values to ensure immutability.
+ */
+ private Map copyDateMap(Map dateMap){
+ Map tempMap = new HashMap();
+
+ for(Iterator it = dateMap.entrySet().iterator();it.hasNext();){
+ Entry entry = (Entry)it.next();
+ Date date = (Date)entry.getValue();
+ tempMap.put(entry.getKey(), new Date(date.getTime()));
+ }
+
+ return tempMap;
+ }
+
+ public boolean equals(Object obj) {
+
+ if(obj instanceof JobRuntimeParameters == false){
+ return false;
+ }
+
+ if(this == obj){
+ return true;
+ }
+
+ JobRuntimeParameters parameters = (JobRuntimeParameters)obj;
+
+ //Since the type contained by each map is known, it's safe to call Map.equals()
+ if(getParameters().equals(parameters.getParameters())){
+ return true;
+ }
+ else{
+ return false;
+ }
+ }
+
+ public int hashCode() {
+
+ return new HashCodeBuilder(7, 21).
+ append(stringMap).
+ append(longMap).
+ append(dateMap).
+ toHashCode();
+ }
+
+ public String toString() {
+
+ return stringMap.toString() + longMap.toString() + dateMap.toString();
+ }
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobRuntimeParametersBuilder.java b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobRuntimeParametersBuilder.java
new file mode 100644
index 000000000..aafbee3cf
--- /dev/null
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobRuntimeParametersBuilder.java
@@ -0,0 +1,88 @@
+/**
+ *
+ */
+package org.springframework.batch.core.domain;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.util.Assert;
+
+/**
+ * Helper class for creating JobRuntimeParameters. Useful because of all JobRuntimeParameters
+ * are immutable, and require 3 separate maps of the three supported types to ensure typesafety.
+ * Once created, it can be used in the same was a java.lang.StringBuilder (except, order is irrelevant),
+ * by adding various parameters types and creating a valid JobRuntimeParametres once finished.
+ *
+ * @author Lucas Ward
+ * @since 1.0
+ * @see JobRuntimeParameters
+ */
+public class JobRuntimeParametersBuilder {
+
+ private final Map stringMap;
+
+ private final Map longMap;
+
+ private final Map dateMap;
+
+ /**
+ * Default constructor. Initializes the builder
+ */
+ public JobRuntimeParametersBuilder() {
+
+ this.stringMap = new HashMap();
+ this.longMap = new HashMap();
+ this.dateMap = new HashMap();
+ }
+
+ /**
+ * Add a new String parameter for the given key.
+ *
+ * @param key - parameter accessor.
+ * @param parameter - runtime parameter
+ * @return a refernece to this object.
+ */
+ public JobRuntimeParametersBuilder addString(String key, String parameter){
+ Assert.notNull(parameter, "Parameter must not be null.");
+ stringMap.put(key, parameter);
+ return this;
+ }
+
+ /**
+ * Add a new Date parameter for the given key.
+ *
+ * @param key - parameter accessor.
+ * @param parameter - runtime parameter
+ * @return a refernece to this object.
+ */
+ public JobRuntimeParametersBuilder addDate(String key, Date parameter){
+ Assert.notNull(parameter, "Parameter must not be null.");
+ dateMap.put(key, new Date(parameter.getTime()));
+ return this;
+ }
+
+ /**
+ * Add a new Long parameter for the given key.
+ *
+ * @param key - parameter accessor.
+ * @param parameter - runtime parameter
+ * @return a refernece to this object.
+ */
+ public JobRuntimeParametersBuilder addLong(String key, Long parameter){
+ Assert.notNull(parameter, "Parameter must not be null.");
+ longMap.put(key, parameter);
+ return this;
+ }
+
+ /**
+ * Conversion method that takes the current state of this builder and returns it as
+ * a JobruntimeParameters object.
+ *
+ * @return a valid JobRuntimeParameters object.
+ */
+ public JobRuntimeParameters toJobRuntimeParameters(){
+ return new JobRuntimeParameters(stringMap, longMap, dateMap);
+ }
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/runtime/SimpleJobIdentifier.java b/spring-batch-core/src/main/java/org/springframework/batch/core/runtime/SimpleJobIdentifier.java
index de00adaf9..0df4232b0 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/runtime/SimpleJobIdentifier.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/runtime/SimpleJobIdentifier.java
@@ -18,22 +18,27 @@ package org.springframework.batch.core.runtime;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.springframework.batch.core.domain.JobIdentifier;
+import org.springframework.batch.core.domain.JobRuntimeParameters;
import org.springframework.util.ClassUtils;
/**
+ * Simple, immutable, implementation of the JobIdentifier interface.
+ *
* @author Dave Syer
+ * @author Lucas Ward
*
*/
public class SimpleJobIdentifier implements JobIdentifier {
private String name;
-
+ private JobRuntimeParameters runtimeParameters;
/**
- * Default constructor.
+ * Default constructor. Since there it is required that the Identifier at least have a name,
+ * the default constructor should not be called.
*/
- public SimpleJobIdentifier() {
+ private SimpleJobIdentifier() {
super();
}
@@ -42,8 +47,12 @@ public class SimpleJobIdentifier implements JobIdentifier {
* @param name
*/
public SimpleJobIdentifier(String name) {
- super();
+ this(name, new JobRuntimeParameters());
+ }
+
+ public SimpleJobIdentifier(String name, JobRuntimeParameters runtimeParameters){
this.name = name;
+ this.runtimeParameters = runtimeParameters;
}
/* (non-Javadoc)
@@ -53,24 +62,33 @@ public class SimpleJobIdentifier implements JobIdentifier {
return this.name;
}
- /**
- * Public setter for the name.
- *
- * @param name the name to set
- */
- public void setName(String name) {
- this.name = name;
+ public JobRuntimeParameters getRuntimeParameters() {
+ return runtimeParameters;
}
public String toString() {
- return ClassUtils.getShortName(getClass())+": name=" + name;
+ return ClassUtils.getShortName(getClass())+": name=" + name + "parameters=" + runtimeParameters;
}
public boolean equals(Object obj) {
- return EqualsBuilder.reflectionEquals(this, obj);
+
+ if(obj instanceof SimpleJobIdentifier == false){
+ return false;
+ }
+
+ if(this == obj){
+ return true;
+ }
+
+ SimpleJobIdentifier rhs = (SimpleJobIdentifier)obj;
+ return new EqualsBuilder().
+ append(runtimeParameters,rhs.getRuntimeParameters()).
+ append(name, rhs.getName()).
+ isEquals();
}
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
+
}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/domain/JobRuntimeParametersBuilderTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/domain/JobRuntimeParametersBuilderTests.java
new file mode 100644
index 000000000..79557f4be
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/domain/JobRuntimeParametersBuilderTests.java
@@ -0,0 +1,36 @@
+/**
+ *
+ */
+package org.springframework.batch.core.domain;
+
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Lucas Ward
+ *
+ */
+public class JobRuntimeParametersBuilderTests extends TestCase {
+
+ JobRuntimeParametersBuilder parametersBuilder;
+
+ Date date = new Date(System.currentTimeMillis());
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ parametersBuilder = new JobRuntimeParametersBuilder();
+ parametersBuilder.addDate("SCHEDULE_DATE", date);
+ parametersBuilder.addLong("LONG", new Long(1));
+ parametersBuilder.addString("STRING", "string value");
+ }
+
+ public void testToJobRuntimeParamters(){
+
+ JobRuntimeParameters parameters = parametersBuilder.toJobRuntimeParameters();
+ assertEquals(parameters.getDate("SCHEDULE_DATE"), date);
+ assertEquals(parameters.getLong("LONG"), new Long(1));
+ assertEquals(parameters.getString("STRING"), "string value");
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/domain/JobRuntimeParametersTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/domain/JobRuntimeParametersTests.java
new file mode 100644
index 000000000..825d2ba00
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/domain/JobRuntimeParametersTests.java
@@ -0,0 +1,122 @@
+/**
+ *
+ */
+package org.springframework.batch.core.domain;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Lucas Ward
+ *
+ */
+public class JobRuntimeParametersTests extends TestCase {
+
+ JobRuntimeParameters parameters;
+
+ Map stringMap;
+
+ Map longMap;
+
+ Map dateMap;
+ Date date1 = new Date(4321431242L);
+ Date date2 = new Date(7809089900L);
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ parameters = getNewParameters();
+ }
+
+ private JobRuntimeParameters getNewParameters(){
+
+ stringMap = new HashMap();
+ stringMap.put("string.key1", "value1");
+ stringMap.put("string.key2", "value2");
+
+ longMap = new HashMap();
+ longMap.put("long.key1", new Long(1));
+ longMap.put("long.key2", new Long(2));
+
+ dateMap = new HashMap();
+ dateMap.put("date.key1", date1 );
+ dateMap.put("date.key2", date2 );
+
+ return new JobRuntimeParameters(stringMap, longMap, dateMap);
+ }
+
+ public void testBadLongConstructorException() throws Exception{
+
+ Map badLongMap = new HashMap();
+ badLongMap.put("key", "bad long");
+
+ try{
+ JobRuntimeParameters testParameters = new JobRuntimeParameters(stringMap, badLongMap, dateMap);
+ fail();
+ }
+ catch(IllegalArgumentException ex){
+ //expected
+ }
+ }
+
+ public void testBadStringConstructorException() throws Exception{
+
+ Map badMap = new HashMap();
+ badMap.put("key", new Integer(2));
+
+ try{
+ JobRuntimeParameters testParameters = new JobRuntimeParameters(badMap, longMap, dateMap);
+ fail();
+ }
+ catch(IllegalArgumentException ex){
+ //expected
+ }
+ }
+
+ public void testBadDateConstructorException() throws Exception{
+
+ Map badMap = new HashMap();
+ badMap.put("key", new java.sql.Date(System.currentTimeMillis()));
+
+ try{
+ JobRuntimeParameters testParameters = new JobRuntimeParameters(stringMap, longMap, badMap);
+ fail();
+ }
+ catch(IllegalArgumentException ex){
+ //expected
+ }
+ }
+
+ public void testGetString(){
+
+ assertEquals("value1", parameters.getString("string.key1"));
+ assertEquals("value2", parameters.getString("string.key2"));
+ }
+
+ public void testGetLong(){
+
+ assertEquals(new Long(1), parameters.getLong("long.key1"));
+ assertEquals(new Long(2), parameters.getLong("long.key2"));
+ }
+
+ public void testGetDate(){
+
+ assertEquals(date1, parameters.getDate("date.key1"));
+ assertEquals(date2, parameters.getDate("date.key2"));
+ }
+
+ public void testEquals(){
+
+ JobRuntimeParameters testParameters = getNewParameters();
+ assertTrue(testParameters.equals(parameters));
+ }
+
+ public void testToString(){
+
+ assertEquals("{string.key1=value1, string.key2=value2}{long.key1=1, long.key2=2}" +
+ "{date.key2=Wed Apr 01 03:11:29 CST 1970, date.key1=Thu Feb 19 18:23:51 CST 1970}", parameters.toString());
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/runtime/SimpleJobIdentifierTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/runtime/SimpleJobIdentifierTests.java
index 1223fa8fc..30bf648a1 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/runtime/SimpleJobIdentifierTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/runtime/SimpleJobIdentifierTests.java
@@ -25,13 +25,6 @@ public class SimpleJobIdentifierTests extends TestCase {
private SimpleJobIdentifier identifier = new SimpleJobIdentifier("foo");
- /**
- * Test method for
- * {@link org.springframework.batch.core.runtime.SimpleJobIdentifier#SimpleJobIdentifier()}.
- */
- public void testSimpleJobIdentifier() {
- assertNull(new SimpleJobIdentifier().getName());
- }
/**
* Test method for
@@ -39,8 +32,6 @@ public class SimpleJobIdentifierTests extends TestCase {
*/
public void testGetName() {
assertEquals("foo", identifier.getName());
- identifier.setName("bar");
- assertEquals("bar", identifier.getName());
}
/**