34947


JavaEEをベースにWebアプリケーションを作成しています。  
ビジネスロジックや、データアクセス用のクラスに、`@RequestScpoed`を使って実装していたのですが、jBatchからは、`@Dependent`または、`@ApplicationScoped`しか呼び出せないことがわかり、困っています。

以下の様なエラーが出てしまいます。

> 重大: Failure in Read-Process-Write Loop  
>  com.ibm.jbatch.container.exception.BatchContainerRuntimeException:
> org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active
> contexts for scope type javax.enterprise.context.RequestScoped

以下のページに参考になりそうな情報があったのですが、  
解決方法がわかりませんでした。  
<https://stackoverflow.com/questions/31847287/cdi-simulate-request-scope>


CC BY-SA 3.0
2017-05-22T04:26:02.600
34920
2017-05-23T03:14:05.340
2017-05-23T12:38:55.250
-1
5792
question
java java-ee
CDIの@RequestScopedで作成したビジネスロジックをjBatchから呼び出す方法


jBatchから呼び出す入口をEJB（@Stateless）にして、その中で、@RequestScopedの既存のビジネスロジックを呼び出す様にしたら、動作しました。


CC BY-SA 3.0
2017-05-22T07:30:43.293
34927
2017-05-22T07:30:43.293
5792
34920
answer


WildFly10.1.0.Final(jBatch実装: jberet 1.2.1, CDI実装: Weld 2.3.5)で試してみました:

batch artifact の中で `@RequestScoped` なCDI Beanをinjectした場合、次のような例外が送出されました。

[code]

    10:15:01,645 WARN  [org.jberet] (Batch Thread - 3) JBERET000001: Failed to run batchlet org.jberet.job.model.RefArtifact@730db889: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped
        at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:689)
        at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:90)
        at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:165)
        at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63)
        at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:83)
        at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:125)
        at jp.himeji_cs.javaee.hello_jbatch.MyRequestScopedBean$Proxy$_$$_WeldClientProxy.sayHello(Unknown Source)
        at org.javaee7.batch.batchlet.simple.MyBatchlet.process(MyBatchlet.java:61)
        at org.jberet.runtime.runner.BatchletRunner.run(BatchletRunner.java:72)
        at org.jberet.runtime.runner.StepExecutionRunner.runBatchletOrChunk(StepExecutionRunner.java:229)
        at org.jberet.runtime.runner.StepExecutionRunner.run(StepExecutionRunner.java:147)
        at org.jberet.runtime.runner.CompositeExecutionRunner.runStep(CompositeExecutionRunner.java:164)
        at org.jberet.runtime.runner.CompositeExecutionRunner.runFromHeadOrRestartPoint(CompositeExecutionRunner.java:88)
        at org.jberet.runtime.runner.JobExecutionRunner.run(JobExecutionRunner.java:60)
        at org.wildfly.extension.batch.jberet.impl.BatchEnvironmentService$WildFlyBatchEnvironment$1.run(BatchEnvironmentService.java:243)
        at org.wildfly.extension.requestcontroller.RequestController$QueuedTask$1.run(RequestController.java:497)
        at org.jberet.spi.JobExecutor$3.run(JobExecutor.java:161)
        at org.jberet.spi.JobExecutor$1.run(JobExecutor.java:99)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
        at org.jboss.threads.JBossThread.run(JBossThread.java:320)
    
[/code]

今回ServletコンテナからjBatchを実行したのですが、jBatch自体は別スレッド(Servletとは別コンテキスト)で処理されるようです。  
(これが仕様からみて当然な挙動なのか、実装依存の話なのかは分かりませんでした。おそらく[JSR-352](https://jcp.org/en/jsr/detail?id=352)
specの"10.5 Batch Artifact Loading", "11 Job Runtime
Lifecycle"あたりが関係しそうでしたが理解できていません…)  
そこでは[request contextがアクティブ化されていない](http://docs.jboss.org/cdi/spec/1.2/cdi-
spec.html#request_context)のでinjectしようとすると例外が発生する、ということだと思います。

解決策のひとつとしては、request contextがアクティブ化される条件(先に示した[CDI
spec](http://docs.jboss.org/cdi/spec/1.2/cdi-
spec.html#request_context)参照)下で実行するようにする、というのが考えられ、[質問文中リンク先で示されている、EJB
Beanを用いる](https://stackoverflow.com/questions/31847287/cdi-simulate-request-
scope#comment51669293_31847287)というのはこれに当たるでしょう。  
もうひとつ別の解決策としては、自前ででアクティブ化する、という方法も考えられます。

  * [java - WebSocket endpoint and CDI injection: No active contexts for scope RequestScoped - Stack Overflow](https://stackoverflow.com/questions/42440851/websocket-endpoint-and-cdi-injection-no-active-contexts-for-scope-requestscoped/42442415#42442415)

この例ではWeld依存になりますが、上記リンク先で示されているインタセプタ`RequestContextInterceptor`を利用する(※ただしそのままでは上手く動かなかったので[Priorityを設定](https://github.com/yukihane/hello-
jbatch/blob/13ef3b2d1934cfcc7ffbea6a3ac22725d244ee42/src/main/java/jp/himeji_cs/javaee/hello_jbatch/scope_controll/RequestContextInterceptor.java#L18))ことで`Batchlet`内でも`@RequestScoped`なCDI
Beanをinjectできるようになりました。

[code]

    @Dependent
    @Named
    public class MyBatchlet extends AbstractBatchlet {
    
        @Inject
        private MyRequestScopedBean myBean;
    
        @RequestContextOperation
        @Override
        public String process() {
            System.out.println(myBean.sayHello());
    
            return BatchStatus.COMPLETED.toString();
        }
    }
    
[/code]

今回検証に使ったソースは[こちら](https://github.com/yukihane/hello-jbatch)になります。


CC BY-SA 3.0
2017-05-23T03:14:05.340
34947
2017-05-23T03:14:05.340
2808
34920
answer