Announcement Announcement Module
Collapse
No announcement yet.
Passing data from step to step within the same job. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Passing data from step to step within the same job.

    I am working on a proof of concept using Spring Batch as a candidate for replacing our current COBOL batch architecture which was designed decades ago on a mainframe environment.

    The job I decided to convert has two main steps to it.

    Step 1 accesses the database to obtain a few pieces of information which will be used repeatedly in the second step. So, I only want to do this step once.

    Step 2 will encompass the normal chunk, reader, processor, and writer login.

    Step 1 is where I am stuck. There is no need for a reader, writer, and processor. All I need is to run a task.

    I have looked at chapter 11 toward the bottom where it discusses passing data to other steps. I have attempted quit a few different approaches to getting this to work and am unsuccessful.

    The problem seems to be getting the stepExecution context retrieved successfully.

    The job definition from the applicationContext file is:

    Code:
    <job id="refundExtractJob"  xmlns="http://www.springframework.org/schema/batch" >
    	<step id="startUpTasks" next="processRefunds" parent="simpleStep" >
    		<tasklet ref="startupTasklet">
    			<listeners>
    				<listener ref="promotionListener"  />
    				<listener ref="saveStepExecutionListener"/>
    			</listeners>
    		</tasklet>
    	</step>
    	
    	<step id="processRefunds" parent="simpleStep">
    		<tasklet>
    			<chunk reader="refundReader"  processor="refundProcessor" 
    					writer="refundWriter" commit-interval="10" />
    		</tasklet>
    	</step> 
    </job>
    	
    <bean id="promotionListener" class="org.springframework.batch.core.listener.ExecutionContextPromotionListener">
    		<property name="keys" 
    			value="batchDate,uddYear,batchDateYymmdd,createTime,effectiveDate,effectiveDateYymmdd,julianDate"/>
    	</bean>
    
    <bean id="saveStepExecutionListener" 	class="org.springframework.batch.core.StepExecutionListener"/>
    
    <bean id="simpleStep" 
    	class="org.springframework.batch.core.step.item.SimpleStepFactoryBean" 
    	abstract="true">
    	<property name="transactionManager" ref="transactionManagerMysql" /> 
    	<property name="jobRepository" ref="jobRepository" />
    	<property name="commitInterval" value="1" />
    </bean>
    
    <bean id="startupTasklet"  class="gov.azdor.refundbatch.RefundStartupTasklet" />

    My class called RefundStartupTasklet class definition is:

    Code:
    	public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception
    From Chapter 11 of the guide, the key to making this all work is the method included in this class:

    Code:
    	@BeforeStep
    	public void setApplicationContext(ApplicationContext arg0)
    			throws BeansException {
    		context = arg0;
    	}
    With my code, this method never gets called which means this code from chapter 11 fails:

    Code:
            ExecutionContext stepContext = this.stepExecution.getExecutionContext();
            stepContext.put("someKey", someObject);
    I did notice that the chapter class is implementing ItemWriter which I am trying to avoid.

    I would really appreciate any help anyone can shed on this problem.

    Thanks, Steve

  • #2
    That chapter 11 is a little out of date, but it never would have worked to inject an ApplicationContext in @BeforeStep anyway. Easier by far is to use scope="step" for your components and simply inject the stepExecution using a late binding expression (see chapter 5 http://static.springsource.org/sprin...l#late-binding).

    However, I wouldn't recommend this approach for manipulating the ExecutionContext if you want restartability. The correct interface for that is ItemStream (http://static.springsource.org/sprin...tml#itemStream).
    Last edited by Dave Syer; Jul 30th, 2010, 02:20 AM. Reason: Added ItemStream reference

    Comment


    • #3
      Dave,

      Thanks for the reply. Actually, the injection of the ApplicationContext works. The saveStepExecution method does not. I need the application context so I can instantiate the bean for accessing my database. So that parts works ok and I can retrieve the application startup values I need.

      I guess I will keep reading the section on late binding until I get it.

      This first step does need to be restartable. In fact I made a change so it will get run each time job runs, regardless of its completion status. It just retrieves a few date values from the database that are then used in the next step for every row that it retrieves.

      I was hoping the ChunkContext could supply me with the jobExecutionContext so I could put these values directly in. Then the item processor in the next step could retrieve those values from the that context without needing to access the database again.

      Since I am not running step 1 inside a chunk tag, I imagine that explains why my chunkContext doesn't supply anything.

      Steve

      Comment


      • #4
        I did finally resolve the problem. I left the xml in the applicationContext the same. On the class RefundStartupTasklet I added StepExecutionListener to be implemented. With that I got the method

        Code:
        @BeforeStep
        public void beforeStep(StepExecution stepExecution) {
        	this.stepExecution = stepExecution;
        }
        In this class, then I have the applicationContext set and the stepExecution set which gives everything I needed to pass on data to the next step.

        Thanks again for your help.

        Steve

        Comment

        Working...
        X