2017-03-20 19:27:59 +01:00
|
|
|
package li.strolch.report;
|
|
|
|
|
2017-03-21 07:51:13 +01:00
|
|
|
import static li.strolch.utils.helper.StringHelper.DASH;
|
|
|
|
|
2017-03-21 15:34:10 +01:00
|
|
|
import java.util.Date;
|
2017-03-20 19:27:59 +01:00
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
2017-03-24 11:25:56 +01:00
|
|
|
import java.util.Set;
|
2017-03-21 08:23:29 +01:00
|
|
|
import java.util.stream.Collector;
|
2017-03-20 19:27:59 +01:00
|
|
|
import java.util.stream.Collectors;
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
|
|
import com.google.gson.JsonObject;
|
|
|
|
|
2017-05-03 15:32:20 +02:00
|
|
|
import li.strolch.agent.api.ComponentContainer;
|
2017-03-20 19:27:59 +01:00
|
|
|
import li.strolch.model.Locator;
|
|
|
|
import li.strolch.model.ParameterBag;
|
|
|
|
import li.strolch.model.Resource;
|
|
|
|
import li.strolch.model.StrolchRootElement;
|
2017-03-21 15:34:10 +01:00
|
|
|
import li.strolch.model.StrolchValueType;
|
2017-05-03 16:06:56 +02:00
|
|
|
import li.strolch.model.parameter.BooleanParameter;
|
2017-03-21 15:34:10 +01:00
|
|
|
import li.strolch.model.parameter.DateParameter;
|
2017-03-20 19:27:59 +01:00
|
|
|
import li.strolch.model.parameter.Parameter;
|
|
|
|
import li.strolch.model.parameter.StringParameter;
|
2017-05-03 15:32:20 +02:00
|
|
|
import li.strolch.model.policy.PolicyDef;
|
2017-03-21 15:34:10 +01:00
|
|
|
import li.strolch.model.visitor.ElementDateVisitor;
|
|
|
|
import li.strolch.model.visitor.ElementStateVisitor;
|
2017-03-20 19:27:59 +01:00
|
|
|
import li.strolch.persistence.api.StrolchTransaction;
|
2017-05-03 15:32:20 +02:00
|
|
|
import li.strolch.policy.PolicyHandler;
|
|
|
|
import li.strolch.report.policy.ReportFilterPolicy;
|
2017-03-20 19:27:59 +01:00
|
|
|
import li.strolch.runtime.StrolchConstants;
|
2017-03-21 15:34:10 +01:00
|
|
|
import li.strolch.utils.collections.DateRange;
|
2017-03-21 07:51:13 +01:00
|
|
|
import li.strolch.utils.collections.MapOfSets;
|
2017-03-21 15:34:10 +01:00
|
|
|
import li.strolch.utils.iso8601.ISO8601FormatFactory;
|
2017-03-20 19:27:59 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
|
|
|
*/
|
|
|
|
public class GenericReport {
|
|
|
|
|
2017-03-21 15:34:10 +01:00
|
|
|
private static final String TYPE_REPORT = "Report";
|
2017-05-03 15:32:20 +02:00
|
|
|
private static final String TYPE_FILTER = "Filter";
|
2017-03-21 15:34:10 +01:00
|
|
|
|
2017-03-20 19:27:59 +01:00
|
|
|
private static final String BAG_RELATIONS = "relations";
|
|
|
|
private static final String BAG_JOINS = "joins";
|
|
|
|
private static final String BAG_PARAMETERS = "parameters";
|
|
|
|
private static final String BAG_COLUMNS = "columns";
|
2017-06-27 08:45:26 +02:00
|
|
|
private static final String BAG_ORDERING = "ordering";
|
2017-03-21 15:34:10 +01:00
|
|
|
|
|
|
|
private static final String PARAM_OBJECT_TYPE = "objectType";
|
2017-05-03 16:06:56 +02:00
|
|
|
private static final String PARAM_HIDE_OBJECT_TYPE_FROM_FILTER_CRITERIA = "hideObjectTypeFromFilterCriteria";
|
2017-06-27 08:45:26 +02:00
|
|
|
private static final String PARAM_DESCENDING = "descending";
|
2017-03-21 15:34:10 +01:00
|
|
|
private static final String PARAM_DATE_RANGE_SEL = "dateRangeSel";
|
2017-05-03 15:32:20 +02:00
|
|
|
private static final String PARAM_FIELD_REF = "fieldRef";
|
|
|
|
private static final String PARAM_POLICY = "policy";
|
2017-03-21 15:34:10 +01:00
|
|
|
|
|
|
|
private static final String COL_ID = "$id";
|
|
|
|
private static final String COL_NAME = "$name";
|
|
|
|
private static final String COL_TYPE = "$type";
|
|
|
|
private static final String COL_STATE = "$state";
|
|
|
|
private static final String COL_DATE = "$date";
|
2017-03-22 14:55:54 +01:00
|
|
|
private static final String COL_SEARCH = "$search";
|
|
|
|
|
|
|
|
private static final String SEARCH_SEPARATOR = ":";
|
2017-03-21 15:34:10 +01:00
|
|
|
|
|
|
|
private static final String SUFFIX_REF = "-Ref";
|
2017-03-21 07:51:13 +01:00
|
|
|
|
2017-03-20 19:27:59 +01:00
|
|
|
// input
|
|
|
|
private StrolchTransaction tx;
|
|
|
|
private String reportId;
|
|
|
|
|
|
|
|
private Resource report;
|
2017-05-03 16:06:56 +02:00
|
|
|
private StringParameter objectTypeP;
|
|
|
|
private boolean hideObjectTypeFromFilterCriteria;
|
2017-03-20 19:27:59 +01:00
|
|
|
private ParameterBag columnsBag;
|
2017-06-27 08:45:26 +02:00
|
|
|
private List<StringParameter> orderingParams;
|
|
|
|
private boolean descending;
|
2017-09-13 15:28:40 +02:00
|
|
|
private List<String> columnIds;
|
2017-03-21 15:34:10 +01:00
|
|
|
private StringParameter dateRangeSelP;
|
|
|
|
|
|
|
|
private DateRange dateRange;
|
2017-05-03 15:32:20 +02:00
|
|
|
private Map<ReportFilterPolicy, StringParameter> filtersByPolicy;
|
|
|
|
private MapOfSets<String, String> filtersById;
|
2017-03-20 19:27:59 +01:00
|
|
|
|
2017-05-03 15:32:20 +02:00
|
|
|
public GenericReport(ComponentContainer container, StrolchTransaction tx, String reportId) {
|
2017-03-20 19:27:59 +01:00
|
|
|
this.tx = tx;
|
|
|
|
this.reportId = reportId;
|
2017-03-27 14:39:03 +02:00
|
|
|
|
|
|
|
// get the report
|
|
|
|
this.report = this.tx.getResourceBy(TYPE_REPORT, this.reportId, true);
|
2017-05-03 15:32:20 +02:00
|
|
|
|
|
|
|
// prepare
|
2017-05-03 16:06:56 +02:00
|
|
|
this.objectTypeP = this.report.getParameter(BAG_PARAMETERS, PARAM_OBJECT_TYPE);
|
|
|
|
|
|
|
|
BooleanParameter hideObjectTypeFromFilterCriteriaP = this.report.getParameter(BAG_PARAMETERS,
|
|
|
|
PARAM_HIDE_OBJECT_TYPE_FROM_FILTER_CRITERIA);
|
|
|
|
this.hideObjectTypeFromFilterCriteria = hideObjectTypeFromFilterCriteriaP != null
|
|
|
|
&& hideObjectTypeFromFilterCriteriaP.getValue();
|
2017-03-27 14:39:03 +02:00
|
|
|
this.columnsBag = this.report.getParameterBag(BAG_COLUMNS, true);
|
2017-09-13 15:28:40 +02:00
|
|
|
|
|
|
|
this.columnIds = this.columnsBag.getParameters().stream() //
|
|
|
|
.sorted((p1, p2) -> Integer.compare(p1.getIndex(), p2.getIndex())) //
|
|
|
|
.map(p -> p.getId()) //
|
|
|
|
.collect(Collectors.toList());
|
2017-06-27 08:45:26 +02:00
|
|
|
|
|
|
|
if (this.report.hasParameter(BAG_PARAMETERS, PARAM_DESCENDING))
|
|
|
|
this.descending = this.report.getParameter(BAG_PARAMETERS, PARAM_DESCENDING).getValue();
|
|
|
|
|
2017-03-27 14:39:03 +02:00
|
|
|
this.dateRangeSelP = this.report.getParameter(BAG_PARAMETERS, PARAM_DATE_RANGE_SEL);
|
2017-05-03 15:32:20 +02:00
|
|
|
|
2017-06-27 08:45:26 +02:00
|
|
|
// evaluate ordering params
|
|
|
|
if (this.report.hasParameterBag(BAG_ORDERING)) {
|
|
|
|
ParameterBag orderingBag = this.report.getParameterBag(BAG_ORDERING);
|
|
|
|
if (orderingBag.hasParameters()) {
|
|
|
|
this.orderingParams = orderingBag.getParameters().stream().map(e -> (StringParameter) e)
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
this.orderingParams.sort((c1, c2) -> Integer.compare(c1.getIndex(), c2.getIndex()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-03 15:32:20 +02:00
|
|
|
// evaluate filters
|
|
|
|
this.filtersByPolicy = new HashMap<>();
|
|
|
|
List<ParameterBag> filterBags = this.report.getParameterBagsByType(TYPE_FILTER);
|
|
|
|
for (ParameterBag filterBag : filterBags) {
|
|
|
|
|
|
|
|
// prepare filter function policy
|
|
|
|
StringParameter functionP = filterBag.getParameter(PARAM_POLICY);
|
|
|
|
PolicyHandler policyHandler = container.getComponent(PolicyHandler.class);
|
|
|
|
PolicyDef policyDef = PolicyDef.valueOf(functionP.getInterpretation(), functionP.getUom());
|
|
|
|
ReportFilterPolicy filterFunction = policyHandler.getPolicy(policyDef, tx);
|
|
|
|
filterFunction.init(functionP.getValue());
|
|
|
|
|
|
|
|
StringParameter fieldRefP = filterBag.getParameter(PARAM_FIELD_REF);
|
|
|
|
this.filtersByPolicy.put(filterFunction, fieldRefP);
|
|
|
|
}
|
2017-03-21 15:34:10 +01:00
|
|
|
}
|
|
|
|
|
2017-04-13 14:41:07 +02:00
|
|
|
public boolean hasDateRangeSelector() {
|
|
|
|
return this.dateRangeSelP != null;
|
|
|
|
}
|
|
|
|
|
2017-03-21 15:34:10 +01:00
|
|
|
public GenericReport dateRange(DateRange dateRange) {
|
|
|
|
this.dateRange = dateRange;
|
|
|
|
return this;
|
2017-03-21 07:51:13 +01:00
|
|
|
}
|
|
|
|
|
2017-09-13 15:28:40 +02:00
|
|
|
public List<String> getColumnKeys() {
|
|
|
|
return this.columnIds;
|
2017-03-27 11:51:53 +02:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:51:13 +01:00
|
|
|
public GenericReport filter(String type, String... ids) {
|
2017-05-03 15:32:20 +02:00
|
|
|
if (this.filtersById == null)
|
|
|
|
this.filtersById = new MapOfSets<>();
|
2017-03-21 07:51:13 +01:00
|
|
|
for (String id : ids) {
|
2017-05-03 15:32:20 +02:00
|
|
|
this.filtersById.addElement(type, id);
|
2017-03-21 07:51:13 +01:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public GenericReport filter(String type, List<String> ids) {
|
2017-05-03 15:32:20 +02:00
|
|
|
if (this.filtersById == null)
|
|
|
|
this.filtersById = new MapOfSets<>();
|
2017-03-21 07:51:13 +01:00
|
|
|
for (String id : ids) {
|
2017-05-03 15:32:20 +02:00
|
|
|
this.filtersById.addElement(type, id);
|
2017-03-21 07:51:13 +01:00
|
|
|
}
|
|
|
|
return this;
|
2017-03-20 19:27:59 +01:00
|
|
|
}
|
|
|
|
|
2017-03-24 11:25:56 +01:00
|
|
|
public GenericReport filter(String type, Set<String> ids) {
|
2017-05-03 15:32:20 +02:00
|
|
|
if (this.filtersById == null)
|
|
|
|
this.filtersById = new MapOfSets<>();
|
2017-03-24 11:25:56 +01:00
|
|
|
for (String id : ids) {
|
2017-05-03 15:32:20 +02:00
|
|
|
this.filtersById.addElement(type, id);
|
2017-03-24 11:25:56 +01:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2017-03-21 08:23:29 +01:00
|
|
|
public Stream<Map<String, StrolchRootElement>> buildStream() {
|
2017-03-20 19:27:59 +01:00
|
|
|
|
|
|
|
// query the main objects and return a stream
|
2017-06-27 08:45:26 +02:00
|
|
|
Stream<Map<String, StrolchRootElement>> stream = queryRows().map(e -> evaluateRow(e));
|
|
|
|
|
|
|
|
if (hasFilter())
|
|
|
|
stream = stream.filter(e -> filter(e));
|
|
|
|
|
|
|
|
if (hasOrdering())
|
|
|
|
stream = stream.sorted((e1, e2) -> sort(e1, e2));
|
|
|
|
|
|
|
|
return stream;
|
2017-03-21 07:51:13 +01:00
|
|
|
}
|
|
|
|
|
2017-03-27 11:51:53 +02:00
|
|
|
public Stream<ReportElement> doReport() {
|
|
|
|
|
2017-03-27 14:04:39 +02:00
|
|
|
return buildStream().map(e -> new ReportElement(this.columnIds, columnId -> {
|
2017-05-04 20:45:44 +02:00
|
|
|
StringParameter columnDefP = this.columnsBag.getParameter(columnId, true);
|
2017-03-27 11:51:53 +02:00
|
|
|
return evaluateColumnValue(columnDefP, e);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2017-03-21 15:34:10 +01:00
|
|
|
public MapOfSets<String, StrolchRootElement> generateFilterCriteria() {
|
2017-03-21 08:23:29 +01:00
|
|
|
return buildStream() //
|
2017-05-03 16:06:56 +02:00
|
|
|
.flatMap(e -> {
|
|
|
|
Stream<StrolchRootElement> stream = e.values().stream();
|
|
|
|
if (this.hideObjectTypeFromFilterCriteria) {
|
|
|
|
stream = stream.filter(element -> !element.getType().equals(this.objectTypeP.getValue()));
|
|
|
|
}
|
|
|
|
return stream;
|
|
|
|
}) //
|
2017-03-21 08:23:29 +01:00
|
|
|
.collect( //
|
|
|
|
Collector.of( //
|
2017-03-21 15:34:10 +01:00
|
|
|
() -> new MapOfSets<String, StrolchRootElement>(), //
|
|
|
|
(m, e) -> m.addElement(e.getType(), e), //
|
2017-03-27 11:51:53 +02:00
|
|
|
(m1, m2) -> m1.addAll(m2), //
|
2017-03-21 08:23:29 +01:00
|
|
|
m -> m));
|
|
|
|
}
|
|
|
|
|
2017-06-27 08:45:26 +02:00
|
|
|
private boolean hasOrdering() {
|
|
|
|
return this.orderingParams != null && !this.orderingParams.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
private int sort(Map<String, StrolchRootElement> row1, Map<String, StrolchRootElement> row2) {
|
|
|
|
|
|
|
|
for (StringParameter fieldRefP : this.orderingParams) {
|
|
|
|
|
|
|
|
String type = fieldRefP.getUom();
|
|
|
|
|
|
|
|
StrolchRootElement column1 = row1.get(type);
|
|
|
|
if (column1 == null)
|
|
|
|
return -1;
|
|
|
|
StrolchRootElement column2 = row2.get(type);
|
|
|
|
if (column2 == null)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
int sortVal;
|
|
|
|
if (fieldRefP.getValue().startsWith("$")) {
|
|
|
|
String columnValue1 = evaluateColumnValue(fieldRefP, row1);
|
|
|
|
String columnValue2 = evaluateColumnValue(fieldRefP, row2);
|
|
|
|
|
|
|
|
if (this.descending) {
|
|
|
|
sortVal = columnValue1.compareTo(columnValue2);
|
|
|
|
} else {
|
|
|
|
sortVal = columnValue2.compareTo(columnValue1);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
Parameter<?> param1 = lookupParameter(fieldRefP, column1);
|
|
|
|
Parameter<?> param2 = lookupParameter(fieldRefP, column2);
|
|
|
|
|
|
|
|
if (this.descending)
|
|
|
|
sortVal = param1.compareTo(param2);
|
|
|
|
else
|
|
|
|
sortVal = param2.compareTo(param1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sortVal != 0)
|
|
|
|
return sortVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean hasFilter() {
|
|
|
|
return !this.filtersByPolicy.isEmpty() || this.dateRange != null
|
|
|
|
|| (this.filtersById != null && !this.filtersById.isEmpty());
|
|
|
|
}
|
|
|
|
|
2017-03-21 07:51:13 +01:00
|
|
|
private boolean filter(Map<String, StrolchRootElement> row) {
|
|
|
|
|
2017-05-03 15:32:20 +02:00
|
|
|
// do filtering by policies
|
|
|
|
for (ReportFilterPolicy filterPolicy : this.filtersByPolicy.keySet()) {
|
|
|
|
StringParameter fieldRefP = this.filtersByPolicy.get(filterPolicy);
|
|
|
|
|
|
|
|
String type = fieldRefP.getUom();
|
|
|
|
|
|
|
|
StrolchRootElement column = row.get(type);
|
|
|
|
|
|
|
|
if (fieldRefP.getValue().startsWith("$")) {
|
|
|
|
String columnValue = evaluateColumnValue(fieldRefP, row);
|
|
|
|
if (!filterPolicy.filter(columnValue))
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
Parameter<?> param = lookupParameter(fieldRefP, column);
|
|
|
|
if (!filterPolicy.filter(param))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// do a date range selection, if required
|
2017-03-21 15:34:10 +01:00
|
|
|
if (this.dateRange != null) {
|
|
|
|
if (this.dateRangeSelP == null)
|
|
|
|
throw new IllegalStateException(
|
|
|
|
"DateRange defined, but report does not defined a date range selector!");
|
|
|
|
|
|
|
|
String type = this.dateRangeSelP.getUom();
|
2017-03-21 07:51:13 +01:00
|
|
|
StrolchRootElement element = row.get(type);
|
|
|
|
if (element == null)
|
|
|
|
return false;
|
|
|
|
|
2017-03-21 15:34:10 +01:00
|
|
|
String dateRangeSel = this.dateRangeSelP.getValue();
|
|
|
|
|
|
|
|
Date date;
|
|
|
|
if (dateRangeSel.equals(COL_DATE)) {
|
|
|
|
date = element.accept(new ElementDateVisitor());
|
|
|
|
} else {
|
2017-03-22 14:55:54 +01:00
|
|
|
Parameter<?> param = lookupParameter(this.dateRangeSelP, element);
|
2017-03-21 15:34:10 +01:00
|
|
|
if (StrolchValueType.parse(param.getType()) != StrolchValueType.DATE)
|
|
|
|
throw new IllegalStateException(
|
|
|
|
"Date Range selector is invalid, as referenced parameter is not a Date but a "
|
|
|
|
+ param.getType());
|
|
|
|
|
|
|
|
date = ((DateParameter) param).getValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.dateRange.contains(date))
|
2017-03-21 07:51:13 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-03-21 15:34:10 +01:00
|
|
|
// then we do a filter by criteria
|
2017-05-03 15:32:20 +02:00
|
|
|
if (this.filtersById != null && !this.filtersById.isEmpty()) {
|
|
|
|
for (String type : this.filtersById.keySet()) {
|
2017-03-21 15:34:10 +01:00
|
|
|
StrolchRootElement element = row.get(type);
|
|
|
|
if (element == null)
|
|
|
|
return false;
|
|
|
|
|
2017-05-03 15:32:20 +02:00
|
|
|
if (!this.filtersById.getSet(type).contains(element.getId()))
|
2017-03-21 15:34:10 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise we want to keep this row
|
2017-03-21 07:51:13 +01:00
|
|
|
return true;
|
2017-03-20 19:27:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public Stream<JsonObject> doReportAsJson() {
|
|
|
|
|
2017-03-27 11:51:53 +02:00
|
|
|
return doReport().map(e -> {
|
|
|
|
JsonObject o = new JsonObject();
|
2017-03-27 14:04:39 +02:00
|
|
|
e.keyValueStream().forEach(elem -> o.addProperty(elem.getKey(), elem.getValue()));
|
2017-03-27 11:51:53 +02:00
|
|
|
return o;
|
2017-03-20 19:27:59 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-27 11:51:53 +02:00
|
|
|
private String evaluateColumnValue(StringParameter columnDefP, Map<String, StrolchRootElement> row) {
|
2017-03-20 19:27:59 +01:00
|
|
|
|
2017-03-27 11:51:53 +02:00
|
|
|
String columnDef = columnDefP.getValue();
|
|
|
|
String refType = columnDefP.getUom();
|
|
|
|
|
|
|
|
// get the referenced object
|
|
|
|
StrolchRootElement column = row.get(refType);
|
|
|
|
|
|
|
|
String columnValue;
|
|
|
|
|
|
|
|
if (column == null)
|
|
|
|
columnValue = DASH;
|
|
|
|
else if (columnDef.equals(COL_ID)) {
|
|
|
|
columnValue = column.getId();
|
|
|
|
} else if (columnDef.equals(COL_NAME)) {
|
|
|
|
columnValue = column.getName();
|
|
|
|
} else if (columnDef.equals(COL_TYPE)) {
|
|
|
|
columnValue = column.getType();
|
|
|
|
} else if (columnDef.equals(COL_STATE)) {
|
|
|
|
columnValue = column.accept(new ElementStateVisitor()).name();
|
|
|
|
} else if (columnDef.equals(COL_DATE)) {
|
|
|
|
columnValue = ISO8601FormatFactory.getInstance().formatDate(column.accept(new ElementDateVisitor()));
|
|
|
|
} else if (columnDef.startsWith(COL_SEARCH)) {
|
|
|
|
Parameter<?> parameter = findParameter(columnDefP, column);
|
|
|
|
if (parameter == null)
|
2017-03-20 19:27:59 +01:00
|
|
|
columnValue = DASH;
|
2017-03-27 11:51:53 +02:00
|
|
|
else
|
|
|
|
columnValue = parameter.getValueAsString();
|
|
|
|
} else {
|
|
|
|
columnValue = lookupParameter(columnDefP, column).getValueAsString();
|
|
|
|
}
|
2017-03-20 19:27:59 +01:00
|
|
|
|
2017-03-27 11:51:53 +02:00
|
|
|
return columnValue;
|
2017-03-20 19:27:59 +01:00
|
|
|
}
|
|
|
|
|
2017-03-22 14:55:54 +01:00
|
|
|
private Parameter<?> findParameter(StringParameter columnDefP, StrolchRootElement column) {
|
|
|
|
|
|
|
|
String columnDef = columnDefP.getValue();
|
|
|
|
|
|
|
|
String[] searchParts = columnDef.split(SEARCH_SEPARATOR);
|
|
|
|
if (searchParts.length != 3)
|
|
|
|
throw new IllegalStateException("Parameter search reference (" + columnDef
|
|
|
|
+ ") is invalid as it does not have 3 parts for " + columnDefP.getLocator());
|
|
|
|
|
|
|
|
String parentParamId = searchParts[1];
|
|
|
|
String paramRef = searchParts[2];
|
|
|
|
|
|
|
|
String[] locatorParts = paramRef.split(Locator.PATH_SEPARATOR);
|
|
|
|
if (locatorParts.length != 3)
|
|
|
|
throw new IllegalStateException("Parameter search reference (" + paramRef
|
|
|
|
+ ") is invalid as it does not have 3 parts for " + columnDefP.getLocator());
|
|
|
|
|
|
|
|
String bagKey = locatorParts[1];
|
|
|
|
String paramKey = locatorParts[2];
|
|
|
|
|
|
|
|
return findParameter(column, parentParamId, bagKey, paramKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
private Parameter<?> findParameter(StrolchRootElement element, String parentParamId, String bagKey,
|
|
|
|
String paramKey) {
|
|
|
|
|
|
|
|
Parameter<?> parameter = element.getParameter(bagKey, paramKey);
|
|
|
|
if (parameter != null)
|
|
|
|
return parameter;
|
|
|
|
|
|
|
|
StringParameter parentRefP = element.getParameter(BAG_RELATIONS, parentParamId);
|
|
|
|
if (parentRefP == null)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
Resource parent = this.tx.getResourceBy(parentRefP);
|
|
|
|
if (parent == null)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
return findParameter(parent, parentParamId, bagKey, paramKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
private Parameter<?> lookupParameter(StringParameter paramRefP, StrolchRootElement column) {
|
2017-03-21 15:34:10 +01:00
|
|
|
String paramRef = paramRefP.getValue();
|
|
|
|
|
|
|
|
String[] locatorParts = paramRef.split(Locator.PATH_SEPARATOR);
|
|
|
|
if (locatorParts.length != 3)
|
|
|
|
throw new IllegalStateException("Parameter reference (" + paramRef
|
|
|
|
+ ") is invalid as it does not have 3 parts for " + paramRefP.getLocator());
|
|
|
|
|
|
|
|
String bagKey = locatorParts[1];
|
|
|
|
String paramKey = locatorParts[2];
|
|
|
|
|
|
|
|
Parameter<?> param = column.getParameter(bagKey, paramKey);
|
|
|
|
if (param == null)
|
|
|
|
throw new IllegalStateException("Parameter reference (" + paramRef + ") for " + paramRefP.getLocator()
|
|
|
|
+ " not found on " + column.getLocator());
|
|
|
|
|
|
|
|
return param;
|
|
|
|
}
|
|
|
|
|
2017-03-20 19:27:59 +01:00
|
|
|
private Stream<StrolchRootElement> queryRows() {
|
|
|
|
|
|
|
|
// find the type of object for which the report is created
|
2017-06-27 08:45:26 +02:00
|
|
|
if (this.objectTypeP.getInterpretation().equals(StrolchConstants.INTERPRETATION_RESOURCE_REF)) {
|
2017-03-20 19:27:59 +01:00
|
|
|
|
2017-06-27 08:45:26 +02:00
|
|
|
return this.tx.getResourceMap().getElementsBy(this.tx, this.objectTypeP.getUom()).stream()
|
2017-03-20 19:27:59 +01:00
|
|
|
.map(e -> e.getRootElement());
|
|
|
|
|
2017-06-27 08:45:26 +02:00
|
|
|
} else if (this.objectTypeP.getInterpretation().equals(StrolchConstants.INTERPRETATION_ORDER_REF)) {
|
2017-03-20 19:27:59 +01:00
|
|
|
|
2017-06-27 08:45:26 +02:00
|
|
|
return this.tx.getOrderMap().getElementsBy(this.tx, this.objectTypeP.getUom()).stream()
|
2017-03-20 19:27:59 +01:00
|
|
|
.map(e -> e.getRootElement());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
2017-06-27 08:45:26 +02:00
|
|
|
throw new IllegalArgumentException("Unhandled element type " + this.objectTypeP.getInterpretation());
|
2017-03-20 19:27:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-21 07:51:13 +01:00
|
|
|
private Map<String, StrolchRootElement> evaluateRow(StrolchRootElement resource) {
|
2017-03-20 19:27:59 +01:00
|
|
|
|
|
|
|
// interpretation -> Resource-Ref, etc.
|
|
|
|
// uom -> object type
|
|
|
|
// value -> element type where relation is defined for this join
|
|
|
|
|
|
|
|
// create the refs element
|
|
|
|
HashMap<String, StrolchRootElement> refs = new HashMap<>();
|
|
|
|
// and add the starting point
|
|
|
|
refs.put(resource.getType(), resource);
|
|
|
|
|
2017-05-03 16:06:56 +02:00
|
|
|
if (!this.report.hasParameterBag(BAG_JOINS))
|
|
|
|
return refs;
|
|
|
|
|
|
|
|
ParameterBag joinBag = this.report.getParameterBag(BAG_JOINS);
|
2017-03-20 19:27:59 +01:00
|
|
|
for (String paramId : joinBag.getParameterKeySet()) {
|
|
|
|
StringParameter joinP = joinBag.getParameter(paramId);
|
|
|
|
addColumnJoin(refs, joinBag, joinP, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return refs;
|
|
|
|
}
|
|
|
|
|
2017-03-21 07:51:13 +01:00
|
|
|
private StrolchRootElement addColumnJoin(Map<String, StrolchRootElement> refs, ParameterBag joinBag,
|
2017-03-20 19:27:59 +01:00
|
|
|
StringParameter joinP, boolean optional) {
|
|
|
|
|
2017-09-13 15:28:40 +02:00
|
|
|
String interpretation = joinP.getInterpretation();
|
|
|
|
String elementType = interpretation.substring(0, interpretation.indexOf(SUFFIX_REF));
|
2017-03-20 19:27:59 +01:00
|
|
|
String joinType = joinP.getUom();
|
|
|
|
String dependencyType = joinP.getValue();
|
|
|
|
|
|
|
|
// get dependency
|
|
|
|
StrolchRootElement dependency;
|
|
|
|
if (refs.containsKey(dependencyType)) {
|
|
|
|
dependency = refs.get(dependencyType);
|
|
|
|
} else {
|
|
|
|
// recursively find the dependency
|
|
|
|
StringParameter dependencyP = joinBag.getParameter(dependencyType);
|
|
|
|
dependency = addColumnJoin(refs, joinBag, dependencyP, false);
|
2017-05-03 15:32:20 +02:00
|
|
|
if (dependency == null)
|
|
|
|
return null;
|
2017-03-20 19:27:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ParameterBag relationsBag = dependency.getParameterBag(BAG_RELATIONS);
|
2017-03-21 15:34:10 +01:00
|
|
|
if (relationsBag == null)
|
|
|
|
throw new IllegalStateException("Invalid join definition value: " + joinP.getValue() + " on: "
|
|
|
|
+ joinP.getLocator() + " as " + dependency.getLocator() + " has no ParameterBag " + BAG_RELATIONS);
|
|
|
|
|
2017-09-13 15:28:40 +02:00
|
|
|
List<Parameter<?>> relationParams = relationsBag.getParametersByInterpretationAndUom(interpretation, joinType);
|
2017-03-20 19:27:59 +01:00
|
|
|
if (relationParams.isEmpty()) {
|
|
|
|
throw new IllegalStateException(
|
|
|
|
"Found no relation parameters with UOM " + joinType + " on dependency " + dependency.getLocator());
|
|
|
|
}
|
|
|
|
if (relationParams.size() > 1) {
|
|
|
|
throw new IllegalStateException("Found multiple possible relation parameters for UOM " + joinType
|
|
|
|
+ " on dependency " + dependency.getLocator());
|
|
|
|
}
|
|
|
|
|
|
|
|
StringParameter relationP = (StringParameter) relationParams.get(0);
|
|
|
|
if (relationP.getValue().isEmpty() && optional) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
Locator locator = Locator.valueOf(elementType, joinType, relationP.getValue());
|
2017-05-03 15:32:20 +02:00
|
|
|
StrolchRootElement joinElem = this.tx.findElement(locator, true);
|
|
|
|
if (joinElem == null)
|
|
|
|
return null;
|
2017-03-20 19:27:59 +01:00
|
|
|
|
|
|
|
refs.put(joinType, joinElem);
|
|
|
|
return joinElem;
|
|
|
|
}
|
|
|
|
}
|