public ChunkTransactionCallback(ChunkContext chunkContext, Semaphore semaphore) { this.chunkContext = chunkContext; this.stepExecution = chunkContext.getStepContext().getStepExecution(); this.semaphore = semaphore; }
chunkContext = new ChunkContext(stepContext); if (!chunkContext.isComplete()) { attributeQueue.add(chunkContext);
@Override public String toString() { return String.format("ChunkContext: attributes=%s, complete=%b, stepContext=%s", Arrays .asList(attributeNames()), complete, stepContext); }
@Override public RepeatStatus doInChunkContext(RepeatContext context, ChunkContext chunkContext) throws Exception { if (addedAttribute) { removedAttribute = chunkContext.hasAttribute("foo"); chunkContext.removeAttribute("foo"); } else { addedAttribute = true; chunkContext.setAttribute("foo", "bar"); } return RepeatStatus.FINISHED; } };
@Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { @SuppressWarnings("unchecked") Chunk<I> inputs = (Chunk<I>) chunkContext.getAttribute(INPUTS_KEY); if (inputs == null) { inputs = chunkProvider.provide(contribution); if (buffering) { chunkContext.setAttribute(INPUTS_KEY, inputs); } } chunkProcessor.process(contribution, inputs); chunkProvider.postProcess(contribution, inputs); // Allow a message coming back from the processor to say that we // are not done yet if (inputs.isBusy()) { logger.debug("Inputs still busy"); return RepeatStatus.CONTINUABLE; } chunkContext.removeAttribute(INPUTS_KEY); chunkContext.setComplete(); if (logger.isDebugEnabled()) { logger.debug("Inputs not busy, ended: " + inputs.isEnd()); } return RepeatStatus.continueIf(!inputs.isEnd()); }
@Override public void afterChunk(ChunkContext context) { try { if(context.isComplete()) { lock.lock(); Serializable collectPartitionData = collector.collectPartitionData(); if(collectPartitionData != null) { partitionQueue.add(collectPartitionData); } } } catch (Throwable e) { throw new BatchRuntimeException("An error occurred while collecting data from the PartitionCollector", e); } finally { if(lock.isHeldByCurrentThread()) { lock.unlock(); } } }
@Before public void setUp() throws Exception { chunkContext = new ChunkContext(null); listener = mock(ChunkListener.class); compositeListener = new CompositeChunkListener(); compositeListener.register(listener); }
@Test public void testIsComplete() { assertFalse(context.isComplete()); context.setComplete(); assertTrue(context.isComplete()); }
@Override public void afterChunkError(ChunkContext context) { if(context != null) { try { delegate.onError((Exception) context.getAttribute(ChunkListener.ROLLBACK_EXCEPTION_KEY)); } catch (Exception e) { throw new UncheckedTransactionException(e); } } else { throw new BatchRuntimeException("Unable to retrieve causing exception due to null ChunkContext"); } } }
@Test public void testAfterChunkSuccessful() throws Exception { Queue<Serializable> dataQueue = new ConcurrentLinkedQueue<>(); adapter = new PartitionCollectorAdapter(dataQueue, new PartitionCollector() { private int count = 0; @Override public Serializable collectPartitionData() throws Exception { return String.valueOf(count++); } }); adapter.setPartitionLock(new ReentrantLock()); ChunkContext context = new ChunkContext(null); context.setComplete(); adapter.afterChunk(context); adapter.afterChunkError(context); adapter.afterChunk(context); assertEquals(3, dataQueue.size()); assertEquals("0", dataQueue.remove()); assertEquals("1", dataQueue.remove()); assertEquals("2", dataQueue.remove()); } }
@Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { String exitStatus; try { exitStatus = batchlet.process(); } finally { chunkContext.setComplete(); } if(StringUtils.hasText(exitStatus)) { contribution.setExitStatus(new ExitStatus(exitStatus)); } return RepeatStatus.FINISHED; }
chunkContext.setAttribute(ChunkListener.ROLLBACK_EXCEPTION_KEY, e); throw e;
@Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { @SuppressWarnings("unchecked") Chunk<I> inputs = (Chunk<I>) chunkContext.getAttribute(INPUTS_KEY); if (inputs == null) { inputs = chunkProvider.provide(contribution); if (buffering) { chunkContext.setAttribute(INPUTS_KEY, inputs); } } chunkProcessor.process(contribution, inputs); chunkProvider.postProcess(contribution, inputs); // Allow a message coming back from the processor to say that we // are not done yet if (inputs.isBusy()) { logger.debug("Inputs still busy"); return RepeatStatus.CONTINUABLE; } chunkContext.removeAttribute(INPUTS_KEY); chunkContext.setComplete(); if (logger.isDebugEnabled()) { logger.debug("Inputs not busy, ended: " + inputs.isEnd()); } return RepeatStatus.continueIf(!inputs.isEnd()); }
@Override public void afterChunkError(ChunkContext context) { try { lock.lock(); if(context.isComplete()) { Serializable collectPartitionData = collector.collectPartitionData(); if(collectPartitionData != null) { partitionQueue.add(collectPartitionData); } } } catch (Throwable e) { throw new BatchRuntimeException("An error occurred while collecting data from the PartitionCollector", e); } finally { if(lock.isHeldByCurrentThread()) { lock.unlock(); } } } }
@Test public void testExecuteNoExitStatus() throws Exception { assertEquals(RepeatStatus.FINISHED, adapter.execute(contribution, new ChunkContext(null))); verify(delegate).process(); }
@Test public void testAfterChunkError() throws Exception { Exception exception = new Exception("This was expected"); when(context.getAttribute(org.springframework.batch.core.ChunkListener.ROLLBACK_EXCEPTION_KEY)).thenReturn(exception); adapter.afterChunkError(context); verify(delegate).onError(exception); } }
@Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { String exitStatus; try { exitStatus = batchlet.process(); } finally { chunkContext.setComplete(); } if(StringUtils.hasText(exitStatus)) { contribution.setExitStatus(new ExitStatus(exitStatus)); } return RepeatStatus.FINISHED; }
chunkContext.setAttribute(ChunkListener.ROLLBACK_EXCEPTION_KEY, e); throw e;
@Test public void testGetStepContext() { StepContext stepContext = context.getStepContext(); assertNotNull(stepContext); assertEquals("bar", context.getStepContext().getJobParameters().get("foo")); }
@Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { @SuppressWarnings("unchecked") Chunk<I> inputs = (Chunk<I>) chunkContext.getAttribute(INPUTS_KEY); if (inputs == null) { inputs = chunkProvider.provide(contribution); if (buffering) { chunkContext.setAttribute(INPUTS_KEY, inputs); } } chunkProcessor.process(contribution, inputs); chunkProvider.postProcess(contribution, inputs); // Allow a message coming back from the processor to say that we // are not done yet if (inputs.isBusy()) { logger.debug("Inputs still busy"); return RepeatStatus.CONTINUABLE; } chunkContext.removeAttribute(INPUTS_KEY); chunkContext.setComplete(); logger.debug("Inputs not busy, ended: " + inputs.isEnd()); return RepeatStatus.continueIf(!inputs.isEnd()); }