diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/listener/RepeatListenerItemReadListenerAdapter.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/listener/RepeatListenerItemReadListenerAdapter.java
new file mode 100644
index 000000000..97672b49d
--- /dev/null
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/listener/RepeatListenerItemReadListenerAdapter.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.execution.listener;
+
+import org.springframework.batch.core.domain.ItemReadListener;
+import org.springframework.batch.repeat.RepeatContext;
+import org.springframework.batch.repeat.RepeatListener;
+import org.springframework.batch.repeat.synch.RepeatSynchronizationManager;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Adapts a {@link RepeatListener} to the {@link ItemReadListener} interface.
+ * The {@link RepeatListener} is assumed to be targeted at the chunk operations
+ * in a step, so after an item corresponds to the after method in
+ * {@link RepeatListener}.
+ *
+ * The open and close methods on the {@link RepeatListener} are also invoked.
+ * The open method is called on the first call to {@link #beforeRead()}, and
+ * the close is registered as a destruction callback in the
+ * {@link RepeatContext}.
+ *
+ * A {@link RepeatContext} is obtained as needed from the
+ * {@link RepeatSynchronizationManager}.
+ *
+ * @author Dave Syer
+ *
+ */
+public class RepeatListenerItemReadListenerAdapter implements ItemReadListener {
+
+ private RepeatListener delegate;
+
+ /**
+ * @param delegate
+ */
+ public RepeatListenerItemReadListenerAdapter(RepeatListener delegate) {
+ super();
+ this.delegate = delegate;
+ }
+
+ /**
+ * Does nothing.
+ *
+ * @see org.springframework.batch.core.domain.ItemReadListener#afterRead(java.lang.Object)
+ */
+ public void afterRead(Object item) {
+ // NO-OP
+
+ }
+
+ /**
+ * Calls the delegate {@link RepeatListener#before}. Also calls
+ * {@link RepeatListener#open} if it hasn't been called yet on this context.
+ *
+ * @see org.springframework.batch.core.domain.ItemReadListener#beforeRead()
+ */
+ public void beforeRead() {
+ RepeatContext context = RepeatSynchronizationManager.getContext();
+ maybeOpen(context);
+ delegate.before(context);
+ }
+
+ /**
+ * @param context
+ */
+ private void maybeOpen(final RepeatContext context) {
+ String identity = ObjectUtils.identityToString(delegate);
+ if (!context.hasAttribute(identity)) {
+ context.setAttribute(identity, Boolean.TRUE);
+ delegate.open(context);
+ context.registerDestructionCallback(identity, new Runnable() {
+ public void run() {
+ delegate.close(context);
+ }
+ });
+ }
+ }
+
+ /**
+ * Calls the delegate {@link RepeatListener#onError}.
+ *
+ * @see org.springframework.batch.core.domain.ItemReadListener#onReadError(java.lang.Exception)
+ */
+ public void onReadError(Exception ex) {
+ delegate.onError(RepeatSynchronizationManager.getContext(), ex);
+ }
+
+}
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/listener/RepeatListenerItemWriteListenerAdapter.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/listener/RepeatListenerItemWriteListenerAdapter.java
new file mode 100644
index 000000000..00b8ad68c
--- /dev/null
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/listener/RepeatListenerItemWriteListenerAdapter.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.execution.listener;
+
+import org.springframework.batch.core.domain.ItemWriteListener;
+import org.springframework.batch.repeat.ExitStatus;
+import org.springframework.batch.repeat.RepeatContext;
+import org.springframework.batch.repeat.RepeatListener;
+import org.springframework.batch.repeat.synch.RepeatSynchronizationManager;
+
+/**
+ * Adapts a {@link RepeatListener} to the {@link ItemWriteListener} interface.
+ * The {@link RepeatListener} is assumed to be targeted at the chunk operations
+ * in a step, so after an item corresponds to the after method in
+ * {@link RepeatListener}.
+ *
+ * A {@link RepeatContext} is obtained as needed from the
+ * {@link RepeatSynchronizationManager}.
+ *
+ * @author Dave Syer
+ *
+ */
+public class RepeatListenerItemWriteListenerAdapter implements ItemWriteListener {
+
+ private RepeatListener delegate;
+
+ /**
+ * @param delegate
+ */
+ public RepeatListenerItemWriteListenerAdapter(RepeatListener delegate) {
+ super();
+ this.delegate = delegate;
+ }
+
+ /**
+ * Calls the delegate {@link RepeatListener#after} with
+ * {@link ExitStatus#CONTINUABLE}.
+ *
+ * @see org.springframework.batch.core.domain.ItemWriteListener#afterWrite()
+ */
+ public void afterWrite() {
+ delegate.after(RepeatSynchronizationManager.getContext(), ExitStatus.CONTINUABLE);
+ }
+
+ /**
+ * Does nothing.
+ *
+ * @see org.springframework.batch.core.domain.ItemWriteListener#beforeWrite(java.lang.Object)
+ */
+ public void beforeWrite(Object item) {
+ // NO-OP
+ }
+
+ /**
+ * Calls the delegate {@link RepeatListener#onError} ignoring the item.
+ *
+ * @see org.springframework.batch.core.domain.ItemWriteListener#onWriteError(java.lang.Exception,
+ * java.lang.Object)
+ */
+ public void onWriteError(Exception ex, Object item) {
+ delegate.onError(RepeatSynchronizationManager.getContext(), ex);
+ }
+
+}
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/ItemOrientedStep.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/ItemOrientedStep.java
index ee3984af6..b3437f508 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/ItemOrientedStep.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/ItemOrientedStep.java
@@ -295,7 +295,6 @@ public class ItemOrientedStep extends AbstractStep implements InitializingBean {
listener.update(stepExecution.getExecutionContext());
try {
- stepExecution.setStatus(BatchStatus.COMPLETED);
jobRepository.saveOrUpdateExecutionContext(stepExecution);
}
catch (Exception e) {
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/ListenerMulticaster.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/ListenerMulticaster.java
index 444ee3194..c765e9a72 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/ListenerMulticaster.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/ListenerMulticaster.java
@@ -25,11 +25,15 @@ import org.springframework.batch.execution.listener.CompositeChunkListener;
import org.springframework.batch.execution.listener.CompositeItemReadListener;
import org.springframework.batch.execution.listener.CompositeItemWriteListener;
import org.springframework.batch.execution.listener.CompositeStepListener;
+import org.springframework.batch.execution.listener.RepeatListenerItemReadListenerAdapter;
+import org.springframework.batch.execution.listener.RepeatListenerItemWriteListenerAdapter;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.exception.StreamException;
import org.springframework.batch.item.stream.CompositeItemStream;
import org.springframework.batch.repeat.ExitStatus;
+import org.springframework.batch.repeat.RepeatListener;
+import org.springframework.batch.repeat.interceptor.CompositeRepeatListener;
/**
* @author Dave Syer
@@ -48,6 +52,17 @@ public class ListenerMulticaster implements ItemStream, StepListener, ChunkListe
private CompositeItemWriteListener itemWriteListener = new CompositeItemWriteListener();
+ private CompositeRepeatListener repeatListener = new CompositeRepeatListener();
+
+ /**
+ * Initialise the listener instance.
+ */
+ public ListenerMulticaster() {
+ super();
+ itemWriteListener.register(new RepeatListenerItemWriteListenerAdapter(repeatListener));
+ itemReadListener.register(new RepeatListenerItemReadListenerAdapter(repeatListener));
+ }
+
/**
* Register each of the objects as listeners. Once registered, calls to the
* {@link ListenerMulticaster} broadcast to the individual listeners.
@@ -82,6 +97,9 @@ public class ListenerMulticaster implements ItemStream, StepListener, ChunkListe
if (listener instanceof ItemWriteListener) {
this.itemWriteListener.register((ItemWriteListener) listener);
}
+ if (listener instanceof RepeatListener) {
+ this.repeatListener.register((RepeatListener) listener);
+ }
}
/**
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/support/HibernateAwareItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/support/HibernateAwareItemWriter.java
index f5087cf6d..c53c751cc 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/support/HibernateAwareItemWriter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/support/HibernateAwareItemWriter.java
@@ -22,11 +22,10 @@ import org.hibernate.SessionFactory;
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.ExitStatus;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.RepeatListener;
+import org.springframework.batch.repeat.synch.RepeatSynchronizationManager;
import org.springframework.beans.factory.InitializingBean;
-import org.springframework.core.AttributeAccessor;
import org.springframework.orm.hibernate3.HibernateOperations;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@@ -46,19 +45,13 @@ import org.springframework.util.Assert;
* @author Dave Syer
*
*/
-public class HibernateAwareItemWriter implements ItemWriter, RepeatListener, InitializingBean {
+public class HibernateAwareItemWriter implements ItemWriter, InitializingBean {
/**
* Key for items processed in the current transaction {@link RepeatContext}.
*/
private static final String ITEMS_PROCESSED = HibernateAwareItemWriter.class.getName() + ".ITEMS_PROCESSED";
- /**
- * Key for {@link RepeatContext} in transaction resource context.
- */
- private static final String WRITER_REPEAT_CONTEXT = HibernateAwareItemWriter.class.getName()
- + ".WRITER_REPEAT_CONTEXT";
-
private Set failed = new HashSet();
private ItemWriter delegate;
@@ -112,99 +105,21 @@ public class HibernateAwareItemWriter implements ItemWriter, RepeatListener, Ini
* @see org.springframework.batch.io.OutputSource#write(java.lang.Object)
*/
public void write(Object output) throws Exception {
+ bindTransactionResources();
getProcessed().add(output);
delegate.write(output);
flushIfNecessary(output);
}
- /**
- * Does nothing unless the delegate is also a {@link RepeatListener} in
- * which case pass on the call to him.
- *
- * @see org.springframework.batch.repeat.RepeatListener#before(org.springframework.batch.repeat.RepeatContext)
- */
- public void before(RepeatContext context) {
- if (delegate instanceof RepeatListener) {
- RepeatListener interceptor = (RepeatListener) delegate;
- interceptor.before(context);
- }
- }
-
- /**
- * Does nothing unless the delegate is also a {@link RepeatListener} in
- * which case pass on the call to him.
- *
- * @see org.springframework.batch.repeat.RepeatListener#after(org.springframework.batch.repeat.RepeatContext,
- * org.springframework.batch.repeat.ExitStatus)
- */
- public void after(RepeatContext context, ExitStatus result) {
- if (delegate instanceof RepeatListener) {
- RepeatListener interceptor = (RepeatListener) delegate;
- interceptor.after(context, result);
- }
- }
-
- /**
- * If the delegate is also a {@link RepeatListener} then it will be given
- * the call before flushing.
- *
- *
- * @see org.springframework.batch.repeat.RepeatListener#close(org.springframework.batch.repeat.RepeatContext)
- */
- public void close(RepeatContext context) {
- try {
- flushInContext();
- }
- finally {
- unsetContext();
- if (delegate instanceof RepeatListener) {
- RepeatListener interceptor = (RepeatListener) delegate;
- interceptor.close(context);
- }
- }
- }
-
- /**
- * Does nothing unless the delegate is also a {@link RepeatListener} in
- * which case pass on the call to him.
- *
- * @see org.springframework.batch.repeat.RepeatListener#onError(org.springframework.batch.repeat.RepeatContext,
- * java.lang.Throwable)
- */
- public void onError(RepeatContext context, Throwable e) {
- if (delegate instanceof RepeatListener) {
- RepeatListener interceptor = (RepeatListener) delegate;
- interceptor.onError(context, e);
- }
- }
-
- /**
- * Sets up the context as a transaction resource so that we can store state
- * and refer back to it in the {@link #write(Object)} method. If the
- * delegate is also a {@link RepeatListener} then it will be given the call
- * afterwards.
- *
- * @see org.springframework.batch.repeat.RepeatListener#open(org.springframework.batch.repeat.RepeatContext)
- */
- public void open(RepeatContext context) {
- this.setContext(context);
- getProcessed().clear();
- if (delegate instanceof RepeatListener) {
- RepeatListener interceptor = (RepeatListener) delegate;
- interceptor.open(context);
- }
- }
-
/**
* Accessor for the list of processed items in this transaction.
*
* @return the processed
*/
private Set getProcessed() {
- Assert.state(TransactionSynchronizationManager.hasResource(WRITER_REPEAT_CONTEXT),
- "RepeatContext not bound to transaction.");
- Set processed = (Set) ((AttributeAccessor) TransactionSynchronizationManager.getResource(WRITER_REPEAT_CONTEXT))
- .getAttribute(ITEMS_PROCESSED);
+ Assert.state(TransactionSynchronizationManager.hasResource(ITEMS_PROCESSED),
+ "Processed items not bound to transaction.");
+ Set processed = (Set) TransactionSynchronizationManager.getResource(ITEMS_PROCESSED);
return processed;
}
@@ -213,22 +128,21 @@ public class HibernateAwareItemWriter implements ItemWriter, RepeatListener, Ini
*
* @param context the context to set
*/
- private void setContext(RepeatContext context) {
- if (TransactionSynchronizationManager.hasResource(WRITER_REPEAT_CONTEXT)) {
+ private void bindTransactionResources() {
+ if (TransactionSynchronizationManager.hasResource(ITEMS_PROCESSED)) {
return;
}
- TransactionSynchronizationManager.bindResource(WRITER_REPEAT_CONTEXT, context);
- context.setAttribute(ITEMS_PROCESSED, new HashSet());
+ TransactionSynchronizationManager.bindResource(ITEMS_PROCESSED, new HashSet());
}
/**
* Remove the transaction resource associated with this context.
*/
- private void unsetContext() {
- if (!TransactionSynchronizationManager.hasResource(WRITER_REPEAT_CONTEXT)) {
+ private void unbindTransactionResources() {
+ if (!TransactionSynchronizationManager.hasResource(ITEMS_PROCESSED)) {
return;
}
- TransactionSynchronizationManager.unbindResource(WRITER_REPEAT_CONTEXT);
+ TransactionSynchronizationManager.unbindResource(ITEMS_PROCESSED);
}
/**
@@ -244,23 +158,21 @@ public class HibernateAwareItemWriter implements ItemWriter, RepeatListener, Ini
flush = failed.contains(output);
}
if (flush) {
- RepeatContext context = (RepeatContext) TransactionSynchronizationManager
- .getResource(WRITER_REPEAT_CONTEXT);
+ RepeatContext context = RepeatSynchronizationManager.getContext();
// Force early completion to commit aggressively if we encounter a
// failed item (from a failed chunk but we don't know which one was
// the problem).
context.setCompleteOnly();
// Flush now, so that if there is a failure this record can be
// skipped.
- flushInContext();
+ doHibernateFlush();
}
-
}
/**
- *
+ * Flush the hibernate session from within a repeat context.
*/
- private void flushInContext() {
+ private void doHibernateFlush() {
try {
hibernateTemplate.flush();
// This should happen when the transaction commits anyway, but to be
@@ -277,25 +189,28 @@ public class HibernateAwareItemWriter implements ItemWriter, RepeatListener, Ini
}
}
- /*
- * (non-Javadoc)
+ /**
+ * Call the delegate clear() method, and then clear the hibernate session.
+ *
* @see org.springframework.batch.item.ItemWriter#clear()
*/
public void clear() throws ClearFailedException {
- if (delegate != null) {
- delegate.clear();
- }
+ unbindTransactionResources();
hibernateTemplate.clear();
+ delegate.clear();
}
/**
- * Flush the Hibernate session. The delegate flush will also be called
- * before finishing.
+ * Flush the Hibernate session and record failures if there are any. The
+ * delegate flush will also be called.
+ *
+ * @see org.springframework.batch.item.ItemWriter#flush()
*/
public void flush() throws FlushFailedException {
- if (delegate != null) {
- delegate.flush();
- }
+ bindTransactionResources();
+ doHibernateFlush();
+ unbindTransactionResources();
+ delegate.flush();
}
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/interceptor/CompositeRepeatListener.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/interceptor/CompositeRepeatListener.java
new file mode 100644
index 000000000..ca548df04
--- /dev/null
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/interceptor/CompositeRepeatListener.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.repeat.interceptor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.springframework.batch.repeat.ExitStatus;
+import org.springframework.batch.repeat.RepeatContext;
+import org.springframework.batch.repeat.RepeatListener;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public class CompositeRepeatListener implements RepeatListener {
+
+ private List listeners = new ArrayList();
+
+ /**
+ * Public setter for the listeners.
+ *
+ * @param listeners
+ */
+ public void setListeners(RepeatListener[] listeners) {
+ this.listeners = Arrays.asList(listeners);
+ }
+
+ /**
+ * Register additional listener.
+ *
+ * @param itemReaderListener
+ */
+ public void register(RepeatListener listener) {
+ if (!listeners.contains(listener)) {
+ listeners.add(listener);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.batch.repeat.RepeatListener#after(org.springframework.batch.repeat.RepeatContext, org.springframework.batch.repeat.ExitStatus)
+ */
+ public void after(RepeatContext context, ExitStatus result) {
+ for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
+ RepeatListener listener = (RepeatListener) iterator.next();
+ listener.after(context, result);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.batch.repeat.RepeatListener#before(org.springframework.batch.repeat.RepeatContext)
+ */
+ public void before(RepeatContext context) {
+ for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
+ RepeatListener listener = (RepeatListener) iterator.next();
+ listener.before(context);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.batch.repeat.RepeatListener#close(org.springframework.batch.repeat.RepeatContext)
+ */
+ public void close(RepeatContext context) {
+ for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
+ RepeatListener listener = (RepeatListener) iterator.next();
+ listener.close(context);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.batch.repeat.RepeatListener#onError(org.springframework.batch.repeat.RepeatContext, java.lang.Throwable)
+ */
+ public void onError(RepeatContext context, Throwable e) {
+ for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
+ RepeatListener listener = (RepeatListener) iterator.next();
+ listener.onError(context, e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.batch.repeat.RepeatListener#open(org.springframework.batch.repeat.RepeatContext)
+ */
+ public void open(RepeatContext context) {
+ for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
+ RepeatListener listener = (RepeatListener) iterator.next();
+ listener.open(context);
+ }
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/io/support/HibernateAwareItemWriterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/io/support/HibernateAwareItemWriterTests.java
index ccabf4e70..f34349c8b 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/io/support/HibernateAwareItemWriterTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/io/support/HibernateAwareItemWriterTests.java
@@ -25,10 +25,8 @@ import junit.framework.TestCase;
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.ExitStatus;
-import org.springframework.batch.repeat.RepeatContext;
-import org.springframework.batch.repeat.RepeatListener;
import org.springframework.batch.repeat.context.RepeatContextSupport;
+import org.springframework.batch.repeat.synch.RepeatSynchronizationManager;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@@ -48,40 +46,17 @@ public class HibernateAwareItemWriterTests extends TestCase {
};
}
- private class StubItemWriter implements ItemWriter, RepeatListener {
+ private class StubItemWriter implements ItemWriter {
public void write(Object item) {
list.add(item);
}
- public void after(RepeatContext context, ExitStatus result) {
- list.add(result);
- }
-
- public void before(RepeatContext context) {
- list.add(context);
- }
-
- public void close(RepeatContext context) {
- list.add(context);
- }
-
- public void onError(RepeatContext context, Throwable e) {
- list.add(e);
- }
-
- public void open(RepeatContext context) {
- list.add(context);
- }
-
- public void close() throws Exception {
- }
-
public void clear() throws ClearFailedException {
- list.add("clear");
+ list.add("delegateClear");
}
public void flush() throws FlushFailedException {
- list.add("flush");
+ list.add("delegateFlush");
}
}
@@ -99,7 +74,7 @@ public class HibernateAwareItemWriterTests extends TestCase {
protected void setUp() throws Exception {
writer.setDelegate(new StubItemWriter());
context = new RepeatContextSupport(null);
- writer.open(context);
+ RepeatSynchronizationManager.register(context);
writer.setHibernateTemplate(new HibernateTemplateWrapper());
list.clear();
}
@@ -158,7 +133,7 @@ public class HibernateAwareItemWriterTests extends TestCase {
* Test method for
* {@link org.springframework.batch.io.support.HibernateAwareItemWriter#write(java.lang.Object)}.
*/
- public void testCloseWithFailure() throws Exception{
+ public void testFlushWithFailure() throws Exception{
final RuntimeException ex = new RuntimeException("bar");
writer.setHibernateTemplate(new HibernateTemplate() {
public void flush() throws DataAccessException {
@@ -166,14 +141,11 @@ public class HibernateAwareItemWriterTests extends TestCase {
}
});
try {
- writer.close(context);
+ writer.flush();
fail("Expected RuntimeException");
} catch (RuntimeException e) {
assertEquals("bar", e.getMessage());
}
- assertEquals(1, list.size());
- System.err.println(list);
- assertTrue(list.contains(context));
}
/**
@@ -181,7 +153,7 @@ public class HibernateAwareItemWriterTests extends TestCase {
* {@link org.springframework.batch.io.support.HibernateAwareItemWriter#write(java.lang.Object)}.
* @throws Exception
*/
- public void testWriteAndCloseWithFailure() throws Exception {
+ public void testWriteAndFlushWithFailure() throws Exception {
final RuntimeException ex = new RuntimeException("bar");
writer.setHibernateTemplate(new HibernateTemplateWrapper() {
public void flush() throws DataAccessException {
@@ -190,41 +162,22 @@ public class HibernateAwareItemWriterTests extends TestCase {
});
writer.write("foo");
try {
- writer.close(context);
+ writer.flush();
fail("Expected RuntimeException");
} catch (RuntimeException e) {
assertEquals("bar", e.getMessage());
}
- assertEquals(2, list.size());
- assertTrue(list.contains(context));
+ assertEquals(1, list.size());
writer.setHibernateTemplate(new HibernateTemplateWrapper() {
public void flush() throws DataAccessException {
list.add("flush");
}
});
- writer.open(context);
writer.write("foo");
- assertEquals(6, list.size());
+ assertEquals(4, list.size());
assertTrue(list.contains("flush"));
assertTrue(list.contains("clear"));
- }
-
- /**
- * Test method for
- * {@link org.springframework.batch.io.support.HibernateAwareItemWriter#before(org.springframework.batch.repeat.RepeatContext)}.
- */
- public void testBefore() {
- writer.before(context);
- assertEquals(1, list.size());
- }
-
- /**
- * Test method for
- * {@link org.springframework.batch.io.support.HibernateAwareItemWriter#after(org.springframework.batch.repeat.RepeatContext, org.springframework.batch.repeat.ExitStatus)}.
- */
- public void testAfter() {
- writer.after(context, ExitStatus.FINISHED);
- assertEquals(1, list.size());
+ assertTrue(context.isCompleteOnly());
}
/**
@@ -233,40 +186,20 @@ public class HibernateAwareItemWriterTests extends TestCase {
*/
public void testFlush() throws Exception{
writer.flush();
- assertEquals(1, list.size());
+ assertEquals(3, list.size());
assertTrue(list.contains("flush"));
+ assertTrue(list.contains("clear"));
+ assertTrue(list.contains("delegateFlush"));
}
/**
* Test method for
* {@link org.springframework.batch.io.support.HibernateAwareItemWriter#close(org.springframework.batch.repeat.RepeatContext)}.
*/
- public void testCloseAfterClear() throws Exception{
- Map map = TransactionSynchronizationManager.getResourceMap();
- String key = (String) map.keySet().iterator().next();
- TransactionSynchronizationManager.unbindResource(key);
- writer.close(context);
- assertEquals(3, list.size());
- assertTrue(list.contains("flush"));
+ public void testClear() throws Exception{
+ writer.clear();
+ assertEquals(2, list.size());
assertTrue(list.contains("clear"));
+ assertTrue(list.contains("delegateClear"));
}
-
- /**
- * Test method for
- * {@link org.springframework.batch.io.support.HibernateAwareItemWriter#onError(org.springframework.batch.repeat.RepeatContext, java.lang.Throwable)}.
- */
- public void testOnError() {
- writer.onError(context, new Exception());
- assertEquals(1, list.size());
- }
-
- /**
- * Test method for
- * {@link org.springframework.batch.io.support.HibernateAwareItemWriter#open(org.springframework.batch.repeat.RepeatContext)}.
- */
- public void testOpen() {
- writer.open(context);
- assertEquals(1, list.size());
- }
-
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/interceptor/CompositeRepeatListenerTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/interceptor/CompositeRepeatListenerTests.java
new file mode 100644
index 000000000..792162796
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/interceptor/CompositeRepeatListenerTests.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.repeat.interceptor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.springframework.batch.repeat.RepeatContext;
+import org.springframework.batch.repeat.RepeatListener;
+import org.springframework.batch.repeat.context.RepeatContextSupport;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public class CompositeRepeatListenerTests extends TestCase {
+
+ private CompositeRepeatListener listener = new CompositeRepeatListener();
+ private RepeatContext context = new RepeatContextSupport(null);
+
+ private List list = new ArrayList();
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.listener.CompositeStepListener#setListeners(org.springframework.batch.core.domain.StepListener[])}.
+ */
+ public void testSetListeners() {
+ listener.setListeners(new RepeatListener[] { new RepeatListenerSupport() {
+ public void open(RepeatContext context) {
+ list.add("fail");
+ }
+ }, new RepeatListenerSupport() {
+ public void open(RepeatContext context) {
+ list.add("continue");
+ }
+ } });
+ listener.open(context);
+ assertEquals(2, list.size());
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.listener.CompositeStepListener#setListener(org.springframework.batch.core.domain.StepListener)}.
+ */
+ public void testSetListener() {
+ listener.register(new RepeatListenerSupport() {
+ public void before(RepeatContext context) {
+ list.add("fail");
+ }
+ });
+ listener.before(context);
+ assertEquals(1, list.size());
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.listener.CompositeStepListener#beforeStep(StepExecution)}.
+ */
+ public void testClose() {
+ listener.register(new RepeatListenerSupport() {
+ public void close(RepeatContext context) {
+ list.add("foo");
+ }
+ });
+ listener.close(context);
+ assertEquals(1, list.size());
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.execution.listener.CompositeStepListener#beforeStep(StepExecution)}.
+ */
+ public void testOnError() {
+ listener.register(new RepeatListenerSupport() {
+ public void onError(RepeatContext context, Throwable e) {
+ list.add(e);
+ }
+ });
+ listener.onError(context, new RuntimeException("foo"));
+ assertEquals(1, list.size());
+ }
+
+}
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/writer/CustomerCreditIncreaseWriter.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/writer/CustomerCreditIncreaseWriter.java
index f8f575bdc..fa0d5517f 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/writer/CustomerCreditIncreaseWriter.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/writer/CustomerCreditIncreaseWriter.java
@@ -34,7 +34,4 @@ public class CustomerCreditIncreaseWriter extends AbstractItemWriter {
customerCreditDao.writeCredit(customerCredit);
}
- public void close() throws Exception {
- }
-
}
diff --git a/spring-batch-samples/src/main/resources/jobs/hibernateJob.xml b/spring-batch-samples/src/main/resources/jobs/hibernateJob.xml
index a8ad1b233..7c44c7e7c 100644
--- a/spring-batch-samples/src/main/resources/jobs/hibernateJob.xml
+++ b/spring-batch-samples/src/main/resources/jobs/hibernateJob.xml
@@ -10,29 +10,23 @@
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
Example for Hibernate integration.
-
-
-
+
+
+
-
+
-
+
-
-
-
-
-
-
+ class="org.springframework.batch.execution.step.support.AlwaysSkipItemSkipPolicy" />
+