/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package reportgen.ren.report;
import reportgen.prototype.Report;
import reportgen.prototype.context.Context;
import reportgen.prototype.context.ContextMode;
import reportgen.prototype.columns.CoreColumnList;
import reportgen.prototype.columns.QueryResultColumn;
import reportgen.ren.executer.SubReportColumn;
import reportgen.ren.report.column.ReportResultColumn;
import reportgen.prototype.utils.RowCount;
import reportgen.ren.report.items.InputList;
import reportgen.ren.report.items.SubReportList;
import reportgen.ren.executer.QueryExecuterSub;
import reportgen.utils.ReportException;
import reportgen.math.reference.subreport.MathExpressionSubReportColumnRef;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.jdom.Element;
import reportgen.factory.ReportFactory;
import reportgen.factory.ReportVersion;
import reportgen.prototype.context.ContextCompound;
import reportgen.prototype.context.ContextConst;
import reportgen.prototype.context.AtomRegistrar;
import reportgen.prototype.context.NoNeedAtom;
import reportgen.prototype.CoreFactoryList;
import reportgen.prototype.QCore;
import reportgen.prototype.UsedReportableType;
import reportgen.ren.report.extendedformat.TableFormatList;
import reportgen.ren.report.items.CoresList;
import reportgen.ren.report.items.ResultColumnList;
import reportgen.ren.loader.SubQueryLoader;
import reportgen.utils.Atom;
import reportgen.utils.SupportXMLRootImpl;
/**
* Объект - запрос
* содержит:
* - ссылку на корневой обект сущность
* - список всех условий выборки
* - список всех полей выборки
* @author axe
*/
public class ReportQuery extends SupportXMLRootImpl implements Report{
public final static String ROOTTAG = "report";
public final static String CORES = "core";
private final ReportVersion version;
private RowCount rowCount;
private final CoresList cores;
private final InputList inputs;
private final SubReportList subReports;
private final ResultColumnList results;
private final TableFormatList tableFormats;
/**
*
*/
public ReportQuery() throws ReportException {
this.results = new ResultColumnList(this);
this.inputs = new InputList(this);
this.subReports = new SubReportList(this);
this.tableFormats = new TableFormatList();
this.rowCount = new RowCount();
this.version = ReportFactory.getActualVersion();
this.cores = new CoresList(this);
CoreFactoryList factory = new CoreFactoryList();
QCore core = factory.createDefaultCore(getReportContext(new NoNeedAtom()));
this.cores.add(core);
}
/**
*
* @param rpt
* @return
* @throws reportgen.ren.ReportException
*/
public ReportQuery(Element root, final SubQueryLoader sl) throws ReportException {
version = new ReportVersion(root);
rowCount = new RowCount(root);
final Set<Atom> atoms = new HashSet<Atom>();
AtomRegistrar ar = new AtomRegistrar() {
@Override
final public void registerAtom(Atom atom) {
assert !atoms.contains(atom) : " Atom value doubled: " + atom;
atoms.add(atom);
}
};
Context constContext = new ContextConst(ar) {
@Override
public ContextMode getContextMode() {
return ContextMode.INPUT;
}
};
inputs = new InputList(this, root, constContext);
Context subReportContext = new ContextCompound(constContext) {
@Override
public SubQueryLoader getQueryLoader() {
return sl;
}
};
subReports = new SubReportList(this, root, subReportContext);
cores = new CoresList(this, root, getReportContext(ar));
results = new ResultColumnList(this, root, getUnionContext(ar));
tableFormats = new TableFormatList(root, getContext3Stage(ar));
for(Atom atom:atoms) {
atom.refresh();
}
}
@Override
protected String getRootTag() {
return ROOTTAG;
}
/**
*
* @return
*/
@Override
protected void toXML(Element root) {
version.toXML(root);
rowCount.toXML(root);
//subreports
Element subreportsEl = subReports.toXML();
if(subreportsEl != null) {
root.addContent(subreportsEl);
}
//inputs
Element inputsEl = inputs.toXML();
if(inputsEl != null) {
root.addContent(inputsEl);
}
//cores
Element coresEl = cores.toXML();
if(coresEl != null) {
root.addContent(coresEl);
}
//results
Element resultsEl = results.toXML();
if(resultsEl != null) {
root.addContent(resultsEl);
}
//table formats
Element tableFromatsEl = tableFormats.toXML();
if(tableFromatsEl != null) {
root.addContent(tableFromatsEl);
}
}
/**
*
* @return
*/
@Override
public ResultColumnList getColumns() {
return results;
}
/**
*
* @return
*/
public TableFormatList getTableFormats() {
return tableFormats;
}
/**
*
* @return
*/
@Override
public RowCount getRowCount() {
return rowCount;
}
/**
*
* @param rows
*/
@Override
public void setRowCount(RowCount rows) {
rowCount = rows;
}
/**
*
* @return
*/
public SubReportList getSubReports() {
return subReports;
}
/**
*
* @return
*/
@Override
public InputList getInputs() {
return inputs;
}
@Override
public CoresList getCores() {
return cores;
}
/**
* Возвращает названия столбцов указанного подотчета, которые были использованы
* в данном отчете
* @param subReportId - идентификатор подотчета
* @return
*/
public Set<String> getUsedSubreportColumns(int subReportId) {
Set<String> used = new HashSet<String>();
//search for specified subreport
QueryExecuterSub subreport = null;
for(int i=0; i<subReports.size(); i++) {
QueryExecuterSub sr = subReports.get(i);
if(sr.getReportId() == subReportId) {
subreport = sr;
break;
}
}
//if found, mark selectable column as used
if(subreport == null) {
return used;
} else {
used.add(subreport.getColTitle(subreport.getSelectColumn()));
}
//get all subreport columns
Set set = new HashSet();
for(int i=0; i<cores.size(); i++) {
QCore core = cores.get(i);
core.buildUsedSet(UsedReportableType.subreport_column, set);
}
//check every subreport column, is it in specified subreport or not, and
//if it does, mark it as used
Iterator it = set.iterator();
while(it.hasNext()) {
MathExpressionSubReportColumnRef col = (MathExpressionSubReportColumnRef) it.next();
SubReportColumn val = col.getValue();
if(val.getReport().getReportId() == subReportId) {
used.add(val.getColumnTitle());
}
}
return used;
}
/**
*
* @throws reportgen.ren.exception.ReportException
*/
@Override
public void validate() throws ReportException {
cores.validate();
results.validate();
inputs.validate();
subReports.validate();
tableFormats.validate();
//проверка, что результаты всех выборок соответствуют результатам отчета
for(int i=0; i<cores.size(); i++) {
QCore core = cores.get(i);
CoreColumnList coreColumns = core.getColumns();
if(coreColumns.size() != results.size()) {
throw new ReportException("Результаты выборки '" + core.getTitle()
+ "' не соответствуют результатам отчета");
}
for(int j=0; j<coreColumns.size(); j++) {
QueryResultColumn coreCol = coreColumns.get(j);
ReportResultColumn resultCol = results.get(j);
Class coreCls = coreCol.getCls();
Class resCls = resultCol.getCls();
if(resCls == null) {
throw new ReportException("Результаты выборки '" + coreCol.getColTitle()
+ "' не может быть равен null");
} else if (coreCls != null && !coreCls.equals(resCls)) {
throw new ReportException("Результаты выборки '" + coreCol.getColTitle()
+ "' не соответствует результату отчета по типу ("
+ coreCol.getCls().getSimpleName() + " != "
+ resultCol.getCls().getSimpleName() + ")");
}
}
}
}
@Override
public void ensureSafeRemove(Object obj2remove) throws ReportException {
for(int i=0; i<cores.size(); i++) {
QCore core = cores.get(i);
core.ensureSafeRemove(obj2remove);
}
if (results.isContain(obj2remove)) {
throw new ReportException("Нельзя удалить этот элемент, ссылка на него содержится в "
+ "результатах отчета");
}
if (tableFormats.isContain(obj2remove)) {
throw new ReportException("Нельзя удалить этот элемент, ссылка на нее содержится в "
+ "форматировании результатов");
}
}
/**
* Возвращает контекст который должен использоваться при построении
* выборки отчета
* @param ctx
* @return
*/
public Context getReportContext(AtomRegistrar ctx) {
return new ReportExpressionContext(ctx, this);
}
/**
* Возвращает контекст который должен использоваться при построении
* результатов отчета
* @param ctx
* @return
*/
public Context getUnionContext(AtomRegistrar ctx) {
return new UnionExpressionContext(ctx, this);
}
/**
* Возвращает контекст который должен использоваться при построении
* форматирующих таблиц
* @param ctx
* @return
*/
public Context getContext3Stage(AtomRegistrar ctx) {
return new ReportExpressionContext3Stage(this, getReportContext(ctx));
}
}