spring-projects / spring-batch

Spring Batch is a framework for writing batch applications using Java and Spring
http://projects.spring.io/spring-batch/
Apache License 2.0
2.73k stars 2.35k forks source link

Step Scope problem in TaskletStep [BATCH-1521] #2061

Closed spring-projects-issues closed 14 years ago

spring-projects-issues commented 14 years ago

Kai Hemme-Unger opened BATCH-1521 and commented

\ (removed cloned description of different issue BATCH-380).


Affects: 1.0.0.m4

spring-projects-issues commented 14 years ago

Kai Hemme-Unger commented

Dear all,

I cloned this issue since it was opened in reply to http://forum.springsource.org/showthread.php?p=286559#post286559 which seems to comment on the problem I have.

Here is the error that I get:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'lazyBindingProxy.positionPagingItemReader': Scope 'step' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No context holder available for step scope

This is the bean definition:

<bean id="positionPagingItemReader" scope="step"
    class="ch.ofwi.matcher.services.business.tdmatcher.v1.impl.jobs.matcher.MatcherRequestCompanyPagingReader">
    <property name="sqlMapClient" ref="matcherMapClient" />
    <property name="queryId" value="tdmatcher.getPagedMatcherCompany" />
    <property name="pageSize" value="1000" />
    <property name="matcherRequestKey" value="#{jobParameters[matcher.request.key]}" />
</bean>

Here is where the bean is referenced:

<batch:step id="matchRecords" >
    <batch:tasklet allow-start-if-complete="true" 
        transaction-manager="matcherTransactionManager">
        <batch:chunk reader="positionPagingItemReader" 
            processor="fuzzyProcessor" writer="matcherRequestPositionUpdater"
            commit-interval="5"></batch:chunk>
        <batch:listeners>
            <batch:listener ref="matcherStepListener"/>
        </batch:listeners>
    </batch:tasklet>
</batch:step>
<batch:job id="csvWriterJob" >
    <batch:step id="writeCSVFile">        
        <batch:tasklet allow-start-if-complete="true">
            <batch:chunk reader="positionPagingItemReader"
                writer="csvWriter" commit-interval="1000"/>
        </batch:tasklet>
    </batch:step>
    <batch:listeners>
    <batch:listener class="ch.ofwi.matcher.services.business.tdmatcher.v1.impl.jobs.exportcsv.ExportCSVJobExecutionListener"/>
    </batch:listeners>
</batch:job>

And here is the code of the bean with name 'positionPagingItemReader':

package ch.ofwi.matcher.services.business.tdmatcher.v1.impl.jobs.matcher;

import java.util.HashMap;
import java.util.Map;

import jptools.logger.Logger;

import org.springframework.batch.item.database.IbatisPagingItemReader;

import ch.ofwi.matcher.dataaccess.dto.MatcherRequestCompany;

public class MatcherRequestCompanyPagingReader extends
    IbatisPagingItemReader<MatcherRequestCompany>
{
    private static final Logger log = Logger.getLogger(MatcherRequestCompanyPagingReader.class);

    /**
     * Sets the matcherRequestKey
     * @param matcherRequestKey The matcherRequestKey to set
     */
    public void setMatcherRequestKey(Long matcherRequestKey)
    {
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("matcrequ_key", matcherRequestKey);
        setParameterValues(parameters);
        log.debug("Setting MatcherRequestKey=" + matcherRequestKey);
    }
}

I use spring-2.5.6 with spring-batch-2.0.3 in a JDK6.

It all seems to work fine in my local environment, the error does only ocurr when I deploy the app to Geronimo AS. What could be the problem here and how could it be solved?

Any help would be very much appreciated.

Thx

Kai

spring-projects-issues commented 14 years ago

Dave Syer commented

Thanks for the detailed report. That was a very old forum post, and the original issue was long ago fixed, so almost certainly irrelevant (hence for anyone else reading this issue I removed the old duplicate description - can you give a reference to the old issue in case anyone wants to check it?). Can you provide some more details about how the job was deployed and luanched?

spring-projects-issues commented 14 years ago

Dave Syer commented

Can you post your stack trace as well, please?

spring-projects-issues commented 14 years ago

Kai Hemme-Unger commented

The Job is deployed as a headless web application (WAR) on Geronimo and launched just normally using the the JobLauncher.

--> jobLauncher.run(matcherJob, builder.toJobParameters());

Here is the other relevant part of the config:

<bean id="jobLauncher"
    class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
    <property name="jobRepository" ref="jobRepository" />
    <property name="taskExecutor">
     <bean
            class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
    </property>
</bean>

<bean name="jobExplorer"
    class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
    <property name="dataSource" ref="springBatchDataSource" />
    <property name="tablePrefix" value="MATCHER.BATCH_" />
</bean>

<bean id="jobRepository"
    class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
    <property name="databaseType" value="oracle" />
    <property name="dataSource" ref="springBatchDataSource" />
    <property name="tablePrefix" value="MATCHER.BATCH_"></property>
    <property name="transactionManager" ref="springTransactionManager" />
</bean>

Stacktrace:

There is just one log message that seems to be important to me:

2010.03.01-11:20:57.307 - D - org.mule.config.spring.SpringRegistry - | org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'lazyBindingProxy.positionPagingItemReader': Scope 'step' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No context holder available for step scope

spring-projects-issues commented 14 years ago

Dave Syer commented

There's no stack trace with that message? It's at DEBUG level and comes from a third party component (org.mule.config.spring.SpringRegistry) so it probably makes sense to look at that in some more detail. My guess is there is something in the container trying to play games with your Spring configuration. Without a stack trace it's going to be hard to pin it down, but it seems like it may not be a problem with Spring - you did say that the job works out of container?

spring-projects-issues commented 14 years ago

Kai Hemme-Unger commented

I created an issue @mulesoft. http://www.mulesoft.org/jira/browse/SPRINGPROXIES-5 Thanks for your support on this!

spring-projects-issues commented 14 years ago

Dave Syer commented

OK. Good luck with that. I also found a couple of related issues, e.g. http://www.mulesoft.org/jira/browse/MULE-3927, which say they are fixed in later versions. Maybe you can upgrade?

Honestly though, judging from the config file, I think you would be better off with a plain Spring MDP (no need for Mule at all really).

spring-projects-issues commented 14 years ago

Kai Hemme-Unger commented

Hi all,

the good news is that there is a workaround for this issue. Instead of scope="step" I instantiate the relevant beans in scope="prototype". The point is that the step parameters then cannot be set by late binding anymore. But the clue is to use the StepExecutionListener interface which has a call back method beforeStep(StepExecution). And the StepExecution object has access to the JobParameters.

Here is the change in the configuration:

<bean id="positionPagingItemReader" scope="prototype"
    class="ch.ofwi.matcher.services.business.tdmatcher.v1.impl.jobs.matcher.MatcherRequestCompanyPagingReader">
    <property name="sqlMapClient" ref="matcherMapClient" />
    <property name="queryId" value="tdmatcher.getPagedMatcherCompany" />
    <property name="pageSize" value="1000" />
    <!-- NO LATE BINDING <property name="matcherRequestKey" value="#{jobParameters[matcher.request.key]}" /> -->
</bean>

And here are the changes in the bean class:

public class MatcherRequestCompanyPagingReader extends
    IbatisPagingItemReader<MatcherRequestCompany> implements StepExecutionListener
{
    private static final Logger log = Logger.getLogger(MatcherRequestCompanyPagingReader.class);

//    /**
//     * OLD
//     */
//    public void setMatcherRequestKey(Long matcherRequestKey)
//    {
//        Map<String, Object> parameters = new HashMap<String, Object>();
//        parameters.put("matcrequ_key", matcherRequestKey);
//        setParameterValues(parameters);
//        log.debug("Setting MatcherRequestKey=" + matcherRequestKey);
//    }

    /**
     * NEW
     */
    @Override
    public void beforeStep(StepExecution stepexecution)
    {
        long matcherRequestKey = stepexecution.getJobParameters().getLong(JobParam.JOB_PARAM_MATCHEREQUEST_KEY);
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("matcrequ_key", matcherRequestKey);
        setParameterValues(parameters);
        log.debug("Setting MatcherRequestKey=" + matcherRequestKey);
    }

    /**
     * @see org.springframework.batch.core.StepExecutionListener#afterStep(org.springframework.batch.core.StepExecution)
     */
    @Override
    public ExitStatus afterStep(StepExecution stepexecution)
    {
        return null;
    }
}

Have fun,

Kai