[BATCH-430] Incremental commit of exception moving

This commit is contained in:
nebhale
2008-03-07 11:54:20 +00:00
parent a60fc1e621
commit 8c2901093e
106 changed files with 736 additions and 848 deletions

View File

@@ -33,7 +33,7 @@ import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ExecutionContextUserSupport;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.exception.ResetFailedException;
import org.springframework.batch.item.ResetFailedException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
@@ -48,62 +48,52 @@ import org.springframework.util.StringUtils;
/**
* <p>
* Simple input source that opens a JDBC cursor and continually retrieves the
* next row in the ResultSet. It is extremely important to note that the
* JdbcDriver used must be version 3.0 or higher. This is because earlier
* versions do not support holding a ResultSet open over commits.
* Simple input source that opens a JDBC cursor and continually retrieves the next row in the ResultSet. It is extremely
* important to note that the JdbcDriver used must be version 3.0 or higher. This is because earlier versions do not
* support holding a ResultSet open over commits.
* </p>
*
* <p>
* Each call to {@link #read()} will call the provided RowMapper, passing in the
* ResultSet. There is currently no wrapping of the ResultSet to suppress calls
* to next(). However, if the RowMapper (mistakenly) increments the current row,
* the next call to read will verify that the current row is at the expected
* position and throw a DataAccessException if it is not. This means that, in
* theory, a RowMapper could read ahead, as long as it returns the row back to
* the correct position before returning. The reason for such strictness on the
* ResultSet is due to the need to maintain control for transactions,
* restartability and skippability. This ensures that each call to
* {@link #read()} returns the ResultSet at the correct line, regardless of
* rollbacks, restarts, or skips.
* Each call to {@link #read()} will call the provided RowMapper, passing in the ResultSet. There is currently no
* wrapping of the ResultSet to suppress calls to next(). However, if the RowMapper (mistakenly) increments the current
* row, the next call to read will verify that the current row is at the expected position and throw a
* DataAccessException if it is not. This means that, in theory, a RowMapper could read ahead, as long as it returns the
* row back to the correct position before returning. The reason for such strictness on the ResultSet is due to the need
* to maintain control for transactions, restartability and skippability. This ensures that each call to {@link #read()}
* returns the ResultSet at the correct line, regardless of rollbacks, restarts, or skips.
* </p>
*
* <p>
* {@link ExecutionContext}: The current row is returned as restart data, and
* when restored from that same data, the cursor is opened and the current row
* set to the value within the restart data. Two values are stored: the current
* {@link ExecutionContext}: The current row is returned as restart data, and when restored from that same data, the
* cursor is opened and the current row set to the value within the restart data. Two values are stored: the current
* line being processed and the number of lines that have been skipped.
* </p>
*
* <p>
* Transactions: The same ResultSet is held open regardless of commits or roll
* backs in a surrounding transaction. This means that when such a transaction
* is committed, the input source is notified through the {@link #mark()} and
* {@link #reset()} so that it can save it's current row number. Later, if the
* transaction is rolled back, the current row can be moved back to the same row
* number as it was on when commit was called.
* Transactions: The same ResultSet is held open regardless of commits or roll backs in a surrounding transaction. This
* means that when such a transaction is committed, the input source is notified through the {@link #mark()} and
* {@link #reset()} so that it can save it's current row number. Later, if the transaction is rolled back, the current
* row can be moved back to the same row number as it was on when commit was called.
* </p>
*
* <p>
* Calling skip will indicate that a record is bad and should not be
* re-presented to the user if the transaction is rolled back. For example, if
* row 2 is read in, and found to be bad, calling skip will inform the
* {@link ItemReader}. If reading is then continued, and a rollback is
* necessary because of an error on output, the input source will be returned to
* row 1. Calling read while on row 1 will move the current row to 3, not 2,
* because 2 has been marked as skipped.
* Calling skip will indicate that a record is bad and should not be re-presented to the user if the transaction is
* rolled back. For example, if row 2 is read in, and found to be bad, calling skip will inform the {@link ItemReader}.
* If reading is then continued, and a rollback is necessary because of an error on output, the input source will be
* returned to row 1. Calling read while on row 1 will move the current row to 3, not 2, because 2 has been marked as
* skipped.
* </p>
*
* <p>
* Calling close on this {@link ItemStream} will cause all resources it is
* currently using to be freed. (Connection, ResultSet, etc). It is then illegal
* to call {@link #read()} again until it has been opened.
* Calling close on this {@link ItemStream} will cause all resources it is currently using to be freed. (Connection,
* ResultSet, etc). It is then illegal to call {@link #read()} again until it has been opened.
* </p>
*
* @author Lucas Ward
* @author Peter Zozom
*/
public class JdbcCursorItemReader extends ExecutionContextUserSupport implements ItemReader, InitializingBean, ItemStream, Skippable {
public class JdbcCursorItemReader extends ExecutionContextUserSupport implements ItemReader, InitializingBean,
ItemStream, Skippable {
private static Log log = LogFactory.getLog(JdbcCursorItemReader.class);
@@ -151,7 +141,7 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
private boolean initialized = false;
private boolean saveState = false;
public JdbcCursorItemReader() {
setName(JdbcCursorItemReader.class.getSimpleName());
}
@@ -159,8 +149,7 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
/**
* Assert that mandatory properties are set.
*
* @throws IllegalArgumentException if either data source or sql properties
* not set.
* @throws IllegalArgumentException if either data source or sql properties not set.
*/
public void afterPropertiesSet() throws Exception {
Assert.notNull(dataSource, "DataSOurce must be provided");
@@ -177,11 +166,10 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/**
* Increment the cursor to the next row, validating the cursor position and
* passing the resultset to the RowMapper. If read has not been called on
* this instance before, the cursor will be opened. If there are skipped
* records for this commit scope, an internal list of skipped records will
* be checked to ensure that only a valid row is given to the mapper.
* Increment the cursor to the next row, validating the cursor position and passing the resultset to the RowMapper.
* If read has not been called on this instance before, the cursor will be opened. If there are skipped records for
* this commit scope, an internal list of skipped records will be checked to ensure that only a valid row is given
* to the mapper.
*
* @returns Object returned by RowMapper
* @throws DataAccessException
@@ -198,8 +186,7 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
try {
if (!rs.next()) {
return null;
}
else {
} else {
currentProcessedRow++;
if (!skippedRows.isEmpty()) {
// while is necessary to handle successive skips.
@@ -217,8 +204,7 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
return mappedResult;
}
}
catch (SQLException se) {
} catch (SQLException se) {
throw getExceptionTranslator().translate("Trying to process next row", sql, se);
}
@@ -229,8 +215,7 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/**
* Mark the current row. Calling reset will cause the result set to be set
* to the current row when mark was called.
* Mark the current row. Calling reset will cause the result set to be set to the current row when mark was called.
*/
public void mark() {
lastCommittedRow = currentProcessedRow;
@@ -247,22 +232,19 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
currentProcessedRow = lastCommittedRow;
if (currentProcessedRow > 0) {
rs.absolute((int) currentProcessedRow);
}
else {
} else {
rs.beforeFirst();
}
}
catch (SQLException se) {
throw new ResetFailedException(getExceptionTranslator().translate(
"Attempted to move ResultSet to last committed row", sql, se));
} catch (SQLException se) {
throw new ResetFailedException("Illegal modification of the result set cursor", getExceptionTranslator()
.translate("Attempted to move ResultSet to last committed row", sql, se));
}
}
/**
* Close this input source. The ResultSet, Statement and Connection created
* will be closed. This must be called or the connection and cursor will be
* held open indefinitely!
* Close this input source. The ResultSet, Statement and Connection created will be closed. This must be called or
* the connection and cursor will be held open indefinitely!
*
* @see org.springframework.batch.item.ResourceLifecycle#close(ExecutionContext)
*/
@@ -288,11 +270,10 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/*
* Executes the provided SQL query. The statement is created with
* 'READ_ONLY' and 'HOLD_CUSORS_OVER_COMMIT' set to true. This is extremely
* important, since a non read-only cursor may lock tables that shouldn't be
* locked, and not holding the cursor open over a commit would require it to
* be reopened after each commit, which would destroy performance.
* Executes the provided SQL query. The statement is created with 'READ_ONLY' and 'HOLD_CUSORS_OVER_COMMIT' set to
* true. This is extremely important, since a non read-only cursor may lock tables that shouldn't be locked, and not
* holding the cursor open over a commit would require it to be reopened after each commit, which would destroy
* performance.
*/
private void executeQuery() {
@@ -301,12 +282,11 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
try {
this.con = dataSource.getConnection();
this.stmt = this.con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
ResultSet.HOLD_CURSORS_OVER_COMMIT);
applyStatementSettings(this.stmt);
this.rs = this.stmt.executeQuery(sql);
handleWarnings(this.stmt.getWarnings());
}
catch (SQLException se) {
} catch (SQLException se) {
close(null);
throw getExceptionTranslator().translate("Executing query", sql, se);
}
@@ -314,10 +294,8 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/*
* Prepare the given JDBC Statement (or PreparedStatement or
* CallableStatement), applying statement settings such as fetch size, max
* rows, and query timeout. @param stmt the JDBC Statement to prepare
* @throws SQLException
* Prepare the given JDBC Statement (or PreparedStatement or CallableStatement), applying statement settings such as
* fetch size, max rows, and query timeout. @param stmt the JDBC Statement to prepare @throws SQLException
*
* @see #setFetchSize
* @see #setMaxRows
@@ -337,16 +315,14 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/*
* Return the exception translator for this instance. <p>Creates a default
* SQLErrorCodeSQLExceptionTranslator for the specified DataSource if none
* is set.
* Return the exception translator for this instance. <p>Creates a default SQLErrorCodeSQLExceptionTranslator for
* the specified DataSource if none is set.
*/
protected SQLExceptionTranslator getExceptionTranslator() {
if (exceptionTranslator == null) {
if (dataSource != null) {
exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource);
}
else {
} else {
exceptionTranslator = new SQLStateSQLExceptionTranslator();
}
}
@@ -354,11 +330,10 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/*
* Throw a SQLWarningException if we're not ignoring warnings, else log the
* warnings (at debug level).
* Throw a SQLWarningException if we're not ignoring warnings, else log the warnings (at debug level).
*
* @param warning the warnings object from the current statement. May be
* <code>null</code>, in which case this method does nothing.
* @param warning the warnings object from the current statement. May be <code>null</code>, in which case this
* method does nothing.
*
* @see org.springframework.jdbc.SQLWarningException
*/
@@ -367,17 +342,17 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
SQLWarning warningToLog = warnings;
while (warningToLog != null) {
log.debug("SQLWarning ignored: SQL state '" + warningToLog.getSQLState() + "', error code '"
+ warningToLog.getErrorCode() + "', message [" + warningToLog.getMessage() + "]");
+ warningToLog.getErrorCode() + "', message [" + warningToLog.getMessage() + "]");
warningToLog = warningToLog.getNextWarning();
}
}
else if (warnings != null) {
} else if (warnings != null) {
throw new SQLWarningException("Warning not ignored", warnings);
}
}
/*
* (non-Javadoc)
*
* @see org.springframework.batch.item.stream.ItemStreamAdapter#getExecutionContext()
*/
public void update(ExecutionContext executionContext) {
@@ -392,6 +367,7 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
/*
* (non-Javadoc)
*
* @see org.springframework.batch.item.stream.ItemStreamAdapter#restoreFrom(org.springframework.batch.item.ExecutionContext)
*/
public void open(ExecutionContext context) {
@@ -409,8 +385,7 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
try {
this.currentProcessedRow = context.getLong(getKey(CURRENT_PROCESSED_ROW));
rs.absolute((int) currentProcessedRow);
}
catch (SQLException se) {
} catch (SQLException se) {
throw getExceptionTranslator().translate("Attempted to move ResultSet to last committed row", sql, se);
}
@@ -425,10 +400,9 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/**
* Skip the current row. If the transaction is rolled back, this row will
* not be represented to the RowMapper when read() is called. For example,
* if you read in row 2, find the data to be bad, and call skip(), then
* continue processing and find
* Skip the current row. If the transaction is rolled back, this row will not be represented to the RowMapper when
* read() is called. For example, if you read in row 2, find the data to be bad, and call skip(), then continue
* processing and find
*/
public void skip() {
skippedRows.add(new Long(currentProcessedRow));
@@ -436,10 +410,9 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/**
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for this
* <code>ResultSet</code> object. If the fetch size specified is zero, the
* JDBC driver ignores the value.
* Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are
* needed for this <code>ResultSet</code> object. If the fetch size specified is zero, the JDBC driver ignores the
* value.
*
* @param fetchSize the number of rows to fetch
* @see ResultSet#setFetchSize(int)
@@ -449,8 +422,8 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/**
* Sets the limit for the maximum number of rows that any
* <code>ResultSet</code> object can contain to the given number.
* Sets the limit for the maximum number of rows that any <code>ResultSet</code> object can contain to the given
* number.
*
* @param maxRows the new max rows limit; zero means there is no limit
* @see Statement#setMaxRows(int)
@@ -460,13 +433,10 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/**
* Sets the number of seconds the driver will wait for a
* <code>Statement</code> object to execute to the given number of
* seconds. If the limit is exceeded, an <code>SQLException</code> is
* thrown.
* Sets the number of seconds the driver will wait for a <code>Statement</code> object to execute to the given
* number of seconds. If the limit is exceeded, an <code>SQLException</code> is thrown.
*
* @param queryTimeout seconds the new query timeout limit in seconds; zero
* means there is no limit
* @param queryTimeout seconds the new query timeout limit in seconds; zero means there is no limit
* @see Statement#setQueryTimeout(int)
*/
public void setQueryTimeout(int queryTimeout) {
@@ -474,8 +444,7 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/**
* Set whether SQLWarnings should be ignored (only logged) or exception
* should be thrown.
* Set whether SQLWarnings should be ignored (only logged) or exception should be thrown.
*
* @param ignoreWarnings if TRUE, warnings are ignored
*/
@@ -484,8 +453,8 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/**
* Allow verification of cursor position after current row is processed by
* RowMapper or RowCallbackHandler. Default value is TRUE.
* Allow verification of cursor position after current row is processed by RowMapper or RowCallbackHandler. Default
* value is TRUE.
*
* @param verifyCursorPosition if true, cursor position is verified
*/
@@ -503,9 +472,8 @@ public class JdbcCursorItemReader extends ExecutionContextUserSupport implements
}
/**
* Set the sql statement to be used when creating the cursor. This statement
* should be a complete and valid Sql statement, as it will be run directly
* without any modification.
* Set the sql statement to be used when creating the cursor. This statement should be a complete and valid Sql
* statement, as it will be run directly without any modification.
*
* @param sql
*/

View File

@@ -21,7 +21,7 @@ import java.util.List;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.exception.NoWorkFoundException;
import org.springframework.batch.item.NoWorkFoundException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

View File

@@ -35,28 +35,27 @@ import org.springframework.batch.io.file.transform.LineTokenizer;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ExecutionContextUserSupport;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemReaderException;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.exception.StreamException;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ReaderNotOpenException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
/**
* This class represents a {@link ItemReader}, that reads lines from text file,
* tokenizes them to structured tuples ({@link FieldSet}s) instances and maps
* the {@link FieldSet}s to domain objects. The location of the file is defined
* by the resource property. To separate the structure of the file,
* {@link LineTokenizer} is used to parse data obtained from the file. <br/>
* This class represents a {@link ItemReader}, that reads lines from text file, tokenizes them to structured tuples ({@link FieldSet}s)
* instances and maps the {@link FieldSet}s to domain objects. The location of the file is defined by the resource
* property. To separate the structure of the file, {@link LineTokenizer} is used to parse data obtained from the file.
* <br/>
*
* A {@link FlatFileItemReader} is not thread safe because it maintains state in
* the form of a {@link ResourceLineReader}. Be careful to configure a
* {@link FlatFileItemReader} using an appropriate factory or scope so that it
* is not shared between threads.<br/>
* A {@link FlatFileItemReader} is not thread safe because it maintains state in the form of a
* {@link ResourceLineReader}. Be careful to configure a {@link FlatFileItemReader} using an appropriate factory or
* scope so that it is not shared between threads.<br/>
*
* <p>
* This class supports restart, skipping invalid lines and storing statistics.
* It can be configured to setup {@link FieldSet} column names from the file
* header, skip given number of lines at the beginning of the file.
* This class supports restart, skipping invalid lines and storing statistics. It can be configured to setup
* {@link FieldSet} column names from the file header, skip given number of lines at the beginning of the file.
* </p>
*
* @author Waseem Malik
@@ -64,7 +63,8 @@ import org.springframework.util.Assert;
* @author Robert Kasanicky
* @author Dave Syer
*/
public class FlatFileItemReader extends ExecutionContextUserSupport implements ItemReader, Skippable, ItemStream, InitializingBean {
public class FlatFileItemReader extends ExecutionContextUserSupport implements ItemReader, Skippable, ItemStream,
InitializingBean {
private static Log log = LogFactory.getLog(FlatFileItemReader.class);
@@ -96,20 +96,20 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
private FieldSetMapper fieldSetMapper;
/**
* Encapsulates the state of the input source. If it is null then we are
* uninitialized.
* Encapsulates the state of the input source. If it is null then we are uninitialized.
*/
private LineReader reader;
public FlatFileItemReader() {
setName(FlatFileItemReader.class.getSimpleName());
}
/**
* Initialize the reader if necessary.
*
* @throws IllegalStateException if the resource cannot be opened
*/
public void open(ExecutionContext executionContext) throws StreamException {
public void open(ExecutionContext executionContext) throws ItemStreamException {
Assert.state(resource.exists(), "Resource must exist: [" + resource + "]");
@@ -140,14 +140,14 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
((AbstractLineTokenizer) tokenizer).setNames(names);
}
}
if (executionContext.containsKey(getKey(READ_STATISTICS_NAME))) {
if (executionContext.containsKey(getKey(READ_STATISTICS_NAME))) {
log.debug("Initializing for restart. Restart data is: " + executionContext);
long lineCount = executionContext.getLong(getKey(READ_STATISTICS_NAME));
LineReader reader = getReader();
Object record = "";
while (reader.getPosition() < lineCount && record != null) {
record = readLine();
@@ -158,23 +158,23 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
/**
* Close and null out the reader.
*
* @throws Exception
*/
public void close(ExecutionContext executionContext) throws StreamException {
public void close(ExecutionContext executionContext) throws ItemStreamException {
try {
if (reader != null) {
log.debug("Closing flat file for reading: " + resource);
reader.close(null);
}
}
finally {
} finally {
reader = null;
}
}
/**
* Reads a line from input, tokenizes is it using the {@link #tokenizer} and
* maps to domain object using {@link #fieldSetMapper}.
* Reads a line from input, tokenizes is it using the {@link #tokenizer} and maps to domain object using
* {@link #fieldSetMapper}.
*
* @see org.springframework.batch.io.ItemReader#read()
*/
@@ -185,25 +185,23 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
try {
FieldSet tokenizedLine = tokenizer.tokenize(line);
return fieldSetMapper.mapLine(tokenizedLine);
}
catch (RuntimeException ex) {
} catch (RuntimeException ex) {
// add current line count to message and re-throw
int lineCount = getReader().getPosition();
throw new FlatFileParsingException("Parsing error at line: " + lineCount + " in resource=" + path
+ ", input=[" + line + "]", ex, line, lineCount);
+ ", input=[" + line + "]", ex, line, lineCount);
}
}
return null;
}
/**
* This method returns the execution attributes for the reader. It returns
* the current Line Count which can be used to reinitialise the batch job in
* case of restart.
* This method returns the execution attributes for the reader. It returns the current Line Count which can be used
* to reinitialise the batch job in case of restart.
*/
public void update(ExecutionContext executionContext) {
if (reader == null) {
throw new StreamException("ItemStream not open or already closed.");
throw new ItemStreamException("ItemStream not open or already closed.");
}
Assert.notNull(executionContext, "ExecutionContext must not be null");
executionContext.putLong(getKey(READ_STATISTICS_NAME), reader.getPosition());
@@ -211,10 +209,8 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
}
/**
* Mark is supported as long as this {@link ItemStream} is used in a
* single-threaded environment. The state backing the mark is a single
* counter, keeping track of the current position, so multiple threads
* cannot be accommodated.
* Mark is supported as long as this {@link ItemStream} is used in a single-threaded environment. The state backing
* the mark is a single counter, keeping track of the current position, so multiple threads cannot be accommodated.
*
* @see org.springframework.batch.item.ItemReader#mark()
*/
@@ -224,6 +220,7 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
/*
* (non-Javadoc)
*
* @see org.springframework.batch.item.ItemStream#reset(org.springframework.batch.item.ExecutionContext)
*/
public void reset() {
@@ -241,8 +238,7 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
}
/**
* @return next line to be tokenized and mapped (possibly skips multiple
* lines).
* @return next line to be tokenized and mapped (possibly skips multiple lines).
*/
protected String readLine() {
String line = nextLine();
@@ -259,8 +255,9 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
private String nextLine() {
try {
return (String) getReader().read();
}
catch (StreamException e) {
} catch (ItemStreamException e) {
throw e;
} catch (ItemReaderException e) {
throw e;
}
catch (Exception e) {
@@ -273,15 +270,14 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
*/
protected LineReader getReader() {
if (reader == null) {
throw new StreamException("ItemStream must be open before it can be read.");
throw new ReaderNotOpenException("Reader must be open before it can be read.");
// reader is now not null, or else an exception is thrown
}
return reader;
}
/**
* Setter for resource property. The location of an input stream that can be
* read.
* Setter for resource property. The location of an input stream that can be read.
*
* @param resource
* @throws IOException
@@ -295,9 +291,8 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
}
/**
* Public setter for the recordSeparatorPolicy. Used to determine where the
* line endings are and do things like continue over a line ending if inside
* a quoted string.
* Public setter for the recordSeparatorPolicy. Used to determine where the line endings are and do things like
* continue over a line ending if inside a quoted string.
*
* @param recordSeparatorPolicy the recordSeparatorPolicy to set
*/
@@ -306,8 +301,8 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
}
/**
* Setter for comment prefixes. Can be used to ignore header lines as well
* by using e.g. the first couple of column names as a prefix.
* Setter for comment prefixes. Can be used to ignore header lines as well by using e.g. the first couple of column
* names as a prefix.
*
* @param comments an array of comment line prefixes.
*/
@@ -317,10 +312,8 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
}
/**
* Indicates whether first line is a header. If the tokenizer is an
* {@link AbstractLineTokenizer} and the column names haven't been set
* already then the header will be used to setup column names. Default is
* <code>false</code>.
* Indicates whether first line is a header. If the tokenizer is an {@link AbstractLineTokenizer} and the column
* names haven't been set already then the header will be used to setup column names. Default is <code>false</code>.
*/
public void setFirstLineIsHeader(boolean firstLineIsHeader) {
this.firstLineIsHeader = firstLineIsHeader;
@@ -343,10 +336,8 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
}
/**
* Public setter for the number of lines to skip at the start of a file. Can
* be used if the file contains a header without useful (column name)
* information, and without a comment delimiter at the beginning of the
* lines.
* Public setter for the number of lines to skip at the start of a file. Can be used if the file contains a header
* without useful (column name) information, and without a comment delimiter at the beginning of the lines.
*
* @param linesToSkip the number of lines to skip
*/
@@ -355,11 +346,9 @@ public class FlatFileItemReader extends ExecutionContextUserSupport implements I
}
/**
* Setter for the encoding for this input source. Default value is
* {@value #DEFAULT_CHARSET}.
* Setter for the encoding for this input source. Default value is {@value #DEFAULT_CHARSET}.
*
* @param encoding a properties object which possibly contains the encoding
* for this input file;
* @param encoding a properties object which possibly contains the encoding for this input file;
*/
public void setEncoding(String encoding) {
this.encoding = encoding;

View File

@@ -31,34 +31,30 @@ import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetCreator;
import org.springframework.batch.io.file.transform.DelimitedLineAggregator;
import org.springframework.batch.io.file.transform.LineAggregator;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ExecutionContextUserSupport;
import org.springframework.batch.item.FlushFailedException;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.exception.ClearFailedException;
import org.springframework.batch.item.exception.FlushFailedException;
import org.springframework.batch.item.exception.ResetFailedException;
import org.springframework.batch.item.exception.StreamException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.util.Assert;
/**
* This class is an output target that writes data to a file or stream. The
* writer also provides restart, statistics and transaction features by
* implementing corresponding interfaces where possible (with a file). The
* location of the file is defined by a {@link Resource} and must represent a
* writable file.<br/>
* This class is an output target that writes data to a file or stream. The writer also provides restart, statistics and
* transaction features by implementing corresponding interfaces where possible (with a file). The location of the file
* is defined by a {@link Resource} and must represent a writable file.<br/>
*
* Uses buffered writer to improve performance.<br/>
*
* Use {@link #write(String)} method to output a line to an item writer.
*
* <p>
* This class will be updated in the future to use a buffering approach to
* handling transactions, rather than outputting directly to the file and
* truncating on rollback
* This class will be updated in the future to use a buffering approach to handling transactions, rather than outputting
* directly to the file and truncating on rollback
* </p>
*
* @author Waseem Malik
@@ -66,8 +62,7 @@ import org.springframework.util.Assert;
* @author Robert Kasanicky
* @author Dave Syer
*/
public class FlatFileItemWriter extends ExecutionContextUserSupport implements ItemWriter, ItemStream,
InitializingBean {
public class FlatFileItemWriter extends ExecutionContextUserSupport implements ItemWriter, ItemStream, InitializingBean {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
@@ -84,13 +79,14 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
private LineAggregator lineAggregator = new DelimitedLineAggregator();
private FieldSetCreator fieldSetCreator;
public FlatFileItemWriter() {
setName(FlatFileItemWriter.class.getSimpleName());
}
/**
* Assert that mandatory properties (resource) are set.
*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
@@ -101,8 +97,8 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
}
/**
* Public setter for the {@link LineAggregator}. This will be used to
* translate a {@link FieldSet} into a line for output.
* Public setter for the {@link LineAggregator}. This will be used to translate a {@link FieldSet} into a line for
* output.
*
* @param lineAggregator the {@link LineAggregator} to set
*/
@@ -111,9 +107,8 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
}
/**
* Public setter for the {@link FieldSetCreator}. This will be used to
* transform the item into a {@link FieldSet} before it is aggregated by the
* {@link LineAggregator}.
* Public setter for the {@link FieldSetCreator}. This will be used to transform the item into a {@link FieldSet}
* before it is aggregated by the {@link LineAggregator}.
*
* @param fieldSetCreator the {@link FieldSetCreator} to set
*/
@@ -131,16 +126,13 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
}
/**
* Writes out a string followed by a "new line", where the format of the new
* line separator is determined by the underlying operating system. If the
* input is not a String and a converter is available the converter will be
* applied and then this method recursively called with the result. If the
* input is an array or collection each value will be written to a separate
* line (recursively calling this method for each value). If no converter is
* Writes out a string followed by a "new line", where the format of the new line separator is determined by the
* underlying operating system. If the input is not a String and a converter is available the converter will be
* applied and then this method recursively called with the result. If the input is an array or collection each
* value will be written to a separate line (recursively calling this method for each value). If no converter is
* supplied the input object's toString method will be used.<br/>
*
* @param data Object (a String or Object that can be converted) to be
* written to output stream
* @param data Object (a String or Object that can be converted) to be written to output stream
* @throws Exception if the transformer or file output fail
*/
public void write(Object data) throws Exception {
@@ -181,11 +173,12 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
/**
* Initialize the Output Template.
*
* @see ResourceLifecycle#open()
*/
public void open(ExecutionContext executionContext) {
OutputState outputState = getOutputState();
if(executionContext.containsKey(getKey(RESTART_DATA_NAME))){
if (executionContext.containsKey(getKey(RESTART_DATA_NAME))) {
outputState.restoreFrom(executionContext);
}
}
@@ -195,7 +188,7 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
*/
public void update(ExecutionContext executionContext) {
if (state == null) {
throw new StreamException("ItemStream not open or already closed.");
throw new ItemStreamException("ItemStream not open or already closed.");
}
Assert.notNull(executionContext, "ExecutionContext must not be null");
executionContext.putLong(getKey(RESTART_DATA_NAME), state.position());
@@ -212,8 +205,7 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
}
/**
* Encapsulates the runtime state of the writer. All state changing
* operations on the writer go through this class.
* Encapsulates the runtime state of the writer. All state changing operations on the writer go through this class.
*/
private class OutputState {
// default encoding for writing to output files - set to UTF-8.
@@ -246,8 +238,7 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
boolean shouldDeleteIfExists = true;
/**
* Return the byte offset position of the cursor in the output file as a
* long integer.
* Return the byte offset position of the cursor in the output file as a long integer.
*/
public long position() {
long pos = 0;
@@ -259,8 +250,7 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
try {
outputBufferedWriter.flush();
pos = fileChannel.position();
}
catch (IOException e) {
} catch (IOException e) {
throw new InfrastructureException("An Error occured while trying to get filechannel position", e);
}
@@ -309,9 +299,8 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
}
outputBufferedWriter.close();
fileChannel.close();
}
catch (IOException ioe) {
throw new StreamException("Unable to close the the ItemWriter", ioe);
} catch (IOException ioe) {
throw new ItemStreamException("Unable to close the the ItemWriter", ioe);
}
}
@@ -329,8 +318,7 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
outputBufferedWriter.write(line);
outputBufferedWriter.flush();
linesWritten++;
}
catch (IOException e) {
} catch (IOException e) {
throw new InfrastructureException("An Error occured while trying to write to FlatFileItemWriter", e);
}
}
@@ -342,8 +330,7 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
try {
fileChannel.truncate(lastMarkedByteOffsetPosition);
fileChannel.position(lastMarkedByteOffsetPosition);
}
catch (IOException e) {
} catch (IOException e) {
throw new InfrastructureException("An Error occured while truncating output file", e);
}
}
@@ -356,8 +343,7 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
}
/**
* Creates the buffered writer for the output file channel based on
* configuration information.
* Creates the buffered writer for the output file channel based on configuration information.
*/
private void initializeBufferedWriter() {
File file;
@@ -376,9 +362,8 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
if (file.exists()) {
if (shouldDeleteIfExists) {
file.delete();
}
else {
throw new StreamException("Resource already exists: " + resource);
} else {
throw new ItemStreamException("Resource already exists: " + resource);
}
}
String parent = file.getParent();
@@ -388,16 +373,14 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
file.createNewFile();
}
}
catch (IOException ioe) {
} catch (IOException ioe) {
throw new DataAccessResourceFailureException("Unable to write to file resource: [" + resource + "]",
ioe);
ioe);
}
try {
fileChannel = (new FileOutputStream(file.getAbsolutePath(), true)).getChannel();
}
catch (FileNotFoundException fnfe) {
} catch (FileNotFoundException fnfe) {
throw new ConfigurationException("Bad filename property parameter " + file, fnfe);
}
@@ -413,8 +396,8 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
}
/**
* Returns the buffered writer opened to the beginning of the file
* specified by the absolute path name contained in absoluteFileName.
* Returns the buffered writer opened to the beginning of the file specified by the absolute path name contained
* in absoluteFileName.
*/
private BufferedWriter getBufferedWriter(FileChannel fileChannel, String encoding, int bufferSize) {
try {
@@ -424,25 +407,21 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
// If a buffer was requested, allocate.
if (bufferSize > 0) {
outputBufferedWriter = new BufferedWriter(Channels.newWriter(fileChannel, encoding), bufferSize);
}
else {
} else {
outputBufferedWriter = new BufferedWriter(Channels.newWriter(fileChannel, encoding));
}
return outputBufferedWriter;
}
catch (UnsupportedCharsetException ucse) {
throw new StreamException("Bad encoding configuration for output file " + fileChannel, ucse);
} catch (UnsupportedCharsetException ucse) {
throw new ItemStreamException("Bad encoding configuration for output file " + fileChannel, ucse);
}
}
/**
* Resets the file writer's current position to the point stored in the
* last marked byte offset position variable. It first checks to make
* sure the current size of the file is not less than the byte position
* to be moved to (if it is, throws an environment exception), then it
* truncates the file to that reset position, and set the cursor to
* start writing at that point.
* Resets the file writer's current position to the point stored in the last marked byte offset position
* variable. It first checks to make sure the current size of the file is not less than the byte position to be
* moved to (if it is, throws an environment exception), then it truncates the file to that reset position, and
* set the cursor to start writing at that point.
*/
public void reset() throws InfrastructureException {
checkFileSize();
@@ -450,10 +429,9 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
}
/**
* Checks (on setState) to make sure that the current output file's size
* is not smaller than the last saved commit point. If it is, then the
* file has been damaged in some way and whole task must be started over
* again from the beginning.
* Checks (on setState) to make sure that the current output file's size is not smaller than the last saved
* commit point. If it is, then the file has been damaged in some way and whole task must be started over again
* from the beginning.
*/
private void checkFileSize() {
long size = -1;
@@ -461,8 +439,7 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
try {
outputBufferedWriter.flush();
size = fileChannel.size();
}
catch (IOException e) {
} catch (IOException e) {
throw new InfrastructureException("An Error occured while checking file size", e);
}
@@ -476,14 +453,13 @@ public class FlatFileItemWriter extends ExecutionContextUserSupport implements I
public void clear() throws ClearFailedException {
try {
getOutputState().reset();
}
catch (InfrastructureException e) {
throw new ResetFailedException(e);
} catch (InfrastructureException e) {
throw new ClearFailedException("Could not reset the state of the writer", e);
}
}
public void flush() throws FlushFailedException {
getOutputState().mark();
}
}

View File

@@ -28,9 +28,10 @@ import java.util.Iterator;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.exception.MarkFailedException;
import org.springframework.batch.item.exception.ResetFailedException;
import org.springframework.batch.item.exception.StreamException;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.MarkFailedException;
import org.springframework.batch.item.ResetFailedException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.batch.item.stream.ItemStreamSupport;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
@@ -38,22 +39,17 @@ import org.springframework.util.Assert;
/**
* An input source that reads lines one by one from a resource. <br/>
*
* A line can consist of multiple lines in the input resource, according to the
* {@link RecordSeparatorPolicy} in force. By default a line is either
* terminated by a newline (as per {@link BufferedReader#readLine()}), or can
* be continued onto the next line if a field surrounded by quotes (\") contains
* a newline.<br/>
* A line can consist of multiple lines in the input resource, according to the {@link RecordSeparatorPolicy} in force.
* By default a line is either terminated by a newline (as per {@link BufferedReader#readLine()}), or can be continued
* onto the next line if a field surrounded by quotes (\") contains a newline.<br/>
*
* Comment lines can be indicated using a line prefix (or collection of
* prefixes) and they will be ignored. The default is "#", so lines starting
* with a pound sign will be ignored.<br/>
* Comment lines can be indicated using a line prefix (or collection of prefixes) and they will be ignored. The default
* is "#", so lines starting with a pound sign will be ignored.<br/>
*
* All the public methods that interact with the underlying resource (open,
* close, read etc.) are synchronized on this.<br/>
* All the public methods that interact with the underlying resource (open, close, read etc.) are synchronized on this.<br/>
*
* Package private because this is not intended to be a public API - used
* internally by the flat file input sources. That makes abuses of the fact that
* it is stateful easier to control.<br/>
* Package private because this is not intended to be a public API - used internally by the flat file input sources.
* That makes abuses of the fact that it is stateful easier to control.<br/>
*
* @author Dave Syer
* @author Rob Harrop
@@ -89,24 +85,22 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
}
/**
* Setter for the {@link RecordSeparatorPolicy}. Default value is a
* {@link DefaultRecordSeparatorPolicy}. Ideally should not be changed once
* a reader is in use, but it would not be fatal if it was.
* Setter for the {@link RecordSeparatorPolicy}. Default value is a {@link DefaultRecordSeparatorPolicy}. Ideally
* should not be changed once a reader is in use, but it would not be fatal if it was.
*
* @param recordSeparatorPolicy the new {@link RecordSeparatorPolicy}
*/
public void setRecordSeparatorPolicy(RecordSeparatorPolicy recordSeparatorPolicy) {
/*
* The rest of the code accesses the policy in synchronized blocks,
* copying the reference before using it. So in principle it can be
* changed in flight - the results might not be what the user expected!
* The rest of the code accesses the policy in synchronized blocks, copying the reference before using it. So in
* principle it can be changed in flight - the results might not be what the user expected!
*/
this.recordSeparatorPolicy = recordSeparatorPolicy;
}
/**
* Setter for comment prefixes. Can be used to ignore header lines as well
* by using e.g. the first couple of column names as a prefix.
* Setter for comment prefixes. Can be used to ignore header lines as well by using e.g. the first couple of column
* names as a prefix.
*
* @param comments an array of comment line prefixes.
*/
@@ -115,8 +109,7 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
}
/**
* Read the next line from the input resource, ignoring comments, and
* according to the {@link RecordSeparatorPolicy}.
* Read the next line from the input resource, ignoring comments, and according to the {@link RecordSeparatorPolicy}.
*
* @return a String.
*
@@ -154,8 +147,7 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
}
/**
* A no-op because the oobject is initialized with all it needs to open in
* the constructor.
* A no-op because the oobject is initialized with all it needs to open in the constructor.
*
* @see org.springframework.batch.item.ResourceLifecycle#open()
*/
@@ -175,8 +167,7 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
}
try {
state.close();
}
finally {
} finally {
state = null;
}
}
@@ -191,14 +182,11 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
}
/**
* Mark the state for return later with reset. Uses the read-ahead limit
* from an underlying {@link BufferedReader}, which means that there is a
* limit to how much data can be recovered if the mark needs to be reset.<br/>
* Mark the state for return later with reset. Uses the read-ahead limit from an underlying {@link BufferedReader},
* which means that there is a limit to how much data can be recovered if the mark needs to be reset.<br/>
*
* Mark is supported as long as this {@link ItemStream} is used in a
* single-threaded environment. The state backing the mark is a single
* counter, keeping track of the current position, so multiple threads
* cannot be accommodated.
* Mark is supported as long as this {@link ItemStream} is used in a single-threaded environment. The state backing
* the mark is a single counter, keeping track of the current position, so multiple threads cannot be accommodated.
*
* @see #reset()
*
@@ -213,8 +201,7 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
*
* @see #mark()
*
* @throws ResetFailedException if the reset is unsuccessful, e.g. if
* the read-ahead limit was breached.
* @throws ResetFailedException if the reset is unsuccessful, e.g. if the read-ahead limit was breached.
*/
public synchronized void reset() throws ResetFailedException {
getState().reset();
@@ -253,10 +240,9 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
}
currentLineCount++;
}
}
catch (IOException e) {
throw new StreamException("Unable to read from resource '" + resource + "' at line "
+ currentLineCount, e);
} catch (IOException e) {
throw new UnexpectedInputException("Unable to read from resource '" + resource + "' at line "
+ currentLineCount, e);
}
return line;
}
@@ -268,9 +254,8 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
try {
reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), encoding));
mark();
}
catch (IOException e) {
throw new StreamException("Could not open resource", e);
} catch (IOException e) {
throw new ItemStreamException("Could not open resource", e);
}
}
@@ -284,11 +269,9 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
}
try {
reader.close();
}
catch (IOException e) {
throw new StreamException("Could not close reader", e);
}
finally {
} catch (IOException e) {
throw new ItemStreamException("Could not close reader", e);
} finally {
currentLineCount = 0;
markedLineCount = -1;
}
@@ -309,15 +292,13 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
try {
reader.mark(READ_AHEAD_LIMIT);
markedLineCount = currentLineCount;
}
catch (IOException e) {
} catch (IOException e) {
throw new MarkFailedException("Could not mark reader", e);
}
}
/**
* Reset the reader and line counters to the last marked position if
* possible.
* Reset the reader and line counters to the last marked position if possible.
*/
public void reset() throws ResetFailedException {
@@ -327,8 +308,7 @@ public class ResourceLineReader extends ItemStreamSupport implements LineReader,
try {
this.reader.reset();
currentLineCount = markedLineCount;
}
catch (IOException e) {
} catch (IOException e) {
throw new ResetFailedException("Could not reset reader", e);
}

View File

@@ -21,9 +21,9 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.FlushFailedException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.exception.ClearFailedException;
import org.springframework.batch.item.exception.FlushFailedException;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.synch.RepeatSynchronizationManager;
import org.springframework.beans.factory.InitializingBean;

View File

@@ -19,9 +19,9 @@ import java.util.HashSet;
import java.util.Set;
import org.hibernate.SessionFactory;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.FlushFailedException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.exception.ClearFailedException;
import org.springframework.batch.item.exception.FlushFailedException;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.synch.RepeatSynchronizationManager;
import org.springframework.beans.factory.InitializingBean;

View File

@@ -20,7 +20,8 @@ import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ExecutionContextUserSupport;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.exception.StreamException;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ReaderNotOpenException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessResourceFailureException;
@@ -75,7 +76,7 @@ public class StaxEventItemReader extends ExecutionContextUserSupport implements
*/
public Object read() {
if (!initialized) {
throw new StreamException("ItemStream must be open before it can be read.");
throw new ReaderNotOpenException("Reader must be open before it can be read.");
}
Object item = null;
@@ -141,7 +142,7 @@ public class StaxEventItemReader extends ExecutionContextUserSupport implements
txReader.onCommit(); // reset the history buffer
}
if (!fragmentReader.hasNext()) {
throw new StreamException("Restore point must be before end of input");
throw new ItemStreamException("Restore point must be before end of input");
}
fragmentReader.next();
moveCursorToNextFragment(fragmentReader);

View File

@@ -17,12 +17,12 @@ import javax.xml.stream.XMLStreamException;
import org.springframework.batch.io.support.FileUtils;
import org.springframework.batch.io.xml.stax.NoStartEndDocumentStreamWriter;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ExecutionContextUserSupport;
import org.springframework.batch.item.FlushFailedException;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.exception.ClearFailedException;
import org.springframework.batch.item.exception.FlushFailedException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessResourceFailureException;

View File

@@ -13,39 +13,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item.exception;
import org.springframework.batch.item.ItemWriter;
package org.springframework.batch.item;
/**
* Unchecked exception indicating that an error has occured while
* trying to call {@link ItemWriter#clear()}
* Unchecked exception indicating that an error has occurred while trying to call {@link ItemWriter#clear()}
*
* @author Lucas Ward
*
* @author Ben Hale
*/
public class ClearFailedException extends StreamException {
public class ClearFailedException extends ItemWriterException {
/**
* @param message
* Create a new {@link ClearFailedException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
public ClearFailedException(String message, Throwable cause) {
super(message, cause);
}
/**
* Create a new {@link ClearFailedException} based on a message.
*
* @param message the message for this exception
*/
public ClearFailedException(String message) {
super(message);
}
/**
* @param msg
* @param nested
*/
public ClearFailedException(String msg, Throwable nested) {
super(msg, nested);
}
/**
* @param msg
* @param nested
*/
public ClearFailedException(Throwable nested) {
super(nested);
}
}

View File

@@ -13,38 +13,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item.exception;
import org.springframework.batch.item.ItemWriter;
package org.springframework.batch.item;
/**
* Unchecked exception indicating that an error has occured while
* trying to call {@link ItemWriter#flush()}
* Unchecked exception indicating that an error has occurred while trying to call {@link ItemWriter#flush()}
*
* @author Lucas Ward
*
* @author Ben Hale
*/
public class FlushFailedException extends StreamException {
public class FlushFailedException extends ItemWriterException {
/**
* @param message
* Create a new {@link FlushFailedException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
public FlushFailedException(String message, Throwable cause) {
super(message, cause);
}
/**
* Create a new {@link FlushFailedException} based on a message.
*
* @param message the message for this exception
*/
public FlushFailedException(String message) {
super(message);
}
/**
* @param msg
* @param nested
*/
public FlushFailedException(String msg, Throwable nested) {
super(msg, nested);
}
/**
* @param msg
* @param nested
*/
public FlushFailedException(Throwable nested) {
super(nested);
}
}

View File

@@ -16,8 +16,6 @@
package org.springframework.batch.item;
import org.springframework.batch.item.exception.MarkFailedException;
import org.springframework.batch.item.exception.ResetFailedException;
import org.springframework.batch.item.reader.AbstractItemReader;
/**
@@ -51,7 +49,7 @@ public interface ItemReader {
*
* @throws Exception if an underlying resource is unavailable.
*/
Object read() throws Exception;
Object read() throws Exception, UnexpectedInputException, NoWorkFoundException;
/**
* Mark the stream so that it can be reset later and the items backed out.<br/>

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item;
/**
* A base exception class that all exceptions thrown from an {@link ItemReader} extend.
*
* @author Ben Hale
*/
public abstract class ItemReaderException extends RuntimeException {
/**
* Create a new {@link ItemReaderException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
public ItemReaderException(String message, Throwable cause) {
super(message, cause);
}
/**
* Create a new {@link ItemReaderException} based on a message.
*
* @param message the message for this exception
*/
public ItemReaderException(String message) {
super(message);
}
}

View File

@@ -16,12 +16,10 @@
package org.springframework.batch.item;
import org.springframework.batch.item.exception.StreamException;
/**
* <p>
* Marker interface defining a contract for periodically storing state and
* restoring from that state should an error occur.
* Marker interface defining a contract for periodically storing state and restoring from that state should an error
* occur.
* <p>
*
* @author Dave Syer
@@ -35,23 +33,22 @@ public interface ItemStream {
*
* @throws IllegalArgumentException if context is null
*/
void open(ExecutionContext executionContext) throws StreamException;
void open(ExecutionContext executionContext) throws ItemStreamException;
/**
* Indicates that the execution context provided during open
* is about to be saved. If any state is remaining, but
* has not been put in the context, it should be added
* here.
* Indicates that the execution context provided during open is about to be saved. If any state is remaining, but
* has not been put in the context, it should be added here.
*
* @param executionContext to be updated
* @throws IllegalArgumentException if executionContext is null.
*/
void update(ExecutionContext executionContext);
void update(ExecutionContext executionContext) throws ItemStreamException;
/**
* If any resources are needed for the stream to operate they need to be
* destroyed here. Once this method has been called all other methods
* (except open) may throw an exception.
* If any resources are needed for the stream to operate they need to be destroyed here. Once this method has been
* called all other methods (except open) may throw an exception.
*
* @param executionContext TODO
*/
void close(ExecutionContext executionContext) throws StreamException;
void close(ExecutionContext executionContext) throws ItemStreamException;
}

View File

@@ -13,40 +13,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item.exception;
import org.springframework.batch.io.exception.InfrastructureException;
package org.springframework.batch.item;
/**
* Exception representing any errors encountered while processing
* a stream.
* Exception representing any errors encountered while processing a stream.
*
* @author Dave Syer
* @author Lucas Ward
*/
public class StreamException extends InfrastructureException {
public class ItemStreamException extends RuntimeException {
/**
* @param message
*/
public StreamException(String message) {
public ItemStreamException(String message) {
super(message);
}
/**
* Constructs a new instance with a message and nested exception.
*
* @param msg the exception message.
*
*/
public StreamException(String msg, Throwable nested) {
public ItemStreamException(String msg, Throwable nested) {
super(msg, nested);
}
/**
* Constructs a new instance with a nested exception and empty message.
*/
public StreamException(Throwable nested) {
public ItemStreamException(Throwable nested) {
super(nested);
}
}

View File

@@ -16,8 +16,6 @@
package org.springframework.batch.item;
import org.springframework.batch.item.exception.ClearFailedException;
import org.springframework.batch.item.exception.FlushFailedException;
/**
* <p>Basic interface for generic output operations. Class implementing this

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item;
/**
* A base exception class that all exceptions thrown from an {@link ItemWriter} extend.
*
* @author Ben Hale
*/
public abstract class ItemWriterException extends RuntimeException {
/**
* Create a new {@link ItemWriterException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
public ItemWriterException(String message, Throwable cause) {
super(message, cause);
}
/**
* Create a new {@link ItemWriterException} based on a message.
*
* @param message the message for this exception
*/
public ItemWriterException(String message) {
super(message);
}
}

View File

@@ -13,35 +13,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item.exception;
package org.springframework.batch.item;
/**
* An exception class thrown when an {@link ItemReader} fails to mark its current state for future retry.
*
* @author Dave Syer
*
* @author Ben Hale
*/
public class MarkFailedException extends StreamException {
public class MarkFailedException extends ItemReaderException {
/**
* @param message
* Create a new {@link MarkFailedException} based on a message.
*
* @param message the message for this exception
*/
public MarkFailedException(String message) {
super(message);
}
/**
* @param msg
* @param nested
* Create a new {@link MarkFailedException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
public MarkFailedException(String msg, Throwable nested) {
super(msg, nested);
}
/**
* @param msg
* @param nested
*/
public MarkFailedException(Throwable nested) {
super(nested);
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2006-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item;
/**
* Exception indicating that an {@link ItemReader} found no work to process while initializing.
*
* @author Lucas Ward
* @author Ben Hale
*/
public class NoWorkFoundException extends ItemReaderException {
/**
* Create a new {@link NoWorkFoundException} based on a message.
*
* @param message the message for this exception
*/
public NoWorkFoundException(String message) {
super(message);
}
/**
* Create a new {@link NoWorkFoundException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
public NoWorkFoundException(String msg, Throwable nested) {
super(msg, nested);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2006-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item;
/**
* Exception indicating that an {@link ItemReader} needed to be opened before read.
*
* @author Ben Hale
*/
public class ReaderNotOpenException extends ItemReaderException {
/**
* Create a new {@link ReaderNotOpenException} based on a message.
*
* @param message the message for this exception
*/
public ReaderNotOpenException(String message) {
super(message);
}
/**
* Create a new {@link ReaderNotOpenException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
public ReaderNotOpenException(String msg, Throwable nested) {
super(msg, nested);
}
}

View File

@@ -13,37 +13,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item.exception;
package org.springframework.batch.item;
/**
* An exception class thrown when an {@link ItemReader} fails to reset its state based on the previous mark.
*
* @author Dave Syer
*
* @author Ben Hale
*/
public class ResetFailedException extends StreamException {
public class ResetFailedException extends ItemReaderException {
/**
* @param message
* Create a new {@link ResetFailedException} based on a message.
*
* @param message the message for this exception
*/
public ResetFailedException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
/**
* @param msg
* @param nested
* Create a new {@link ResetFailedException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
public ResetFailedException(String msg, Throwable nested) {
super(msg, nested);
}
/**
* @param msg
* @param nested
*/
public ResetFailedException(Throwable nested) {
super(nested);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item;
/**
* Used to signal an unexpected end of an input or message stream. This is an abnormal condition, not just the end of
* the data - e.g. if a resource becomes unavailable, or a stream becomes unreadable.
*
* @author Dave Syer
* @author Ben Hale
*/
public class UnexpectedInputException extends ItemReaderException {
/**
* Create a new {@link UnexpectedInputException} based on a message.
*
* @param message the message for this exception
*/
public UnexpectedInputException(String message) {
super(message);
}
/**
* Create a new {@link UnexpectedInputException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
public UnexpectedInputException(String msg, Throwable nested) {
super(msg, nested);
}
}

View File

@@ -1,46 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item.exception;
/**
* @author Dave Syer
*
*/
public class CommitFailedException extends StreamException {
/**
* @param message
*/
public CommitFailedException(String message) {
super(message);
}
/**
* @param msg
* @param nested
*/
public CommitFailedException(String msg, Throwable nested) {
super(msg, nested);
}
/**
* @param msg
* @param nested
*/
public CommitFailedException(Throwable nested) {
super(nested);
}
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright 2006-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item.exception;
/**
* Exception indicating that an {@link ItemReader} found
* no work to process while initializing.
*
* @author Lucas Ward
*
*/
public class NoWorkFoundException extends StreamException {
public NoWorkFoundException(String msg) {
super(msg);
}
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item.exception;
/**
* Used to signal an unexpected end of an input or message stream. This is an
* abnormal condition, not just the end of the data - e.g. if a resource becomes
* unavailable, or a stream becomes unreadable.
*
* @author Dave Syer
*/
public class UnexpectedInputException extends StreamException {
/**
* Generated serial UID.
*/
private static final long serialVersionUID = -8325588758094208905L;
public UnexpectedInputException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,7 +0,0 @@
<html>
<body>
<p>
Infrastructure implementations of item exception concerns.
</p>
</body>
</html>

View File

@@ -17,8 +17,8 @@
package org.springframework.batch.item.reader;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.exception.MarkFailedException;
import org.springframework.batch.item.exception.ResetFailedException;
import org.springframework.batch.item.MarkFailedException;
import org.springframework.batch.item.ResetFailedException;
/**
* Base class for {@link ItemReader} implementations.

View File

@@ -18,9 +18,9 @@ package org.springframework.batch.item.reader;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.exception.MarkFailedException;
import org.springframework.batch.item.exception.ResetFailedException;
import org.springframework.batch.item.exception.StreamException;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.MarkFailedException;
import org.springframework.batch.item.ResetFailedException;
import org.springframework.batch.support.AbstractMethodInvokingDelegator;
/**
@@ -43,7 +43,7 @@ public class ItemReaderAdapter extends AbstractMethodInvokingDelegator implement
*
* @see org.springframework.batch.item.ItemReader#close(ExecutionContext)
*/
public void close() throws StreamException {
public void close() throws ItemStreamException {
}

View File

@@ -26,7 +26,7 @@ import org.springframework.batch.item.FailedItemIdentifier;
import org.springframework.batch.item.ItemKeyGenerator;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemRecoverer;
import org.springframework.batch.item.exception.UnexpectedInputException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.jms.JmsException;
import org.springframework.jms.core.JmsOperations;
import org.springframework.jms.core.JmsTemplate;

View File

@@ -22,7 +22,7 @@ import java.util.List;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.exception.StreamException;
import org.springframework.batch.item.ItemStreamException;
/**
* Simple {@link ItemStream} that delegates to a list of other streams.
@@ -83,9 +83,9 @@ public class CompositeItemStream implements ItemStream {
/**
* Broadcast the call to close from this {@link StreamManager}.
* @throws StreamException
* @throws ItemStreamException
*/
public void close(ExecutionContext executionContext) throws StreamException {
public void close(ExecutionContext executionContext) throws ItemStreamException {
synchronized (streams) {
for (Iterator it = streams.iterator(); it.hasNext();) {
ItemStream itemStream = (ItemStream) it.next();
@@ -96,9 +96,9 @@ public class CompositeItemStream implements ItemStream {
/**
* Broadcast the call to open from this {@link StreamManager}.
* @throws StreamException
* @throws ItemStreamException
*/
public void open(ExecutionContext executionContext) throws StreamException {
public void open(ExecutionContext executionContext) throws ItemStreamException {
synchronized (streams) {
for (Iterator it = streams.iterator(); it.hasNext();) {
ItemStream itemStream = (ItemStream) it.next();

View File

@@ -17,7 +17,7 @@ package org.springframework.batch.item.stream;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.exception.StreamException;
import org.springframework.batch.item.ItemStreamException;
/**
* Empty method implementation of {@link ItemStream}.
@@ -31,14 +31,14 @@ public class ItemStreamSupport implements ItemStream {
* No-op.
* @see org.springframework.batch.item.ItemStream#close(ExecutionContext)
*/
public void close(ExecutionContext executionContext) throws StreamException {
public void close(ExecutionContext executionContext) throws ItemStreamException {
}
/**
* No-op.
* @see org.springframework.batch.item.ItemStream#open()
*/
public void open(ExecutionContext executionContext) throws StreamException {
public void open(ExecutionContext executionContext) throws ItemStreamException {
}
/**

View File

@@ -15,9 +15,9 @@
*/
package org.springframework.batch.item.writer;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.FlushFailedException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.exception.ClearFailedException;
import org.springframework.batch.item.exception.FlushFailedException;
/**
* Abstract {@link ItemWriter} that allows for base classes to only

View File

@@ -1,8 +1,8 @@
package org.springframework.batch.item.writer;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.FlushFailedException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.exception.ClearFailedException;
import org.springframework.batch.item.exception.FlushFailedException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

View File

@@ -16,9 +16,9 @@
package org.springframework.batch.item.writer;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.FlushFailedException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.exception.ClearFailedException;
import org.springframework.batch.item.exception.FlushFailedException;
import org.springframework.batch.support.AbstractMethodInvokingDelegator;

View File

@@ -16,9 +16,9 @@
package org.springframework.batch.item.writer;
import org.springframework.batch.item.ClearFailedException;
import org.springframework.batch.item.FlushFailedException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.exception.ClearFailedException;
import org.springframework.batch.item.exception.FlushFailedException;
import org.springframework.batch.support.AbstractMethodInvokingDelegator;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;