]> gerrit.simantics Code Review - simantics/district.git/commitdiff
Utilities for checking component consistency against tech type data 78/4478/1
authorReino Ruusu <reino.ruusu@semantum.fi>
Fri, 25 Sep 2020 06:27:23 +0000 (09:27 +0300)
committerReino Ruusu <reino.ruusu@semantum.fi>
Fri, 25 Sep 2020 06:30:07 +0000 (06:30 +0000)
gitlab #96

Change-Id: I3039933e89a214eb29d8f339c5385ed1e5876b6c

org.simantics.district.network/src/org/simantics/district/network/techtype/TechTypeValidationUtils.java

index a82f65a6cee8bfd5e5e46bb70437e0ebccd31907..941036cd625d129a210cdf5d22f046ffc6b4fd98 100644 (file)
@@ -1,9 +1,12 @@
 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;
@@ -11,17 +14,22 @@ import org.simantics.databoard.binding.NumberBinding;
 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;
@@ -86,23 +94,15 @@ public class TechTypeValidationUtils {
                                                                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);
                                                        }
                                                }
                                        }
@@ -112,6 +112,107 @@ public class TechTypeValidationUtils {
                        }
                });
        }
+       
+       /**
+        * 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) {