/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package reportgen.ren.executer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import reportgen.prototype.QCoreInlineJava;
import reportgen.prototype.entity.QEntityProperty;
import reportgen.prototype.entity.QSQLProcessor;
import reportgen.prototype.inline.InlineCoreJavaList;
import reportgen.prototype.queryresults.ResultsRow;
import reportgen.prototype.queryresults.ResultsRowList;
import reportgen.ren.report.column.ReportResultColumn;
import reportgen.ren.report.items.CoresList;
import reportgen.ren.report.userinput.QueryInputValue;
import reportgen.ren.report.ReportQuery;
import reportgen.prototype.utils.ItemSelectorEditable;
import reportgen.utils.ReportException;
import reportgen.math.ResultColumn;
import reportgen.prototype.queryresults.QueryResults;
import reportgen.ren.report.userinput.UserInputSelect;
import reportgen.ren.report.userinput.UserInputChunk;
import reportgen.ren.report.userinput.UserInput;
import reportgen.prototype.stream.QQuery;
import reportgen.prototype.columns.QueryResultColumn;
import reportgen.math.complex.generic.MathExpressionGeneric;
import reportgen.prototype.QCore;
/**
* Инкапсулирует отчет.
* Используется при выполнении отчета, как объект
* - хранящий информацию об отчете (название, описание и сам отчет),
* - возвращающий информацию о требуемом вводе пользователя,
* - внедряющий выбор ползьзователя в отчет,
* - испольняющий отчет.
*
* @author axe
*/
public class QueryExecuter {
/**
* Идентификатор отчета.
*/
protected int id;
/**
* Ядро запроса
*/
protected ReportQuery report;
/**
* был ли сделан выбор пользователя. Выбор становится сделанным как только
* назначаются данные пользовательского ввода. Если обновляются результаты
* отчета, выбор становится несделанным
*/
private boolean userInputIsDone = false;
private String title;
private String description;
/**
* Конструктор, которым пользуется бин, при создании корня отчета
* @param id табельный номер отчета (0 - при апробации отчета)
* @param report ядро отчета
*/
public QueryExecuter(int id, ReportQuery report, String title, String description) {
this.id = id;
this.report = report;
this.title = title;
this.description = description;
}
/**
* Функция доступа к ядру подотчета
* Изменять возвращенное ядро нельзя.
* @return ядро подотчета
*/
public ReportQuery getQuery() {
return report;
}
/**
* Функция доступа к табельному номеру отчета
* @return табельный номер
*/
public int getId() {
return id;
}
/**
* Функция доступа к названию отчета
* @return название отчета
*/
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
/**
* Возвращает информацию о требуемом действии пользователя:
* набор опций отчета из которых пользователь должен что то выбрать или заполнить,
* который затем будет передан на сторону клиента, что бы тот сделал выбор
* @return null, если выбор пользователя уже был сделан
*/
public UserInputChunk getInputValue() throws ReportException {
if(userInputIsDone) {
return null;
}
UserInputChunk chunk = new UserInputChunk(id, title, description);
//Проверка входных параметров
ItemSelectorEditable<QueryInputValue> inputs = report.getInputs();
for(int i=0; i<inputs.size(); i++) {
QueryInputValue qiv = inputs.get(i);
if(!qiv.isConstant()) {
chunk.addUserInput(qiv.getUserInput());
}
}
//проверка подотчетов
ItemSelectorEditable<QueryExecuterSub> subreports = report.getSubReports();
for (int i=0; i<subreports.size(); i++) {
QueryExecuterSub subreport = subreports.get(i);
UserInputSelect val = subreport.getResultInputValue();
if(val != null) {
chunk.addUserInput(val);
}
}
if(chunk.getData().size() > 0) {
return chunk;
}
return null;
}
/**
* Назначает результаты выбора пользователя во входные данные отчета.
* @param input Сформированный на пользовательской стороне объект, хранящий
* информацию о выборе, который был сделан пользователем
* @throws reportgen.ren.exception.ReportException
*/
public void setUserInput(UserInputChunk input) throws ReportException {
//Проверка входных параметров, все они должн быть назначены
ItemSelectorEditable<QueryInputValue> it = report.getInputs();
for(int i=0; i<it.size(); i++) {
QueryInputValue qiv = it.get(i);
if(!qiv.isConstant()) {
UserInput ui = input.getUserInput(QueryInputValue.TAG + "@" + qiv.getSelectTitle());
if(ui == null) {
throw new ReportException("Отсутствует обязательный входной параметр: '"
+ qiv.getSelectTitle() + "'");
}
qiv.setUserInput(ui);
}
}
//проверка подотчетов
ItemSelectorEditable<QueryExecuterSub> subreports = report.getSubReports();
for(int i=0; i<subreports.size(); i++) {
QueryExecuterSub subreport = subreports.get(i);
UserInputSelect val = subreport.getResultInputValue();
if(val == null) {
//не требует результатов (константный отчет)
continue;
}
UserInput ui = input.getUserInput(subreport.getReportId() + "@" + val.getTitle());
if(ui == null) {
throw new ReportException("Отсутствует обязательный входной параметр: '" + val.getTitle() + "'");
} else if(ui instanceof UserInputSelect) {
subreport.setResultUserInput((UserInputSelect) ui);
} else {
throw new ReportException("Некорректная попытка изменения результата подотчета.");
}
}
userInputIsDone = true;
}
/**
* Выполняет отчет, последовательно выполняя его выборки и обрабатывая
* их результаты, которые впоследствии сольет в один результат.
* @param manager
* @return
* @throws reportgen.exception.ReportException
*/
public QueryResults execute(EntityManager manager) throws ReportException {
CoresList cores = report.getCores();
List<ResultsRowList> results = new ArrayList<ResultsRowList>();
//execute cores
for(int i=0; i<cores.size(); i++) {
QCore core = cores.get(i);
QSQLProcessor processor = core.getSQLProcessor();
Query sqlQuery = prepareSQL(manager, processor);
//prepare result set
List<ResultColumn> colProps = new ArrayList<ResultColumn>();
for(QueryResultColumn col:core.getColumns().getList()) {
colProps.add(col.getProperty());
}
ResultsRowList rrlist = new ResultsRowList(colProps, core.getPostConditions(), core.getRowCount());
//fill result set
for(Object row: sqlQuery.getResultList()) {
Map<QEntityProperty, Object> model = processor.analyze(row);
ResultsRow resultRow = buildResultsRow(manager, core, model);
rrlist.appendRow(resultRow);
}
System.out.println("<<<<<<<<<< CONTINUE 1 ANALYZE RESULTS >>>>>>>>>>>>>>");
rrlist.commit();
results.add(rrlist);
}
//prepare result list
List<ResultColumn> colsList = new ArrayList<ResultColumn>();
for(ReportResultColumn col :report.getColumns().getList()) {
colsList.add(col.getProperties());
}
ResultsRowList resultSet = new ResultsRowList(colsList, null, report.getRowCount());
//fill list
for(ResultsRowList result: results) {
for(ResultsRow row : result.getResultRows()) {
resultSet.appendRow(row);
}
}
resultSet.commit();
return resultSet.getResults();
}
private Query prepareSQL(EntityManager manager, QSQLProcessor processor) throws ReportException {
QQuery query = new QQuery();
processor.appendToQuery(query);
return prepareParams(manager, query);
}
private Query prepareParams(EntityManager manager, QQuery query) {
String sql = query.getSql();
System.out.println("== SQL: " + sql);
Query sqlQuery = manager.createQuery(sql);
Iterator it = query.getParams().iterator();
int paramIndex = 0;
while (it.hasNext()) {
sqlQuery.setParameter("param" + paramIndex, it.next());
paramIndex++;
}
return sqlQuery;
}
/**
*
* @param row
*/
private ResultsRow buildResultsRow(EntityManager manager, QCore core,
Map<QEntityProperty, Object> model) throws ReportException {
List<QueryResultColumn> colProps = core.getColumns().getList();
ResultsRow rr = new ResultsRow(colProps.size());
// для каждой колонки получаем значение
int i=0;
for(QueryResultColumn col: colProps) {
MathExpressionGeneric expession = col.getExpression();
rr.setValue(i, expession.getValue(model));
i++;
}
InlineCoreJavaList javacores = core.getResultInJavaList();
if(javacores != null) {
for(QCoreInlineJava jCore: javacores.getList()) {
}
}
return rr;
}
}