[New] Extended filtering GenericReport with multi refs

This commit is contained in:
Robert von Burg 2019-10-30 10:50:45 +01:00
parent 826175301a
commit 25362da8d1
9 changed files with 193 additions and 29 deletions

View File

@ -15,6 +15,8 @@ public class ReportConstants {
public static final String PARAM_DESCENDING = "descending";
public static final String PARAM_DATE_RANGE_SEL = "dateRangeSel";
public static final String PARAM_FIELD_REF = "fieldRef";
public static final String PARAM_FIELD_REF1 = "fieldRef1";
public static final String PARAM_FIELD_REF2 = "fieldRef2";
public static final String PARAM_ALLOW_MISSING_COLUMNS = "allowMissingColumns";
public static final String PARAM_POLICY = "policy";

View File

@ -30,6 +30,7 @@ import li.strolch.utils.ObjectHelper;
import li.strolch.utils.collections.DateRange;
import li.strolch.utils.collections.MapOfLists;
import li.strolch.utils.collections.MapOfSets;
import li.strolch.utils.collections.TypedTuple;
import li.strolch.utils.iso8601.ISO8601FormatFactory;
/**
@ -51,7 +52,7 @@ public class GenericReport extends ReportPolicy {
private StringParameter dateRangeSelP;
private DateRange dateRange;
private Map<ReportFilterPolicy, StringParameter> filtersByPolicy;
private Map<ReportFilterPolicy, TypedTuple<StringParameter, StringParameter>> filtersByPolicy;
private MapOfSets<String, String> filtersById;
private long counter;
@ -128,6 +129,23 @@ public class GenericReport extends ReportPolicy {
List<ParameterBag> filterBags = this.reportRes.getParameterBagsByType(TYPE_FILTER);
for (ParameterBag filterBag : filterBags) {
if (filterBag.hasParameter(PARAM_FIELD_REF) && (filterBag.hasParameter(PARAM_FIELD_REF1) || filterBag
.hasParameter(PARAM_FIELD_REF2))) {
throw new IllegalArgumentException(
"Filter " + filterBag.getLocator() + " can not have combination of " + PARAM_FIELD_REF
+ " and any of " + PARAM_FIELD_REF1 + ", " + PARAM_FIELD_REF2);
} else if ((filterBag.hasParameter(PARAM_FIELD_REF1) && !filterBag.hasParameter(PARAM_FIELD_REF2)) || (
!filterBag.hasParameter(PARAM_FIELD_REF1) && filterBag.hasParameter(PARAM_FIELD_REF2))) {
throw new IllegalArgumentException(
"Filter " + filterBag.getLocator() + " must have both " + PARAM_FIELD_REF1 + " and "
+ PARAM_FIELD_REF2);
} else if (!filterBag.hasParameter(PARAM_FIELD_REF) && (!filterBag.hasParameter(PARAM_FIELD_REF1)
|| !filterBag.hasParameter(PARAM_FIELD_REF2))) {
throw new IllegalArgumentException(
"Filter " + filterBag.getLocator() + " is missing the " + PARAM_FIELD_REF + " or "
+ PARAM_FIELD_REF1 + ", " + PARAM_FIELD_REF2 + " combination!");
}
// prepare filter function policy
StringParameter functionP = filterBag.getParameter(PARAM_POLICY);
PolicyHandler policyHandler = getContainer().getComponent(PolicyHandler.class);
@ -135,8 +153,15 @@ public class GenericReport extends ReportPolicy {
ReportFilterPolicy filterFunction = policyHandler.getPolicy(policyDef, tx());
filterFunction.init(functionP.getValue());
StringParameter fieldRefP = filterBag.getParameter(PARAM_FIELD_REF);
this.filtersByPolicy.put(filterFunction, fieldRefP);
TypedTuple<StringParameter, StringParameter> refTuple = new TypedTuple<>();
if (filterBag.hasParameter(PARAM_FIELD_REF)) {
refTuple.setFirst(filterBag.getParameter(PARAM_FIELD_REF));
} else {
refTuple.setFirst(filterBag.getParameter(PARAM_FIELD_REF1));
refTuple.setSecond(filterBag.getParameter(PARAM_FIELD_REF2));
}
this.filtersByPolicy.put(filterFunction, refTuple);
}
}
@ -374,7 +399,7 @@ public class GenericReport extends ReportPolicy {
return buildStream().map(e -> new ReportElement(this.columnIds, columnId -> {
StringParameter columnDefP = this.columnsBag.getParameter(columnId, true);
Object value = evaluateColumnValue(columnDefP, e);
Object value = evaluateColumnValue(columnDefP, e, false);
if (value instanceof Date)
return ISO8601FormatFactory.getInstance().formatDate((Date) value);
if (value instanceof Parameter)
@ -474,8 +499,8 @@ public class GenericReport extends ReportPolicy {
int sortVal;
if (fieldRefP.getValue().startsWith("$")) {
Object columnValue1 = evaluateColumnValue(fieldRefP, row1);
Object columnValue2 = evaluateColumnValue(fieldRefP, row2);
Object columnValue1 = evaluateColumnValue(fieldRefP, row1, false);
Object columnValue2 = evaluateColumnValue(fieldRefP, row2, false);
if (this.descending) {
sortVal = ObjectHelper.compare(columnValue2, columnValue1, true);
@ -531,23 +556,18 @@ public class GenericReport extends ReportPolicy {
// do filtering by policies
for (ReportFilterPolicy filterPolicy : this.filtersByPolicy.keySet()) {
StringParameter fieldRefP = this.filtersByPolicy.get(filterPolicy);
TypedTuple<StringParameter, StringParameter> refTuple = this.filtersByPolicy.get(filterPolicy);
String type = fieldRefP.getUom();
if (refTuple.hasFirst() && refTuple.hasSecond()) {
Object value1 = evaluateColumnValue(refTuple.getFirst(), row, true);
Object value2 = evaluateColumnValue(refTuple.getSecond(), row, true);
StrolchRootElement column = row.get(type);
// if column is null, then don't include in result
if (column == null)
return false;
if (fieldRefP.getValue().startsWith("$")) {
Object value = evaluateColumnValue(fieldRefP, row);
if (!filterPolicy.filter(value))
if (value1 == null || value2 == null || !filterPolicy.filter(value1, value2))
return false;
} else {
Optional<Parameter<?>> param = lookupParameter(fieldRefP, column);
if (param.isPresent() && !filterPolicy.filter(param.get()))
Object value = evaluateColumnValue(refTuple.getFirst(), row, true);
if (value == null || !filterPolicy.filter(value))
return false;
}
}
@ -605,10 +625,14 @@ public class GenericReport extends ReportPolicy {
* the column definition
* @param row
* the row
* @param allowNull
* handles the return value if the lookup fails. If true, then null is returned, else the empty string is
* returned
*
* @return the column value
*/
protected Object evaluateColumnValue(StringParameter columnDefP, Map<String, StrolchRootElement> row) {
protected Object evaluateColumnValue(StringParameter columnDefP, Map<String, StrolchRootElement> row,
boolean allowNull) {
String columnDef = columnDefP.getValue();
String refType = columnDefP.getUom();
@ -619,7 +643,7 @@ public class GenericReport extends ReportPolicy {
Object columnValue;
if (column == null) {
columnValue = EMPTY;
columnValue = allowNull ? null : EMPTY;
} else if (columnDef.equals(COL_OBJECT)) {
columnValue = column;
} else if (columnDef.equals(COL_ID)) {
@ -756,7 +780,9 @@ public class GenericReport extends ReportPolicy {
// and add the starting point
refs.put(element.getType(), element);
// now add all the joins
handleJoins(refs, BAG_JOINS);
return refs;
}

View File

@ -10,6 +10,7 @@ import li.strolch.model.StrolchValueType;
import li.strolch.model.parameter.Parameter;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.utils.ObjectHelper;
import li.strolch.utils.dbc.DBC;
public class IsInReportFilter extends ReportFilterPolicy {
@ -19,6 +20,7 @@ public class IsInReportFilter extends ReportFilterPolicy {
@Override
public boolean filter(Object value) {
DBC.PRE.assertNotNull("value required!", value);
Object left;
if (value instanceof Date) {

View File

@ -45,6 +45,7 @@ public abstract class ReportFilterPolicy extends StrolchPolicy {
}
public boolean filter(Object value) {
DBC.PRE.assertNotNull("value required!", value);
Object left;
if (value instanceof Date) {
@ -77,6 +78,10 @@ public abstract class ReportFilterPolicy extends StrolchPolicy {
return filter(left, this.right, this.negate);
}
public boolean filter(Object value1, Object value2) {
throw new UnsupportedOperationException("Handling multiple values not supported!");
}
protected Date parseFilterValueToDate(String filterValue) {
DBC.INTERIM.assertNotEmpty("filterValue must not be empty for date comparisons!", filterValue);

View File

@ -0,0 +1,65 @@
package li.strolch.report.policy;
import java.util.Date;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.model.parameter.Parameter;
import li.strolch.model.policy.KeyPolicyDef;
import li.strolch.model.policy.PolicyDef;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.utils.dbc.DBC;
public class ValueRefReportFilter extends ReportFilterPolicy {
private ReportFilterPolicy filterPolicy;
public ValueRefReportFilter(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
}
@Override
public void init(String value) {
super.init(value);
this.filterPolicy = tx().getPolicy(PolicyDef
.valueOf(ReportFilterPolicy.class.getSimpleName(), KeyPolicyDef.XML_PREFIX + this.filterValue));
}
@Override
public boolean filter(Object value) {
throw new UnsupportedOperationException("2 values required!");
}
@Override
public boolean filter(Object value1, Object value2) {
DBC.PRE.assertNotNull("value1 required!", value1);
DBC.PRE.assertNotNull("value2 required!", value2);
Object left;
if (value1 instanceof Date) {
left = value1;
} else if (value1 instanceof Parameter) {
Parameter parameter = (Parameter) value1;
left = parameter.getValue();
} else {
left = value1.toString();
}
Object right;
if (value2 instanceof Date) {
right = value2;
} else if (value2 instanceof Parameter) {
Parameter parameter = (Parameter) value2;
right = parameter.getValue();
} else {
right = value2.toString();
}
return this.filterPolicy.filter(left, right, this.negate);
}
@Override
protected boolean filter(Object left, Object right, boolean negate) {
throw new UnsupportedOperationException("Not used");
}
}

View File

@ -1,6 +1,7 @@
package li.strolch.report;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.*;
@ -9,7 +10,6 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import com.google.gson.JsonObject;
import li.strolch.model.StrolchElement;
@ -241,11 +241,11 @@ public class GenericReportTest {
assertFalse(filterCriteria.containsSet("Location"));
assertFalse(filterCriteria.containsSet("Slot"));
assertThat(filterCriteria.getSet("Product").stream().map(StrolchElement::getId).collect(Collectors.toSet()),
assertThat(filterCriteria.getSet("Product").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("product01", "product02"));
assertThat(filterCriteria.getSet("Storage").stream().map(StrolchElement::getId).collect(Collectors.toSet()),
assertThat(filterCriteria.getSet("Storage").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("storage01", "storage02"));
assertThat(filterCriteria.getSet("Section").stream().map(StrolchElement::getId).collect(Collectors.toSet()),
assertThat(filterCriteria.getSet("Section").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("section001", "section002"));
}
}
@ -268,11 +268,11 @@ public class GenericReportTest {
assertFalse(filterCriteria.containsSet("Location"));
assertFalse(filterCriteria.containsSet("Slot"));
assertThat(filterCriteria.getSet("Product").stream().map(StrolchElement::getId).collect(Collectors.toSet()),
assertThat(filterCriteria.getSet("Product").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("product01"));
assertThat(filterCriteria.getSet("Storage").stream().map(StrolchElement::getId).collect(Collectors.toSet()),
assertThat(filterCriteria.getSet("Storage").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("storage01", "storage02"));
assertThat(filterCriteria.getSet("Section").stream().map(StrolchElement::getId).collect(Collectors.toSet()),
assertThat(filterCriteria.getSet("Section").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("section001", "section002"));
}
}

View File

@ -0,0 +1,38 @@
package li.strolch.report;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.model.Resource;
import li.strolch.model.parameter.BooleanParameter;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.report.policy.ReportFilterPolicy;
import li.strolch.utils.dbc.DBC;
public class PackableFilterPolicy extends ReportFilterPolicy {
public PackableFilterPolicy(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
}
@Override
public boolean filter(Object value) {
throw new UnsupportedOperationException("2 values required!");
}
@Override
public boolean filter(Object value1, Object value2) {
DBC.PRE.assertNotNull("value1 required!", value1);
DBC.PRE.assertNotNull("value2 required!", value2);
BooleanParameter productPackable = (BooleanParameter) value1;
Resource location = (Resource) value2;
BooleanParameter locationPackable = location.getParameter("packingLocation", false);
if (locationPackable == null)
return this.negate;
boolean packable = productPackable.getValue() == locationPackable.getValue();
return this.negate != packable;
}
@Override
protected boolean filter(Object left, Object right, boolean negate) {
throw new UnsupportedOperationException("Not used");
}
}

View File

@ -4,9 +4,10 @@
<Policy Key="Contains" Class="li.strolch.report.policy.ContainsReportFilter" />
<Policy Key="IsIn" Class="li.strolch.report.policy.IsInReportFilter" />
<Policy Key="GreaterThan" Class="li.strolch.report.policy.GreaterThanReportFilter" />
<Policy Key="GreaterThan" Class="li.strolch.report.policy.GreaterThanReportFilter" />
<Policy Key="LessThan" Class="li.strolch.report.policy.LessThanReportFilter" />
<Policy Key="Equals" Class="li.strolch.report.policy.EqualsReportFilter" />
<Policy Key="ValueRef" Class="li.strolch.report.policy.ValueRefReportFilter" />
<Policy Key="Packable" Class="li.strolch.report.PackableFilterPolicy" />
</PolicyType>
</StrolchPolicies>

View File

@ -71,6 +71,21 @@
<Parameter Id="policy" Name="Filter Policy" Type="String" Interpretation="ReportFilterPolicy" Uom="key:Equals" Value="!"/>
<Parameter Id="fieldRef" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="Slot" Value="Bags/relations/product"/>
</ParameterBag>
<ParameterBag Id="valueRef1Filter" Name="Filter" Type="Filter">
<Parameter Id="policy" Name="Filter Policy" Type="String" Interpretation="ReportFilterPolicy" Uom="key:ValueRef" Value="GreaterThan"/>
<Parameter Id="fieldRef1" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="Slot" Value="Bags/parameters/maxQuantity"/>
<Parameter Id="fieldRef2" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="Storage" Value="$search:parent:Bags/parameters/minQuantity"/>
</ParameterBag>
<ParameterBag Id="valueRef2Filter" Name="Filter" Type="Filter">
<Parameter Id="policy" Name="Filter Policy" Type="String" Interpretation="ReportFilterPolicy" Uom="key:ValueRef" Value="!Equals"/>
<Parameter Id="fieldRef1" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="Storage" Value="$search:parent:Bags/parameters/minQuantity"/>
<Parameter Id="fieldRef2" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="Slot" Value="Bags/parameters/maxQuantity"/>
</ParameterBag>
<ParameterBag Id="packableFilter" Name="Filter" Type="Filter">
<Parameter Id="policy" Name="Filter Policy" Type="String" Interpretation="ReportFilterPolicy" Uom="key:Packable" Value=""/>
<Parameter Id="fieldRef1" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="Product" Value="Bags/parameters/packable"/>
<Parameter Id="fieldRef2" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="Location" Value="$object"/>
</ParameterBag>
<ParameterBag Id="columns" Name="Display Columns" Type="Display">
<Parameter Id="location" Name="Location" Type="String" Interpretation="Resource-Ref" Uom="Location" Value="$name"/>
@ -137,11 +152,13 @@
<Resource Id="product01" Name="Product 01" Type="Product">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="expirationDate" Name="Expiration Date" Type="Date" Value="2017-02-01T10:00:00.000+01:00"/>
<Parameter Id="packable" Name="Packable" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<Resource Id="product02" Name="Product 02" Type="Product">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="expirationDate" Name="Expiration Date" Type="Date" Value="2017-03-01T10:00:00.000+01:00"/>
<Parameter Id="packable" Name="Packable" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
@ -185,11 +202,13 @@
<Resource Id="location01" Name="Location 01" Type="Location">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="description" Name="Description" Type="String" Value="Just a location"/>
<Parameter Id="packingLocation" Name="Packing Location" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<Resource Id="location02" Name="Location 02" Type="Location">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="description" Name="Description" Type="String" Value="Just a location"/>
<Parameter Id="packingLocation" Name="Packing Location" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
@ -232,6 +251,7 @@
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="quantity" Name="Quantity" Type="Float" Value="20.0"/>
<Parameter Id="maxQuantity" Name="max. quantity of items" Type="Float" Value="40.0"/>
<Parameter Id="minQuantity" Name="Min Quantity" Type="Float" Value="4.0"/>
<Parameter Id="state" Name="State" Type="String" Value="valid"/>
</ParameterBag>
<ParameterBag Id="relations" Name="Relations" Type="Parameters">
@ -244,6 +264,7 @@
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="quantity" Name="Quantity" Type="Float" Value="18.0"/>
<Parameter Id="maxQuantity" Name="max. quantity of items" Type="Float" Value="20.0"/>
<Parameter Id="minQuantity" Name="Min Quantity" Type="Float" Value="10.0"/>
<Parameter Id="state" Name="State" Type="String" Value="valid"/>
</ParameterBag>
<ParameterBag Id="relations" Name="Relations" Type="Parameters">
@ -256,6 +277,7 @@
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="quantity" Name="Quantity" Type="Float" Value="11.0"/>
<Parameter Id="maxQuantity" Name="max. quantity of items" Type="Float" Value="40.0"/>
<Parameter Id="minQuantity" Name="Min Quantity" Type="Float" Value="6.0"/>
<Parameter Id="state" Name="State" Type="String" Value="valid"/>
</ParameterBag>
<ParameterBag Id="relations" Name="Relations" Type="Parameters">
@ -268,6 +290,7 @@
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="quantity" Name="Quantity" Type="Float" Value="16.0"/>
<Parameter Id="maxQuantity" Name="max. quantity of items" Type="Float" Value="20.0"/>
<Parameter Id="minQuantity" Name="Min Quantity" Type="Float" Value="6.0"/>
<Parameter Id="state" Name="State" Type="String" Value="valid"/>
</ParameterBag>
<ParameterBag Id="relations" Name="Relations" Type="Parameters">
@ -280,6 +303,7 @@
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="quantity" Name="Quantity" Type="Float" Value="0.0"/>
<Parameter Id="maxQuantity" Name="max. quantity of items" Type="Float" Value="20.0"/>
<Parameter Id="minQuantity" Name="Min Quantity" Type="Float" Value="6.0"/>
<Parameter Id="state" Name="State" Type="String" Value="valid"/>
</ParameterBag>
<ParameterBag Id="relations" Name="Relations" Type="Parameters">
@ -292,6 +316,7 @@
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="quantity" Name="Quantity" Type="Float" Value="22.0"/>
<Parameter Id="maxQuantity" Name="max. quantity of items" Type="Float" Value="20.0"/>
<Parameter Id="minQuantity" Name="Min Quantity" Type="Float" Value="6.0"/>
<Parameter Id="state" Name="State" Type="String" Value="valid"/>
</ParameterBag>
<ParameterBag Id="relations" Name="Relations" Type="Parameters">