Compare commits

...

4 Commits

Author SHA1 Message Date
Robert von Burg 3054d5fca5
[Minor] Added ExceptionHelper.getRootCauseMessage() 2024-05-03 10:08:10 +02:00
Robert von Burg 19825b37a8
[Major] Refactored facet generation for reports
simplified code, move facet value generation into policy, added extension point for formatting criteria to Json, so the facet value's name can be changed in subclasses.
2024-05-02 12:43:21 +02:00
Robert von Burg c65c6624fb
[Fix] Ignoring more bundles in I18nMessage 2024-04-30 12:50:54 +02:00
Robert von Burg 4d7b3faf3f
[Fix] Fixed RestfulStrolchComponent not starting 2024-04-23 15:30:59 +02:00
8 changed files with 516 additions and 504 deletions

View File

@ -91,12 +91,12 @@ public class Report implements AutoCloseable {
return this.reportPolicy.doReportWithPage(offset, limit);
}
public MapOfSets<String, StrolchRootElement> generateFilterCriteria(int limit) {
public MapOfSets<String, JsonObject> generateFilterCriteria(int limit) {
return this.reportPolicy.generateFilterCriteria(limit);
}
public Stream<StrolchRootElement> generateFilterCriteria(String type) {
return this.reportPolicy.generateFilterCriteria(type);
public Stream<JsonObject> generateFilterCriteria(String type, int limit, String query) {
return this.reportPolicy.generateFilterCriteria(type,limit, query);
}
public long getCounter() {

View File

@ -1,17 +1,5 @@
package li.strolch.report.policy;
import static java.util.Comparator.comparing;
import static java.util.Comparator.comparingInt;
import static java.util.stream.Collectors.toList;
import static li.strolch.model.StrolchModelConstants.*;
import static li.strolch.report.ReportConstants.*;
import static li.strolch.utils.helper.StringHelper.EMPTY;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;
import com.google.gson.JsonObject;
import li.strolch.model.*;
import li.strolch.model.parameter.AbstractParameter;
@ -33,6 +21,20 @@ import li.strolch.utils.collections.TypedTuple;
import li.strolch.utils.dbc.DBC;
import li.strolch.utils.iso8601.ISO8601;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;
import static java.text.MessageFormat.format;
import static java.util.Comparator.comparing;
import static java.util.Comparator.comparingInt;
import static java.util.stream.Collectors.toList;
import static li.strolch.model.StrolchModelConstants.*;
import static li.strolch.report.ReportConstants.*;
import static li.strolch.utils.ObjectHelper.*;
import static li.strolch.utils.helper.StringHelper.EMPTY;
/**
* A Generic Report defines a report as is described at <a href="https://strolch.li/documentation-reports.html">Strolch
* Reports</a>
@ -88,9 +90,11 @@ public class GenericReport extends ReportPolicy {
this.columnsBag = this.reportRes.getParameterBag(BAG_COLUMNS, true);
this.columnIds = this.columnsBag.getParameters().stream() //
.sorted(comparingInt(Parameter::getIndex)) //
.map(StrolchElement::getId) //
this.columnIds = this.columnsBag
.getParameters()
.stream()
.sorted(comparingInt(Parameter::getIndex))
.map(StrolchElement::getId)
.collect(toList());
this.parallel = this.reportRes.getBoolean(PARAM_PARALLEL);
@ -167,36 +171,21 @@ 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);
if (filterBag.hasParameter(PARAM_FIELD_REF) && (
filterBag.hasParameter(PARAM_FIELD_REF1) || filterBag.hasParameter(PARAM_FIELD_REF2))) {
throw new IllegalArgumentException(
format("Filter {0} can not have combination of {1} and any of {2}, {3}", filterBag.getLocator(),
PARAM_FIELD_REF, 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!");
throw new IllegalArgumentException(
format("Filter {0} must have both {1} and {2}", filterBag.getLocator(), PARAM_FIELD_REF1,
PARAM_FIELD_REF2));
} else if (!filterBag.hasParameter(PARAM_FIELD_REF) && (
!filterBag.hasParameter(PARAM_FIELD_REF1) || !filterBag.hasParameter(PARAM_FIELD_REF2))) {
throw new IllegalArgumentException(
format("Filter {0} is missing the {1} or {2}, {3} combination!", filterBag.getLocator(),
PARAM_FIELD_REF, PARAM_FIELD_REF1, PARAM_FIELD_REF2));
}
// prepare filter function policy
@ -379,7 +368,7 @@ public class GenericReport extends ReportPolicy {
Stream<Map<String, StrolchRootElement>> stream;
// query the main objects and return a stream
stream = queryRows() //
stream = queryRows()
// transform each element into a map of Type,Value pairs
.map(this::evaluateRow);
@ -458,10 +447,9 @@ public class GenericReport extends ReportPolicy {
StringParameter joinParamP = additionalTypeBag.getStringP(PARAM_JOIN_PARAM);
String[] locatorParts = joinParamP.getValue().split(Locator.PATH_SEPARATOR);
if (locatorParts.length != 3)
throw new IllegalStateException("Parameter reference ("
+ joinParamP.getValue()
+ ") is invalid as it does not have 3 parts for "
+ joinParamP.getLocator());
throw new IllegalStateException(
format("Parameter reference ({0}) is invalid as it does not have 3 parts for {1}",
joinParamP.getValue(), joinParamP.getLocator()));
String bagKey = locatorParts[1];
String paramKey = locatorParts[2];
@ -476,19 +464,15 @@ public class GenericReport extends ReportPolicy {
StrolchRootElement joinElement = row.get(joinWithP.getUom());
if (joinElement == null)
throw new IllegalStateException("Additional join type "
+ joinWithP.getUom()
+ " is not available on row for "
+ joinWithP.getLocator());
throw new IllegalStateException(
format("Additional join type {0} is not available on row for {1}", joinWithP.getUom(),
joinWithP.getLocator()));
Optional<Parameter<?>> refP = lookupParameter(joinWithP, joinElement, false);
if (refP.isEmpty()) {
throw new IllegalStateException("Parameter reference ("
+ joinWithP.getValue()
+ ") for "
+ joinWithP.getLocator()
+ " not found on "
+ joinElement.getLocator());
throw new IllegalStateException(
format("Parameter reference ({0}) for {1} not found on {2}", joinWithP.getValue(),
joinWithP.getLocator(), joinElement.getLocator()));
}
StringParameter joinP = (StringParameter) refP.get();
@ -520,14 +504,12 @@ public class GenericReport extends ReportPolicy {
protected String formatColumn(Map<String, StrolchRootElement> row, String columnId) {
StringParameter columnDefP = this.columnsBag.getParameter(columnId, true);
Object value = evaluateColumnValue(columnDefP, row, false);
if (value instanceof ZonedDateTime) {
return ISO8601.toString((ZonedDateTime) value);
} else if (value instanceof Date) {
return ISO8601.toString((Date) value);
} else if (value instanceof Parameter) {
return formatColumn((Parameter<?>) value);
} else
return value.toString();
return switch (value) {
case ZonedDateTime zonedDateTime -> ISO8601.toString(zonedDateTime);
case Date date -> ISO8601.toString(date);
case Parameter<?> parameter -> formatColumn(parameter);
default -> value.toString();
};
}
protected String formatColumn(Parameter<?> param) {
@ -570,76 +552,29 @@ public class GenericReport extends ReportPolicy {
* @return the filter criteria as a map of sets
*/
@Override
public MapOfSets<String, StrolchRootElement> generateFilterCriteria(int limit) {
public MapOfSets<String, JsonObject> generateFilterCriteria(int limit) {
int maxFacetValues = getMaxFacetValues(limit);
if (limit <= 0 || limit >= MAX_FACET_VALUE_LIMIT) {
logger.warn("Overriding invalid limit " + limit + " with " + MAX_FACET_VALUE_LIMIT);
limit = 100;
}
int maxFacetValues;
int reportMaxFacetValues = this.reportRes.getInteger(PARAM_MAX_FACET_VALUES);
if (reportMaxFacetValues != 0 && reportMaxFacetValues != limit) {
logger.warn("Report "
+ this.reportRes.getId()
+ " has "
+ PARAM_MAX_FACET_VALUES
+ " defined as "
+ reportMaxFacetValues
+ ". Ignoring requested limit "
+ limit);
maxFacetValues = reportMaxFacetValues;
} else {
maxFacetValues = limit;
}
MapOfSets<String, StrolchRootElement> result = new MapOfSets<>(true);
MapOfSets<String, JsonObject> result = new MapOfSets<>(true);
// we need the list of possible element types, which designate the criteria
List<String> criteria = this.filterCriteriaParams.values().stream() //
.filter(p -> {
if (p.getUom().equals(UOM_NONE))
throw new IllegalStateException(
"Join UOM " + p.getUom() + " invalid: " + p.getId() + " for " + p.getLocator());
if (p.getId().equals(PARAM_OBJECT_TYPE))
return filterCriteriaAllowed(p.getUom());
return filterCriteriaAllowed(p.getId());
}) //
.sorted(comparing(StringParameter::getIndex)) //
.map(StringParameter::getUom) //
.collect(toList());
List<String> criteria = this.filterCriteriaParams.values().stream().filter(p -> {
if (p.getUom().equals(UOM_NONE))
throw new IllegalStateException(
format("Join UOM {0} invalid: {1} for {2}", p.getUom(), p.getId(), p.getLocator()));
if (p.getId().equals(PARAM_OBJECT_TYPE))
return filterCriteriaAllowed(p.getUom());
return filterCriteriaAllowed(p.getId());
}).sorted(comparing(StringParameter::getIndex)).map(StringParameter::getUom).collect(toList());
criteria.addAll(this.directCriteria);
int maxRowsForFacetGeneration = this.reportRes.getInteger(PARAM_MAX_ROWS_FOR_FACET_GENERATION);
if (!this.directCriteria.isEmpty()) {
criteria.forEach(type -> {
if (!this.directCriteria.contains(type))
return;
StringParameter filterCriteriaP = this.filterCriteriaParams.get(type);
if (filterCriteriaP == null) {
logger.warn("Filter criteria not found for " + type);
return;
}
Stream<? extends StrolchRootElement> stream = switch (filterCriteriaP.getInterpretation()) {
case INTERPRETATION_RESOURCE_REF -> tx().streamResources(filterCriteriaP.getUom());
case INTERPRETATION_ORDER_REF -> tx().streamOrders(filterCriteriaP.getUom());
case INTERPRETATION_ACTIVITY_REF -> tx().streamActivities(filterCriteriaP.getUom());
default -> throw new IllegalArgumentException("Unhandled filter criteria interpretation "
+ filterCriteriaP.getInterpretation()
+ " for "
+ filterCriteriaP.getLocator());
};
stream = stream.map(this::mapFilterCriteria).filter(this::filterDirectCriteria);
if (hasOrdering())
stream = stream.sorted(this::sortDirectCriteria);
if (maxFacetValues > 0)
stream = stream.limit(maxFacetValues);
stream.forEachOrdered(e -> result.addElement(e.getType(), e));
if (this.directCriteria.contains(type))
prepareStreamForDirectCriteria(type, maxFacetValues).forEachOrdered(
e -> result.addElement(e.getType(), mapCriteriaToJson(e)));
});
criteria.removeAll(this.directCriteria);
@ -656,7 +591,7 @@ public class GenericReport extends ReportPolicy {
for (String criterion : criteria) {
if (row.containsKey(criterion) && result.size(criterion) < maxFacetValues)
result.addElement(criterion, row.get(criterion));
result.addElement(criterion, mapCriteriaToJson(row.get(criterion)));
}
// stop if we have enough data
@ -671,13 +606,80 @@ public class GenericReport extends ReportPolicy {
return result;
}
protected StrolchRootElement mapFilterCriteria(StrolchRootElement element) {
return element;
@Override
public Stream<JsonObject> generateFilterCriteria(String type, int limit, String query) {
int maxFacetValues = getMaxFacetValues(limit);
Stream<StrolchRootElement> stream;
if (this.directCriteria.contains(type)) {
stream = prepareStreamForDirectCriteria(type, 0).map(e -> (StrolchRootElement) e);
} else {
stream = buildStream().filter(row -> row.containsKey(type)).map(row -> row.get(type)).distinct();
}
Stream<JsonObject> resultStream = filterAndMapFilterCriteria(stream, query);
if (maxFacetValues != 0)
resultStream = resultStream.limit(maxFacetValues);
return resultStream;
}
@Override
public Stream<StrolchRootElement> generateFilterCriteria(String type) {
return buildStream().filter(row -> row.containsKey(type)).map(row -> row.get(type)).distinct();
protected Stream<JsonObject> filterAndMapFilterCriteria(Stream<StrolchRootElement> stream, String query) {
Stream<JsonObject> resultStream = stream.map(this::mapCriteriaToJson);
String[] queryParts = query == null || query.isEmpty() ? null : query.split(" ");
if (queryParts != null)
resultStream = resultStream.filter(f -> contains(f.get(Tags.Json.NAME).getAsString(), queryParts, true));
return resultStream;
}
protected JsonObject mapCriteriaToJson(StrolchRootElement criterion) {
JsonObject result = new JsonObject();
result.addProperty(Tags.Json.ID, criterion.getId());
result.addProperty(Tags.Json.NAME, criterion.getName());
return result;
}
protected Stream<? extends StrolchRootElement> prepareStreamForDirectCriteria(String type, int maxFacetValues) {
StringParameter filterCriteriaP = this.filterCriteriaParams.get(type);
if (filterCriteriaP == null) {
logger.warn("Filter criteria not found for {}", type);
return Stream.empty();
}
Stream<? extends StrolchRootElement> stream = switch (filterCriteriaP.getInterpretation()) {
case INTERPRETATION_RESOURCE_REF -> tx().streamResources(filterCriteriaP.getUom());
case INTERPRETATION_ORDER_REF -> tx().streamOrders(filterCriteriaP.getUom());
case INTERPRETATION_ACTIVITY_REF -> tx().streamActivities(filterCriteriaP.getUom());
default -> throw new IllegalArgumentException(
format("Unhandled filter criteria interpretation {0} for {1}", filterCriteriaP.getInterpretation(),
filterCriteriaP.getLocator()));
};
stream = stream.filter(this::filterDirectCriteria);
if (hasOrdering())
stream = stream.sorted(this::sortDirectCriteria);
if (maxFacetValues > 0)
stream = stream.limit(maxFacetValues);
return stream;
}
private int getMaxFacetValues(int limit) {
if (limit <= 0 || limit >= MAX_FACET_VALUE_LIMIT) {
logger.warn("Overriding invalid limit {} with " + MAX_FACET_VALUE_LIMIT, limit);
limit = 100;
}
int maxFacetValues;
int reportMaxFacetValues = this.reportRes.getInteger(PARAM_MAX_FACET_VALUES);
if (reportMaxFacetValues != 0 && reportMaxFacetValues != limit) {
logger.warn("Report {} has " + PARAM_MAX_FACET_VALUES + " defined as {}. Ignoring requested limit {}",
this.reportRes.getId(), reportMaxFacetValues, limit);
maxFacetValues = reportMaxFacetValues;
} else {
maxFacetValues = limit;
}
return maxFacetValues;
}
/**
@ -705,31 +707,9 @@ public class GenericReport extends ReportPolicy {
int sortVal;
if (fieldRefP.getValue().startsWith("$")) {
Object columnValue1 = evaluateColumnValue(fieldRefP, Map.of(column1.getType(), column1), false);
Object columnValue2 = evaluateColumnValue(fieldRefP, Map.of(column2.getType(), column2), false);
if (this.descending) {
sortVal = ObjectHelper.compare(columnValue2, columnValue1, true);
} else {
sortVal = ObjectHelper.compare(columnValue1, columnValue2, true);
}
sortVal = compareFieldRef(fieldRefP, column1, column2);
} else {
Optional<Parameter<?>> param1 = lookupParameter(fieldRefP, column1, false);
Optional<Parameter<?>> param2 = lookupParameter(fieldRefP, column2, false);
if (param1.isEmpty() && param2.isEmpty())
continue;
if (param1.isPresent() && param2.isEmpty())
return 1;
else if (param1.isEmpty())
return -1;
if (this.descending)
sortVal = param2.get().compareTo(param1.get());
else
sortVal = param1.get().compareTo(param2.get());
sortVal = compareParamFieldRefP(fieldRefP, column1, column2);
}
if (sortVal != 0)
@ -765,31 +745,9 @@ public class GenericReport extends ReportPolicy {
int sortVal;
if (fieldRefP.getValue().startsWith("$")) {
Object columnValue1 = evaluateColumnValue(fieldRefP, row1, false);
Object columnValue2 = evaluateColumnValue(fieldRefP, row2, false);
if (this.descending) {
sortVal = ObjectHelper.compare(columnValue2, columnValue1, true);
} else {
sortVal = ObjectHelper.compare(columnValue1, columnValue2, true);
}
sortVal = compareFieldRef(fieldRefP, row1, row2);
} else {
Optional<Parameter<?>> param1 = lookupParameter(fieldRefP, column1, false);
Optional<Parameter<?>> param2 = lookupParameter(fieldRefP, column2, false);
if (param1.isEmpty() && param2.isEmpty())
continue;
if (param1.isPresent() && param2.isEmpty())
return 1;
else if (param1.isEmpty())
return -1;
if (this.descending)
sortVal = param2.get().compareTo(param1.get());
else
sortVal = param1.get().compareTo(param2.get());
sortVal = compareParamFieldRefP(fieldRefP, column1, column2);
}
if (sortVal != 0)
@ -799,6 +757,41 @@ public class GenericReport extends ReportPolicy {
return 0;
}
private int compareFieldRef(StringParameter fieldRefP, Map<String, StrolchRootElement> row1,
Map<String, StrolchRootElement> row2) {
Object columnValue1 = evaluateColumnValue(fieldRefP, row1, false);
Object columnValue2 = evaluateColumnValue(fieldRefP, row2, false);
if (this.descending)
return compare(columnValue2, columnValue1, true);
return compare(columnValue1, columnValue2, true);
}
private int compareFieldRef(StringParameter fieldRefP, StrolchRootElement column1, StrolchRootElement column2) {
Object columnValue1 = evaluateColumnValue(fieldRefP, Map.of(column1.getType(), column1), false);
Object columnValue2 = evaluateColumnValue(fieldRefP, Map.of(column2.getType(), column2), false);
if (this.descending)
return compare(columnValue2, columnValue1, true);
return compare(columnValue1, columnValue2, true);
}
private int compareParamFieldRefP(StringParameter fieldRefP, StrolchRootElement column1,
StrolchRootElement column2) {
Optional<Parameter<?>> param1 = lookupParameter(fieldRefP, column1, false);
Optional<Parameter<?>> param2 = lookupParameter(fieldRefP, column2, false);
if (param1.isEmpty() && param2.isEmpty())
return 0;
if (param1.isPresent() && param2.isEmpty())
return 1;
else if (param1.isEmpty())
return -1;
if (this.descending)
return param2.get().compareTo(param1.get());
return param1.get().compareTo(param2.get());
}
/**
* Returns true if a filter is defined, i.e. {@link ParameterBag ParameterBags} of type
* {@link ReportConstants#TYPE_FILTER}, a date range
@ -806,8 +799,8 @@ public class GenericReport extends ReportPolicy {
* @return true if a filter is defined
*/
protected boolean hasFilter() {
return !this.filtersByPolicy.isEmpty() || this.dateRange != null || (this.filtersById != null
&& !this.filtersById.isEmpty());
return !this.filtersByPolicy.isEmpty() || this.dateRange != null || (
this.filtersById != null && !this.filtersById.isEmpty());
}
protected boolean filterDirectCriteria(StrolchRootElement element) {
@ -893,7 +886,7 @@ public class GenericReport extends ReportPolicy {
Optional<Parameter<?>> param = lookupParameter(this.dateRangeSelP, element, false);
if (param.isEmpty() || param.get().getValueType() != StrolchValueType.DATE)
throw new IllegalStateException(
"Date Range selector is invalid, as referenced parameter is not a Date but " + (
format("Date Range selector is invalid, as referenced parameter is not a Date but {0}",
param.isPresent() ? param.get().getValueType() : "null"));
date = ((DateParameter) param.get()).getValueZdt();
@ -961,8 +954,8 @@ public class GenericReport extends ReportPolicy {
else
columnValue = parameter;
} else {
columnValue = lookupParameter(columnDefP, column, allowNull) //
.orElseGet(() -> allowNull ? null : new StringParameter(columnDefP.getValue(), columnDef, ""));
columnValue = lookupParameter(columnDefP, column, allowNull).orElseGet(
() -> allowNull ? null : new StringParameter(columnDefP.getValue(), columnDef, ""));
}
return columnValue;
@ -982,20 +975,18 @@ public class GenericReport extends ReportPolicy {
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());
throw new IllegalStateException(
format("Parameter search reference ({0}) is invalid as it does not have 3 parts for {1}", columnDef,
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());
throw new IllegalStateException(
format("Parameter search reference ({0}) is invalid as it does not have 3 parts for {1}", paramRef,
columnDefP.getLocator()));
String bagKey = locatorParts[1];
String paramKey = locatorParts[2];
@ -1018,22 +1009,18 @@ public class GenericReport extends ReportPolicy {
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());
throw new IllegalStateException(
format("Parameter reference ({0}) is invalid as it does not have 3 parts for {1}", paramRef,
paramRefP.getLocator()));
String bagKey = locatorParts[1];
String paramKey = locatorParts[2];
Parameter<?> param = element.getParameter(bagKey, paramKey);
if (!overrideAllowMissingColumns && !this.allowMissingColumns && param == null)
throw new IllegalStateException("Parameter reference ("
+ paramRef
+ ") for "
+ paramRefP.getLocator()
+ " not found on "
+ element.getLocator());
throw new IllegalStateException(
format("Parameter reference ({0}) for {1} not found on {2}", paramRef, paramRefP.getLocator(),
element.getLocator()));
return Optional.ofNullable(param);
}
@ -1058,15 +1045,17 @@ public class GenericReport extends ReportPolicy {
}
protected boolean hasJoinOnType(String type) {
return (this.reportRes.hasParameterBag(BAG_JOINS) //
&& this.reportRes.getParameterBag(BAG_JOINS).hasParameter(type)) //
|| (this.reportRes.hasParameterBag(BAG_ADDITIONAL_TYPE) //
&& this.reportRes
.getParameterBag(BAG_ADDITIONAL_TYPE)
.getString(PARAM_OBJECT_TYPE)
.equals(type)) //
|| (this.reportRes.hasParameterBag(BAG_ADDITIONAL_JOINS) //
&& this.reportRes.getParameterBag(BAG_ADDITIONAL_JOINS).hasParameter(type));
return (
this.reportRes.hasParameterBag(BAG_JOINS) && this.reportRes
.getParameterBag(BAG_JOINS)
.hasParameter(type)) || (
this.reportRes.hasParameterBag(BAG_ADDITIONAL_TYPE) && this.reportRes
.getParameterBag(BAG_ADDITIONAL_TYPE)
.getString(PARAM_OBJECT_TYPE)
.equals(type)) || (
this.reportRes.hasParameterBag(BAG_ADDITIONAL_JOINS) && this.reportRes
.getParameterBag(BAG_ADDITIONAL_JOINS)
.hasParameter(type));
}
protected Stream<? extends StrolchRootElement> getStreamFor(StringParameter objectTypeP) {
@ -1146,38 +1135,7 @@ public class GenericReport extends ReportPolicy {
return null;
}
ParameterBag relationsBag = dependency.getParameterBag(BAG_RELATIONS);
if (relationsBag == null)
throw new IllegalStateException("Invalid join definition value: "
+ joinP.getValue()
+ " on: "
+ joinP.getLocator()
+ " as "
+ dependency.getLocator()
+ " has no ParameterBag "
+ BAG_RELATIONS);
List<Parameter<?>> relationParams = relationsBag
.getParametersByInterpretationAndUom(interpretation, joinType)
.stream()
.filter(p -> p.getValueType() == StrolchValueType.STRING)
.toList();
if (relationParams.isEmpty())
throw new IllegalStateException("Found no relation parameters with UOM "
+ joinType
+ " of type "
+ StrolchValueType.STRING.getType()
+ " on dependency "
+ dependency.getLocator());
if (relationParams.size() > 1)
throw new IllegalStateException("Found multiple possible relation parameters for UOM "
+ joinType
+ " on dependency "
+ dependency.getLocator());
Parameter<?> relationParam = relationParams.get(0);
StringParameter relationP = (StringParameter) relationParam;
StringParameter relationP = getJoinRelationParam(dependency, joinP, joinType, interpretation);
if (relationP.getValue().isEmpty() && optional)
return null;
@ -1189,4 +1147,33 @@ public class GenericReport extends ReportPolicy {
refs.put(joinType, joinElem);
return joinElem;
}
private static StringParameter getJoinRelationParam(StrolchRootElement dependency, StringParameter joinP,
String joinType, String interpretation) {
ParameterBag relationsBag = dependency.getParameterBag(BAG_RELATIONS);
if (relationsBag == null)
throw new IllegalStateException(
format("Invalid join definition value: {0} on: {1} as {2} has no ParameterBag {3}",
joinP.getValue(), joinP.getLocator(), dependency.getLocator(), BAG_RELATIONS));
List<Parameter<?>> relationParams = relationsBag
.getParametersByInterpretationAndUom(interpretation, joinType)
.stream()
.filter(p -> p.getValueType() == StrolchValueType.STRING)
.toList();
if (relationParams.isEmpty())
throw new IllegalStateException(
format("Found no relation parameters with UOM {0} of type {1} on dependency {2}", joinType,
StrolchValueType.STRING.getType(), dependency.getLocator()));
if (relationParams.size() > 1)
throw new IllegalStateException("Found multiple possible relation parameters for UOM "
+ joinType
+ " on dependency "
+ dependency.getLocator());
Parameter<?> relationParam = relationParams.getFirst();
return (StringParameter) relationParam;
}
}

View File

@ -1,10 +1,5 @@
package li.strolch.report.policy;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import com.google.gson.JsonObject;
import li.strolch.model.Resource;
import li.strolch.model.StrolchRootElement;
@ -14,6 +9,11 @@ import li.strolch.report.ReportElement;
import li.strolch.utils.collections.DateRange;
import li.strolch.utils.collections.MapOfSets;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
public abstract class ReportPolicy extends StrolchPolicy {
public ReportPolicy(StrolchTransaction tx) {
@ -48,9 +48,9 @@ public abstract class ReportPolicy extends StrolchPolicy {
public abstract Stream<ReportElement> doReportWithPage(int offset, int limit);
public abstract MapOfSets<String, StrolchRootElement> generateFilterCriteria(int limit);
public abstract MapOfSets<String, JsonObject> generateFilterCriteria(int limit);
public abstract Stream<StrolchRootElement> generateFilterCriteria(String type);
public abstract Stream<JsonObject> generateFilterCriteria(String type, int limit, String query);
public abstract long getCounter();

View File

@ -1,18 +1,7 @@
package li.strolch.report;
import static java.util.stream.Collectors.toSet;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import com.google.gson.JsonObject;
import li.strolch.model.StrolchElement;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.Tags;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.model.Certificate;
import li.strolch.testbase.runtime.RuntimeMock;
@ -23,6 +12,16 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static java.util.stream.Collectors.toSet;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.*;
public class GenericReportTest {
private static final String RUNTIME_PATH = "target/GenericReportTest/";
@ -48,49 +47,49 @@ public class GenericReportTest {
public void shouldGenerateJsonReport() {
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true);
Report report = new Report(tx, "stockReport")) {
Report report = new Report(tx, "stockReport")) {
report.doReportAsJson() //
.forEach(e -> {
switch (e.get("slot").getAsString()) {
case "Slot 1" -> {
assertEquals("Product 01", e.get("product").getAsString());
assertEquals("20.0", e.get("quantity").getAsString());
assertEquals("40.0", e.get("maxQuantity").getAsString());
assertEquals("4.0", e.get("minQuantity").getAsString());
assertEquals("Section 001", e.get("section").getAsString());
assertEquals("Storage 01", e.get("storage").getAsString());
assertEquals("Location 01", e.get("location").getAsString());
}
case "Slot 2" -> {
assertEquals("Product 02", e.get("product").getAsString());
assertEquals("18.0", e.get("quantity").getAsString());
assertEquals("20.0", e.get("maxQuantity").getAsString());
assertEquals("4.0", e.get("minQuantity").getAsString());
assertEquals("Section 001", e.get("section").getAsString());
assertEquals("Storage 01", e.get("storage").getAsString());
assertEquals("Location 01", e.get("location").getAsString());
}
case "Slot 3" -> {
assertEquals("Product 01", e.get("product").getAsString());
assertEquals("11.0", e.get("quantity").getAsString());
assertEquals("40.0", e.get("maxQuantity").getAsString());
assertEquals("6.0", e.get("minQuantity").getAsString());
assertEquals("Section 002", e.get("section").getAsString());
assertEquals("Storage 02", e.get("storage").getAsString());
assertEquals("Location 02", e.get("location").getAsString());
}
case "Slot 4" -> {
assertEquals("Product 02", e.get("product").getAsString());
assertEquals("16.0", e.get("quantity").getAsString());
assertEquals("20.0", e.get("maxQuantity").getAsString());
assertEquals("6.0", e.get("minQuantity").getAsString());
assertEquals("Section 002", e.get("section").getAsString());
assertEquals("Storage 02", e.get("storage").getAsString());
assertEquals("Location 02", e.get("location").getAsString());
}
default -> fail("Unhandled result element: \n" + e);
case "Slot 1" -> {
assertEquals("Product 01", e.get("product").getAsString());
assertEquals("20.0", e.get("quantity").getAsString());
assertEquals("40.0", e.get("maxQuantity").getAsString());
assertEquals("4.0", e.get("minQuantity").getAsString());
assertEquals("Section 001", e.get("section").getAsString());
assertEquals("Storage 01", e.get("storage").getAsString());
assertEquals("Location 01", e.get("location").getAsString());
}
case "Slot 2" -> {
assertEquals("Product 02", e.get("product").getAsString());
assertEquals("18.0", e.get("quantity").getAsString());
assertEquals("20.0", e.get("maxQuantity").getAsString());
assertEquals("4.0", e.get("minQuantity").getAsString());
assertEquals("Section 001", e.get("section").getAsString());
assertEquals("Storage 01", e.get("storage").getAsString());
assertEquals("Location 01", e.get("location").getAsString());
}
case "Slot 3" -> {
assertEquals("Product 01", e.get("product").getAsString());
assertEquals("11.0", e.get("quantity").getAsString());
assertEquals("40.0", e.get("maxQuantity").getAsString());
assertEquals("6.0", e.get("minQuantity").getAsString());
assertEquals("Section 002", e.get("section").getAsString());
assertEquals("Storage 02", e.get("storage").getAsString());
assertEquals("Location 02", e.get("location").getAsString());
}
case "Slot 4" -> {
assertEquals("Product 02", e.get("product").getAsString());
assertEquals("16.0", e.get("quantity").getAsString());
assertEquals("20.0", e.get("maxQuantity").getAsString());
assertEquals("6.0", e.get("minQuantity").getAsString());
assertEquals("Section 002", e.get("section").getAsString());
assertEquals("Storage 02", e.get("storage").getAsString());
assertEquals("Location 02", e.get("location").getAsString());
}
default -> fail("Unhandled result element: \n" + e);
}
});
}
@ -100,7 +99,7 @@ public class GenericReportTest {
public void shouldFilterReport1() {
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true);
Report report = new Report(tx, "stockReport")) {
Report report = new Report(tx, "stockReport")) {
report.filter("Product", "product01") //
.doReportAsJson() //
@ -108,12 +107,12 @@ public class GenericReportTest {
String slotName = e.get("slot").getAsString();
switch (slotName) {
case "Slot 1":
case "Slot 3":
break;
default:
fail("Unexpected slot name " + slotName + ", should have been filtered!");
break;
case "Slot 1":
case "Slot 3":
break;
default:
fail("Unexpected slot name " + slotName + ", should have been filtered!");
break;
}
});
}
@ -123,7 +122,7 @@ public class GenericReportTest {
public void shouldFilterReport2() {
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true);
Report report = new Report(tx, "stockReport")) {
Report report = new Report(tx, "stockReport")) {
report.filter("Product", "product01") //
.filter("Location", "location02") //
@ -144,7 +143,7 @@ public class GenericReportTest {
Date from = new Date(LocalDate.of(2016, 1, 1).toEpochDay() * 86400000);
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true);
Report report = new Report(tx, "stockReport")) {
Report report = new Report(tx, "stockReport")) {
Date to = new Date(LocalDate.of(2017, 1, 1).toEpochDay() * 86400000);
DateRange dateRange = new DateRange().from(from, true).to(to, false);
@ -158,7 +157,7 @@ public class GenericReportTest {
}
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true);
Report report = new Report(tx, "stockReport")) {
Report report = new Report(tx, "stockReport")) {
Date to = new Date(LocalDate.of(2017, 3, 1).toEpochDay() * 86400000);
DateRange dateRange = new DateRange().from(from, true).to(to, false);
@ -185,7 +184,10 @@ public class GenericReportTest {
Date to = new Date(LocalDate.of(2017, 1, 1).toEpochDay() * 86400000);
DateRange dateRange = new DateRange().from(from, true).to(to, false);
List<JsonObject> result = report.filter("Product", "product01").dateRange(dateRange).doReportAsJson()
List<JsonObject> result = report
.filter("Product", "product01")
.dateRange(dateRange)
.doReportAsJson()
.toList();
assertTrue(result.isEmpty());
}
@ -196,7 +198,10 @@ public class GenericReportTest {
Date to = new Date(LocalDate.of(2017, 3, 1).toEpochDay() * 86400000);
DateRange dateRange = new DateRange().from(from, true).to(to, false);
List<JsonObject> result = report.filter("Product", "product01").dateRange(dateRange).doReportAsJson()
List<JsonObject> result = report
.filter("Product", "product01")
.dateRange(dateRange)
.doReportAsJson()
.toList();
assertEquals(2, result.size());
}
@ -207,8 +212,11 @@ public class GenericReportTest {
Date to = new Date(LocalDate.of(2017, 3, 2).toEpochDay() * 86400000);
DateRange dateRange = new DateRange().from(from, true).to(to, false);
List<JsonObject> result = report.filter("Product", "product01", "product02").dateRange(dateRange)
.doReportAsJson().toList();
List<JsonObject> result = report
.filter("Product", "product01", "product02")
.dateRange(dateRange)
.doReportAsJson()
.toList();
assertEquals(4, result.size());
}
}
@ -218,21 +226,27 @@ public class GenericReportTest {
public void shouldCreateFilterCriteria() {
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true);
Report report = new Report(tx, "stockReport")) {
Report report = new Report(tx, "stockReport")) {
MapOfSets<String, StrolchRootElement> filterCriteria = report.generateFilterCriteria(1000);
MapOfSets<String, JsonObject> filterCriteria = report.generateFilterCriteria(1000);
assertFalse(filterCriteria.containsSet("Location"));
assertFalse(filterCriteria.containsSet("Slot"));
MatcherAssert
.assertThat(filterCriteria.getSet("Product").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("product01", "product02"));
MatcherAssert
.assertThat(filterCriteria.getSet("Storage").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("storage01", "storage02"));
MatcherAssert
.assertThat(filterCriteria.getSet("Section").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("section001", "section002"));
MatcherAssert.assertThat(filterCriteria
.getSet("Product")
.stream()
.map(e -> e.get(Tags.Json.ID).getAsString())
.collect(toSet()), containsInAnyOrder("product01", "product02"));
MatcherAssert.assertThat(filterCriteria
.getSet("Storage")
.stream()
.map(e -> e.get(Tags.Json.ID).getAsString())
.collect(toSet()), containsInAnyOrder("storage01", "storage02"));
MatcherAssert.assertThat(filterCriteria
.getSet("Section")
.stream()
.map(e -> e.get(Tags.Json.ID).getAsString())
.collect(toSet()), containsInAnyOrder("section001", "section002"));
}
}
@ -240,9 +254,10 @@ public class GenericReportTest {
public void shouldCreateFilterCriteriaFiltered1() {
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true);
Report report = new Report(tx, "stockReport")) {
Report report = new Report(tx, "stockReport")) {
MapOfSets<String, StrolchRootElement> filterCriteria = report.filter("Product", "product01")
MapOfSets<String, JsonObject> filterCriteria = report
.filter("Product", "product01")
.generateFilterCriteria(1000);
// assert sequence of filter criteria is correct
@ -254,15 +269,21 @@ public class GenericReportTest {
assertFalse(filterCriteria.containsSet("Location"));
assertFalse(filterCriteria.containsSet("Slot"));
MatcherAssert
.assertThat(filterCriteria.getSet("Product").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("product01"));
MatcherAssert
.assertThat(filterCriteria.getSet("Storage").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("storage01", "storage02"));
MatcherAssert
.assertThat(filterCriteria.getSet("Section").stream().map(StrolchElement::getId).collect(toSet()),
containsInAnyOrder("section001", "section002"));
MatcherAssert.assertThat(filterCriteria
.getSet("Product")
.stream()
.map(e -> e.get(Tags.Json.ID).getAsString())
.collect(toSet()), containsInAnyOrder("product01"));
MatcherAssert.assertThat(filterCriteria
.getSet("Storage")
.stream()
.map(e -> e.get(Tags.Json.ID).getAsString())
.collect(toSet()), containsInAnyOrder("storage01", "storage02"));
MatcherAssert.assertThat(filterCriteria
.getSet("Section")
.stream()
.map(e -> e.get(Tags.Json.ID).getAsString())
.collect(toSet()), containsInAnyOrder("section001", "section002"));
}
}
@ -270,13 +291,13 @@ public class GenericReportTest {
public void shouldCreateFilterCriteriaFiltered2() {
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true);
Report report = new Report(tx, "stockReport")) {
Report report = new Report(tx, "stockReport")) {
Date from = new Date(LocalDate.of(2017, 3, 1).toEpochDay() * 86400000);
Date to = new Date(LocalDate.of(2017, 3, 5).toEpochDay() * 86400000);
DateRange dateRange = new DateRange().from(from, true).to(to, false);
MapOfSets<String, StrolchRootElement> filterCriteria = report //
MapOfSets<String, JsonObject> filterCriteria = report //
.dateRange(dateRange) //
.filter("Product", "product01") //
.generateFilterCriteria(1000);
@ -289,26 +310,26 @@ public class GenericReportTest {
public void shouldDoAdditionalJoin() {
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true);
Report report = new Report(tx, "slotsByOrderUsageReport")) {
Report report = new Report(tx, "slotsByOrderUsageReport")) {
AtomicInteger slotsFound = new AtomicInteger();
report.doReportAsJson().forEach(e -> {
switch (e.get("slot").getAsString()) {
case "Slot 1", "Slot 3" -> {
assertEquals("Harry", e.get("firstName").getAsString());
assertEquals("Barns", e.get("lastName").getAsString());
slotsFound.getAndIncrement();
}
case "Slot 2", "Slot 4", "Slot 5" -> {
assertEquals("Geoffrey", e.get("firstName").getAsString());
assertEquals("Bobcat", e.get("lastName").getAsString());
slotsFound.getAndIncrement();
}
case "Slot 6" -> {
assertEquals("", e.get("firstName").getAsString());
slotsFound.getAndIncrement();
}
case "Slot 1", "Slot 3" -> {
assertEquals("Harry", e.get("firstName").getAsString());
assertEquals("Barns", e.get("lastName").getAsString());
slotsFound.getAndIncrement();
}
case "Slot 2", "Slot 4", "Slot 5" -> {
assertEquals("Geoffrey", e.get("firstName").getAsString());
assertEquals("Bobcat", e.get("lastName").getAsString());
slotsFound.getAndIncrement();
}
case "Slot 6" -> {
assertEquals("", e.get("firstName").getAsString());
slotsFound.getAndIncrement();
}
}
});

View File

@ -104,8 +104,8 @@ public class I18nMessage {
} catch (MissingResourceException e) {
if (!missingKeysMap.containsSet(baseName + "_" + locale.toLanguageTag())) {
logger.error("Failed to find resource bundle " + baseName + " " + locale.toLanguageTag()
+ ", returning current bundle " + this.bundle.getLocale().toLanguageTag());
logger.error("Failed to find resource bundle {} {}, returning current bundle {}", baseName,
locale.toLanguageTag(), this.bundle.getLocale().toLanguageTag());
missingKeysMap.addSet(baseName + "_" + locale.toLanguageTag(), emptySet());
}
return this.bundle;
@ -123,10 +123,10 @@ public class I18nMessage {
if (isEmpty(this.bundleName))
return getMessage();
if (!missingKeysMap.containsSet(this.bundleName + "_" + locale.toLanguageTag())) {
logger.warn("No bundle found for " + this.bundleName + " " + locale + ". Available are: ");
logger.warn("No bundle found for {} {}. Available are: ", this.bundleName, locale);
getBundleMap().forEach((s, map) -> {
logger.info(" " + s);
map.forEach((l, resourceBundle) -> logger.info(" " + l + ": " + map.keySet()));
logger.info(" {}", s);
map.forEach((l, resourceBundle) -> logger.info(" {}: {}", l, map.keySet()));
});
missingKeysMap.addSet(this.bundleName + "_" + locale.toLanguageTag(), emptySet());
}
@ -192,7 +192,7 @@ public class I18nMessage {
String languageTag = bundle.getLocale().toLanguageTag();
String bundleKey = baseName + "_" + languageTag;
if (!missingKeysMap.containsElement(bundleKey, this.key)) {
logger.error("Key " + this.key + " is missing in bundle " + baseName + " for locale " + languageTag);
logger.error("Key {} is missing in bundle {} for locale {}", this.key, baseName, languageTag);
missingKeysMap.addElement(bundleKey, this.key);
}
@ -265,14 +265,14 @@ public class I18nMessage {
try {
CodeSource src = I18nMessage.class.getProtectionDomain().getCodeSource();
if (src == null) {
logger.error(
"Failed to find CodeSource for ProtectionDomain " + I18nMessage.class.getProtectionDomain());
logger.error("Failed to find CodeSource for ProtectionDomain {}",
I18nMessage.class.getProtectionDomain());
return;
}
File jarLocationF = new File(src.getLocation().toURI());
if (!(jarLocationF.exists() && jarLocationF.getParentFile().isDirectory())) {
logger.info("Found JAR repository at " + jarLocationF.getParentFile());
logger.info("Found JAR repository at {}", jarLocationF.getParentFile());
return;
}
@ -292,16 +292,10 @@ public class I18nMessage {
JarEntry je = entries.nextElement();
String entryName = je.getName();
if (entryName.startsWith("META-INF") //
|| entryName.equals("ENV.properties") //
|| entryName.equals("agentVersion.properties") //
|| entryName.equals("appVersion.properties") //
|| entryName.equals("componentVersion.properties") //
|| entryName.equals("strolch_db_version.properties"))
if (!entryName.endsWith(".properties"))
continue;
if (!entryName.endsWith(".properties"))
if (shouldIgnorePropertyFile(entryName))
continue;
TypedTuple<String, Locale> tuple = parsePropertyName(entryName);
@ -316,23 +310,21 @@ public class I18nMessage {
bundleMap.addElement(bundle.getBaseBundleName(), bundle.getLocale(), bundle);
String propertyName = entryName.replace('/', '.');
logger.info(
" Loaded bundle " + bundle.getBaseBundleName() + " " + bundle.getLocale() + " from "
+ propertyName + " from JAR " + file.getName());
logger.info(" Loaded bundle {} {} from {} from JAR {}", bundle.getBaseBundleName(),
bundle.getLocale(), propertyName, file.getName());
}
}
}
File classesD = new File(jarD.getParentFile(), "classes");
if (classesD.isDirectory()) {
File[] propertyFiles = classesD.listFiles(
(dir, name) -> name.endsWith(".properties") && !(name.equals("appVersion.properties")
|| name.equals("ENV.properties")));
File[] propertyFiles = classesD.listFiles((dir, name) -> name.endsWith(".properties") && !(
name.equals("appVersion.properties") || name.equals("ENV.properties")));
if (propertyFiles != null) {
for (File propertyFile : propertyFiles) {
logger.info(" Found property file " + propertyFile.getName() + " in classes "
+ classesD.getAbsolutePath());
logger.info(" Found property file {} in classes {}", propertyFile.getName(),
classesD.getAbsolutePath());
TypedTuple<String, Locale> tuple = parsePropertyName(propertyFile.getName());
if (tuple == null)
@ -346,8 +338,8 @@ public class I18nMessage {
}
bundleMap.addElement(bundle.getBaseBundleName(), bundle.getLocale(), bundle);
logger.info(" Loaded bundle " + bundle.getBaseBundleName() + " " + bundle.getLocale()
+ " from file " + propertyFile.getName());
logger.info(" Loaded bundle {} {} from file {}", bundle.getBaseBundleName(),
bundle.getLocale(), propertyFile.getName());
}
}
}
@ -378,17 +370,17 @@ public class I18nMessage {
int languageI = Arrays.binarySearch(Locale.getISOLanguages(), language);
int countryI = Arrays.binarySearch(Locale.getISOCountries(), country);
if (languageI >= 0 && countryI >= 0)
locale = new Locale(language, country);
locale = Locale.of(language, country);
else {
logger.warn("Ignoring bad bundle locale for " + entryName);
logger.warn("Ignoring malformed bad bundle locale for {}", entryName);
return null;
}
} else {
int languageI = Arrays.binarySearch(Locale.getISOLanguages(), localeS);
if (languageI >= 0)
locale = new Locale(localeS);
locale = Locale.forLanguageTag(localeS);
else {
logger.warn("Ignoring bad bundle locale for " + entryName);
logger.warn("Ignoring bad bundle locale for {}", entryName);
return null;
}
}
@ -401,6 +393,7 @@ public class I18nMessage {
}
private static class CustomControl extends ResourceBundle.Control {
private final InputStream stream;
public CustomControl(InputStream stream) {
@ -414,65 +407,76 @@ public class I18nMessage {
}
}
private static boolean shouldIgnorePropertyFile(String name) {
return name.startsWith("META-INF")
|| name.equals("ENV.properties")
|| name.equals("agentVersion.properties")
|| name.equals("appVersion.properties")
|| name.equals("componentVersion.properties")
|| name.contains("_db_version");
}
private static boolean shouldIgnoreFile(File file) {
return file.getName().contains("aopalliance") //
|| file.getName().contains("activation") //
|| file.getName().contains("antlr") //
|| file.getName().contains("assertj-core") //
|| file.getName().startsWith("com.sun") //
|| file.getName().startsWith("commonj.") //
|| file.getName().startsWith("commons-") //
|| file.getName().startsWith("jackson-") //
|| file.getName().startsWith("hapi-") //
|| file.getName().startsWith("jaxb-") //
|| file.getName().startsWith("org.hl7.") //
|| file.getName().startsWith("listenablefuture-") //
|| file.getName().startsWith("j2objc-annotations") //
|| file.getName().startsWith("failureaccess-") //
|| file.getName().startsWith("error_prone_") //
|| file.getName().startsWith("guava-") //
|| file.getName().startsWith("org.eclipse") //
|| file.getName().startsWith("javax") //
|| file.getName().startsWith("jaxws") //
|| file.getName().startsWith("jaxrs") //
|| file.getName().startsWith("jaxb") //
|| file.getName().contains("jsr305") //
|| file.getName().contains("c3p0") //
|| file.getName().contains("camel") //
|| file.getName().contains("checker-qual") //
|| file.getName().contains("cron") //
|| file.getName().contains("FastInfoset") //
|| file.getName().contains("gmbal") //
|| file.getName().contains("grizzly") //
|| file.getName().contains("gson") //
|| file.getName().contains("ha-api") //
|| file.getName().contains("HikariCP") //
|| file.getName().contains("hk2") //
|| file.getName().contains("icu4j") //
|| file.getName().contains("jakarta") //
|| file.getName().contains("javassist") //
|| file.getName().contains("jersey") //
|| file.getName().contains("joda-time") //
|| file.getName().contains("logback") //
|| file.getName().contains("management-api") //
|| file.getName().contains("mchange-commons-java") //
|| file.getName().contains("mimepull") //
|| file.getName().contains("org.abego.treelayout") //
|| file.getName().contains("osgi") //
|| file.getName().contains("pfl-basic") //
|| file.getName().contains("pfl-tf") //
|| file.getName().contains("policy-2.7.10") //
|| file.getName().contains("postgresql") //
|| file.getName().contains("quartz") //
|| file.getName().contains("saaj-impl") //
|| file.getName().contains("sax") //
|| file.getName().contains("slf4j") //
|| file.getName().contains("ST4") //
|| file.getName().contains("stax-ex") //
|| file.getName().contains("stax2-api") //
|| file.getName().contains("streambuffer") //
|| file.getName().contains("tyrus") //
|| file.getName().contains("validation-api") //
|| file.getName().contains("yasson");
String name = file.getName();
return name.contains("aopalliance")
|| name.contains("activation")
|| name.contains("antlr")
|| name.contains("assertj-core")
|| name.startsWith("com.sun")
|| name.startsWith("commonj.")
|| name.startsWith("commons-")
|| name.startsWith("jackson-")
|| name.startsWith("hapi-")
|| name.startsWith("jaxb-")
|| name.startsWith("org.hl7.")
|| name.startsWith("org.glassfish.")
|| name.startsWith("listenablefuture-")
|| name.startsWith("j2objc-annotations")
|| name.startsWith("failureaccess-")
|| name.startsWith("error_prone_")
|| name.startsWith("guava-")
|| name.startsWith("org.eclipse")
|| name.startsWith("javax")
|| name.startsWith("jaxws")
|| name.startsWith("jaxrs")
|| name.startsWith("jaxb")
|| name.contains("jsr305")
|| name.contains("c3p0")
|| name.contains("camel")
|| name.contains("checker-qual")
|| name.contains("cron")
|| name.contains("FastInfoset")
|| name.contains("gmbal")
|| name.contains("grizzly")
|| name.contains("gson")
|| name.contains("ha-api")
|| name.contains("HikariCP")
|| name.contains("hk2")
|| name.contains("icu4j")
|| name.contains("jakarta")
|| name.contains("javassist")
|| name.contains("jersey")
|| name.contains("joda-time")
|| name.contains("logback")
|| name.contains("management-api")
|| name.contains("mchange-commons-java")
|| name.contains("mimepull")
|| name.contains("org.abego.treelayout")
|| name.contains("osgi")
|| name.contains("pfl-basic")
|| name.contains("pfl-tf")
|| name.contains("policy-2.7.10")
|| name.contains("postgresql")
|| name.contains("quartz")
|| name.contains("saaj-impl")
|| name.contains("sax")
|| name.contains("slf4j")
|| name.contains("ST4")
|| name.contains("stax-ex")
|| name.contains("stax2-api")
|| name.contains("streambuffer")
|| name.contains("tyrus")
|| name.contains("validation-api")
|| name.contains("yasson");
}
}

View File

@ -224,6 +224,19 @@ public class ExceptionHelper {
return getExceptionMessage(getRootCause(throwable), true);
}
/**
* Returns {@link #getExceptionMessage(Throwable, boolean)} for the root cause of the given {@link Throwable}
*
* @param throwable the throwable for which to get the message of the root cause
* @param withClassName if true, then exception class name is prepended to the exception message, if the exception
* message is null, then this param is ignored
*
* @return {@link #getExceptionMessage(Throwable, boolean)} for the root cause of the given {@link Throwable}
*/
public static String getRootCauseMessage(Throwable throwable, boolean withClassName) {
return getExceptionMessage(getRootCause(throwable), withClassName);
}
/**
* Walks the causes for the given {@link Throwable} and sees if the given cause exists
*

View File

@ -204,10 +204,7 @@ public class RestfulStrolchComponent extends StrolchComponent {
@Override
public void start() throws Exception {
if (instance == null)
instance = this;
else if (instance != this)
throw new IllegalStateException("Instance is already set! This component is a singleton resource!");
instance = this;
super.start();
}

View File

@ -75,13 +75,21 @@ public class ReportResource {
try (StrolchTransaction tx = getInstance().openTx(cert, realm, getContext())) {
StrolchRootElementToJsonVisitor visitor = new StrolchRootElementToJsonVisitor().flat().withoutVersion()
.withoutObjectType().withoutPolicies().withoutStateVariables()
.ignoreBags(BAG_JOINS, BAG_COLUMNS, BAG_ORDERING, BAG_ADDITIONAL_TYPE).ignoreBagByType(TYPE_FILTER)
StrolchRootElementToJsonVisitor visitor = new StrolchRootElementToJsonVisitor()
.flat()
.withoutVersion()
.withoutObjectType()
.withoutPolicies()
.withoutStateVariables()
.ignoreBags(BAG_JOINS, BAG_COLUMNS, BAG_ORDERING, BAG_ADDITIONAL_TYPE)
.ignoreBagByType(TYPE_FILTER)
.resourceHook((reportRes, reportJ) -> reportJ.addProperty(PARAM_DATE_RANGE,
reportRes.hasParameter(BAG_PARAMETERS, PARAM_DATE_RANGE_SEL)));
JsonArray result = new ReportSearch(tx).search(tx).orderByName(false)
.map(resource -> resource.accept(visitor)).asStream()
JsonArray result = new ReportSearch(tx)
.search(tx)
.orderByName(false)
.map(resource -> resource.accept(visitor))
.asStream()
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
return ResponseUtil.toResponse(DATA, result);
@ -103,7 +111,8 @@ public class ReportResource {
File localesF = new File(request.getServletContext().getRealPath(LOCALES_JSON));
JsonObject localeJ = null;
if (localesF.exists()) {
JsonObject localesJ = JsonParser.parseString(new String(Files.readAllBytes(localesF.toPath())))
JsonObject localesJ = JsonParser
.parseString(new String(Files.readAllBytes(localesF.toPath())))
.getAsJsonObject();
if (localesJ.has(cert.getLocale().toLanguageTag()))
localeJ = localesJ.get(cert.getLocale().toLanguageTag()).getAsJsonObject();
@ -124,21 +133,19 @@ public class ReportResource {
JsonArray facetsJ = new JsonArray();
JsonObject finalLocaleJ = localeJ;
MapOfSets<String, StrolchRootElement> criteria = report.generateFilterCriteria(limit);
MapOfSets<String, JsonObject> criteria = report.generateFilterCriteria(limit);
criteria.keySet().stream().sorted(comparing(type -> {
JsonElement translatedJ = finalLocaleJ == null ? null : finalLocaleJ.get(type);
return translatedJ == null ? type : translatedJ.getAsString();
})).forEach(type -> {
Set<StrolchRootElement> elements = criteria.getSet(type);
Set<JsonObject> elements = criteria.getSet(type);
JsonObject filter = new JsonObject();
filter.addProperty(Tags.Json.TYPE, type);
filter.add(Tags.Json.VALUES, elements.stream().sorted(comparing(StrolchElement::getName)).map(f -> {
JsonObject o = new JsonObject();
o.addProperty(Tags.Json.ID, f.getId());
o.addProperty(Tags.Json.NAME, f.getName());
return o;
}).collect(JsonArray::new, JsonArray::add, JsonArray::addAll));
filter.add(Tags.Json.VALUES, elements
.stream()
.sorted(comparing(e -> e.get(Tags.Json.NAME).getAsString()))
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll));
facetsJ.add(filter);
});
@ -148,7 +155,7 @@ public class ReportResource {
result.addProperty(PARAM_DURATION, duration);
result.addProperty(PARAM_PARALLEL, report.isParallel());
logger.info("Facet Generation for " + id + " took: " + duration);
logger.info("Facet Generation for {} took: {}", id, duration);
return ResponseUtil.toResponse(DATA, result);
}
}
@ -171,7 +178,8 @@ public class ReportResource {
File localesF = new File(request.getServletContext().getRealPath(LOCALES_JSON));
JsonObject localeJ = null;
if (localesF.exists()) {
JsonObject localesJ = JsonParser.parseString(new String(Files.readAllBytes(localesF.toPath())))
JsonObject localesJ = JsonParser
.parseString(new String(Files.readAllBytes(localesF.toPath())))
.getAsJsonObject();
if (localesJ.has(cert.getLocale().toLanguageTag()))
localeJ = localesJ.get(cert.getLocale().toLanguageTag()).getAsJsonObject();
@ -189,37 +197,13 @@ public class ReportResource {
report.getReportPolicy().setI18nData(localeJ);
// get filter criteria
Stream<StrolchRootElement> criteria = report.generateFilterCriteria(type);
if (query != null && !query.isEmpty()) {
String[] parts = query.split(" ");
criteria = criteria.filter(f -> ObjectHelper.contains(f.getName(), parts, true));
}
int maxFacetValues;
int reportMaxFacetValues = report.getReportResource().getInteger(PARAM_MAX_FACET_VALUES);
if (reportMaxFacetValues != 0 && reportMaxFacetValues != limit) {
logger.warn("Report " + report.getReportResource().getId() + " has " + PARAM_MAX_FACET_VALUES +
" defined as " + reportMaxFacetValues + ". Ignoring requested limit " + limit);
maxFacetValues = reportMaxFacetValues;
} else {
maxFacetValues = limit;
}
criteria = criteria.sorted(comparing(StrolchElement::getName));
if (maxFacetValues != 0)
criteria = criteria.limit(maxFacetValues);
// add the data finally
JsonArray array = criteria.map(f -> {
JsonObject o = new JsonObject();
o.addProperty(Tags.Json.ID, f.getId());
o.addProperty(Tags.Json.NAME, f.getName());
return o;
}).collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
JsonArray array = report
.generateFilterCriteria(type, limit, query)
.sorted(comparing(e -> e.get(Tags.Json.NAME).getAsString()))
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
String duration = formatNanoDuration(System.nanoTime() - start);
logger.info("Facet Generation for " + id + "." + type + " took: " + duration);
logger.info("Facet Generation for {}.{} took: {}", id, type, duration);
return ResponseUtil.toResponse(DATA, array);
}
}
@ -273,7 +257,8 @@ public class ReportResource {
File localesF = new File(request.getServletContext().getRealPath(LOCALES_JSON));
JsonObject localeJ = null;
if (localesF.exists()) {
JsonObject localesJ = JsonParser.parseString(new String(Files.readAllBytes(localesF.toPath())))
JsonObject localesJ = JsonParser
.parseString(new String(Files.readAllBytes(localesF.toPath())))
.getAsJsonObject();
if (localesJ.has(cert.getLocale().toLanguageTag()))
localeJ = localesJ.get(cert.getLocale().toLanguageTag()).getAsJsonObject();
@ -349,7 +334,7 @@ public class ReportResource {
finalResult.addProperty(PARAM_DURATION, duration);
finalResult.addProperty(PARAM_PARALLEL, report.isParallel());
logger.info(id + " Report took: " + duration);
logger.info("{} Report took: {}", id, duration);
return ResponseUtil.toResponse(DATA, finalResult);
}
}
@ -400,7 +385,8 @@ public class ReportResource {
File localesF = new File(request.getServletContext().getRealPath(LOCALES_JSON));
JsonObject localeJ = null;
if (localesF.exists()) {
JsonObject localesJ = JsonParser.parseString(new String(Files.readAllBytes(localesF.toPath())))
JsonObject localesJ = JsonParser
.parseString(new String(Files.readAllBytes(localesF.toPath())))
.getAsJsonObject();
if (localesJ.has(cert.getLocale().toLanguageTag()))
localeJ = localesJ.get(cert.getLocale().toLanguageTag()).getAsJsonObject();
@ -411,8 +397,10 @@ public class ReportResource {
// send
String fileName = id + "_" + System.currentTimeMillis() + ".csv";
return Response.ok(out, TEXT_CSV_TYPE)
.header("Content-Disposition", "attachment; filename=\"" + fileName + "\"").build();
return Response
.ok(out, TEXT_CSV_TYPE)
.header("Content-Disposition", "attachment; filename=\"" + fileName + "\"")
.build();
}
private StreamingOutput getOut(Certificate cert, String realm, String reportId, JsonObject localeJ,
@ -485,12 +473,14 @@ public class ReportResource {
// go through all filters and add to the map of sets
for (JsonElement elem : filters.getAsJsonArray()) {
if (!elem.isJsonObject()) {
logger.warn("There are wrong formatted filters:\n" + elem);
logger.warn("There are wrong formatted filters:\n{}", elem);
continue;
}
JsonObject filter = elem.getAsJsonObject();
filter.get(PARAM_FACET_FILTERS).getAsJsonArray()
filter
.get(PARAM_FACET_FILTERS)
.getAsJsonArray()
.forEach(f -> result.addElement(filter.get(PARAM_FACET_TYPE).getAsString(), f.getAsString()));
}