Initial move over from i21 repo.

This commit is contained in:
dsyer
2007-08-15 20:04:43 +00:00
parent 3237c34eb5
commit 170c815916
781 changed files with 67769 additions and 181 deletions

1
changelog.txt Normal file
View File

@@ -0,0 +1 @@
Do not edit this file: use src/site/apt/changelog.apt instead.

11
core/.classpath Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry exported="true" kind="var" path="CLOVER_RUNTIME"/>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/test/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>

32
core/.project Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>batch-core</name>
<comment>Simple container application for batch processing, using the
Spring Batch Framework to express a domain of Jobs, Steps,
Chunks, etc.</comment>
<projects>
<project>batch-infrastructure</project>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
<nature>org.springframework.ide.eclipse.core.springnature</nature>
</natures>
</projectDescription>

31
core/.springBeans Normal file
View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<configExtensions>
<configExtension>xml</configExtension>
</configExtensions>
<configs>
</configs>
<configSets>
<configSet>
<name><![CDATA[sqlDaoTest]]></name>
<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
<incomplete>false</incomplete>
<configs>
</configs>
</configSet>
<configSet>
<name><![CDATA[hibernateDaoTest]]></name>
<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
<incomplete>false</incomplete>
<configs>
</configs>
</configSet>
<configSet>
<name><![CDATA[launcher]]></name>
<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
<incomplete>false</incomplete>
<configs>
</configs>
</configSet>
</configSets>
</beansProjectDescription>

1
core/changelog.txt Normal file
View File

@@ -0,0 +1 @@
Do not edit this file: use src/site/apt/changelog.apt instead.

76
core/pom.xml Normal file
View File

@@ -0,0 +1,76 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-batch-core</artifactId>
<packaging>jar</packaging>
<name>Core</name>
<description>
<!-- Use CDATA to keep it on a single line in the manifest -->
<![CDATA[Core domain for batch processing, expressing a domain of Jobs, Steps, Chunks, etc.]]>
</description>
<parent>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch</artifactId>
<version>1.0-m2-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-infrastructure</artifactId>
<version>${project.version}</version>
</dependency>
<!-- optional dependency from infrastructure -->
<dependency>
<groupId>backport-util-concurrent</groupId>
<artifactId>backport-util-concurrent</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>easymock</groupId>
<artifactId>easymock</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clover-plugin</artifactId>
<configuration>
<licenseLocation>${basedir}/src/test/resources/clover.license</licenseLocation>
</configuration>
<executions>
<execution>
<phase>pre-site</phase>
<goals>
<goal>instrument</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clover-plugin</artifactId>
</plugin>
</plugins>
</reporting>
</project>

View File

@@ -0,0 +1,42 @@
/*
* 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.configuration;
/**
* Checked exception that indicates a name clash when registering
* {@link JobConfiguration} instances.
*
* @author Dave Syer
*
*/
public class DuplicateJobConfigurationException extends JobConfigurationException {
/**
* Create an exception with the given message.
*/
public DuplicateJobConfigurationException(String msg) {
super(msg);
}
/**
* @param msg The message to send to caller
* @param e the cause of the exception
*/
public DuplicateJobConfigurationException(String msg, Throwable e) {
super(msg, e);
}
}

View File

@@ -0,0 +1,102 @@
/*
* 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.configuration;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.BeanNameAware;
/**
* Batch domain object representing a job configuration. JobConfiguration is an
* explicit abstraction representing the configuration of a job specified by a
* developer. It should be noted that restart policy is applied to the job as a
* whole and not to a step.
*
* @author Lucas Ward
* @author Dave Syer
*/
public class JobConfiguration implements BeanNameAware {
private List stepConfigurations = new ArrayList();
private String name;
private boolean restartable = false;
private int startLimit = Integer.MAX_VALUE;
/**
* Default constructor.
*/
public JobConfiguration() {
super();
}
/**
* Convenience constructor to immediately add name (which is mandatory but
* not final).
* @param name
*/
public JobConfiguration(String name) {
super();
this.name = name;
}
public void setBeanName(String name) {
if (this.name == null) {
this.name = name;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getStepConfigurations() {
return stepConfigurations;
}
public void setSteps(List stepConfigurations) {
this.stepConfigurations.clear();
this.stepConfigurations.addAll(stepConfigurations);
}
public void addStep(StepConfiguration stepConfiguration) {
this.stepConfigurations.add(stepConfiguration);
}
public int getStartLimit() {
return startLimit;
}
public void setStartLimit(int startLimit) {
this.startLimit = startLimit;
}
public void setRestartable(boolean restartable) {
this.restartable = restartable;
}
public boolean isRestartable() {
return restartable;
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.configuration;
/**
* Base class for checked exceptions related to {@link JobConfiguration}
* creation, registration or use.
*
* @author Dave Syer
*
*/
public class JobConfigurationException extends Exception {
/**
* Create an exception with the given message.
*/
public JobConfigurationException(String msg) {
super(msg);
}
/**
* @param msg The message to send to caller
* @param e the cause of the exception
*/
public JobConfigurationException(String msg, Throwable e) {
super(msg, e);
}
}

View File

@@ -0,0 +1,38 @@
/*
* 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.configuration;
/**
* A runtime service locator interface for retrieving job configurations by
* <code>name</code>.
*
* @author Dave Syer
*
*/
public interface JobConfigurationLocator {
/**
* Locates a {@link JobConfiguration} at runtime.
*
* @param name the name of the {@link JobConfiguration} which should be
* unique
* @return a {@link JobConfiguration} identified by the given name
*
* @throws NoSuchJobConfigurationException if the required configuratio can
* not be found.
*/
JobConfiguration getJobConfiguration(String name) throws NoSuchJobConfigurationException;
}

View File

@@ -0,0 +1,44 @@
/*
* 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.configuration;
/**
* A runtime service registry interface for registering job configurations by
* <code>name</code>.
*
* @author Dave Syer
*
*/
public interface JobConfigurationRegistry extends JobConfigurationLocator {
/**
* Registers a {@link JobConfiguration} at runtime.
*
* @param jobConfiguration the {@link JobConfiguration} to be registered
*
* @throws DuplicateJobConfigurationException if a configuration with the
* same name has already been registered.
*/
void register(JobConfiguration jobConfiguration) throws DuplicateJobConfigurationException;
/**
* Unregisters a previously registered {@link JobConfiguration}. If it was
* not previously registered there is no error.
*
* @param jobConfiguration the {@link JobConfiguration} to unregister.
*/
void unregister(JobConfiguration jobConfiguration);
}

View File

@@ -0,0 +1,36 @@
/*
* 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.configuration;
import java.util.Collection;
/**
* A listable extension of {@link JobConfigurationRegistry}.
*
* @author Dave Syer
*
*/
public interface ListableJobConfigurationRegistry extends JobConfigurationRegistry {
/**
* Provides the currently registered configurations. The return value is
* unmodifiable and disconnected from the underlying registry storage.
*
* @return a collection of {@link JobConfiguration} instances. Empty if none
* are registered.
*/
Collection getJobConfigurations();
}

View File

@@ -0,0 +1,42 @@
/*
* 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.configuration;
/**
* Checked exception to indicate that a required {@link JobConfiguration} is not
* available.
*
* @author Dave Syer
*
*/
public class NoSuchJobConfigurationException extends JobConfigurationException {
/**
* Create an exception with the given message.
*/
public NoSuchJobConfigurationException(String msg) {
super(msg);
}
/**
* @param msg The message to send to caller
* @param e the cause of the exception
*/
public NoSuchJobConfigurationException(String msg, Throwable e) {
super(msg, e);
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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.configuration;
import org.springframework.batch.core.tasklet.Tasklet;
/**
* Batch domain interface representing the configuration of a step. As with the
* (@link JobConfiguration), step configuration is meant to explicitly represent
* a the configuration of a step by a developer. This allows for the separation
* of what a developer configures from the myriad of concerns required for
* executing a job.
*
* @author Dave Syer
*
*/
public interface StepConfiguration {
/**
* @return the name of this step configuration.
*/
String getName();
/**
* @return the {@link Tasklet} instance to execute for each item processed.
*/
Tasklet getTasklet();
/**
* @return true if a job that is already marked as complete can be started
* again.
*/
boolean isAllowStartIfComplete();
/**
* @return the number of times a job can be started with the same
* identifier.
*/
int getStartLimit();
}

View File

@@ -0,0 +1,117 @@
/*
* 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.configuration;
import org.springframework.batch.core.tasklet.Tasklet;
/**
* Basic no-op support implementation for use as base class for
* {@link StepConfiguration}.
*
* @author Dave Syer
*
*/
public class StepConfigurationSupport implements StepConfiguration {
private String name;
private int startLimit = Integer.MAX_VALUE;
private Tasklet tasklet;
private boolean allowStartIfComplete;
/**
* Default constructor for {@link StepConfigurationSupport}.
*/
public StepConfigurationSupport() {
super();
}
/**
* @param string
*/
public StepConfigurationSupport(String string) {
super();
this.name = string;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.core.configuration.StepConfiguration#getName()
*/
public String getName() {
return this.name;
}
/**
* Public setter for the name.
*
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.core.configuration.StepConfiguration#getStartLimit()
*/
public int getStartLimit() {
return this.startLimit;
}
/**
* Public setter for the startLimit.
*
* @param startLimit the startLimit to set
*/
public void setStartLimit(int startLimit) {
this.startLimit = startLimit;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.core.configuration.StepConfiguration#getTasklet()
*/
public Tasklet getTasklet() {
return this.tasklet;
}
/**
* Public setter for the tasklet.
*
* @param tasklet the tasklet to set
*/
public void setTasklet(Tasklet tasklet) {
this.tasklet = tasklet;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.core.configuration.StepConfiguration#shouldAllowStartIfComplete()
*/
public boolean isAllowStartIfComplete() {
return this.allowStartIfComplete;
}
/**
* Public setter for the shouldAllowStartIfComplete.
*
* @param allowStartIfComplete the shouldAllowStartIfComplete to set
*/
public void setAllowStartIfComplete(boolean allowStartIfComplete) {
this.allowStartIfComplete = allowStartIfComplete;
}
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Interfaces and generic implementations of configuration concerns.
</p>
</body>
</html>

View File

@@ -0,0 +1,62 @@
/*
* 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.domain;
/**
* Typesafe enumeration representating the status of an artifact within
* the batch container. See Effective Java Programming by Joshua Bloch
* for more details on the pattern used.
*
* @author Lucas Ward
*
*/
public class BatchStatus {
private final String name;
private BatchStatus(String name) {
this.name = name;
}
public String toString(){
return name;
}
public static final BatchStatus COMPLETED = new BatchStatus("COMPLETED");
public static final BatchStatus STARTED = new BatchStatus("STARTED");
public static final BatchStatus STARTING = new BatchStatus("STARTING");
public static final BatchStatus FAILED = new BatchStatus("FAILED");
public static final BatchStatus STOPPED = new BatchStatus("STOPPED");
private static final BatchStatus[] VALUES = {STARTING, STARTED, COMPLETED, FAILED, STOPPED};
public static BatchStatus getStatus(String statusAsString){
for(int i = 0; i < VALUES.length; i++){
if(VALUES[i].toString().equals(statusAsString)){
return (BatchStatus)VALUES[i];
}
}
return null;
}
}

View File

@@ -0,0 +1,106 @@
/*
* 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.domain;
import java.io.Serializable;
import org.springframework.util.ClassUtils;
/**
* Batch Domain Entity class. Any class that should be uniquely identifiable
* from another should subclass from Entity. More information on this pattern
* and the difference between Entities and Value Objects can be found in Domain
* Driven Design by Eric Evans.
*
* @author Lucas Ward
* @author Dave Syer
*
*/
public class Entity implements Serializable {
private Long id;
private Integer version;
public Entity() {
super();
}
public Entity(Long id) {
super();
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
/**
* @return the version
*/
public Integer getVersion() {
return version;
}
// @Override
public String toString() {
return ClassUtils.getShortName(getClass()) + ": id=" + getId();
}
/**
* Attempt to establish identity based on id if both exist. If either id
* does not exist use Object.equals().
*
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (!(other instanceof Entity)) {
return false;
}
Entity step = (Entity) other;
if (id == null || step.getId() == null) {
return step == this;
}
return id.equals(step.getId());
}
/**
* Use ID if it exists to establish hash code, otherwise fall back to
* Object.hashCode(). Based on the same information as equals, so if that
* changes, this will. N.B. this follows the contract of Object.hashCode(),
* but will cause problems for anyone adding an unsaved {@link Entity} to a
* Set because Set.contains() will almost certainly return false for the
* {@link Entity} after it is saved. Spring Batch does not store any of its
* entities in Sets as a matter of course, so internally this is consistent.
* Clients should not be exposed to unsaved entities.
*
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
if (id == null) {
return super.hashCode();
}
return 39 + 87 * id.hashCode();
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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.domain;
import java.sql.Timestamp;
/**
* Batch domain object representing the execution of a job.
*
* @author Lucas Ward
*
*/
public class JobExecution extends Entity {
// TODO declare transient or make serializable
private BatchStatus status = BatchStatus.STARTING;
private Timestamp startTime = new Timestamp(System.currentTimeMillis());
private Timestamp endTime = null;
private Long jobId;
private int exitCode;
// Package private constructor for Hibernate
JobExecution() {}
/**
* Because a JobExecution isn't valid unless the jobId is set, this
* constructor is the only valid one.
*
* @param jobId
*/
public JobExecution(Long jobId) {
this.jobId = jobId;
}
public Timestamp getEndTime() {
return endTime;
}
public void setEndTime(Timestamp endTime) {
this.endTime = endTime;
}
public Timestamp getStartTime() {
return startTime;
}
public void setStartTime(Timestamp startTime) {
this.startTime = startTime;
}
public BatchStatus getStatus() {
return status;
}
public void setStatus(BatchStatus status) {
this.status = status;
}
public Long getJobId() {
return jobId;
}
public void setJobId(Long jobId) {
this.jobId = jobId;
}
/**
* @param exitCode
*/
public void setExitCode(int exitCode) {
this.exitCode = exitCode;
}
/**
* @return the exitCode
*/
public int getExitCode() {
return exitCode;
}
}

View File

@@ -0,0 +1,106 @@
/*
* 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.domain;
import java.util.ArrayList;
import java.util.List;
import org.springframework.batch.core.runtime.JobIdentifier;
/**
* Batch domain object representing a job instance. A job instance is defined as
* a logical container for steps with unique identification of the unit as a
* whole. A job can be executed many times with the same instance, usually if it
* fails and is restarted, or if it is launched on an ad-hoc basis "on demand".
*
* @author Lucas Ward
* @author Dave Syer
*/
public class JobInstance extends Entity {
private List steps = new ArrayList();
private JobIdentifier identifier;
// TODO declare transient or make the class serializable
private BatchStatus status;
private int jobExecutionCount;
public JobInstance() {
this(null);
}
public JobInstance(Long id) {
super();
setId(id);
}
public BatchStatus getStatus() {
return status;
}
public void setStatus(BatchStatus status) {
this.status = status;
}
public List getSteps() {
return steps;
}
public void setSteps(List steps) {
this.steps = steps;
}
public void addStep(StepInstance step) {
this.steps.add(step);
}
public int getJobExecutionCount() {
return jobExecutionCount;
}
public void setJobExecutionCount(int jobExecutionCount) {
this.jobExecutionCount = jobExecutionCount;
}
/**
* Public accessor for the identifier property.
*
* @return the identifier
*/
public JobIdentifier getIdentifier() {
return identifier;
}
/**
* Public setter for the identifier.
*
* @param identifier the identifier to set
*/
public void setIdentifier(JobIdentifier identifier) {
this.identifier = identifier;
}
/**
* @return the identifier name if there is one
*/
public String getName() {
return identifier==null ? null : identifier.getName();
}
}

View File

@@ -0,0 +1,190 @@
/*
* 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.domain;
import java.sql.Timestamp;
import java.util.Properties;
/**
* Batch domain object representation the execution of a step. Unlike
* JobExecution, there are four additional properties: luwCount, commitCount,
* rollbackCount and statistics. These values represent how many times a step
* has iterated through logical units of work, how many times it has been
* committed, and any other statistics the developer wishes to store,
* respectively.
*
* @author Lucas Ward
*
*/
public class StepExecution extends Entity {
// TODO declare transient or make serializable
private BatchStatus status = BatchStatus.STARTING;
private int taskCount = 0;
private int commitCount = 0;
private int rollbackCount = 0;
private Timestamp startTime = new Timestamp(System.currentTimeMillis());
private Timestamp endTime = null;
private Properties statistics = new Properties();
private Long stepId;
private Long jobExecutionId;
private int exitCode;
/**
* Package private constructor for Hibernate
*/
StepExecution() {
super();
}
public StepExecution(Long stepId, Long jobExecutionId) {
this();
this.stepId = stepId;
this.jobExecutionId = jobExecutionId;
}
public void incrementCommitCount() {
commitCount++;
}
public void incrementTaskCount() {
taskCount++;
}
public void incrementRollbackCount() {
rollbackCount++;
}
public Properties getStatistics() {
return statistics;
}
public void setStatistics(Properties statistics) {
this.statistics = statistics;
}
public Integer getCommitCount() {
return new Integer(commitCount);
}
public void setCommitCount(int commitCount) {
this.commitCount = commitCount;
}
public Timestamp getEndTime() {
return endTime;
}
public void setEndTime(Timestamp endTime) {
this.endTime = endTime;
}
public Integer getTaskCount() {
return new Integer(taskCount);
}
public void setTaskCount(int taskCount) {
this.taskCount = taskCount;
}
public void setRollbackCount(int rollbackCount) {
this.rollbackCount = rollbackCount;
}
public Integer getRollbackCount() {
return new Integer(rollbackCount);
}
public Timestamp getStartTime() {
return startTime;
}
public void setStartTime(Timestamp startTime) {
this.startTime = startTime;
}
public BatchStatus getStatus() {
return status;
}
public void setStatus(BatchStatus status) {
this.status = status;
}
public Long getStepId() {
return stepId;
}
/**
* Accessor for the job execution id.
* @return the jobExecutionId
*/
public Long getJobExecutionId() {
return jobExecutionId;
}
/* (non-Javadoc)
* @see org.springframework.batch.container.common.domain.Entity#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if (stepId==null && jobExecutionId==null || !(obj instanceof StepExecution) || getId()!=null) {
return super.equals(obj);
}
StepExecution other = (StepExecution) obj;
if (stepId==null) {
return jobExecutionId.equals(other.getJobExecutionId());
}
return stepId.equals(other.getStepId()) && (jobExecutionId==null || jobExecutionId.equals(other.getJobExecutionId()));
}
/* (non-Javadoc)
* @see org.springframework.batch.container.common.domain.Entity#hashCode()
*/
public int hashCode() {
return super.hashCode() + 31*(stepId!=null ? stepId.hashCode() : 0) + 91*(jobExecutionId!=null ? jobExecutionId.hashCode() : 0);
}
public String toString() {
return super.toString() + ", taskCount=" + taskCount + ", commitCount=" + commitCount + ", rollbackCount="
+ rollbackCount;
}
/**
* @param exitCode
*/
public void setExitCode(int exitCode) {
this.exitCode = exitCode;
}
/**
* @return the exitCode
*/
public int getExitCode() {
return exitCode;
}
}

View File

@@ -0,0 +1,127 @@
/*
* 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.domain;
import org.springframework.batch.restart.GenericRestartData;
import org.springframework.batch.restart.RestartData;
/**
* <p>
* Batch domain entity representing a step which is sequentially executed by a
* job. Logically, steps are identified as a function of a job plus each step's
* name. For example, job 'TestJob' which has 2 steps: "TestStep1" and
* "TestStep2". The first step can be thought of as identified by
* "TestJob.TestStep1". In relational terms this may be represented by a foreign
* key on the Job's ID. Therefore, Each step instance is uniquely identified by
* it's ID, which is obtained from a JobRepository. Two steps with the same name
* and same job can be considered the same step.
* </p>
*
* <p>
* Because each step represents a runnable batch artifact with it's own
* lifecycle, each step contains status and an execution count. Status
* represents the status of each step's last execution (such as started,
* completed, failed, etc) and execution count is the count of executions for
* this individual step. It should be noted that a restartable job will create a
* new step instance (the same logical step, with a different ID) for every run.
* </p>
*
* @author Lucas Ward
* @author Dave Syer
*
*/
public class StepInstance extends Entity {
private JobInstance job;
// TODO declare transient or make serializable
private BatchStatus status;
private RestartData restartData = new GenericRestartData(null);
private int stepExecutionCount = 0;
private StepExecution stepExecution;
private String name;
public StepInstance() {
this(null);
}
public StepInstance(Long stepId) {
setId(stepId);
}
public int getStepExecutionCount() {
return stepExecutionCount;
}
public void setStepExecutionCount(int stepExecutionCount) {
this.stepExecutionCount = stepExecutionCount;
}
public RestartData getRestartData() {
return restartData;
}
public void setRestartData(RestartData restartData) {
this.restartData = restartData;
}
public BatchStatus getStatus() {
return status;
}
public void setStatus(BatchStatus status) {
this.status = status;
}
public void setJob(JobInstance job) {
this.job = job;
}
public JobInstance getJob() {
return job;
}
public StepExecution getStepExecution() {
return stepExecution;
}
public void setStepExecution(StepExecution stepInstance) {
this.stepExecution = stepInstance;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Long getJobId() {
return job==null ? null : job.getId();
}
// @Override
public String toString() {
return super.toString() + ", name=" + name + ", status=" + getStatus() + " in " + job;
}
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Interfaces and generic implementations of domain concerns.
</p>
</body>
</html>

View File

@@ -0,0 +1,35 @@
/*
* 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.executor;
import org.springframework.batch.core.configuration.JobConfiguration;
import org.springframework.batch.core.runtime.JobExecutionContext;
import org.springframework.batch.io.exception.BatchCriticalException;
/**
* Interface for running a job from its configuration.
*
* @author Lucas Ward
* @author Dave Syer
* @see JobConfiguration
* @see JobExecutionContext
*/
public interface JobExecutor {
public void run(JobConfiguration configuration, JobExecutionContext jobExecutionContext) throws BatchCriticalException;
}

View File

@@ -0,0 +1,55 @@
/*
* 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.executor;
import org.springframework.batch.core.configuration.StepConfiguration;
import org.springframework.batch.core.runtime.StepExecutionContext;
import org.springframework.batch.io.exception.BatchCriticalException;
import org.springframework.batch.repeat.ExitStatus;
/**
* Interface for processing a step. Implementations are free to process the step
* and return when finished, or to schedule the step for processing
* concurrently, or in the future. The status of the execution should be
* trackable with the step execution context ({@see Step#getContext()}). The
* configuration should be treated as immutable.<br/>
*
* Because step execution paramaters and policies can vary from step to step, a
* {@link StepExecutor} should be created by the caller using a
* {@link StepExecutorFactory}.
*
* @author Lucas Ward
* @author Dave Syer
*
*/
public interface StepExecutor {
/**
* Process the step according to the given configuration.
*
* @param configuration the configuration to use when running the step.
* Contains a recipe for the business logic of an individual processing
* operation. Also used to determine policies for commit intervals and
* exception handling, for instance.
* @param stepExecutionContext an entity representing the step to be executed
* @throws StepInterruptedException if the step is interrupted externally
* @throws BatchCriticalException if there is a problem that needs to be
* signalled to the caller
*/
ExitStatus process(StepConfiguration configuration, StepExecutionContext stepExecutionContext) throws StepInterruptedException, BatchCriticalException;
}

View File

@@ -0,0 +1,44 @@
/*
* 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.executor;
import org.springframework.batch.core.configuration.StepConfiguration;
/**
* Factory interface for creating or locating {@link StepExecutor} instances.
* Because step execution parameters and policies can vary from step to step, a
* {@link StepExecutor} should be created by the caller using a
* {@link StepExecutorFactory}. The factory is responsible for ensuring that
* the returned instance is appropriate for the configuration supplied. If the
* {@link StepExecutor} instance is stateful (which is normal) the factory
* should return a different instance for each call.
*
* @author Dave Syer
*
*/
public interface StepExecutorFactory {
/**
* Use the configuration given to create or locate a suitable
* {@link StepExecutor}.
*
* @param configuration a {@link StepConfiguration} instance.
* @return a {@link StepExecutor} that can be used to execute a step with
* the given configuration
*/
StepExecutor getExecutor(StepConfiguration configuration);
}

View File

@@ -0,0 +1,30 @@
/*
* 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.executor;
/**
* Exception to indicate the the lifecycle has been interrupted.
*
* @author Lucas Ward
*
*/
public class StepInterruptedException extends Exception {
public StepInterruptedException(String msg){
super(msg);
}
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Interfaces and generic implementations of executor concerns.
</p>
</body>
</html>

View File

@@ -0,0 +1,11 @@
<html>
<body>
<p>
Core domain context for Spring Batch covering jobs, steps,
configuration and execution abstractions. Most classes here are
interfaces with implementations saved for specific applications. This
is the public API of Spring Batch. There is a reference
implementation of the core interfaces in the execution module.
</p>
</body>
</html>

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.repository;
import org.springframework.batch.io.exception.BatchCriticalException;
/**
* @author Dave Syer
*
*/
public class BatchRestartException extends BatchCriticalException {
/**
* @param string the message
*/
public BatchRestartException(String string) {
super(string);
}
/**
* @param msg the cause
* @param t the message
*/
public BatchRestartException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.repository;
import org.springframework.batch.core.configuration.JobConfiguration;
import org.springframework.batch.core.domain.JobExecution;
import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.core.domain.StepInstance;
import org.springframework.batch.core.runtime.JobIdentifier;
/**
* <p>
* Repository for storing batch jobs and steps. Before using any methods, a Job
* must first be obtained using the findOrCreateJob method. Once a Job and it's
* related steps are obtained, they can be updated. It should be noted that any
* reconstituted steps are expected to contain restart data <strong>if the
* RestartPolicy associated with the step returns true, and RestartData exists.</strong>
* </p>
*
* Once a Job/Steps has been created, Job and Step executions can be created and
* associated with a job, by setting the JobId and StepId respectively. Once
* these Id's are set, an execution can be persisted. If the object is in a
* transient state (i.e. it has no id of it's own) then an ID will be created
* for that specific execution, and then stored ('saved'). (NOTE: The
* relationship between a Job/Step and Job/StepExecutions is 1:N) If an ID does
* exist, then the execution will be stored ('updated').
*
*
* @author Lucas Ward
*
*/
public interface JobRepository {
/**
* Find or create a job for a given Job identifier or configuration. If the
* job that is uniquely identified by JobIdentifier already exists, it's
* persisted values (including ID) will be returned in a new Job object. If
* no previous run is found, a new job will be created and returned.
* @param jobConfiguration - describes the configuration for jobs and steps
* @param runtimeInformation TODO
*
* @return a valid job
*
*
* @throws NoSuchBatchDomainObjectException if more than one job is found for
* the given configuration.
*/
public JobInstance findOrCreateJob(JobConfiguration jobConfiguration, JobIdentifier jobIdentifier);
/**
* Update a Job.
*
* Preconditions: Job must contain a valid ID. This can be ensured by first
* obtaining a job from findOrCreateJob.
*
* @param job
* @see JobInstance
*/
public void update(JobInstance job);
/**
* Save or Update a JobExecution. If no ID is found a new instance will be
* created. (saved). If an ID does exist it will be updated. It is not
* advisable that an ID be assigned to a JobExecution before calling this
* method. Instead, it should be left blank, to be assigned by a
* JobRepository.
*
* Preconditions: JobExecution must contain a valid JobId.
*
* @param jobInstance
*/
public void saveOrUpdate(JobExecution jobExecution);
/**
* Update a step.
*
* Preconditions: Step must contain a valid ID. This can be ensured by first
* obtaining a Job from findOrCreateJob, and accessing it's step list.
*
* @param step
* @see StepInstance
*/
public void update(StepInstance step);
/**
* Save or Update a StepExecution. If no ID is found a new instance will be
* created. (saved). If an ID does exist it will be updated. It is not
* advisable that an ID be assigned to a JobExecution before calling this
* method. Instead, it should be left blank, to be assigned by a
* JobRepository.
*
* Preconditions: StepExecution must have a valid StepId.
*
* @param jobInstance
*/
public void saveOrUpdate(StepExecution stepExecution);
}

View File

@@ -0,0 +1,34 @@
/*
* 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.repository;
/**
* This exception identifies that a batch domain object is invalid, which
* is generally caused by an invalid ID. (An ID which doesn't exist in the database).
*
* @author Lucas Ward
* @author Dave Syer
*
*/
public class NoSuchBatchDomainObjectException extends RuntimeException {
private static final long serialVersionUID = 4399621765157283111L;
public NoSuchBatchDomainObjectException(String message){
super(message);
}
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Interfaces and generic implementations of repository concerns.
</p>
</body>
</html>

View File

@@ -0,0 +1,198 @@
/*
* 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.runtime;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.HashSet;
import org.springframework.batch.core.domain.JobExecution;
import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.repeat.RepeatContext;
/**
* Context for an executing job. Maintains invariants and provides communication
* channel for all components requiring information about the job and its steps.
*
* @author Dave Syer
*
*/
public class JobExecutionContext {
private JobIdentifier jobIdentifier;
private final JobInstance job;
private final JobExecution jobExecution;
private Collection stepExecutions = new HashSet();
private Collection stepContexts = new HashSet();
private Collection chunkContexts = new HashSet();
/**
* Constructor with all the mandatory properties.
*
* @param jobIdentifier
*/
public JobExecutionContext(JobIdentifier jobIdentifier, JobInstance job) {
super();
this.jobIdentifier = jobIdentifier;
this.job = job;
this.jobExecution = new JobExecution(job.getId());
this.jobExecution.setStartTime(new Timestamp(System.currentTimeMillis()));
}
/**
* Accessor for the potentially multiple chunk contexts that are in
* progress. In a single-threaded, sequential execution there would normally
* be only one current chunk, but in more complicated scenarios there might
* be multiple active contexts.
* @return all the chunk contexts that have been registered and not
* unregistered. A collection opf {@link RepeatContext} objects.
*/
public Collection getChunkContexts() {
synchronized (chunkContexts) {
return new HashSet(chunkContexts);
}
}
/**
* Accessor for the runtime information of this execution.
* @return the {@link JobRuntimeInformation} that was used to start this job
* execution.
*/
public JobIdentifier getJobIdentifier() {
return jobIdentifier;
}
/**
* Accessor for the potentially multiple step contexts that are in progress.
* In a single-threaded, sequential execution there would normally be only
* one current step, but in more complicated scenarios there might be
* multiple active contexts.
* @return all the step contexts that have been registered and not
* unregistered. A collection of {@link RepeatContext} objects.
*/
public Collection getStepContexts() {
synchronized (stepContexts) {
return new HashSet(stepContexts);
}
}
/**
* Called at the start of a step, before any business logic is processed.
* @param context the current step context.
*/
public void registerStepContext(RepeatContext stepContext) {
synchronized (stepContexts) {
this.stepContexts.add(stepContext);
}
}
/**
* Called at the end of a step, after all business logic is processed, or in
* the case of a failure.
* @param context the current step context.
*/
public void unregisterStepContext(RepeatContext stepContext) {
synchronized (stepContexts) {
this.stepContexts.remove(stepContext);
}
}
/**
* Called at the start of a chunk, before any business logic is processed.
* @param context the current chunk context.
*/
public void registerChunkContext(RepeatContext chunkContext) {
synchronized (chunkContexts) {
this.chunkContexts.add(chunkContext);
}
}
/**
* Called at the end of a chunk, after all business logic is processed, or
* in the case of a failure.
* @param context the current chunk context.
*/
public void unregisterChunkContext(RepeatContext chunkContext) {
synchronized (chunkContexts) {
this.chunkContexts.remove(chunkContext);
}
}
/**
* @return the Job that is executing.
*/
public JobInstance getJob() {
return job;
}
/**
* @return the current job execution.
*/
public JobExecution getJobExecution() {
return jobExecution;
}
/**
* Accessor for the step executions.
* @return the step executions that were registered
*/
public Collection getStepExecutions() {
return stepExecutions;
}
/**
* Register a step execution with the current job execution.
* @param stepExecution
*/
public void registerStepExecution(StepExecution stepExecution) {
this.stepExecutions.add(stepExecution);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if (!(obj instanceof JobExecutionContext)) {
return super.equals(obj);
}
JobExecutionContext other = (JobExecutionContext) obj;
return job.equals(other.getJob()) && jobExecution.equals(other.getJobExecution());
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return 23*job.hashCode() + 61*jobExecution.hashCode();
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return "identifier=" + jobIdentifier + "; steps=" + stepContexts + "; chunks=" + chunkContexts;
}
}

View File

@@ -0,0 +1,27 @@
/*
* 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.runtime;
/**
* @author Dave Syer
*
*/
public interface JobExecutionContextFactory {
JobExecutionContext create(JobIdentifier jobIdentifier);
}

View File

@@ -0,0 +1,94 @@
/*
* 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.runtime;
import java.util.Collection;
import org.springframework.batch.core.domain.JobExecution;
import org.springframework.batch.core.domain.JobInstance;
/**
* Registry for currently active job executions, which can be used for
* monitoring and management purposes. Not to be confused with a persistent
* repository of jobs.
*
* @author Dave Syer
*
*/
public interface JobExecutionRegistry {
/**
* Register a job instance and obtain the runtime context of the
* execution.
*
* @param runtimeInformation the {@link JobRuntimeInformation} that can be
* used to identify this execution in subsequent calls to the registry. Must
* not be null.
* @param job
* @param the {@link JobInstance} instance to register.
*
* @throws NullPointerException if the first parameter is null.
*/
JobExecutionContext register(JobIdentifier jobIdentifier, JobInstance job);
/**
* Check if a given {@link JobExecution}, or one with the same id property,
* is already registered.
*
* @param runtimeInformation the {@link JobIdentifier} to check.
* @return true if it has been registered.
*/
boolean isRegistered(JobIdentifier jobIdentifier);
/**
* Unregister a particular {@link JobExecution}, or one with the same id
* property.
*
* @param execution the {@link JobIdentifier} to unregister.
*/
void unregister(JobIdentifier jobIdentifier);
/**
* Find all the currently registered {@link JobExecutionContext} objects.
*
* @return all the currently registered contexts.
*/
Collection findAll();
/**
* Return a collection of {@link JobExecutionContext} objects representing
* the currently executing jobs with {@link JobRuntimeInformation} having
* the given name.
*
* @param name the name of the {@link JobRuntimeInformation} as a to key the
* search. The name can be null, in which case the key is null, i.e.
* {@link JobRuntimeInformation} instances with null name will match.
* @return a {@link Collection} of {@link JobExecutionContext}.
*/
Collection findByName(String name);
/**
* Return a {@link JobExecutionContext} representing the currently executing
* jobs with the given {@link JobRuntimeInformation}.
*
* @param runtimeInformation the {@link JobIdentifier} to use as a
* search key.
* @return the {@link JobExecutionContext} that was registered under the
* given key, if there is one, null otherwise.
*/
JobExecutionContext get(JobIdentifier jobIdentifier);
}

View File

@@ -0,0 +1,24 @@
/*
* 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.runtime;
public interface JobIdentifier {
public String getName();
}

View File

@@ -0,0 +1,39 @@
/*
* 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.runtime;
/**
* A job configuration can be executed with many possible runtime parameters,
* which identify the instance of the job. This factory allows job identifiers
* to be created with different properties according to the
* {@link JobIdentifier} strategy required. For example some projects or jobs
* need a schedule date as part of the {@link JobIdentifier} and some do not
* (e.g. for an ad-hoc execution a simple label might be enough).
*
*
* @author Dave Syer
*
*/
public interface JobIdentifierFactory {
/**
* Get a new {@link JobIdentifier} instance.
* @param name the name of the job configuration.
* @return a {@link JobIdentifier} with the same name.
*/
public JobIdentifier getJobIdentifier(String name);
}

View File

@@ -0,0 +1,65 @@
/*
* 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.runtime;
/**
* @author Dave Syer
*
*/
public class SimpleJobIdentifier implements JobIdentifier {
private String name;
/**
* Default constructor.
*/
public SimpleJobIdentifier() {
super();
}
/**
* Convenience constructor with name.
* @param name
*/
public SimpleJobIdentifier(String name) {
super();
this.name = name;
}
/* (non-Javadoc)
* @see org.springframework.batch.core.runtime.JobIdentifier#getName()
*/
public String getName() {
return this.name;
}
/**
* Public setter for the name.
*
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
public String toString() {
return "name=" + name;
}
}

View File

@@ -0,0 +1,105 @@
/*
* 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.runtime;
import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.core.domain.StepInstance;
import org.springframework.util.Assert;
/**
* Context for an executing step within a job. Maintains invariants and provides
* communication channel for all components requiring information about the
* step.
*
* @author Dave Syer
*
*/
public class StepExecutionContext {
private JobExecutionContext jobExecutionContext;
private final StepInstance step;
private final StepExecution stepExecution;
/**
* Constructor with all the mandatory properties.
*
* @param jobExecutionContext
*/
public StepExecutionContext(JobExecutionContext jobExecutionContext, StepInstance step) {
super();
Assert.notNull(jobExecutionContext);
Assert.notNull(jobExecutionContext.getJobExecution(), "The JobExecutionContext must have a JobExecution");
Assert.notNull(step);
this.jobExecutionContext = jobExecutionContext;
this.step = step;
this.stepExecution = new StepExecution(step.getId(), jobExecutionContext.getJobExecution().getId());
}
/**
* Accessor for the step governing this execution.
* @return the step
*/
public StepInstance getStep() {
return step;
}
/**
* Accessor for the execution context information of the enclosing job.
* @return the {@link jobExecutionContext} that was used to start this step
* execution.
*/
public JobExecutionContext getJobExecutionContext() {
return jobExecutionContext;
}
/**
* Retrieve the current step execution or create a new one if there is none.
* @return the current step execution.
*/
public StepExecution getStepExecution() {
return stepExecution;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if (!(obj instanceof StepExecutionContext)) {
return super.equals(obj);
}
StepExecutionContext other = (StepExecutionContext) obj;
return step.equals(other.getStep()) && stepExecution.equals(other.getStepExecution());
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return 23*step.hashCode() + 61*stepExecution.hashCode();
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return "step=" + step + "; stepExecution=" + stepExecution;
}
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Interfaces and generic implementations of runtime concerns.
</p>
</body>
</html>

View File

@@ -0,0 +1,39 @@
/*
* 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.tasklet;
/**
* Marker interface for {@link Tasklet} implementations that are able totake a
* recovery action in the case that an exception is thrown inside
* {@link Tasklet#execute()}. Containers must ensure that the recover method is
* called in a different transactional context than the failed execution, e.g.
* by creating a new transaction with propagation REQUIRES_NEW.
*
* @author Dave Syer
*
*/
public interface Recoverable {
/**
* Take some action to recover the current batch operation. E.g. send a
* message to an error queue, or append a bad record to a special file.
*
* @param cause the exception that caused the recovery step to be called.
*/
void recover(Throwable cause);
}

View File

@@ -0,0 +1,54 @@
/*
* 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.tasklet;
import org.springframework.batch.core.configuration.StepConfiguration;
/**
* The primary interface describing the touch-point between the batch developer
* and a spring-batch execution. The execute method will be called to indicate
* to the developer that it is time to execute business logic. The value
* returned from this method will indicate whether or not processing should
* continue. It is important to note that in the vast majority of cases this
* class should not be directly implemented by batch developers for processing.
* Most batch processing is significantly more complex than simple execute and
* should logically be broken into a minimum of two processes (read and write).
* However, many architecture teams may find creating their own implementations
* of this interface useful for differentiating different batch job types, or
* for creating more flexibility within their batch jobs.
*
* @see StepConfiguration
* @author Lucas Ward
* @author Dave Syer
*
*/
public interface Tasklet {
/**
* Primary batch processing driver. All processing of batch business data
* should be handled within this method. Any processing which intends to
* control the flow of the batch lifecycle by throwing exceptions (such as
* BatchCriticalExeception) should throw them within this method. Doing so
* outside of this method will prevent the architecture from gracefully
* shutting down and providing such features as transaction rollback.
*
* @return boolean indicating whether the processing should continue (i.e.
* false when data are exhausted).
*/
public boolean execute() throws Exception;
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Interfaces and generic implementations of tasklet concerns.
</p>
</body>
</html>

View File

@@ -0,0 +1,8 @@
<html>
<body>
<p>
The Core domain concepts expressed as interfaces and generic
implementations.
</p>
</body>
</html>

View File

@@ -0,0 +1,8 @@
Changelog: Spring Batch Core
* 1.0-M2
** 2007/07/12
* No-one uses this file: we should just switch to auto-generated changelogs?

View File

@@ -0,0 +1,60 @@
------
Simple Batch Execution Core
------
Dave Syer
------
August 2007
Overview of the Spring Batch Core Domain
The Spring Batch Core Domain consists of a public API for launching,
monitoring and managing batch jobs.
[images/core-domain-overview.png] The Spring Batch Core Domain with
dependencies to infrastructure indicated schematically.
The figure above shows the central parts of the core domain and its
main touch points with the batch application develepor
(<<<*Configuration>>>). To launch a job there is a
<<<JobExecutor>>> interface and a facade for it that can be used to
simplify the launching for dumb clients like JMX or a command line.
A <<<JobConfiguration>>> is composed of a list of
<<<StepConfiguration>>>s, each of which is executed in turn by the
<<<JobExecutor>>>, delegating to a <<<StepExecutor>>>. The
<<<StepExecutor>>> is a central strategy in the Spring Batch Core.
Implementations of <<<StepExecutor>>> are responsible for sharing
the work specified by the <<<StepConfiguration>>> out, but in ways
that the configuration doesn't need to be aware of. For instance,
the same <<<StepConfiguration>>> might be used in a simple
in-process sequential executor, or in a multi-threaded
implementation, or one that delegates to remote calls to a
distributed system.
[images/core-domain-extended.png] The Spring Batch Core Domain
extended to include the datababase entities and identifier strategy.
A <<<JobConfiguration>>> can be re-used to create multiple job
instances and this is reflected in the figure above showing an
extended picture of the core domain. When a <<<JobConfiguration>>>
is launched the <<<JobExecutor>>> first checks to see if a job with
the same <<<JobIdentifier>>> was already executed. We expect one of
the following outcomes, depending on the <<<JobExecutor>>>
implementation and <<<JobConfiguration>>>:
* If the job was not previously launched then it can be created
and executed. A new <<<JobInstance>>> is created and stored in a
repository (usually a database). A new <<<JobExecution>>> is also
created to track the progress of this particular execution.
* If the job was previously launched the <<<JobConfiguration>>>
has a flag indicating whether or not to continue and launch a new
execution (was this expected?). The decision is parameterised to
depend on whether or not the job failed last time it was executed.
If the there was a previous failure - maybe the operator has fixed
some bad input and wants to run it again - then we might want to
restart the previous job. Or it might be an ad-hoc request that
doesn't need to be distinguished from previous runs. In either
case a new <<<JobExecution>>> is created and stored to monitor
this execution of the <<<JobInstance>>>.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

31
core/src/site/site.xml Normal file
View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Spring Batch: ${project.name}">
<bannerLeft>
<name>Spring Batch: ${project.name}</name>
</bannerLeft>
<bannerRight>
<src>images/shim.gif</src>
</bannerRight>
<poweredBy>
<logo name="" href="" img="images/shim.gif"/>
</poweredBy>
<skin>
<groupId>org.springframework.maven.skins</groupId>
<artifactId>maven-spring-skin</artifactId>
<version>1.0.3</version>
</skin>
<body>
<links>
<item name="Home" href="../index.html"/>
<item name="${project.name}" href="index.html"/>
</links>
<menu name="Spring Batch Core">
<item name="${project.name}" href="index.html"/>
<item name="Changelog" href="changelog.html"/>
</menu>
<menu ref="reports"/>
</body>
</project>

View File

@@ -0,0 +1,37 @@
/*
* 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;
import junit.framework.TestCase;
public abstract class AbstractExceptionTests extends TestCase {
public void testExceptionString() throws Exception {
Exception exception = getException("foo");
assertEquals("foo", exception.getMessage());
}
public void testExceptionStringThrowable() throws Exception {
Exception exception = getException("foo", new IllegalStateException());
assertEquals("foo", exception.getMessage().substring(0, 3));
}
public abstract Exception getException(String msg) throws Exception;
public abstract Exception getException(String msg, Throwable t) throws Exception;
}

View File

@@ -0,0 +1,44 @@
/*
* 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.configuration;
import org.springframework.batch.core.AbstractExceptionTests;
import org.springframework.batch.core.configuration.DuplicateJobConfigurationException;
/**
* @author Dave Syer
*
*/
public class DuplicateJobConfigurationExceptionTests extends AbstractExceptionTests {
/*
* (non-Javadoc)
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String)
*/
public Exception getException(String msg) throws Exception {
return new DuplicateJobConfigurationException(msg);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String,
* java.lang.Throwable)
*/
public Exception getException(String msg, Throwable t) throws Exception {
return new DuplicateJobConfigurationException(msg, t);
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.configuration;
import org.springframework.batch.core.AbstractExceptionTests;
import org.springframework.batch.core.configuration.JobConfigurationException;
/**
* @author Dave Syer
*
*/
public class JobConfigurationExceptionTests extends AbstractExceptionTests {
/*
* (non-Javadoc)
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String)
*/
public Exception getException(String msg) throws Exception {
return new JobConfigurationException(msg);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String,
* java.lang.Throwable)
*/
public Exception getException(String msg, Throwable t) throws Exception {
return new JobConfigurationException(msg, t);
}
}

View File

@@ -0,0 +1,106 @@
/*
* 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.configuration;
import java.util.Collections;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class JobConfigurationTests extends TestCase {
JobConfiguration configuration = new JobConfiguration("job");
/**
* Test method for
* {@link org.springframework.batch.core.configuration.JobConfiguration#JobConfiguration()}.
*/
public void testJobConfiguration() {
configuration = new JobConfiguration();
assertNull(configuration.getName());
}
/**
* Test method for
* {@link org.springframework.batch.core.configuration.JobConfiguration#setBeanName(java.lang.String)}.
*/
public void testSetBeanName() {
configuration.setBeanName("foo");
assertEquals("job", configuration.getName());
}
/**
* Test method for
* {@link org.springframework.batch.core.configuration.JobConfiguration#setBeanName(java.lang.String)}.
*/
public void testSetBeanNameWithNullName() {
configuration.setName(null);
assertEquals(null, configuration.getName());
configuration.setBeanName("foo");
assertEquals("foo", configuration.getName());
}
/**
* Test method for
* {@link org.springframework.batch.core.configuration.JobConfiguration#setName(java.lang.String)}.
*/
public void testSetName() {
configuration.setName("foo");
assertEquals("foo", configuration.getName());
}
/**
* Test method for
* {@link org.springframework.batch.core.configuration.JobConfiguration#setSteps(java.util.List)}.
*/
public void testSetSteps() {
configuration.setSteps(Collections.singletonList(new StepConfigurationSupport("step")));
assertEquals(1, configuration.getStepConfigurations().size());
}
/**
* Test method for
* {@link org.springframework.batch.core.configuration.JobConfiguration#addStep(org.springframework.batch.core.configuration.StepConfiguration)}.
*/
public void testAddStep() {
configuration.addStep(new StepConfigurationSupport("step"));
assertEquals(1, configuration.getStepConfigurations().size());
}
/**
* Test method for
* {@link org.springframework.batch.core.configuration.JobConfiguration#setStartLimit(int)}.
*/
public void testSetStartLimit() {
assertEquals(Integer.MAX_VALUE, configuration.getStartLimit());
configuration.setStartLimit(10);
assertEquals(10, configuration.getStartLimit());
}
/**
* Test method for
* {@link org.springframework.batch.core.configuration.JobConfiguration#setRestartable(boolean)}.
*/
public void testSetRestartable() {
assertFalse(configuration.isRestartable());
configuration.setRestartable(true);
assertTrue(configuration.isRestartable());
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.configuration;
import org.springframework.batch.core.AbstractExceptionTests;
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
/**
* @author Dave Syer
*
*/
public class NoSuchJobConfigurationExceptionTests extends AbstractExceptionTests {
/*
* (non-Javadoc)
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String)
*/
public Exception getException(String msg) throws Exception {
return new NoSuchJobConfigurationException(msg);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String,
* java.lang.Throwable)
*/
public Exception getException(String msg, Throwable t) throws Exception {
return new NoSuchJobConfigurationException(msg, t);
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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.configuration;
import junit.framework.TestCase;
import org.springframework.batch.core.tasklet.Tasklet;
/**
* @author Dave Syer
*
*/
public class StepConfigurationSupportTests extends TestCase {
private StepConfigurationSupport configuration = new StepConfigurationSupport("step");
/**
* Test method for {@link org.springframework.batch.core.configuration.StepConfigurationSupport#StepConfigurationSupport()}.
*/
public void testStepConfigurationSupport() {
configuration = new StepConfigurationSupport();
assertNull(configuration.getName());
}
/**
* Test method for {@link org.springframework.batch.core.configuration.StepConfigurationSupport#getName()}.
*/
public void testGetName() {
configuration.setName("foo");
assertEquals("foo", configuration.getName());
}
/**
* Test method for {@link org.springframework.batch.core.configuration.StepConfigurationSupport#getStartLimit()}.
*/
public void testGetStartLimit() {
assertEquals(Integer.MAX_VALUE, configuration.getStartLimit());
configuration.setStartLimit(10);
assertEquals(10, configuration.getStartLimit());
}
/**
* Test method for {@link org.springframework.batch.core.configuration.StepConfigurationSupport#getTasklet()}.
*/
public void testGetTasklet() {
assertEquals(null, configuration.getTasklet());
Tasklet tasklet = new Tasklet() {
public boolean execute() throws Exception {
return false;
}
};
configuration.setTasklet(tasklet);
assertEquals(tasklet, configuration.getTasklet());
}
/**
* Test method for {@link org.springframework.batch.core.configuration.StepConfigurationSupport#isAllowStartIfComplete()}.
*/
public void testShouldAllowStartIfComplete() {
assertEquals(false, configuration.isAllowStartIfComplete());
configuration.setAllowStartIfComplete(true);
assertEquals(true, configuration.isAllowStartIfComplete());
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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.domain;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class BatchStatusTests extends TestCase {
/**
* Test method for {@link org.springframework.batch.core.domain.BatchStatus#toString()}.
*/
public void testToString() {
assertEquals("FAILED", BatchStatus.FAILED.toString());
}
/**
* Test method for {@link org.springframework.batch.core.domain.BatchStatus#getStatus(java.lang.String)}.
*/
public void testGetStatus() {
assertEquals(BatchStatus.FAILED, BatchStatus.getStatus(BatchStatus.FAILED.toString()));
}
/**
* Test method for {@link org.springframework.batch.core.domain.BatchStatus#getStatus(java.lang.String)}.
*/
public void testGetStatusWrongCode() {
assertEquals(null, BatchStatus.getStatus("foo"));
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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.domain;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class EntityTests extends TestCase {
Entity entity = new Entity(new Long(11));
/**
* Test method for {@link org.springframework.batch.core.domain.Entity#hashCode()}.
*/
public void testHashCode() {
assertEquals(entity.hashCode(), new Entity(entity.getId()).hashCode());
}
/**
* Test method for {@link org.springframework.batch.core.domain.Entity#hashCode()}.
*/
public void testHashCodeNullId() {
int withoutNull = entity.hashCode();
entity.setId(null);
int withNull = entity.hashCode();
assertTrue(withoutNull!=withNull);
}
/**
* Test method for {@link org.springframework.batch.core.domain.Entity#getVersion()}.
*/
public void testGetVersion() {
assertEquals(null, entity.getVersion());
}
/**
* @throws Exception
*/
public void testToString() throws Exception {
Entity job = new Entity();
assertTrue(job.toString().indexOf("id=null") >= 0);
}
/**
* Test method for {@link org.springframework.batch.core.domain.Entity#equals(java.lang.Object)}.
*/
public void testEqualsEntity() {
assertEquals(entity, new Entity(entity.getId()));
}
/**
* Test method for {@link org.springframework.batch.core.domain.Entity#equals(java.lang.Object)}.
*/
public void testEqualsEntityWrongId() {
assertFalse(entity.equals(new Entity()));
}
/**
* Test method for {@link org.springframework.batch.core.domain.Entity#equals(java.lang.Object)}.
*/
public void testEqualsObject() {
assertFalse(entity.equals(new Object()));
}
/**
* Test method for {@link org.springframework.batch.core.domain.Entity#equals(java.lang.Object)}.
*/
public void testEqualsNull() {
assertFalse(entity.equals(null));
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.domain;
import java.sql.Timestamp;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class JobExecutionTests extends TestCase {
private JobExecution execution = new JobExecution(new Long(11));
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#JobExecution()}.
*/
public void testJobExecution() {
assertNull(new JobExecution().getId());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#getEndTime()}.
*/
public void testGetEndTime() {
assertNull(execution.getEndTime());
execution.setEndTime(new Timestamp(100L));
assertEquals(100L, execution.getEndTime().getTime());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#getStartTime()}.
*/
public void testGetStartTime() {
assertNotNull(execution.getStartTime());
execution.setStartTime(new Timestamp(0L));
assertEquals(0L, execution.getStartTime().getTime());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#getStatus()}.
*/
public void testGetStatus() {
assertEquals(BatchStatus.STARTING, execution.getStatus());
execution.setStatus(BatchStatus.COMPLETED);
assertEquals(BatchStatus.COMPLETED, execution.getStatus());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#getJobId()}.
*/
public void testGetJobId() {
assertEquals(11, execution.getJobId().longValue());
execution.setJobId(new Long(23));
assertEquals(23, execution.getJobId().longValue());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#getExitCode()}.
*/
public void testGetExitCode() {
assertEquals(0, execution.getExitCode());
execution.setExitCode(23);
assertEquals(23, execution.getExitCode());
}
}

View File

@@ -0,0 +1,100 @@
/*
* 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.domain;
import java.util.Collections;
import org.springframework.batch.core.runtime.JobIdentifier;
import junit.framework.TestCase;
/**
* @author dsyer
*
*/
public class JobInstanceTests extends TestCase {
private JobInstance instance = new JobInstance(new Long(11));
/**
* Test method for {@link org.springframework.batch.core.domain.JobInstance#JobInstance()}.
*/
public void testJobInstance() {
assertNull(new JobInstance().getId());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobInstance#getStatus()}.
*/
public void testGetStatus() {
assertNull(instance.getStatus());
instance.setStatus(BatchStatus.COMPLETED);
assertNotNull(instance.getStatus());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobInstance#getSteps()}.
*/
public void testGetSteps() {
assertEquals(0, instance.getSteps().size());
instance.setSteps(Collections.singletonList(new StepInstance()));
assertEquals(1, instance.getSteps().size());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobInstance#addStep(org.springframework.batch.core.domain.StepInstance)}.
*/
public void testAddStep() {
instance.addStep(new StepInstance());
assertEquals(1, instance.getSteps().size());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobInstance#getJobExecutionCount()}.
*/
public void testGetJobExecutionCount() {
assertEquals(0, instance.getJobExecutionCount());
instance.setJobExecutionCount(22);
assertEquals(22, instance.getJobExecutionCount());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobInstance#getIdentifier()}.
*/
public void testGetIdentifier() {
assertEquals(null, instance.getIdentifier());
instance.setIdentifier(new JobIdentifier() {
public String getName() {
return "foo";
}
});
assertEquals("foo", instance.getIdentifier().getName());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobInstance#getIdentifier()}.
*/
public void testGetName() {
assertEquals(null, instance.getName());
instance.setIdentifier(new JobIdentifier() {
public String getName() {
return "foo";
}
});
assertEquals("foo", instance.getName());
}
}

View File

@@ -0,0 +1,190 @@
/*
* 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.domain;
import java.sql.Timestamp;
import java.util.Properties;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class StepExecutionTests extends TestCase {
private StepExecution execution = new StepExecution(new Long(11), new Long(23));
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#JobExecution()}.
*/
public void testStepExecution() {
assertNull(new StepExecution().getId());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#getEndTime()}.
*/
public void testGetEndTime() {
assertNull(execution.getEndTime());
execution.setEndTime(new Timestamp(0L));
assertEquals(0L, execution.getEndTime().getTime());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#getStartTime()}.
*/
public void testGetStartTime() {
assertNotNull(execution.getStartTime());
execution.setStartTime(new Timestamp(10L));
assertEquals(10L, execution.getStartTime().getTime());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#getStatus()}.
*/
public void testGetStatus() {
assertEquals(BatchStatus.STARTING, execution.getStatus());
execution.setStatus(BatchStatus.COMPLETED);
assertEquals(BatchStatus.COMPLETED, execution.getStatus());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#getJobId()}.
*/
public void testGetJobId() {
assertEquals(23, execution.getJobExecutionId().longValue());
}
/**
* Test method for {@link org.springframework.batch.core.domain.JobExecution#getExitCode()}.
*/
public void testGetExitCode() {
assertEquals(0, execution.getExitCode());
execution.setExitCode(23);
assertEquals(23, execution.getExitCode());
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepExecution#incrementCommitCount()}.
*/
public void testIncrementCommitCount() {
int before = execution.getCommitCount().intValue();
execution.incrementCommitCount();
int after = execution.getCommitCount().intValue();
assertEquals(before+1, after);
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepExecution#incrementTaskCount()}.
*/
public void testIncrementLuwCount() {
int before = execution.getTaskCount().intValue();
execution.incrementTaskCount();
int after = execution.getTaskCount().intValue();
assertEquals(before+1, after);
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepExecution#incrementRollbackCount()}.
*/
public void testIncrementRollbackCount() {
int before = execution.getRollbackCount().intValue();
execution.incrementRollbackCount();
int after = execution.getRollbackCount().intValue();
assertEquals(before+1, after);
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepExecution#getCommitCount()}.
*/
public void testGetCommitCount() {
execution.setCommitCount(123);
assertEquals(123, execution.getCommitCount().intValue());
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepExecution#getTaskCount()}.
*/
public void testGetTaskCount() {
execution.setTaskCount(123);
assertEquals(123, execution.getTaskCount().intValue());
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepExecution#getRollbackCount()}.
*/
public void testGetRollbackCount() {
execution.setRollbackCount(123);
assertEquals(123, execution.getRollbackCount().intValue());
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepExecution#getStepId()}.
*/
public void testGetStepId() {
assertEquals(11, execution.getStepId().longValue());
}
public void testToString() throws Exception {
assertTrue("Should contain task count: "+execution.toString(), execution.toString().indexOf("task")>=0);
assertTrue("Should contain commit count: "+execution.toString(), execution.toString().indexOf("commit")>=0);
assertTrue("Should contain rollback count: "+execution.toString(), execution.toString().indexOf("rollback")>=0);
}
public void testStatistics() throws Exception {
assertNotNull(execution.getStatistics());
execution.setStatistics(new Properties() {{
setProperty("foo", "bar");
}});
assertEquals("bar", execution.getStatistics().getProperty("foo"));
}
public void testEqualsWithSameIdentifier() throws Exception {
StepExecution step1 = new StepExecution(new Long(100), new Long(11));
StepExecution step2 = new StepExecution(new Long(100), new Long(11));
assertEquals(step1, step2);
}
public void testEqualsWithNull() throws Exception {
StepExecution step = new StepExecution(new Long(100), new Long(11));
assertFalse(step.equals(null));
}
public void testEqualsWithNullIdentifiers() throws Exception {
StepExecution step = new StepExecution(new Long(100), new Long(11));
assertFalse(step.equals(new StepExecution()));
}
public void testEqualsWithNullJob() throws Exception {
StepExecution step = new StepExecution(null, new Long(11));
assertFalse(step.equals(new StepExecution()));
}
public void testEqualsWithNullStep() throws Exception {
StepExecution step = new StepExecution(new Long(11), null);
assertFalse(step.equals(new StepExecution()));
}
public void testHashCode() throws Exception {
assertTrue("Hash code same as parent", new Entity(execution.getId()).hashCode()!=execution.hashCode());
}
public void testHashCodeWithNullIds() throws Exception {
assertTrue("Hash code not same as parent", new Entity(execution.getId()).hashCode()!=new StepExecution().hashCode());
}
}

View File

@@ -0,0 +1,125 @@
/*
* 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.domain;
import java.util.Properties;
import org.springframework.batch.restart.GenericRestartData;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class StepInstanceTests extends TestCase {
StepInstance instance = new StepInstance(new Long(13));
/**
* Test method for {@link org.springframework.batch.core.domain.StepInstance#StepInstance()}.
*/
public void testStepInstance() {
assertNull(new StepInstance().getId());
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepInstance#getStepExecutionCount()}.
*/
public void testGetStepExecutionCount() {
assertEquals(0, instance.getStepExecutionCount());
instance.setStepExecutionCount(23);
assertEquals(23, instance.getStepExecutionCount());
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepInstance#getRestartData()}.
*/
public void testGetRestartData() {
assertNotNull(instance.getRestartData());
assertEquals(null, instance.getRestartData().getProperties());
instance.setRestartData(new GenericRestartData(new Properties() {{
setProperty("foo", "bar");
}}));
assertEquals("bar", instance.getRestartData().getProperties().getProperty("foo"));
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepInstance#getStatus()}.
*/
public void testGetStatus() {
assertEquals(null, instance.getStatus());
instance.setStatus(BatchStatus.COMPLETED);
assertEquals(BatchStatus.COMPLETED, instance.getStatus());
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepInstance#getJob()}.
*/
public void testGetJob() {
assertEquals(null, instance.getJob());
JobInstance job = new JobInstance();
instance.setJob(job);
assertEquals(job, instance.getJob());
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepInstance#getStepExecution()}.
*/
public void testGetStepExecution() {
assertEquals(null, instance.getStepExecution());
StepExecution execution = new StepExecution(instance.getId(), new Long(111));
instance.setStepExecution(execution);
assertNotNull(execution.getJobExecutionId());
assertEquals(execution.getJobExecutionId(), instance.getStepExecution().getJobExecutionId());
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepInstance#getName()}.
*/
public void testGetName() {
assertEquals(null, instance.getName());
instance.setName("foo");
assertEquals("foo", instance.getName());
}
/**
* Test method for {@link org.springframework.batch.core.domain.StepInstance#getJobId()}.
*/
public void testGetJobId() {
assertEquals(null, instance.getJobId());
instance.setJob(new JobInstance(new Long(23)));
assertEquals(23, instance.getJobId().longValue());
}
public void testEqualsWithSameIdentifier() throws Exception {
JobInstance job = new JobInstance(new Long(100));
StepInstance step1 = new StepInstance(new Long(0));
StepInstance step2 = new StepInstance(new Long(0));
step1.setJob(job);
step2.setJob(job);
String stepName = "foo";
step1.setName(stepName);
step2.setName(stepName);
assertEquals(step1, step2);
}
public void testToString() throws Exception {
assertTrue("Should contain name", instance.toString().indexOf("name=")>=0);
assertTrue("Should contain status", instance.toString().indexOf("status=")>=0);
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.executor;
import org.springframework.batch.core.AbstractExceptionTests;
/**
* @author Dave Syer
*
*/
public class StepInterruptedExceptionTests extends AbstractExceptionTests {
/* (non-Javadoc)
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String)
*/
public Exception getException(String msg) throws Exception {
return new StepInterruptedException(msg);
}
/* (non-Javadoc)
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String, java.lang.Throwable)
*/
public Exception getException(String msg, Throwable t) throws Exception {
return new RuntimeException(msg, t);
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.repository;
import org.springframework.batch.core.AbstractExceptionTests;
/**
* @author Dave Syer
*
*/
public class BatchRestartExceptionTests extends AbstractExceptionTests {
/*
* (non-Javadoc)
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String)
*/
public Exception getException(String msg) throws Exception {
return new BatchRestartException(msg);
}
/*
* (non-Javadoc)
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String,
* java.lang.Throwable)
*/
public Exception getException(String msg, Throwable t) throws Exception {
return new BatchRestartException(msg, t);
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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.repository;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class NoSuchBatchDomainObjectExceptionTests extends TestCase {
public void testCreateException() throws Exception {
NoSuchBatchDomainObjectException e = new NoSuchBatchDomainObjectException("Foo");
assertEquals("Foo", e.getMessage());
}
}

View File

@@ -0,0 +1,118 @@
/*
* 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.runtime;
import junit.framework.TestCase;
import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.repeat.context.RepeatContextSupport;
/**
* @author Dave Syer
*
*/
public class JobExecutionContextTests extends TestCase {
private JobExecutionContext context = createContext("foo", 11);
public void testContextContainsInfo() throws Exception {
assertEquals("foo", context.getJobIdentifier().getName());
}
public void testNullContexts() throws Exception {
assertEquals(0, context.getStepContexts().size());
assertEquals(0, context.getChunkContexts().size());
}
public void testStepContext() throws Exception {
context.registerStepContext(new RepeatContextSupport(null));
assertEquals(1, context.getStepContexts().size());
}
public void testAddAndRemoveStepContext() throws Exception {
context.registerStepContext(new RepeatContextSupport(null));
assertEquals(1, context.getStepContexts().size());
context.unregisterStepContext(new RepeatContextSupport(null));
assertEquals(0, context.getStepContexts().size());
}
public void testAddAndRemoveStepExecution() throws Exception {
assertEquals(0, context.getStepExecutions().size());
context.registerStepExecution(new StepExecution(new Long(11), new Long(12)));
assertEquals(1, context.getStepExecutions().size());
}
public void testAddAndRemoveChunkContext() throws Exception {
context.registerChunkContext(new RepeatContextSupport(null));
assertEquals(1, context.getChunkContexts().size());
context.unregisterChunkContext(new RepeatContextSupport(null));
assertEquals(0, context.getChunkContexts().size());
}
public void testRemoveChunkContext() throws Exception {
context.unregisterChunkContext(new RepeatContextSupport(null));
assertEquals(0, context.getChunkContexts().size());
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#equals(java.lang.Object)}.
*/
public void testEqualsObject() {
assertFalse(context.equals(new Object()));
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#equals(java.lang.Object)}.
*/
public void testEqualsNull() {
assertFalse(context.equals(null));
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#equals(java.lang.Object)}.
*/
public void testEqualsContext() {
JobExecutionContext other = createContext("foo", 11);
assertFalse("Expect unequal before save", context.equals(other));
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#toString()}.
*/
public void testToString() {
assertTrue("Identifier not contained in toString: " + context.toString(), context.toString().indexOf("identifier=") >= 0);
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#hashCode()}.
*/
public void testHashCode() {
assertNotNull(context.getJob().getId());
assertNull(context.getJobExecution().getId());
assertTrue("Expecting unequal hash codes before save", context.hashCode() != createContext("foo", 11)
.hashCode());
}
private JobExecutionContext createContext(String name, int jobId) {
return new JobExecutionContext(new SimpleJobIdentifier(name), new JobInstance(new Long(jobId)));
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.runtime;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
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
* {@link org.springframework.batch.core.runtime.SimpleJobIdentifier#getName()}.
*/
public void testGetName() {
assertEquals("foo", identifier.getName());
identifier.setName("bar");
assertEquals("bar", identifier.getName());
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.SimpleJobIdentifier#toString()}.
*/
public void testToString() {
assertTrue("SimpleJobIdentifier toString should contain name: " + identifier.toString(), identifier.toString()
.indexOf("name=") >= 0);
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.runtime;
import junit.framework.TestCase;
import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.domain.StepInstance;
/**
* @author Dave Syer
*
*/
public class StepExecutionContextTests extends TestCase {
private StepExecutionContext context = createContext("foo", 11, 12);
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#hashCode()}.
*/
public void testHashCode() {
assertNotNull(context.getStep().getId());
assertNull(context.getStepExecution().getId());
assertTrue("Expecting unequal hash codes before save", context.hashCode() != createContext("foo", 11, 12)
.hashCode());
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#getStep()}.
*/
public void testGetStep() {
assertNotNull(context.getStep());
assertEquals(12, context.getStep().getId().longValue());
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#getJobExecutionContext()}.
*/
public void testGetJobExecutionContext() {
assertNotNull(context.getJobExecutionContext());
assertEquals(11, context.getJobExecutionContext().getJob().getId().longValue());
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#getStepExecution()}.
*/
public void testGetStepExecution() {
assertNotNull(context.getStepExecution());
assertEquals(null, context.getStepExecution().getId());
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#equals(java.lang.Object)}.
*/
public void testEqualsObject() {
assertFalse(context.equals(new Object()));
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#equals(java.lang.Object)}.
*/
public void testEqualsNull() {
assertFalse(context.equals(null));
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#equals(java.lang.Object)}.
*/
public void testEqualsContext() {
StepExecutionContext other = createContext("foo", 11, 12);
assertTrue(context.equals(other));
}
/**
* Test method for
* {@link org.springframework.batch.core.runtime.StepExecutionContext#toString()}.
*/
public void testToString() {
assertTrue("Step not contained in toString: " + context.toString(), context.toString().indexOf("step=") >= 0);
}
/**
* @param name
* @param jobId
* @param stepId
* @return
*/
private StepExecutionContext createContext(String name, int jobId, int stepId) {
JobInstance job = new JobInstance(new Long(jobId));
return new StepExecutionContext(new JobExecutionContext(new SimpleJobIdentifier(name), job), new StepInstance(
new Long(stepId)));
}
}

View File

@@ -0,0 +1,172 @@
Product: Clover
License: Open Source License, 0.x, 1.x
Issued: Thu Mar 15 2007 12:55:00 CDT
Expiry: Never
Maintenance Expiry: Never
Key: d24b469cbe33bb71017d39a9d
Name: Andy Colyer
Org: Spring Portfolio
Certificate: AAACUG+Ow8B7/zEbxOMqqKwwrdpP+a1COmJGHco7sCNLjHkHnajPF+dQW
Ct12PMy0uml0s9xuus5wKngJ9OFk5/FZgYzdyIG5/rxEgRevOoLO7uYipoJrkt4TPBwIm4
hxEw+b9xUNP0x1tTqSsgUP6fqSYilMajaHYGuRD9iV3LeP7hwWulpXY3hz3W5WjsKYp3Nf
fPyts/AffWHANGj5DHV+4yGm2IGIzIgHOGx9hISC7boFknmwM/GQ78RO1yzNnkSJ9dHPz2
VdGTrKob36k3OVy7vwwCPpSm+01KDpkY4ZQN4ynqPIFzvJ07F1IBUvU49CGzSvX3v6qmOp
mT11CTGtP49xPafrKNjDDV8PxCsoesEBRaY4FJzquzWz0j6CkIQqidzCj3WDCtog3ct+za
SuuZ51n027sVFhbM69dZZzv8bYCgSHdQ3sG1a9DxM7+6JRfRcIBFgt/V78vK41MF4p9Mi1
qmEPMLizpu7eBo1GDoQ8Lb3EhIWrfxDb4Db3NFc9hYpCKoreFlEw1A+eJlrLeomy43pVtk
SNPTDDoahNrXLeIu7SiRoHiemMrUjWvYtT9jwnVOsIjELa8n8cfW7gMzJdenCcNWl/T3Cr
8rSu3pVfz07AvX6+wQZWqzvGGnlwpnFXu1YJROxITYNINVNKXCAby33Mdbm51DPA3rEyk+
dpS31tU2XrR4iY1Zypja1M0voOkzL74pf9ExgUGeJqyvi5LWTn3b4kGGT/bkwhbbDn6sAA
zlxKRvxsbYOBUzk3UZ448Heg2HwCjwarCh/C0QIcX8vWnUjqssdvxT7Jlr1rZwqK1LKqbH
l7YvP9Ee7SoHfoHrW770yK23u2IdDK44Sf6G3NBE0Muq7W1bcZwrZ1/ZRk8vE2kt0F0fXI
wz7Thjs5lXvcZDJO4nEtXpmSdCaDjUXBpjvsZE2ZjPa2Q1tv3KFhHWqdfNRant7FyeWYg=
=
License Agreement: CLOVER VERSION 1 (ONE) SOFTWARE LICENSE AGREEMENT
1. Licenses and Software
Cenqua Pty Ltd, an Australian Proprietary Limited Company ("CENQUA")
hereby grants to the purchaser (the "LICENSEE") a limited, revocable,
worldwide, non-exclusive, nontransferable, non-sublicensable license
to use the Clover version 1 (one) software (the "Software"),
including any minor upgrades thereof during the Term (hereinafter
defined) up to, but not including the next major version of the
Software. The licensee shall not, or knowingly allow others to,
reverse engineer, decompile, disassemble, modify, adapt, create
derivative works from or otherwise attempt to derive source code from
the Software provided. And, in accordance with the terms and
conditions of this Software License Agreement (the "Agreement"), the
Software shall be used solely by the licensed users in accordance
with the following edition specific conditions:
a) Server Edition
A Server Edition license entitles the Licensee to execute one
instance of Clover Server Edition on one (1) machine for the purposes
of instrumententing source code and generating reports. There are no
limitations on the use of the instrumented source code or generated
reports produced by Server Edition.
b) Workstation Edition
A Workstation Edition license entitles the licensee to use Clover
Workstation Edition on one (1) machine by one (1) individual end
user. Workstation Edition does not permit the generation of reports
for distribution.
c) Team Edition
A Team Edition license entitles the licensee to use Clover Team
edition on any number of machines solely by the licensed number of
users. Reports generated by Clover Team Edition are strictly for use
only by the licensed number of individual end users.
2. License Fee
In exchange for the License(s), the Licensee shall pay to CENQUA a
one-time, up front, non-refundable license fee. At the sole
discretion of CENQUA this fee will be waived for non-commercial
projects. Notwithstanding the Licensee's payment of the License Fee,
CENQUA reserves the right to terminate the License if CENQUA
discovers that the Licensee and/or the Licensee's use of the Software
is in breach of this Agreement.
3. Proprietary Rights
CENQUA will retain all right, title and interest in and to the
Software, all copies thereof, and CENQUA website(s), software, and
other intellectual property, including, but not limited to, ownership
of all copyrights, look and feel, trademark rights, design rights,
trade secret rights and any and all other intellectual property and
other proprietary rights therein. The Licensee will not directly or
indirectly obtain or attempt to obtain at any time, any right, title
or interest by registration or otherwise in or to the trademarks,
service marks, copyrights, trade names, symbols, logos or
designations or other intellectual property rights owned or used by
CENQUA. All technical manuals or other information provided by CENQUA
to the Licensee shall be the sole property of CENQUA.
4. Term and Termination
Subject to the other provisions hereof, this Agreement shall commence
upon the Licensee's opting into this Agreement and continue until the
Licensee discontinues use of the Software or the Agreement terminates
automatically upon the Licensee's breach of any term or condition of
this Agreement (the "Term"). Upon any such termination, the Licensee
will delete the Software immediately.
5. Copying & Transfer
The Licensee may copy the Software for back-up purposes only. The
Licensee may not assign or otherwise transfer the Software to any
third party.
6. Specific Disclaimer of Warranty and Limitation of Liability
THE SOFTWARE IS PROVIDED WITHOUT WARRANTY OF ANY KIND. CENQUA
DISCLAIMS ALL WARRANTIES, EXPRESSED OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE. CENQUA WILL NOT BE LIABLE FOR ANY DAMAGES
ASSOCIATED WITH THE SOFTWARE, INCLUDING, WITHOUT LIMITATION,
ORDINARY, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OF ANY KIND,
INCLUDING BUT NOT LIMITED TO DAMAGES RELATING TO LOST DATA OR LOST
PROFITS, EVEN IF CENQUA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
7. Warranties and Representations
Licensee Indemnification. CENQUA agrees to indemnify, defend and hold
the Licensee harmless from and against any and all liabilities,
damages, losses, claims, costs, and expenses (including reasonable
legal fees) arising out of or resulting from the Software or the use
thereof infringing upon, misappropriating or violating any patents,
copyrights, trademarks, or trade secret rights or other proprietary
rights of persons, firms or entities who are not parties to this
Agreement.
CENQUA Indemnification. The Licensee warrants and represents that the
Licensee's actions with regard to the Software will be in compliance
with all applicable laws; and the Licensee agrees to indemnify,
defend, and hold CENQUA harmless from and against any and all
liabilities, damages, losses, claims, costs, and expenses (including
reasonable legal fees) arising out of or resulting from the
Licensee's failure to observe the use restrictions set forth herein.
8. Publicity
The Licensee grants permission for CENQUA to use Licensee's name
solely in customer lists. CENQUA shall not, without prior consent in
writing, use the Licensee's name, or that of its affiliates, in any
form with the specific exception of customer lists. CENQUA agrees to
remove Licensee's name from any and all materials within 7 days if
notified by the Licensee in writing.
9. Governing Law
This Agreement shall be governed by the laws of New South Wales,
Australia.
10.Independent Contractors
The parties are independent contractors with respect to each other,
and nothing in this Agreement shall be construed as creating an
employer-employee relationship, a partnership, agency relationship or
a joint venture between the parties.
11. Assignment
This Agreement is not assignable or transferable by the Licensee.
CENQUA in its sole discretion may transfer a license to a third party
at the written request of the Licensee.
12. Entire Agreement
This Agreement constitutes the entire agreement between the parties
concerning the Licensee's use of the Software. This Agreement
supersedes any prior verbal understanding between the parties and any
Licensee purchase order or other ordering document, regardless of
whether such document is received by CENQUA before or after execution
of this Agreement. This Agreement may be amended only in writing by
CENQUA.

View File

@@ -0,0 +1,13 @@
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.category.org.apache.activemq=ERROR
log4j.category.org.springframework.batch=DEBUG
log4j.category.org.springframework.transaction=INFO
log4j.category.org.hibernate.SQL=DEBUG
# for debugging datasource initialization
# log4j.category.test.jdbc=DEBUG

49
dictionary.txt Normal file
View File

@@ -0,0 +1,49 @@
pluggable
resynchronize
lifecycle
username
javadoc
refactoring
rollbacks
synchronization
programmatically
apache
rollback
callback
callbacks
throwable
interceptors
serializable
accessor
synchronized
registry
synchronizes
autostart
listable
rethrows
interceptor
transactional
continuable
proxy
dave
syer
versioned
unversionable
stateful
locatable
synchronizations
restartable
restartability
strategise
tokenized
initialize
uninitialized
aggregator
aggregators
lucas
throwables
hibernate
incrementer
hoc
unbind
tasklet

23
docs/.project Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>batch-docs</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,4 @@
#Sun Jul 08 09:33:19 BST 2007
eclipse.preferences.version=1
project.repository.kind=jira
project.repository.url=http\://opensource.atlassian.com/projects/spring

127
docs/pom.xml Normal file
View File

@@ -0,0 +1,127 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-batch-docs</artifactId>
<name>Documentation</name>
<packaging>pom</packaging>
<description>Spring Batch Documentation - reference guide and user manuals.</description>
<parent>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch</artifactId>
<version>1.0-m2-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<pluginRepositories>
<pluginRepository>
<id>agilejava</id>
<url>http://agilejava.com/maven</url>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId>
<executions>
<execution>
<id>single-page</id>
<goals>
<goal>generate-html</goal>
<goal>generate-pdf</goal>
</goals>
<configuration>
<chunkedOutput>false</chunkedOutput>
<htmlCustomization>${basedir}/src/docbkx/resources/xsl/html.xsl</htmlCustomization>
<foCustomization>${basedir}/src/docbkx/resources/xsl/fopdf.xsl</foCustomization>
<postProcess>
<copy todir="${basedir}/target/site/reference">
<fileset dir="${basedir}/target/docbkx">
<include name="**/*.pdf" />
</fileset>
</copy>
<copy todir="${basedir}/target/site/reference/html-single">
<fileset dir="${basedir}/target/docbkx/html">
<include name="**/*.html" />
</fileset>
</copy>
<copy todir="${basedir}/target/site/reference/html-single">
<fileset dir="${basedir}/src/docbkx/resources">
<include name="**/*.css" />
</fileset>
</copy>
<copy todir="${basedir}/target/site/reference/html-single">
<fileset dir="${basedir}/src/site/resources/reference">
<include name="**/*.png" />
<include name="**/*.gif" />
<include name="**/*.jpg" />
</fileset>
</copy>
<move file="${basedir}/target/site/reference/pdf/index.pdf"
tofile="${basedir}/target/site/reference/pdf/${artifactId}.pdf" failonerror="false" />
</postProcess>
</configuration>
<phase>pre-site</phase>
</execution>
<execution>
<id>multi-page</id>
<goals>
<goal>generate-html</goal>
</goals>
<configuration>
<chunkedOutput>true</chunkedOutput>
<htmlCustomization>${basedir}/src/docbkx/resources/xsl/html_chunk.xsl</htmlCustomization>
<postProcess>
<copy todir="${basedir}/target/site/reference">
<fileset dir="${basedir}/target/docbkx">
<include name="**/*.html" />
</fileset>
</copy>
<copy todir="${basedir}/target/site/reference/html">
<fileset dir="${basedir}/src/docbkx/resources">
<include name="**/*.css" />
<include name="**/*.png" />
<include name="**/*.gif" />
<include name="**/*.jpg" />
</fileset>
</copy>
<copy todir="${basedir}/target/site/reference/html">
<fileset dir="${basedir}/src/site/resources/reference">
<include name="**/*.png" />
<include name="**/*.gif" />
<include name="**/*.jpg" />
</fileset>
</copy>
</postProcess>
</configuration>
<phase>pre-site</phase>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.docbook</groupId>
<artifactId>docbook-xml</artifactId>
<version>4.4</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<configuration>
<includes>index.xml</includes>
<htmlStylesheet>css/html.css</htmlStylesheet>
<xincludeSupported>true</xincludeSupported>
<sourceDirectory>${basedir}/src/site/docbook/reference</sourceDirectory>
<entities>
<entity>
<name>version</name>
<value>${version}</value>
</entity>
</entities>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,15 @@
-----
Spring Batch Docsumentation
-----
Dave Syer
-----
Aug 2007
-----
Spring Batch Documentation
If youare seeing this page you probably built Spring Batch from the
SVN soure code. The real documentation is still work in progress
and will be released here shortly. Meanwhile you can get the latest
and greatest at the Spring Batch home page
http://static.springframework.org/spring-batch/docs.

28
docs/src/site/site.xml Normal file
View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Spring Batch: ${project.name}">
<bannerLeft>
<name>Spring Batch: ${project.name}</name>
</bannerLeft>
<bannerRight>
<src>images/shim.gif</src>
</bannerRight>
<poweredBy>
<logo name="" href="" img="images/shim.gif"/>
</poweredBy>
<skin>
<groupId>org.springframework.maven.skins</groupId>
<artifactId>maven-spring-skin</artifactId>
<version>1.0.3</version>
</skin>
<body>
<links>
<item name="Home" href="../index.html"/>
<item name="${project.name}" href="index.html"/>
</links>
<menu name="Project Documentation">
<item name="${project.name}" href="index.html"/>
</menu>
${reports}
</body>
</project>

11
execution/.classpath Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry exported="true" kind="var" path="CLOVER_RUNTIME"/>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" path="src/test/resources"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

29
execution/.project Normal file
View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>batch-execution</name>
<comment>Execution tools and implementations of Spring Batch Core interfaces</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.springframework.ide.eclipse.core.springnature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,5 @@
#Fri Aug 03 14:01:44 BST 2007
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.4
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.source=1.4
org.eclipse.jdt.core.compiler.compliance=1.4

44
execution/.springBeans Normal file
View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<configExtensions>
<configExtension>xml</configExtension>
</configExtensions>
<configs>
<config>src/test/resources/simple-container-definition.xml</config>
<config>src/test/resources/job-configuration.xml</config>
<config>src/test/resources/org/springframework/batch/execution/repository/dao/data-source-context.xml</config>
<config>src/test/resources/org/springframework/batch/execution/repository/dao/hibernate-context.xml</config>
<config>src/test/resources/org/springframework/batch/execution/repository/dao/hibernate-dao-test.xml</config>
<config>src/test/resources/org/springframework/batch/execution/repository/dao/sql-dao-test.xml</config>
</configs>
<configSets>
<configSet>
<name><![CDATA[bootstrap]]></name>
<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
<incomplete>false</incomplete>
<configs>
<config>src/test/resources/job-configuration.xml</config>
<config>src/test/resources/simple-container-definition.xml</config>
</configs>
</configSet>
<configSet>
<name><![CDATA[sqltest]]></name>
<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
<incomplete>false</incomplete>
<configs>
<config>src/test/resources/org/springframework/batch/execution/repository/dao/data-source-context.xml</config>
<config>src/test/resources/org/springframework/batch/execution/repository/dao/sql-dao-test.xml</config>
</configs>
</configSet>
<configSet>
<name><![CDATA[hibernatetest]]></name>
<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
<incomplete>false</incomplete>
<configs>
<config>src/test/resources/org/springframework/batch/execution/repository/dao/data-source-context.xml</config>
<config>src/test/resources/org/springframework/batch/execution/repository/dao/hibernate-context.xml</config>
<config>src/test/resources/org/springframework/batch/execution/repository/dao/hibernate-dao-test.xml</config>
</configs>
</configSet>
</configSets>
</beansProjectDescription>

231
execution/pom.xml Normal file
View File

@@ -0,0 +1,231 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-batch-execution</artifactId>
<packaging>jar</packaging>
<name>Execution</name>
<description>
<!-- Use CDATA to keep it on a single line in the manifest -->
<![CDATA[Execution tools and implementations of Spring Batch Core interfaces]]>
</description>
<parent>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch</artifactId>
<version>1.0-m2-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>easymock</groupId>
<artifactId>easymock</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<!-- Needed by Hibernate if JTA is excluded -->
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jta_1.1_spec</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<!-- Force Hibernate to use a particular nodep version of cglib in case of clash with Spring AOP -->
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.1_3</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.3.ga</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</exclusion>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm-attrs</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>generate-sql</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<typedef resource="foundrylogic/vpp/typedef.properties" />
<taskdef resource="foundrylogic/vpp/taskdef.properties" />
<!-- Scripts for DAO tests - N.B. under source control. -->
<vppcopy
todir="${basedir}/src/test/resources/org/springframework/batch/execution/repository/dao" overwrite="true">
<config>
<context>
<property key="includes" value="src/main/sql" />
<property file="${basedir}/src/main/sql/hsqldb.properties" />
</context>
<engine>
<property key="velocimacro.library" value="src/main/sql/hsqldb.vpp" />
</engine>
</config>
<fileset dir="${basedir}/src/main/sql" includes="*.sql.vpp" excludes="schema*" />
<mapper type="glob" from="*.sql.vpp" to="*.sql" />
</vppcopy>
<!-- Reference script for HSQLDB - N.B. not under source control, but packagaed in jar. -->
<vppcopy todir="${basedir}/target/generated-resources" overwrite="true">
<config>
<context>
<property key="includes" value="src/main/sql" />
<property file="${basedir}/src/main/sql/hsqldb.properties" />
</context>
<engine>
<property key="velocimacro.library" value="src/main/sql/hsqldb.vpp" />
</engine>
</config>
<fileset dir="${basedir}/src/main/sql" includes="schema.sql.vpp" />
<mapper type="glob" from="*.sql.vpp" to="*-hsqldb.sql" />
</vppcopy>
<!-- Reference script for DB2 - N.B. not under source control, but packagaed in jar. -->
<vppcopy todir="${basedir}/target/generated-resources" overwrite="true">
<config>
<context>
<property key="includes" value="src/main/sql" />
<property file="${basedir}/src/main/sql/db2.properties" />
</context>
<engine>
<property key="velocimacro.library" value="src/main/sql/db2.vpp" />
</engine>
</config>
<fileset dir="${basedir}/src/main/sql" includes="schema.sql.vpp" />
<mapper type="glob" from="*.sql.vpp" to="*-db2.sql" />
</vppcopy>
<!-- Reference script for Derby - N.B. not under source control, but packagaed in jar. -->
<vppcopy todir="${basedir}/target/generated-resources" overwrite="true">
<config>
<context>
<property key="includes" value="src/main/sql" />
<property file="${basedir}/src/main/sql/derby.properties" />
</context>
<engine>
<property key="velocimacro.library" value="src/main/sql/derby.vpp" />
</engine>
</config>
<fileset dir="${basedir}/src/main/sql" includes="schema.sql.vpp" />
<mapper type="glob" from="*.sql.vpp" to="*-derby.sql" />
</vppcopy>
<!-- Reference script for Oracle - N.B. not under source control, but packagaed in jar. -->
<vppcopy todir="${basedir}/target/generated-resources" overwrite="true">
<config>
<context>
<property key="includes" value="src/main/sql" />
<property file="${basedir}/src/main/sql/oracle10g.properties" />
</context>
<engine>
<property key="velocimacro.library" value="src/main/sql/oracle10g.vpp" />
</engine>
</config>
<fileset dir="${basedir}/src/main/sql" includes="schema.sql.vpp" />
<mapper type="glob" from="*.sql.vpp" to="*-oracle10g.sql" />
</vppcopy>
<!-- Reference script for PostgreSQL - N.B. not under source control, but packagaed in jar. -->
<vppcopy todir="${basedir}/target/generated-resources" overwrite="true">
<config>
<context>
<property key="includes" value="src/main/sql" />
<property file="${basedir}/src/main/sql/postgresql.properties" />
</context>
<engine>
<property key="velocimacro.library" value="src/main/sql/postgresql.vpp" />
</engine>
</config>
<fileset dir="${basedir}/src/main/sql" includes="schema.sql.vpp" />
<mapper type="glob" from="*.sql.vpp" to="*-postgresql.sql" />
</vppcopy>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clover-plugin</artifactId>
<configuration>
<licenseLocation>${basedir}/src/test/resources/clover.license</licenseLocation>
</configuration>
<executions>
<execution>
<phase>pre-site</phase>
<goals>
<goal>instrument</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clover-plugin</artifactId>
</plugin>
</plugins>
</reporting>
</project>

View File

@@ -0,0 +1,64 @@
/*
* 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;
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
import org.springframework.batch.core.runtime.JobIdentifier;
/**
* Interface which defines a facade for running jobs. The interface is
* intentionally minimal, and depends only on simple java types, so that the
* facade can be used to launch a job from basic environments like a command
* line or a JMX console. TODO: remove dependency on
* {@link JobIdentifier}?
*
* @author Lucas Ward
* @author Dave Syer
*/
public interface JobExecutorFacade {
/**
* Start a job execution identifiable by the {@link JobIdentifier}.
* Implementations normally require a job configuration to be locatable
* corresponding to the {@link JobIdentifier}, preferably matching
* them at least by name.
* @param runtimeInformation
*
* @throws NoSuchJobConfigurationException
*/
void start(JobIdentifier runtimeInformation) throws NoSuchJobConfigurationException;
/**
* Stop the job execution that was started with this runtime information.
* @param runtimeInformation the {@link JobIdentifier}.
* @throws NoSuchJobExecutionException if a job with this runtime
* information is not running
*/
void stop(JobIdentifier runtimeInformation) throws NoSuchJobExecutionException;
/**
* Simple check for whether or not there are jobs in progress. Can be used
* by clients to wait for all jobs to finish. Finer grained monitoring and
* reporting can be implemented using the persistent execution details
* (normally in a database), provided they are maintained by the
* implementation.
*
* @return true if any jobs are active.
*/
boolean isRunning();
}

View File

@@ -0,0 +1,32 @@
/*
* 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;
/**
* @author Dave Syer
*
*/
public class NoSuchJobExecutionException extends Exception {
/**
* @param message
*/
public NoSuchJobExecutionException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,294 @@
/*
* 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;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.configuration.JobConfiguration;
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
import org.springframework.batch.core.runtime.JobIdentifier;
import org.springframework.batch.core.runtime.JobIdentifierFactory;
import org.springframework.batch.execution.JobExecutorFacade;
import org.springframework.batch.execution.NoSuchJobExecutionException;
import org.springframework.batch.execution.runtime.ScheduledJobIdentifierFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.util.Assert;
/**
* Base class for {@link JobLauncher} implementations making no
* choices about concurrent processing of jobs.
*
* @see JobLauncher
* @author Lucas Ward
*/
public abstract class AbstractJobLauncher implements JobLauncher,
InitializingBean, ApplicationListener {
private static final Log logger = LogFactory.getLog(AbstractJobLauncher.class);
protected JobExecutorFacade batchContainer;
private String jobConfigurationName;
private final Object monitor = new Object();
// Do not autostart by default - allow user to set job configuration
// later and then manually start:
private volatile boolean autoStart = false;
private JobIdentifierFactory jobRuntimeInformationFactory = new ScheduledJobIdentifierFactory();
// A private registry for keeping track of running jobs.
private volatile Map registry = new HashMap();
/**
* Setter for {@link JobIdentifier}.
*
* @param jobRuntimeInformationFactory the jobRuntimeInformationFactory to
* set
*/
public void setJobRuntimeInformationFactory(JobIdentifierFactory jobRuntimeInformationFactory) {
this.jobRuntimeInformationFactory = jobRuntimeInformationFactory;
}
/**
* Setter for the {@link JobConfiguration} that this launcher will run.
*
* @param jobConfiguration the jobConfiguration to set
*/
public void setJobConfigurationName(String jobConfiguration) {
this.jobConfigurationName = jobConfiguration;
}
/**
* Setter for autostart flag. If this is true then the container will be
* started when the Spring context is refreshed. Defaults to false.
*
* @param autoStart
*/
public void setAutoStart(boolean autoStart) {
this.autoStart = autoStart;
}
/**
* Setter for {@link JobExecutorFacade}. Mandatory property.
*
* @param batchContainer
*/
public void setBatchContainer(JobExecutorFacade batchContainer) {
this.batchContainer = batchContainer;
}
/**
* Check that mandatory properties are set.
*
* @see #setBatchContainer(JobExecutorFacade)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
Assert.notNull(batchContainer);
}
/**
* If autostart flag is on, initialise on context start-up.
*
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(ApplicationEvent event) {
if ((event instanceof ContextRefreshedEvent) && this.autoStart && !isRunning()) {
start();
}
}
/**
* Extension point for subclasses. Implementations might choose to start the
* job in a new thread or in the current thread.<br/>
* @param runtimeInformation the {@link JobIdentifier} to start the
* launcher with.
* @throws NoSuchJobConfigurationException
*/
protected abstract void doStart(JobIdentifier jobIdentifier) throws NoSuchJobConfigurationException;
/**
* Start the provided container. The current thread will first be saved.
* This may seem odd at first, however, this simple bootstrap requires that
* only one thread can kick off a container, and that the first thread that
* calls start is the 'processing thread'. If the container has already been
* started, no exception will be thrown.
* @throws NoSuchJobConfigurationException if the container cannot locate a job configuration
* @throws IllegalStateException if JobConfiguration is null.
* @see Lifecycle#start().
*/
public void start(JobIdentifier jobIdentifier) throws NoSuchJobConfigurationException {
synchronized (monitor) {
if (isRunning(jobIdentifier)) {
return;
}
}
register(jobIdentifier);
doStart(jobIdentifier);
/*
* Subclasses have to take care of unregistering the runtimeInformation -
* if we do it here and doStart() is implemented to return immediately
* without waiting for the job to finish, then we will have a job
* running that is not in the registry.
*/
}
/**
* Start a job execution with the given name. If a job is already running
* has no effect.
*
* @param name the name to assign to the job
* @throws NoSuchJobConfigurationException
*/
public void start(String name) throws NoSuchJobConfigurationException {
JobIdentifier runtimeInformation = jobRuntimeInformationFactory.getJobIdentifier(name);
this.start(runtimeInformation);
}
/**
* Start a job execution with default name and other runtime information
* provided by the factory. If a job is already running has no effect. The
* default name is taken from the enclosed {@link JobConfiguration}.
* @throws NoSuchJobConfigurationException if the job configuration cannot be located
*
* @see #setJobRuntimeInformationFactory(JobIdentifierFactory)
* @see org.springframework.context.Lifecycle#start()
*/
public void start() {
if (jobConfigurationName==null) {
return;
}
try {
this.start(jobConfigurationName);
}
catch (NoSuchJobConfigurationException e) {
logger.error("Could not start", e);
}
}
/**
* Extension point for subclasses to stop a specific job.
* @throws NoSuchJobExecutionException
*
* @see org.springframework.batch.container.bootstrap.BatchContainerLauncher#stop(JobRuntimeInformation))
*/
protected abstract void doStop(JobIdentifier runtimeInformation) throws NoSuchJobExecutionException;
/**
* Stop all jobs if any are running. If not, no action will be taken.
* Delegates to the {@link #doStop()} method.
* @throws NoSuchJobExecutionException
* @see org.springframework.context.Lifecycle#stop()
* @see org.springframework.batch.execution.bootstrap.JobLauncher#stop()
*/
final public void stop() {
for (Iterator iter = new HashSet(registry.keySet()).iterator(); iter.hasNext();) {
JobIdentifier context = (JobIdentifier) iter.next();
try {
stop(context);
}
catch (NoSuchJobExecutionException e) {
logger.error(e);
}
}
}
/**
* Stop a job with this {@link JobIdentifier}. Delegates to the
* {@link #doStop(JobIdentifier)} method.
* @throws NoSuchJobExecutionException
*
* @see org.springframework.batch.execution.bootstrap.JobLauncher#stop(org.springframework.batch.core.runtime.JobIdentifier)
* @see BatchContainer#stop(JobRuntimeInformation))
*/
final public void stop(JobIdentifier runtimeInformation) throws NoSuchJobExecutionException {
synchronized (monitor) {
doStop(runtimeInformation);
}
}
/**
* Stop all jobs with {@link JobIdentifier} having this name.
* Delegates to the {@link #stop(JobIdentifier)}.
* @throws NoSuchJobExecutionException
*
* @see org.springframework.batch.execution.bootstrap.JobLauncher#stop(java.lang.String)
*/
final public void stop(String name) throws NoSuchJobExecutionException {
this.stop(jobRuntimeInformationFactory.getJobIdentifier(name));
}
/*
* (non-Javadoc)
* @see org.springframework.batch.container.bootstrap.BatchContainerLauncher#isRunning()
*/
public boolean isRunning() {
Collection jobs = new HashSet(registry.keySet());
for (Iterator iter = jobs.iterator(); iter.hasNext();) {
JobIdentifier context = (JobIdentifier) iter.next();
if (!isRunning(context)) {
return false;
}
}
return !jobs.isEmpty();
}
protected boolean isRunning(JobIdentifier runtimeInformation) {
synchronized (registry) {
return registry.get(runtimeInformation) != null;
}
}
/**
* Convenient synchronized accessor for the registry. Can be used by
* subclasses if necessary (but it isn't likely).
* @param runtimeInformation
*/
protected void register(JobIdentifier runtimeInformation) {
synchronized (registry) {
registry.put(runtimeInformation, runtimeInformation);
}
}
/**
* Convenient synchronized accessor for the registry. Must be used by
* subclasses to release the {@link JobIdentifier} when a job is
* finished (or stopped).
*
* @param runtimeInformation
*/
protected void unregister(JobIdentifier runtimeInformation) {
synchronized (registry) {
registry.remove(runtimeInformation);
}
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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;
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Dave Syer
* @since 2.1
*/
public class BatchCommandLineLauncher {
/**
* The key for the parent context.
*/
public static final String PARENT_KEY = "simple-container";
private ConfigurableApplicationContext parent;
private JobLauncher launcher;
/**
* Default constructor for the launcher. Sets up the parent context to use
* for all job executions using a context key {@link #PARENT_KEY}.
*/
public BatchCommandLineLauncher() {
parent = (ConfigurableApplicationContext) ContextSingletonBeanFactoryLocator.getInstance().useBeanFactory(
PARENT_KEY).getFactory();
}
/**
* Injection setter for the {@link JobLauncher}.
*
* @param launcher the launcher to set
*/
public void setLauncher(JobLauncher launcher) {
this.launcher = launcher;
}
/**
* @param path the path to a Spring context configuration for this job
* @param jobName the name of the job execution to use
* @throws NoSuchJobConfigurationException
*/
private void start(String path, String jobName) throws NoSuchJobConfigurationException {
if (!path.endsWith(".xml")) {
path = path + ".xml";
}
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { path }, parent);
context.getAutowireCapableBeanFactory().autowireBeanProperties(this,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
try {
if (!launcher.isRunning()) {
if (jobName == null) {
launcher.start();
}
else {
launcher.start(jobName);
}
}
}
finally {
try {
context.stop();
}
finally {
context.close();
}
}
}
/**
* Launch a batch job using a {@link BatchCommandLineLauncher}. Creates a
* new Spring context for the job execution, and uses a common parent for
* all such contexts.
*
* @param args 0 - path to resource to load job configuration context
* (default "job-configuration.xml"); 1 - runtime name for job execution
* (default "job-execution-id").
* @throws NoSuchJobConfigurationException
*/
public static void main(String[] args) throws NoSuchJobConfigurationException {
String path = "job-configuration.xml";
String name = null;
if (args.length > 0) {
path = args[0];
}
if (args.length > 1) {
name = args[1];
}
BatchCommandLineLauncher command = new BatchCommandLineLauncher();
command.start(path, name);
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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;
import org.springframework.batch.execution.JobExecutorFacade;
import org.springframework.batch.repeat.interceptor.RepeatOperationsApplicationEvent;
import org.springframework.context.ApplicationEvent;
/**
* {@link ApplicationEvent} that encodes a request from the execution layer to a
* running {@link JobExecutorFacade}.
*
* @author Dave Syer
*
*/
public class BatchExecutionRequestEvent extends ApplicationEvent {
/**
* Constructor for {@link BatchExecutionRequestEvent}. The source is the
* execution layer service implementation that is sending the signal.<br/>
*
* TODO: the source sould be Serializable so really it should be just a
* message about the request?
*
* Currently encodes a request to publish back a
* {@link RepeatOperationsApplicationEvent}. Could be extended in the
* future to narrow the request to ask for specific information to be
* published back.
*/
public BatchExecutionRequestEvent(Object source) {
super(source);
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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;
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
import org.springframework.batch.core.runtime.JobIdentifier;
import org.springframework.batch.execution.JobExecutorFacade;
import org.springframework.batch.execution.NoSuchJobExecutionException;
import org.springframework.context.Lifecycle;
/**
* Simple interface for controlling a {@link JobExecutorFacade} for a single job
* configuration, and also possibly ad-hoc executions, based on different
* runtime information. Implementations should concentrate on launching and
* controlling a single job, as configured in a {@link JobExecutorFacade} instance.
*
* @author Dave Syer
* @since 2.1
*/
public interface JobLauncher extends Lifecycle {
/**
* Return whether or not a job execution is currently running.
*/
boolean isRunning();
/**
* Start a job execution with the given runtime information.
* @throws NoSuchJobConfigurationException
*/
void start(JobIdentifier runtimeInformation) throws NoSuchJobConfigurationException;
/**
* Start a job execution with the given name and other runtime information
* generated on the fly.
*
* @param name the name to assign to the job
* @throws NoSuchJobConfigurationException
*/
void start(String name) throws NoSuchJobConfigurationException;
/**
* Start a job execution with default name and other runtime information
* generated on the fly.<br/>
*
* Because {@link Lifecycle#start()} does not throw checked exceptions this
* also does not, so an error message and stack trace will be logged if the
* required job(s) cannot be started.
*
* @see org.springframework.context.Lifecycle#start()
*/
public void start();
/**
* Stop the job execution that was started with this runtime information.
* @param runtimeInformation the {@link JobIdentifier}.
* @throws NoSuchJobExecutionException
*/
void stop(JobIdentifier runtimeInformation) throws NoSuchJobExecutionException;
/**
* Stop all currently executing jobs matching the given name. All jobs
* started with {@link JobIdentifier} having this name will be
* stopped.
* @throws NoSuchJobExecutionException
*/
void stop(String name) throws NoSuchJobExecutionException;
/**
* Stop the current job executions if there are any. If not, no action will
* be taken.
* @throws NoSuchJobExecutionException
*
* @see org.springframework.context.Lifecycle#stop()
*/
public void stop();
}

View File

@@ -0,0 +1,110 @@
/*
* 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;
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
import org.springframework.batch.core.runtime.JobIdentifier;
import org.springframework.batch.execution.JobExecutorFacade;
import org.springframework.context.Lifecycle;
/**
* Simple bootstrapping mechanism for running a single job execution in a
* {@link JobExecutorFacade}.
*
* <p>
* This simple implementation does not run the job asynchronously, so the start
* method will not return before the job ends. However, the job execution to be
* interrupted via the stop method in another thread.
* </p>
*
* @see Lifecycle
* @author Lucas Ward
* @author Dave Syer
* @since 2.1
*/
public class SimpleJobLauncher extends AbstractJobLauncher {
private volatile Thread processingThread;
private volatile boolean running = false;
/**
* Return whether or not the container is currently running. This is done by
* checking the thread to see if it is still alive.
*/
public boolean isRunning() {
return running && processingThread != null && processingThread.isAlive();
}
/**
* Start the provided container. The current thread will first be saved.
* This may seem odd at first, however, this simple bootstrap requires that
* only one thread can kick off a container, and that the first thread that
* calls start is the 'processing thread'. If the container has already been
* started, no exception will be thrown.
* @throws NoSuchJobConfigurationException
* @see Lifecycle#start().
*
* @throws IllegalStateException if JobConfiguration is null.
*/
protected void doStart(JobIdentifier jobIdentifier) throws NoSuchJobConfigurationException {
/*
* There is no reason to kick off a new thread, since only one thread
* should be processing at once. However, a handle to the thread should
* be maintained to allow for interrupt
*/
processingThread = Thread.currentThread();
// TODO: push this out to a method call in parent inside synchronized
// block?
running = true;
try {
batchContainer.start(jobIdentifier);
}
finally {
running = false;
unregister(jobIdentifier);
}
}
/**
* Stop the job if it is running by interrupting its thread. If no job is
* running, no action will be taken.
*
* (non-Javadoc)
* @see org.springframework.context.Lifecycle#stop()
*/
protected void doStop() {
if (isRunning()) {
processingThread.interrupt();
running = false;
}
}
/**
* Delegates to {@link #doStop()}. Since there is only one job running in
* this launcher this is OK.
*
* (non-Javadoc)
* @see org.springframework.context.Lifecycle#stop()
*/
protected void doStop(JobIdentifier runtimeInformation) {
doStop();
}
}

View File

@@ -0,0 +1,184 @@
/*
* 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;
import java.util.Properties;
import javax.management.Notification;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
import org.springframework.batch.core.runtime.JobExecutionContext;
import org.springframework.batch.core.runtime.JobIdentifier;
import org.springframework.batch.execution.JobExecutorFacade;
import org.springframework.batch.execution.NoSuchJobExecutionException;
import org.springframework.batch.repeat.interceptor.RepeatOperationsApplicationEvent;
import org.springframework.batch.statistics.StatisticsProvider;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.jmx.export.notification.NotificationPublisher;
import org.springframework.jmx.export.notification.NotificationPublisherAware;
import org.springframework.util.Assert;
/**
* Bootstrapping mechanism for running job executions concurrently with a
* {@link JobExecutorFacade}.
*
* <p>
* This implementation can run jobs asynchronously. Jobs are stopped by calling
* the container stop methods, which is a graceful shutdown.
* </p>
*
* @see JobExecutorFacade
* @author Dave Syer
* @since 2.1
*/
public class TaskExecutorJobLauncher extends AbstractJobLauncher implements ApplicationListener,
NotificationPublisherAware, ApplicationEventPublisherAware {
private static final Log logger = LogFactory.getLog(TaskExecutorJobLauncher.class);
private TaskExecutor taskExecutor = new SyncTaskExecutor();
private NotificationPublisher notificationPublisher;
private int notificationCount = 0;
private ApplicationEventPublisher applicationEventPublisher;
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)
*/
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
/**
* Setter for the {@link TaskExecutor}. Defaults to a
* {@link SyncTaskExecutor}.
*
* @param taskExecutor the taskExecutor to set
*/
public void setTaskExecutor(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
/*
* (non-Javadoc)
* @see org.springframework.jmx.export.notification.NotificationPublisherAware#setNotificationPublisher(org.springframework.jmx.export.notification.NotificationPublisher)
*/
public void setNotificationPublisher(NotificationPublisher notificationPublisher) {
this.notificationPublisher = notificationPublisher;
}
/**
* Start the provided container using the task executor provided.
*
* @throws IllegalStateException if JobConfiguration is null.
*/
protected void doStart(final JobIdentifier runtimeInformation) {
Assert.state(taskExecutor != null, "TaskExecutor must be provided");
taskExecutor.execute(new Runnable() {
public void run() {
try {
batchContainer.start(runtimeInformation);
}
catch (NoSuchJobConfigurationException e) {
applicationEventPublisher.publishEvent(new RepeatOperationsApplicationEvent(runtimeInformation,
"No such job", RepeatOperationsApplicationEvent.ERROR));
logger.error("JobConfiguration could not be located inside Runnable for runtime information: ["
+ runtimeInformation + "]", e);
}
finally {
unregister(runtimeInformation);
}
}
});
}
/**
* Delegates to the underlying {@link JobExecutorFacade}. Does not wait for
* the jobs to stop (probably therefore returns immediately).
* @throws NoSuchJobExecutionException
*
* @see org.springframework.context.Lifecycle#stop()
*/
protected void doStop(JobIdentifier runtimeInformation) throws NoSuchJobExecutionException {
batchContainer.stop(runtimeInformation);
// TODO: wait for the jobs to stop?
}
/**
* If the event is a {@link RepeatOperationsApplicationEvent} for open and
* close we log the event at INFO level and send a JMX notification if we
* are also an MBean.
*
* @see org.springframework.batch.execution.bootstrap.AbstractJobLauncher#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(ApplicationEvent applicationEvent) {
super.onApplicationEvent(applicationEvent);
if (applicationEvent instanceof RepeatOperationsApplicationEvent) {
RepeatOperationsApplicationEvent event = (RepeatOperationsApplicationEvent) applicationEvent;
int type = event.getType();
if (type == RepeatOperationsApplicationEvent.OPEN || type == RepeatOperationsApplicationEvent.CLOSE
|| type == RepeatOperationsApplicationEvent.ERROR) {
String message = event.getMessage() + "; source=" + event.getSource();
logger.info(message);
publish(message);
}
return;
}
}
/**
* Accessor for the job executions passed back in response to a call to
* {@link #requestContextNotification()}. Because the request is
* potentially fulfilled asynchronously, and only on demand, the data might
* be out of date by the time this method is called, so it should be used
* for information purposes only.
*
* @return Properties representing the last {@link JobExecutionContext}
* objects passed up from the underlying execution. If there are no jobs
* running it will be empty.
*/
public Properties getStatistics() {
if (batchContainer instanceof StatisticsProvider) {
return ((StatisticsProvider) batchContainer).getStatistics();
} else {
return new Properties();
}
}
/**
* @param event
*/
private void publish(String message) {
if (notificationPublisher != null) {
notificationPublisher.sendNotification(new Notification("RepeatOperationsApplicationEvent", this,
notificationCount++, message));
}
}
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Specific implementations of bootstrap concerns.
</p>
</body>
</html>

View File

@@ -0,0 +1,113 @@
/*
* 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.configuration;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import org.springframework.batch.core.configuration.DuplicateJobConfigurationException;
import org.springframework.batch.core.configuration.JobConfiguration;
import org.springframework.batch.core.configuration.JobConfigurationLocator;
import org.springframework.batch.core.configuration.JobConfigurationRegistry;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.Assert;
/**
* A {@link BeanPostProcessor} that registers {@link JobConfiguration} beans
* with a {@link JobConfigurationRegistry}. Include a bean of this type along
* with your job configuration, and use the same
* {@link JobConfigurationRegistry} as a {@link JobConfigurationLocator} when
* you need to locate a {@link JobConfigurationLocator} to launch.
*
* @author Dave Syer
*
*/
public class JobConfigurationRegistryBeanPostProcessor implements BeanPostProcessor, InitializingBean, DisposableBean {
// It doesn't make sense for this to have a default value...
private JobConfigurationRegistry jobConfigurationRegistry = null;
private Collection jobConfigurations = new HashSet();
/**
* Injection setter for {@link JobConfigurationRegistry}.
*
* @param jobConfigurationRegistry the jobConfigurationRegistry to set
*/
public void setJobConfigurationRegistry(JobConfigurationRegistry jobConfigurationRegistry) {
this.jobConfigurationRegistry = jobConfigurationRegistry;
}
/**
* Make sure the registry is set before use.
*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
Assert.notNull(jobConfigurationRegistry, "JobConfigurationRegistry must not be null");
}
/**
* De-register all the {@link JobConfiguration} instances that were
* regsistered by this post processor.
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
for (Iterator iter = jobConfigurations.iterator(); iter.hasNext();) {
JobConfiguration jobConfiguration = (JobConfiguration) iter.next();
jobConfigurationRegistry.unregister(jobConfiguration);
}
jobConfigurations.clear();
}
/**
* If the bean is an instance of {@link JobConfiguration} then register it.
* @throws FatalBeanException if there is a
* {@link DuplicateJobConfigurationException}.
*
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object,
* java.lang.String)
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof JobConfiguration) {
JobConfiguration jobConfiguration = (JobConfiguration) bean;
try {
jobConfigurationRegistry.register(jobConfiguration);
jobConfigurations.add(jobConfiguration);
}
catch (DuplicateJobConfigurationException e) {
throw new FatalBeanException("Cannot register job configuration", e);
}
}
return bean;
}
/**
* Do nothing.
*
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object,
* java.lang.String)
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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.configuration;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.springframework.batch.core.configuration.DuplicateJobConfigurationException;
import org.springframework.batch.core.configuration.JobConfiguration;
import org.springframework.batch.core.configuration.JobConfigurationRegistry;
import org.springframework.batch.core.configuration.ListableJobConfigurationRegistry;
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
import org.springframework.util.Assert;
/**
* Simple map-based implementation of {@link JobConfigurationRegistry}. Access
* to the map is synchronized, guarded by an internal lock.
*
* @author Dave Syer
*
*/
public class MapJobConfigurationRegistry implements ListableJobConfigurationRegistry {
private Map map = new HashMap();
/*
* (non-Javadoc)
* @see org.springframework.batch.container.common.configuration.JobConfigurationRegistry#registerJobConfiguration(org.springframework.batch.container.common.configuration.JobConfiguration)
*/
public void register(JobConfiguration jobConfiguration) throws DuplicateJobConfigurationException {
Assert.notNull(jobConfiguration);
String name = jobConfiguration.getName();
Assert.notNull(name, "Job configuration must have a name.");
synchronized (map) {
if (map.containsKey(name) && jobConfiguration.equals(map.get(name))) {
throw new DuplicateJobConfigurationException("A job configuration with this name [" + name
+ "] was already registered");
}
// allow replacing job configuration with new instance
map.put(name, jobConfiguration);
}
}
/*
* (non-Javadoc)
* @see org.springframework.batch.container.common.configuration.JobConfigurationRegistry#unregister(org.springframework.batch.container.common.configuration.JobConfiguration)
*/
public void unregister(JobConfiguration jobConfiguration) {
String name = jobConfiguration.getName();
Assert.notNull(name, "Job configuration must have a name.");
synchronized (map) {
map.remove(name);
}
}
/*
* (non-Javadoc)
* @see org.springframework.batch.container.common.configuration.JobConfigurationLocator#getJobConfiguration(java.lang.String)
*/
public JobConfiguration getJobConfiguration(String name) throws NoSuchJobConfigurationException {
synchronized (map) {
if (!map.containsKey(name)) {
throw new NoSuchJobConfigurationException("No job configuration with the name [" + name
+ "] was registered");
}
return (JobConfiguration) map.get(name);
}
}
/* (non-Javadoc)
* @see org.springframework.batch.container.common.configuration.ListableJobConfigurationRegistry#getJobConfigurations()
*/
public Collection getJobConfigurations() {
synchronized (map) {
return Collections.unmodifiableCollection(new HashSet(map.keySet()));
}
}
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Specific implementations of configuration concerns.
</p>
</body>
</html>

View File

@@ -0,0 +1,176 @@
/*
* 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.facade;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* *******This class is currently undergoing heavy refactoring*****************
*
* Strategy for locating different resources on the file system. For each unique
* step, the same file handle will be returned. A unique step is defined as
* having the same job name, job run, schedule date, stream name, and step name.
* An external file mover (such as an EAI solution) should rename and move any
* input files to conform to the patter defined by the file pattern.<br/>
*
* If no pattern is passed in, then following default is used:
*
* <pre>
* %BATCH_ROOT%/job_data/%JOB_NAME%/%SCHEDULE_DATE%-%STREAM_NAME%-%STEP_NAME%.txt
* </pre>
*
* The %% variables are replaced with the corresponding bean property at run
* time, when the factory method is executed.
*
* @author Tomas Slanina
* @author Lucas Ward
* @author Dave Syer
*
* @see FactoryBean
*/
public class BatchResourceFactoryBean extends AbstractFactoryBean implements ResourceLoaderAware {
private static final String BATCH_ROOT_PATTERN = "%BATCH_ROOT%";
private static final String JOB_NAME_PATTERN = "%JOB_NAME%";
private static final String JOB_RUN_PATTERN = "%JOB_RUN%";
private static final String STEP_NAME_PATTERN = "%STEP_NAME%";
private static final String STREAM_PATTERN = "%STREAM_NAME%";
private static final String SCHEDULE_DATE_PATTERN = "%SCHEDULE_DATE%";
private static final String DEFAULT_PATTERN = "%BATCH_ROOT%/job_data/%JOB_NAME%/"
+ "%SCHEDULE_DATE%-%STREAM_NAME%-%STEP_NAME%.txt";
private String filePattern = DEFAULT_PATTERN;
private String jobName = "";
private String jobStream = "";
private int jobRun = 0;
private String scheduleDate = "";
private String rootDirectory = "";
private String stepName = "";
private ResourceLoader resourceLoader;
/*
* (non-Javadoc)
* @see org.springframework.context.ResourceLoaderAware#setResourceLoader(org.springframework.core.io.ResourceLoader)
*/
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
/**
* Returns the Resource representing the file defined by the file pattern.
*
* @see FactoryBean#getObject()
* @return a resource representing the file on the file system.
*/
protected Object createInstance() {
if (resourceLoader == null) {
resourceLoader = new FileSystemResourceLoader();
}
return resourceLoader.getResource(createFileName());
}
public Class getObjectType() {
return Resource.class;
}
/**
* helper method for <code>createFileName()</code>
*/
private String replacePattern(String string, String pattern, String replacement) {
// check to ensure pattern exists in string.
if (string.indexOf(pattern) != -1) {
return StringUtils.replace(string, pattern, replacement);
}
return string;
}
/**
* Creates a filename given a pattern and step context information.
*
* Deliberate package access, so that the method can be accessed by unit
* tests
*/
private String createFileName() {
Assert.notNull(filePattern, "filename pattern is null");
String fileName = filePattern;
// TODO consider refactoring to void replacePattern() method and
// collecting variable fileName
fileName = replacePattern(fileName, BATCH_ROOT_PATTERN, rootDirectory);
fileName = replacePattern(fileName, JOB_NAME_PATTERN, jobName);
fileName = replacePattern(fileName, STEP_NAME_PATTERN, stepName);
fileName = replacePattern(fileName, STREAM_PATTERN, jobStream);
fileName = replacePattern(fileName, JOB_RUN_PATTERN, String.valueOf(jobRun));
fileName = replacePattern(fileName, SCHEDULE_DATE_PATTERN, scheduleDate);
return fileName;
}
public void setFilePattern(String filePattern) {
this.filePattern = filePattern;
}
public void setRootDirectory(String rootDirectory) {
this.rootDirectory = rootDirectory;
}
public void setStepName(String stepName) {
this.stepName = stepName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public void setJobRun(int jobRun) {
this.jobRun = jobRun;
}
public void setJobStream(String jobStream) {
this.jobStream = jobStream;
}
public void setScheduleDate(String scheduleDate) {
this.scheduleDate = scheduleDate;
}
}

View File

@@ -0,0 +1,215 @@
/*
* 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.facade;
import java.util.Iterator;
import java.util.Properties;
import org.springframework.batch.core.configuration.JobConfiguration;
import org.springframework.batch.core.configuration.JobConfigurationLocator;
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.executor.JobExecutor;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.runtime.JobExecutionContext;
import org.springframework.batch.core.runtime.JobExecutionRegistry;
import org.springframework.batch.core.runtime.JobIdentifier;
import org.springframework.batch.execution.JobExecutorFacade;
import org.springframework.batch.execution.NoSuchJobExecutionException;
import org.springframework.batch.execution.job.DefaultJobExecutor;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.statistics.StatisticsProvider;
import org.springframework.util.Assert;
/**
* <p>
* Simple implementation of (@link {@link JobExecutorFacade}).
*
* <p>
* A {@link JobIdentifier} will be used to uniquely identify the job by the
* repository. Once the job is obtained, the {@link JobExecutor} will be used to
* run the job.
* </p>
*
* @author Lucas Ward
* @author Dave Syer
*
*/
public class SimpleJobExecutorFacade implements JobExecutorFacade, StatisticsProvider {
private JobExecutor jobExecutor;
private JobRepository jobRepository;
private JobExecutionRegistry jobExecutionRegistry = new VolatileJobExecutionRegistry();
// there is no sensible default for this
private JobConfigurationLocator jobConfigurationLocator;
private int running = 0;
private Object mutex = new Object();
/**
* Public accessor for the running property.
*
* @return the running
*/
public boolean isRunning() {
synchronized (mutex) {
return running > 0;
}
}
public SimpleJobExecutorFacade() {
jobExecutor = new DefaultJobExecutor();
}
/**
* Setter for the job execution registry. The default should be adequate so
* this setter method is mainly used for testing.
* @param jobExecutionRegistry the jobExecutionRegistry to set
*/
public void setJobExecutionRegistry(JobExecutionRegistry jobExecutionRegistry) {
this.jobExecutionRegistry = jobExecutionRegistry;
}
/**
* Setter for injection of {@link JobConfigurationLocator}.
*
* @param jobConfigurationLocator the jobConfigurationLocator to set
*/
public void setJobConfigurationLocator(JobConfigurationLocator jobConfigurationLocator) {
this.jobConfigurationLocator = jobConfigurationLocator;
}
/**
* Locates a {@link JobConfiguration} by using the name of the provided
* {@link JobIdentifier} and the {@link JobConfigurationLocator}.
*
* @see org.springframework.batch.execution.JobExecutorFacade#start(org.springframework.batch.execution.common.domain.JobConfiguration,
* org.springframework.batch.core.runtime.JobIdentifier)
*
* @throws IllegalArgumentException if the runtime information is null or
* its name is null
* @throws IllegalStateException if the {@link JobConfigurationLocator} does
* not contain a {@link JobConfiguration} with the name provided.
* @throws IllegalStateException if the {@link JobExecutor} is null
* @throws IllegalStateException if the {@link JobConfigurationLocator} is
* null
*
*/
public void start(JobIdentifier jobRuntimeInformation) throws NoSuchJobConfigurationException {
Assert.notNull(jobRuntimeInformation, "JobRuntimeInformation must not be null.");
Assert.notNull(jobRuntimeInformation.getName(), "JobRuntimeInformation name must not be null.");
Assert.state(!jobExecutionRegistry.isRegistered(jobRuntimeInformation),
"A job with this JobRuntimeInformation is already executing in this container");
Assert.state(jobExecutor != null, "JobExecutor must be provided.");
Assert.state(jobConfigurationLocator != null, "JobConfigurationLocator must be provided.");
JobConfiguration jobConfiguration = jobConfigurationLocator
.getJobConfiguration(jobRuntimeInformation.getName());
final JobInstance job = jobRepository.findOrCreateJob(jobConfiguration, jobRuntimeInformation);
JobExecutionContext jobExecutionContext = jobExecutionRegistry.register(jobRuntimeInformation, job);
try {
synchronized (mutex) {
running++;
}
jobExecutor.run(jobConfiguration, jobExecutionContext);
}
finally {
synchronized (mutex) {
// assume execution is synchronous so when we get to here we are
// not running any more
running--;
}
jobExecutionRegistry.unregister(jobRuntimeInformation);
}
}
/*
* (non-Javadoc)
* @see org.springframework.batch.container.BatchContainer#stop(org.springframework.batch.container.common.runtime.JobRuntimeInformation)
*/
public void stop(JobIdentifier runtimeInformation) throws NoSuchJobExecutionException {
JobExecutionContext jobExecutionContext = (JobExecutionContext) jobExecutionRegistry.get(runtimeInformation);
if (jobExecutionContext == null) {
throw new NoSuchJobExecutionException("No such Job is executing: [" + runtimeInformation + "]");
}
for (Iterator iter = jobExecutionContext.getStepContexts().iterator(); iter.hasNext();) {
RepeatContext context = (RepeatContext) iter.next();
context.setTerminateOnly();
}
;
for (Iterator iter = jobExecutionContext.getChunkContexts().iterator(); iter.hasNext();) {
RepeatContext context = (RepeatContext) iter.next();
context.setTerminateOnly();
}
}
/**
* Setter for {@link JobExecutor}.
*
* @param jobExecutor
*/
public void setJobExecutor(JobExecutor jobExecutor) {
this.jobExecutor = jobExecutor;
}
/**
* Setter for {@link JobRepository}.
*
* @param jobRepository
*/
public void setJobRepository(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
/**
* @return a read-only view of the state of the running jobs.
*/
public Properties getStatistics() {
int i = 0;
Properties props = new Properties();
for (Iterator iter = jobExecutionRegistry.findAll().iterator(); iter.hasNext();) {
JobExecutionContext element = (JobExecutionContext) iter.next();
i++;
String runtime = "job" + i;
props.setProperty(runtime, "" + element.getJobIdentifier());
int j = 0;
for (Iterator iterator = element.getStepContexts().iterator(); iterator.hasNext();) {
RepeatContext context = (RepeatContext) iterator.next();
j++;
props.setProperty(runtime + ".step" + j, "" + context);
}
j = 0;
for (Iterator iterator = element.getChunkContexts().iterator(); iterator.hasNext();) {
RepeatContext context = (RepeatContext) iterator.next();
j++;
props.setProperty(runtime + ".chunk" + j, "" + context);
}
}
return props;
}
}

View File

@@ -0,0 +1,126 @@
/*
* 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.facade;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.runtime.JobExecutionContext;
import org.springframework.batch.core.runtime.JobExecutionRegistry;
import org.springframework.batch.core.runtime.JobIdentifier;
/**
* Simple in-memory implementation of {@link JobExecutionRegistry}.
* Synchronizes all access to the underlying storage. Good for most purposes.
*
* @author Dave Syer
*
*/
public class VolatileJobExecutionRegistry implements JobExecutionRegistry {
private Map contexts = new HashMap();
/*
* (non-Javadoc)
* @see org.springframework.batch.container.common.executor.JobExecutionRegistry#findByName(java.lang.String)
*/
public Collection findByName(String name) {
Set values = new HashSet();
HashMap contexts;
synchronized (this.contexts) {
contexts = new HashMap(this.contexts);
}
for (Iterator iter = contexts.entrySet().iterator(); iter.hasNext();) {
Map.Entry entry = (Map.Entry) iter.next();
String runtimeName = ((JobIdentifier) entry.getKey()).getName();
if ((name == null && runtimeName == null) || name.equals(runtimeName)) {
values.add(entry.getValue());
}
}
return values;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.container.common.executor.JobExecutionRegistry#findAll()
*/
public Collection findAll() {
synchronized (this.contexts) {
return new HashSet(contexts.values());
}
}
/*
* (non-Javadoc)
* @see org.springframework.batch.container.common.executor.JobExecutionRegistry#findByRuntimeInformation(org.springframework.batch.container.common.runtime.JobRuntimeInformation)
*/
public JobExecutionContext get(JobIdentifier runtimeInformation) {
synchronized (this.contexts) {
return (JobExecutionContext) contexts.get(runtimeInformation);
}
}
/*
* (non-Javadoc)
* @see org.springframework.batch.container.common.executor.JobExecutionRegistry#isRegistered(org.springframework.batch.container.common.runtime.JobRuntimeInformation)
*/
public boolean isRegistered(JobIdentifier runtimeInformation) {
synchronized (this.contexts) {
return contexts.containsKey(runtimeInformation);
}
}
/*
* (non-Javadoc)
* @see org.springframework.batch.container.common.executor.JobExecutionRegistry#register(org.springframework.batch.container.common.runtime.JobRuntimeInformation,
* org.springframework.batch.container.common.domain.JobExecution)
*/
public JobExecutionContext register(JobIdentifier jobIdentifier, JobInstance job) {
if (isRegistered(jobIdentifier)) {
return get(jobIdentifier);
}
JobExecutionContext context = new JobExecutionContext(jobIdentifier, job);
synchronized (this.contexts) {
contexts.put(jobIdentifier, context);
}
return context;
}
/*
* (non-Javadoc)
* @see org.springframework.batch.container.common.executor.JobExecutionRegistry#unregister(org.springframework.batch.container.common.runtime.JobRuntimeInformation)
*/
public void unregister(JobIdentifier runtimeInformation) {
synchronized (this.contexts) {
contexts.remove(runtimeInformation);
}
}
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Specific implementations of facade concerns.
</p>
</body>
</html>

View File

@@ -0,0 +1,152 @@
/*
* 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.job;
import java.sql.Timestamp;
import java.util.Iterator;
import java.util.List;
import org.springframework.batch.core.configuration.JobConfiguration;
import org.springframework.batch.core.configuration.StepConfiguration;
import org.springframework.batch.core.domain.BatchStatus;
import org.springframework.batch.core.domain.JobExecution;
import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.domain.StepInstance;
import org.springframework.batch.core.executor.JobExecutor;
import org.springframework.batch.core.executor.StepExecutor;
import org.springframework.batch.core.executor.StepExecutorFactory;
import org.springframework.batch.core.executor.StepInterruptedException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.runtime.JobExecutionContext;
import org.springframework.batch.core.runtime.StepExecutionContext;
import org.springframework.batch.execution.step.DefaultStepExecutorFactory;
import org.springframework.batch.io.exception.BatchCriticalException;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.repeat.RepeatContext;
/**
* Default implementation of (@JobLifecycle) interface. Sequentially executes a
* job by iterating it's life of steps. Interruption of a job run is pluggable
* by passing in various interruption policies.
*
* @author Lucas Ward
*/
public class DefaultJobExecutor implements JobExecutor {
private JobRepository jobRepository;
private StepExecutorFactory stepExecutorResolver = new DefaultStepExecutorFactory();
public void run(JobConfiguration configuration, JobExecutionContext jobExecutionContext)
throws BatchCriticalException {
JobInstance job = jobExecutionContext.getJob();
JobExecution jobExecution = jobExecutionContext.getJobExecution();
updateStatus(jobExecutionContext, BatchStatus.STARTING);
List steps = job.getSteps();
ExitStatus status = ExitStatus.FAILED;
try {
for (Iterator i = steps.iterator(), j = configuration.getStepConfigurations().iterator(); i.hasNext()
&& j.hasNext();) {
StepInstance step = (StepInstance) i.next();
StepConfiguration stepConfiguration = (StepConfiguration) j.next();
if (shouldStart(step, stepConfiguration)) {
updateStatus(jobExecutionContext, BatchStatus.STARTED);
StepExecutor stepExecutor = stepExecutorResolver.getExecutor(stepConfiguration);
StepExecutionContext stepExecutionContext = new StepExecutionContext(jobExecutionContext, step);
status = stepExecutor.process(stepConfiguration, stepExecutionContext);
}
}
updateStatus(jobExecutionContext, BatchStatus.COMPLETED);
}
catch (StepInterruptedException e) {
updateStatus(jobExecutionContext, BatchStatus.STOPPED);
rethrow(e);
}
catch (Throwable t) {
updateStatus(jobExecutionContext, BatchStatus.FAILED);
rethrow(t);
}
finally {
jobExecution.setEndTime(new Timestamp(System.currentTimeMillis()));
jobExecution.setExitCode(status.getExitCode());
jobRepository.saveOrUpdate(jobExecution);
}
}
private void updateStatus(JobExecutionContext jobExecutionContext, BatchStatus status) {
JobInstance job = jobExecutionContext.getJob();
JobExecution jobExecution = jobExecutionContext.getJobExecution();
jobExecution.setStatus(status);
job.setStatus(status);
jobRepository.update(job);
jobRepository.saveOrUpdate(jobExecution);
for (Iterator iter = jobExecutionContext.getStepContexts().iterator(); iter.hasNext();) {
RepeatContext context = (RepeatContext) iter.next();
context.setAttribute("JOB_STATUS", status);
}
}
/*
* Given a step and configuration, return true if the step should start,
* false if it should not, and throw an exception if the job should finish.
*/
private boolean shouldStart(StepInstance step, StepConfiguration stepConfiguration) {
if (step.getStatus() == BatchStatus.COMPLETED && stepConfiguration.isAllowStartIfComplete() == false) {
// step is complete, false should be returned, indicated that the
// step should
// not be started
return false;
}
if (step.getStepExecutionCount() < stepConfiguration.getStartLimit()) {
// step start count is less than start max, return true
return true;
}
else {
// start max has been exceeded, throw an exception.
throw new BatchCriticalException("Maximum start limit exceeded for step: " + step.getName() + "StartMax: "
+ stepConfiguration.getStartLimit());
}
}
/**
* @param t
*/
private static void rethrow(Throwable t) throws RuntimeException {
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
else {
throw new BatchCriticalException(t);
}
}
public void setJobRepository(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
public void setStepExecutorResolver(StepExecutorFactory stepExecutorResolver) {
this.stepExecutorResolver = stepExecutorResolver;
}
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Specific implementations of job concerns.
</p>
</body>
</html>

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Reference implementation of the Spring Batch Core.
</p>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More