/* * Copyright (c) 2016 NTT DATA Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jp.terasoluna.fw.batch.executor; import org.springframework.context.ApplicationContext; import org.springframework.util.Assert; import jp.terasoluna.fw.batch.blogic.BLogic; import jp.terasoluna.fw.batch.blogic.BLogicResolver; import jp.terasoluna.fw.batch.blogic.vo.BLogicParam; import jp.terasoluna.fw.batch.blogic.vo.BLogicParamConverter; import jp.terasoluna.fw.batch.constants.LogId; import jp.terasoluna.fw.batch.exception.handler.BLogicExceptionHandlerResolver; import jp.terasoluna.fw.batch.exception.handler.ExceptionHandler; import jp.terasoluna.fw.batch.executor.repository.JobControlFinder; import jp.terasoluna.fw.batch.executor.repository.JobStatusChanger; import jp.terasoluna.fw.batch.executor.vo.BLogicResult; import jp.terasoluna.fw.batch.executor.vo.BatchJobData; import jp.terasoluna.fw.logger.TLogger; /** * ジョブシーケンスコードにもとづいたジョブを、ワーカスレッドで実行する実装クラス<br> * <p> * 本クラスは、以下の3ステップに処理を分割している。 * <ol> * <li>{@code #beforeExecute}:前処理。ジョブステータスを「実行中:1」に変更する</li> * <li>{@code #executeWorker}:主処理。BLogicを実行する。</li> * <li>{@code #afterExecuteWorker}:後処理。ジョブステータスを「処理済み:2」に変更する</li> * </ol> * </p> * <p> * 前処理は、本クラスを呼び出す側(メインスレッド)にて実行すること。主処理、後処理はワーカスレッドにて実行すること。<br> * 後処理は、主処理の内部で呼び出されるため個別に呼び出してはならない。<br> * </p> * @since 3.6 */ public class AsyncJobWorkerImpl implements AsyncJobWorker { /** * ロガー */ private static final TLogger LOGGER = TLogger .getLogger(AsyncJobWorkerImpl.class); /** * BLogicのインスタンスを取得するためのBLogicResolverオブジェクト */ protected BLogicResolver blogicResolver; /** * BLogic用の例外ハンドラのインスタンスを取得するためのBLogicExceptionHandlerResolverオブジェクト */ protected BLogicExceptionHandlerResolver blogicExceptionHandlerResolver; /** * ジョブ業務コードに対応するジョブ用DIコンテナを取得するためのApplicationContextResolverオブジェクト */ protected ApplicationContextResolver blogicApplicationContextResolver; /** * ジョブシーケンスコードに該当するBatchJobDataを取得するためのJobControlFinderオブジェクト */ protected JobControlFinder jobControlFinder; /** * BatchJobDataからBLogicParamに変換するためのBLogicParamConverterオブジェクト */ protected BLogicParamConverter blogicParamConverter; /** * ジョブ管理テーブルのジョブステータスを変更するためのJobStatusChangerオブジェクト */ protected JobStatusChanger jobStatusChanger; /** * BLogicの実行を移譲するBLogicExecutorオブジェクト */ protected BLogicExecutor blogicExecutor; /** * AsyncJobWorkerImplのコンストラクタ * * @param blogicResolver BLogicのインスタンスを取得するためのBLogicResolverオブジェクト * @param blogicExceptionHandlerResolver BLogic用の例外ハンドラのインスタンスを取得するためのBLogicExceptionHandlerResolverオブジェクト * @param blogicApplicationContextResolver ジョブ業務コードに対応するジョブ用DIコンテナを取得するためのBLogicApplicationContextResolverオブジェクト * @param jobControlFinder ジョブシーケンスコードに該当するBatchJobDataを取得するためのJobControlFinderオブジェクト * @param blogicParamConverter BatchJobDataからBLogicParamに変換するためのBLogicParamConverterオブジェクト * @param blogicExecutor BLogicの実行を移譲するBLogicExecutorオブジェクト * @param jobStatusChanger ジョブ管理テーブルのジョブステータスを変更するためのJobStatusChangerオブジェクト */ protected AsyncJobWorkerImpl(BLogicResolver blogicResolver, BLogicExceptionHandlerResolver blogicExceptionHandlerResolver, ApplicationContextResolver blogicApplicationContextResolver, JobControlFinder jobControlFinder, BLogicParamConverter blogicParamConverter, BLogicExecutor blogicExecutor, JobStatusChanger jobStatusChanger) { Assert.notNull(blogicResolver, LOGGER.getLogMessage(LogId.EAL025056, this.getClass().getSimpleName(), "BLogicResolver")); Assert.notNull(blogicExceptionHandlerResolver, LOGGER.getLogMessage( LogId.EAL025056, this.getClass().getSimpleName(), "BLogicExceptionHandlerResolver")); Assert.notNull(blogicApplicationContextResolver, LOGGER.getLogMessage( LogId.EAL025056, this.getClass().getSimpleName(), "ApplicationContextResolver")); Assert.notNull(jobControlFinder, LOGGER.getLogMessage(LogId.EAL025056, this.getClass().getSimpleName(), "JobControlFinder")); Assert.notNull(blogicParamConverter, LOGGER.getLogMessage( LogId.EAL025056, this.getClass().getSimpleName(), "BLogicParamConverter")); Assert.notNull(blogicExecutor, LOGGER.getLogMessage(LogId.EAL025056, this.getClass().getSimpleName(), "BLogicExecutor")); Assert.notNull(jobStatusChanger, LOGGER.getLogMessage(LogId.EAL025056, this.getClass().getSimpleName(), "JobStatusChanger")); this.blogicResolver = blogicResolver; this.blogicExceptionHandlerResolver = blogicExceptionHandlerResolver; this.blogicApplicationContextResolver = blogicApplicationContextResolver; this.jobControlFinder = jobControlFinder; this.blogicParamConverter = blogicParamConverter; this.blogicExecutor = blogicExecutor; this.jobStatusChanger = jobStatusChanger; } /** * ジョブシーケンスコードに該当するジョブの前処理を行う<br> * <p> * ジョブシーケンスコードに該当するレコードのジョブステータスを「実行中:1」に変更する。 * </p> * @param jobSequenceId ジョブシーケンスコード * @return 前処理の処理結果(true:更新成功、false:更新失敗) */ public boolean beforeExecute(final String jobSequenceId) { boolean updated = jobStatusChanger.changeToStartStatus(jobSequenceId); return updated; } /** * ジョブシーケンスコードに該当するジョブの主処理を行う<br> * <p> * <ul> * <li>{@code #beforeExecute}を呼び出す</li> * <li>ジョブシーケンスコードに該当するBatchJobDataを取得後、ジョブ業務コード(jobAppCd)からBLogic、BLogicParam、例外ハンドラのそれぞれのインスタンスを取得し、 * BLogicExecutorにBLogicの実行を移譲する。</li> * <li>{@code #afterExecuteWorker}を呼び出す。</li> * </ul> * </p> * @param jobSequenceId ジョブシーケンスコード */ @Override public void executeWorker(final String jobSequenceId) { LOGGER.info(LogId.IAL025001, jobSequenceId); BLogicResult blogicResult = new BLogicResult(); ApplicationContext blogicContext = null; ExceptionHandler blogicExceptionHandler = null; BLogic blogic = null; BLogicParam blogicParam = null; try { BatchJobData batchJobData = jobControlFinder .resolveBatchJobData(jobSequenceId); blogicContext = blogicApplicationContextResolver .resolveApplicationContext(batchJobData); blogic = blogicResolver.resolveBLogic(blogicContext, batchJobData.getJobAppCd()); blogicParam = blogicParamConverter.convertBLogicParam(batchJobData); try { blogicExceptionHandler = blogicExceptionHandlerResolver .resolveExceptionHandler(blogicContext, batchJobData.getJobAppCd()); } catch (Exception e) { // Do nothing } if (blogicExceptionHandler == null) { // ExceptionHandlerがない場合でも処理を継続する LOGGER.warn(LogId.WAL025010); } try { blogicResult = blogicExecutor.execute(blogicContext, blogic, blogicParam, blogicExceptionHandler); } catch (Exception e) { LOGGER.error(LogId.EAL025059, e, jobSequenceId); } } catch (Exception e) { LOGGER.error(LogId.EAL025055, e, jobSequenceId); } finally { afterExecuteWorker(jobSequenceId, blogicResult); blogicApplicationContextResolver .closeApplicationContext(blogicContext); LOGGER.info(LogId.IAL025003, jobSequenceId, blogicResult.getBlogicStatus()); } } /** * ジョブシーケンスコードに該当するジョブの後処理を行う<br> * <p> * ジョブシーケンスコードに該当するジョブのレコードに対し、ビジネスロジック戻り値を更新し、 ジョブステータスを「処理済み:2」に更新する。 * </p> * @param jobSequenceId ジョブシーケンスコード * @param blogicResult ビジネスロジック戻り値 */ protected void afterExecuteWorker(String jobSequenceId, BLogicResult blogicResult) { Integer blogicStatus = blogicResult == null ? null : blogicResult .getBlogicStatus(); try { boolean updated = jobStatusChanger.changeToEndStatus(jobSequenceId, blogicResult); if (!updated) { LOGGER.error(LogId.EAL025025, jobSequenceId, blogicStatus); } } catch (Exception e) { LOGGER.error(LogId.EAL025025, e, jobSequenceId, blogicStatus); } } }