/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package framework.beans.reportgen.item;
import framework.audit.AuditDoc;
import framework.beans.EntityDetails;
import framework.beans.FacadeBean;
import framework.beans.directory.reportType.ReportType;
import framework.beans.reportgen.ReportEntitySetResource;
import framework.beans.security.BeanRights;
import framework.generic.ClipsServerException;
import framework.security.UserRightsSetAbstract;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.ejb.EJB;
import javax.ejb.Stateful;
import reportgen.prototype.queryresults.QueryResults;
import reportgen.ren.report.items.ResultColumnList;
import reportgen.prototype.utils.ItemSelectorEditable;
import reportgen.utils.ReportException;
import reportgen.ren.report.ReportQuery;
import reportgen.factory.ReportFactory;
import reportgen.ren.loader.SubQueryLoader;
import reportgen.ren.loader.SubQueryLoaderResult;
import reportgen.ren.executer.QueryExecuter;
import reportgen.ren.executer.QueryExecuterSub;
import reportgen.ren.executer.QueryResultsData;
import reportgen.prototype.Report;
import reportgen.ren.report.userinput.UserInputChunk;
/**
*
* @author petr
*/
@Stateful(mappedName="clips-beans/ReportQueryBean")
public class ReportQueryBean
extends FacadeBean<ReportgenQuery>
implements ReportQueryRemote, SubQueryLoader {
public static int COMMAND_SET_COLLAB = 4;
@EJB
ReportEntitySetResource resource;
private QueryExecuter rootQuery;
public ReportQueryBean() {
super(ReportgenQuery.class);
}
@Override
protected void initBeanRights() throws ClipsServerException {
resource.init();
int[] r = new int[5];
r[COMMAND_READ] = RightPresence(UserRightsSetAbstract.EXECUTE_REPORT.id);
r[COMMAND_MODIFY] = r[COMMAND_CREATE] = RightPresence(UserRightsSetAbstract.WRITE_REGION_ADMIN_DIRECTORY.id);
r[COMMAND_REMOVE] = RightPresence(UserRightsSetAbstract.WRITE_REGION_ADMIN_DIRECTORY.id);
r[COMMAND_SET_COLLAB] = RightPresence(UserRightsSetAbstract.WRITE_CLINIC_ADMIN_DIRECTORY.id);
rights = new BeanRights(r);
}
/**
* additionally checks, that in new edition of this reports, columns used in
* another reports was not removed
* @param entity
* @param details
* @throws framework.generic.ClipsServerException
*/
@Override
protected void onUpdate(ReportgenQuery entity,
EntityDetails details, AuditDoc auditDoc, List<AuditDoc> auditDocList) throws ClipsServerException {
QueryDetails d = (QueryDetails) details;
if(d.query == null || d.query.length() == 0) {
throw new ClipsServerException("Попытка сохранения пустого отчета");
}
if(d.title == null || d.title.length() > 255 || d.title.length() < 10) {
throw new ClipsServerException("Название должно быть от 10 до 255 символов в длину");
}
if(d.description != null && d.description.length() > 1024) {
throw new ClipsServerException("Описание должно быть не более 1024 символов в длину");
}
if (d.reportType == 0) {
throw new ClipsServerException("Отчет не привязан ни к какой группе");
}
// check report
Report report = null;
try {
report = ReportFactory.fromString(entity.getId(), d.query, this);
} catch (ReportException ex) {
throw new ClipsServerException("Попытка сохранения некорректного отчета", ex);
}
HashSet<String> newCols = new HashSet<String>();
ResultColumnList newColsSelector = report.getColumns();
for(int i=0; i<newColsSelector.size(); i++) {
newCols.add(newColsSelector.get(i).getTitle());
}
//check super reports
Field[] f = new Field[]{new Field("id", entity.getId(), Field.OPERATOR_NOT_EQUAL)};
Iterator iterator = findEntityList(ReportgenQuery.class, f).iterator();
while (iterator.hasNext()) {
ReportgenQuery superReportQuery = (ReportgenQuery) iterator.next();
ReportQuery superReport = null;
try {
superReport = ReportFactory.fromString(superReportQuery.getId(),
superReportQuery.getQuery(), this);
} catch (ReportException ex) {
//do nothing
}
if(superReport == null) {
continue;
}
Iterator<String> usedSubreportColumns = superReport.getUsedSubreportColumns(entity.getId()).iterator();
while(usedSubreportColumns.hasNext()) {
String col = usedSubreportColumns.next();
if(!newCols.contains(col)) {
throw new ClipsServerException("Отчет '" + superReportQuery.getTitle()
+ "' использует столбец данного отчета с именем '" + col
+ "', который в новой редакции отсутствует.");
}
}
}
entity.setReportType(findEntity(ReportType.class, d.reportType));
entity.setSubsidiary(d.subsidiary);
entity.setQuery(d.query);
entity.setTitle(d.title);
entity.setDescription(d.description);
}
/**
* checks all another reports in fact of using removing one
* @param entity
* @throws framework.generic.ClipsServerException
*/
@Override
protected void onRemove(ReportgenQuery entity,
List<AuditDoc> audit) throws ClipsServerException {
//check all other reports in fack of using removing one
Field[] f = new Field[]{new Field("id", entity.getId(), Field.OPERATOR_NOT_EQUAL)};
Iterator iterator = findEntityList(ReportgenQuery.class, f).iterator();
while (iterator.hasNext()) {
ReportgenQuery superReportQuery = (ReportgenQuery) iterator.next();
ReportQuery superReport = null;
try {
superReport = ReportFactory.fromString(superReportQuery.getId(),
superReportQuery.getQuery(), this);
} catch (ReportException ex) {
continue;
}
ItemSelectorEditable<QueryExecuterSub> usedSubreports = superReport.getSubReports();
for(int i=0; i<usedSubreports.size(); i++) {
QueryExecuterSub col = usedSubreports.get(i);
if(col.getReportId() == entity.getId()) {
throw new ClipsServerException("Отчет '" + col.getReportTitle()
+ "' не может быть удален, поскольку его использует отчет '"
+ superReportQuery.getTitle() + "'");
}
}
}
//delete related objects
deleteEntityList(ReportCollab.class, new Field [] { new Field("report", entity) });
deleteEntityList(ReportQueryExecution.class, new Field [] { new Field("report", entity) });
}
@Override
public List<QueryExecutionDetails> getExecutionDetails() throws ClipsServerException {
checkCommandAccessibility(COMMAND_READ);
List<ReportQueryExecution> list = findEntityList(ReportQueryExecution.class, "report", getExistentEntity());
List<QueryExecutionDetails> res = new ArrayList<QueryExecutionDetails>(list.size());
Iterator<ReportQueryExecution> it = list.iterator();
while(it.hasNext()) {
ReportQueryExecution data = it.next();
res.add(data.getDetails());
}
return res;
}
/**
* Возвращает сет ид коллабов, которым разрешено выполнять данный отчет
* @param report ид отчета
* @return
* @throws framework.generic.ClipsServerException
*/
@Override
public Set<Integer> getCollabs() throws ClipsServerException {
//checkCommandAccessibility(COMMAND_MODIFY);
int report = getExistentEntity().getId();
Iterator list = findEntityList(ReportCollab.class, "key.report", report).iterator();
Set<Integer> res = new HashSet<Integer>();
while(list.hasNext()) {
ReportCollab reportCollab = (ReportCollab)list.next();
res.add(reportCollab.getKey().getCollab());
}
return res;
}
/**
* Назначает отчету сет ид коллабов, которым разрешено выполнять данный отчет
* @param report ид репорта
* @param collabs сет ид коллабов
* @throws framework.generic.ClipsServerException
*/
@Override
public void setCollabs(Set<Integer> collabs) throws ClipsServerException {
checkCommandAccessibility(COMMAND_SET_COLLAB);
int report = getExistentEntity().getId();
Set<Integer> backup = new HashSet<Integer>(collabs);
Set<Integer> oldCollabs = getCollabs();
collabs.removeAll(oldCollabs);
oldCollabs.removeAll(backup);
if(oldCollabs.size() > 0) {
@SuppressWarnings("unchecked")
Field f[] = {
new Field("key.report", report),
new Field("key.collab", oldCollabs, Field.OPERATOR_IN)
};
deleteEntityList(ReportCollab.class, f);
}
Iterator<Integer> addNew = collabs.iterator();
while(addNew.hasNext()) {
ReportCollab r = new ReportCollab();
r.setKey(new ReportCollabPK(report, addNew.next()));
System.out.println("Added new:" + r);
manager.persist(r);
}
}
private boolean canCollabToDo(int collabID) throws ClipsServerException {
return getCollabs().contains(collabID);
}
@Override
public Object doReport(String reportXML) throws ClipsServerException {
checkCommandAccessibility(COMMAND_CREATE);
Object rr = null;
try {
System.out.println("TESTING XML:\n" + reportXML);
ReportQuery report = ReportFactory.fromString(0, reportXML, this);
rootQuery = new QueryExecuter(0, report, "Тестовый отчет", "");
rr = executeQuery(rootQuery);
} catch (Exception reportException) {
throw new ClipsServerException("При обработке отчета произошла ошибка", reportException);
}
return rr;
}
@Override
public Object doReport(int id) throws ClipsServerException {
if(!canCollabToDo(getCollaboratorId())) {
checkCommandAccessibility(COMMAND_READ);
}
ReportgenQuery query = findEntity(ReportgenQuery.class, id);
try {
ReportQuery report = ReportFactory.fromString(id, query.getQuery(), this);
rootQuery = new QueryExecuter(id, report, query.getTitle(), query.getDescription());
return executeQuery(rootQuery);
} catch (Exception reportException) {
throw new ClipsServerException("При обработке отчета произошла ошибка", reportException);
}
}
@Override
public Object continueReport(UserInputChunk input) throws ClipsServerException {
if(!canCollabToDo(getCollaboratorId())) {
checkCommandAccessibility(COMMAND_READ);
}
if(rootQuery == null) {
throw new ClipsServerException("Некорректная попытка продолжить выполнение отчета");
}
try {
if(input != null) {
setInput(rootQuery, input);
}
return executeQuery(rootQuery);
} catch (ReportException reportException) {
throw new ClipsServerException("При обработке отчета произошла ошибка", reportException);
}
}
/**
* Выполняет первый по приоритету, нуждающийся в выполнении
* @param parentQuery
* @return
* @throws reportgen.ren.ReportException
*/
private Object executeQuery(QueryExecuter query)
throws ReportException {
//проверим, что все подотчеты рассчитаны
ItemSelectorEditable<QueryExecuterSub> subreports = query.getQuery().getSubReports();
for(int i=0; i<subreports.size(); i++) {
QueryExecuterSub subquery = subreports.get(i);
if(subquery.isConstant() || subquery.isResultsIsSet()) {
//не трогать отчет, который является константой или уже рассчитан
continue;
}
//РЕКУРСИВНО рассчитываем подотчет
Object result = executeQuery(subquery.getReport());
if(result instanceof QueryResults) {
QueryResults queryResults = (QueryResults) result;
subquery.setResults(queryResults);
result = new QueryResultsData(query.getId(), subquery, queryResults);
}
//либо подотчет рассчитан, и вернем данные об этом клиенту
// либо требуется пользовательский ввод
return result;
}
//все подотчет рассчитаны, build input data if user selection need
UserInputChunk inputNeed = query.getInputValue();
if(inputNeed != null) {
return inputNeed;
}
//now ready for executing - execute
return query.execute(manager);
}
/**
* Назначает входное значение одному из отчетов. Данный отчет и все
* отчеты следующие по приоритету подвергаются очистке результатов.
* @param query
* @param input
* @return
* @throws ReportException
*/
private boolean setInput(QueryExecuter query, UserInputChunk input)
throws ReportException {
boolean inputUsed = (input == null);
if(input != null && input.getId() == query.getId()) {
query.setUserInput(input);
return true;
}
ItemSelectorEditable<QueryExecuterSub> subreports = query.getQuery().getSubReports();
for(int i=0; i<subreports.size(); i++) {
QueryExecuterSub subquery = subreports.get(i);
if(subquery.isConstant()) {
//не трогать отчет, который является константой
continue;
}
if(!inputUsed) {
inputUsed = setInput(subquery.getReport(), input);
} else {
// для всех последующих отчетов, кроме данного, корректровать
// ввод пользователя не обязательно
// (флаг корректируется при назначении результатов отчета)
//subquery.getReport().setUserInputIsDone(false);
}
if(inputUsed) {
//для всех последующих отчетов, включая данный, очищаем результаты расчета
subquery.clearResults();
}
}
return inputUsed;
}
/**
* Возвращает подотчет.
* Используется сервером. проверка прав не требуется.
* @param id
* @return
* @throws reportgen.ren.ReportException
*/
@Override
public SubQueryLoaderResult loadSubReport(int id) throws ReportException {
ReportgenQuery query = manager.find(ReportgenQuery.class, id);
if(query == null) {
throw new ReportException("Запроса с номером " + id + " не существует!");
}
SubQueryLoaderResult res = new SubQueryLoaderResult();
res.title = query.getTitle();
res.description = query.getDescription();
res.report = ReportFactory.fromString(id, query.getQuery(), this);
return res;
}
}