/* * Copyright 2015 Observational Health Data Sciences and Informatics [OHDSI.org]. * * 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 org.ohdsi.webapi.feasibility; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.ohdsi.sql.SqlSplit; import org.ohdsi.sql.SqlTranslate; import org.ohdsi.webapi.cohortdefinition.CohortDefinition; import org.ohdsi.webapi.cohortdefinition.CohortDefinitionRepository; import org.ohdsi.webapi.cohortdefinition.CohortGenerationInfo; import org.ohdsi.webapi.GenerationStatus; import org.ohdsi.webapi.helper.ResourceHelper; import org.ohdsi.webapi.util.SessionUtils; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; /** * * @author Chris Knoll <cknoll@ohdsi.org> */ public class PerformFeasibilityTasklet implements Tasklet { private static final Log log = LogFactory.getLog(PerformFeasibilityTasklet.class); private final static FeasibilityStudyQueryBuilder studyQueryBuilder = new FeasibilityStudyQueryBuilder(); private final static String CREATE_TEMP_TABLES_TEMPLATE = ResourceHelper.GetResourceAsString("/resources/feasibility/sql/inclusionRuleTable_CREATE.sql"); private final static String DROP_TEMP_TABLES_TEMPLATE = ResourceHelper.GetResourceAsString("/resources/feasibility/sql/inclusionRuleTable_DROP.sql"); private final JdbcTemplate jdbcTemplate; private final TransactionTemplate transactionTemplate; private final FeasibilityStudyRepository feasibilityStudyRepository; private final CohortDefinitionRepository cohortDefinitionRepository; public PerformFeasibilityTasklet( final JdbcTemplate jdbcTemplate, final TransactionTemplate transactionTemplate, final FeasibilityStudyRepository feasibilityStudyRepository, final CohortDefinitionRepository cohortDefinitionRepository) { this.jdbcTemplate = jdbcTemplate; this.transactionTemplate = transactionTemplate; this.feasibilityStudyRepository = feasibilityStudyRepository; this.cohortDefinitionRepository = cohortDefinitionRepository; } private StudyGenerationInfo findStudyGenerationInfoBySourceId(Collection<StudyGenerationInfo> infoList, Integer sourceId) { for (StudyGenerationInfo info : infoList) { if (info.getId().getSourceId()== sourceId) return info; } return null; } private CohortGenerationInfo findCohortGenerationInfoBySourceId(Collection<CohortGenerationInfo> infoList, Integer sourceId) { for (CohortGenerationInfo info : infoList) { if (info.getId().getSourceId()== sourceId) return info; } return null; } private void prepareTempTables(FeasibilityStudy study, String dialect, String sessionId) { String translatedSql = SqlTranslate.translateSql(CREATE_TEMP_TABLES_TEMPLATE, "sql server", dialect, sessionId, null); String[] sqlStatements = SqlSplit.splitSql(translatedSql); this.jdbcTemplate.batchUpdate(sqlStatements); String insertSql = SqlTranslate.translateSql("INSERT INTO #inclusionRules (study_id, sequence, name) VALUES (?,?,?)","sql server", dialect, sessionId, null); List<InclusionRule> inclusionRules = study.getInclusionRules(); for (int i = 0; i< inclusionRules.size(); i++) { InclusionRule r = inclusionRules.get(i); this.jdbcTemplate.update(insertSql, new Object[] { study.getId(), i, r.getName()}); } } private void cleanupTempTables(String dialect, String sessionId) { String translatedSql = SqlTranslate.translateSql(DROP_TEMP_TABLES_TEMPLATE, "sql server", dialect, sessionId, null); String[] sqlStatements = SqlSplit.splitSql(translatedSql); this.jdbcTemplate.batchUpdate(sqlStatements); } private int[] doTask(ChunkContext chunkContext) { Map<String, Object> jobParams = chunkContext.getStepContext().getJobParameters(); Integer studyId = Integer.valueOf(jobParams.get("study_id").toString()); int[] result = null; try { String sessionId = SessionUtils.sessionId(); FeasibilityStudy study = this.feasibilityStudyRepository.findOne(studyId); FeasibilityStudyQueryBuilder.BuildExpressionQueryOptions options = new FeasibilityStudyQueryBuilder.BuildExpressionQueryOptions(); options.cdmSchema = jobParams.get("cdm_database_schema").toString(); options.ohdsiSchema = jobParams.get("target_database_schema").toString(); options.cohortTable = jobParams.get("target_database_schema").toString() + "." + jobParams.get("target_table").toString(); if (study.getResultRule() != null) { prepareTempTables(study, jobParams.get("target_dialect").toString(), sessionId); String expressionSql = studyQueryBuilder.buildSimulateQuery(study, options); String translatedSql = SqlTranslate.translateSql(expressionSql, "sql server", jobParams.get("target_dialect").toString(), sessionId, null); String[] sqlStatements = SqlSplit.splitSql(translatedSql); result = PerformFeasibilityTasklet.this.jdbcTemplate.batchUpdate(sqlStatements); cleanupTempTables(jobParams.get("target_dialect").toString(), sessionId); } else { String expressionSql = studyQueryBuilder.buildNullQuery(study, options); String translatedSql = SqlTranslate.translateSql(expressionSql, "sql server", jobParams.get("target_dialect").toString(), sessionId, null); String[] sqlStatements = SqlSplit.splitSql(translatedSql); result = PerformFeasibilityTasklet.this.jdbcTemplate.batchUpdate(sqlStatements); } } catch (Exception e) { throw new RuntimeException(e); } return result; } @Override public RepeatStatus execute(final StepContribution contribution, final ChunkContext chunkContext) throws Exception { Date startTime = Calendar.getInstance().getTime(); Map<String, Object> jobParams = chunkContext.getStepContext().getJobParameters(); Integer studyId = Integer.valueOf(jobParams.get("study_id").toString()); Integer sourceId = Integer.valueOf(jobParams.get("source_id").toString()); boolean isValid = false; DefaultTransactionDefinition requresNewTx = new DefaultTransactionDefinition(); requresNewTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); TransactionStatus initStatus = this.transactionTemplate.getTransactionManager().getTransaction(requresNewTx); FeasibilityStudy study = this.feasibilityStudyRepository.findOne(studyId); CohortDefinition resultDef = study.getResultRule(); if (resultDef != null) { CohortGenerationInfo resultInfo = findCohortGenerationInfoBySourceId(resultDef.getGenerationInfoList(), sourceId); resultInfo.setIsValid(false) .setStatus(GenerationStatus.RUNNING) .setStartTime(startTime) .setExecutionDuration(null); } StudyGenerationInfo studyInfo = findStudyGenerationInfoBySourceId(study.getStudyGenerationInfoList(), sourceId); studyInfo.setIsValid(false); studyInfo.setStartTime(startTime); studyInfo.setStatus(GenerationStatus.RUNNING); this.feasibilityStudyRepository.save(study); this.transactionTemplate.getTransactionManager().commit(initStatus); try { final int[] ret = this.transactionTemplate.execute(new TransactionCallback<int[]>() { @Override public int[] doInTransaction(final TransactionStatus status) { return doTask(chunkContext); } }); log.debug("Update count: " + ret.length); isValid = true; } catch (final TransactionException e) { isValid = false; log.error(e.getMessage(), e); throw e;//FAIL job status } finally { TransactionStatus completeStatus = this.transactionTemplate.getTransactionManager().getTransaction(requresNewTx); Date endTime = Calendar.getInstance().getTime(); study = this.feasibilityStudyRepository.findOne(studyId); resultDef = study.getResultRule(); if (resultDef != null) { CohortGenerationInfo resultInfo = findCohortGenerationInfoBySourceId(resultDef.getGenerationInfoList(), sourceId); resultInfo = findCohortGenerationInfoBySourceId(resultDef.getGenerationInfoList(), sourceId); resultInfo.setIsValid(isValid); resultInfo.setExecutionDuration(new Integer((int)(endTime.getTime() - startTime.getTime()))); resultInfo.setStatus(GenerationStatus.COMPLETE); } studyInfo = findStudyGenerationInfoBySourceId(study.getStudyGenerationInfoList(), sourceId); studyInfo.setIsValid(isValid); studyInfo.setExecutionDuration(new Integer((int)(endTime.getTime() - startTime.getTime()))); studyInfo.setStatus(GenerationStatus.COMPLETE); this.feasibilityStudyRepository.save(study); this.transactionTemplate.getTransactionManager().commit(completeStatus); } return RepeatStatus.FINISHED; } }