CLOSED - issue BATCH-979: Insert Apache license header in Java sources (where missing)

This commit is contained in:
dsyer
2009-01-13 11:08:59 +00:00
parent 33d38611f4
commit df2ef02932
156 changed files with 6384 additions and 3957 deletions

View File

@@ -1,3 +1,19 @@
/*
* 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;
/**

View File

@@ -1,3 +1,19 @@
/*
* 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.adapter;
import org.springframework.util.MethodInvoker;

View File

@@ -1,3 +1,19 @@
/*
* 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.database;
import java.util.List;

View File

@@ -1,6 +1,19 @@
/**
*
/*
* 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.database.support;
import java.sql.PreparedStatement;

View File

@@ -1,3 +1,19 @@
/*
* 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.database.support;
import java.util.List;

View File

@@ -1,18 +1,34 @@
package org.springframework.batch.item.file;
import java.io.Writer;
import java.io.IOException;
/**
* Callback interface for writing a footer to a file.
*
* @author Robert Kasanicky
*/
public interface FlatFileFooterCallback {
/**
* Write contents to a file using the supplied {@link Writer}. It is not
* required to flush the writer inside this method.
*/
void writeFooter(Writer writer) throws IOException;
}
/*
* 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.file;
import java.io.Writer;
import java.io.IOException;
/**
* Callback interface for writing a footer to a file.
*
* @author Robert Kasanicky
*/
public interface FlatFileFooterCallback {
/**
* Write contents to a file using the supplied {@link Writer}. It is not
* required to flush the writer inside this method.
*/
void writeFooter(Writer writer) throws IOException;
}

View File

@@ -1,18 +1,34 @@
package org.springframework.batch.item.file;
import java.io.Writer;
import java.io.IOException;
/**
* Callback interface for writing to a header to a file.
*
* @author Robert Kasanicky
*/
public interface FlatFileHeaderCallback {
/**
* Write contents to a file using the supplied {@link Writer}. It is not
* required to flush the writer inside this method.
*/
void writeHeader(Writer writer) throws IOException;
}
/*
* 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.file;
import java.io.Writer;
import java.io.IOException;
/**
* Callback interface for writing to a header to a file.
*
* @author Robert Kasanicky
*/
public interface FlatFileHeaderCallback {
/**
* Write contents to a file using the supplied {@link Writer}. It is not
* required to flush the writer inside this method.
*/
void writeHeader(Writer writer) throws IOException;
}

View File

@@ -1,227 +1,243 @@
package org.springframework.batch.item.file;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ReaderNotOpenException;
import org.springframework.batch.item.file.mapping.LineMapper;
import org.springframework.batch.item.file.separator.RecordSeparatorPolicy;
import org.springframework.batch.item.file.separator.SimpleRecordSeparatorPolicy;
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Restartable {@link ItemReader} that reads lines from input
* {@link #setResource(Resource)}. Line is defined by the
* {@link #setRecordSeparatorPolicy(RecordSeparatorPolicy)} and mapped to item
* using {@link #setLineMapper(LineMapper)}.
*
* @author Robert Kasanicky
*/
public class FlatFileItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> implements
ResourceAwareItemReaderItemStream<T>, InitializingBean {
private static final Log logger = LogFactory.getLog(FlatFileItemReader.class);
// default encoding for input files
public static final String DEFAULT_CHARSET = Charset.defaultCharset().name();
private RecordSeparatorPolicy recordSeparatorPolicy = new SimpleRecordSeparatorPolicy();
private Resource resource;
private BufferedReader reader;
private int lineCount = 0;
private String[] comments = new String[] { "#" };
private boolean noInput = false;
private String encoding = DEFAULT_CHARSET;
private LineMapper<T> lineMapper;
private int linesToSkip = 0;
private LineCallbackHandler skippedLinesCallback;
public FlatFileItemReader() {
setName(ClassUtils.getShortName(FlatFileItemReader.class));
}
/**
* @param skippedLinesCallback will be called for each one of the initial skipped
* lines before any items are read.
*/
public void setSkippedLinesCallback(LineCallbackHandler skippedLinesCallback) {
this.skippedLinesCallback = skippedLinesCallback;
}
/**
* 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
*/
public void setLinesToSkip(int linesToSkip) {
this.linesToSkip = linesToSkip;
}
/**
* Setter for line mapper. This property is required to be set.
* @param lineMapper maps line to item
*/
public void setLineMapper(LineMapper<T> lineMapper) {
this.lineMapper = lineMapper;
}
/**
* Setter for the encoding for this input source. Default value is
* {@link #DEFAULT_CHARSET}.
*
* @param encoding a properties object which possibly contains the encoding
* for this input file;
*/
public void setEncoding(String encoding) {
this.encoding = encoding;
}
/**
* 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.
*/
public void setComments(String[] comments) {
this.comments = new String[comments.length];
System.arraycopy(comments, 0, this.comments, 0, comments.length);
}
/**
* Public setter for the input resource.
*/
public void setResource(Resource resource) {
this.resource = resource;
}
/**
* 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
*/
public void setRecordSeparatorPolicy(RecordSeparatorPolicy recordSeparatorPolicy) {
this.recordSeparatorPolicy = recordSeparatorPolicy;
}
/**
* @return string corresponding to logical record according to
* {@link #setRecordSeparatorPolicy(RecordSeparatorPolicy)} (might span
* multiple lines in file).
*/
@Override
protected T doRead() throws Exception {
if (noInput) {
return null;
}
String line = readLine();
String record = line;
if (line != null) {
while (line != null && !recordSeparatorPolicy.isEndOfRecord(record)) {
record = recordSeparatorPolicy.preProcess(record) + (line = readLine());
}
}
String logicalLine = recordSeparatorPolicy.postProcess(record);
if (logicalLine == null) {
return null;
}
else {
return lineMapper.mapLine(logicalLine, lineCount);
}
}
/**
* @return next line (skip comments).
*/
private String readLine() {
if (reader == null) {
throw new ReaderNotOpenException("Reader must be open before it can be read.");
}
String line = null;
try {
line = this.reader.readLine();
if (line == null) {
return null;
}
lineCount++;
while (isComment(line)) {
line = reader.readLine();
if (line == null) {
return null;
}
lineCount++;
}
}
catch (IOException e) {
throw new FlatFileParseException("Unable to read from resource: [" + resource + "]", e, line, lineCount );
}
return line;
}
private boolean isComment(String line) {
for (String prefix : comments) {
if (line.startsWith(prefix)) {
return true;
}
}
return false;
}
@Override
protected void doClose() throws Exception {
lineCount = 0;
reader.close();
}
@Override
protected void doOpen() throws Exception {
Assert.notNull(resource, "Input resource must be set");
Assert.notNull(recordSeparatorPolicy, "RecordSeparatorPolicy must be set");
noInput = false;
if (!resource.exists()) {
noInput = true;
logger.warn("Input resource does not exist");
return;
}
reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), encoding));
for (int i = 0; i < linesToSkip; i++) {
String line = readLine();
if (skippedLinesCallback != null) {
skippedLinesCallback.handleLine(line);
}
}
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(lineMapper, "LineMapper is required");
}
}
/*
* 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.file;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ReaderNotOpenException;
import org.springframework.batch.item.file.mapping.LineMapper;
import org.springframework.batch.item.file.separator.RecordSeparatorPolicy;
import org.springframework.batch.item.file.separator.SimpleRecordSeparatorPolicy;
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Restartable {@link ItemReader} that reads lines from input
* {@link #setResource(Resource)}. Line is defined by the
* {@link #setRecordSeparatorPolicy(RecordSeparatorPolicy)} and mapped to item
* using {@link #setLineMapper(LineMapper)}.
*
* @author Robert Kasanicky
*/
public class FlatFileItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> implements
ResourceAwareItemReaderItemStream<T>, InitializingBean {
private static final Log logger = LogFactory.getLog(FlatFileItemReader.class);
// default encoding for input files
public static final String DEFAULT_CHARSET = Charset.defaultCharset().name();
private RecordSeparatorPolicy recordSeparatorPolicy = new SimpleRecordSeparatorPolicy();
private Resource resource;
private BufferedReader reader;
private int lineCount = 0;
private String[] comments = new String[] { "#" };
private boolean noInput = false;
private String encoding = DEFAULT_CHARSET;
private LineMapper<T> lineMapper;
private int linesToSkip = 0;
private LineCallbackHandler skippedLinesCallback;
public FlatFileItemReader() {
setName(ClassUtils.getShortName(FlatFileItemReader.class));
}
/**
* @param skippedLinesCallback will be called for each one of the initial skipped
* lines before any items are read.
*/
public void setSkippedLinesCallback(LineCallbackHandler skippedLinesCallback) {
this.skippedLinesCallback = skippedLinesCallback;
}
/**
* 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
*/
public void setLinesToSkip(int linesToSkip) {
this.linesToSkip = linesToSkip;
}
/**
* Setter for line mapper. This property is required to be set.
* @param lineMapper maps line to item
*/
public void setLineMapper(LineMapper<T> lineMapper) {
this.lineMapper = lineMapper;
}
/**
* Setter for the encoding for this input source. Default value is
* {@link #DEFAULT_CHARSET}.
*
* @param encoding a properties object which possibly contains the encoding
* for this input file;
*/
public void setEncoding(String encoding) {
this.encoding = encoding;
}
/**
* 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.
*/
public void setComments(String[] comments) {
this.comments = new String[comments.length];
System.arraycopy(comments, 0, this.comments, 0, comments.length);
}
/**
* Public setter for the input resource.
*/
public void setResource(Resource resource) {
this.resource = resource;
}
/**
* 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
*/
public void setRecordSeparatorPolicy(RecordSeparatorPolicy recordSeparatorPolicy) {
this.recordSeparatorPolicy = recordSeparatorPolicy;
}
/**
* @return string corresponding to logical record according to
* {@link #setRecordSeparatorPolicy(RecordSeparatorPolicy)} (might span
* multiple lines in file).
*/
@Override
protected T doRead() throws Exception {
if (noInput) {
return null;
}
String line = readLine();
String record = line;
if (line != null) {
while (line != null && !recordSeparatorPolicy.isEndOfRecord(record)) {
record = recordSeparatorPolicy.preProcess(record) + (line = readLine());
}
}
String logicalLine = recordSeparatorPolicy.postProcess(record);
if (logicalLine == null) {
return null;
}
else {
return lineMapper.mapLine(logicalLine, lineCount);
}
}
/**
* @return next line (skip comments).
*/
private String readLine() {
if (reader == null) {
throw new ReaderNotOpenException("Reader must be open before it can be read.");
}
String line = null;
try {
line = this.reader.readLine();
if (line == null) {
return null;
}
lineCount++;
while (isComment(line)) {
line = reader.readLine();
if (line == null) {
return null;
}
lineCount++;
}
}
catch (IOException e) {
throw new FlatFileParseException("Unable to read from resource: [" + resource + "]", e, line, lineCount );
}
return line;
}
private boolean isComment(String line) {
for (String prefix : comments) {
if (line.startsWith(prefix)) {
return true;
}
}
return false;
}
@Override
protected void doClose() throws Exception {
lineCount = 0;
reader.close();
}
@Override
protected void doOpen() throws Exception {
Assert.notNull(resource, "Input resource must be set");
Assert.notNull(recordSeparatorPolicy, "RecordSeparatorPolicy must be set");
noInput = false;
if (!resource.exists()) {
noInput = true;
logger.warn("Input resource does not exist");
return;
}
reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), encoding));
for (int i = 0; i < linesToSkip; i++) {
String line = readLine();
if (skippedLinesCallback != null) {
skippedLinesCallback.handleLine(line);
}
}
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(lineMapper, "LineMapper is required");
}
}

View File

@@ -1,12 +1,28 @@
package org.springframework.batch.item.file;
/**
* Callback interface for handling a line from file. Useful e.g. for header
* processing.
*
* @author Robert Kasanicky
*/
public interface LineCallbackHandler {
void handleLine(String line);
}
/*
* 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.file;
/**
* Callback interface for handling a line from file. Useful e.g. for header
* processing.
*
* @author Robert Kasanicky
*/
public interface LineCallbackHandler {
void handleLine(String line);
}

View File

@@ -1,245 +1,261 @@
package org.springframework.batch.item.file;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.NoWorkFoundException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.batch.item.util.ExecutionContextUserSupport;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Reads items from multiple resources sequentially - resource list is given by
* {@link #setResources(Resource[])}, the actual reading is delegated to
* {@link #setDelegate(ResourceAwareItemReaderItemStream)}.
*
* Input resources are ordered using {@link #setComparator(Comparator)} to make
* sure resource ordering is preserved between job runs in restart scenario.
*
* Reset (rollback) capability is implemented by item buffering.
*
*
* @author Robert Kasanicky
*/
public class MultiResourceItemReader<T> implements ItemReader<T>, ItemStream {
private static final Log logger = LogFactory.getLog(MultiResourceItemReader.class);
private final ExecutionContextUserSupport executionContextUserSupport = new ExecutionContextUserSupport();
private ResourceAwareItemReaderItemStream<? extends T> delegate;
private Resource[] resources;
private MultiResourceIndex index = new MultiResourceIndex();
private boolean saveState = true;
// signals there are no resources to read -> just return null on first read
private boolean noInput;
private Comparator<Resource> comparator = new Comparator<Resource>() {
/**
* Compares resource filenames.
*/
public int compare(Resource r1, Resource r2) {
return r1.getFilename().compareTo(r2.getFilename());
}
};
public MultiResourceItemReader() {
executionContextUserSupport.setName(ClassUtils.getShortName(MultiResourceItemReader.class));
}
/**
* Reads the next item, jumping to next resource if necessary.
*/
public T read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException {
if (noInput) {
return null;
}
T item;
item = readNextItem();
index.incrementItemCount();
return item;
}
/**
* Use the delegate to read the next item, jump to next resource if current
* one is exhausted. Items are appended to the buffer.
* @return next item from input
*/
private T readNextItem() throws Exception {
T item = delegate.read();
while (item == null) {
index.incrementResourceCount();
if (index.currentResource >= resources.length) {
return null;
}
delegate.close();
delegate.setResource(resources[index.currentResource]);
delegate.open(new ExecutionContext());
item = delegate.read();
}
return item;
}
/**
* Close the {@link #setDelegate(ResourceAwareItemReaderItemStream)} reader
* and reset instance variable values.
*/
public void close() throws ItemStreamException {
index = new MultiResourceIndex();
delegate.close();
noInput = false;
}
/**
* Figure out which resource to start with in case of restart, open the
* delegate and restore delegate's position in the resource.
*/
public void open(ExecutionContext executionContext) throws ItemStreamException {
Assert.notNull(resources, "Resources must be set");
noInput = false;
if (resources.length == 0) {
logger.warn("No resources to read");
noInput = true;
return;
}
Arrays.sort(resources, comparator);
index.open(executionContext);
delegate.setResource(resources[index.currentResource]);
delegate.open(new ExecutionContext());
try {
for (int i = 0; i < index.currentItem; i++) {
delegate.read();
}
}
catch (Exception e) {
throw new ItemStreamException("Could not restore position on restart", e);
}
}
/**
* Store the current resource index and position in the resource.
*/
public void update(ExecutionContext executionContext) throws ItemStreamException {
if (saveState) {
index.update(executionContext);
}
}
/**
* @param delegate reads items from single {@link Resource}.
*/
public void setDelegate(ResourceAwareItemReaderItemStream<? extends T> delegate) {
this.delegate = delegate;
}
/**
* Set the boolean indicating whether or not state should be saved in the
* provided {@link ExecutionContext} during the {@link ItemStream} call to
* update.
*
* @param saveState
*/
public void setSaveState(boolean saveState) {
this.saveState = saveState;
}
/**
* @param comparator used to order the injected resources, by default
* compares {@link Resource#getFilename()} values.
*/
public void setComparator(Comparator<Resource> comparator) {
this.comparator = comparator;
}
/**
* @param resources input resources
*/
public void setResources(Resource[] resources) {
this.resources = resources;
}
/**
* Facilitates keeping track of the position within multi-resource input.
*/
private class MultiResourceIndex {
private static final String RESOURCE_KEY = "resourceIndex";
private static final String ITEM_KEY = "itemIndex";
private int currentResource = 0;
private int markedResource = 0;
private int currentItem = 0;
private int markedItem = 0;
public void incrementItemCount() {
currentItem++;
}
public void incrementResourceCount() {
currentResource++;
currentItem = 0;
}
public void mark() {
markedResource = currentResource;
markedItem = currentItem;
}
public void reset() {
currentResource = markedResource;
currentItem = markedItem;
}
public void open(ExecutionContext ctx) {
if (ctx.containsKey(executionContextUserSupport.getKey(RESOURCE_KEY))) {
currentResource = ctx.getInt(executionContextUserSupport.getKey(RESOURCE_KEY));
}
if (ctx.containsKey(executionContextUserSupport.getKey(ITEM_KEY))) {
currentItem = ctx.getInt(executionContextUserSupport.getKey(ITEM_KEY));
}
}
public void update(ExecutionContext ctx) {
ctx.putInt(executionContextUserSupport.getKey(RESOURCE_KEY), index.currentResource);
ctx.putInt(executionContextUserSupport.getKey(ITEM_KEY), index.currentItem);
}
}
}
/*
* 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.file;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.NoWorkFoundException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.batch.item.util.ExecutionContextUserSupport;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Reads items from multiple resources sequentially - resource list is given by
* {@link #setResources(Resource[])}, the actual reading is delegated to
* {@link #setDelegate(ResourceAwareItemReaderItemStream)}.
*
* Input resources are ordered using {@link #setComparator(Comparator)} to make
* sure resource ordering is preserved between job runs in restart scenario.
*
* Reset (rollback) capability is implemented by item buffering.
*
*
* @author Robert Kasanicky
*/
public class MultiResourceItemReader<T> implements ItemReader<T>, ItemStream {
private static final Log logger = LogFactory.getLog(MultiResourceItemReader.class);
private final ExecutionContextUserSupport executionContextUserSupport = new ExecutionContextUserSupport();
private ResourceAwareItemReaderItemStream<? extends T> delegate;
private Resource[] resources;
private MultiResourceIndex index = new MultiResourceIndex();
private boolean saveState = true;
// signals there are no resources to read -> just return null on first read
private boolean noInput;
private Comparator<Resource> comparator = new Comparator<Resource>() {
/**
* Compares resource filenames.
*/
public int compare(Resource r1, Resource r2) {
return r1.getFilename().compareTo(r2.getFilename());
}
};
public MultiResourceItemReader() {
executionContextUserSupport.setName(ClassUtils.getShortName(MultiResourceItemReader.class));
}
/**
* Reads the next item, jumping to next resource if necessary.
*/
public T read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException {
if (noInput) {
return null;
}
T item;
item = readNextItem();
index.incrementItemCount();
return item;
}
/**
* Use the delegate to read the next item, jump to next resource if current
* one is exhausted. Items are appended to the buffer.
* @return next item from input
*/
private T readNextItem() throws Exception {
T item = delegate.read();
while (item == null) {
index.incrementResourceCount();
if (index.currentResource >= resources.length) {
return null;
}
delegate.close();
delegate.setResource(resources[index.currentResource]);
delegate.open(new ExecutionContext());
item = delegate.read();
}
return item;
}
/**
* Close the {@link #setDelegate(ResourceAwareItemReaderItemStream)} reader
* and reset instance variable values.
*/
public void close() throws ItemStreamException {
index = new MultiResourceIndex();
delegate.close();
noInput = false;
}
/**
* Figure out which resource to start with in case of restart, open the
* delegate and restore delegate's position in the resource.
*/
public void open(ExecutionContext executionContext) throws ItemStreamException {
Assert.notNull(resources, "Resources must be set");
noInput = false;
if (resources.length == 0) {
logger.warn("No resources to read");
noInput = true;
return;
}
Arrays.sort(resources, comparator);
index.open(executionContext);
delegate.setResource(resources[index.currentResource]);
delegate.open(new ExecutionContext());
try {
for (int i = 0; i < index.currentItem; i++) {
delegate.read();
}
}
catch (Exception e) {
throw new ItemStreamException("Could not restore position on restart", e);
}
}
/**
* Store the current resource index and position in the resource.
*/
public void update(ExecutionContext executionContext) throws ItemStreamException {
if (saveState) {
index.update(executionContext);
}
}
/**
* @param delegate reads items from single {@link Resource}.
*/
public void setDelegate(ResourceAwareItemReaderItemStream<? extends T> delegate) {
this.delegate = delegate;
}
/**
* Set the boolean indicating whether or not state should be saved in the
* provided {@link ExecutionContext} during the {@link ItemStream} call to
* update.
*
* @param saveState
*/
public void setSaveState(boolean saveState) {
this.saveState = saveState;
}
/**
* @param comparator used to order the injected resources, by default
* compares {@link Resource#getFilename()} values.
*/
public void setComparator(Comparator<Resource> comparator) {
this.comparator = comparator;
}
/**
* @param resources input resources
*/
public void setResources(Resource[] resources) {
this.resources = resources;
}
/**
* Facilitates keeping track of the position within multi-resource input.
*/
private class MultiResourceIndex {
private static final String RESOURCE_KEY = "resourceIndex";
private static final String ITEM_KEY = "itemIndex";
private int currentResource = 0;
private int markedResource = 0;
private int currentItem = 0;
private int markedItem = 0;
public void incrementItemCount() {
currentItem++;
}
public void incrementResourceCount() {
currentResource++;
currentItem = 0;
}
public void mark() {
markedResource = currentResource;
markedItem = currentItem;
}
public void reset() {
currentResource = markedResource;
currentItem = markedItem;
}
public void open(ExecutionContext ctx) {
if (ctx.containsKey(executionContextUserSupport.getKey(RESOURCE_KEY))) {
currentResource = ctx.getInt(executionContextUserSupport.getKey(RESOURCE_KEY));
}
if (ctx.containsKey(executionContextUserSupport.getKey(ITEM_KEY))) {
currentItem = ctx.getInt(executionContextUserSupport.getKey(ITEM_KEY));
}
}
public void update(ExecutionContext ctx) {
ctx.putInt(executionContextUserSupport.getKey(RESOURCE_KEY), index.currentResource);
ctx.putInt(executionContextUserSupport.getKey(ITEM_KEY), index.currentItem);
}
}
}

View File

@@ -1,141 +1,157 @@
package org.springframework.batch.item.file;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.util.ExecutionContextUserSupport;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Wraps a {@link ResourceAwareItemWriterItemStream} and creates a new output
* resource when the count of items written in current resource exceeds
* {@link #setItemCountLimitPerResource(int)}. Suffix creation can be customized
* with {@link #setResourceSuffixCreator(ResourceSuffixCreator)}.
*
* Note that new resources are created only at chunk boundaries i.e. the number
* of items written into one resource is between the limit set by
* {@link #setItemCountLimitPerResource(int)} and (limit + chunk size).
*
* @param <T> item type
*
* @author Robert Kasanicky
*/
public class MultiResourceItemWriter<T> extends ExecutionContextUserSupport implements ItemWriter<T>, ItemStream {
final static private String RESOURCE_INDEX_KEY = "resource.index";
final static private String CURRENT_RESOURCE_ITEM_COUNT = "resource.item.count";
private Resource resource;
private ResourceAwareItemWriterItemStream<? super T> delegate;
private int itemCountLimitPerResource = Integer.MAX_VALUE;
private int currentResourceItemCount = 0;
private int resourceIndex = 1;
private ResourceSuffixCreator suffixCreator = new SimpleResourceSuffixCreator();
private boolean saveState = true;
public MultiResourceItemWriter() {
setName(ClassUtils.getShortName(MultiResourceItemWriter.class));
}
public void write(List<? extends T> items) throws Exception {
if (currentResourceItemCount >= itemCountLimitPerResource) {
delegate.close();
resourceIndex++;
currentResourceItemCount = 0;
setResourceToDelegate();
delegate.open(new ExecutionContext());
}
delegate.write(items);
currentResourceItemCount += items.size();
}
/**
* Allows customization of the suffix of the created resources based on the
* index.
*/
public void setResourceSuffixCreator(ResourceSuffixCreator suffixCreator) {
this.suffixCreator = suffixCreator;
}
/**
* After this limit is exceeded the next chunk will be written into newly
* created resource.
*/
public void setItemCountLimitPerResource(int itemCountLimitPerResource) {
this.itemCountLimitPerResource = itemCountLimitPerResource;
}
/**
* Delegate used for actual writing of the output.
*/
public void setDelegate(ResourceAwareItemWriterItemStream<? super T> delegate) {
this.delegate = delegate;
}
/**
* Prototype for output resources. Actual output files will be created in
* the same directory and use the same name as this prototype with appended
* suffix (according to
* {@link #setResourceSuffixCreator(ResourceSuffixCreator)}.
*/
public void setResource(Resource resource) {
this.resource = resource;
}
public void setSaveState(boolean saveState) {
this.saveState = saveState;
}
public void close() throws ItemStreamException {
resourceIndex = 1;
currentResourceItemCount = 0;
delegate.close();
}
public void open(ExecutionContext executionContext) throws ItemStreamException {
resourceIndex = executionContext.getInt(getKey(RESOURCE_INDEX_KEY), 1);
currentResourceItemCount = executionContext.getInt(getKey(CURRENT_RESOURCE_ITEM_COUNT), 0);
try {
setResourceToDelegate();
}
catch (IOException e) {
throw new ItemStreamException("Couldn't open resource", e);
}
delegate.open(executionContext);
}
public void update(ExecutionContext executionContext) throws ItemStreamException {
if (saveState) {
delegate.update(executionContext);
executionContext.putInt(getKey(CURRENT_RESOURCE_ITEM_COUNT), currentResourceItemCount);
executionContext.putInt(getKey(RESOURCE_INDEX_KEY), resourceIndex);
}
}
/**
* Create output resource (if necessary) and point the delegate to it.
*/
private void setResourceToDelegate() throws IOException {
String path = resource.getFile().getAbsolutePath() + suffixCreator.getSuffix(resourceIndex);
File file = new File(path);
file.createNewFile();
Assert.state(file.canWrite(), "Output resource " + path + " must be writable");
delegate.setResource(new FileSystemResource(file));
}
}
/*
* 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.file;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.util.ExecutionContextUserSupport;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Wraps a {@link ResourceAwareItemWriterItemStream} and creates a new output
* resource when the count of items written in current resource exceeds
* {@link #setItemCountLimitPerResource(int)}. Suffix creation can be customized
* with {@link #setResourceSuffixCreator(ResourceSuffixCreator)}.
*
* Note that new resources are created only at chunk boundaries i.e. the number
* of items written into one resource is between the limit set by
* {@link #setItemCountLimitPerResource(int)} and (limit + chunk size).
*
* @param <T> item type
*
* @author Robert Kasanicky
*/
public class MultiResourceItemWriter<T> extends ExecutionContextUserSupport implements ItemWriter<T>, ItemStream {
final static private String RESOURCE_INDEX_KEY = "resource.index";
final static private String CURRENT_RESOURCE_ITEM_COUNT = "resource.item.count";
private Resource resource;
private ResourceAwareItemWriterItemStream<? super T> delegate;
private int itemCountLimitPerResource = Integer.MAX_VALUE;
private int currentResourceItemCount = 0;
private int resourceIndex = 1;
private ResourceSuffixCreator suffixCreator = new SimpleResourceSuffixCreator();
private boolean saveState = true;
public MultiResourceItemWriter() {
setName(ClassUtils.getShortName(MultiResourceItemWriter.class));
}
public void write(List<? extends T> items) throws Exception {
if (currentResourceItemCount >= itemCountLimitPerResource) {
delegate.close();
resourceIndex++;
currentResourceItemCount = 0;
setResourceToDelegate();
delegate.open(new ExecutionContext());
}
delegate.write(items);
currentResourceItemCount += items.size();
}
/**
* Allows customization of the suffix of the created resources based on the
* index.
*/
public void setResourceSuffixCreator(ResourceSuffixCreator suffixCreator) {
this.suffixCreator = suffixCreator;
}
/**
* After this limit is exceeded the next chunk will be written into newly
* created resource.
*/
public void setItemCountLimitPerResource(int itemCountLimitPerResource) {
this.itemCountLimitPerResource = itemCountLimitPerResource;
}
/**
* Delegate used for actual writing of the output.
*/
public void setDelegate(ResourceAwareItemWriterItemStream<? super T> delegate) {
this.delegate = delegate;
}
/**
* Prototype for output resources. Actual output files will be created in
* the same directory and use the same name as this prototype with appended
* suffix (according to
* {@link #setResourceSuffixCreator(ResourceSuffixCreator)}.
*/
public void setResource(Resource resource) {
this.resource = resource;
}
public void setSaveState(boolean saveState) {
this.saveState = saveState;
}
public void close() throws ItemStreamException {
resourceIndex = 1;
currentResourceItemCount = 0;
delegate.close();
}
public void open(ExecutionContext executionContext) throws ItemStreamException {
resourceIndex = executionContext.getInt(getKey(RESOURCE_INDEX_KEY), 1);
currentResourceItemCount = executionContext.getInt(getKey(CURRENT_RESOURCE_ITEM_COUNT), 0);
try {
setResourceToDelegate();
}
catch (IOException e) {
throw new ItemStreamException("Couldn't open resource", e);
}
delegate.open(executionContext);
}
public void update(ExecutionContext executionContext) throws ItemStreamException {
if (saveState) {
delegate.update(executionContext);
executionContext.putInt(getKey(CURRENT_RESOURCE_ITEM_COUNT), currentResourceItemCount);
executionContext.putInt(getKey(RESOURCE_INDEX_KEY), resourceIndex);
}
}
/**
* Create output resource (if necessary) and point the delegate to it.
*/
private void setResourceToDelegate() throws IOException {
String path = resource.getFile().getAbsolutePath() + suffixCreator.getSuffix(resourceIndex);
File file = new File(path);
file.createNewFile();
Assert.state(file.canWrite(), "Output resource " + path + " must be writable");
delegate.setResource(new FileSystemResource(file));
}
}

View File

@@ -1,16 +1,32 @@
package org.springframework.batch.item.file;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.core.io.Resource;
/**
* Interface for {@link ItemReader}s that implement {@link ItemStream} and read
* input from {@link Resource}.
*
* @author Robert Kasanicky
*/
public interface ResourceAwareItemReaderItemStream<T> extends ItemReader<T>, ItemStream {
void setResource(Resource resource);
}
/*
* 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.file;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.core.io.Resource;
/**
* Interface for {@link ItemReader}s that implement {@link ItemStream} and read
* input from {@link Resource}.
*
* @author Robert Kasanicky
*/
public interface ResourceAwareItemReaderItemStream<T> extends ItemReader<T>, ItemStream {
void setResource(Resource resource);
}

View File

@@ -1,16 +1,32 @@
package org.springframework.batch.item.file;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemWriter;
import org.springframework.core.io.Resource;
/**
* Interface for {@link ItemWriter}s that implement {@link ItemStream} and write
* output to {@link Resource}.
*
* @author Robert Kasanicky
*/
public interface ResourceAwareItemWriterItemStream<T> extends ItemStream, ItemWriter<T> {
void setResource(Resource resource);
}
/*
* 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.file;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemWriter;
import org.springframework.core.io.Resource;
/**
* Interface for {@link ItemWriter}s that implement {@link ItemStream} and write
* output to {@link Resource}.
*
* @author Robert Kasanicky
*/
public interface ResourceAwareItemWriterItemStream<T> extends ItemStream, ItemWriter<T> {
void setResource(Resource resource);
}

View File

@@ -1,15 +1,31 @@
package org.springframework.batch.item.file;
/**
* Strategy interface for translating resource index into unique filename
* suffix.
*
* @see MultiResourceItemWriter
* @see SimpleResourceSuffixCreator
*
* @author Robert Kasanicky
*/
public interface ResourceSuffixCreator {
String getSuffix(int index);
}
/*
* 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.file;
/**
* Strategy interface for translating resource index into unique filename
* suffix.
*
* @see MultiResourceItemWriter
* @see SimpleResourceSuffixCreator
*
* @author Robert Kasanicky
*/
public interface ResourceSuffixCreator {
String getSuffix(int index);
}

View File

@@ -1,15 +1,31 @@
package org.springframework.batch.item.file;
/**
* Trivial implementation of {@link ResourceSuffixCreator} that uses the index
* itself as suffix, separated by dot.
*
* @author Robert Kasanicky
*/
public class SimpleResourceSuffixCreator implements ResourceSuffixCreator {
public String getSuffix(int index) {
return "." + index;
}
}
/*
* 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.file;
/**
* Trivial implementation of {@link ResourceSuffixCreator} that uses the index
* itself as suffix, separated by dot.
*
* @author Robert Kasanicky
*/
public class SimpleResourceSuffixCreator implements ResourceSuffixCreator {
public String getSuffix(int index) {
return "." + index;
}
}

View File

@@ -1,39 +1,55 @@
package org.springframework.batch.item.file.mapping;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.batch.item.file.transform.LineTokenizer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* Two-phase {@link LineMapper} implementation consisting of tokenization of the
* line into {@link FieldSet} followed by mapping to item.
*
* @author Robert Kasanicky
*
* @param <T> type of the item
*/
public class DefaultLineMapper<T> implements LineMapper<T>, InitializingBean {
private LineTokenizer tokenizer;
private FieldSetMapper<T> fieldSetMapper;
public T mapLine(String line, int lineNumber) throws Exception {
return fieldSetMapper.mapFieldSet(tokenizer.tokenize(line));
}
public void setLineTokenizer(LineTokenizer tokenizer) {
this.tokenizer = tokenizer;
}
public void setFieldSetMapper(FieldSetMapper<T> fieldSetMapper) {
this.fieldSetMapper = fieldSetMapper;
}
public void afterPropertiesSet() {
Assert.notNull(tokenizer, "The LineTokenizer must be set");
Assert.notNull(fieldSetMapper, "The FieldSetMapper must be set");
}
}
/*
* 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.file.mapping;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.batch.item.file.transform.LineTokenizer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* Two-phase {@link LineMapper} implementation consisting of tokenization of the
* line into {@link FieldSet} followed by mapping to item.
*
* @author Robert Kasanicky
*
* @param <T> type of the item
*/
public class DefaultLineMapper<T> implements LineMapper<T>, InitializingBean {
private LineTokenizer tokenizer;
private FieldSetMapper<T> fieldSetMapper;
public T mapLine(String line, int lineNumber) throws Exception {
return fieldSetMapper.mapFieldSet(tokenizer.tokenize(line));
}
public void setLineTokenizer(LineTokenizer tokenizer) {
this.tokenizer = tokenizer;
}
public void setFieldSetMapper(FieldSetMapper<T> fieldSetMapper) {
this.fieldSetMapper = fieldSetMapper;
}
public void afterPropertiesSet() {
Assert.notNull(tokenizer, "The LineTokenizer must be set");
Assert.notNull(fieldSetMapper, "The FieldSetMapper must be set");
}
}

View File

@@ -1,31 +1,47 @@
package org.springframework.batch.item.file.mapping;
import org.springframework.batch.item.file.transform.LineTokenizer;
/**
* Interface for mapping lines (strings) to domain objects typically used to map lines read from a file to domain objects
* on a per line basis. Implementations of this interface perform the actual
* work of parsing a line without having to deal with how the line was
* obtained.
*
* @author Robert Kasanicky
* @param <T> type of the domain object
* @see FieldSetMapper
* @see LineTokenizer
* @since 2.0
*/
public interface LineMapper<T> {
/**
* Implementations must implement this method to map the provided line to
* the parameter type T. The line number represents the number of lines
* into a file the current line resides.
*
* @param line to be mapped
* @param lineNumber of the current line
* @return mapped object of type T
* @throws Exception if error occured while parsing.
*/
T mapLine(String line, int lineNumber) throws Exception;
}
/*
* 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.file.mapping;
import org.springframework.batch.item.file.transform.LineTokenizer;
/**
* Interface for mapping lines (strings) to domain objects typically used to map lines read from a file to domain objects
* on a per line basis. Implementations of this interface perform the actual
* work of parsing a line without having to deal with how the line was
* obtained.
*
* @author Robert Kasanicky
* @param <T> type of the domain object
* @see FieldSetMapper
* @see LineTokenizer
* @since 2.0
*/
public interface LineMapper<T> {
/**
* Implementations must implement this method to map the provided line to
* the parameter type T. The line number represents the number of lines
* into a file the current line resides.
*
* @param line to be mapped
* @param lineNumber of the current line
* @return mapped object of type T
* @throws Exception if error occured while parsing.
*/
T mapLine(String line, int lineNumber) throws Exception;
}

View File

@@ -1,9 +1,25 @@
package org.springframework.batch.item.file.mapping;
public class PassThroughLineMapper implements LineMapper<String>{
public String mapLine(String line, int lineNumber) throws Exception {
return line;
}
}
/*
* 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.file.mapping;
public class PassThroughLineMapper implements LineMapper<String>{
public String mapLine(String line, int lineNumber) throws Exception {
return line;
}
}

View File

@@ -1,15 +1,31 @@
package org.springframework.batch.item.file.transform;
public class PassThroughLineAggregator<T> implements LineAggregator<T> {
/**
* Simply convert to a String with toString().
*
* @see org.springframework.batch.item.file.transform.LineAggregator#aggregate(java.lang.Object)
*/
public String aggregate(T item) {
return item.toString();
}
}
/*
* 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.file.transform;
public class PassThroughLineAggregator<T> implements LineAggregator<T> {
/**
* Simply convert to a String with toString().
*
* @see org.springframework.batch.item.file.transform.LineAggregator#aggregate(java.lang.Object)
*/
public String aggregate(T item) {
return item.toString();
}
}

View File

@@ -1,3 +1,19 @@
/*
* 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.file.transform;
import org.springframework.util.Assert;

View File

@@ -1,3 +1,19 @@
/*
* 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.file.transform;
import java.beans.PropertyEditorSupport;

View File

@@ -1,3 +1,19 @@
/*
* 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.file.transform;
import java.util.Collection;

View File

@@ -1,129 +1,145 @@
package org.springframework.batch.item.support;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.batch.item.util.ExecutionContextUserSupport;
import org.springframework.util.Assert;
/**
* Abstract superclass for {@link ItemReader}s that supports restart by storing
* item count in the {@link ExecutionContext} (therefore requires item ordering
* to be preserved between runs).
*
* Subclasses are inherently *not* thread-safe.
*
* @author Robert Kasanicky
*/
public abstract class AbstractItemCountingItemStreamItemReader<T> implements ItemReader<T>, ItemStream {
private static final String READ_COUNT = "read.count";
private int currentItemCount = 0;
private ExecutionContextUserSupport ecSupport = new ExecutionContextUserSupport();
private boolean saveState = true;
/**
* Read next item from input.
* @return item
* @throws Exception
*/
protected abstract T doRead() throws Exception;
/**
* Open resources necessary to start reading input.
*/
protected abstract void doOpen() throws Exception;
/**
* Close the resources opened in {@link #doOpen()}.
*/
protected abstract void doClose() throws Exception;
/**
* Move to the given item index. Subclasses should override this method if
* there is a more efficient way of moving to given index than re-reading
* the input using {@link #doRead()}.
*/
protected void jumpToItem(int itemIndex) throws Exception {
for (int i = 0; i < itemIndex; i++) {
doRead();
}
}
public T read() throws Exception, UnexpectedInputException, ParseException {
currentItemCount++;
return doRead();
}
protected int getCurrentItemCount() {
return currentItemCount;
}
protected void setCurrentItemCount(int count) {
this.currentItemCount = count;
}
public void close() throws ItemStreamException {
currentItemCount = 0;
try {
doClose();
}
catch (Exception e) {
throw new ItemStreamException("Error while closing item reader", e);
}
}
public void open(ExecutionContext executionContext) throws ItemStreamException {
try {
doOpen();
}
catch (Exception e) {
throw new ItemStreamException("Failed to initialize the reader", e);
}
if (executionContext.containsKey(ecSupport.getKey(READ_COUNT))) {
int itemCount = executionContext.getInt(ecSupport.getKey(READ_COUNT));
try {
jumpToItem(itemCount);
}
catch (Exception e) {
throw new ItemStreamException("Could not move to stored position on restart", e);
}
currentItemCount = itemCount;
}
}
public void update(ExecutionContext executionContext) throws ItemStreamException {
if (saveState) {
Assert.notNull(executionContext, "ExecutionContext must not be null");
executionContext.putInt(ecSupport.getKey(READ_COUNT), currentItemCount);
}
}
public void setName(String name) {
ecSupport.setName(name);
}
/**
* Set the flag that determines whether to save internal data for
* {@link ExecutionContext}. Only switch this to false if you don't want to
* save any state from this stream, and you don't need it to be restartable.
*
* @param saveState flag value (default true).
*/
public void setSaveState(boolean saveState) {
this.saveState = saveState;
}
}
/*
* 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.support;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.batch.item.util.ExecutionContextUserSupport;
import org.springframework.util.Assert;
/**
* Abstract superclass for {@link ItemReader}s that supports restart by storing
* item count in the {@link ExecutionContext} (therefore requires item ordering
* to be preserved between runs).
*
* Subclasses are inherently *not* thread-safe.
*
* @author Robert Kasanicky
*/
public abstract class AbstractItemCountingItemStreamItemReader<T> implements ItemReader<T>, ItemStream {
private static final String READ_COUNT = "read.count";
private int currentItemCount = 0;
private ExecutionContextUserSupport ecSupport = new ExecutionContextUserSupport();
private boolean saveState = true;
/**
* Read next item from input.
* @return item
* @throws Exception
*/
protected abstract T doRead() throws Exception;
/**
* Open resources necessary to start reading input.
*/
protected abstract void doOpen() throws Exception;
/**
* Close the resources opened in {@link #doOpen()}.
*/
protected abstract void doClose() throws Exception;
/**
* Move to the given item index. Subclasses should override this method if
* there is a more efficient way of moving to given index than re-reading
* the input using {@link #doRead()}.
*/
protected void jumpToItem(int itemIndex) throws Exception {
for (int i = 0; i < itemIndex; i++) {
doRead();
}
}
public T read() throws Exception, UnexpectedInputException, ParseException {
currentItemCount++;
return doRead();
}
protected int getCurrentItemCount() {
return currentItemCount;
}
protected void setCurrentItemCount(int count) {
this.currentItemCount = count;
}
public void close() throws ItemStreamException {
currentItemCount = 0;
try {
doClose();
}
catch (Exception e) {
throw new ItemStreamException("Error while closing item reader", e);
}
}
public void open(ExecutionContext executionContext) throws ItemStreamException {
try {
doOpen();
}
catch (Exception e) {
throw new ItemStreamException("Failed to initialize the reader", e);
}
if (executionContext.containsKey(ecSupport.getKey(READ_COUNT))) {
int itemCount = executionContext.getInt(ecSupport.getKey(READ_COUNT));
try {
jumpToItem(itemCount);
}
catch (Exception e) {
throw new ItemStreamException("Could not move to stored position on restart", e);
}
currentItemCount = itemCount;
}
}
public void update(ExecutionContext executionContext) throws ItemStreamException {
if (saveState) {
Assert.notNull(executionContext, "ExecutionContext must not be null");
executionContext.putInt(ecSupport.getKey(READ_COUNT), currentItemCount);
}
}
public void setName(String name) {
ecSupport.setName(name);
}
/**
* Set the flag that determines whether to save internal data for
* {@link ExecutionContext}. Only switch this to false if you don't want to
* save any state from this stream, and you don't need it to be restartable.
*
* @param saveState flag value (default true).
*/
public void setSaveState(boolean saveState) {
this.saveState = saveState;
}
}

View File

@@ -1,3 +1,19 @@
/*
* 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.support;
import java.util.List;

View File

@@ -1,3 +1,19 @@
/*
* 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.support;
import java.util.Arrays;

View File

@@ -1,3 +1,19 @@
/*
* 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.support;
import org.springframework.batch.item.ItemProcessor;

View File

@@ -1,3 +1,19 @@
/*
* 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.util;
import java.io.File;

View File

@@ -1,42 +1,58 @@
package org.springframework.batch.item.validator;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.util.Assert;
/**
* Simple implementation of {@link ItemProcessor} validates and input and
* returns it without modifications.
*
* @author Robert Kasanicky
*
*/
public class ValidatingItemProcessor<T> implements ItemProcessor<T, T> {
private Validator validator;
public ValidatingItemProcessor(Validator validator){
Assert.notNull(validator, "Validator must not be null.");
this.validator = validator;
}
/**
* Set the validator used to validate each item.
*
* @param validator
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/**
* Validate the item and return it unmodified
*
* @return the input item
* @throws ValidationException if validation fails
*/
public T process(T item) throws ValidationException {
validator.validate(item);
return item;
}
}
/*
* 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.validator;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.util.Assert;
/**
* Simple implementation of {@link ItemProcessor} validates and input and
* returns it without modifications.
*
* @author Robert Kasanicky
*
*/
public class ValidatingItemProcessor<T> implements ItemProcessor<T, T> {
private Validator validator;
public ValidatingItemProcessor(Validator validator){
Assert.notNull(validator, "Validator must not be null.");
this.validator = validator;
}
/**
* Set the validator used to validate each item.
*
* @param validator
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/**
* Validate the item and return it unmodified
*
* @return the input item
* @throws ValidationException if validation fails
*/
public T process(T item) throws ValidationException {
validator.validate(item);
return item;
}
}

View File

@@ -1,3 +1,19 @@
/*
* 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.xml;
import java.io.InputStream;

View File

@@ -1,3 +1,19 @@
/*
* 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.xml;
import java.io.File;

View File

@@ -1,20 +1,36 @@
package org.springframework.batch.item.xml;
import java.io.IOException;
import javax.xml.stream.XMLEventWriter;
/**
* Callback interface for writing to an XML file - useful e.g. for handling headers
* and footers.
*
* @author Robert Kasanicky
*/
public interface StaxWriterCallback {
/**
* Write contents using the supplied {@link XMLEventWriter}. It is not
* required to flush the writer inside this method.
*/
void write(XMLEventWriter writer) throws IOException;
}
/*
* 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.xml;
import java.io.IOException;
import javax.xml.stream.XMLEventWriter;
/**
* Callback interface for writing to an XML file - useful e.g. for handling headers
* and footers.
*
* @author Robert Kasanicky
*/
public interface StaxWriterCallback {
/**
* Write contents using the supplied {@link XMLEventWriter}. It is not
* required to flush the writer inside this method.
*/
void write(XMLEventWriter writer) throws IOException;
}

View File

@@ -1,3 +1,19 @@
/*
* 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.xml.stax;
import javax.xml.stream.XMLEventReader;

View File

@@ -1,3 +1,19 @@
/*
* 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.xml.stax;
import javax.xml.namespace.NamespaceContext;

View File

@@ -1,3 +1,19 @@
/*
* 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.xml.stax;
import java.util.NoSuchElementException;

View File

@@ -1,3 +1,19 @@
/*
* 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.xml.stax;
import javax.xml.stream.XMLEventReader;

View File

@@ -1,3 +1,19 @@
/*
* 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.xml.stax;
import javax.xml.stream.XMLEventWriter;

View File

@@ -1,3 +1,19 @@
/*
* 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.repeat;
public enum RepeatStatus {

View File

@@ -1,3 +1,19 @@
/*
* 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.repeat.support;
import org.springframework.batch.repeat.RepeatStatus;

View File

@@ -1,6 +1,19 @@
/**
*
/*
* 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.support;
import java.util.HashMap;