/*
* 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.service;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.opencsv.CSVWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ohdsi.sql.SqlTranslate;
import org.ohdsi.webapi.GenerationStatus;
import org.ohdsi.webapi.exampleapplication.model.Widget;
import org.ohdsi.webapi.helper.ResourceHelper;
import org.ohdsi.webapi.ircalc.AnalysisReport;
import org.ohdsi.webapi.ircalc.ExecutionInfo;
import org.ohdsi.webapi.ircalc.IncidenceRateAnalysis;
import org.ohdsi.webapi.ircalc.IncidenceRateAnalysisDetails;
import org.ohdsi.webapi.ircalc.IncidenceRateAnalysisExpression;
import org.ohdsi.webapi.ircalc.IncidenceRateAnalysisRepository;
import org.ohdsi.webapi.ircalc.PerformAnalysisTasklet;
import org.ohdsi.webapi.job.JobExecutionResource;
import org.ohdsi.webapi.job.JobTemplate;
import org.ohdsi.webapi.shiro.management.Security;
import org.ohdsi.webapi.source.Source;
import org.ohdsi.webapi.source.SourceDaimon;
import org.ohdsi.webapi.util.SessionUtils;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallback;
/**
*
* @author Chris Knoll <cknoll@ohdsi.org>
*/
@Path("/ir/")
@Component
public class IRAnalysisService extends AbstractDaoService {
private static final Log log = LogFactory.getLog(IRAnalysisService.class);
private final static String STRATA_STATS_QUERY_TEMPLATE = ResourceHelper.GetResourceAsString("/resources/incidencerate/sql/strata_stats.sql");
@Autowired
private IncidenceRateAnalysisRepository irAnalysisRepository;
@Autowired
private JobBuilderFactory jobBuilders;
@Autowired
private StepBuilderFactory stepBuilders;
@Autowired
private JobTemplate jobTemplate;
@Autowired
private Security security;
@Context
ServletContext context;
private ExecutionInfo findExecutionInfoBySourceId(Collection<ExecutionInfo> infoList, Integer sourceId) {
for (ExecutionInfo info : infoList) {
if (sourceId.equals(info.getId().getSourceId())) {
return info;
}
}
return null;
}
public static class IRAnalysisListItem {
public Integer id;
public String name;
public String description;
public String createdBy;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd, HH:mm")
public Date createdDate;
public String modifiedBy;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd, HH:mm")
public Date modifiedDate;
}
public static class IRAnalysisDTO extends IRAnalysisListItem {
public String expression;
}
public static class AnalysisInfoDTO {
public ExecutionInfo executionInfo;
public List<AnalysisReport.Summary> summaryList = new ArrayList<>();
}
public static class StratifyReportItem {
public long bits;
public long totalPersons;
public long timeAtRisk;
public long cases;
}
private final RowMapper<AnalysisReport.Summary> summaryMapper = new RowMapper<AnalysisReport.Summary>() {
@Override
public AnalysisReport.Summary mapRow(ResultSet rs, int rowNum) throws SQLException {
AnalysisReport.Summary summary = new AnalysisReport.Summary();
summary.targetId = rs.getInt("target_id");
summary.outcomeId = rs.getInt("outcome_id");
summary.totalPersons = rs.getLong("person_count");
summary.timeAtRisk = rs.getLong("time_at_risk");
summary.cases = rs.getLong("cases");
return summary;
}
};
private List<AnalysisReport.Summary> getAnalysisSummaryList(int id, Source source) {
String resultsTableQualifier = source.getTableQualifier(SourceDaimon.DaimonType.Results);
String summaryQuery = String.format("select target_id, outcome_id, sum(person_count) as person_count, sum(time_at_risk) as time_at_risk, sum(cases) as cases from %s.ir_analysis_result where analysis_id = %d GROUP BY target_id, outcome_id", resultsTableQualifier, id);
String translatedSql = SqlTranslate.translateSql(summaryQuery, "sql server", source.getSourceDialect(), SessionUtils.sessionId(), resultsTableQualifier);
List<AnalysisReport.Summary> summaryList = this.getSourceJdbcTemplate(source).query(translatedSql, summaryMapper);
return summaryList;
}
private final RowMapper<AnalysisReport.StrataStatistic> strataRuleStatisticMapper = new RowMapper<AnalysisReport.StrataStatistic>() {
@Override
public AnalysisReport.StrataStatistic mapRow(ResultSet rs, int rowNum) throws SQLException {
AnalysisReport.StrataStatistic statistic = new AnalysisReport.StrataStatistic();
statistic.id = rs.getInt("strata_sequence");
statistic.name = rs.getString("name");
statistic.targetId = rs.getInt("target_id");
statistic.outcomeId = rs.getInt("outcome_id");
statistic.totalPersons = rs.getLong("person_count");
statistic.timeAtRisk = rs.getLong("time_at_risk");
statistic.cases = rs.getLong("cases");
return statistic;
}
};
private List<AnalysisReport.StrataStatistic> getStrataStatistics(int id, Source source) {
String resultsTableQualifier = source.getTableQualifier(SourceDaimon.DaimonType.Results);
String statisticsQuery = STRATA_STATS_QUERY_TEMPLATE;
statisticsQuery = statisticsQuery.replace("@results_database_schema", resultsTableQualifier);
statisticsQuery = statisticsQuery.replace("@analysis_id", String.valueOf(id));
String translatedSql = SqlTranslate.translateSql(statisticsQuery, "sql server", source.getSourceDialect(), SessionUtils.sessionId(), resultsTableQualifier);
return this.getSourceJdbcTemplate(source).query(translatedSql, strataRuleStatisticMapper);
}
private int countSetBits(long n) {
int count = 0;
while (n > 0) {
n &= (n - 1);
count++;
}
return count;
}
private String formatBitMask(Long n, int size) {
return StringUtils.reverse(StringUtils.leftPad(Long.toBinaryString(n), size, "0"));
}
private final RowMapper<StratifyReportItem> stratifyResultsMapper = new RowMapper<StratifyReportItem>() {
@Override
public StratifyReportItem mapRow(ResultSet rs, int rowNum) throws SQLException {
StratifyReportItem resultItem = new StratifyReportItem();
resultItem.bits = rs.getLong("strata_mask");
resultItem.totalPersons = rs.getLong("person_count");
resultItem.timeAtRisk = rs.getLong("time_at_risk");
resultItem.cases = rs.getLong("cases");
return resultItem;
}
};
private String getStrataTreemapData(int analysisId, int targetId, int outcomeId, int inclusionRuleCount, Source source) {
String resultsTableQualifier = source.getTableQualifier(SourceDaimon.DaimonType.Results);
String analysisResultsQuery = String.format("select strata_mask, person_count, time_at_risk, cases from %s.ir_analysis_result where analysis_id = %d and target_id = %d and outcome_id = %d",
resultsTableQualifier, analysisId, targetId, outcomeId);
String translatedSql = SqlTranslate.translateSql(analysisResultsQuery, "sql server", source.getSourceDialect(), SessionUtils.sessionId(), resultsTableQualifier);
// [0] is the inclusion rule bitmask, [1] is the count of the match
List<StratifyReportItem> items = this.getSourceJdbcTemplate(source).query(translatedSql, stratifyResultsMapper);
Map<Integer, List<StratifyReportItem>> groups = new HashMap<>();
for (StratifyReportItem item : items) {
int bitsSet = countSetBits(item.bits);
if (!groups.containsKey(bitsSet)) {
groups.put(bitsSet, new ArrayList<StratifyReportItem>());
}
groups.get(bitsSet).add(item);
}
StringBuilder treemapData = new StringBuilder("{\"name\" : \"Everyone\", \"children\" : [");
List<Integer> groupKeys = new ArrayList<>(groups.keySet());
Collections.sort(groupKeys);
Collections.reverse(groupKeys);
int groupCount = 0;
// create a nested treemap data where more matches (more bits set in string) appear higher in the hierarchy)
for (Integer groupKey : groupKeys) {
if (groupCount > 0) {
treemapData.append(",");
}
treemapData.append(String.format("{\"name\" : \"Group %d\", \"children\" : [", groupKey));
int groupItemCount = 0;
for (StratifyReportItem groupItem : groups.get(groupKey)) {
if (groupItemCount > 0) {
treemapData.append(",");
}
//sb_treemap.Append("{\"name\": \"" + cohort_identifer + "\", \"size\": " + cohorts[cohort_identifer].ToString() + "}");
treemapData.append(String.format("{\"name\": \"%s\", \"size\": %d, \"cases\": %d, \"timeAtRisk\": %d }", formatBitMask(groupItem.bits, inclusionRuleCount), groupItem.totalPersons, groupItem.cases, groupItem.timeAtRisk));
groupItemCount++;
}
groupCount++;
}
treemapData.append(StringUtils.repeat("]}", groupCount + 1));
return treemapData.toString();
}
public IRAnalysisDTO analysisToDTO(IncidenceRateAnalysis analysis) {
IRAnalysisDTO aDTO = new IRAnalysisDTO();
aDTO.id = analysis.getId();
aDTO.name = analysis.getName();
aDTO.description = analysis.getDescription();
aDTO.createdBy = analysis.getCreatedBy();
aDTO.createdDate = analysis.getCreatedDate();
aDTO.modifiedBy = analysis.getModifiedBy();
aDTO.modifiedDate = analysis.getModifiedDate();
aDTO.expression = analysis.getDetails() != null ? analysis.getDetails().getExpression() : null;
return aDTO;
}
/**
* Returns all IR Analysis in a list.
*
* @return List of IncidenceRateAnalysis
*/
@GET
@Path("/")
@Produces(MediaType.APPLICATION_JSON)
public List<IRAnalysisService.IRAnalysisListItem> getIRAnalysisList() {
ArrayList<IRAnalysisService.IRAnalysisListItem> result = new ArrayList<>();
Iterable<IncidenceRateAnalysis> analysisList = this.irAnalysisRepository.findAll();
for (IncidenceRateAnalysis p : analysisList) {
IRAnalysisService.IRAnalysisListItem item = new IRAnalysisService.IRAnalysisListItem();
item.id = p.getId();
item.name = p.getName();
item.description = p.getDescription();
item.createdBy = p.getCreatedBy();
item.createdDate = p.getCreatedDate();
item.modifiedBy = p.getModifiedBy();
item.modifiedDate = p.getModifiedDate();
result.add(item);
}
return result;
}
/**
* Creates the incidence rate analysis
*
* @param analysis The analysis to create.
* @return The new FeasibilityStudy
*/
@POST
@Path("/")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Transactional
public IRAnalysisDTO createAnalysis(IRAnalysisDTO analysis) {
Date currentTime = Calendar.getInstance().getTime();
// it might be possible to leverage saveAnalysis() but not sure how to pull the auto ID from
// the DB to pass it into saveAnalysis (since saveAnalysis does a findOne() at the start).
// If there's a way to get the Entity into the persistence manager so findOne() returns this newly created entity
// then we could create the entity here (wihtout persist) and then call saveAnalysis within the sasme Tx.
IncidenceRateAnalysis newAnalysis = new IncidenceRateAnalysis();
newAnalysis.setName(analysis.name)
.setDescription(analysis.description)
.setCreatedBy(security.getSubject())
.setCreatedDate(currentTime);
if (analysis.expression != null) {
IncidenceRateAnalysisDetails details = new IncidenceRateAnalysisDetails(newAnalysis);
newAnalysis.setDetails(details);
details.setExpression(analysis.expression);
}
else
newAnalysis.setDetails(null);
IncidenceRateAnalysis createdAnalysis = this.irAnalysisRepository.save(newAnalysis);
return analysisToDTO(createdAnalysis);
}
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Transactional(readOnly = true)
public IRAnalysisDTO getAnalysis(@PathParam("id") final int id) {
IncidenceRateAnalysis a = this.irAnalysisRepository.findOne(id);
return analysisToDTO(a);
}
@PUT
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Transactional
public IRAnalysisDTO saveAnalysis(@PathParam("id") final int id, IRAnalysisDTO analysis) {
Date currentTime = Calendar.getInstance().getTime();
IncidenceRateAnalysis updatedAnalysis = this.irAnalysisRepository.findOne(id);
updatedAnalysis.setName(analysis.name)
.setDescription(analysis.description)
.setModifiedBy(security.getSubject())
.setModifiedDate(currentTime);
if (analysis.expression != null) {
IncidenceRateAnalysisDetails details = updatedAnalysis.getDetails();
if (details == null) {
details = new IncidenceRateAnalysisDetails(updatedAnalysis);
updatedAnalysis.setDetails(details);
}
details.setExpression(analysis.expression);
}
else
updatedAnalysis.setDetails(null);
this.irAnalysisRepository.save(updatedAnalysis);
return getAnalysis(id);
}
@GET
@Path("/{analysis_id}/execute/{sourceKey}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public JobExecutionResource performAnalysis(@PathParam("analysis_id") final int analysisId, @PathParam("sourceKey") final String sourceKey) {
Date startTime = Calendar.getInstance().getTime();
Source source = this.getSourceRepository().findBySourceKey(sourceKey);
String resultsTableQualifier = source.getTableQualifier(SourceDaimon.DaimonType.Results);
String cdmTableQualifier = source.getTableQualifier(SourceDaimon.DaimonType.CDM);
DefaultTransactionDefinition requresNewTx = new DefaultTransactionDefinition();
requresNewTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus initStatus = this.getTransactionTemplate().getTransactionManager().getTransaction(requresNewTx);
IncidenceRateAnalysis analysis = this.irAnalysisRepository.findOne(analysisId);
ExecutionInfo analysisInfo = findExecutionInfoBySourceId(analysis.getExecutionInfoList(), source.getSourceId());
if (analysisInfo != null) {
if (analysisInfo.getStatus() != GenerationStatus.COMPLETE)
return null; // Exit execution, another process has started it.
}
else {
analysisInfo = new ExecutionInfo(analysis, source);
analysis.getExecutionInfoList().add(analysisInfo);
}
analysisInfo.setStatus(GenerationStatus.PENDING)
.setStartTime(startTime)
.setExecutionDuration(null);
this.irAnalysisRepository.save(analysis);
this.getTransactionTemplate().getTransactionManager().commit(initStatus);
JobParametersBuilder builder = new JobParametersBuilder();
builder.addString("jobName", "IR Analysis: " + analysis.getId() + " : " + source.getSourceName() + " (" + source.getSourceKey() + ")");
builder.addString("cdm_database_schema", cdmTableQualifier);
builder.addString("results_database_schema", resultsTableQualifier);
builder.addString("target_dialect", source.getSourceDialect());
builder.addString("analysis_id", ("" + analysisId));
builder.addString("source_id", ("" + source.getSourceId()));
final JobParameters jobParameters = builder.toJobParameters();
PerformAnalysisTasklet analysisTasklet = new PerformAnalysisTasklet(getSourceJdbcTemplate(source), getTransactionTemplate(), irAnalysisRepository);
Step irAnalysisStep = stepBuilders.get("irAnalysis.execute")
.tasklet(analysisTasklet)
.build();
Job executeAnalysis = jobBuilders.get("irAnalysis")
.start(irAnalysisStep)
.build();
JobExecutionResource jobExec = this.jobTemplate.launch(executeAnalysis, jobParameters);
return jobExec; }
@GET
@Path("/{id}/info")
@Produces(MediaType.APPLICATION_JSON)
@Transactional(readOnly = true)
public List<AnalysisInfoDTO> getAnalysisInfo(@PathParam("id") final int id) {
IncidenceRateAnalysis analysis = this.irAnalysisRepository.findOne(id);
List<AnalysisInfoDTO> result = new ArrayList<>();
for (ExecutionInfo executionInfo : analysis.getExecutionInfoList()) {
AnalysisInfoDTO info = new AnalysisInfoDTO();
info.executionInfo = executionInfo;
try {
if (executionInfo.getStatus() == GenerationStatus.COMPLETE && executionInfo.getIsValid())
info.summaryList = getAnalysisSummaryList(id, executionInfo.getSource());
}
catch (Exception e)
{
log.error("Error getting IR Analysis summary list.", e);
}
result.add(info);
}
return result;
}
@GET
@Path("/{id}/report/{sourceKey}")
@Produces(MediaType.APPLICATION_JSON)
@Transactional
public AnalysisReport getAnalysisReport(@PathParam("id") final int id, @PathParam("sourceKey") final String sourceKey, @QueryParam("targetId") final int targetId, @QueryParam("outcomeId") final int outcomeId ) {
Source source = this.getSourceRepository().findBySourceKey(sourceKey);
AnalysisReport.Summary summary = IterableUtils.find(getAnalysisSummaryList(id, source), new Predicate<AnalysisReport.Summary>() {
@Override
public boolean evaluate(AnalysisReport.Summary summary) {
return ((summary.targetId == targetId) && (summary.outcomeId == outcomeId));
}
});
Collection<AnalysisReport.StrataStatistic> strataStats = CollectionUtils.select(getStrataStatistics(id, source), new Predicate<AnalysisReport.StrataStatistic>() {
@Override
public boolean evaluate(AnalysisReport.StrataStatistic summary) {
return ((summary.targetId == targetId) && (summary.outcomeId == outcomeId));
}
});
String treemapData = getStrataTreemapData(id, targetId, outcomeId, strataStats.size(), source);
AnalysisReport report = new AnalysisReport();
report.summary = summary;
report.stratifyStats = new ArrayList<>(strataStats);
report.treemapData = treemapData;
return report;
}
/**
* Copies the specified cohort definition
*
* @param id - the Cohort Definition ID to copy
* @return the copied cohort definition as a CohortDefinitionDTO
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{id}/copy")
@javax.transaction.Transactional
public IRAnalysisDTO copy(@PathParam("id") final int id) {
IRAnalysisDTO analysis = getAnalysis(id);
analysis.id = null; // clear the ID
analysis.name = "COPY OF: " + analysis.name;
IRAnalysisDTO copyStudy = createAnalysis(analysis);
return copyStudy;
}
/**
* Exports the analysis definition and results
*
* @param id - the IR Analysis ID to export
* @return Response containing binary stream of zipped data
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{id}/export")
@Transactional
public Response export(@PathParam("id") final int id) {
Response response = null;
HashMap<String, String> fileList = new HashMap<>();
HashMap<Integer, String> distTypeLookup = new HashMap<>();
distTypeLookup.put(1, "TAR");
distTypeLookup.put(2, "TTO");
try {
IncidenceRateAnalysis analysis = this.irAnalysisRepository.findOne(id);
Set<ExecutionInfo> executions = analysis.getExecutionInfoList();
fileList.put("analysisDefinition.json", analysis.getDetails().getExpression());
// squentially return reults of IR calculation. In Spring 1.4.2, we can utlilize @Async operations to do this in parallel.
// store results in single CSV file
ArrayList<String[]> summaryLines = new ArrayList<>();
ArrayList<String[]> strataLines = new ArrayList<>();
ArrayList<String[]> distLines = new ArrayList<>();
for (ExecutionInfo execution : executions)
{
Source source = execution.getSource();
String resultsTableQualifier = source.getTableQualifier(SourceDaimon.DaimonType.Results);
// perform this query to CDM in an isolated transaction to avoid expensive JDBC transaction synchronization
DefaultTransactionDefinition requresNewTx = new DefaultTransactionDefinition();
requresNewTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus initStatus = this.getTransactionTemplateRequiresNew().getTransactionManager().getTransaction(requresNewTx);
// get the summary data
List<AnalysisReport.Summary> summaryList = getAnalysisSummaryList(id, source);
if (summaryLines.isEmpty())
{
summaryLines.add("db_id#targetId#outcomeId#total#timeAtRisk#cases".split("#"));
}
for (AnalysisReport.Summary summary : summaryList)
{
summaryLines.add(new String[] {source.getSourceKey(),String.valueOf(summary.targetId), String.valueOf(summary.outcomeId), String.valueOf(summary.totalPersons), String.valueOf(summary.timeAtRisk), String.valueOf(summary.cases)});
}
// get the strata results
List<AnalysisReport.StrataStatistic> strataList = getStrataStatistics(id, source);
if (strataLines.isEmpty())
{
strataLines.add("db_id#targetId#outcomeId#strata_id#strata_name#total#timeAtRisk#cases".split("#"));
}
for (AnalysisReport.StrataStatistic strata : strataList)
{
strataLines.add(new String[] {source.getSourceKey(),String.valueOf(strata.targetId), String.valueOf(strata.outcomeId),String.valueOf(strata.id), String.valueOf(strata.name), String.valueOf(strata.totalPersons), String.valueOf(strata.timeAtRisk), String.valueOf(strata.cases)});
}
// get the distribution data
String distQuery = String.format("select '%s' as db_id, target_id, outcome_id, strata_sequence, dist_type, total, avg_value, std_dev, min_value, p10_value, p25_value, median_value, p75_value, p90_value, max_value from %s.ir_analysis_dist where analysis_id = %d", source.getSourceKey(), resultsTableQualifier, id);
String translatedSql = SqlTranslate.translateSql(distQuery, "sql server", source.getSourceDialect(), SessionUtils.sessionId(), resultsTableQualifier);
SqlRowSet rs = this.getSourceJdbcTemplate(source).queryForRowSet(translatedSql);
this.getTransactionTemplateRequiresNew().getTransactionManager().commit(initStatus);
if (distLines.isEmpty())
{
distLines.add(rs.getMetaData().getColumnNames());
}
while (rs.next())
{
ArrayList<String> columns = new ArrayList<>();
for(int i = 1; i <= rs.getMetaData().getColumnNames().length; i++)
{
switch (rs.getMetaData().getColumnName(i)) {
case "dist_type":
columns.add(distTypeLookup.get(rs.getInt(i)));
break;
default:
columns.add(rs.getString(i));
break;
}
}
distLines.add(columns.toArray(new String[0]));
}
}
// Write report lines to CSV
StringWriter sw = null;
CSVWriter csvWriter = null;
sw = new StringWriter();
csvWriter = new CSVWriter(sw);
csvWriter.writeAll(summaryLines);
csvWriter.flush();
fileList.put("ir_summary.csv", sw.getBuffer().toString());
sw = new StringWriter();
csvWriter = new CSVWriter(sw);
csvWriter.writeAll(strataLines);
csvWriter.flush();
fileList.put("ir_strata.csv", sw.getBuffer().toString());
sw = new StringWriter();
csvWriter = new CSVWriter(sw);
csvWriter.writeAll(distLines);
csvWriter.flush();
fileList.put("ir_dist.csv", sw.getBuffer().toString());
// build zip output
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
for(String fileName : fileList.keySet())
{
ZipEntry resultsEntry = new ZipEntry(fileName);
zos.putNextEntry(resultsEntry);
zos.write(fileList.get(fileName).getBytes());
}
zos.closeEntry();
zos.close();
baos.flush();
baos.close();
response = Response
.ok(baos)
.type(MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", String.format("attachment; filename=\"%s\"", "ir_analysis_" + id + ".zip"))
.build();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return response;
}
/**
* Deletes the specified cohort definition
*
* @param id - the Cohort Definition ID to copy
*/
@DELETE
@Produces(MediaType.APPLICATION_JSON)
@Path("/{id}")
public void delete(@PathParam("id") final int id) {
irAnalysisRepository.delete(id);
}
/**
* Deletes the specified cohort definition
*
* @param id - the Cohort Definition ID to copy
*/
@DELETE
@Produces(MediaType.APPLICATION_JSON)
@Path("/{id}/info/{sourceKey}")
@Transactional
public void deleteInfo(@PathParam("id") final int id, @PathParam("sourceKey") final String sourceKey) {
IncidenceRateAnalysis analysis = irAnalysisRepository.findOne(id);
ExecutionInfo itemToRemove = null;
for (ExecutionInfo info : analysis.getExecutionInfoList())
{
if (info.getSource().getSourceKey().equals(sourceKey))
itemToRemove = info;
}
if (itemToRemove != null)
analysis.getExecutionInfoList().remove(itemToRemove);
irAnalysisRepository.save(analysis);
}
}