Apply spring-javaformat style for consistency with other projects

Resolves #4118
This commit is contained in:
Mahmoud Ben Hassine
2022-05-25 17:47:13 +02:00
parent b3fe088879
commit c4ad90b9b1
1626 changed files with 44478 additions and 45612 deletions

View File

@@ -27,15 +27,15 @@ package org.springframework.batch.core;
public enum BatchStatus {
/**
* The order of the status values is significant because it can be used to
* aggregate a set of status values. The result should be the maximum
* value. Since {@code COMPLETED} is first in the order, only if all elements of an
* execution are {@code COMPLETED} can the aggregate status be COMPLETED. A running
* execution is expected to move from {@code STARTING} to {@code STARTED} to {@code COMPLETED}
* (through the order defined by {@link #upgradeTo(BatchStatus)}). Higher
* values than {@code STARTED} signify more serious failures. {@code ABANDONED} is used for
* steps that have finished processing but were not successful and where
* they should be skipped on a restart (so {@code FAILED} is the wrong status).
* The order of the status values is significant because it can be used to aggregate a
* set of status values. The result should be the maximum value. Since
* {@code COMPLETED} is first in the order, only if all elements of an execution are
* {@code COMPLETED} can the aggregate status be COMPLETED. A running execution is
* expected to move from {@code STARTING} to {@code STARTED} to {@code COMPLETED}
* (through the order defined by {@link #upgradeTo(BatchStatus)}). Higher values than
* {@code STARTED} signify more serious failures. {@code ABANDONED} is used for steps
* that have finished processing but were not successful and where they should be
* skipped on a restart (so {@code FAILED} is the wrong status).
*/
/**
@@ -72,8 +72,8 @@ public enum BatchStatus {
UNKNOWN;
/**
* Convenience method to return the higher value status of the statuses passed to the method.
*
* Convenience method to return the higher value status of the statuses passed to the
* method.
* @param status1 The first status to check.
* @param status2 The second status to check.
* @return The higher value status of the two statuses.
@@ -84,7 +84,6 @@ public enum BatchStatus {
/**
* Convenience method to decide if a status indicates that work is in progress.
*
* @return true if the status is STARTING, STARTED
*/
public boolean isRunning() {
@@ -92,9 +91,7 @@ public enum BatchStatus {
}
/**
* Convenience method to decide if a status indicates execution was
* unsuccessful.
*
* Convenience method to decide if a status indicates execution was unsuccessful.
* @return {@code true} if the status is {@code FAILED} or greater.
*/
public boolean isUnsuccessful() {
@@ -102,13 +99,12 @@ public enum BatchStatus {
}
/**
* Method used to move status values through their logical progression, and
* override less severe failures with more severe ones. This value is
* compared with the parameter, and the one that has higher priority is
* returned. If both are {@code STARTED} or less than the value returned is the
* largest in the sequence {@code STARTING}, {@code STARTED}, {@code COMPLETED}. Otherwise, the value
* returned is the maximum of the two.
*
* Method used to move status values through their logical progression, and override
* less severe failures with more severe ones. This value is compared with the
* parameter, and the one that has higher priority is returned. If both are
* {@code STARTED} or less than the value returned is the largest in the sequence
* {@code STARTING}, {@code STARTED}, {@code COMPLETED}. Otherwise, the value returned
* is the maximum of the two.
* @param other Another status to which to compare.
* @return either this or the other status, depending on their priority.
*/
@@ -151,7 +147,6 @@ public enum BatchStatus {
* Find a {@code BatchStatus} that matches the beginning of the given value. If no
* match is found, return {@code COMPLETED} as the default because it has low
* precedence.
*
* @param value A string representing a status.
* @return a {BatchStatus} object.
*/
@@ -164,4 +159,5 @@ public enum BatchStatus {
// Default match should be the lowest priority
return COMPLETED;
}
}

View File

@@ -18,9 +18,8 @@ package org.springframework.batch.core;
import org.springframework.batch.core.scope.context.ChunkContext;
/**
* Listener interface for the lifecycle of a chunk. A chunk
* can be thought of as a collection of items that are
* committed together.
* Listener interface for the lifecycle of a chunk. A chunk can be thought of as a
* collection of items that are committed together.
*
* @author Lucas Ward
* @author Michael Minella
@@ -36,7 +35,6 @@ public interface ChunkListener extends StepListener {
/**
* Callback before the chunk is executed, but inside the transaction.
*
* @param context The current {@link ChunkContext}
*/
default void beforeChunk(ChunkContext context) {
@@ -44,24 +42,23 @@ public interface ChunkListener extends StepListener {
/**
* Callback after the chunk is executed, outside the transaction.
*
* @param context The current {@link ChunkContext}
*/
default void afterChunk(ChunkContext context) {
}
/**
* Callback after a chunk has been marked for rollback. It is invoked
* after transaction rollback. While the rollback will have occurred,
* transactional resources might still be active and accessible. Due to
* this, data access code within this callback still "participates" in
* the original transaction unless it declares that it runs in its own
* transaction. <em>As a result, you should use {@code PROPAGATION_REQUIRES_NEW} for any
* transactional operation that is called from here.</em>
*
* @param context the chunk context containing the exception that caused
* the underlying rollback.
* Callback after a chunk has been marked for rollback. It is invoked after
* transaction rollback. While the rollback will have occurred, transactional
* resources might still be active and accessible. Due to this, data access code
* within this callback still "participates" in the original transaction unless it
* declares that it runs in its own transaction. <em>As a result, you should use
* {@code PROPAGATION_REQUIRES_NEW} for any transactional operation that is called
* from here.</em>
* @param context the chunk context containing the exception that caused the
* underlying rollback.
*/
default void afterChunkError(ChunkContext context) {
}
}

View File

@@ -25,10 +25,10 @@ import org.springframework.util.Assert;
import org.springframework.util.DigestUtils;
/**
* Default implementation of the {@link JobKeyGenerator} interface.
* This implementation provides a single hash value based on the {@link JobParameters} object
* passed in. Only identifying parameters (as per {@link JobParameter#isIdentifying()})
* are used in the calculation of the key.
* Default implementation of the {@link JobKeyGenerator} interface. This implementation
* provides a single hash value based on the {@link JobParameters} object passed in. Only
* identifying parameters (as per {@link JobParameter#isIdentifying()}) are used in the
* calculation of the key.
*
* @author Michael Minella
* @author Mahmoud Ben Hassine
@@ -50,16 +50,17 @@ public class DefaultJobKeyGenerator implements JobKeyGenerator<JobParameters> {
Collections.sort(keys);
for (String key : keys) {
JobParameter jobParameter = props.get(key);
if(jobParameter.isIdentifying()) {
String value = jobParameter.getValue()==null ? "" : jobParameter.toString();
if (jobParameter.isIdentifying()) {
String value = jobParameter.getValue() == null ? "" : jobParameter.toString();
stringBuffer.append(key).append("=").append(value).append(";");
}
}
try {
return DigestUtils.md5DigestAsHex(stringBuffer.toString().getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(
"UTF-8 encoding not available. Fatal (should be in the JDK).");
}
catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
}
}
}

View File

@@ -21,10 +21,9 @@ 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. See Domain
* Driven Design, by Eric Evans, for more information on this pattern
* and the difference between Entities and Value Objects.
* Batch Domain Entity class. Any class that should be uniquely identifiable from another
* should subclass from Entity. See Domain Driven Design, by Eric Evans, for more
* information on this pattern and the difference between Entities and Value Objects.
*
* @author Lucas Ward
* @author Dave Syer
@@ -48,15 +47,14 @@ public class Entity implements Serializable {
/**
* The constructor for the {@link Entity} where the ID is established.
*
* @param id The ID for the entity.
*/
public Entity(Long id) {
super();
//Commented out because StepExecutions are still created in a disconnected
//manner. The Repository should create them, then this can be uncommented.
//Assert.notNull(id, "Entity id must not be null.");
// Commented out because StepExecutions are still created in a disconnected
// manner. The Repository should create them, then this can be uncommented.
// Assert.notNull(id, "Entity id must not be null.");
this.id = id;
}
@@ -95,23 +93,24 @@ public class Entity implements Serializable {
public void incrementVersion() {
if (version == null) {
version = 0;
} else {
}
else {
version = version + 1;
}
}
/**
* Creates a string representation of the {@code Entity},
* including the {@code id}, {@code version}, and class name.
*/
/**
* Creates a string representation of the {@code Entity}, including the {@code id},
* {@code version}, and class name.
*/
@Override
public String toString() {
return String.format("%s: id=%d, version=%d", ClassUtils.getShortName(getClass()), id, version);
}
/**
* Attempt to establish identity based on {@code id} if both exist. If either {@code id}
* does not exist, use {@code Object.equals()}.
* Attempt to establish identity based on {@code id} if both exist. If either
* {@code id} does not exist, use {@code Object.equals()}.
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@@ -135,14 +134,13 @@ public class Entity implements Serializable {
/**
* Use {@code id}, if it exists, to establish a hash code. Otherwise fall back to
* {@code Object.hashCode()}. It is based on the
* same information as {@code equals}, so, if that
* changes, this will. Note that this follows the contract of {@code Object.hashCode()}
* but will cause problems for anyone adding an unsaved {@link Entity} to a
* {@code Set} because {@code Set.contains()} almost certainly returns 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 this is internally consistent.
* Clients should not be exposed to unsaved entities.
* {@code Object.hashCode()}. It is based on the same information as {@code equals},
* so, if that changes, this will. Note that this follows the contract of
* {@code Object.hashCode()} but will cause problems for anyone adding an unsaved
* {@link Entity} to a {@code Set} because {@code Set.contains()} almost certainly
* returns 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 this is internally
* consistent. Clients should not be exposed to unsaved entities.
*
* @see java.lang.Object#hashCode()
*/

View File

@@ -22,8 +22,7 @@ import java.io.Serializable;
import java.io.StringWriter;
/**
* Value object used to carry information about the status of a
* job or step execution.
* Value object used to carry information about the status of a job or step execution.
*
* {@code ExitStatus} is immutable and, therefore, thread-safe.
*
@@ -34,17 +33,16 @@ import java.io.StringWriter;
public class ExitStatus implements Serializable, Comparable<ExitStatus> {
/**
* Convenient constant value representing unknown state - assumed to not
* be continuable.
* Convenient constant value representing unknown state - assumed to not be
* continuable.
*/
public static final ExitStatus UNKNOWN = new ExitStatus("UNKNOWN");
/**
* Convenient constant value representing continuable state where processing
* is still taking place, so no further action is required. Used for
* asynchronous execution scenarios where the processing is happening in
* another thread or process and the caller is not required to wait for the
* result.
* Convenient constant value representing continuable state where processing is still
* taking place, so no further action is required. Used for asynchronous execution
* scenarios where the processing is happening in another thread or process and the
* caller is not required to wait for the result.
*/
public static final ExitStatus EXECUTING = new ExitStatus("EXECUTING");
@@ -54,8 +52,8 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
public static final ExitStatus COMPLETED = new ExitStatus("COMPLETED");
/**
* Convenient constant value representing a job that did no processing
* (for example, because it was already complete).
* Convenient constant value representing a job that did no processing (for example,
* because it was already complete).
*/
public static final ExitStatus NOOP = new ExitStatus("NOOP");
@@ -65,8 +63,7 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
public static final ExitStatus FAILED = new ExitStatus("FAILED");
/**
* Convenient constant value representing finished processing with
* interrupted status.
* Convenient constant value representing finished processing with interrupted status.
*/
public static final ExitStatus STOPPED = new ExitStatus("STOPPED");
@@ -75,8 +72,8 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
private final String exitDescription;
/**
* Constructor that accepts the exit code and sets the exit description to an empty {@link String}.
*
* Constructor that accepts the exit code and sets the exit description to an empty
* {@link String}.
* @param exitCode The exit code to be used for the {@link ExitStatus}.
*/
public ExitStatus(String exitCode) {
@@ -84,8 +81,8 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
}
/**
* Constructor that establishes the exit code and the exit description for the {@link ExitStatus}.
*
* Constructor that establishes the exit code and the exit description for the
* {@link ExitStatus}.
* @param exitCode The exit code to be used for the {@link ExitStatus}.
* @param exitDescription The exit description to be used for the {@link ExitStatus}.
*/
@@ -97,7 +94,6 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
/**
* Getter for the exit code (defaults to blank).
*
* @return the exit code.
*/
public String getExitCode() {
@@ -106,7 +102,6 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
/**
* Getter for the exit description (defaults to blank)
*
* @return {@link String} containing the exit description.
*/
public String getExitDescription() {
@@ -114,11 +109,10 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
}
/**
* Create a new {@link ExitStatus} with a logical combination of the exit
* code and a concatenation of the descriptions. If either value has a
* higher severity, its exit code is used in the result. In the
* case of equal severity, the exit code is replaced if the new value is
* alphabetically greater.<br>
* Create a new {@link ExitStatus} with a logical combination of the exit code and a
* concatenation of the descriptions. If either value has a higher severity, its exit
* code is used in the result. In the case of equal severity, the exit code is
* replaced if the new value is alphabetically greater.<br>
* <br>
*
* Severity is defined by the exit code:
@@ -133,10 +127,9 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
* Others have severity 7, so custom exit codes always win.<br>
*
* If the input is {@code null} just return this.
*
* @param status An {@link ExitStatus} object to combine with this one.
* @return a new {@link ExitStatus} combining the current value and the
* argument provided.
* @return a new {@link ExitStatus} combining the current value and the argument
* provided.
*/
public ExitStatus and(ExitStatus status) {
if (status == null) {
@@ -151,8 +144,8 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
/**
* @param status An {@link ExitStatus} to compare
* @return greater than zero, 0, or less than zero,
* according to the severity and exit code.
* @return greater than zero, 0, or less than zero, according to the severity and exit
* code.
* @see java.lang.Comparable
*/
@Override
@@ -167,8 +160,8 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
}
/**
* Determines severity (an int between 1 and 7, inclusive)
* based on an {@code ExitStatus} object.
* Determines severity (an int between 1 and 7, inclusive) based on an
* {@code ExitStatus} object.
* @param status The {@code ExitStatus} object from which to determine the severity.
* @return the severity number.
*/
@@ -228,12 +221,10 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
}
/**
* Add an exit code to an existing {@link ExitStatus}. If there is already a
* code present, it will be replaced.
*
* Add an exit code to an existing {@link ExitStatus}. If there is already a code
* present, it will be replaced.
* @param code The code to add.
* @return a new {@link ExitStatus} with the same properties but a new exit
* code.
* @return a new {@link ExitStatus} with the same properties but a new exit code.
*/
public ExitStatus replaceExitCode(String code) {
return new ExitStatus(code, exitDescription);
@@ -241,7 +232,6 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
/**
* Check if this status represents a running process.
*
* @return {@code true} if the exit code is {@code EXECUTING} or {@code UNKNOWN}.
*/
public boolean isRunning() {
@@ -249,10 +239,8 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
}
/**
* Add an exit description to an existing {@link ExitStatus}. If there is
* already a description present, the two are concatenated with a
* semicolon.
*
* Add an exit description to an existing {@link ExitStatus}. If there is already a
* description present, the two are concatenated with a semicolon.
* @param description The description to add.
* @return a new {@link ExitStatus} with the same properties but a new exit
* description.
@@ -273,9 +261,8 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
}
/**
* Extract the stack trace from the throwable provided and append it to
* the existing description.
*
* Extract the stack trace from the throwable provided and append it to the existing
* description.
* @param throwable A {@link Throwable} instance containing the stack trace.
* @return a new ExitStatus with the stack trace appended.
*/
@@ -287,16 +274,18 @@ public class ExitStatus implements Serializable, Comparable<ExitStatus> {
}
/**
* @param status The {@code ExitStatus} object containing the exit code to be evaluated.
* @param status The {@code ExitStatus} object containing the exit code to be
* evaluated.
* @return {@code true} if the value matches a known exit code.
*/
public static boolean isNonDefaultExitStatus(ExitStatus status) {
return status == null || status.getExitCode() == null ||
status.getExitCode().equals(ExitStatus.COMPLETED.getExitCode()) ||
status.getExitCode().equals(ExitStatus.EXECUTING.getExitCode()) ||
status.getExitCode().equals(ExitStatus.FAILED.getExitCode()) ||
status.getExitCode().equals(ExitStatus.NOOP.getExitCode()) ||
status.getExitCode().equals(ExitStatus.STOPPED.getExitCode()) ||
status.getExitCode().equals(ExitStatus.UNKNOWN.getExitCode());
return status == null || status.getExitCode() == null
|| status.getExitCode().equals(ExitStatus.COMPLETED.getExitCode())
|| status.getExitCode().equals(ExitStatus.EXECUTING.getExitCode())
|| status.getExitCode().equals(ExitStatus.FAILED.getExitCode())
|| status.getExitCode().equals(ExitStatus.NOOP.getExitCode())
|| status.getExitCode().equals(ExitStatus.STOPPED.getExitCode())
|| status.getExitCode().equals(ExitStatus.UNKNOWN.getExitCode());
}
}

View File

@@ -19,10 +19,9 @@ import org.springframework.batch.item.ItemProcessor;
import org.springframework.lang.Nullable;
/**
* Listener interface for the processing of an item. Implementations
* of this interface are notified before and after an item is
* passed to the {@link ItemProcessor} and in the event of any
* exceptions thrown by the processor.
* Listener interface for the processing of an item. Implementations of this interface are
* notified before and after an item is passed to the {@link ItemProcessor} and in the
* event of any exceptions thrown by the processor.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
@@ -32,17 +31,15 @@ public interface ItemProcessListener<T, S> extends StepListener {
/**
* Called before {@link ItemProcessor#process(Object)}.
*
* @param item to be processed.
*/
default void beforeProcess(T item) {
}
/**
* Called after {@link ItemProcessor#process(Object)} returns. If the
* processor returns {@code null}, this method is still called, with
* a {@code null} result, allowing for notification of "filtered" items.
*
* Called after {@link ItemProcessor#process(Object)} returns. If the processor
* returns {@code null}, this method is still called, with a {@code null} result,
* allowing for notification of "filtered" items.
* @param item to be processed
* @param result of processing
*/
@@ -51,10 +48,10 @@ public interface ItemProcessListener<T, S> extends StepListener {
/**
* Called if an exception was thrown from {@link ItemProcessor#process(Object)}.
*
* @param item attempted to be processed
* @param e - exception thrown during processing.
*/
default void onProcessError(T item, Exception e) {
}
}

View File

@@ -33,10 +33,8 @@ public interface ItemReadListener<T> extends StepListener {
}
/**
* Called after {@link ItemReader#read()}.
* This method is called only for actual items (that is, it is not called when the
* reader returns {@code null}).
*
* Called after {@link ItemReader#read()}. This method is called only for actual items
* (that is, it is not called when the reader returns {@code null}).
* @param item returned from read()
*/
default void afterRead(T item) {
@@ -44,9 +42,9 @@ public interface ItemReadListener<T> extends StepListener {
/**
* Called if an error occurs while trying to read.
*
* @param ex thrown from {@link ItemReader}
*/
default void onReadError(Exception ex) {
}
}

View File

@@ -22,20 +22,18 @@ import org.springframework.batch.item.ItemWriter;
/**
* <p>
* Listener interface for the writing of items. Implementations
* of this interface are notified before, after, and in case
* of any exception thrown while writing a list of items.
* Listener interface for the writing of items. Implementations of this interface are
* notified before, after, and in case of any exception thrown while writing a list of
* items.
* </p>
*
* <p>
* <em>Note: </em> This listener is designed to work around the
* lifecycle of an item. This means that each method should be
* called once within the lifecycle of an item and that, in fault-tolerant
* scenarios, any transactional work that is done in
* one of these methods is rolled back and not re-applied.
* Because of this, it is recommended to not perform any logic
* that participates in a transaction when using this listener.
*</p>
* <em>Note: </em> This listener is designed to work around the lifecycle of an item. This
* means that each method should be called once within the lifecycle of an item and that,
* in fault-tolerant scenarios, any transactional work that is done in one of these
* methods is rolled back and not re-applied. Because of this, it is recommended to not
* perform any logic that participates in a transaction when using this listener.
* </p>
*
* @author Lucas Ward
* @author Mahmoud Ben Hassine
@@ -45,31 +43,28 @@ public interface ItemWriteListener<S> extends StepListener {
/**
* Called before {@link ItemWriter#write(java.util.List)}
*
* @param items to be written
*/
default void beforeWrite(List<? extends S> items) {
}
/**
* Called after {@link ItemWriter#write(java.util.List)}. This is
* called before any transaction is committed, and before
* Called after {@link ItemWriter#write(java.util.List)}. This is called before any
* transaction is committed, and before
* {@link ChunkListener#afterChunk(ChunkContext)}.
*
* @param items written items
*/
default void afterWrite(List<? extends S> items) {
}
/**
* Called if an error occurs while trying to write. Called inside a
* transaction, but the transaction will normally be rolled back. There is
* no way to identify from this callback which of the items (if any) caused
* the error.
*
* Called if an error occurs while trying to write. Called inside a transaction, but
* the transaction will normally be rolled back. There is no way to identify from this
* callback which of the items (if any) caused the error.
* @param exception thrown from {@link ItemWriter}
* @param items attempted to be written.
*/
default void onWriteError(Exception exception, List<? extends S> items) {
}
}

View File

@@ -20,9 +20,8 @@ import org.springframework.lang.Nullable;
/**
* Batch domain object representing a job. {@code Job} is an explicit abstraction
* representing the configuration of a job specified by a developer.
* Note that the restart policy is applied to the job as a whole and not to a
* step.
* representing the configuration of a job specified by a developer. Note that the restart
* policy is applied to the job as a whole and not to a step.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
@@ -33,29 +32,28 @@ public interface Job {
/**
* Flag to indicate if this job can be restarted, at least in principle.
*
* @return true if this job can be restarted after a failure. Defaults to {@code true}.
* @return true if this job can be restarted after a failure. Defaults to
* {@code true}.
*/
default boolean isRestartable() {
return true;
}
/**
* Run the {@link JobExecution} and update the meta information, such as status
* and statistics, as necessary. This method should not throw any exceptions
* for failed execution. Clients should be careful to inspect the
* {@link JobExecution} status to determine success or failure.
*
* Run the {@link JobExecution} and update the meta information, such as status and
* statistics, as necessary. This method should not throw any exceptions for failed
* execution. Clients should be careful to inspect the {@link JobExecution} status to
* determine success or failure.
* @param execution a {@link JobExecution}
*/
void execute(JobExecution execution);
/**
* If clients need to generate new parameters for the next execution in a
* sequence, they can use this incrementer. The return value may be {@code null},
* when this job does not have a natural sequence.
*
* @return an incrementer to be used for creating new parameters. Defaults to {@code null}.
* If clients need to generate new parameters for the next execution in a sequence,
* they can use this incrementer. The return value may be {@code null}, when this job
* does not have a natural sequence.
* @return an incrementer to be used for creating new parameters. Defaults to
* {@code null}.
*/
@Nullable
default JobParametersIncrementer getJobParametersIncrementer() {
@@ -63,10 +61,9 @@ public interface Job {
}
/**
* A validator for the job parameters of a {@link JobExecution}. Clients of
* a {@code Job} may need to validate the parameters for a launch or before or during
* A validator for the job parameters of a {@link JobExecution}. Clients of a
* {@code Job} may need to validate the parameters for a launch or before or during
* the execution.
*
* @return a validator that can be used to check parameter values (never
* {@code null}). Defaults to {@link DefaultJobParametersValidator}.
*/

View File

@@ -67,8 +67,8 @@ public class JobExecution extends Entity {
private transient volatile List<Throwable> failureExceptions = new CopyOnWriteArrayList<>();
/**
* Constructor that sets the state of the instance to the {@link JobExecution} parameter.
*
* Constructor that sets the state of the instance to the {@link JobExecution}
* parameter.
* @param original The {@link JobExecution} to be copied.
*/
public JobExecution(JobExecution original) {
@@ -88,12 +88,13 @@ public class JobExecution extends Entity {
}
/**
* Because a JobExecution is not valid unless the job is set, this
* constructor is the only valid one from a modeling point of view.
*
* Because a JobExecution is not valid unless the job is set, this constructor is the
* only valid one from a modeling point of view.
* @param job The job of which this execution is a part.
* @param id A {@link Long} that represents the {@code id} for the {@code JobExecution}.
* @param jobParameters A {@link JobParameters} instance for this {@code JobExecution}.
* @param id A {@link Long} that represents the {@code id} for the
* {@code JobExecution}.
* @param jobParameters A {@link JobParameters} instance for this
* {@code JobExecution}.
*/
public JobExecution(JobInstance job, Long id, @Nullable JobParameters jobParameters) {
super(id);
@@ -103,9 +104,9 @@ public class JobExecution extends Entity {
/**
* Constructor for transient (unsaved) instances.
*
* @param job The enclosing {@link JobInstance}.
* @param jobParameters The {@link JobParameters} instance for this {@code JobExecution}.
* @param jobParameters The {@link JobParameters} instance for this
* {@code JobExecution}.
*/
public JobExecution(JobInstance job, JobParameters jobParameters) {
this(job, null, jobParameters);
@@ -113,7 +114,6 @@ public class JobExecution extends Entity {
/**
* Constructor that accepts the job execution {@code id} and {@link JobParameters}.
*
* @param id The job execution {@code id}.
* @param jobParameters The {@link JobParameters} for the {@link JobExecution}.
*/
@@ -123,7 +123,6 @@ public class JobExecution extends Entity {
/**
* Constructor that accepts the job execution {@code id}.
*
* @param id The job execution {@code id}.
*/
public JobExecution(Long id) {
@@ -147,7 +146,6 @@ public class JobExecution extends Entity {
/**
* Set the {@link JobInstance} used by the {@link JobExecution}.
*
* @param jobInstance The {@link JobInstance} used by the {@link JobExecution}.
*/
public void setJobInstance(JobInstance jobInstance) {
@@ -156,7 +154,6 @@ public class JobExecution extends Entity {
/**
* Set the end time.
*
* @param endTime The {@link Date} to be used for the end time.
*/
public void setEndTime(Date endTime) {
@@ -173,7 +170,6 @@ public class JobExecution extends Entity {
/**
* Set the start time.
*
* @param startTime The {@link Date} to be used for the start time.
*/
public void setStartTime(Date startTime) {
@@ -189,7 +185,6 @@ public class JobExecution extends Entity {
/**
* Set the value of the {@code status} field.
*
* @param status The status to set.
*/
public void setStatus(BatchStatus status) {
@@ -197,10 +192,9 @@ public class JobExecution extends Entity {
}
/**
* Upgrade the {@code status} field if the provided value is greater than the
* existing one. Clients using this method to set the status can be sure
* to not overwrite a failed status with a successful one.
*
* Upgrade the {@code status} field if the provided value is greater than the existing
* one. Clients using this method to set the status can be sure to not overwrite a
* failed status with a successful one.
* @param status The new status value.
*/
public void upgradeStatus(BatchStatus status) {
@@ -210,7 +204,6 @@ public class JobExecution extends Entity {
/**
* Convenience getter for the {@code id} of the enclosing job. Useful for DAO
* implementations.
*
* @return the @{code id} of the enclosing job.
*/
public Long getJobId() {
@@ -243,7 +236,6 @@ public class JobExecution extends Entity {
/**
* Accessor for the step executions.
*
* @return the step executions that were registered.
*/
public Collection<StepExecution> getStepExecutions() {
@@ -253,8 +245,7 @@ public class JobExecution extends Entity {
/**
* Register a step execution with the current job execution.
* @param stepName the name of the step the new execution is associated with.
* @return an empty {@link StepExecution} associated with this
* {@code JobExecution}.
* @return an empty {@link StepExecution} associated with this {@code JobExecution}.
*/
public StepExecution createStepExecution(String stepName) {
StepExecution stepExecution = new StepExecution(stepName, this);
@@ -263,9 +254,8 @@ public class JobExecution extends Entity {
}
/**
* Test if this {@link JobExecution} indicates that it is running.
* Note that this does not necessarily mean that it has been persisted.
*
* Test if this {@link JobExecution} indicates that it is running. Note that this does
* not necessarily mean that it has been persisted.
* @return {@code true} if the end time is null and the start time is not null.
*/
public boolean isRunning() {
@@ -273,8 +263,7 @@ public class JobExecution extends Entity {
}
/**
* Test if this {@link JobExecution} indicates that it has been signalled to
* stop.
* Test if this {@link JobExecution} indicates that it has been signalled to stop.
* @return {@code true} if the status is {@link BatchStatus#STOPPING}.
*/
public boolean isStopping() {
@@ -283,7 +272,6 @@ public class JobExecution extends Entity {
/**
* Sets the {@link ExecutionContext} for this execution.
*
* @param executionContext The context.
*/
public void setExecutionContext(ExecutionContext executionContext) {
@@ -291,9 +279,8 @@ public class JobExecution extends Entity {
}
/**
* Returns the {@link ExecutionContext} for this execution. The content is
* expected to be persisted after each step completion (successful or not).
*
* Returns the {@link ExecutionContext} for this execution. The content is expected to
* be persisted after each step completion (successful or not).
* @return The {@link ExecutionContext}.
*/
public ExecutionContext getExecutionContext() {
@@ -315,8 +302,8 @@ public class JobExecution extends Entity {
}
/**
* Package-private method for re-constituting the step executions from
* existing instances.
* Package-private method for re-constituting the step executions from existing
* instances.
* @param The {@code stepExecution} execution to be added.
*/
void addStepExecution(StepExecution stepExecution) {
@@ -326,9 +313,8 @@ public class JobExecution extends Entity {
/**
* Get the date representing the last time this {@code JobExecution} was updated in
* the {@link org.springframework.batch.core.repository.JobRepository}.
*
* @return a {@code Date} object representing the last time this
* {@code JobExecution} was updated.
* @return a {@code Date} object representing the last time this {@code JobExecution}
* was updated.
*/
@Nullable
public Date getLastUpdated() {
@@ -337,9 +323,8 @@ public class JobExecution extends Entity {
/**
* Set the last time this {@code JobExecution} was updated.
*
* @param lastUpdated The {@link Date} instance to which to set
* the job execution's {@code lastUpdated} attribute.
* @param lastUpdated The {@link Date} instance to which to set the job execution's
* {@code lastUpdated} attribute.
*/
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
@@ -355,7 +340,6 @@ public class JobExecution extends Entity {
/**
* Add the provided throwable to the failure exception list.
*
* @param t A {@link Throwable} instance to be added failure exception list.
*/
public synchronized void addFailureException(Throwable t) {
@@ -363,9 +347,8 @@ public class JobExecution extends Entity {
}
/**
* Return all failure causing exceptions for this {@code JobExecution}, including
* step executions.
*
* Return all failure causing exceptions for this {@code JobExecution}, including step
* executions.
* @return a {@code List<Throwable>} containing all exceptions causing failure for
* this {@code JobExecution}.
*/
@@ -380,11 +363,8 @@ public class JobExecution extends Entity {
}
/**
* Deserialize and ensure transient fields are re-instantiated when read
* back.
*
* Deserialize and ensure transient fields are re-instantiated when read back.
* @param stream instance of {@link ObjectInputStream}.
*
* @throws IOException if an error occurs during read.
* @throws ClassNotFoundException thrown if the class is not found.
*/
@@ -400,9 +380,9 @@ public class JobExecution extends Entity {
*/
@Override
public String toString() {
return super.toString()
+ String.format(", startTime=%s, endTime=%s, lastUpdated=%s, status=%s, exitStatus=%s, job=[%s], jobParameters=[%s]",
startTime, endTime, lastUpdated, status, exitStatus, jobInstance, jobParameters);
return super.toString() + String.format(
", startTime=%s, endTime=%s, lastUpdated=%s, status=%s, exitStatus=%s, job=[%s], jobParameters=[%s]",
startTime, endTime, lastUpdated, status, exitStatus, jobInstance, jobParameters);
}
/**
@@ -410,9 +390,10 @@ public class JobExecution extends Entity {
* @param stepExecutions The step executions to add to the current list.
*/
public void addStepExecutions(List<StepExecution> stepExecutions) {
if (stepExecutions!=null) {
if (stepExecutions != null) {
this.stepExecutions.removeAll(stepExecutions);
this.stepExecutions.addAll(stepExecutions);
}
}
}

View File

@@ -16,10 +16,10 @@
package org.springframework.batch.core;
/**
* Root of exception hierarchy for checked exceptions in job and step execution.
* Clients of the {@link Job} should expect to have to catch and deal with these
* exceptions because they signal a user error or an inconsistent state between
* the user's instructions and the data.
* Root of exception hierarchy for checked exceptions in job and step execution. Clients
* of the {@link Job} should expect to have to catch and deal with these exceptions
* because they signal a user error or an inconsistent state between the user's
* instructions and the data.
*
* @author Dave Syer
*
@@ -36,13 +36,12 @@ public class JobExecutionException extends Exception {
}
/**
* Construct a {@link JobExecutionException} with a generic message and a
* cause.
*
* Construct a {@link JobExecutionException} with a generic message and a cause.
* @param msg The message.
* @param cause The cause of the exception.
*/
public JobExecutionException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -16,10 +16,10 @@
package org.springframework.batch.core;
/**
* Provide callbacks at specific points in the lifecycle of a {@link Job}.
* Implementations can be stateful if they are careful to either ensure thread
* safety or to use one instance of a listener per job, assuming that job
* instances themselves are not used by more than one thread.
* Provide callbacks at specific points in the lifecycle of a {@link Job}. Implementations
* can be stateful if they are careful to either ensure thread safety or to use one
* instance of a listener per job, assuming that job instances themselves are not used by
* more than one thread.
*
* @author Dave Syer
* @author Parikshit Dutta
@@ -28,17 +28,15 @@ public interface JobExecutionListener {
/**
* Callback before a job executes.
*
* @param jobExecution the current {@link JobExecution}
*/
default void beforeJob(JobExecution jobExecution) {
}
/**
* Callback after completion of a job. Called after both successful and
* failed executions. To perform logic on a particular status, use
* Callback after completion of a job. Called after both successful and failed
* executions. To perform logic on a particular status, use
* {@code if (jobExecution.getStatus() == BatchStatus.X)}.
*
* @param jobExecution the current {@link JobExecution}
*/
default void afterJob(JobExecution jobExecution) {

View File

@@ -19,18 +19,17 @@ package org.springframework.batch.core;
import org.springframework.util.Assert;
/**
* Batch domain object representing a uniquely identifiable job run.
* {@code JobInstance} can be restarted multiple times in case of execution failure, and
* its lifecycle ends with first successful execution.
* Batch domain object representing a uniquely identifiable job run. {@code JobInstance}
* can be restarted multiple times in case of execution failure, and its lifecycle ends
* with first successful execution.
*
* Trying to execute an existing {@code JobInstance} that has already completed
* successfully results in an error. An error is also raised for an attempt
* to restart a failed {@code JobInstance} if the {@code Job} is not restartable.
* successfully results in an error. An error is also raised for an attempt to restart a
* failed {@code JobInstance} if the {@code Job} is not restartable.
*
* @see Job
* @see JobParameters
* @see JobExecution
*
* @author Lucas Ward
* @author Dave Syer
* @author Robert Kasanicky
@@ -45,7 +44,6 @@ public class JobInstance extends Entity {
/**
* Constructor for {@link JobInstance}.
*
* @param id The instance ID.
* @param jobName The name associated with the {@link JobInstance}.
*/
@@ -62,9 +60,9 @@ public class JobInstance extends Entity {
return jobName;
}
/**
/**
* Adds the job name to the string representation of the super class ({@link Entity}).
*/
*/
@Override
public String toString() {
return super.toString() + ", Job=[" + jobName + "]";
@@ -76,4 +74,5 @@ public class JobInstance extends Entity {
public long getInstanceId() {
return super.getId();
}
}

View File

@@ -16,13 +16,11 @@
package org.springframework.batch.core;
/**
* Exception to indicate the job has been interrupted. The exception state
* indicated is not normally recoverable by batch application clients, but
* it is used internally to force a check. The exception is often wrapped
* in a runtime exception (usually {@link UnexpectedJobExecutionException}) before
* reaching the client.
* Exception to indicate the job has been interrupted. The exception state indicated is
* not normally recoverable by batch application clients, but it is used internally to
* force a check. The exception is often wrapped in a runtime exception (usually
* {@link UnexpectedJobExecutionException}) before reaching the client.
*
* @author Lucas Ward
* @author Dave Syer
@@ -35,7 +33,6 @@ public class JobInterruptedException extends JobExecutionException {
/**
* Constructor that sets the message for the exception.
*
* @param msg The message for the exception.
*/
public JobInterruptedException(String msg) {
@@ -44,9 +41,9 @@ public class JobInterruptedException extends JobExecutionException {
/**
* Constructor that sets the message for the exception.
*
* @param msg The message for the exception.
* @param status The desired {@link BatchStatus} of the surrounding execution after interruption.
* @param status The desired {@link BatchStatus} of the surrounding execution after
* interruption.
*/
public JobInterruptedException(String msg, BatchStatus status) {
super(msg);
@@ -55,10 +52,10 @@ public class JobInterruptedException extends JobExecutionException {
/**
* The desired status of the surrounding execution after the interruption.
*
* @return the status of the interruption (default STOPPED)
*/
public BatchStatus getStatus() {
return status;
}
}

View File

@@ -16,12 +16,11 @@
package org.springframework.batch.core;
/**
* Strategy interface for the generation of the key used in identifying
* unique {@link JobInstance} objects.
* Strategy interface for the generation of the key used in identifying unique
* {@link JobInstance} objects.
*
* @author Michael Minella
* @author Mahmoud Ben Hassine
*
* @param <T> The type of the source data used to calculate the key.
* @since 2.2
*/
@@ -29,11 +28,10 @@ public interface JobKeyGenerator<T> {
/**
* Method to generate the unique key used to identify a job instance.
*
* @param source Source information used to generate the key (must not be {@code null}).
*
* @return a unique string identifying the job based on the information
* supplied.
* @param source Source information used to generate the key (must not be
* {@code null}).
* @return a unique string identifying the job based on the information supplied.
*/
String generateKey(T source);
}

View File

@@ -23,10 +23,9 @@ import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
/**
* Domain representation of a parameter to a batch job. Only the following types
* can be parameters: String, Long, Date, and Double. The identifying flag is
* used to indicate if the parameter is to be used as part of the identification of
* a job instance.
* Domain representation of a parameter to a batch job. Only the following types can be
* parameters: String, Long, Date, and Double. The identifying flag is used to indicate if
* the parameter is to be used as part of the identification of a job instance.
*
* @author Lucas Ward
* @author Dave Syer
@@ -54,7 +53,6 @@ public class JobParameter implements Serializable {
/**
* Construct a new {@code JobParameter} from a {@link Long}.
*
* @param parameter {@link Long} instance. Must not be {@code null}.
* @param identifying {@code true} if the {@code JobParameter} should be identifying.
*/
@@ -64,7 +62,6 @@ public class JobParameter implements Serializable {
/**
* Construct a new {@code JobParameter} from a {@link Date}.
*
* @param parameter {@link Date} instance. Must not be {@code null}.
* @param identifying {@code true} if the {@code JobParameter} should be identifying.
*/
@@ -74,7 +71,6 @@ public class JobParameter implements Serializable {
/**
* Construct a new {@code JobParameter} from a {@link Double}.
*
* @param parameter {@link Double} instance. Must not be {@code null}.
* @param identifying {@code true} if the {@code JobParameter} should be identifying.
*/
@@ -91,7 +87,6 @@ public class JobParameter implements Serializable {
/**
* Construct a new {@code JobParameter} from a {@link String}.
*
* @param parameter A {@link String} instance.
*/
public JobParameter(String parameter) {
@@ -100,7 +95,6 @@ public class JobParameter implements Serializable {
/**
* Construct a new {@code JobParameter} from a {@link Long}.
*
* @param parameter A {@link Long} instance.
*/
public JobParameter(Long parameter) {
@@ -109,7 +103,6 @@ public class JobParameter implements Serializable {
/**
* Construct a new {@code JobParameter} as a {@link Date}.
*
* @param parameter A {@link Date} instance.
*/
public JobParameter(Date parameter) {
@@ -118,7 +111,6 @@ public class JobParameter implements Serializable {
/**
* Construct a new {@code JobParameter} from a {@link Double}.
*
* @param parameter A {@link Double} instance.
*/
public JobParameter(Double parameter) {
@@ -126,7 +118,8 @@ public class JobParameter implements Serializable {
}
/**
* @return The identifying flag. It is set to {@code true} if the job parameter is identifying.
* @return The identifying flag. It is set to {@code true} if the job parameter is
* identifying.
*/
public boolean isIdentifying() {
return identifying;
@@ -162,7 +155,7 @@ public class JobParameter implements Serializable {
@Override
public String toString() {
return parameterType == ParameterType.DATE ? "" + ((Date) parameter).getTime() : parameter.toString();
return parameterType == ParameterType.DATE ? "" + ((Date) parameter).getTime() : parameter.toString();
}
@Override
@@ -191,5 +184,7 @@ public class JobParameter implements Serializable {
* Double parameter type.
*/
DOUBLE;
}
}

View File

@@ -27,14 +27,13 @@ import java.util.Properties;
import org.springframework.lang.Nullable;
/**
* Value object representing runtime parameters to a batch job. Because the
* parameters have no individual meaning outside
* of the {@code JobParameters} object they are
* contained within, it is a value object rather than an entity. It is also
* extremely important that a parameters object can be reliably compared to
* another for equality, in order to determine if one {@code JobParameters} object
* equals another. Furthermore, because these parameters need to be
* persisted, it is vital that the types added are restricted.
* Value object representing runtime parameters to a batch job. Because the parameters
* have no individual meaning outside of the {@code JobParameters} object they are
* contained within, it is a value object rather than an entity. It is also extremely
* important that a parameters object can be reliably compared to another for equality, in
* order to determine if one {@code JobParameters} object equals another. Furthermore,
* because these parameters need to be persisted, it is vital that the types added are
* restricted.
*
* This class is immutable and, therefore, thread-safe.
*
@@ -47,7 +46,7 @@ import org.springframework.lang.Nullable;
@SuppressWarnings("serial")
public class JobParameters implements Serializable {
private final Map<String,JobParameter> parameters;
private final Map<String, JobParameter> parameters;
/**
* Default constructor.
@@ -57,174 +56,163 @@ public class JobParameters implements Serializable {
}
/**
* Constructor that is initialized with the content of a {@link Map}
* that contains a {@code String} key and a {@link JobParameter} value.
*
* @param parameters The {@link Map} that contains a {@code String} key
* and a {@link JobParameter} value.
* Constructor that is initialized with the content of a {@link Map} that contains a
* {@code String} key and a {@link JobParameter} value.
* @param parameters The {@link Map} that contains a {@code String} key and a
* {@link JobParameter} value.
*/
public JobParameters(Map<String,JobParameter> parameters) {
public JobParameters(Map<String, JobParameter> parameters) {
this.parameters = new LinkedHashMap<>(parameters);
}
/**
* Typesafe getter for the {@link Long} represented by the provided key.
*
* @param key The key for which to get a value.
* @return The {@link Long} value or {@code null} if the key is absent.
*/
@Nullable
public Long getLong(String key){
public Long getLong(String key) {
if (!parameters.containsKey(key)) {
return null;
}
Object value = parameters.get(key).getValue();
return value==null ? null : ((Long)value).longValue();
return value == null ? null : ((Long) value).longValue();
}
/**
* Typesafe getter for the {@link Long} represented by the provided key. If the
* key does not exist, the default value is returned.
*
* Typesafe getter for the {@link Long} represented by the provided key. If the key
* does not exist, the default value is returned.
* @param key The key for which to return the value.
* @param defaultValue The default value to return if the value does not exist.
* @return the parameter represented by the provided key or, if that is
* missing, the default value.
* @return the parameter represented by the provided key or, if that is missing, the
* default value.
*/
@Nullable
public Long getLong(String key, @Nullable Long defaultValue){
if(parameters.containsKey(key)){
public Long getLong(String key, @Nullable Long defaultValue) {
if (parameters.containsKey(key)) {
return getLong(key);
}
else{
else {
return defaultValue;
}
}
/**
* Typesafe getter for the {@link String} represented by the provided key.
*
* @param key The key for which to get a value.
* @return The {@link String} value or {@code null} if the key is absent.
*/
@Nullable
public String getString(String key){
public String getString(String key) {
JobParameter value = parameters.get(key);
return value==null ? null : value.toString();
return value == null ? null : value.toString();
}
/**
* Typesafe getter for the {@link String} represented by the provided key. If the
* key does not exist, the default value is returned.
*
* Typesafe getter for the {@link String} represented by the provided key. If the key
* does not exist, the default value is returned.
* @param key The key for which to return the value.
* @param defaultValue The defult value to return if the value does not exist.
* @return the parameter represented by the provided key or, if that is
* missing, the default value.
* @return the parameter represented by the provided key or, if that is missing, the
* default value.
*/
@Nullable
public String getString(String key, @Nullable String defaultValue){
if(parameters.containsKey(key)){
public String getString(String key, @Nullable String defaultValue) {
if (parameters.containsKey(key)) {
return getString(key);
}
else{
else {
return defaultValue;
}
}
/**
* Typesafe getter for the {@link Long} represented by the provided key.
*
* @param key The key for which to get a value.
* @return The {@link Double} value or {@code null} if the key is absent.
*/
@Nullable
public Double getDouble(String key){
public Double getDouble(String key) {
if (!parameters.containsKey(key)) {
return null;
}
Double value = (Double)parameters.get(key).getValue();
return value==null ? null : value.doubleValue();
Double value = (Double) parameters.get(key).getValue();
return value == null ? null : value.doubleValue();
}
/**
* Typesafe getter for the {@link Double} represented by the provided key. If the
* key does not exist, the default value is returned.
*
* Typesafe getter for the {@link Double} represented by the provided key. If the key
* does not exist, the default value is returned.
* @param key The key for which to return the value.
* @param defaultValue The default value to return if the value does not exist.
* @return the parameter represented by the provided key or, if that is
* missing, the default value.
* @return the parameter represented by the provided key or, if that is missing, the
* default value.
*/
@Nullable
public Double getDouble(String key, @Nullable Double defaultValue){
if(parameters.containsKey(key)){
public Double getDouble(String key, @Nullable Double defaultValue) {
if (parameters.containsKey(key)) {
return getDouble(key);
}
else{
else {
return defaultValue;
}
}
/**
* Typesafe getter for the {@link Date} represented by the provided key.
*
* @param key The key for which to get a value.
* @return the {@link java.util.Date} value or {@code null} if the key
* is absent.
* @return the {@link java.util.Date} value or {@code null} if the key is absent.
*/
@Nullable
public Date getDate(String key){
return this.getDate(key,null);
public Date getDate(String key) {
return this.getDate(key, null);
}
/**
* Typesafe getter for the {@link Date} represented by the provided key. If the
* key does not exist, the default value is returned.
*
* Typesafe getter for the {@link Date} represented by the provided key. If the key
* does not exist, the default value is returned.
* @param key The key for which to return the value.
* @param defaultValue The default value to return if the value does not exist.
* @return the parameter represented by the provided key or, if that is
* missing, the default value.
* @return the parameter represented by the provided key or, if that is missing, the
* default value.
*/
@Nullable
public Date getDate(String key, @Nullable Date defaultValue){
if(parameters.containsKey(key)){
return (Date)parameters.get(key).getValue();
public Date getDate(String key, @Nullable Date defaultValue) {
if (parameters.containsKey(key)) {
return (Date) parameters.get(key).getValue();
}
else{
else {
return defaultValue;
}
}
/**
* Get a map of all parameters, including {@link String},
* {@link Long}, and {@link Date} types.
*
* Get a map of all parameters, including {@link String}, {@link Long}, and
* {@link Date} types.
* @return an unmodifiable map containing all parameters.
*/
public Map<String, JobParameter> getParameters(){
public Map<String, JobParameter> getParameters() {
return Collections.unmodifiableMap(parameters);
}
/**
* @return {@code true} if the parameters object is empty or {@code false} otherwise.
*/
public boolean isEmpty(){
public boolean isEmpty() {
return parameters.isEmpty();
}
@Override
public boolean equals(Object obj) {
if(obj instanceof JobParameters == false){
if (obj instanceof JobParameters == false) {
return false;
}
if(obj == this){
if (obj == this) {
return true;
}
JobParameters rhs = (JobParameters)obj;
JobParameters rhs = (JobParameters) obj;
return this.parameters.equals(rhs.parameters);
}
@@ -239,7 +227,8 @@ public class JobParameters implements Serializable {
}
/**
* @return The {@link Properties} that contain the key and values for the {@link JobParameter} objects.
* @return The {@link Properties} that contain the key and values for the
* {@link JobParameter} objects.
*/
public Properties toProperties() {
Properties props = new Properties();
@@ -252,4 +241,5 @@ public class JobParameters implements Serializable {
return props;
}
}

View File

@@ -28,14 +28,13 @@ import org.springframework.util.Assert;
/**
* Helper class for creating {@link JobParameters}. Useful because all
* {@link JobParameter} objects are immutable and must be instantiated separately
* to ensure type safety. Once created, it can be used in the
* same was a {@link java.lang.StringBuilder} (except that order is irrelevant), by adding
* various parameter types and creating a valid {@link JobParameters} object once
* finished.<br>
* {@link JobParameter} objects are immutable and must be instantiated separately to
* ensure type safety. Once created, it can be used in the same was a
* {@link java.lang.StringBuilder} (except that order is irrelevant), by adding various
* parameter types and creating a valid {@link JobParameters} object once finished.<br>
* <br>
* Using the {@code identifying} flag indicates if the parameter should be used
* in the identification of a {@link JobInstance} object. That flag defaults to {@code true}.
* Using the {@code identifying} flag indicates if the parameter should be used in the
* identification of a {@link JobInstance} object. That flag defaults to {@code true}.
*
* @author Lucas Ward
* @author Michael Minella
@@ -59,7 +58,8 @@ public class JobParametersBuilder {
}
/**
* @param jobExplorer {@link JobExplorer} used for looking up previous job parameter information.
* @param jobExplorer {@link JobExplorer} used for looking up previous job parameter
* information.
*/
public JobParametersBuilder(JobExplorer jobExplorer) {
this.jobExplorer = jobExplorer;
@@ -75,17 +75,18 @@ public class JobParametersBuilder {
}
/**
* Constructor to add conversion capabilities to support JSR-352. Per the spec, it is expected that all
* keys and values in the provided {@link Properties} instance are {@link String} objects.
*
* Constructor to add conversion capabilities to support JSR-352. Per the spec, it is
* expected that all keys and values in the provided {@link Properties} instance are
* {@link String} objects.
* @param properties the job parameters to be used.
*/
public JobParametersBuilder(Properties properties) {
this.parameterMap = new LinkedHashMap<>();
if(properties != null) {
if (properties != null) {
for (Map.Entry<Object, Object> curProperty : properties.entrySet()) {
this.parameterMap.put((String) curProperty.getKey(), new JobParameter((String) curProperty.getValue(), false));
this.parameterMap.put((String) curProperty.getKey(),
new JobParameter((String) curProperty.getValue(), false));
}
}
}
@@ -93,7 +94,8 @@ public class JobParametersBuilder {
/**
* Copy constructor. Initializes the builder with the supplied parameters.
* @param jobParameters {@link JobParameters} instance used to initialize the builder.
* @param jobExplorer {@link JobExplorer} used for looking up previous job parameter information.
* @param jobExplorer {@link JobExplorer} used for looking up previous job parameter
* information.
*/
public JobParametersBuilder(JobParameters jobParameters, JobExplorer jobExplorer) {
this.jobExplorer = jobExplorer;
@@ -102,7 +104,6 @@ public class JobParametersBuilder {
/**
* Add a new identifying String parameter for the given key.
*
* @param key The parameter accessor.
* @param parameter The runtime parameter. Must not be {@code null}.
* @return a reference to this object.
@@ -114,10 +115,10 @@ public class JobParametersBuilder {
/**
* Add a new String parameter for the given key.
*
* @param key The parameter accessor.
* @param parameter The runtime parameter. Must not be {@code null}.
* @param identifying The indicates if the parameter is used as part of identifying a job instance.
* @param identifying The indicates if the parameter is used as part of identifying a
* job instance.
* @return a reference to this object.
*/
public JobParametersBuilder addString(String key, @NonNull String parameter, boolean identifying) {
@@ -127,7 +128,6 @@ public class JobParametersBuilder {
/**
* Add a new identifying {@link Date} parameter for the given key.
*
* @param key The parameter accessor.
* @param parameter The runtime parameter. Must not be {@code null}.
* @return a reference to this object.
@@ -139,10 +139,10 @@ public class JobParametersBuilder {
/**
* Add a new {@link Date} parameter for the given key.
*
* @param key The parameter accessor.
* @param parameter The runtime parameter. Must not be {@code null}.
* @param identifying Indicates if the parameter is used as part of identifying a job instance
* @param identifying Indicates if the parameter is used as part of identifying a job
* instance
* @return a reference to this object.
*/
public JobParametersBuilder addDate(String key, @NonNull Date parameter, boolean identifying) {
@@ -152,7 +152,6 @@ public class JobParametersBuilder {
/**
* Add a new identifying {@link Long} parameter for the given key.
*
* @param key The parameter accessor.
* @param parameter The runtime parameter. Must not be {@code null}.
* @return a reference to this object.
@@ -164,10 +163,10 @@ public class JobParametersBuilder {
/**
* Add a new {@link Long} parameter for the given key.
*
* @param key The parameter accessor.
* @param parameter The runtime parameter. Must not be {@code null}.
* @param identifying Indicates if the parameter is used as part of identifying a job instance.
* @param identifying Indicates if the parameter is used as part of identifying a job
* instance.
* @return a reference to this object.
*/
public JobParametersBuilder addLong(String key, @NonNull Long parameter, boolean identifying) {
@@ -177,7 +176,6 @@ public class JobParametersBuilder {
/**
* Add a new identifying {@link Double} parameter for the given key.
*
* @param key The parameter accessor.
* @param parameter The runtime parameter. Must not be {@code null}.
* @return a reference to this object.
@@ -189,10 +187,10 @@ public class JobParametersBuilder {
/**
* Add a new {@link Double} parameter for the given key.
*
* @param key The parameter accessor.
* @param parameter The runtime parameter. Must not be {@code null}.
* @param identifying Indicates if the parameter is used as part of identifying a job instance.
* @param identifying Indicates if the parameter is used as part of identifying a job
* instance.
* @return a reference to this object.
*/
public JobParametersBuilder addDouble(String key, @NonNull Double parameter, boolean identifying) {
@@ -201,9 +199,8 @@ public class JobParametersBuilder {
}
/**
* Conversion method that takes the current state of this builder and
* returns it as a {@code JobParameters} object.
*
* Conversion method that takes the current state of this builder and returns it as a
* {@code JobParameters} object.
* @return a valid {@link JobParameters} object.
*/
public JobParameters toJobParameters() {
@@ -212,7 +209,6 @@ public class JobParametersBuilder {
/**
* Add a new {@link JobParameter} for the given key.
*
* @param key The parameter accessor.
* @param jobParameter The runtime parameter.
* @return a reference to this object.
@@ -238,12 +234,13 @@ public class JobParametersBuilder {
/**
* Initializes the {@link JobParameters} based on the state of the {@link Job}. This
* should be called after all parameters have been entered into the builder.
* All parameters already set on this builder instance are appended to
* those retrieved from the job incrementer, overriding any with the same key (this is the same
* behavior as {@link org.springframework.batch.core.launch.support.CommandLineJobRunner}
* with the {@code -next} option and {@link org.springframework.batch.core.launch.JobOperator#startNextInstance(String)}).
*
* should be called after all parameters have been entered into the builder. All
* parameters already set on this builder instance are appended to those retrieved
* from the job incrementer, overriding any with the same key (this is the same
* behavior as
* {@link org.springframework.batch.core.launch.support.CommandLineJobRunner} with the
* {@code -next} option and
* {@link org.springframework.batch.core.launch.JobOperator#startNextInstance(String)}).
* @param job The job for which the {@link JobParameters} are being constructed.
* @return a reference to this object.
*
@@ -252,7 +249,8 @@ public class JobParametersBuilder {
public JobParametersBuilder getNextJobParameters(Job job) {
Assert.state(this.jobExplorer != null, "A JobExplorer is required to get next job parameters");
Assert.notNull(job, "Job must not be null");
Assert.notNull(job.getJobParametersIncrementer(), "No job parameters incrementer found for job=" + job.getName());
Assert.notNull(job.getJobParametersIncrementer(),
"No job parameters incrementer found for job=" + job.getName());
String name = job.getName();
JobParameters nextParameters;
@@ -280,4 +278,5 @@ public class JobParametersBuilder {
this.parameterMap = nextParametersMap;
return this;
}
}

View File

@@ -28,10 +28,8 @@ import org.springframework.lang.Nullable;
public interface JobParametersIncrementer {
/**
* Increments the provided parameters. If the input is empty, this method
* should return a bootstrap or initial value to be used on the first
* instance of a job.
*
* Increments the provided parameters. If the input is empty, this method should
* return a bootstrap or initial value to be used on the first instance of a job.
* @param parameters the last value used
* @return the next value to use (never {@code null})
*/

View File

@@ -1,37 +1,35 @@
/*
* Copyright 2009-2022 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
*
* https://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;
/**
* Exception for {@link Job} to signal that some {@link JobParameters} are
* invalid.
*
* @author Dave Syer
*
*/
@SuppressWarnings("serial")
public class JobParametersInvalidException extends JobExecutionException {
/**
* Constructor that sets the message for the exception.
*
* @param msg The {@link String} message for the {@link Exception}.
*/
public JobParametersInvalidException(String msg) {
super(msg);
}
}
/*
* Copyright 2009-2022 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
*
* https://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;
/**
* Exception for {@link Job} to signal that some {@link JobParameters} are invalid.
*
* @author Dave Syer
*
*/
@SuppressWarnings("serial")
public class JobParametersInvalidException extends JobExecutionException {
/**
* Constructor that sets the message for the exception.
* @param msg The {@link String} message for the {@link Exception}.
*/
public JobParametersInvalidException(String msg) {
super(msg);
}
}

View File

@@ -1,39 +1,38 @@
/*
* Copyright 2010-2022 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
*
* https://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 org.springframework.lang.Nullable;
/**
* Strategy interface for a {@link Job} to use in validating its parameters for
* an execution.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
*/
public interface JobParametersValidator {
/**
* Check that the parameters meet whatever requirements are appropriate, and
* throw an exception if not.
*
* @param parameters some {@link JobParameters} (can be {@code null})
* @throws JobParametersInvalidException if the parameters are invalid
*/
void validate(@Nullable JobParameters parameters) throws JobParametersInvalidException;
}
/*
* Copyright 2010-2022 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
*
* https://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 org.springframework.lang.Nullable;
/**
* Strategy interface for a {@link Job} to use in validating its parameters for an
* execution.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
*/
public interface JobParametersValidator {
/**
* Check that the parameters meet whatever requirements are appropriate, and throw an
* exception if not.
* @param parameters some {@link JobParameters} (can be {@code null})
* @throws JobParametersInvalidException if the parameters are invalid
*/
void validate(@Nullable JobParameters parameters) throws JobParametersInvalidException;
}

View File

@@ -16,35 +16,31 @@
package org.springframework.batch.core;
/**
* Interface for listener to skipped items. Callbacks are called by
* {@link Step} implementations at the appropriate time in the step lifecycle.
* Implementers of this interface should not assume that any method is
* called immediately after an error has been encountered. Because there
* may be errors later on in processing the chunk, this listener is not
* called until just before committing.
* Interface for listener to skipped items. Callbacks are called by {@link Step}
* implementations at the appropriate time in the step lifecycle. Implementers of this
* interface should not assume that any method is called immediately after an error has
* been encountered. Because there may be errors later on in processing the chunk, this
* listener is not called until just before committing.
*
* @author Dave Syer
* @author Robert Kasanicky
* @author Mahmoud Ben Hassine
*
*/
public interface SkipListener<T,S> extends StepListener {
public interface SkipListener<T, S> extends StepListener {
/**
* Callback for a failure on read that is legal and, consequently, is not going to be
* re-thrown. In case a transaction is rolled back and items are re-read, this
* callback occurs repeatedly for the same cause. This happens only
* if read items are not buffered.
*
* callback occurs repeatedly for the same cause. This happens only if read items are
* not buffered.
* @param t cause of the failure
*/
default void onSkipInRead(Throwable t) {
}
/**
* This item failed on write with the given exception, and a skip was called
* for.
*
* This item failed on write with the given exception, and a skip was called for.
* @param item the failed item
* @param t the cause of the failure
*/
@@ -52,9 +48,7 @@ public interface SkipListener<T,S> extends StepListener {
}
/**
* This item failed on processing with the given exception, and a skip was called
* for.
*
* This item failed on processing with the given exception, and a skip was called for.
* @param item the failed item
* @param t the cause of the failure
*/

View File

@@ -24,10 +24,10 @@ public class StartLimitExceededException extends RuntimeException {
/**
* Constructor that sets the message for the exception.
*
* @param message The message for the exception.
*/
public StartLimitExceededException(String message) {
super(message);
}
}

View File

@@ -16,8 +16,9 @@
package org.springframework.batch.core;
/**
* Batch domain interface representing the configuration of a step. As with a {@link Job}, a {@link Step} is meant to
* explicitly represent the configuration of a step by a developer but also the ability to execute the step.
* Batch domain interface representing the configuration of a step. As with a {@link Job},
* a {@link Step} is meant to explicitly represent the configuration of a step by a
* developer but also the ability to execute the step.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
@@ -36,8 +37,8 @@ public interface Step {
String getName();
/**
* @return {@code true} if a step that is already marked as complete can be started again.
* Defaults to {@code false}.
* @return {@code true} if a step that is already marked as complete can be started
* again. Defaults to {@code false}.
*/
default boolean isAllowStartIfComplete() {
return false;
@@ -52,14 +53,13 @@ public interface Step {
}
/**
* Process the step and assign progress and status meta information to the {@link StepExecution} provided. The
* {@link Step} is responsible for setting the meta information and also saving it, if required by the
* implementation.<br>
*
* It is not safe to reuse an instance of {@link Step} to process multiple concurrent executions.
* Process the step and assign progress and status meta information to the
* {@link StepExecution} provided. The {@link Step} is responsible for setting the
* meta information and also saving it, if required by the implementation.<br>
*
* It is not safe to reuse an instance of {@link Step} to process multiple concurrent
* executions.
* @param stepExecution an entity representing the step to be executed.
*
* @throws JobInterruptedException if the step is interrupted externally.
*/
void execute(StepExecution stepExecution) throws JobInterruptedException;

View File

@@ -18,8 +18,8 @@ package org.springframework.batch.core;
import java.io.Serializable;
/**
* Represents a contribution to a {@link StepExecution}, buffering changes until
* they can be applied at a chunk boundary.
* Represents a contribution to a {@link StepExecution}, buffering changes until they can
* be applied at a chunk boundary.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
@@ -57,7 +57,6 @@ public class StepContribution implements Serializable {
/**
* Set the {@link ExitStatus} for this contribution.
*
* @param status {@link ExitStatus} instance to be used to set the exit status.
*/
public void setExitStatus(ExitStatus status) {
@@ -66,7 +65,6 @@ public class StepContribution implements Serializable {
/**
* Public getter for the {@code ExitStatus}.
*
* @return the {@link ExitStatus} for this contribution
*/
public ExitStatus getExitStatus() {
@@ -75,7 +73,6 @@ public class StepContribution implements Serializable {
/**
* Increment the counter for the number of items processed.
*
* @param count The {@code long} amount to increment by.
*/
public void incrementFilterCount(long count) {
@@ -91,7 +88,6 @@ public class StepContribution implements Serializable {
/**
* Increment the counter for the number of items written.
*
* @param count The {@code long} amount to increment by.
*/
public void incrementWriteCount(long count) {
@@ -100,7 +96,6 @@ public class StepContribution implements Serializable {
/**
* Public access to the read counter.
*
* @return the read item counter.
*/
public long getReadCount() {
@@ -109,7 +104,6 @@ public class StepContribution implements Serializable {
/**
* Public access to the write counter.
*
* @return the write item counter.
*/
public long getWriteCount() {
@@ -118,7 +112,6 @@ public class StepContribution implements Serializable {
/**
* Public getter for the filter counter.
*
* @return the filter counter.
*/
public long getFilterCount() {
@@ -126,17 +119,16 @@ public class StepContribution implements Serializable {
}
/**
* @return the sum of skips accumulated in the parent {@link StepExecution}
* and this <code>StepContribution</code>.
* @return the sum of skips accumulated in the parent {@link StepExecution} and this
* <code>StepContribution</code>.
*/
public long getStepSkipCount() {
return readSkipCount + writeSkipCount + processSkipCount + parentSkipCount;
}
/**
* @return the number of skips collected in this
* <code>StepContribution</code> (not including skips accumulated in the
* parent {@link StepExecution}).
* @return the number of skips collected in this <code>StepContribution</code> (not
* including skips accumulated in the parent {@link StepExecution}).
*/
public long getSkipCount() {
return readSkipCount + writeSkipCount + processSkipCount;
@@ -151,7 +143,6 @@ public class StepContribution implements Serializable {
/**
* Increment the read skip count for this contribution.
*
* @param count The {@code long} amount to increment by.
*/
public void incrementReadSkipCount(long count) {
@@ -173,8 +164,7 @@ public class StepContribution implements Serializable {
}
/**
* Public getter for the read skip count.
*
* Public getter for the read skip count.
* @return the read skip count.
*/
public long getReadSkipCount() {
@@ -182,8 +172,7 @@ public class StepContribution implements Serializable {
}
/**
* Public getter for the write skip count.
*
* Public getter for the write skip count.
* @return the write skip count.
*/
public long getWriteSkipCount() {
@@ -192,7 +181,6 @@ public class StepContribution implements Serializable {
/**
* Public getter for the process skip count.
*
* @return the process skip count.
*/
public long getProcessSkipCount() {
@@ -201,7 +189,6 @@ public class StepContribution implements Serializable {
/**
* Public getter for the parent step execution of this contribution.
*
* @return parent step execution of this contribution
*/
public StepExecution getStepExecution() {

View File

@@ -29,8 +29,8 @@ import org.springframework.util.Assert;
/**
* Batch domain object representation for the execution of a step. Unlike
* {@link JobExecution}, additional properties are related to the processing
* of items, such as commit count and others.
* {@link JobExecution}, additional properties are related to the processing of items,
* such as commit count and others.
*
* @author Lucas Ward
* @author Dave Syer
@@ -81,7 +81,6 @@ public class StepExecution extends Entity {
/**
* Constructor with mandatory properties.
*
* @param stepName The step to which this execution belongs.
* @param jobExecution The current job execution.
* @param id The ID of this execution.
@@ -96,7 +95,6 @@ public class StepExecution extends Entity {
/**
* Constructor that substitutes null for the execution ID.
*
* @param stepName The step to which this execution belongs.
* @param jobExecution The current job execution.
*/
@@ -108,10 +106,9 @@ public class StepExecution extends Entity {
}
/**
* Constructor that requires only a stepName. Intended only to be
* used over serialization libraries to address the circular
* reference between {@link JobExecution} and StepExecution.
*
* Constructor that requires only a stepName. Intended only to be used over
* serialization libraries to address the circular reference between
* {@link JobExecution} and StepExecution.
* @param stepName The name of the executed step.
*/
@SuppressWarnings("unused")
@@ -124,7 +121,6 @@ public class StepExecution extends Entity {
/**
* Returns the {@link ExecutionContext} for this execution.
*
* @return the attributes.
*/
public ExecutionContext getExecutionContext() {
@@ -133,7 +129,6 @@ public class StepExecution extends Entity {
/**
* Sets the {@link ExecutionContext} for this execution.
*
* @param executionContext The attributes.
*/
public void setExecutionContext(ExecutionContext executionContext) {
@@ -142,7 +137,6 @@ public class StepExecution extends Entity {
/**
* Returns the current number of commits for this execution.
*
* @return the current number of commits.
*/
public long getCommitCount() {
@@ -151,7 +145,6 @@ public class StepExecution extends Entity {
/**
* Sets the current number of commits for this execution.
*
* @param commitCount The current number of commits.
*/
public void setCommitCount(long commitCount) {
@@ -160,7 +153,6 @@ public class StepExecution extends Entity {
/**
* Returns the time when this execution ended or {@code null} if the step is running.
*
* @return the time when this execution ended or {@code null} if the step is running.
*/
@Nullable
@@ -170,7 +162,6 @@ public class StepExecution extends Entity {
/**
* Sets the time when this execution ended.
*
* @param endTime The time when this execution ended.
*/
public void setEndTime(Date endTime) {
@@ -179,7 +170,6 @@ public class StepExecution extends Entity {
/**
* Returns the current number of items read for this execution.
*
* @return the current number of items read for this execution.
*/
public long getReadCount() {
@@ -188,7 +178,6 @@ public class StepExecution extends Entity {
/**
* Sets the current number of read items for this execution.
*
* @param readCount The current number of read items for this execution.
*/
public void setReadCount(long readCount) {
@@ -197,7 +186,6 @@ public class StepExecution extends Entity {
/**
* Returns the current number of items written for this execution.
*
* @return The current number of items written for this execution.
*/
public long getWriteCount() {
@@ -206,7 +194,6 @@ public class StepExecution extends Entity {
/**
* Sets the current number of written items for this execution.
*
* @param writeCount The current number of written items for this execution.
*/
public void setWriteCount(long writeCount) {
@@ -215,7 +202,6 @@ public class StepExecution extends Entity {
/**
* Returns the current number of rollbacks for this execution.
*
* @return the current number of rollbacks for this execution.
*/
public long getRollbackCount() {
@@ -224,7 +210,6 @@ public class StepExecution extends Entity {
/**
* Returns the current number of items filtered out of this execution.
*
* @return the current number of items filtered out of this execution.
*/
public long getFilterCount() {
@@ -233,9 +218,7 @@ public class StepExecution extends Entity {
/**
* Sets the number of items filtered out of this execution.
*
* @param filterCount The number of items filtered out of this execution to
* set.
* @param filterCount The number of items filtered out of this execution to set.
*/
public void setFilterCount(long filterCount) {
this.filterCount = filterCount;
@@ -243,7 +226,6 @@ public class StepExecution extends Entity {
/**
* Sets the number of rollbacks for this execution.
*
* @param rollbackCount {@code long} the number of rollbacks.
*/
public void setRollbackCount(long rollbackCount) {
@@ -252,7 +234,6 @@ public class StepExecution extends Entity {
/**
* Gets the time this execution was created
*
* @return the time when this execution was created.
*/
public Date getCreateTime() {
@@ -261,7 +242,6 @@ public class StepExecution extends Entity {
/**
* Sets the time this execution was created
*
* @param createTime creation time of this execution.
*/
public void setCreateTime(Date createTime) {
@@ -270,7 +250,6 @@ public class StepExecution extends Entity {
/**
* Gets the time when this execution started.
*
* @return the time when this execution started.
*/
@Nullable
@@ -280,7 +259,6 @@ public class StepExecution extends Entity {
/**
* Sets the time when this execution started.
*
* @param startTime The time when this execution started.
*/
public void setStartTime(Date startTime) {
@@ -289,7 +267,6 @@ public class StepExecution extends Entity {
/**
* Returns the current status of this step.
*
* @return the current status of this step.
*/
public BatchStatus getStatus() {
@@ -298,7 +275,6 @@ public class StepExecution extends Entity {
/**
* Sets the current status of this step.
*
* @param status The current status of this step.
*/
public void setStatus(BatchStatus status) {
@@ -306,10 +282,9 @@ public class StepExecution extends Entity {
}
/**
* Upgrade the status field if the provided value is greater than the
* existing one. Clients using this method to set the status can be sure
* that they do not overwrite a failed status with a successful one.
*
* Upgrade the status field if the provided value is greater than the existing one.
* Clients using this method to set the status can be sure that they do not overwrite
* a failed status with a successful one.
* @param status The new status value,
*/
public void upgradeStatus(BatchStatus status) {
@@ -325,7 +300,6 @@ public class StepExecution extends Entity {
/**
* Accessor for the job execution ID.
*
* @return the {@code jobExecutionId}.
*/
public Long getJobExecutionId() {
@@ -336,7 +310,8 @@ public class StepExecution extends Entity {
}
/**
* @param exitStatus The {@link ExitStatus} instance used to establish the exit status.
* @param exitStatus The {@link ExitStatus} instance used to establish the exit
* status.
*/
public void setExitStatus(ExitStatus exitStatus) {
this.exitStatus = exitStatus;
@@ -351,9 +326,7 @@ public class StepExecution extends Entity {
/**
* Accessor for the execution context information of the enclosing job.
*
* @return the {@link JobExecution} that was used to start this step
* execution.
* @return the {@link JobExecution} that was used to start this step execution.
*/
public JobExecution getJobExecution() {
return jobExecution;
@@ -361,7 +334,6 @@ public class StepExecution extends Entity {
/**
* Factory method for {@link StepContribution}.
*
* @return a new {@link StepContribution}
*/
public StepContribution createStepContribution() {
@@ -370,10 +342,9 @@ public class StepExecution extends Entity {
/**
* This method should be called on successful execution just before a chunk commit.
* Synchronizes access to the {@link StepExecution} so that changes
* are atomic.
*
* @param contribution The {@link StepContribution} instance used to update the {@code StepExecution} state.
* Synchronizes access to the {@link StepExecution} so that changes are atomic.
* @param contribution The {@link StepContribution} instance used to update the
* {@code StepExecution} state.
*/
public synchronized void apply(StepContribution contribution) {
readSkipCount += contribution.getReadSkipCount();
@@ -386,8 +357,8 @@ public class StepExecution extends Entity {
}
/**
* Increments the rollback count.
* Should be used on unsuccessful execution after a chunk has rolled back.
* Increments the rollback count. Should be used on unsuccessful execution after a
* chunk has rolled back.
*/
public synchronized void incrementRollbackCount() {
rollbackCount++;
@@ -401,8 +372,8 @@ public class StepExecution extends Entity {
}
/**
* Sets a flag that signals to an execution environment that this
* execution (and its surrounding job) wishes to exit.
* Sets a flag that signals to an execution environment that this execution (and its
* surrounding job) wishes to exit.
*/
public void setTerminateOnly() {
this.terminateOnly = true;
@@ -424,9 +395,8 @@ public class StepExecution extends Entity {
/**
* Convenience method to get the current job parameters.
*
* @return the {@link JobParameters} from the enclosing job or empty if
* that is {@code null}.
* @return the {@link JobParameters} from the enclosing job or empty if that is
* {@code null}.
*/
public JobParameters getJobParameters() {
if (jobExecution == null) {
@@ -451,8 +421,8 @@ public class StepExecution extends Entity {
/**
* Set the number of records skipped on read.
*
* @param readSkipCount A {@code long} containing the read skip count to be used for the step execution.
* @param readSkipCount A {@code long} containing the read skip count to be used for
* the step execution.
*/
public void setReadSkipCount(long readSkipCount) {
this.readSkipCount = readSkipCount;
@@ -460,8 +430,8 @@ public class StepExecution extends Entity {
/**
* Set the number of records skipped on write.
*
* @param writeSkipCount A {@code long} containing write skip count to be used for the step execution.
* @param writeSkipCount A {@code long} containing write skip count to be used for the
* step execution.
*/
public void setWriteSkipCount(long writeSkipCount) {
this.writeSkipCount = writeSkipCount;
@@ -476,8 +446,8 @@ public class StepExecution extends Entity {
/**
* Sets the number of records skipped during processing.
*
* @param processSkipCount A {@code long} containing the process skip count to be used for the step execution.
* @param processSkipCount A {@code long} containing the process skip count to be used
* for the step execution.
*/
public void setProcessSkipCount(long processSkipCount) {
this.processSkipCount = processSkipCount;
@@ -493,9 +463,8 @@ public class StepExecution extends Entity {
/**
* Sets the time when the {@code StepExecution} was last updated before persisting.
*
* @param lastUpdated the {@link Date} instance used to establish the last
* updated date for the {@code StepExecution}.
* @param lastUpdated the {@link Date} instance used to establish the last updated
* date for the {@code StepExecution}.
*/
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
@@ -510,7 +479,6 @@ public class StepExecution extends Entity {
/**
* Add a {@link Throwable} to failure exceptions.
*
* @param throwable The {@link Throwable} to add to failure exceptions.
*/
public void addFailureException(Throwable throwable) {
@@ -520,8 +488,7 @@ public class StepExecution extends Entity {
/*
* (non-Javadoc)
*
* @see
* org.springframework.batch.container.common.domain.Entity#equals(java.
* @see org.springframework.batch.container.common.domain.Entity#equals(java.
* lang.Object)
*/
@Override
@@ -538,11 +505,8 @@ public class StepExecution extends Entity {
}
/**
* Deserialize and ensure transient fields are re-instantiated when read
* back.
*
* Deserialize and ensure transient fields are re-instantiated when read back.
* @param stream An instance of {@link ObjectInputStream}.
*
* @throws IOException If an error occurs during read.
* @throws ClassNotFoundException If the class is not found.
*/
@@ -560,8 +524,8 @@ public class StepExecution extends Entity {
public int hashCode() {
Object jobExecutionId = getJobExecutionId();
Long id = getId();
return super.hashCode() + 31 * (stepName != null ? stepName.hashCode() : 0) + 91
* (jobExecutionId != null ? jobExecutionId.hashCode() : 0) + 59 * (id != null ? id.hashCode() : 0);
return super.hashCode() + 31 * (stepName != null ? stepName.hashCode() : 0)
+ 91 * (jobExecutionId != null ? jobExecutionId.hashCode() : 0) + 59 * (id != null ? id.hashCode() : 0);
}
@Override
@@ -570,15 +534,14 @@ public class StepExecution extends Entity {
}
/**
* @return The {@link String} containing a summary of the step execution.
* @return The {@link String} containing a summary of the step execution.
*/
public String getSummary() {
return super.toString()
+ String.format(
", name=%s, status=%s, exitStatus=%s, readCount=%d, filterCount=%d, writeCount=%d readSkipCount=%d, writeSkipCount=%d"
+ ", processSkipCount=%d, commitCount=%d, rollbackCount=%d", stepName, status,
exitStatus.getExitCode(), readCount, filterCount, writeCount, readSkipCount, writeSkipCount,
processSkipCount, commitCount, rollbackCount);
return super.toString() + String.format(
", name=%s, status=%s, exitStatus=%s, readCount=%d, filterCount=%d, writeCount=%d readSkipCount=%d, writeSkipCount=%d"
+ ", processSkipCount=%d, commitCount=%d, rollbackCount=%d",
stepName, status, exitStatus.getExitCode(), readCount, filterCount, writeCount, readSkipCount,
writeSkipCount, processSkipCount, commitCount, rollbackCount);
}
}

View File

@@ -28,29 +28,27 @@ import org.springframework.lang.Nullable;
public interface StepExecutionListener extends StepListener {
/**
* Initialize the state of the listener with the {@link StepExecution} from
* the current scope.
*
* Initialize the state of the listener with the {@link StepExecution} from the
* current scope.
* @param stepExecution instance of {@link StepExecution}.
*/
default void beforeStep(StepExecution stepExecution) {
}
/**
* Give a listener a chance to modify the exit status from a step. The value
* returned is combined with the normal exit status by using
* Give a listener a chance to modify the exit status from a step. The value returned
* is combined with the normal exit status by using
* {@link ExitStatus#and(ExitStatus)}.
*
* Called after execution of the step's processing logic (whether successful or
* failed). Throwing an exception in this method has no effect, as it is only
* logged.
*
* failed). Throwing an exception in this method has no effect, as it is only logged.
* @param stepExecution a {@link StepExecution} instance.
* @return an {@link ExitStatus} to combine with the normal value. Return
* {@code null} (the default) to leave the old value unchanged.
* @return an {@link ExitStatus} to combine with the normal value. Return {@code null}
* (the default) to leave the old value unchanged.
*/
@Nullable
default ExitStatus afterStep(StepExecution stepExecution) {
return null;
}
}

View File

@@ -16,9 +16,8 @@
package org.springframework.batch.core;
/**
* Marker interface that acts as a parent to all step
* domain listeners, such as: {@link StepExecutionListener},
* {@link ChunkListener}, {@link ItemReadListener}, and
* Marker interface that acts as a parent to all step domain listeners, such as:
* {@link StepExecutionListener}, {@link ChunkListener}, {@link ItemReadListener}, and
* {@link ItemWriteListener}
*
* @author Lucas Ward

View File

@@ -17,18 +17,18 @@
package org.springframework.batch.core;
/**
* Indicates to the framework that a critical error has occurred and processing
* should immediately stop.
* Indicates to the framework that a critical error has occurred and processing should
* immediately stop.
*
* @author Lucas Ward
*
*/
public class UnexpectedJobExecutionException extends RuntimeException {
private static final long serialVersionUID = 8838982304219248527L;
/**
* Constructs a new instance with a message.
*
* @param msg The exception message.
*
*/
@@ -38,7 +38,6 @@ public class UnexpectedJobExecutionException extends RuntimeException {
/**
* Constructs a new instance with a message.
*
* @param msg The exception message.
* @param nested An instance of {@link Throwable} that is the cause of the exception.
*

View File

@@ -33,7 +33,7 @@ import java.lang.annotation.Target;
* @see ChunkListener#afterChunk(ChunkContext context)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface AfterChunk {
}

View File

@@ -24,8 +24,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks a method to be called after a chunk has failed and been
* marked for rollback.<br>
* Marks a method to be called after a chunk has failed and been marked for rollback.<br>
* <br>
* Expected signature: void afterFailedChunk(ChunkContext context)
*
@@ -34,7 +33,7 @@ import java.lang.annotation.Target;
* @see ChunkListener#afterChunkError(ChunkContext context)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface AfterChunkError {
}

View File

@@ -26,8 +26,8 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
/**
* Marks a method to be called after a {@link Job} has completed. Annotated
* methods are called regardless of the status of the {@link JobExecution}. <br>
* Marks a method to be called after a {@link Job} has completed. Annotated methods are
* called regardless of the status of the {@link JobExecution}. <br>
* <br>
* Expected signature: void afterJob({@link JobExecution} jobExecution)
*
@@ -36,7 +36,7 @@ import org.springframework.batch.core.JobExecutionListener;
* @see JobExecutionListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface AfterJob {
}

View File

@@ -25,10 +25,9 @@ import org.springframework.batch.core.ItemProcessListener;
import org.springframework.batch.item.ItemProcessor;
/**
* Marks a method to be called after an item is passed to an
* {@link ItemProcessor}. {@code item} is the input item.
* {@code result} is the processed item. {@code result} can be null
* if the {@code item} is filtered.<br>
* Marks a method to be called after an item is passed to an {@link ItemProcessor}.
* {@code item} is the input item. {@code result} is the processed item. {@code result}
* can be null if the {@code item} is filtered.<br>
* <br>
* Expected signature: void afterProcess(T item, S result)
*
@@ -37,7 +36,7 @@ import org.springframework.batch.item.ItemProcessor;
* @see ItemProcessListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface AfterProcess {
}

View File

@@ -27,13 +27,13 @@ import org.springframework.batch.item.ItemReader;
* Marks a method to be called after an item is read from an {@link ItemReader} <br>
* <br>
* Expected signature: void afterRead(T item)
*
*
* @author Lucas Ward
* @since 2.0
* @see ItemReadListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface AfterRead {
}

View File

@@ -27,18 +27,17 @@ import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
/**
* Marks a method to be called after a {@link Step} has completed. Annotated
* methods are called regardless of the status of the {@link StepExecution}. <br>
* Marks a method to be called after a {@link Step} has completed. Annotated methods are
* called regardless of the status of the {@link StepExecution}. <br>
* <br>
* Expected signature: {@link ExitStatus} afterStep({@link StepExecution}
* stepExecution);
* Expected signature: {@link ExitStatus} afterStep({@link StepExecution} stepExecution);
*
* @author Lucas Ward
* @since 2.0
* @see StepExecutionListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface AfterStep {
}

View File

@@ -26,9 +26,9 @@ import org.springframework.batch.core.ItemWriteListener;
import org.springframework.batch.item.ItemWriter;
/**
* Marks a method to be called after an item is passed to an {@link ItemWriter}.
* Note that this annotation takes a {@link List} because Spring Batch
* generally processes a group of items (for the sake of efficiency).<br>
* Marks a method to be called after an item is passed to an {@link ItemWriter}. Note that
* this annotation takes a {@link List} because Spring Batch generally processes a group
* of items (for the sake of efficiency).<br>
* <br>
* Expected signature: void afterWrite({@link List}&lt;? extends S&gt; items)
*
@@ -37,7 +37,7 @@ import org.springframework.batch.item.ItemWriter;
* @see ItemWriteListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface AfterWrite {
}

View File

@@ -33,7 +33,7 @@ import org.springframework.batch.core.scope.context.ChunkContext;
* @see ChunkListener#beforeChunk(ChunkContext context)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface BeforeChunk {
}

View File

@@ -28,9 +28,9 @@ import org.springframework.batch.core.Step;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* Marks a method to be called before a {@link Job} is executed, which comes
* after a {@link JobExecution} is created and persisted but before the first
* {@link Step} is executed. <br>
* Marks a method to be called before a {@link Job} is executed, which comes after a
* {@link JobExecution} is created and persisted but before the first {@link Step} is
* executed. <br>
* <br>
* Expected signature: void beforeJob({@link JobExecution} jobExecution)
*
@@ -39,7 +39,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
* @see JobExecutionListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
@Qualifier("JobExecutionListener")
public @interface BeforeJob {

View File

@@ -24,17 +24,16 @@ import org.springframework.batch.core.ItemProcessListener;
import org.springframework.batch.item.ItemProcessor;
/**
* Marks a method to be called before an item is passed to an
* {@link ItemProcessor} <br>
* Marks a method to be called before an item is passed to an {@link ItemProcessor} <br>
* <br>
* Expected signature: void beforeProcess(T item)
*
*
* @author Lucas Ward
* @since 2.0
* @see ItemProcessListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface BeforeProcess {
}

View File

@@ -27,13 +27,13 @@ import org.springframework.batch.item.ItemReader;
* Marks a method to be called before an item is read from an {@link ItemReader} <br>
* <br>
* Expected signature: void beforeRead()
*
*
* @author Lucas Ward
* @since 2.0
* @see ItemReadListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface BeforeRead {
}

View File

@@ -26,9 +26,8 @@ import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
/**
* Marks a method to be called before a {@link Step} is executed, which comes
* after a {@link StepExecution} is created and persisted but before the first
* item is read. <br>
* Marks a method to be called before a {@link Step} is executed, which comes after a
* {@link StepExecution} is created and persisted but before the first item is read. <br>
* <br>
* Expected signature: void beforeStep({@link StepExecution} stepExecution)
*
@@ -37,7 +36,7 @@ import org.springframework.batch.core.StepExecutionListener;
* @see StepExecutionListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface BeforeStep {
}

View File

@@ -35,7 +35,7 @@ import org.springframework.batch.item.ItemWriter;
* @see ItemWriteListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface BeforeWrite {
}

View File

@@ -25,8 +25,7 @@ import org.springframework.batch.core.ItemProcessListener;
import org.springframework.batch.item.ItemProcessor;
/**
* Marks a method to be called if an exception is thrown by an
* {@link ItemProcessor}. <br>
* Marks a method to be called if an exception is thrown by an {@link ItemProcessor}. <br>
* <br>
* Expected signature: void onProcessError(T item, {@link Exception} e)
*
@@ -35,7 +34,7 @@ import org.springframework.batch.item.ItemProcessor;
* @see ItemProcessListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface OnProcessError {
}

View File

@@ -24,8 +24,7 @@ import org.springframework.batch.core.ItemReadListener;
import org.springframework.batch.item.ItemReader;
/**
* Marks a method to be called if an exception is thrown by an
* {@link ItemReader}. <br>
* Marks a method to be called if an exception is thrown by an {@link ItemReader}. <br>
* <br>
* Expected signature: void onReadError({@link Exception} ex)
*
@@ -34,7 +33,7 @@ import org.springframework.batch.item.ItemReader;
* @see ItemReadListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface OnReadError {
}

View File

@@ -25,8 +25,8 @@ import org.springframework.batch.core.SkipListener;
import org.springframework.batch.item.ItemProcessor;
/**
* Marks a method to be called when an item is skipped due to an exception
* thrown in the {@link ItemProcessor}.<br>
* Marks a method to be called when an item is skipped due to an exception thrown in the
* {@link ItemProcessor}.<br>
* <br>
* Expected signature: void onSkipInProcess(T item, {@link Throwable} t)
*
@@ -35,7 +35,7 @@ import org.springframework.batch.item.ItemProcessor;
* @see SkipListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface OnSkipInProcess {
}

View File

@@ -25,8 +25,8 @@ import org.springframework.batch.core.SkipListener;
import org.springframework.batch.item.ItemReader;
/**
* Marks a method to be called when an item is skipped due to an exception
* thrown in the {@link ItemReader}. <br>
* Marks a method to be called when an item is skipped due to an exception thrown in the
* {@link ItemReader}. <br>
* <br>
* Expected signature: void onSkipInRead({@link Throwable} t)
*
@@ -35,7 +35,7 @@ import org.springframework.batch.item.ItemReader;
* @see SkipListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface OnSkipInRead {
}

View File

@@ -25,17 +25,17 @@ import org.springframework.batch.core.SkipListener;
import org.springframework.batch.item.ItemWriter;
/**
* Marks a method to be called when an item is skipped due to an exception
* thrown in the {@link ItemWriter}.<br>
* Marks a method to be called when an item is skipped due to an exception thrown in the
* {@link ItemWriter}.<br>
* <br>
* Expected signature: void onSkipInWrite(S item, {@link Throwable} t)
*
*
* @author Lucas Ward
* @since 2.0
* @see SkipListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface OnSkipInWrite {
}

View File

@@ -26,20 +26,19 @@ import org.springframework.batch.core.ItemWriteListener;
import org.springframework.batch.item.ItemWriter;
/**
* Marks a method to be called if an exception is thrown by an
* {@link ItemWriter}. Note that this annotation takes a {@link List}
* because Spring Batch generally processes a group of items
* (for the sake of efficiency).<br>
* Marks a method to be called if an exception is thrown by an {@link ItemWriter}. Note
* that this annotation takes a {@link List} because Spring Batch generally processes a
* group of items (for the sake of efficiency).<br>
* <br>
* Expected signature: void onWriteError({@link Exception} exception,
* {@link List}&lt;? extends S&gt; items)
* Expected signature: void onWriteError({@link Exception} exception, {@link List}&lt;?
* extends S&gt; items)
*
* @author Lucas Ward
* @since 2.0
* @see ItemWriteListener
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Target({ ElementType.METHOD })
public @interface OnWriteError {
}

View File

@@ -16,9 +16,9 @@
package org.springframework.batch.core.configuration;
/**
* Represents an error has occurred in the configuration of base batch
* infrastructure (creation of a {@link org.springframework.batch.core.repository.JobRepository}
* for example.
* Represents an error has occurred in the configuration of base batch infrastructure
* (creation of a {@link org.springframework.batch.core.repository.JobRepository} for
* example.
*
* @author Michael Minella
* @author Mahmoud Ben Hassine
@@ -34,4 +34,5 @@ public class BatchConfigurationException extends RuntimeException {
public BatchConfigurationException(Throwable t) {
super(t);
}
}

View File

@@ -19,18 +19,16 @@ import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionException;
/**
* Checked exception that indicates a name clash when registering
* {@link Job} instances.
*
* Checked exception that indicates a name clash when registering {@link Job} instances.
*
* @author Dave Syer
*
*
*/
@SuppressWarnings("serial")
public class DuplicateJobException extends JobExecutionException {
/**
* Create an exception with the given message.
*
* @param msg error message.
*/
public DuplicateJobException(String msg) {

View File

@@ -19,7 +19,7 @@ import org.springframework.batch.core.Job;
/**
* Strategy for creating a single job.
*
*
* @author Dave Syer
*
*/
@@ -27,7 +27,6 @@ public interface JobFactory {
/**
* Create a new instance of {@link Job}.
*
* @return The {@link Job}.
*/
Job createJob();

View File

@@ -22,22 +22,19 @@ import org.springframework.lang.Nullable;
/**
* A runtime service locator interface for retrieving job configurations by
* <code>name</code>.
*
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
*
*/
public interface JobLocator {
/**
* Locates a {@link Job} at runtime.
*
* @param name the name of the {@link Job} which should be
* unique
* @param name the name of the {@link Job} which should be unique
* @return a {@link Job} identified by the given name
*
* @throws NoSuchJobException if the required configuration can
* not be found.
* @throws NoSuchJobException if the required configuration can not be found.
*/
Job getJob(@Nullable String name) throws NoSuchJobException;
}

View File

@@ -20,27 +20,25 @@ import org.springframework.batch.core.Job;
/**
* A runtime service registry interface for registering job configurations by
* <code>name</code>.
*
*
* @author Dave Syer
*
*
*/
public interface JobRegistry extends ListableJobLocator {
/**
* Registers a {@link Job} at runtime.
*
* @param jobFactory the {@link Job} to be registered
*
* @throws DuplicateJobException if a factory with the same job name has
* already been registered.
* @throws DuplicateJobException if a factory with the same job name has already been
* registered.
*/
void register(JobFactory jobFactory) throws DuplicateJobException;
/**
* Unregisters a previously registered {@link Job}. If it was not
* previously registered there is no error.
*
* Unregisters a previously registered {@link Job}. If it was not previously
* registered there is no error.
* @param jobName the {@link Job} to unregister.
*/
void unregister(String jobName);
}

View File

@@ -19,17 +19,17 @@ import java.util.Collection;
/**
* A listable extension of {@link JobLocator}.
*
*
* @author Dave Syer
*
*
*/
public interface ListableJobLocator extends JobLocator {
/**
* Provides the currently registered job names. The return value is
* unmodifiable and disconnected from the underlying registry storage.
*
* Provides the currently registered job names. The return value is unmodifiable and
* disconnected from the underlying registry storage.
* @return a collection of String. Empty if none are registered.
*/
Collection<String> getJobNames();
}

View File

@@ -30,34 +30,32 @@ import java.util.Collection;
*/
public interface StepRegistry {
/**
* Registers all the step of the given job. If the job is already registered,
* the method {@link #unregisterStepsFromJob(String)} is called before registering
* the given steps.
*
* @param jobName the give job name
* @param steps the job steps
* @throws DuplicateJobException if a job with the same job name has already been registered.
*/
void register(String jobName, Collection<Step> steps) throws DuplicateJobException;
/**
* Registers all the step of the given job. If the job is already registered, the
* method {@link #unregisterStepsFromJob(String)} is called before registering the
* given steps.
* @param jobName the give job name
* @param steps the job steps
* @throws DuplicateJobException if a job with the same job name has already been
* registered.
*/
void register(String jobName, Collection<Step> steps) throws DuplicateJobException;
/**
* Unregisters all the steps of the given job. If the job is not registered,
* nothing happens.
*
* @param jobName the given job name
*/
void unregisterStepsFromJob(String jobName);
/**
* Unregisters all the steps of the given job. If the job is not registered, nothing
* happens.
* @param jobName the given job name
*/
void unregisterStepsFromJob(String jobName);
/**
* Returns the {@link Step} of the specified job based on its name.
*
* @param jobName the name of the job
* @param stepName the name of the step to retrieve
* @return the step with the given name belonging to the mentioned job
* @throws NoSuchJobException no such job with that name exists
* @throws NoSuchStepException no such step with that name for that job exists
*/
Step getStep(String jobName, String stepName) throws NoSuchJobException, NoSuchStepException;
/**
* Returns the {@link Step} of the specified job based on its name.
* @param jobName the name of the job
* @param stepName the name of the step to retrieve
* @return the step with the given name belonging to the mentioned job
* @throws NoSuchJobException no such job with that name exists
* @throws NoSuchStepException no such step with that name for that job exists
*/
Step getStep(String jobName, String stepName) throws NoSuchJobException, NoSuchStepException;
}

View File

@@ -40,9 +40,10 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;
/**
* Base {@code Configuration} class providing common structure for enabling and using Spring Batch.
* Customization is available by implementing the {@link BatchConfigurer} interface.
*
* Base {@code Configuration} class providing common structure for enabling and using
* Spring Batch. Customization is available by implementing the {@link BatchConfigurer}
* interface.
*
* @author Dave Syer
* @author Michael Minella
* @author Mahmoud Ben Hassine
@@ -64,7 +65,6 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial
/**
* Establish the {@link JobBuilderFactory} for the batch execution.
*
* @return The instance of the {@link JobBuilderFactory}.
* @throws Exception The {@link Exception} thrown if error occurs.
*/
@@ -75,7 +75,6 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial
/**
* Establish the {@link StepBuilderFactory} for the batch execution.
*
* @return The instance of the {@link StepBuilderFactory}.
* @throws Exception The {@link Exception} thrown if error occurs.
*/
@@ -86,7 +85,6 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial
/**
* Establish the {@link JobRepository} for the batch execution.
*
* @return The instance of the {@link JobRepository}.
* @throws Exception The {@link Exception} thrown if error occurs.
*/
@@ -95,7 +93,6 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial
/**
* Establish the {@link JobLauncher} for the batch execution.
*
* @return The instance of the {@link JobLauncher}.
* @throws Exception The {@link Exception} thrown if error occurs.
*/
@@ -104,7 +101,6 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial
/**
* Establish the {@link JobExplorer} for the batch execution.
*
* @return The instance of the {@link JobExplorer}.
* @throws Exception The {@link Exception} thrown if error occurs.
*/
@@ -113,7 +109,6 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial
/**
* Establish the {@link JobRegistry} for the batch execution.
*
* @return The instance of the {@link JobRegistry}.
* @throws Exception The {@link Exception} thrown if error occurs.
*/
@@ -124,7 +119,6 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial
/**
* Establish the {@link PlatformTransactionManager} for the batch execution.
*
* @return The instance of the {@link PlatformTransactionManager}.
* @throws Exception The {@link Exception} thrown if error occurs.
*/
@@ -132,8 +126,8 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
Map<String, Object> annotationAttributes =
importMetadata.getAnnotationAttributes(EnableBatchProcessing.class.getName(), false);
Map<String, Object> annotationAttributes = importMetadata
.getAnnotationAttributes(EnableBatchProcessing.class.getName(), false);
AnnotationAttributes enabled = AnnotationAttributes.fromMap(annotationAttributes);
String message = "@EnableBatchProcessing is not present on importing class " + importMetadata.getClassName();
Assert.notNull(enabled, message);
@@ -146,10 +140,12 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial
}
/**
* If a {@link BatchConfigurer} exists, return it. If the configurers list is empty, create a {@link DefaultBatchConfigurer}.
* If more than one configurer is present in the list, an {@link IllegalStateException} is thrown.
* If a {@link BatchConfigurer} exists, return it. If the configurers list is empty,
* create a {@link DefaultBatchConfigurer}. If more than one configurer is present in
* the list, an {@link IllegalStateException} is thrown.
* @param configurers The {@link Collection} of configurers to review.
* @return The {@link BatchConfigurer} that was in the configurers collection or the one created.
* @return The {@link BatchConfigurer} that was in the configurers collection or the
* one created.
*/
protected BatchConfigurer getConfigurer(Collection<BatchConfigurer> configurers) {
if (this.configurer != null) {
@@ -175,12 +171,14 @@ public abstract class AbstractBatchConfiguration implements ImportAware, Initial
DataSource dataSource;
try {
dataSource = this.context.getBean(DataSource.class);
} catch (NoUniqueBeanDefinitionException exception) {
}
catch (NoUniqueBeanDefinitionException exception) {
throw new IllegalStateException(
"Multiple data sources are defined in the application context and no primary candidate was found. " +
"To use the default BatchConfigurer, one of the data sources should be annotated with '@Primary'.",
"Multiple data sources are defined in the application context and no primary candidate was found. "
+ "To use the default BatchConfigurer, one of the data sources should be annotated with '@Primary'.",
exception);
} catch (NoSuchBeanDefinitionException exception) {
}
catch (NoSuchBeanDefinitionException exception) {
throw new IllegalStateException(
"To use the default BatchConfigurer, the application context must contain at least one data source.",
exception);

View File

@@ -21,9 +21,10 @@ import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
/**
* Base {@code Configuration} class providing common structure for enabling and using Spring Batch. Customization is
* available by implementing the {@link BatchConfigurer} interface.
*
* Base {@code Configuration} class providing common structure for enabling and using
* Spring Batch. Customization is available by implementing the {@link BatchConfigurer}
* interface.
*
* @author Dave Syer
* @since 2.2
* @see EnableBatchProcessing
@@ -33,8 +34,8 @@ public class BatchConfigurationSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<?> annotationType = EnableBatchProcessing.class;
AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(
annotationType.getName(), false));
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(annotationType.getName(), false));
Assert.notNull(attributes, String.format("@%s is not present on importing class '%s' as expected",
annotationType.getSimpleName(), importingClassMetadata.getClassName()));

View File

@@ -21,10 +21,11 @@ import org.springframework.batch.core.repository.JobRepository;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Strategy interface for users to provide as a factory for custom components needed by a Batch system.
*
* Strategy interface for users to provide as a factory for custom components needed by a
* Batch system.
*
* @author Dave Syer
*
*
*/
public interface BatchConfigurer {
@@ -51,4 +52,5 @@ public interface BatchConfigurer {
* @throws Exception The {@link Exception} thrown if an error occurs.
*/
JobExplorer getJobExplorer() throws Exception;
}

View File

@@ -37,15 +37,18 @@ import org.springframework.util.Assert;
public class DefaultBatchConfigurer implements BatchConfigurer {
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
private JobRepository jobRepository;
private JobLauncher jobLauncher;
private JobExplorer jobExplorer;
/**
* Create a new {@link DefaultBatchConfigurer} with the passed datasource. This constructor
* will configure a default {@link DataSourceTransactionManager}.
*
* Create a new {@link DefaultBatchConfigurer} with the passed datasource. This
* constructor will configure a default {@link DataSourceTransactionManager}.
* @param dataSource to use for the job repository and job explorer
*/
public DefaultBatchConfigurer(DataSource dataSource) {
@@ -53,7 +56,8 @@ public class DefaultBatchConfigurer implements BatchConfigurer {
}
/**
* Create a new {@link DefaultBatchConfigurer} with the passed datasource and transaction manager.
* Create a new {@link DefaultBatchConfigurer} with the passed datasource and
* transaction manager.
* @param dataSource to use for the job repository and job explorer
* @param transactionManager to use for the job repository
*/
@@ -66,7 +70,6 @@ public class DefaultBatchConfigurer implements BatchConfigurer {
/**
* Sets the dataSource.
*
* @param dataSource The data source to use. Must not be {@code null}.
*/
public void setDataSource(DataSource dataSource) {
@@ -81,7 +84,6 @@ public class DefaultBatchConfigurer implements BatchConfigurer {
return this.dataSource;
}
@Override
public JobRepository getJobRepository() {
return this.jobRepository;
@@ -103,7 +105,8 @@ public class DefaultBatchConfigurer implements BatchConfigurer {
}
/**
* Initialize the {@link DefaultBatchConfigurer} with the {@link JobRepository}, {@link JobExplorer}, and {@link JobLauncher}.
* Initialize the {@link DefaultBatchConfigurer} with the {@link JobRepository},
* {@link JobExplorer}, and {@link JobLauncher}.
*/
@PostConstruct
public void initialize() {
@@ -111,14 +114,16 @@ public class DefaultBatchConfigurer implements BatchConfigurer {
this.jobRepository = createJobRepository();
this.jobExplorer = createJobExplorer();
this.jobLauncher = createJobLauncher();
} catch (Exception e) {
}
catch (Exception e) {
throw new BatchConfigurationException(e);
}
}
/**
* @return An instance of {@link JobLauncher}.
* @throws Exception The {@link Exception} that is thrown if an error occurs while creating the {@link JobLauncher}.
* @throws Exception The {@link Exception} that is thrown if an error occurs while
* creating the {@link JobLauncher}.
*/
protected JobLauncher createJobLauncher() throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
@@ -129,7 +134,8 @@ public class DefaultBatchConfigurer implements BatchConfigurer {
/**
* @return An instance of {@link JobRepository}.
* @throws Exception The {@link Exception} that is thrown if an error occurs while creating the {@link JobRepository}.
* @throws Exception The {@link Exception} that is thrown if an error occurs while
* creating the {@link JobRepository}.
*/
protected JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
@@ -141,7 +147,8 @@ public class DefaultBatchConfigurer implements BatchConfigurer {
/**
* @return An instance of {@link JobExplorer}.
* @throws Exception The {@link Exception} that is thrown if an error occurs while creating the {@link JobExplorer}.
* @throws Exception The {@link Exception} that is thrown if an error occurs while
* creating the {@link JobExplorer}.
*/
protected JobExplorer createJobExplorer() throws Exception {
JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
@@ -149,4 +156,5 @@ public class DefaultBatchConfigurer implements BatchConfigurer {
jobExplorerFactoryBean.afterPropertiesSet();
return jobExplorerFactoryBean.getObject();
}
}

View File

@@ -33,8 +33,10 @@ import org.springframework.transaction.PlatformTransactionManager;
/**
* <p>
* Enable Spring Batch features and provide a base configuration for setting up batch jobs in an &#064;Configuration
* class, roughly equivalent to using the {@code <batch:*>} XML namespace.</p>
* Enable Spring Batch features and provide a base configuration for setting up batch jobs
* in an &#064;Configuration class, roughly equivalent to using the {@code <batch:*>} XML
* namespace.
* </p>
*
* <pre class="code">
* &#064;Configuration
@@ -62,8 +64,8 @@ import org.springframework.transaction.PlatformTransactionManager;
* }
* </pre>
*
* The user should provide a {@link DataSource} as a bean in the context, or else implement {@link BatchConfigurer} in
* the configuration class itself, e.g.
* The user should provide a {@link DataSource} as a bean in the context, or else
* implement {@link BatchConfigurer} in the configuration class itself, e.g.
*
* <pre class="code">
* &#064;Configuration
@@ -85,30 +87,41 @@ import org.springframework.transaction.PlatformTransactionManager;
* }
* </pre>
*
* If multiple {@link javax.sql.DataSource}s are defined in the context, the primary autowire candidate
* will be used, otherwise an exception will be thrown.
* If multiple {@link javax.sql.DataSource}s are defined in the context, the primary
* autowire candidate will be used, otherwise an exception will be thrown.
*
* Note that only one of your configuration classes needs to have the <code>&#064;EnableBatchProcessing</code>
* annotation. Once you have an <code>&#064;EnableBatchProcessing</code> class in your configuration you will have an
* instance of {@link StepScope} and {@link org.springframework.batch.core.scope.JobScope} so your beans inside steps
* can have <code>&#064;Scope("step")</code> and <code>&#064;Scope("job")</code> respectively. You will also be
* able to <code>&#064;Autowired</code> some useful stuff into your context:
* Note that only one of your configuration classes needs to have the
* <code>&#064;EnableBatchProcessing</code> annotation. Once you have an
* <code>&#064;EnableBatchProcessing</code> class in your configuration you will have an
* instance of {@link StepScope} and {@link org.springframework.batch.core.scope.JobScope}
* so your beans inside steps can have <code>&#064;Scope("step")</code> and
* <code>&#064;Scope("job")</code> respectively. You will also be able to
* <code>&#064;Autowired</code> some useful stuff into your context:
*
* <ul>
* <li>a {@link JobRepository} (bean name "jobRepository" of type {@link org.springframework.batch.core.repository.support.SimpleJobRepository})</li>
* <li>a {@link JobLauncher} (bean name "jobLauncher" of type {@link org.springframework.batch.core.launch.support.SimpleJobLauncher})</li>
* <li>a {@link JobRegistry} (bean name "jobRegistry" of type {@link org.springframework.batch.core.configuration.support.MapJobRegistry})</li>
* <li>a {@link org.springframework.batch.core.explore.JobExplorer} (bean name "jobExplorer" of type {@link org.springframework.batch.core.explore.support.SimpleJobExplorer})</li>
* <li>a {@link JobBuilderFactory} (bean name "jobBuilders") as a convenience to prevent you from having to inject the
* job repository into every job, as in the examples above</li>
* <li>a {@link StepBuilderFactory} (bean name "stepBuilders") as a convenience to prevent you from having to inject the
* job repository and transaction manager into every step</li>
* <li>a {@link JobRepository} (bean name "jobRepository" of type
* {@link org.springframework.batch.core.repository.support.SimpleJobRepository})</li>
* <li>a {@link JobLauncher} (bean name "jobLauncher" of type
* {@link org.springframework.batch.core.launch.support.SimpleJobLauncher})</li>
* <li>a {@link JobRegistry} (bean name "jobRegistry" of type
* {@link org.springframework.batch.core.configuration.support.MapJobRegistry})</li>
* <li>a {@link org.springframework.batch.core.explore.JobExplorer} (bean name
* "jobExplorer" of type
* {@link org.springframework.batch.core.explore.support.SimpleJobExplorer})</li>
* <li>a {@link JobBuilderFactory} (bean name "jobBuilders") as a convenience to prevent
* you from having to inject the job repository into every job, as in the examples
* above</li>
* <li>a {@link StepBuilderFactory} (bean name "stepBuilders") as a convenience to prevent
* you from having to inject the job repository and transaction manager into every
* step</li>
* </ul>
*
* The transaction manager provided by this annotation will be of type {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
* configured with the {@link javax.sql.DataSource} provided within the context.
* The transaction manager provided by this annotation will be of type
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager} configured
* with the {@link javax.sql.DataSource} provided within the context.
*
* In order to use a custom transaction manager, a custom {@link BatchConfigurer} should be provided. For example:
* In order to use a custom transaction manager, a custom {@link BatchConfigurer} should
* be provided. For example:
*
* <pre class="code">
* &#064;Configuration
@@ -130,11 +143,13 @@ import org.springframework.transaction.PlatformTransactionManager;
* }
* </pre>
*
* If the configuration is specified as <code>modular=true</code> then the context will also contain an
* {@link AutomaticJobRegistrar}. The job registrar is useful for modularizing your configuration if there are multiple
* jobs. It works by creating separate child application contexts containing job configurations and registering those
* jobs. The jobs can then create steps and other dependent components without needing to worry about bean definition
* name clashes. Beans of type {@link ApplicationContextFactory} will be registered automatically with the job
* If the configuration is specified as <code>modular=true</code> then the context will
* also contain an {@link AutomaticJobRegistrar}. The job registrar is useful for
* modularizing your configuration if there are multiple jobs. It works by creating
* separate child application contexts containing job configurations and registering those
* jobs. The jobs can then create steps and other dependent components without needing to
* worry about bean definition name clashes. Beans of type
* {@link ApplicationContextFactory} will be registered automatically with the job
* registrar. Example:
*
* <pre class="code">
@@ -157,12 +172,13 @@ import org.springframework.transaction.PlatformTransactionManager;
* }
* </pre>
*
* Note that a modular parent context in general should <em>not</em> itself contain &#64;Bean definitions for job,
* especially if a {@link BatchConfigurer} is provided, because cyclic configuration dependencies are otherwise likely
* to develop.
* Note that a modular parent context in general should <em>not</em> itself contain
* &#64;Bean definitions for job, especially if a {@link BatchConfigurer} is provided,
* because cyclic configuration dependencies are otherwise likely to develop.
*
* <p>
* For reference, the first example above can be compared to the following Spring XML configuration:
* For reference, the first example above can be compared to the following Spring XML
* configuration:
*
* <pre class="code">
* {@code
@@ -173,7 +189,8 @@ import org.springframework.transaction.PlatformTransactionManager;
* <step id="step2" .../>
* </job>
* <beans:bean id="transactionManager" .../>
* <beans:bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
* <beans:bean id="jobLauncher" class=
"org.springframework.batch.core.launch.support.SimpleJobLauncher">
* <beans:property name="jobRepository" ref="jobRepository" />
* </beans:bean>
* </batch>
@@ -191,12 +208,12 @@ import org.springframework.transaction.PlatformTransactionManager;
public @interface EnableBatchProcessing {
/**
* Indicate whether the configuration is going to be modularized into multiple application contexts. If true then
* you should not create any &#64;Bean Job definitions in this context, but rather supply them in separate (child)
* contexts through an {@link ApplicationContextFactory}.
*
* @return boolean indicating whether the configuration is going to be
* modularized into multiple application contexts. Defaults to false.
* Indicate whether the configuration is going to be modularized into multiple
* application contexts. If true then you should not create any &#64;Bean Job
* definitions in this context, but rather supply them in separate (child) contexts
* through an {@link ApplicationContextFactory}.
* @return boolean indicating whether the configuration is going to be modularized
* into multiple application contexts. Defaults to false.
*/
boolean modular() default false;

View File

@@ -19,11 +19,12 @@ import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
/**
* Convenient factory for a {@link JobBuilder} which sets the {@link JobRepository} automatically.
*
* Convenient factory for a {@link JobBuilder} which sets the {@link JobRepository}
* automatically.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
*
*/
public class JobBuilderFactory {
@@ -37,9 +38,9 @@ public class JobBuilderFactory {
}
/**
* Creates a job builder and initializes its job repository. Note that if the builder is used to create a &#64;Bean
* definition then the name of the job and the bean name might be different.
*
* Creates a job builder and initializes its job repository. Note that if the builder
* is used to create a &#64;Bean definition then the name of the job and the bean name
* might be different.
* @param name the name of the job
* @return a job builder
*/

View File

@@ -24,9 +24,10 @@ import java.lang.annotation.RetentionPolicy;
/**
* <p>
* Convenient annotation for job scoped beans that defaults the proxy mode, so that it doesn't have to be specified
* explicitly on every bean definition. Use this on any &#64;Bean that needs to inject &#64;Values from the job
* context, and any bean that needs to share a lifecycle with a job execution (e.g. an JobExecutionListener). E.g.
* Convenient annotation for job scoped beans that defaults the proxy mode, so that it
* doesn't have to be specified explicitly on every bean definition. Use this on any
* &#64;Bean that needs to inject &#64;Values from the job context, and any bean that
* needs to share a lifecycle with a job execution (e.g. an JobExecutionListener). E.g.
* </p>
*
* <pre class="code">
@@ -38,7 +39,10 @@ import java.lang.annotation.RetentionPolicy;
* }
* </pre>
*
* <p>Marking a &#64;Bean as &#64;JobScope is equivalent to marking it as <code>&#64;Scope(value="job", proxyMode=TARGET_CLASS)</code></p>
* <p>
* Marking a &#64;Bean as &#64;JobScope is equivalent to marking it as
* <code>&#64;Scope(value="job", proxyMode=TARGET_CLASS)</code>
* </p>
*
* @author Michael Minella
*

View File

@@ -30,8 +30,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Base {@code Configuration} class providing common structure for enabling and using Spring Batch.
* Customization is available by implementing the {@link BatchConfigurer} interface.
* Base {@code Configuration} class providing common structure for enabling and using
* Spring Batch. Customization is available by implementing the {@link BatchConfigurer}
* interface.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
@@ -45,7 +46,6 @@ public class ModularBatchConfiguration extends SimpleBatchConfiguration {
/**
* Creates a {@link AutomaticJobRegistrar} bean.
*
* @return New instance of {@link AutomaticJobRegistrar}.
* @throws Exception The {@link Exception} thrown if an error occurs.
*/

View File

@@ -55,4 +55,5 @@ public class ScopeConfiguration {
public static JobScope jobScope() {
return jobScope;
}
}

View File

@@ -35,8 +35,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Base {@code Configuration} class providing common structure for enabling and using Spring Batch.
* Customization is available by implementing the {@link BatchConfigurer} interface.
* Base {@code Configuration} class providing common structure for enabling and using
* Spring Batch. Customization is available by implementing the {@link BatchConfigurer}
* interface.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine

View File

@@ -22,10 +22,10 @@ import org.springframework.transaction.PlatformTransactionManager;
/**
* Convenient factory for a {@link StepBuilder} which sets the {@link JobRepository} and
* {@link PlatformTransactionManager} automatically.
*
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
*
*/
public class StepBuilderFactory {
@@ -35,9 +35,9 @@ public class StepBuilderFactory {
/**
* Constructor for the {@link StepBuilderFactory}.
*
* @param jobRepository The {@link JobRepository} to be used by the builder factory.
* @param transactionManager The {@link PlatformTransactionManager} to be used by the builder factory.
* @param transactionManager The {@link PlatformTransactionManager} to be used by the
* builder factory.
*/
public StepBuilderFactory(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
this.jobRepository = jobRepository;
@@ -45,16 +45,14 @@ public class StepBuilderFactory {
}
/**
* Creates a step builder and initializes its job repository and transaction manager. Note that if the builder is
* used to create a &#64;Bean definition then the name of the step and the bean name might be different.
*
* Creates a step builder and initializes its job repository and transaction manager.
* Note that if the builder is used to create a &#64;Bean definition then the name of
* the step and the bean name might be different.
* @param name the name of the step
* @return a step builder
*/
public StepBuilder get(String name) {
return new StepBuilder(name)
.repository(this.jobRepository)
.transactionManager(this.transactionManager);
return new StepBuilder(name).repository(this.jobRepository).transactionManager(this.transactionManager);
}
}

View File

@@ -24,9 +24,10 @@ import java.lang.annotation.RetentionPolicy;
/**
* <p>
* Convenient annotation for step scoped beans that defaults the proxy mode, so that it doesn't have to be specified
* explicitly on every bean definition. Use this on any &#64;Bean that needs to inject &#64;Values from the step
* context, and any bean that needs to share a lifecycle with a step execution (e.g. an ItemStream). E.g.
* Convenient annotation for step scoped beans that defaults the proxy mode, so that it
* doesn't have to be specified explicitly on every bean definition. Use this on any
* &#64;Bean that needs to inject &#64;Values from the step context, and any bean that
* needs to share a lifecycle with a step execution (e.g. an ItemStream). E.g.
* </p>
*
* <pre class="code">
@@ -38,7 +39,10 @@ import java.lang.annotation.RetentionPolicy;
* }
* </pre>
*
* <p>Marking a &#64;Bean as &#64;StepScope is equivalent to marking it as <code>&#64;Scope(value="step", proxyMode=TARGET_CLASS)</code></p>
* <p>
* Marking a &#64;Bean as &#64;StepScope is equivalent to marking it as
* <code>&#64;Scope(value="step", proxyMode=TARGET_CLASS)</code>
* </p>
*
* @author Dave Syer
*

View File

@@ -41,10 +41,12 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* {@link ApplicationContextFactory} implementation that takes a parent context and a path to the context to create.
* When createApplicationContext method is called, the child {@link ApplicationContext} will be returned. The child
* context is not re-created every time it is requested, it is lazily initialized and cached. Clients should ensure that
* it is closed when it is no longer needed. If a path is not set, the parent will always be returned.
* {@link ApplicationContextFactory} implementation that takes a parent context and a path
* to the context to create. When createApplicationContext method is called, the child
* {@link ApplicationContext} will be returned. The child context is not re-created every
* time it is requested, it is lazily initialized and cached. Clients should ensure that
* it is closed when it is no longer needed. If a path is not set, the parent will always
* be returned.
*
*/
public abstract class AbstractApplicationContextFactory implements ApplicationContextFactory, ApplicationContextAware {
@@ -62,9 +64,8 @@ public abstract class AbstractApplicationContextFactory implements ApplicationCo
private Collection<Class<?>> beanPostProcessorExcludeClasses;
/**
* Create a factory instance with the resource specified. The resources are Spring configuration files or java
* packages containing configuration files.
*
* Create a factory instance with the resource specified. The resources are Spring
* configuration files or java packages containing configuration files.
* @param resource resource to be used in the creation of the ApplicationContext.
*/
public AbstractApplicationContextFactory(Object... resource) {
@@ -75,17 +76,18 @@ public abstract class AbstractApplicationContextFactory implements ApplicationCo
beanFactoryPostProcessorClasses.add(CustomEditorConfigurer.class);
beanPostProcessorExcludeClasses = new ArrayList<>();
/*
* Assume that a BeanPostProcessor that is BeanFactoryAware must be specific to the parent and remove it from
* the child (e.g. an AutoProxyCreator will not work properly). Unfortunately there might still be a a
* BeanPostProcessor with a dependency that itself is BeanFactoryAware, but we can't legislate for that here.
* Assume that a BeanPostProcessor that is BeanFactoryAware must be specific to
* the parent and remove it from the child (e.g. an AutoProxyCreator will not work
* properly). Unfortunately there might still be a a BeanPostProcessor with a
* dependency that itself is BeanFactoryAware, but we can't legislate for that
* here.
*/
beanPostProcessorExcludeClasses.add(BeanFactoryAware.class);
}
/**
* Flag to indicate that configuration such as bean post processors and custom editors should be copied from the
* parent context. Defaults to true.
*
* Flag to indicate that configuration such as bean post processors and custom editors
* should be copied from the parent context. Defaults to true.
* @param copyConfiguration the flag value to set
*/
public void setCopyConfiguration(boolean copyConfiguration) {
@@ -93,9 +95,8 @@ public abstract class AbstractApplicationContextFactory implements ApplicationCo
}
/**
* Protected access for subclasses to the flag determining whether configuration should be copied from parent
* context.
*
* Protected access for subclasses to the flag determining whether configuration
* should be copied from parent context.
* @return the flag value
*/
protected final boolean isCopyConfiguration() {
@@ -103,9 +104,9 @@ public abstract class AbstractApplicationContextFactory implements ApplicationCo
}
/**
* Determines which bean factory post processors (like property placeholders) should be copied from the parent
* context. Defaults to {@link PropertySourcesPlaceholderConfigurer} and {@link CustomEditorConfigurer}.
*
* Determines which bean factory post processors (like property placeholders) should
* be copied from the parent context. Defaults to
* {@link PropertySourcesPlaceholderConfigurer} and {@link CustomEditorConfigurer}.
* @param beanFactoryPostProcessorClasses array of post processor types to be copied
*/
@@ -118,11 +119,11 @@ public abstract class AbstractApplicationContextFactory implements ApplicationCo
}
/**
* Determines by exclusion which bean post processors should be copied from the parent context. Defaults to
* {@link BeanFactoryAware} (so any post processors that have a reference to the parent bean factory are not copied
* into the child). Note that these classes do not themselves have to be {@link BeanPostProcessor} implementations
* or sub-interfaces.
*
* Determines by exclusion which bean post processors should be copied from the parent
* context. Defaults to {@link BeanFactoryAware} (so any post processors that have a
* reference to the parent bean factory are not copied into the child). Note that
* these classes do not themselves have to be {@link BeanPostProcessor}
* implementations or sub-interfaces.
* @param beanPostProcessorExcludeClasses the classes to set
*/
public void setBeanPostProcessorExcludeClasses(Class<?>[] beanPostProcessorExcludeClasses) {
@@ -134,9 +135,8 @@ public abstract class AbstractApplicationContextFactory implements ApplicationCo
}
/**
* Protected access to the list of bean factory post processor classes that should be copied over to the context
* from the parent.
*
* Protected access to the list of bean factory post processor classes that should be
* copied over to the context from the parent.
* @return the classes for post processors that were nominated for copying
*/
protected final Collection<Class<? extends BeanFactoryPostProcessor>> getBeanFactoryPostProcessorClasses() {
@@ -177,11 +177,11 @@ public abstract class AbstractApplicationContextFactory implements ApplicationCo
Object... resources);
/**
* Extension point for special subclasses that want to do more complex things with the context prior to refresh. The
* default implementation does nothing.
*
* Extension point for special subclasses that want to do more complex things with the
* context prior to refresh. The default implementation does nothing.
* @param parent the parent for the new application context
* @param context the new application context before it is refreshed, but after bean factory is initialized
* @param context the new application context before it is refreshed, but after bean
* factory is initialized
*
* @see AbstractApplicationContextFactory#setBeanFactoryPostProcessorClasses(Class[])
*/
@@ -189,10 +189,9 @@ public abstract class AbstractApplicationContextFactory implements ApplicationCo
}
/**
* Extension point for special subclasses that want to do more complex things with the bean factory prior to
* refresh. The default implementation copies all configuration from the parent according to the
* {@link #setCopyConfiguration(boolean) flag} set.
*
* Extension point for special subclasses that want to do more complex things with the
* bean factory prior to refresh. The default implementation copies all configuration
* from the parent according to the {@link #setCopyConfiguration(boolean) flag} set.
* @param parent the parent bean factory for the new context (will never be null)
* @param beanFactory the new bean factory before bean definitions are loaded
*
@@ -205,15 +204,15 @@ public abstract class AbstractApplicationContextFactory implements ApplicationCo
List<BeanPostProcessor> parentPostProcessors = new ArrayList<>();
List<BeanPostProcessor> childPostProcessors = new ArrayList<>();
childPostProcessors.addAll(beanFactory instanceof AbstractBeanFactory ? ((AbstractBeanFactory) beanFactory)
.getBeanPostProcessors() : new ArrayList<>());
parentPostProcessors.addAll(parent instanceof AbstractBeanFactory ? ((AbstractBeanFactory) parent)
.getBeanPostProcessors() : new ArrayList<>());
childPostProcessors.addAll(beanFactory instanceof AbstractBeanFactory
? ((AbstractBeanFactory) beanFactory).getBeanPostProcessors() : new ArrayList<>());
parentPostProcessors.addAll(parent instanceof AbstractBeanFactory
? ((AbstractBeanFactory) parent).getBeanPostProcessors() : new ArrayList<>());
try {
Class<?> applicationContextAwareProcessorClass =
ClassUtils.forName("org.springframework.context.support.ApplicationContextAwareProcessor",
parent.getBeanClassLoader());
Class<?> applicationContextAwareProcessorClass = ClassUtils.forName(
"org.springframework.context.support.ApplicationContextAwareProcessor",
parent.getBeanClassLoader());
for (BeanPostProcessor beanPostProcessor : new ArrayList<>(parentPostProcessors)) {
if (applicationContextAwareProcessorClass.isAssignableFrom(beanPostProcessor.getClass())) {
@@ -243,8 +242,8 @@ public abstract class AbstractApplicationContextFactory implements ApplicationCo
beanFactory.copyConfigurationFrom(parent);
List<BeanPostProcessor> beanPostProcessors = beanFactory instanceof AbstractBeanFactory ? ((AbstractBeanFactory) beanFactory)
.getBeanPostProcessors() : new ArrayList<>();
List<BeanPostProcessor> beanPostProcessors = beanFactory instanceof AbstractBeanFactory
? ((AbstractBeanFactory) beanFactory).getBeanPostProcessors() : new ArrayList<>();
beanPostProcessors.clear();
beanPostProcessors.addAll(aggregatedPostProcessors);

View File

@@ -21,14 +21,13 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Factory for the creation of {@link ApplicationContext}s. This interface
* is primarily useful when creating a new {@link ApplicationContext} per
* execution of a {@link Job}.
*
* Factory for the creation of {@link ApplicationContext}s. This interface is primarily
* useful when creating a new {@link ApplicationContext} per execution of a {@link Job}.
*
* @author Lucas Ward
*/
public interface ApplicationContextFactory {
ConfigurableApplicationContext createApplicationContext();
}

View File

@@ -21,8 +21,8 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
/**
* A {@link JobFactory} that creates its own {@link ApplicationContext} and
* pulls a bean out when asked to create a {@link Job}.
* A {@link JobFactory} that creates its own {@link ApplicationContext} and pulls a bean
* out when asked to create a {@link Job}.
*
* @author Dave Syer
*
@@ -32,10 +32,9 @@ public class ApplicationContextJobFactory implements JobFactory {
private final Job job;
/**
* @param jobName the id of the {@link Job} in the application context to be
* created
* @param applicationContextFactory a factory for an application context
* containing a job with the job name provided
* @param jobName the id of the {@link Job} in the application context to be created
* @param applicationContextFactory a factory for an application context containing a
* job with the job name provided
*/
public ApplicationContextJobFactory(String jobName, ApplicationContextFactory applicationContextFactory) {
@SuppressWarnings("resource")
@@ -44,8 +43,8 @@ public class ApplicationContextJobFactory implements JobFactory {
}
/**
* Create an {@link ApplicationContext} from the factory provided and pull
* out a bean with the name given during initialization.
* Create an {@link ApplicationContext} from the factory provided and pull out a bean
* with the name given during initialization.
*
* @see org.springframework.batch.core.configuration.JobFactory#createJob()
*/

View File

@@ -32,18 +32,17 @@ import org.springframework.core.Ordered;
import org.springframework.util.Assert;
/**
* Loads and unloads {@link Job Jobs} when the application context is created and destroyed. Each resource provided is
* loaded as an application context with the current context as its parent, and then all the jobs from the child context
* are registered under their bean names. A {@link JobRegistry} is required.
* Loads and unloads {@link Job Jobs} when the application context is created and
* destroyed. Each resource provided is loaded as an application context with the current
* context as its parent, and then all the jobs from the child context are registered
* under their bean names. A {@link JobRegistry} is required.
*
* @author Lucas Ward
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
* @since 2.1
*/
public class AutomaticJobRegistrar implements Ordered, SmartLifecycle, ApplicationContextAware,
InitializingBean {
public class AutomaticJobRegistrar implements Ordered, SmartLifecycle, ApplicationContextAware, InitializingBean {
private Collection<ApplicationContextFactory> applicationContextFactories = new ArrayList<>();
@@ -62,9 +61,8 @@ public class AutomaticJobRegistrar implements Ordered, SmartLifecycle, Applicati
private int order = Ordered.LOWEST_PRECEDENCE;
/**
* The enclosing application context, which can be used to check if {@link ApplicationContextEvent events} come
* from the expected source.
*
* The enclosing application context, which can be used to check if
* {@link ApplicationContextEvent events} come from the expected source.
* @param applicationContext the enclosing application context if there is one
* @see ApplicationContextAware#setApplicationContext(ApplicationContext)
*/
@@ -75,8 +73,8 @@ public class AutomaticJobRegistrar implements Ordered, SmartLifecycle, Applicati
/**
* Add some factories to the set that will be used to load contexts and jobs.
*
* @param applicationContextFactory the {@link ApplicationContextFactory} values to use
* @param applicationContextFactory the {@link ApplicationContextFactory} values to
* use
*/
public void addApplicationContextFactory(ApplicationContextFactory applicationContextFactory) {
if (applicationContextFactory instanceof ApplicationContextAware) {
@@ -87,8 +85,8 @@ public class AutomaticJobRegistrar implements Ordered, SmartLifecycle, Applicati
/**
* Add some factories to the set that will be used to load contexts and jobs.
*
* @param applicationContextFactories the {@link ApplicationContextFactory} values to use
* @param applicationContextFactories the {@link ApplicationContextFactory} values to
* use
*/
public void setApplicationContextFactories(ApplicationContextFactory[] applicationContextFactories) {
for (ApplicationContextFactory applicationContextFactory : applicationContextFactories) {
@@ -98,7 +96,6 @@ public class AutomaticJobRegistrar implements Ordered, SmartLifecycle, Applicati
/**
* The job loader that will be used to load and manage jobs.
*
* @param jobLoader the {@link JobLoader} to set
*/
public void setJobLoader(JobLoader jobLoader) {
@@ -142,7 +139,8 @@ public class AutomaticJobRegistrar implements Ordered, SmartLifecycle, Applicati
}
/**
* Take all the contexts from the factories provided and pass them to the {@link JobLoader}.
* Take all the contexts from the factories provided and pass them to the
* {@link JobLoader}.
*
* @see Lifecycle#start()
*/
@@ -166,7 +164,6 @@ public class AutomaticJobRegistrar implements Ordered, SmartLifecycle, Applicati
/**
* Check if this component has been started.
*
* @return true if started successfully and not stopped
* @see Lifecycle#isRunning()
*/

View File

@@ -30,14 +30,15 @@ import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.Resource;
/**
* A convenient factory for creating a set of {@link ApplicationContextFactory}
* components from a set of {@link Resource resources}.
* A convenient factory for creating a set of {@link ApplicationContextFactory} components
* from a set of {@link Resource resources}.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
*/
public class ClasspathXmlApplicationContextsFactoryBean implements FactoryBean<ApplicationContextFactory[]>, ApplicationContextAware {
public class ClasspathXmlApplicationContextsFactoryBean
implements FactoryBean<ApplicationContextFactory[]>, ApplicationContextAware {
private List<Resource> resources = new ArrayList<>();
@@ -50,13 +51,10 @@ public class ClasspathXmlApplicationContextsFactoryBean implements FactoryBean<A
private ApplicationContext applicationContext;
/**
* A set of resources to load using a
* {@link GenericApplicationContextFactory}. Each resource should be a
* Spring configuration file which is loaded into an application context
* whose parent is the current context. In a configuration file the
* resources can be given as a pattern (e.g.
* <code>classpath*:/config/*-context.xml</code>).
*
* A set of resources to load using a {@link GenericApplicationContextFactory}. Each
* resource should be a Spring configuration file which is loaded into an application
* context whose parent is the current context. In a configuration file the resources
* can be given as a pattern (e.g. <code>classpath*:/config/*-context.xml</code>).
* @param resources array of resources to use
*/
public void setResources(Resource[] resources) {
@@ -64,10 +62,8 @@ public class ClasspathXmlApplicationContextsFactoryBean implements FactoryBean<A
}
/**
* Flag to indicate that configuration such as bean post processors and
* custom editors should be copied from the parent context. Defaults to
* true.
*
* Flag to indicate that configuration such as bean post processors and custom editors
* should be copied from the parent context. Defaults to true.
* @param copyConfiguration the flag value to set
*/
public void setCopyConfiguration(boolean copyConfiguration) {
@@ -75,10 +71,9 @@ public class ClasspathXmlApplicationContextsFactoryBean implements FactoryBean<A
}
/**
* Determines which bean factory post processors (like property
* placeholders) should be copied from the parent context. Defaults to
* Determines which bean factory post processors (like property placeholders) should
* be copied from the parent context. Defaults to
* {@link PropertySourcesPlaceholderConfigurer} and {@link CustomEditorConfigurer}.
*
* @param beanFactoryPostProcessorClasses post processor types to be copied
*/
@@ -88,12 +83,11 @@ public class ClasspathXmlApplicationContextsFactoryBean implements FactoryBean<A
}
/**
* Determines by exclusion which bean post processors should be copied from
* the parent context. Defaults to {@link BeanFactoryAware} (so any post
* processors that have a reference to the parent bean factory are not
* copied into the child). Note that these classes do not themselves have to
* be {@link BeanPostProcessor} implementations or sub-interfaces.
*
* Determines by exclusion which bean post processors should be copied from the parent
* context. Defaults to {@link BeanFactoryAware} (so any post processors that have a
* reference to the parent bean factory are not copied into the child). Note that
* these classes do not themselves have to be {@link BeanPostProcessor}
* implementations or sub-interfaces.
* @param beanPostProcessorExcludeClasses the classes to set
*/
public void setBeanPostProcessorExcludeClasses(Class<?>[] beanPostProcessorExcludeClasses) {
@@ -101,9 +95,8 @@ public class ClasspathXmlApplicationContextsFactoryBean implements FactoryBean<A
}
/**
* Create an {@link ApplicationContextFactory} from each resource provided
* in {@link #setResources(Resource[])}.
*
* Create an {@link ApplicationContextFactory} from each resource provided in
* {@link #setResources(Resource[])}.
* @return an array of {@link ApplicationContextFactory}
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
@@ -133,7 +126,6 @@ public class ClasspathXmlApplicationContextsFactoryBean implements FactoryBean<A
/**
* The type of object returned by this factory - an array of
* {@link ApplicationContextFactory}.
*
* @return array of {@link ApplicationContextFactory}
* @see FactoryBean#getObjectType()
*/
@@ -153,9 +145,7 @@ public class ClasspathXmlApplicationContextsFactoryBean implements FactoryBean<A
}
/**
* An application context that can be used as a parent context for all the
* factories.
*
* An application context that can be used as a parent context for all the factories.
* @param applicationContext the {@link ApplicationContext} to set
* @see ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/

View File

@@ -39,10 +39,10 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Default implementation of {@link JobLoader}. Uses a {@link JobRegistry} to
* manage a population of loaded jobs and clears them up when asked. An optional
* {@link StepRegistry} might also be set to register the step(s) available for
* each registered job.
* Default implementation of {@link JobLoader}. Uses a {@link JobRegistry} to manage a
* population of loaded jobs and clears them up when asked. An optional
* {@link StepRegistry} might also be set to register the step(s) available for each
* registered job.
*
* @author Dave Syer
* @author Stephane Nicoll
@@ -53,6 +53,7 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
private static Log logger = LogFactory.getLog(DefaultJobLoader.class);
private JobRegistry jobRegistry;
private StepRegistry stepRegistry;
private Map<ApplicationContextFactory, ConfigurableApplicationContext> contexts = new ConcurrentHashMap<>();
@@ -68,7 +69,6 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
/**
* Creates a job loader with the job registry provided.
*
* @param jobRegistry a {@link JobRegistry}
*/
public DefaultJobLoader(JobRegistry jobRegistry) {
@@ -77,7 +77,6 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
/**
* Creates a job loader with the job and step registries provided.
*
* @param jobRegistry a {@link JobRegistry}
* @param stepRegistry a {@link StepRegistry} (can be {@code null})
*/
@@ -88,7 +87,6 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
/**
* The {@link JobRegistry} to use for jobs created.
*
* @param jobRegistry the job registry
*/
public void setJobRegistry(JobRegistry jobRegistry) {
@@ -97,7 +95,6 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
/**
* The {@link StepRegistry} to use for the steps of created jobs.
*
* @param stepRegistry the step registry
*/
public void setStepRegistry(StepRegistry stepRegistry) {
@@ -105,8 +102,7 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
}
/**
* Unregister all the jobs and close all the contexts created by this
* loader.
* Unregister all the jobs and close all the contexts created by this loader.
*
* @see JobLoader#clear()
*/
@@ -217,11 +213,10 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
}
/**
* Returns all the {@link Step} instances defined by the specified {@link StepLocator}.
* <br>
* The specified <tt>jobApplicationContext</tt> is used to collect additional steps that
* are not exposed by the step locator
*
* Returns all the {@link Step} instances defined by the specified
* {@link StepLocator}. <br>
* The specified <tt>jobApplicationContext</tt> is used to collect additional steps
* that are not exposed by the step locator
* @param stepLocator the given step locator
* @param jobApplicationContext the application context of the job
* @return all the {@link Step} defined by the given step locator and context
@@ -234,8 +229,10 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
result.add(stepLocator.getStep(stepName));
}
// Because some steps are referenced by name, we need to look in the context to see if there
// are more Step instances defined. Right now they are registered as being available in the
// Because some steps are referenced by name, we need to look in the context to
// see if there
// are more Step instances defined. Right now they are registered as being
// available in the
// context of the job but we have no idea if they are linked to that Job or not.
final Map<String, Step> allSteps = jobApplicationContext.getBeansOfType(Step.class);
for (Map.Entry<String, Step> entry : allSteps.entrySet()) {
@@ -247,10 +244,9 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
}
/**
* Registers the specified {@link Job} defined in the specified {@link ConfigurableApplicationContext}.
* <br>
* Registers the specified {@link Job} defined in the specified
* {@link ConfigurableApplicationContext}. <br>
* Makes sure to update the {@link StepRegistry} if it is available.
*
* @param context the context in which the job is defined
* @param job the job to register
* @throws DuplicateJobException if that job is already registered
@@ -270,10 +266,9 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
/**
* Unregisters the job identified by the specified <tt>jobName</tt>.
*
* @param jobName the name of the job to unregister
*/
private void doUnregister(String jobName) {
private void doUnregister(String jobName) {
jobRegistry.unregister(jobName);
if (stepRegistry != null) {
stepRegistry.unregisterStepsFromJob(jobName);
@@ -285,4 +280,5 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
public void afterPropertiesSet() {
Assert.notNull(jobRegistry, "Job registry could not be null.");
}
}

View File

@@ -34,28 +34,31 @@ import java.util.Arrays;
import java.util.List;
/**
* {@link ApplicationContextFactory} implementation that takes a parent context and a path to the context to create.
* When createApplicationContext method is called, the child {@link ApplicationContext} will be returned. The child
* context is not re-created every time it is requested, it is lazily initialized and cached. Clients should ensure that
* {@link ApplicationContextFactory} implementation that takes a parent context and a path
* to the context to create. When createApplicationContext method is called, the child
* {@link ApplicationContext} will be returned. The child context is not re-created every
* time it is requested, it is lazily initialized and cached. Clients should ensure that
* it is closed when it is no longer needed.
*
*
*/
public class GenericApplicationContextFactory extends AbstractApplicationContextFactory {
/**
* Create an application context factory for the resource specified. The resource can be an actual {@link Resource},
* in which case it will be interpreted as an XML file, or it can be a &#64;Configuration class, or a package name.
* All types must be the same (mixing XML with a java package for example is not allowed and will result in an
* {@link java.lang.IllegalArgumentException}).
*
* @param resources some resources (XML configuration files, &#064;Configuration classes or java packages to scan)
* Create an application context factory for the resource specified. The resource can
* be an actual {@link Resource}, in which case it will be interpreted as an XML file,
* or it can be a &#64;Configuration class, or a package name. All types must be the
* same (mixing XML with a java package for example is not allowed and will result in
* an {@link java.lang.IllegalArgumentException}).
* @param resources some resources (XML configuration files, &#064;Configuration
* classes or java packages to scan)
*/
public GenericApplicationContextFactory(Object... resources) {
super(resources);
}
/**
* @see AbstractApplicationContextFactory#createApplicationContext(ConfigurableApplicationContext, Object...)
* @see AbstractApplicationContextFactory#createApplicationContext(ConfigurableApplicationContext,
* Object...)
*/
@Override
protected ConfigurableApplicationContext createApplicationContext(ConfigurableApplicationContext parent,
@@ -63,23 +66,26 @@ public class GenericApplicationContextFactory extends AbstractApplicationContext
ConfigurableApplicationContext context;
if (allObjectsOfType(resources, Resource.class)) {
context = new ResourceXmlApplicationContext(parent, resources);
} else if (allObjectsOfType(resources, Class.class)) {
context = new ResourceAnnotationApplicationContext(parent, resources);
} else if (allObjectsOfType(resources, String.class)) {
context = new ResourceAnnotationApplicationContext(parent, resources);
} else {
context = new ResourceXmlApplicationContext(parent, resources);
}
else if (allObjectsOfType(resources, Class.class)) {
context = new ResourceAnnotationApplicationContext(parent, resources);
}
else if (allObjectsOfType(resources, String.class)) {
context = new ResourceAnnotationApplicationContext(parent, resources);
}
else {
List<Class<?>> types = new ArrayList<>();
for (Object resource : resources) {
types.add(resource.getClass());
}
throw new IllegalArgumentException("No application context could be created for resource types: "
+ Arrays.toString(types.toArray()));
throw new IllegalArgumentException(
"No application context could be created for resource types: " + Arrays.toString(types.toArray()));
}
return context;
}
private boolean allObjectsOfType(Object[] objects, Class<?> type) {
for (Object object : objects) {
if (!type.isInstance(object)) {
@@ -140,29 +146,32 @@ public class GenericApplicationContextFactory extends AbstractApplicationContext
class ResourceXmlApplicationContextHelper extends ApplicationContextHelper {
ResourceXmlApplicationContextHelper(ConfigurableApplicationContext parent, GenericApplicationContext context, Object... config) {
ResourceXmlApplicationContextHelper(ConfigurableApplicationContext parent,
GenericApplicationContext context, Object... config) {
super(parent, context, config);
}
@Override
protected String generateId(Object... configs) {
Resource[] resources = Arrays.copyOfRange(configs, 0, configs.length, Resource[].class);
try {
List<String> uris = new ArrayList<>();
for (Resource resource : resources) {
uris.add(resource.getURI().toString());
}
return StringUtils.collectionToCommaDelimitedString(uris);
}
catch (IOException e) {
return Arrays.toString(resources);
}
try {
List<String> uris = new ArrayList<>();
for (Resource resource : resources) {
uris.add(resource.getURI().toString());
}
return StringUtils.collectionToCommaDelimitedString(uris);
}
catch (IOException e) {
return Arrays.toString(resources);
}
}
@Override
protected void loadConfiguration(Object... configs) {
Resource[] resources = Arrays.copyOfRange(configs, 0, configs.length, Resource[].class);
load(resources);
}
}
helper = new ResourceXmlApplicationContextHelper(parent, this, resources);
refresh();
@@ -189,7 +198,8 @@ public class GenericApplicationContextFactory extends AbstractApplicationContext
class ResourceAnnotationApplicationContextHelper extends ApplicationContextHelper {
public ResourceAnnotationApplicationContextHelper(ConfigurableApplicationContext parent, GenericApplicationContext context, Object... config) {
public ResourceAnnotationApplicationContextHelper(ConfigurableApplicationContext parent,
GenericApplicationContext context, Object... config) {
super(parent, context, config);
}
@@ -207,6 +217,7 @@ public class GenericApplicationContextFactory extends AbstractApplicationContext
return Arrays.toString(configs);
}
}
@Override
protected void loadConfiguration(Object... configs) {
if (allObjectsOfType(configs, Class.class)) {
@@ -218,6 +229,7 @@ public class GenericApplicationContextFactory extends AbstractApplicationContext
scan(pkgs);
}
}
}
helper = new ResourceAnnotationApplicationContextHelper(parent, this, resources);
refresh();

View File

@@ -23,14 +23,13 @@ import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
* A {@link Job} that can optionally prepend a group name to another job's name,
* to make it fit a naming convention for type or origin. E.g. the source job
* might be <code>overnightJob</code> and the group
* <code>financeDepartment</code>, which would result in a {@link Job} with
* identical functionality but named <code>financeDepartment.overnightJob</code>
* . The use of a "." separator for elements is deliberate, since it is a "safe"
* character in a <a href="https://www.w3.org/Addressing/URL">URL</a>.
*
* A {@link Job} that can optionally prepend a group name to another job's name, to make
* it fit a naming convention for type or origin. E.g. the source job might be
* <code>overnightJob</code> and the group <code>financeDepartment</code>, which would
* result in a {@link Job} with identical functionality but named
* <code>financeDepartment.overnightJob</code> . The use of a "." separator for elements
* is deliberate, since it is a "safe" character in a
* <a href="https://www.w3.org/Addressing/URL">URL</a>.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
@@ -39,8 +38,8 @@ import org.springframework.util.ClassUtils;
public class GroupAwareJob implements Job {
/**
* The separator between group and delegate job names in the final name
* given to this job.
* The separator between group and delegate job names in the final name given to this
* job.
*/
private static final String SEPARATOR = ".";
@@ -50,7 +49,6 @@ public class GroupAwareJob implements Job {
/**
* Create a new {@link Job} with the delegate and no group name.
*
* @param delegate a delegate for the features of a regular Job
*/
public GroupAwareJob(Job delegate) {
@@ -59,7 +57,6 @@ public class GroupAwareJob implements Job {
/**
* Create a new {@link Job} with the given group name and delegate.
*
* @param groupName the group name to prepend (can be {@code null})
* @param delegate a delegate for the features of a regular Job
*/
@@ -75,14 +72,13 @@ public class GroupAwareJob implements Job {
}
/**
* Concatenates the group name and the delegate job name (joining with a
* ".").
* Concatenates the group name and the delegate job name (joining with a ".").
*
* @see org.springframework.batch.core.Job#getName()
*/
@Override
public String getName() {
return groupName==null ? delegate.getName() : groupName + SEPARATOR + delegate.getName();
return groupName == null ? delegate.getName() : groupName + SEPARATOR + delegate.getName();
}
@Override

View File

@@ -24,11 +24,10 @@ import org.springframework.batch.core.configuration.JobFactory;
import org.springframework.batch.core.configuration.JobRegistry;
/**
* Generic service that can bind and unbind a {@link JobFactory} in a
* {@link JobRegistry}.
*
* Generic service that can bind and unbind a {@link JobFactory} in a {@link JobRegistry}.
*
* @author Dave Syer
*
*
*/
public class JobFactoryRegistrationListener {
@@ -37,9 +36,7 @@ public class JobFactoryRegistrationListener {
private JobRegistry jobRegistry;
/**
* Public setter for a {@link JobRegistry} to use for all the bind and
* unbind events.
*
* Public setter for a {@link JobRegistry} to use for all the bind and unbind events.
* @param jobRegistry {@link JobRegistry}
*/
public void setJobRegistry(JobRegistry jobRegistry) {
@@ -47,8 +44,7 @@ public class JobFactoryRegistrationListener {
}
/**
* Take the {@link JobFactory} provided and register it with the
* {@link JobRegistry}.
* Take the {@link JobFactory} provided and register it with the {@link JobRegistry}.
* @param jobFactory a {@link JobFactory}
* @param params not needed by this listener.
* @throws Exception if there is a problem

View File

@@ -22,36 +22,30 @@ import org.springframework.batch.core.configuration.DuplicateJobException;
/**
* @author Dave Syer
*
* @since 2.1
*/
public interface JobLoader {
/**
* Load an application context and register all the jobs.
*
* @param factory a factory for an application context (containing jobs)
* @return a collection of the jobs created
*
* @throws DuplicateJobException if a job with the same name was already
* registered
* @throws DuplicateJobException if a job with the same name was already registered
*/
Collection<Job> load(ApplicationContextFactory factory) throws DuplicateJobException;
/**
* Load an application context and register all the jobs, having first
* unregistered them if already registered. Implementations should also take
* care to close and clean up the application context previously created if
* possible (either from this factory or from one with the same jobs).
*
* Load an application context and register all the jobs, having first unregistered
* them if already registered. Implementations should also take care to close and
* clean up the application context previously created if possible (either from this
* factory or from one with the same jobs).
* @param factory a factory for an application context (containing jobs)
* @return a collection of the jobs created
*/
Collection<Job> reload(ApplicationContextFactory factory);
/**
* Unregister all the jobs and close all the contexts created by this
* loader.
* Unregister all the jobs and close all the contexts created by this loader.
*/
void clear();

View File

@@ -37,15 +37,15 @@ import org.springframework.util.Assert;
/**
* A {@link BeanPostProcessor} that registers {@link Job} beans with a
* {@link JobRegistry}. Include a bean of this type along with your job
* configuration, and use the same {@link JobRegistry} as a {@link JobLocator}
* when you need to locate a {@link Job} to launch.
* {@link JobRegistry}. Include a bean of this type along with your job configuration, and
* use the same {@link JobRegistry} as a {@link JobLocator} when you need to locate a
* {@link Job} to launch.
*
* @author Dave Syer
*
*/
public class JobRegistryBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware, InitializingBean,
DisposableBean {
public class JobRegistryBeanPostProcessor
implements BeanPostProcessor, BeanFactoryAware, InitializingBean, DisposableBean {
private static Log logger = LogFactory.getLog(JobRegistryBeanPostProcessor.class);
@@ -59,13 +59,11 @@ DisposableBean {
private DefaultListableBeanFactory beanFactory;
/**
* The group name for jobs registered by this component. Optional (defaults
* to null, which means that jobs are registered with their bean names).
* Useful where there is a hierarchy of application contexts all
* contributing to the same {@link JobRegistry}: child contexts can then
* define an instance with a unique group name to avoid clashes between job
* names.
*
* The group name for jobs registered by this component. Optional (defaults to null,
* which means that jobs are registered with their bean names). Useful where there is
* a hierarchy of application contexts all contributing to the same
* {@link JobRegistry}: child contexts can then define an instance with a unique group
* name to avoid clashes between job names.
* @param groupName the groupName to set
*/
public void setGroupName(String groupName) {
@@ -74,7 +72,6 @@ DisposableBean {
/**
* Injection setter for {@link JobRegistry}.
*
* @param jobRegistry the jobConfigurationRegistry to set
*/
public void setJobRegistry(JobRegistry jobRegistry) {
@@ -84,8 +81,7 @@ DisposableBean {
/*
* (non-Javadoc)
*
* @see
* org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org
* @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org
* .springframework.beans.factory.BeanFactory)
*/
@Override
@@ -106,8 +102,8 @@ DisposableBean {
}
/**
* Unregister all the {@link Job} instances that were registered by this
* post processor.
* Unregister all the {@link Job} instances that were registered by this post
* processor.
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
@Override
@@ -137,7 +133,7 @@ DisposableBean {
if (beanFactory != null && beanFactory.containsBean(beanName)) {
groupName = getGroupName(beanFactory.getBeanDefinition(beanName), job);
}
job = groupName==null ? job : new GroupAwareJob(groupName, job);
job = groupName == null ? job : new GroupAwareJob(groupName, job);
ReferenceJobFactory jobFactory = new ReferenceJobFactory(job);
String name = jobFactory.getJobName();
if (logger.isDebugEnabled()) {
@@ -155,10 +151,9 @@ DisposableBean {
}
/**
* Determine a group name for the job to be registered. Default
* implementation just returns the {@link #setGroupName(String) groupName}
* configured. Provides an extension point for specialised subclasses.
*
* Determine a group name for the job to be registered. Default implementation just
* returns the {@link #setGroupName(String) groupName} configured. Provides an
* extension point for specialised subclasses.
* @param beanDefinition the bean definition for the job
* @param job the job
* @return a group name for the job (or null if not needed)
@@ -177,4 +172,5 @@ DisposableBean {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}

View File

@@ -40,7 +40,8 @@ public class MapJobRegistry implements JobRegistry {
/**
* The map holding the registered job factories.
*/
// The "final" ensures that it is visible and initialized when the constructor resolves.
// The "final" ensures that it is visible and initialized when the constructor
// resolves.
private final ConcurrentMap<String, JobFactory> map = new ConcurrentHashMap<>();
@Override
@@ -50,8 +51,7 @@ public class MapJobRegistry implements JobRegistry {
Assert.notNull(name, "Job configuration must have a name.");
JobFactory previousValue = map.putIfAbsent(name, jobFactory);
if (previousValue != null) {
throw new DuplicateJobException("A job configuration with this name [" + name
+ "] was already registered");
throw new DuplicateJobException("A job configuration with this name [" + name + "] was already registered");
}
}
@@ -66,7 +66,8 @@ public class MapJobRegistry implements JobRegistry {
JobFactory factory = map.get(name);
if (factory == null) {
throw new NoSuchJobException("No job configuration with the name [" + name + "] was registered");
} else {
}
else {
return factory.createJob();
}
}

View File

@@ -44,15 +44,14 @@ public class MapStepRegistry implements StepRegistry {
Assert.notNull(jobName, "The job name cannot be null.");
Assert.notNull(steps, "The job steps cannot be null.");
final Map<String, Step> jobSteps = new HashMap<>();
for (Step step : steps) {
jobSteps.put(step.getName(), step);
}
final Object previousValue = map.putIfAbsent(jobName, jobSteps);
if (previousValue != null) {
throw new DuplicateJobException("A job configuration with this name [" + jobName
+ "] was already registered");
throw new DuplicateJobException(
"A job configuration with this name [" + jobName + "] was already registered");
}
}
@@ -68,13 +67,15 @@ public class MapStepRegistry implements StepRegistry {
Assert.notNull(stepName, "The step name cannot be null.");
if (!map.containsKey(jobName)) {
throw new NoSuchJobException("No job configuration with the name [" + jobName + "] was registered");
} else {
}
else {
final Map<String, Step> jobSteps = map.get(jobName);
if (jobSteps.containsKey(stepName)) {
return jobSteps.get(stepName);
} else {
throw new NoSuchStepException("The step called [" + stepName + "] does not exist in the job [" +
jobName + "]");
}
else {
throw new NoSuchStepException(
"The step called [" + stepName + "] does not exist in the job [" + jobName + "]");
}
}
}

View File

@@ -19,8 +19,8 @@ import org.springframework.batch.core.Job;
import org.springframework.batch.core.configuration.JobFactory;
/**
* A {@link JobFactory} that just keeps a reference to a {@link Job}. It never
* modifies its {@link Job}.
* A {@link JobFactory} that just keeps a reference to a {@link Job}. It never modifies
* its {@link Job}.
*
* @author Dave Syer
*

View File

@@ -131,10 +131,9 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
private String jobFactoryRef;
/**
* Convenience method for subclasses to set the job factory reference if it
* is available (null is fine, but the quality of error reports is better if
* it is available).
*
* Convenience method for subclasses to set the job factory reference if it is
* available (null is fine, but the quality of error reports is better if it is
* available).
* @param jobFactoryRef name of the ref
*/
protected void setJobFactoryRef(String jobFactoryRef) {
@@ -186,9 +185,8 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
stepExists = true;
}
else if (nodeName.equals(SPLIT_ELE)) {
stateTransitions.addAll(splitParser
.parse(child, new ParserContext(parserContext.getReaderContext(), parserContext
.getDelegate(), builder.getBeanDefinition())));
stateTransitions.addAll(splitParser.parse(child, new ParserContext(parserContext.getReaderContext(),
parserContext.getDelegate(), builder.getBeanDefinition())));
stepExists = true;
}
@@ -203,8 +201,8 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
String flowName = (String) builder.getRawBeanDefinition().getAttribute("flowName");
if (!stepExists && !StringUtils.hasText(element.getAttribute("parent"))) {
parserContext.getReaderContext().error("The flow [" + flowName + "] must contain at least one step, flow or split",
element);
parserContext.getReaderContext()
.error("The flow [" + flowName + "] must contain at least one step, flow or split", element);
}
// Ensure that all elements are reachable
@@ -224,7 +222,6 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
/**
* Find all of the elements that are pointed to by this element.
*
* @param element The parent element
* @return a collection of reachable element names
*/
@@ -253,9 +250,9 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
/**
* Find all of the elements reachable from the startElement.
*
* @param startElement name of the element to start from
* @param reachableElementMap Map of elements that can be reached from the startElement
* @param reachableElementMap Map of elements that can be reached from the
* startElement
* @param accumulator a collection of reachable element names
*/
protected void findAllReachableElements(String startElement, Map<String, Set<String>> reachableElementMap,
@@ -277,8 +274,7 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
* @param stateDef The bean definition for the current state
* @param element the &lt;step/gt; element to parse
* @return a collection of
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
* references
* {@link org.springframework.batch.core.job.flow.support.StateTransition} references
*/
public static Collection<BeanDefinition> getNextElements(ParserContext parserContext, BeanDefinition stateDef,
Element element) {
@@ -287,13 +283,11 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
/**
* @param parserContext the parser context for the bean factory
* @param stepId the id of the current state if it is a step state, null
* otherwise
* @param stepId the id of the current state if it is a step state, null otherwise
* @param stateDef The bean definition for the current state
* @param element the &lt;step/gt; element to parse
* @return a collection of
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
* references
* {@link org.springframework.batch.core.job.flow.support.StateTransition} references
*/
public static Collection<BeanDefinition> getNextElements(ParserContext parserContext, String stepId,
BeanDefinition stateDef, Element element) {
@@ -328,9 +322,8 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
}
}
else if (hasNextAttribute) {
parserContext.getReaderContext().error(
"The <" + element.getNodeName() + "/> may not contain a '" + NEXT_ATTR
+ "' attribute and a transition element", element);
parserContext.getReaderContext().error("The <" + element.getNodeName() + "/> may not contain a '"
+ NEXT_ATTR + "' attribute and a transition element", element);
}
return list;
@@ -357,8 +350,7 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
* @param stateDef The bean definition for the current state
* @param parserContext the parser context for the bean factory
* @return a collection of
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
* references
* {@link org.springframework.batch.core.job.flow.support.StateTransition} references
*/
private static Collection<BeanDefinition> parseTransitionElement(Element transitionElement, String stateId,
BeanDefinition stateDef, ParserContext parserContext) {
@@ -373,24 +365,24 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
boolean abandon = stateId != null && StringUtils.hasText(restartAttribute) && !restartAttribute.equals(stateId);
String exitCodeAttribute = transitionElement.getAttribute(EXIT_CODE_ATTR);
return createTransition(status, onAttribute, nextAttribute, exitCodeAttribute, stateDef, parserContext, abandon);
return createTransition(status, onAttribute, nextAttribute, exitCodeAttribute, stateDef, parserContext,
abandon);
}
/**
* @param status The batch status that this transition will set. Use
* BatchStatus.UNKNOWN if not applicable.
* @param on The pattern that this transition should match. Use null for
* "no restriction" (same as "*").
* @param on The pattern that this transition should match. Use null for "no
* restriction" (same as "*").
* @param next The state to which this transition should go. Use null if not
* applicable.
* @param exitCode The exit code that this transition will set. Use null to
* default to batchStatus.
* @param exitCode The exit code that this transition will set. Use null to default to
* batchStatus.
* @param stateDef The bean definition for the current state
* @param parserContext the parser context for the bean factory
* @param abandon the abandon flag to be used by the transition.
* @return a collection of
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
* references
* {@link org.springframework.batch.core.job.flow.support.StateTransition} references
*/
protected static Collection<BeanDefinition> createTransition(FlowExecutionStatus status, String on, String next,
String exitCode, BeanDefinition stateDef, ParserContext parserContext, boolean abandon) {
@@ -409,8 +401,7 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
endBuilder.addConstructorArgValue(exitCodeExists ? exitCode : status.getName());
String endName = (status == FlowExecutionStatus.STOPPED ? STOP_ELE
: status == FlowExecutionStatus.FAILED ? FAIL_ELE : END_ELE)
+ (endCounter++);
: status == FlowExecutionStatus.FAILED ? FAIL_ELE : END_ELE) + (endCounter++);
endBuilder.addConstructorArgValue(endName);
endBuilder.addConstructorArgValue(abandon);
@@ -456,11 +447,11 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
/**
* Strip the namespace from the element name if it exists.
*/
private static String stripNamespace(String elementName){
if(elementName.startsWith("batch:")){
private static String stripNamespace(String elementName) {
if (elementName.startsWith("batch:")) {
return elementName.substring(6);
}
else{
else {
return elementName;
}
}

View File

@@ -55,7 +55,8 @@ public abstract class AbstractListenerParser {
}
public void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.addPropertyValue("delegate", parseListenerElement(element, parserContext, builder.getRawBeanDefinition()));
builder.addPropertyValue("delegate",
parseListenerElement(element, parserContext, builder.getRawBeanDefinition()));
ManagedMap<String, String> metaDataMap = new ManagedMap<>();
for (String metaDataPropertyName : getMethodNameAttributes()) {
@@ -67,7 +68,8 @@ public abstract class AbstractListenerParser {
builder.addPropertyValue("metaDataMap", metaDataMap);
}
public static BeanMetadataElement parseListenerElement(Element element, ParserContext parserContext, BeanDefinition enclosing) {
public static BeanMetadataElement parseListenerElement(Element element, ParserContext parserContext,
BeanDefinition enclosing) {
String listenerRef = element.getAttribute(REF_ATTR);
List<Element> beanElements = DomUtils.getChildElementsByTagName(element, BEAN_ELE);
List<Element> refElements = DomUtils.getChildElementsByTagName(element, REF_ELE);
@@ -79,8 +81,8 @@ public abstract class AbstractListenerParser {
}
else if (beanElements.size() == 1) {
Element beanElement = beanElements.get(0);
BeanDefinitionHolder beanDefinitionHolder = parserContext.getDelegate().parseBeanDefinitionElement(
beanElement, enclosing);
BeanDefinitionHolder beanDefinitionHolder = parserContext.getDelegate()
.parseBeanDefinitionElement(beanElement, enclosing);
parserContext.getDelegate().decorateBeanDefinitionIfRequired(beanElement, beanDefinitionHolder);
return beanDefinitionHolder;
}
@@ -117,8 +119,8 @@ public abstract class AbstractListenerParser {
}
String id = element.getAttribute(ID_ATTR);
parserContext.getReaderContext().error(
"The <" + element.getTagName() + (StringUtils.hasText(id) ? " id=\"" + id + "\"" : "")
parserContext.getReaderContext()
.error("The <" + element.getTagName() + (StringUtils.hasText(id) ? " id=\"" + id + "\"" : "")
+ "/> element must have exactly one of: '" + REF_ATTR + "' attribute, <" + BEAN_ELE
+ "/> attribute, or <" + REF_ELE + "/> element. Found: " + found + ".", element);
}
@@ -133,7 +135,8 @@ public abstract class AbstractListenerParser {
}
/**
* @return The {@link Class} for the implementation of {@link AbstractListenerFactoryBean}.
* @return The {@link Class} for the implementation of
* {@link AbstractListenerFactoryBean}.
*/
protected abstract Class<? extends AbstractListenerFactoryBean<?>> getBeanClass();

View File

@@ -1,303 +1,307 @@
/*
* Copyright 2006-2022 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
*
* https://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.xml;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.batch.core.listener.StepListenerMetaData;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
/**
* Internal parser for the &lt;step/&gt; elements inside a job. A step element
* references a bean definition for a
* {@link org.springframework.batch.core.Step} and goes on to (optionally) list
* a set of transitions from that step to others with &lt;next on="pattern"
* to="stepName"/&gt;. Used by the {@link JobParser}.
*
* @author Dave Syer
* @author Thomas Risberg
* @author Josh Long
* @see JobParser
* @since 2.0
*/
public abstract class AbstractStepParser {
/**
* The ID attribute for the step parser.
*/
protected static final String ID_ATTR = "id";
private static final String PARENT_ATTR = "parent";
private static final String REF_ATTR = "ref";
private static final String ALLOW_START_ATTR = "allow-start-if-complete";
private static final String TASKLET_ELE = "tasklet";
private static final String PARTITION_ELE = "partition";
private static final String JOB_ELE = "job";
private static final String JOB_PARAMS_EXTRACTOR_ATTR = "job-parameters-extractor";
private static final String JOB_LAUNCHER_ATTR = "job-launcher";
private static final String STEP_ATTR = "step";
private static final String STEP_ELE = STEP_ATTR;
private static final String PARTITIONER_ATTR = "partitioner";
private static final String AGGREGATOR_ATTR = "aggregator";
private static final String HANDLER_ATTR = "handler";
private static final String HANDLER_ELE = "handler";
private static final String TASK_EXECUTOR_ATTR = "task-executor";
private static final String GRID_SIZE_ATTR = "grid-size";
private static final String FLOW_ELE = "flow";
private static final String JOB_REPO_ATTR = "job-repository";
private static final StepListenerParser stepListenerParser = new StepListenerParser(StepListenerMetaData.stepExecutionListenerMetaData());
/**
* @param stepElement The &lt;step/&gt; element
* @param parserContext instance of {@link ParserContext}.
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
* from the enclosing tag. Use 'null' if unknown.
* @return {@link AbstractBeanDefinition} for the stepElement.
*/
protected AbstractBeanDefinition parseStep(Element stepElement, ParserContext parserContext, String jobFactoryRef) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition bd = builder.getRawBeanDefinition();
// look at all nested elements
NodeList children = stepElement.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node nd = children.item(i);
if (nd instanceof Element) {
Element nestedElement = (Element) nd;
String name = nestedElement.getLocalName();
if (TASKLET_ELE.equals(name)) {
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
new TaskletParser().parseTasklet(stepElement, nestedElement, bd, parserContext, stepUnderspecified);
}
else if (FLOW_ELE.equals(name)) {
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
parseFlow(stepElement, nestedElement, bd, parserContext, stepUnderspecified);
}
else if (PARTITION_ELE.equals(name)) {
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
parsePartition(stepElement, nestedElement, bd, parserContext, stepUnderspecified, jobFactoryRef);
}
else if (JOB_ELE.equals(name)) {
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
parseJob(stepElement, nestedElement, bd, parserContext, stepUnderspecified);
}
else if ("description".equals(name)) {
bd.setDescription(nestedElement.getTextContent());
}
// nested bean reference/declaration
else {
String ns = nestedElement.getNamespaceURI();
Object value = null;
boolean skip = false;
// Spring NS
if ((ns == null && name.equals(BeanDefinitionParserDelegate.BEAN_ELEMENT))
|| ns.equals(BeanDefinitionParserDelegate.BEANS_NAMESPACE_URI)) {
BeanDefinitionHolder holder = parserContext.getDelegate().parseBeanDefinitionElement(nestedElement);
value = parserContext.getDelegate().decorateBeanDefinitionIfRequired(nestedElement, holder);
}
// Spring Batch transitions
else if (ns.equals("http://www.springframework.org/schema/batch")) {
// don't parse
skip = true;
}
// Custom NS
else {
value = parserContext.getDelegate().parseCustomElement(nestedElement);
}
if (!skip) {
bd.setBeanClass(StepParserStepFactoryBean.class);
bd.setAttribute("isNamespaceStep", true);
builder.addPropertyValue("tasklet", value);
}
}
}
}
String parentRef = stepElement.getAttribute(PARENT_ATTR);
if (StringUtils.hasText(parentRef)) {
bd.setParentName(parentRef);
}
String isAbstract = stepElement.getAttribute("abstract");
if (StringUtils.hasText(isAbstract)) {
bd.setAbstract(Boolean.valueOf(isAbstract));
}
String jobRepositoryRef = stepElement.getAttribute(JOB_REPO_ATTR);
if (StringUtils.hasText(jobRepositoryRef)) {
builder.addPropertyReference("jobRepository", jobRepositoryRef);
}
if (StringUtils.hasText(jobFactoryRef)) {
bd.setAttribute("jobParserJobFactoryBeanRef", jobFactoryRef);
}
//add the allow parser here
String isAllowStart = stepElement.getAttribute(ALLOW_START_ATTR);
if (StringUtils.hasText(isAllowStart)) {
//check if the value is already set from an inner element
if (!bd.getPropertyValues().contains("allowStartIfComplete")) {
//set the value as a property
bd.getPropertyValues().add("allowStartIfComplete", Boolean.valueOf(isAllowStart));
}//end if
}
stepListenerParser.handleListenersElement(stepElement, bd, parserContext);
return bd;
}
private void parsePartition(Element stepElement, Element partitionElement, AbstractBeanDefinition bd, ParserContext parserContext, boolean stepUnderspecified, String jobFactoryRef ) {
bd.setBeanClass(StepParserStepFactoryBean.class);
bd.setAttribute("isNamespaceStep", true);
String stepRef = partitionElement.getAttribute(STEP_ATTR);
String partitionerRef = partitionElement.getAttribute(PARTITIONER_ATTR);
String aggregatorRef = partitionElement.getAttribute(AGGREGATOR_ATTR);
String handlerRef = partitionElement.getAttribute(HANDLER_ATTR);
if (!StringUtils.hasText(partitionerRef)) {
parserContext.getReaderContext().error("You must specify a partitioner", partitionElement);
return;
}
MutablePropertyValues propertyValues = bd.getPropertyValues();
propertyValues.addPropertyValue("partitioner", new RuntimeBeanReference(partitionerRef));
if (StringUtils.hasText(aggregatorRef)) {
propertyValues.addPropertyValue("stepExecutionAggregator", new RuntimeBeanReference(aggregatorRef));
}
boolean customHandler = false;
if (!StringUtils.hasText(handlerRef)) {
Element handlerElement = DomUtils.getChildElementByTagName(partitionElement, HANDLER_ELE);
if (handlerElement != null) {
String taskExecutorRef = handlerElement.getAttribute(TASK_EXECUTOR_ATTR);
if (StringUtils.hasText(taskExecutorRef)) {
propertyValues.addPropertyValue("taskExecutor", new RuntimeBeanReference(taskExecutorRef));
}
String gridSize = handlerElement.getAttribute(GRID_SIZE_ATTR);
if (StringUtils.hasText(gridSize)) {
propertyValues.addPropertyValue("gridSize", new TypedStringValue(gridSize));
}
}
} else {
customHandler = true;
BeanDefinition partitionHandler = BeanDefinitionBuilder.genericBeanDefinition().getRawBeanDefinition();
partitionHandler.setParentName(handlerRef);
propertyValues.addPropertyValue("partitionHandler", partitionHandler);
}
Element inlineStepElement = DomUtils.getChildElementByTagName(partitionElement, STEP_ELE);
if (inlineStepElement == null && !StringUtils.hasText(stepRef) && !customHandler) {
parserContext.getReaderContext().error("You must specify a step", partitionElement);
return;
}
if (StringUtils.hasText(stepRef)) {
propertyValues.addPropertyValue("step", new RuntimeBeanReference(stepRef));
} else if( inlineStepElement!=null) {
AbstractBeanDefinition stepDefinition = parseStep(inlineStepElement, parserContext, jobFactoryRef);
stepDefinition.getPropertyValues().addPropertyValue("name", stepElement.getAttribute(ID_ATTR));
propertyValues.addPropertyValue("step", stepDefinition );
}
}
private void parseJob(Element stepElement, Element jobElement, AbstractBeanDefinition bd, ParserContext parserContext, boolean stepUnderspecified) {
bd.setBeanClass(StepParserStepFactoryBean.class);
bd.setAttribute("isNamespaceStep", true);
String jobRef = jobElement.getAttribute(REF_ATTR);
if (!StringUtils.hasText(jobRef)) {
parserContext.getReaderContext().error("You must specify a job", jobElement);
return;
}
MutablePropertyValues propertyValues = bd.getPropertyValues();
propertyValues.addPropertyValue("job", new RuntimeBeanReference(jobRef));
String jobParametersExtractor = jobElement.getAttribute(JOB_PARAMS_EXTRACTOR_ATTR);
String jobLauncher = jobElement.getAttribute(JOB_LAUNCHER_ATTR);
if (StringUtils.hasText(jobParametersExtractor)) {
propertyValues.addPropertyValue("jobParametersExtractor", new RuntimeBeanReference(jobParametersExtractor));
}
if (StringUtils.hasText(jobLauncher)) {
propertyValues.addPropertyValue("jobLauncher", new RuntimeBeanReference(jobLauncher));
}
}
private void parseFlow(Element stepElement, Element flowElement, AbstractBeanDefinition bd,
ParserContext parserContext, boolean stepUnderspecified) {
bd.setBeanClass(StepParserStepFactoryBean.class);
bd.setAttribute("isNamespaceStep", true);
String flowRef = flowElement.getAttribute(PARENT_ATTR);
String idAttribute = stepElement.getAttribute(ID_ATTR);
BeanDefinition flowDefinition = new GenericBeanDefinition();
flowDefinition.setParentName(flowRef);
MutablePropertyValues propertyValues = flowDefinition.getPropertyValues();
if (StringUtils.hasText(idAttribute)) {
propertyValues.addPropertyValue("name", idAttribute);
}
bd.getPropertyValues().addPropertyValue("flow", flowDefinition);
}
}
/*
* Copyright 2006-2022 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
*
* https://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.xml;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.batch.core.listener.StepListenerMetaData;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
/**
* Internal parser for the &lt;step/&gt; elements inside a job. A step element references
* a bean definition for a {@link org.springframework.batch.core.Step} and goes on to
* (optionally) list a set of transitions from that step to others with &lt;next
* on="pattern" to="stepName"/&gt;. Used by the {@link JobParser}.
*
* @author Dave Syer
* @author Thomas Risberg
* @author Josh Long
* @see JobParser
* @since 2.0
*/
public abstract class AbstractStepParser {
/**
* The ID attribute for the step parser.
*/
protected static final String ID_ATTR = "id";
private static final String PARENT_ATTR = "parent";
private static final String REF_ATTR = "ref";
private static final String ALLOW_START_ATTR = "allow-start-if-complete";
private static final String TASKLET_ELE = "tasklet";
private static final String PARTITION_ELE = "partition";
private static final String JOB_ELE = "job";
private static final String JOB_PARAMS_EXTRACTOR_ATTR = "job-parameters-extractor";
private static final String JOB_LAUNCHER_ATTR = "job-launcher";
private static final String STEP_ATTR = "step";
private static final String STEP_ELE = STEP_ATTR;
private static final String PARTITIONER_ATTR = "partitioner";
private static final String AGGREGATOR_ATTR = "aggregator";
private static final String HANDLER_ATTR = "handler";
private static final String HANDLER_ELE = "handler";
private static final String TASK_EXECUTOR_ATTR = "task-executor";
private static final String GRID_SIZE_ATTR = "grid-size";
private static final String FLOW_ELE = "flow";
private static final String JOB_REPO_ATTR = "job-repository";
private static final StepListenerParser stepListenerParser = new StepListenerParser(
StepListenerMetaData.stepExecutionListenerMetaData());
/**
* @param stepElement The &lt;step/&gt; element
* @param parserContext instance of {@link ParserContext}.
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean} from the
* enclosing tag. Use 'null' if unknown.
* @return {@link AbstractBeanDefinition} for the stepElement.
*/
protected AbstractBeanDefinition parseStep(Element stepElement, ParserContext parserContext, String jobFactoryRef) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition bd = builder.getRawBeanDefinition();
// look at all nested elements
NodeList children = stepElement.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node nd = children.item(i);
if (nd instanceof Element) {
Element nestedElement = (Element) nd;
String name = nestedElement.getLocalName();
if (TASKLET_ELE.equals(name)) {
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
new TaskletParser().parseTasklet(stepElement, nestedElement, bd, parserContext, stepUnderspecified);
}
else if (FLOW_ELE.equals(name)) {
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
parseFlow(stepElement, nestedElement, bd, parserContext, stepUnderspecified);
}
else if (PARTITION_ELE.equals(name)) {
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
parsePartition(stepElement, nestedElement, bd, parserContext, stepUnderspecified, jobFactoryRef);
}
else if (JOB_ELE.equals(name)) {
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
parseJob(stepElement, nestedElement, bd, parserContext, stepUnderspecified);
}
else if ("description".equals(name)) {
bd.setDescription(nestedElement.getTextContent());
}
// nested bean reference/declaration
else {
String ns = nestedElement.getNamespaceURI();
Object value = null;
boolean skip = false;
// Spring NS
if ((ns == null && name.equals(BeanDefinitionParserDelegate.BEAN_ELEMENT))
|| ns.equals(BeanDefinitionParserDelegate.BEANS_NAMESPACE_URI)) {
BeanDefinitionHolder holder = parserContext.getDelegate()
.parseBeanDefinitionElement(nestedElement);
value = parserContext.getDelegate().decorateBeanDefinitionIfRequired(nestedElement, holder);
}
// Spring Batch transitions
else if (ns.equals("http://www.springframework.org/schema/batch")) {
// don't parse
skip = true;
}
// Custom NS
else {
value = parserContext.getDelegate().parseCustomElement(nestedElement);
}
if (!skip) {
bd.setBeanClass(StepParserStepFactoryBean.class);
bd.setAttribute("isNamespaceStep", true);
builder.addPropertyValue("tasklet", value);
}
}
}
}
String parentRef = stepElement.getAttribute(PARENT_ATTR);
if (StringUtils.hasText(parentRef)) {
bd.setParentName(parentRef);
}
String isAbstract = stepElement.getAttribute("abstract");
if (StringUtils.hasText(isAbstract)) {
bd.setAbstract(Boolean.valueOf(isAbstract));
}
String jobRepositoryRef = stepElement.getAttribute(JOB_REPO_ATTR);
if (StringUtils.hasText(jobRepositoryRef)) {
builder.addPropertyReference("jobRepository", jobRepositoryRef);
}
if (StringUtils.hasText(jobFactoryRef)) {
bd.setAttribute("jobParserJobFactoryBeanRef", jobFactoryRef);
}
// add the allow parser here
String isAllowStart = stepElement.getAttribute(ALLOW_START_ATTR);
if (StringUtils.hasText(isAllowStart)) {
// check if the value is already set from an inner element
if (!bd.getPropertyValues().contains("allowStartIfComplete")) {
// set the value as a property
bd.getPropertyValues().add("allowStartIfComplete", Boolean.valueOf(isAllowStart));
} // end if
}
stepListenerParser.handleListenersElement(stepElement, bd, parserContext);
return bd;
}
private void parsePartition(Element stepElement, Element partitionElement, AbstractBeanDefinition bd,
ParserContext parserContext, boolean stepUnderspecified, String jobFactoryRef) {
bd.setBeanClass(StepParserStepFactoryBean.class);
bd.setAttribute("isNamespaceStep", true);
String stepRef = partitionElement.getAttribute(STEP_ATTR);
String partitionerRef = partitionElement.getAttribute(PARTITIONER_ATTR);
String aggregatorRef = partitionElement.getAttribute(AGGREGATOR_ATTR);
String handlerRef = partitionElement.getAttribute(HANDLER_ATTR);
if (!StringUtils.hasText(partitionerRef)) {
parserContext.getReaderContext().error("You must specify a partitioner", partitionElement);
return;
}
MutablePropertyValues propertyValues = bd.getPropertyValues();
propertyValues.addPropertyValue("partitioner", new RuntimeBeanReference(partitionerRef));
if (StringUtils.hasText(aggregatorRef)) {
propertyValues.addPropertyValue("stepExecutionAggregator", new RuntimeBeanReference(aggregatorRef));
}
boolean customHandler = false;
if (!StringUtils.hasText(handlerRef)) {
Element handlerElement = DomUtils.getChildElementByTagName(partitionElement, HANDLER_ELE);
if (handlerElement != null) {
String taskExecutorRef = handlerElement.getAttribute(TASK_EXECUTOR_ATTR);
if (StringUtils.hasText(taskExecutorRef)) {
propertyValues.addPropertyValue("taskExecutor", new RuntimeBeanReference(taskExecutorRef));
}
String gridSize = handlerElement.getAttribute(GRID_SIZE_ATTR);
if (StringUtils.hasText(gridSize)) {
propertyValues.addPropertyValue("gridSize", new TypedStringValue(gridSize));
}
}
}
else {
customHandler = true;
BeanDefinition partitionHandler = BeanDefinitionBuilder.genericBeanDefinition().getRawBeanDefinition();
partitionHandler.setParentName(handlerRef);
propertyValues.addPropertyValue("partitionHandler", partitionHandler);
}
Element inlineStepElement = DomUtils.getChildElementByTagName(partitionElement, STEP_ELE);
if (inlineStepElement == null && !StringUtils.hasText(stepRef) && !customHandler) {
parserContext.getReaderContext().error("You must specify a step", partitionElement);
return;
}
if (StringUtils.hasText(stepRef)) {
propertyValues.addPropertyValue("step", new RuntimeBeanReference(stepRef));
}
else if (inlineStepElement != null) {
AbstractBeanDefinition stepDefinition = parseStep(inlineStepElement, parserContext, jobFactoryRef);
stepDefinition.getPropertyValues().addPropertyValue("name", stepElement.getAttribute(ID_ATTR));
propertyValues.addPropertyValue("step", stepDefinition);
}
}
private void parseJob(Element stepElement, Element jobElement, AbstractBeanDefinition bd,
ParserContext parserContext, boolean stepUnderspecified) {
bd.setBeanClass(StepParserStepFactoryBean.class);
bd.setAttribute("isNamespaceStep", true);
String jobRef = jobElement.getAttribute(REF_ATTR);
if (!StringUtils.hasText(jobRef)) {
parserContext.getReaderContext().error("You must specify a job", jobElement);
return;
}
MutablePropertyValues propertyValues = bd.getPropertyValues();
propertyValues.addPropertyValue("job", new RuntimeBeanReference(jobRef));
String jobParametersExtractor = jobElement.getAttribute(JOB_PARAMS_EXTRACTOR_ATTR);
String jobLauncher = jobElement.getAttribute(JOB_LAUNCHER_ATTR);
if (StringUtils.hasText(jobParametersExtractor)) {
propertyValues.addPropertyValue("jobParametersExtractor", new RuntimeBeanReference(jobParametersExtractor));
}
if (StringUtils.hasText(jobLauncher)) {
propertyValues.addPropertyValue("jobLauncher", new RuntimeBeanReference(jobLauncher));
}
}
private void parseFlow(Element stepElement, Element flowElement, AbstractBeanDefinition bd,
ParserContext parserContext, boolean stepUnderspecified) {
bd.setBeanClass(StepParserStepFactoryBean.class);
bd.setAttribute("isNamespaceStep", true);
String flowRef = flowElement.getAttribute(PARENT_ATTR);
String idAttribute = stepElement.getAttribute(ID_ATTR);
BeanDefinition flowDefinition = new GenericBeanDefinition();
flowDefinition.setParentName(flowRef);
MutablePropertyValues propertyValues = flowDefinition.getPropertyValues();
if (StringUtils.hasText(idAttribute)) {
propertyValues.addPropertyValue("name", idAttribute);
}
bd.getPropertyValues().addPropertyValue("flow", flowDefinition);
}
}

View File

@@ -1,49 +1,52 @@
/*
* 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
*
* https://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.xml;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* @author Dan Garrette
* @since 2.0.1
*/
public class BeanDefinitionUtils {
/**
* @param beanName a bean definition name
* @param propertyName the name of the property
* @param beanFactory a {@link BeanFactory}
* @return The {@link PropertyValue} for the property of the bean. Search
* parent hierarchy if necessary. Return null if none is found.
*/
public static PropertyValue getPropertyValue(String beanName, String propertyName, ConfigurableListableBeanFactory beanFactory) {
return beanFactory.getMergedBeanDefinition(beanName).getPropertyValues().getPropertyValue(propertyName);
}
/**
* @param beanName a bean definition name
* @param attributeName the name of the property
* @param beanFactory a {@link BeanFactory}
* @return The value for the attribute of the bean. Search parent hierarchy
* if necessary. Return null if none is found.
*/
public static Object getAttribute(String beanName, String attributeName, ConfigurableListableBeanFactory beanFactory) {
return beanFactory.getMergedBeanDefinition(beanName).getAttribute(attributeName);
}
}
/*
* 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
*
* https://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.xml;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* @author Dan Garrette
* @since 2.0.1
*/
public class BeanDefinitionUtils {
/**
* @param beanName a bean definition name
* @param propertyName the name of the property
* @param beanFactory a {@link BeanFactory}
* @return The {@link PropertyValue} for the property of the bean. Search parent
* hierarchy if necessary. Return null if none is found.
*/
public static PropertyValue getPropertyValue(String beanName, String propertyName,
ConfigurableListableBeanFactory beanFactory) {
return beanFactory.getMergedBeanDefinition(beanName).getPropertyValues().getPropertyValue(propertyName);
}
/**
* @param beanName a bean definition name
* @param attributeName the name of the property
* @param beanFactory a {@link BeanFactory}
* @return The value for the attribute of the bean. Search parent hierarchy if
* necessary. Return null if none is found.
*/
public static Object getAttribute(String beanName, String attributeName,
ConfigurableListableBeanFactory beanFactory) {
return beanFactory.getMergedBeanDefinition(beanName).getAttribute(attributeName);
}
}

View File

@@ -40,7 +40,7 @@ import org.springframework.util.xml.DomUtils;
/**
* Internal parser for the &lt;chunk/&gt; element inside a step.
*
*
* @author Thomas Risberg
* @since 2.0
*/
@@ -71,10 +71,11 @@ public class ChunkElementParser {
* @param bd {@link AbstractBeanDefinition} instance of the containing bean.
* @param element the element to parse
* @param parserContext the context to use
* @param underspecified if true, a fatal error will not be raised if attribute
* or element is missing.
* @param underspecified if true, a fatal error will not be raised if attribute or
* element is missing.
*/
protected void parse(Element element, AbstractBeanDefinition bd, ParserContext parserContext, boolean underspecified) {
protected void parse(Element element, AbstractBeanDefinition bd, ParserContext parserContext,
boolean underspecified) {
MutablePropertyValues propertyValues = bd.getPropertyValues();
@@ -111,21 +112,24 @@ public class ChunkElementParser {
if (!underspecified
&& propertyValues.contains("commitInterval") == propertyValues.contains("chunkCompletionPolicy")) {
if (propertyValues.contains("commitInterval")) {
parserContext.getReaderContext().error(
"The <" + element.getNodeName() + "/> element must contain either '" + COMMIT_INTERVAL_ATTR
+ "' " + "or '" + CHUNK_COMPLETION_POLICY_ATTR + "', but not both.", element);
parserContext.getReaderContext()
.error("The <" + element.getNodeName() + "/> element must contain either '"
+ COMMIT_INTERVAL_ATTR + "' " + "or '" + CHUNK_COMPLETION_POLICY_ATTR
+ "', but not both.", element);
}
else {
parserContext.getReaderContext().error(
"The <" + element.getNodeName() + "/> element must contain either '" + COMMIT_INTERVAL_ATTR
+ "' " + "or '" + CHUNK_COMPLETION_POLICY_ATTR + "'.", element);
parserContext
.getReaderContext().error(
"The <" + element.getNodeName() + "/> element must contain either '"
+ COMMIT_INTERVAL_ATTR + "' " + "or '" + CHUNK_COMPLETION_POLICY_ATTR + "'.",
element);
}
}
String skipLimit = element.getAttribute("skip-limit");
ManagedMap<TypedStringValue, Boolean> skippableExceptions =
new ExceptionElementParser().parse(element, parserContext, "skippable-exception-classes");
ManagedMap<TypedStringValue, Boolean> skippableExceptions = new ExceptionElementParser().parse(element,
parserContext, "skippable-exception-classes");
if (StringUtils.hasText(skipLimit)) {
if (skippableExceptions == null) {
skippableExceptions = new ManagedMap<>();
@@ -134,9 +138,10 @@ public class ChunkElementParser {
propertyValues.addPropertyValue("skipLimit", skipLimit);
}
if (skippableExceptions != null) {
List<Element> exceptionClassElements = DomUtils.getChildElementsByTagName(element, "skippable-exception-classes");
List<Element> exceptionClassElements = DomUtils.getChildElementsByTagName(element,
"skippable-exception-classes");
if(!CollectionUtils.isEmpty(exceptionClassElements)) {
if (!CollectionUtils.isEmpty(exceptionClassElements)) {
skippableExceptions.setMergeEnabled(exceptionClassElements.get(0).hasAttribute(MERGE_ATTR)
&& Boolean.valueOf(exceptionClassElements.get(0).getAttribute(MERGE_ATTR)));
}
@@ -149,8 +154,8 @@ public class ChunkElementParser {
underspecified);
String retryLimit = element.getAttribute("retry-limit");
ManagedMap<TypedStringValue, Boolean> retryableExceptions =
new ExceptionElementParser().parse(element, parserContext, "retryable-exception-classes");
ManagedMap<TypedStringValue, Boolean> retryableExceptions = new ExceptionElementParser().parse(element,
parserContext, "retryable-exception-classes");
if (StringUtils.hasText(retryLimit)) {
if (retryableExceptions == null) {
retryableExceptions = new ManagedMap<>();
@@ -159,9 +164,10 @@ public class ChunkElementParser {
propertyValues.addPropertyValue("retryLimit", retryLimit);
}
if (retryableExceptions != null) {
List<Element> exceptionClassElements = DomUtils.getChildElementsByTagName(element, "retryable-exception-classes");
List<Element> exceptionClassElements = DomUtils.getChildElementsByTagName(element,
"retryable-exception-classes");
if(!CollectionUtils.isEmpty(exceptionClassElements)) {
if (!CollectionUtils.isEmpty(exceptionClassElements)) {
retryableExceptions.setMergeEnabled(exceptionClassElements.get(0).hasAttribute(MERGE_ATTR)
&& Boolean.valueOf(exceptionClassElements.get(0).getAttribute(MERGE_ATTR)));
}
@@ -199,50 +205,52 @@ public class ChunkElementParser {
/**
* Handle the ItemReader, ItemProcessor, and ItemWriter attributes/elements.
*/
private void handleItemHandler(AbstractBeanDefinition enclosing, String handlerName, String propertyName, String adapterClassName, boolean required,
Element element, ParserContext parserContext, MutablePropertyValues propertyValues, boolean underspecified) {
private void handleItemHandler(AbstractBeanDefinition enclosing, String handlerName, String propertyName,
String adapterClassName, boolean required, Element element, ParserContext parserContext,
MutablePropertyValues propertyValues, boolean underspecified) {
String refName = element.getAttribute(handlerName);
List<Element> children = DomUtils.getChildElementsByTagName(element, handlerName);
if (children.size() == 1) {
if (StringUtils.hasText(refName)) {
parserContext.getReaderContext().error(
"The <" + element.getNodeName() + "/> element may not have both a '" + handlerName
+ "' attribute and a <" + handlerName + "/> element.", element);
parserContext.getReaderContext()
.error("The <" + element.getNodeName() + "/> element may not have both a '" + handlerName
+ "' attribute and a <" + handlerName + "/> element.", element);
}
handleItemHandlerElement(enclosing, propertyName, adapterClassName, propertyValues, children.get(0), parserContext);
handleItemHandlerElement(enclosing, propertyName, adapterClassName, propertyValues, children.get(0),
parserContext);
}
else if (children.size() > 1) {
parserContext.getReaderContext().error(
"The <" + handlerName + "/> element may not appear more than once in a single <"
+ element.getNodeName() + "/>.", element);
parserContext.getReaderContext().error("The <" + handlerName
+ "/> element may not appear more than once in a single <" + element.getNodeName() + "/>.",
element);
}
else if (StringUtils.hasText(refName)) {
propertyValues.addPropertyValue(propertyName, new RuntimeBeanReference(refName));
}
else if (required && !underspecified) {
parserContext.getReaderContext().error(
"The <" + element.getNodeName() + "/> element has neither a '" + handlerName
+ "' attribute nor a <" + handlerName + "/> element.", element);
parserContext.getReaderContext().error("The <" + element.getNodeName() + "/> element has neither a '"
+ handlerName + "' attribute nor a <" + handlerName + "/> element.", element);
}
}
/**
* Handle the &lt;reader/&gt;, &lt;processor/&gt;, or &lt;writer/&gt; that
* is defined within the item handler.
* Handle the &lt;reader/&gt;, &lt;processor/&gt;, or &lt;writer/&gt; that is defined
* within the item handler.
*/
private void handleItemHandlerElement(AbstractBeanDefinition enclosing, String propertyName, String adapterClassName,
MutablePropertyValues propertyValues, Element element, ParserContext parserContext) {
private void handleItemHandlerElement(AbstractBeanDefinition enclosing, String propertyName,
String adapterClassName, MutablePropertyValues propertyValues, Element element,
ParserContext parserContext) {
List<Element> beanElements = DomUtils.getChildElementsByTagName(element, BEAN_ELE);
List<Element> refElements = DomUtils.getChildElementsByTagName(element, REF_ELE);
if (beanElements.size() + refElements.size() != 1) {
parserContext.getReaderContext().error(
"The <" + element.getNodeName() + "/> must have exactly one of either a <" + BEAN_ELE
+ "/> element or a <" + REF_ELE + "/> element.", element);
parserContext.getReaderContext()
.error("The <" + element.getNodeName() + "/> must have exactly one of either a <" + BEAN_ELE
+ "/> element or a <" + REF_ELE + "/> element.", element);
}
else if (beanElements.size() == 1) {
Element beanElement = beanElements.get(0);
BeanDefinitionHolder beanDefinitionHolder = parserContext.getDelegate().parseBeanDefinitionElement(
beanElement, enclosing);
BeanDefinitionHolder beanDefinitionHolder = parserContext.getDelegate()
.parseBeanDefinitionElement(beanElement, enclosing);
parserContext.getDelegate().decorateBeanDefinitionIfRequired(beanElement, beanDefinitionHolder);
propertyValues.addPropertyValue(propertyName, beanDefinitionHolder);
@@ -256,8 +264,7 @@ public class ChunkElementParser {
}
/**
* Handle the adapter-method attribute by using an
* AbstractMethodInvokingDelegator
* Handle the adapter-method attribute by using an AbstractMethodInvokingDelegator
*/
private void handleAdapterMethodAttribute(String propertyName, String adapterClassName,
MutablePropertyValues stepPvs, Element element) {
@@ -296,8 +303,8 @@ public class ChunkElementParser {
}
}
private void handleRetryListenerElements(ParserContext parserContext, Element element, ManagedList<BeanMetadataElement> beans,
BeanDefinition enclosing) {
private void handleRetryListenerElements(ParserContext parserContext, Element element,
ManagedList<BeanMetadataElement> beans, BeanDefinition enclosing) {
List<Element> listenerElements = DomUtils.getChildElementsByTagName(element, "listener");
if (listenerElements != null) {
for (Element listenerElement : listenerElements) {
@@ -306,7 +313,8 @@ public class ChunkElementParser {
}
}
private void handleStreamsElement(Element element, MutablePropertyValues propertyValues, ParserContext parserContext) {
private void handleStreamsElement(Element element, MutablePropertyValues propertyValues,
ParserContext parserContext) {
Element streamsElement = DomUtils.getChildElementByTagName(element, "streams");
if (streamsElement != null) {
ManagedList<RuntimeBeanReference> streamBeans = new ManagedList<>();

View File

@@ -19,8 +19,6 @@ import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
*
*
* @author Dave Syer
*
*/

View File

@@ -1,153 +1,150 @@
/*
* Copyright 2006-2021 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
*
* https://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.xml;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.AbstractStep;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Post-process jobs and steps defined using the batch namespace to inject
* dependencies.
*
* @author Dan Garrette
* @since 2.0.1
*/
public class CoreNamespacePostProcessor implements BeanPostProcessor, BeanFactoryPostProcessor, ApplicationContextAware {
private static final String DEFAULT_JOB_REPOSITORY_NAME = "jobRepository";
private static final String DEFAULT_TRANSACTION_MANAGER_NAME = "transactionManager";
private static final String JOB_FACTORY_PROPERTY_NAME = "jobParserJobFactoryBeanRef";
private static final String JOB_REPOSITORY_PROPERTY_NAME = "jobRepository";
private ApplicationContext applicationContext;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
for (String beanName : beanFactory.getBeanDefinitionNames()) {
injectJobRepositoryIntoSteps(beanName, beanFactory);
overrideStepClass(beanName, beanFactory);
}
}
/**
* Automatically inject job-repository from a job into its steps. Only
* inject if the step is an AbstractStep or StepParserStepFactoryBean.
*
* @param beanName
* @param beanFactory
*/
private void injectJobRepositoryIntoSteps(String beanName, ConfigurableListableBeanFactory beanFactory) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
if (bd.hasAttribute(JOB_FACTORY_PROPERTY_NAME)) {
MutablePropertyValues pvs = bd.getPropertyValues();
if (beanFactory.isTypeMatch(beanName, AbstractStep.class)) {
String jobName = (String) bd.getAttribute(JOB_FACTORY_PROPERTY_NAME);
PropertyValue jobRepository = BeanDefinitionUtils.getPropertyValue(jobName,
JOB_REPOSITORY_PROPERTY_NAME, beanFactory);
if (jobRepository != null) {
// Set the job's JobRepository onto the step
pvs.addPropertyValue(jobRepository);
}
else {
// No JobRepository found, so inject the default
RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference(DEFAULT_JOB_REPOSITORY_NAME);
pvs.addPropertyValue(JOB_REPOSITORY_PROPERTY_NAME, jobRepositoryBeanRef);
}
}
}
}
/**
* If any of the beans in the parent hierarchy is a &lt;step/&gt; with a
* &lt;tasklet/&gt;, then the bean class must be
* {@link StepParserStepFactoryBean}.
*
* @param beanName
* @param beanFactory
*/
private void overrideStepClass(String beanName, ConfigurableListableBeanFactory beanFactory) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
Object isNamespaceStep = BeanDefinitionUtils
.getAttribute(beanName, "isNamespaceStep", beanFactory);
if (isNamespaceStep != null && (Boolean) isNamespaceStep) {
((AbstractBeanDefinition) bd).setBeanClass(StepParserStepFactoryBean.class);
}
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return injectDefaults(bean);
}
/**
* Inject defaults into factory beans.
* <ul>
* <li>Inject "jobRepository" into any {@link JobParserJobFactoryBean}
* without a jobRepository.
* <li>Inject "transactionManager" into any
* {@link StepParserStepFactoryBean} without a transactionManager.
* </ul>
*
* @param bean
* @return
*/
private Object injectDefaults(Object bean) {
if (bean instanceof JobParserJobFactoryBean) {
JobParserJobFactoryBean fb = (JobParserJobFactoryBean) bean;
JobRepository jobRepository = fb.getJobRepository();
if (jobRepository == null) {
fb.setJobRepository((JobRepository) applicationContext.getBean(DEFAULT_JOB_REPOSITORY_NAME));
}
} else if (bean instanceof StepParserStepFactoryBean) {
StepParserStepFactoryBean<?, ?> fb = (StepParserStepFactoryBean<?, ?>) bean;
JobRepository jobRepository = fb.getJobRepository();
if (jobRepository == null) {
fb.setJobRepository((JobRepository) applicationContext.getBean(DEFAULT_JOB_REPOSITORY_NAME));
}
PlatformTransactionManager transactionManager = fb.getTransactionManager();
if (transactionManager == null && fb.requiresTransactionManager()) {
fb.setTransactionManager((PlatformTransactionManager) applicationContext
.getBean(DEFAULT_TRANSACTION_MANAGER_NAME));
}
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
/*
* Copyright 2006-2021 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
*
* https://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.xml;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.AbstractStep;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Post-process jobs and steps defined using the batch namespace to inject dependencies.
*
* @author Dan Garrette
* @since 2.0.1
*/
public class CoreNamespacePostProcessor
implements BeanPostProcessor, BeanFactoryPostProcessor, ApplicationContextAware {
private static final String DEFAULT_JOB_REPOSITORY_NAME = "jobRepository";
private static final String DEFAULT_TRANSACTION_MANAGER_NAME = "transactionManager";
private static final String JOB_FACTORY_PROPERTY_NAME = "jobParserJobFactoryBeanRef";
private static final String JOB_REPOSITORY_PROPERTY_NAME = "jobRepository";
private ApplicationContext applicationContext;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
for (String beanName : beanFactory.getBeanDefinitionNames()) {
injectJobRepositoryIntoSteps(beanName, beanFactory);
overrideStepClass(beanName, beanFactory);
}
}
/**
* Automatically inject job-repository from a job into its steps. Only inject if the
* step is an AbstractStep or StepParserStepFactoryBean.
* @param beanName
* @param beanFactory
*/
private void injectJobRepositoryIntoSteps(String beanName, ConfigurableListableBeanFactory beanFactory) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
if (bd.hasAttribute(JOB_FACTORY_PROPERTY_NAME)) {
MutablePropertyValues pvs = bd.getPropertyValues();
if (beanFactory.isTypeMatch(beanName, AbstractStep.class)) {
String jobName = (String) bd.getAttribute(JOB_FACTORY_PROPERTY_NAME);
PropertyValue jobRepository = BeanDefinitionUtils.getPropertyValue(jobName,
JOB_REPOSITORY_PROPERTY_NAME, beanFactory);
if (jobRepository != null) {
// Set the job's JobRepository onto the step
pvs.addPropertyValue(jobRepository);
}
else {
// No JobRepository found, so inject the default
RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference(DEFAULT_JOB_REPOSITORY_NAME);
pvs.addPropertyValue(JOB_REPOSITORY_PROPERTY_NAME, jobRepositoryBeanRef);
}
}
}
}
/**
* If any of the beans in the parent hierarchy is a &lt;step/&gt; with a
* &lt;tasklet/&gt;, then the bean class must be {@link StepParserStepFactoryBean}.
* @param beanName
* @param beanFactory
*/
private void overrideStepClass(String beanName, ConfigurableListableBeanFactory beanFactory) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
Object isNamespaceStep = BeanDefinitionUtils.getAttribute(beanName, "isNamespaceStep", beanFactory);
if (isNamespaceStep != null && (Boolean) isNamespaceStep) {
((AbstractBeanDefinition) bd).setBeanClass(StepParserStepFactoryBean.class);
}
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return injectDefaults(bean);
}
/**
* Inject defaults into factory beans.
* <ul>
* <li>Inject "jobRepository" into any {@link JobParserJobFactoryBean} without a
* jobRepository.
* <li>Inject "transactionManager" into any {@link StepParserStepFactoryBean} without
* a transactionManager.
* </ul>
* @param bean
* @return
*/
private Object injectDefaults(Object bean) {
if (bean instanceof JobParserJobFactoryBean) {
JobParserJobFactoryBean fb = (JobParserJobFactoryBean) bean;
JobRepository jobRepository = fb.getJobRepository();
if (jobRepository == null) {
fb.setJobRepository((JobRepository) applicationContext.getBean(DEFAULT_JOB_REPOSITORY_NAME));
}
}
else if (bean instanceof StepParserStepFactoryBean) {
StepParserStepFactoryBean<?, ?> fb = (StepParserStepFactoryBean<?, ?>) bean;
JobRepository jobRepository = fb.getJobRepository();
if (jobRepository == null) {
fb.setJobRepository((JobRepository) applicationContext.getBean(DEFAULT_JOB_REPOSITORY_NAME));
}
PlatformTransactionManager transactionManager = fb.getTransactionManager();
if (transactionManager == null && fb.requiresTransactionManager()) {
fb.setTransactionManager(
(PlatformTransactionManager) applicationContext.getBean(DEFAULT_TRANSACTION_MANAGER_NAME));
}
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}

View File

@@ -59,7 +59,6 @@ public class CoreNamespaceUtils {
/**
* Create the beans based on the content of the source.
*
* @param parserContext The parser context to be used.
* @param source The source for the auto registration.
*/
@@ -72,7 +71,8 @@ public class CoreNamespaceUtils {
}
private static void checkForStepScope(ParserContext parserContext, Object source) {
checkForScope(parserContext, source, XML_CONFIG_STEP_SCOPE_PROCESSOR_CLASS_NAME, STEP_SCOPE_PROCESSOR_BEAN_NAME);
checkForScope(parserContext, source, XML_CONFIG_STEP_SCOPE_PROCESSOR_CLASS_NAME,
STEP_SCOPE_PROCESSOR_BEAN_NAME);
}
private static void checkForJobScope(ParserContext parserContext, Object source) {
@@ -85,14 +85,14 @@ public class CoreNamespaceUtils {
String[] beanNames = parserContext.getRegistry().getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition bd = parserContext.getRegistry().getBeanDefinition(beanName);
if (scopeClassName.equals(bd.getBeanClassName()) || JAVA_CONFIG_SCOPE_CLASS_NAME.equals(bd.getBeanClassName())) {
if (scopeClassName.equals(bd.getBeanClassName())
|| JAVA_CONFIG_SCOPE_CLASS_NAME.equals(bd.getBeanClassName())) {
foundScope = true;
break;
}
}
if (!foundScope) {
BeanDefinitionBuilder stepScopeBuilder = BeanDefinitionBuilder
.genericBeanDefinition(scopeClassName);
BeanDefinitionBuilder stepScopeBuilder = BeanDefinitionBuilder.genericBeanDefinition(scopeClassName);
AbstractBeanDefinition abd = stepScopeBuilder.getBeanDefinition();
abd.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
abd.setSource(source);
@@ -102,15 +102,15 @@ public class CoreNamespaceUtils {
/**
* Register a {@link Comparator} to be used to sort {@link StateTransition}s
*
* @param parserContext
*/
private static void addStateTransitionComparator(ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
if (!stateTransitionComparatorAlreadyDefined(registry)) {
AbstractBeanDefinition defaultStateTransitionComparator = BeanDefinitionBuilder.genericBeanDefinition(
DefaultStateTransitionComparator.class).getBeanDefinition();
registry.registerBeanDefinition(DefaultStateTransitionComparator.STATE_TRANSITION_COMPARATOR, defaultStateTransitionComparator);
AbstractBeanDefinition defaultStateTransitionComparator = BeanDefinitionBuilder
.genericBeanDefinition(DefaultStateTransitionComparator.class).getBeanDefinition();
registry.registerBeanDefinition(DefaultStateTransitionComparator.STATE_TRANSITION_COMPARATOR,
defaultStateTransitionComparator);
}
}
@@ -120,14 +120,13 @@ public class CoreNamespaceUtils {
/**
* Register a RangePropertyEditor if one does not already exist.
*
* @param parserContext
*/
private static void addRangePropertyEditor(ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
if (!rangeArrayEditorAlreadyDefined(registry)) {
AbstractBeanDefinition customEditorConfigurer = BeanDefinitionBuilder.genericBeanDefinition(
CUSTOM_EDITOR_CONFIGURER_CLASS_NAME).getBeanDefinition();
AbstractBeanDefinition customEditorConfigurer = BeanDefinitionBuilder
.genericBeanDefinition(CUSTOM_EDITOR_CONFIGURER_CLASS_NAME).getBeanDefinition();
customEditorConfigurer.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
ManagedMap<String, String> editors = new ManagedMap<>();
editors.put(RANGE_ARRAY_CLASS_NAME, RANGE_ARRAY_EDITOR_CLASS_NAME);
@@ -166,8 +165,8 @@ public class CoreNamespaceUtils {
private static void addCoreNamespacePostProcessor(ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
if (!coreNamespaceBeanPostProcessorAlreadyDefined(registry)) {
AbstractBeanDefinition postProcessorBeanDef = BeanDefinitionBuilder.genericBeanDefinition(
CORE_NAMESPACE_POST_PROCESSOR_CLASS_NAME).getBeanDefinition();
AbstractBeanDefinition postProcessorBeanDef = BeanDefinitionBuilder
.genericBeanDefinition(CORE_NAMESPACE_POST_PROCESSOR_CLASS_NAME).getBeanDefinition();
postProcessorBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(CORE_NAMESPACE_POST_PROCESSOR_CLASS_NAME, postProcessorBeanDef);
}
@@ -184,9 +183,8 @@ public class CoreNamespaceUtils {
}
/**
* Should this element be treated as incomplete? If it has a parent or is
* abstract, then it may not have all properties.
*
* Should this element be treated as incomplete? If it has a parent or is abstract,
* then it may not have all properties.
* @param element to be evaluated.
* @return TRUE if the element is abstract or has a parent
*/
@@ -204,12 +202,11 @@ public class CoreNamespaceUtils {
}
/**
* Check that the schema location declared in the source file being parsed
* matches the Spring Batch version. (The old 2.0 schema is not 100%
* compatible with the new parser, so it is an error to explicitly define
* 2.0. It might be an error to declare spring-batch.xsd as an alias, but
* you are only going to find that out when one of the sub parses breaks.)
*
* Check that the schema location declared in the source file being parsed matches the
* Spring Batch version. (The old 2.0 schema is not 100% compatible with the new
* parser, so it is an error to explicitly define 2.0. It might be an error to declare
* spring-batch.xsd as an alias, but you are only going to find that out when one of
* the sub parses breaks.)
* @param element the element that is to be parsed next
* @return true if we find a schema declaration that matches
*/

View File

@@ -24,38 +24,37 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
* Internal parser for the &lt;decision/&gt; elements inside a job. A decision
* element references a bean definition for a
* {@link org.springframework.batch.core.job.flow.JobExecutionDecider}
* and goes on to list a set of transitions to other states with &lt;next
* on="pattern" to="stepName"/&gt;. Used by the {@link JobParser}.
*
* Internal parser for the &lt;decision/&gt; elements inside a job. A decision element
* references a bean definition for a
* {@link org.springframework.batch.core.job.flow.JobExecutionDecider} and goes on to list
* a set of transitions to other states with &lt;next on="pattern" to="stepName"/&gt;.
* Used by the {@link JobParser}.
*
* @see JobParser
*
* @author Dave Syer
*
*
*/
public class DecisionParser {
/**
* Parse the decision and turn it into a list of transitions.
*
* @param element the &lt;decision/gt; element to parse
* @param parserContext the parser context for the bean factory
* @return a collection of bean definitions for
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
* instances objects
* @return a collection of bean definitions for
* {@link org.springframework.batch.core.job.flow.support.StateTransition} instances
* objects
*/
public Collection<BeanDefinition> parse(Element element, ParserContext parserContext) {
String refAttribute = element.getAttribute("decider");
String idAttribute = element.getAttribute("id");
BeanDefinitionBuilder stateBuilder =
BeanDefinitionBuilder.genericBeanDefinition("org.springframework.batch.core.job.flow.support.state.DecisionState");
BeanDefinitionBuilder stateBuilder = BeanDefinitionBuilder
.genericBeanDefinition("org.springframework.batch.core.job.flow.support.state.DecisionState");
stateBuilder.addConstructorArgValue(new RuntimeBeanReference(refAttribute));
stateBuilder.addConstructorArgValue(idAttribute);
return InlineFlowParser.getNextElements(parserContext, stateBuilder.getBeanDefinition(), element);
}
}

View File

@@ -26,7 +26,8 @@ import org.w3c.dom.Element;
public class ExceptionElementParser {
public ManagedMap<TypedStringValue, Boolean> parse(Element element, ParserContext parserContext, String exceptionListName) {
public ManagedMap<TypedStringValue, Boolean> parse(Element element, ParserContext parserContext,
String exceptionListName) {
List<Element> children = DomUtils.getChildElementsByTagName(element, exceptionListName);
if (children.size() == 1) {
ManagedMap<TypedStringValue, Boolean> map = new ManagedMap<>();
@@ -37,9 +38,9 @@ public class ExceptionElementParser {
return map;
}
else if (children.size() > 1) {
parserContext.getReaderContext().error(
"The <" + exceptionListName + "/> element may not appear more than once in a single <"
+ element.getNodeName() + "/>.", element);
parserContext.getReaderContext().error("The <" + exceptionListName
+ "/> element may not appear more than once in a single <" + element.getNodeName() + "/>.",
element);
}
return null;
}
@@ -51,4 +52,5 @@ public class ExceptionElementParser {
map.put(new TypedStringValue(className, Class.class), include);
}
}
}

View File

@@ -27,11 +27,10 @@ import org.w3c.dom.Element;
/**
* Internal parser for the &lt;flow/&gt; elements inside a job.
*
*
* @see JobParser
*
* @author Dave Syer
*
*
*/
public class FlowElementParser {
@@ -41,12 +40,11 @@ public class FlowElementParser {
/**
* Parse the flow and turn it into a list of transitions.
*
* @param element the &lt;flow/gt; element to parse
* @param parserContext the parser context for the bean factory
* @return a collection of bean definitions for
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
* instances objects
* {@link org.springframework.batch.core.job.flow.support.StateTransition} instances
* objects
*/
public Collection<BeanDefinition> parse(Element element, ParserContext parserContext) {
@@ -65,4 +63,5 @@ public class FlowElementParser {
return InlineFlowParser.getNextElements(parserContext, stateBuilder.getBeanDefinition(), element);
}
}

View File

@@ -28,15 +28,15 @@ import org.w3c.dom.Element;
*
*/
public class InlineFlowParser extends AbstractFlowParser {
private final String flowName;
/**
* Construct a {@link InlineFlowParser} with the specified name and using the
* provided job repository ref.
*
* Construct a {@link InlineFlowParser} with the specified name and using the provided
* job repository ref.
* @param flowName the name of the flow
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
* from the enclosing tag
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean} from the
* enclosing tag
*/
public InlineFlowParser(String flowName, String jobFactoryRef) {
this.flowName = flowName;
@@ -57,10 +57,12 @@ public class InlineFlowParser extends AbstractFlowParser {
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.getRawBeanDefinition().setAttribute("flowName", flowName);
builder.addPropertyValue("name", flowName);
builder.addPropertyValue("stateTransitionComparator", new RuntimeBeanReference(DefaultStateTransitionComparator.STATE_TRANSITION_COMPARATOR));
builder.addPropertyValue("stateTransitionComparator",
new RuntimeBeanReference(DefaultStateTransitionComparator.STATE_TRANSITION_COMPARATOR));
super.doParse(element, parserContext, builder);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.popAndRegisterContainingComponent();
}
}

View File

@@ -26,14 +26,12 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
* Internal parser for the &lt;step/&gt; elements inside a job. A step element
* references a bean definition for a
* {@link org.springframework.batch.core.Step} and goes on to (optionally) list
* a set of transitions from that step to others with &lt;next on="pattern"
* to="stepName"/&gt;. Used by the {@link JobParser}.
*
* Internal parser for the &lt;step/&gt; elements inside a job. A step element references
* a bean definition for a {@link org.springframework.batch.core.Step} and goes on to
* (optionally) list a set of transitions from that step to others with &lt;next
* on="pattern" to="stepName"/&gt;. Used by the {@link JobParser}.
*
* @see JobParser
*
* @author Dave Syer
* @author Thomas Risberg
* @since 2.0
@@ -42,14 +40,13 @@ public class InlineStepParser extends AbstractStepParser {
/**
* Parse the step and turn it into a list of transitions.
*
* @param element the &lt;step/gt; element to parse
* @param parserContext the parser context for the bean factory
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
* from the enclosing tag
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean} from the
* enclosing tag
* @return a collection of bean definitions for
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
* instances objects
* {@link org.springframework.batch.core.job.flow.support.StateTransition} instances
* objects
*/
public Collection<BeanDefinition> parse(Element element, ParserContext parserContext, String jobFactoryRef) {

View File

@@ -22,8 +22,8 @@ import org.springframework.batch.core.listener.JobListenerMetaData;
import org.springframework.batch.core.listener.ListenerMetaData;
/**
* Parser for a step listener element. Builds a {@link JobListenerFactoryBean}
* using attributes from the configuration.
* Parser for a step listener element. Builds a {@link JobListenerFactoryBean} using
* attributes from the configuration.
*
* @author Dan Garrette
* @since 2.0

View File

@@ -32,11 +32,11 @@ import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Parser for the &lt;job/&gt; element in the Batch namespace. Sets up and returns
* a bean definition for a {@link org.springframework.batch.core.Job}.
*
* Parser for the &lt;job/&gt; element in the Batch namespace. Sets up and returns a bean
* definition for a {@link org.springframework.batch.core.Job}.
*
* @author Dave Syer
*
*
*/
public class JobParser extends AbstractSingleBeanDefinitionParser {
@@ -57,9 +57,9 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
/**
* Create a bean definition for a
* {@link org.springframework.batch.core.job.flow.FlowJob}. Nested step
* elements are delegated to an {@link InlineStepParser}.
*
* {@link org.springframework.batch.core.job.flow.FlowJob}. Nested step elements are
* delegated to an {@link InlineStepParser}.
*
* @see AbstractSingleBeanDefinitionParser#doParse(Element, ParserContext,
* BeanDefinitionBuilder)
*/
@@ -68,9 +68,10 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
if (!CoreNamespaceUtils.namespaceMatchesVersion(element)) {
parserContext.getReaderContext().error(
"You are using a version of the spring-batch XSD that is not compatible with Spring Batch 3.0." +
" Please upgrade your schema declarations (or use the spring-batch.xsd alias if you are " +
"feeling lucky).", element);
"You are using a version of the spring-batch XSD that is not compatible with Spring Batch 3.0."
+ " Please upgrade your schema declarations (or use the spring-batch.xsd alias if you are "
+ "feeling lucky).",
element);
return;
}
@@ -110,9 +111,9 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
if (isAbstract) {
for (String tagName : Arrays.asList("step", "decision", "split")) {
if (!DomUtils.getChildElementsByTagName(element, tagName).isEmpty()) {
parserContext.getReaderContext().error(
"The <" + tagName + "/> element may not appear on a <job/> with abstract=\"true\" ["
+ jobName + "]", element);
parserContext.getReaderContext().error("The <" + tagName
+ "/> element may not appear on a <job/> with abstract=\"true\" [" + jobName + "]",
element);
}
}
}
@@ -144,15 +145,14 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
parserContext.popAndRegisterContainingComponent();
}
else if (listenersElements.size() > 1) {
parserContext.getReaderContext().error(
"The '<listeners/>' element may not appear more than once in a single <job/>.", element);
parserContext.getReaderContext()
.error("The '<listeners/>' element may not appear more than once in a single <job/>.", element);
}
}
/**
* Parse the element to retrieve {@link BeanMetadataElement}.
*
* @param element The {@link Element} to be parsed.
* @param parserContext The {@link ParserContext}.
* @return The {@link BeanMetadataElement} extracted from the element parameter.
@@ -166,8 +166,8 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
return new RuntimeBeanReference(refAttribute);
}
else if (beanElement != null) {
BeanDefinitionHolder beanDefinitionHolder = parserContext.getDelegate().parseBeanDefinitionElement(
beanElement);
BeanDefinitionHolder beanDefinitionHolder = parserContext.getDelegate()
.parseBeanDefinitionElement(beanElement);
parserContext.getDelegate().decorateBeanDefinitionIfRequired(beanElement, beanDefinitionHolder);
return beanDefinitionHolder;
}
@@ -175,8 +175,8 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
return (BeanMetadataElement) parserContext.getDelegate().parsePropertySubElement(refElement, null);
}
parserContext.getReaderContext().error(
"One of ref attribute or a nested bean definition or ref element must be specified", element);
parserContext.getReaderContext()
.error("One of ref attribute or a nested bean definition or ref element must be specified", element);
return null;
}

View File

@@ -1,172 +1,168 @@
/*
* Copyright 2006-2022 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
*
* https://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.xml;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.JobParametersIncrementer;
import org.springframework.batch.core.JobParametersValidator;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.job.flow.FlowJob;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* This {@link FactoryBean} is used by the batch namespace parser to create
* {@link FlowJob} objects. It stores all of the properties that are
* configurable on the &lt;job/&gt;.
*
* @author Dan Garrette
* @author Dave Syer
* @since 2.0.1
*/
public class JobParserJobFactoryBean implements SmartFactoryBean<FlowJob> {
private String name;
private Boolean restartable;
private JobRepository jobRepository;
private JobParametersValidator jobParametersValidator;
private JobExecutionListener[] jobExecutionListeners;
private JobParametersIncrementer jobParametersIncrementer;
private Flow flow;
/**
* Constructor for the factory bean that initializes the name.
*
* @param name The name to be used by the factory bean.
*/
public JobParserJobFactoryBean(String name) {
this.name = name;
}
@Override
public final FlowJob getObject() throws Exception {
Assert.isTrue(StringUtils.hasText(name), "The job must have an id.");
FlowJob flowJob = new FlowJob(name);
if (restartable != null) {
flowJob.setRestartable(restartable);
}
if (jobRepository != null) {
flowJob.setJobRepository(jobRepository);
}
if (jobParametersValidator != null) {
flowJob.setJobParametersValidator(jobParametersValidator);
}
if (jobExecutionListeners != null) {
flowJob.setJobExecutionListeners(jobExecutionListeners);
}
if (jobParametersIncrementer != null) {
flowJob.setJobParametersIncrementer(jobParametersIncrementer);
}
if (flow != null) {
flowJob.setFlow(flow);
}
flowJob.afterPropertiesSet();
return flowJob;
}
/**
* Set the restartable flag for the factory bean.
*
* @param restartable The restartable flag to be used by the factory bean.
*/
public void setRestartable(Boolean restartable) {
this.restartable = restartable;
}
/**
* Set the {@link JobRepository} for the factory bean.
*
* @param jobRepository The {@link JobRepository} to be used by the factory bean.
*/
public void setJobRepository(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
/**
* Set the {@link JobParametersValidator} for the factory bean.
*
* @param jobParametersValidator The {@link JobParametersValidator} to be used by the factory bean.
*/
public void setJobParametersValidator(JobParametersValidator jobParametersValidator) {
this.jobParametersValidator = jobParametersValidator;
}
/**
* @return The {@link JobRepository} used by the factory bean.
*/
public JobRepository getJobRepository() {
return this.jobRepository;
}
public void setJobExecutionListeners(JobExecutionListener[] jobExecutionListeners) {
this.jobExecutionListeners = jobExecutionListeners;
}
/**
* Set the {@link JobParametersIncrementer} for the factory bean.
*
* @param jobParametersIncrementer The {@link JobParametersIncrementer} to be used by the factory bean.
*/
public void setJobParametersIncrementer(JobParametersIncrementer jobParametersIncrementer) {
this.jobParametersIncrementer = jobParametersIncrementer;
}
/**
* Set the flow for the factory bean.
*
* @param flow The {@link Flow} to be used by the factory bean.
*/
public void setFlow(Flow flow) {
this.flow = flow;
}
@Override
public Class<FlowJob> getObjectType() {
return FlowJob.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public boolean isEagerInit() {
return true;
}
@Override
public boolean isPrototype() {
return false;
}
}
/*
* Copyright 2006-2022 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
*
* https://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.xml;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.JobParametersIncrementer;
import org.springframework.batch.core.JobParametersValidator;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.job.flow.FlowJob;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* This {@link FactoryBean} is used by the batch namespace parser to create
* {@link FlowJob} objects. It stores all of the properties that are configurable on the
* &lt;job/&gt;.
*
* @author Dan Garrette
* @author Dave Syer
* @since 2.0.1
*/
public class JobParserJobFactoryBean implements SmartFactoryBean<FlowJob> {
private String name;
private Boolean restartable;
private JobRepository jobRepository;
private JobParametersValidator jobParametersValidator;
private JobExecutionListener[] jobExecutionListeners;
private JobParametersIncrementer jobParametersIncrementer;
private Flow flow;
/**
* Constructor for the factory bean that initializes the name.
* @param name The name to be used by the factory bean.
*/
public JobParserJobFactoryBean(String name) {
this.name = name;
}
@Override
public final FlowJob getObject() throws Exception {
Assert.isTrue(StringUtils.hasText(name), "The job must have an id.");
FlowJob flowJob = new FlowJob(name);
if (restartable != null) {
flowJob.setRestartable(restartable);
}
if (jobRepository != null) {
flowJob.setJobRepository(jobRepository);
}
if (jobParametersValidator != null) {
flowJob.setJobParametersValidator(jobParametersValidator);
}
if (jobExecutionListeners != null) {
flowJob.setJobExecutionListeners(jobExecutionListeners);
}
if (jobParametersIncrementer != null) {
flowJob.setJobParametersIncrementer(jobParametersIncrementer);
}
if (flow != null) {
flowJob.setFlow(flow);
}
flowJob.afterPropertiesSet();
return flowJob;
}
/**
* Set the restartable flag for the factory bean.
* @param restartable The restartable flag to be used by the factory bean.
*/
public void setRestartable(Boolean restartable) {
this.restartable = restartable;
}
/**
* Set the {@link JobRepository} for the factory bean.
* @param jobRepository The {@link JobRepository} to be used by the factory bean.
*/
public void setJobRepository(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
/**
* Set the {@link JobParametersValidator} for the factory bean.
* @param jobParametersValidator The {@link JobParametersValidator} to be used by the
* factory bean.
*/
public void setJobParametersValidator(JobParametersValidator jobParametersValidator) {
this.jobParametersValidator = jobParametersValidator;
}
/**
* @return The {@link JobRepository} used by the factory bean.
*/
public JobRepository getJobRepository() {
return this.jobRepository;
}
public void setJobExecutionListeners(JobExecutionListener[] jobExecutionListeners) {
this.jobExecutionListeners = jobExecutionListeners;
}
/**
* Set the {@link JobParametersIncrementer} for the factory bean.
* @param jobParametersIncrementer The {@link JobParametersIncrementer} to be used by
* the factory bean.
*/
public void setJobParametersIncrementer(JobParametersIncrementer jobParametersIncrementer) {
this.jobParametersIncrementer = jobParametersIncrementer;
}
/**
* Set the flow for the factory bean.
* @param flow The {@link Flow} to be used by the factory bean.
*/
public void setFlow(Flow flow) {
this.flow = flow;
}
@Override
public Class<FlowJob> getObjectType() {
return FlowJob.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public boolean isEagerInit() {
return true;
}
@Override
public boolean isPrototype() {
return false;
}
}

View File

@@ -27,8 +27,8 @@ import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Parser for the &lt;job-repository/&gt; element in the Batch namespace. Sets up
* and returns a JobRepositoryFactoryBean.
* Parser for the &lt;job-repository/&gt; element in the Batch namespace. Sets up and
* returns a JobRepositoryFactoryBean.
*
* @author Thomas Risberg
* @since 2.0
@@ -65,7 +65,7 @@ public class JobRepositoryParser extends AbstractSingleBeanDefinitionParser {
CoreNamespaceUtils.autoregisterBeansForNamespace(parserContext, element);
String dataSource = element.getAttribute("data-source");
String jdbcOperations = element.getAttribute("jdbc-operations");
String transactionManager = element.getAttribute("transaction-manager");
@@ -88,8 +88,8 @@ public class JobRepositoryParser extends AbstractSingleBeanDefinitionParser {
builder.addPropertyReference("jdbcOperations", jdbcOperations);
}
if (StringUtils.hasText(isolationLevelForCreate)) {
builder.addPropertyValue("isolationLevelForCreate", DefaultTransactionDefinition.PREFIX_ISOLATION
+ isolationLevelForCreate);
builder.addPropertyValue("isolationLevelForCreate",
DefaultTransactionDefinition.PREFIX_ISOLATION + isolationLevelForCreate);
}
if (StringUtils.hasText(tablePrefix)) {
builder.addPropertyValue("tablePrefix", tablePrefix);
@@ -107,4 +107,5 @@ public class JobRepositoryParser extends AbstractSingleBeanDefinitionParser {
builder.setRole(BeanDefinition.ROLE_SUPPORT);
}
}

View File

@@ -35,10 +35,10 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* Convenience factory for SimpleFlow instances for use in XML namespace. It
* replaces the states in the input with proxies that have a unique name formed
* from the flow name and the original state name (unless the name is already in
* that form, in which case it is not modified).
* Convenience factory for SimpleFlow instances for use in XML namespace. It replaces the
* states in the input with proxies that have a unique name formed from the flow name and
* the original state name (unless the name is already in that form, in which case it is
* not modified).
*
* @author Dave Syer
* @author Michael Minella
@@ -72,7 +72,6 @@ public class SimpleFlowFactoryBean implements FactoryBean<SimpleFlow>, Initializ
/**
* The name of the flow that is created by this factory.
*
* @param name the value of the name
*/
public void setName(String name) {
@@ -81,10 +80,8 @@ public class SimpleFlowFactoryBean implements FactoryBean<SimpleFlow>, Initializ
}
/**
* The raw state transitions for the flow. They will be transformed into
* proxies that have the same behavior but unique names prefixed with the
* flow name.
*
* The raw state transitions for the flow. They will be transformed into proxies that
* have the same behavior but unique names prefixed with the flow name.
* @param stateTransitions the list of transitions
*/
public void setStateTransitions(List<StateTransition> stateTransitions) {
@@ -93,19 +90,20 @@ public class SimpleFlowFactoryBean implements FactoryBean<SimpleFlow>, Initializ
/**
* Check mandatory properties (name).
*
* @throws Exception thrown if error occurs.
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.hasText(name, "The flow must have a name");
if(flowType == null) {
if (flowType == null) {
flowType = SimpleFlow.class;
}
}
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
@Override
@@ -135,10 +133,9 @@ public class SimpleFlowFactoryBean implements FactoryBean<SimpleFlow>, Initializ
}
/**
* Convenience method to get a state that proxies the input but with a
* different name, appropriate to this flow. If the state is a StepState
* then the step name is also changed.
*
* Convenience method to get a state that proxies the input but with a different name,
* appropriate to this flow. If the state is a StepState then the step name is also
* changed.
* @param state
* @return
*/
@@ -157,14 +154,12 @@ public class SimpleFlowFactoryBean implements FactoryBean<SimpleFlow>, Initializ
/**
* Provides an extension point to provide alternative {@link StepState}
* implementations within a {@link SimpleFlow}
*
* @param state The state that will be used to create the StepState
* @param oldName The name to be replaced
* @param stateName The name for the new State
* @return a state for the requested data
*/
protected State createNewStepState(State state, String oldName,
String stateName) {
protected State createNewStepState(State state, String oldName, String stateName) {
return new StepState(stateName, ((StepState) state).getStep(oldName));
}
@@ -179,13 +174,14 @@ public class SimpleFlowFactoryBean implements FactoryBean<SimpleFlow>, Initializ
}
/**
* A State that proxies a delegate and changes its name but leaves its
* behavior unchanged.
* A State that proxies a delegate and changes its name but leaves its behavior
* unchanged.
*
* @author Dave Syer
*
*/
public static class DelegateState extends AbstractState implements FlowHolder {
private final State state;
private DelegateState(String name, State state) {
@@ -212,7 +208,7 @@ public class SimpleFlowFactoryBean implements FactoryBean<SimpleFlow>, Initializ
@Override
public Collection<Flow> getFlows() {
return (state instanceof FlowHolder) ? ((FlowHolder)state).getFlows() : Collections.<Flow>emptyList();
return (state instanceof FlowHolder) ? ((FlowHolder) state).getFlows() : Collections.<Flow>emptyList();
}
}

View File

@@ -33,14 +33,13 @@ import org.w3c.dom.Element;
/**
* Internal parser for the &lt;split/&gt; elements inside a job. A split element
* optionally references a bean definition for a {@link TaskExecutor} and goes
* on to list a set of transitions to other states with &lt;next on="pattern"
* to="stepName"/&gt;. Used by the {@link JobParser}.
*
* optionally references a bean definition for a {@link TaskExecutor} and goes on to list
* a set of transitions to other states with &lt;next on="pattern" to="stepName"/&gt;.
* Used by the {@link JobParser}.
*
* @see JobParser
*
* @author Dave Syer
*
*
*/
public class SplitParser {
@@ -49,11 +48,9 @@ public class SplitParser {
private final String jobFactoryRef;
/**
* Construct a {@link InlineFlowParser} using the provided job repository
* ref.
*
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
* from the enclosing tag
* Construct a {@link InlineFlowParser} using the provided job repository ref.
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean} from the
* enclosing tag
*/
public SplitParser(String jobFactoryRef) {
this.jobFactoryRef = jobFactoryRef;
@@ -61,12 +58,11 @@ public class SplitParser {
/**
* Parse the split and turn it into a list of transitions.
*
* @param element the &lt;split/gt; element to parse
* @param parserContext the parser context for the bean factory
* @return a collection of bean definitions for
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
* instances objects
* {@link org.springframework.batch.core.job.flow.support.StateTransition} instances
* objects
*/
public Collection<BeanDefinition> parse(Element element, ParserContext parserContext) {

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