package org.simantics.district.network.techtype;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import org.simantics.Simantics;
import org.simantics.databoard.binding.error.BindingException;
import org.simantics.databoard.type.Datatype;
import org.simantics.databoard.type.NumberType;
+import org.simantics.databoard.type.StringType;
import org.simantics.databoard.util.Range;
import org.simantics.databoard.util.RangeException;
import org.simantics.db.ReadGraph;
import org.simantics.db.Resource;
+import org.simantics.db.Statement;
import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.request.IndexRoot;
import org.simantics.db.common.request.ResourceRead;
import org.simantics.db.common.request.UniqueRead;
import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.QueryIndexUtils;
import org.simantics.db.layer0.request.PropertyInfo;
import org.simantics.db.layer0.request.PropertyInfoRequest;
import org.simantics.district.network.ontology.DistrictNetworkResource;
+import org.simantics.district.network.techtype.requests.PossibleTechTypeKeyName;
import org.simantics.district.network.techtype.requests.TechTypeTableData;
import org.simantics.layer0.Layer0;
import org.slf4j.Logger;
continue;
}
- String valueString = values.get(propertyName).replace(",", ".");
- try {
- Double num = Double.valueOf(valueString);
- NumberBinding binding = (NumberBinding)info.defaultBinding;
- Number value = (Number) binding.create(num);
-
- if (!rng.contains(value)) {
- LOGGER.trace(" {} - range violation {} / {}", propertyName, valueString, range);
- result.add(code + "/" + propertyName);
- } else {
- LOGGER.trace(" {} - valid value {} / {}", propertyName, valueString, range);
- }
- } catch (NumberFormatException e) {
+ Number value = getPossibleNumericValue(info, values.get(propertyName));
+ if (value == null) {
// Nothing to do here, treat non-numeric strings as missing values
- LOGGER.trace(" {} - no value {} / {}", propertyName, valueString, range);
- } catch (BindingException e) {
- LOGGER.error("Binding error for property {}", propertyName, e);
+ LOGGER.trace(" {} - no value {} / {}", propertyName, values.get(propertyName), range);
+ } else if (!rng.contains(value)) {
+ LOGGER.trace(" {} - range violation {} / {}", propertyName, values.get(propertyName), range);
+ result.add(code + "/" + propertyName);
+ } else {
+ LOGGER.trace(" {} - valid value {} / {}", propertyName, values.get(propertyName), range);
}
}
}
}
});
}
+
+ /**
+ * Find all component properties that do not match the value given in a tech type table.
+ *
+ * @param table A TechTypeTable instance
+ * @return Lists of all non-matching properties, indexed by component resource
+ * @throws DatabaseException
+ */
+ public static Map<Resource, List<PropertyInfo>> findConsistencyViolations(Resource table) throws DatabaseException {
+ LOGGER.trace("Validating resource table {}", table);
+
+ // Use a unique read - we don't want to pollute the cache with this
+ return Simantics.getSession().syncRequest(new UniqueRead<Map<Resource, List<PropertyInfo>>>() {
+ @Override
+ public Map<Resource, List<PropertyInfo>> perform(ReadGraph graph) throws DatabaseException {
+ Resource type = graph.getPossibleObject(table, DistrictNetworkResource.getInstance(graph).TechType_TechTypeTable_HasComponentType);
+ if (type == null)
+ return Collections.emptyMap();
+
+ Resource model = graph.syncRequest(new IndexRoot(table));
+ Map<String, PropertyInfo> props = graph.syncRequest(new PropertyInfoMapOfType(type), TransientCacheListener.instance());
+
+ String keyName = graph.syncRequest(new PossibleTechTypeKeyName(type));
+ PropertyInfo keyPredicate = props.get(keyName);
+
+ if (keyName.startsWith("_"))
+ keyName = keyName.substring(1);
+
+ Map<String, Map<String, String>> data = graph.syncRequest(new TechTypeTableData(table), TransientCacheListener.instance());
+ Map<Resource, List<PropertyInfo>> result = new HashMap<>();
+
+ for (Resource component : QueryIndexUtils.searchByType(graph, model, type)) {
+ String key = graph.getRelatedValue2(component, keyPredicate.predicate);
+ Map<String, String> values = data.get(key);
+ if (values == null) {
+ // Highlight the missing tech type key
+ addMapListItem(result, component, keyPredicate);
+ continue;
+ }
+
+ for (PropertyInfo prop : props.values()) {
+ if (!prop.isHasProperty)
+ continue;
+
+ String valueString = values.get(prop.name);
+ if (valueString == null)
+ continue;
+
+ Object value = null;
+ if (prop.requiredDatatype instanceof NumberType) {
+ value = getPossibleNumericValue(prop, valueString);
+ } else if (prop.requiredDatatype instanceof StringType) {
+ value = valueString;
+ } else {
+ continue;
+ }
+
+ if (value == null) {
+ Statement statement = graph.getPossibleStatement(component, prop.predicate);
+ if (statement != null && statement.getObject().equals(component)) {
+ addMapListItem(result, component, prop);
+ }
+
+ continue;
+ }
+
+ Object currentValue = graph.getRelatedValue2(component, prop.predicate);
+ if (!Objects.equals(value, currentValue)) {
+ addMapListItem(result, component, prop);
+ }
+ }
+ }
+
+ return result;
+ }
+ });
+ }
+
+ private static Number getPossibleNumericValue(PropertyInfo info, String valueString) {
+ try {
+ Double num = Double.valueOf(valueString.replace(",", "."));
+ NumberBinding binding = (NumberBinding)info.defaultBinding;
+ Number value = (Number) binding.create(num);
+ return value;
+ } catch (NumberFormatException e) {
+ return null;
+ } catch (BindingException e) {
+ LOGGER.error("Binding error for property {}", info.name, e);
+ return null;
+ }
+ }
+
+ private static <A, B> void addMapListItem(Map<A, List<B>> result, A a, B b) {
+ List<B> list = result.get(a);
+ if (list == null) {
+ list = new ArrayList<>();
+ result.put(a, list);
+ }
+
+ list.add(b);
+ }
private static class PropertyInfoMapOfType extends ResourceRead<Map<String, PropertyInfo>> {
protected PropertyInfoMapOfType(Resource type) {