/** * Check return value from batch operation. * * @param value the last callback result. * @return true if the value is {@link RepeatStatus#CONTINUABLE}. */ protected final boolean canContinue(RepeatStatus value) { return value.isContinuable(); }
/** * True if the result is null, or a {@link RepeatStatus} indicating * completion. * * @see org.springframework.batch.repeat.CompletionPolicy#isComplete(org.springframework.batch.repeat.RepeatContext, * RepeatStatus) */ @Override public boolean isComplete(RepeatContext context, RepeatStatus result) { return (result == null || !result.isContinuable()); }
@Override public int compare(ResultHolder h1, ResultHolder h2) { RepeatStatus result1 = h1.getResult(); RepeatStatus result2 = h2.getResult(); if (result1 == null && result2 == null) { return 0; } if (result1 == null) { return -1; } else if (result2 == null) { return 1; } if ((result1.isContinuable() && result2.isContinuable()) || (!result1.isContinuable() && !result2.isContinuable())) { return 0; } if (result1.isContinuable()) { return -1; } return 1; } }
/** * If exit status is not continuable return <code>true</code>, otherwise * delegate to {@link #isComplete(RepeatContext)}. * * @see org.springframework.batch.repeat.CompletionPolicy#isComplete(org.springframework.batch.repeat.RepeatContext, * RepeatStatus) */ @Override public boolean isComplete(RepeatContext context, RepeatStatus result) { if (result != null && !result.isContinuable()) { return true; } else { return isComplete(context); } }
/** * Convenience method to execute after interceptors on a callback result. * * @param context the current batch context. * @param value the result of the callback to process. */ protected void executeAfterInterceptors(final RepeatContext context, RepeatStatus value) { // Don't re-throw exceptions here: let the exception handler deal with // that... if (value != null && value.isContinuable()) { for (int i = listeners.length; i-- > 0;) { RepeatListener interceptor = listeners[i]; interceptor.after(context, value); } } }
private boolean isContinuable(ResultHolder value) { return value.getResult() != null && value.getResult().isContinuable(); }
@Override public RepeatStatus doInIteration(RepeatContext context) throws Exception { int position = count.incrementAndGet(); String item = position <= total ? "" + position : null; items.add("" + item); if (item != null) { beBusy(); } /* * In a multi-threaded task, one of the callbacks can call * FINISHED early, while other threads are still working, and * would do more work if the callback was called again. (This * happens for instance if there is a failure and you want to * retry the work.) */ RepeatStatus result = RepeatStatus.continueIf(position != early && item != null); if (position == error) { throw new RuntimeException("Planned"); } if (!result.isContinuable()) { logger.debug("Returning " + result + " for count=" + position); } return result; } };
@Override public RepeatStatus doInIteration(RepeatContext context) throws Exception { RepeatStatus result = super.doInIteration(context); if (!result.isContinuable() && chunker.first()) { chunker.set(); } chunker.increment(); return result; }
/** * Test that a result is returned from the batch. * @throws Exception */ @Test public void testResult() throws Exception { RepeatStatus result = template.iterate(new ItemReaderRepeatCallback<>(provider, processor)); assertEquals(NUMBER_OF_ITEMS, processor.count); // We are complete - do not expect to be called again assertFalse(result.isContinuable()); }
/** * Check that a the context can be used to signal early completion. * * @throws Exception */ @Test public void testEarlyCompletionWithContext() throws Exception { RepeatStatus result = template.iterate(new ItemReaderRepeatCallback<Trade>(provider, processor) { @Override public RepeatStatus doInIteration(RepeatContext context) throws Exception { RepeatStatus result = super.doInIteration(context); if (processor.count >= 2) { context.setCompleteOnly(); // If we return null the batch will terminate anyway // without an exception... } return result; } }); // 2 items were processed before completion signalled assertEquals(2, processor.count); // Not all items processed assertTrue(result.isContinuable()); }
/** * Check that a the context can be used to signal early completion. * * @throws Exception */ @Test public void testEarlyCompletionWithContextTerminated() throws Exception { RepeatStatus result = template.iterate(new ItemReaderRepeatCallback<Trade>(provider, processor) { @Override public RepeatStatus doInIteration(RepeatContext context) throws Exception { RepeatStatus result = super.doInIteration(context); if (processor.count >= 2) { context.setTerminateOnly(); // If we return null the batch will terminate anyway // without an exception... } return result; } }); // 2 items were processed before completion signalled assertEquals(2, processor.count); // Not all items processed assertTrue(result.isContinuable()); }
public void testExecute() throws Exception { NestedRepeatCallback callback = new NestedRepeatCallback(new RepeatTemplate(), new RepeatCallback() { @Override public RepeatStatus doInIteration(RepeatContext context) throws Exception { count++; return RepeatStatus.continueIf(count <= 1); } }); RepeatStatus result = callback.doInIteration(null); assertEquals(2, count); assertFalse(result.isContinuable()); // False because processing has finished } }
assertFalse(result.isContinuable());
@Test public void testOrdering() throws Exception { queue.expect(); queue.expect(); queue.put(new TestResultHolder(RepeatStatus.FINISHED)); queue.put(new TestResultHolder(RepeatStatus.CONTINUABLE)); assertFalse(queue.isEmpty()); assertTrue(queue.take().getResult().isContinuable()); assertFalse(queue.take().getResult().isContinuable()); }
/** * Chunking using a dedicated TerminationPolicy. Transactions would be laid * on at the level of chunkTemplate.execute() or the surrounding callback. */ @Test public void testChunkedBatchWithTerminationPolicy() throws Exception { RepeatTemplate repeatTemplate = new RepeatTemplate(); final RepeatCallback callback = new ItemReaderRepeatCallback<>(provider, processor); final RepeatTemplate chunkTemplate = new RepeatTemplate(); // The policy is resettable so we only have to resolve this dependency // once chunkTemplate.setCompletionPolicy(new SimpleCompletionPolicy(2)); RepeatStatus result = repeatTemplate.iterate(new NestedRepeatCallback(chunkTemplate, callback) { @Override public RepeatStatus doInIteration(RepeatContext context) throws Exception { count++; // for test assertion return super.doInIteration(context); } }); assertEquals(NUMBER_OF_ITEMS, processor.count); // The chunk executes 3 times because the last one // returns false. We terminate the main batch when // we encounter a partially empty chunk. assertEquals(3, count); assertFalse(result.isContinuable()); }
@Test public void testPutTake() throws Exception { queue.expect(); assertTrue(queue.isExpecting()); assertTrue(queue.isEmpty()); queue.put(new TestResultHolder(RepeatStatus.CONTINUABLE)); assertFalse(queue.isEmpty()); assertTrue(queue.take().getResult().isContinuable()); assertFalse(queue.isExpecting()); }
/** * Chunking with an asynchronous taskExecutor in the chunks. Transactions * have to be at the level of the business callback. */ @Test public void testAsynchronousChunkedBatchWithCompletionPolicy() throws Exception { RepeatTemplate repeatTemplate = new RepeatTemplate(); final RepeatCallback callback = new ItemReaderRepeatCallback<>(provider, processor); final TaskExecutorRepeatTemplate chunkTemplate = new TaskExecutorRepeatTemplate(); // The policy is resettable so we only have to resolve this dependency // once chunkTemplate.setCompletionPolicy(new SimpleCompletionPolicy(2)); chunkTemplate.setTaskExecutor(new SimpleAsyncTaskExecutor()); RepeatStatus result = repeatTemplate.iterate(new NestedRepeatCallback(chunkTemplate, callback) { @Override public RepeatStatus doInIteration(RepeatContext context) throws Exception { count++; // for test assertion return super.doInIteration(context); } }); assertEquals(NUMBER_OF_ITEMS, processor.count); assertFalse(result.isContinuable()); assertTrue("Expected at least 3 chunks but found: "+count, count>=3); }
/** * Check return value from batch operation. * * @param value the last callback result. * @return true if the value is {@link RepeatStatus#CONTINUABLE}. */ protected final boolean canContinue(RepeatStatus value) { return value.isContinuable(); }
/** * True if the result is null, or a {@link RepeatStatus} indicating * completion. * * @see org.springframework.batch.repeat.CompletionPolicy#isComplete(org.springframework.batch.repeat.RepeatContext, * RepeatStatus) */ @Override public boolean isComplete(RepeatContext context, RepeatStatus result) { return (result == null || !result.isContinuable()); }
private boolean isContinuable(ResultHolder value) { return value.getResult() != null && value.getResult().isContinuable(); }