]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network/src/org/simantics/district/network/techtype/TechTypeValidationUtils.java
a82f65a6cee8bfd5e5e46bb70437e0ebccd31907
[simantics/district.git] / org.simantics.district.network / src / org / simantics / district / network / techtype / TechTypeValidationUtils.java
1 package org.simantics.district.network.techtype;
2
3 import java.util.Collections;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Map;
7 import java.util.Set;
8
9 import org.simantics.Simantics;
10 import org.simantics.databoard.binding.NumberBinding;
11 import org.simantics.databoard.binding.error.BindingException;
12 import org.simantics.databoard.type.Datatype;
13 import org.simantics.databoard.type.NumberType;
14 import org.simantics.databoard.util.Range;
15 import org.simantics.databoard.util.RangeException;
16 import org.simantics.db.ReadGraph;
17 import org.simantics.db.Resource;
18 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
19 import org.simantics.db.common.request.ResourceRead;
20 import org.simantics.db.common.request.UniqueRead;
21 import org.simantics.db.exception.DatabaseException;
22 import org.simantics.db.layer0.request.PropertyInfo;
23 import org.simantics.db.layer0.request.PropertyInfoRequest;
24 import org.simantics.district.network.ontology.DistrictNetworkResource;
25 import org.simantics.district.network.techtype.requests.TechTypeTableData;
26 import org.simantics.layer0.Layer0;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 public class TechTypeValidationUtils {
31         private static final Logger LOGGER = LoggerFactory.getLogger(TechTypeValidationUtils.class);
32         
33         /**
34          * Return a set of invalid tech type table entries.
35          * 
36          * The tech type table values are validated against any limits that have been
37          * defined for associated component type properties.
38          * 
39          * Invalid entries are designated by strings of the form "<type_code>/<property_name>".
40          * 
41          * @param table  A tech type table resource
42          * @return  A set of labels for invalid values
43          * @throws DatabaseException
44          */
45         public static Set<String> validateTechTypeTable(Resource table) throws DatabaseException {
46                 LOGGER.trace("Validating resource table {}", table);
47                 
48                 // Use a unique read - we don't want to pollute the cache with this
49                 return Simantics.getSession().syncRequest(new UniqueRead<Set<String>>() {
50                         @Override
51                         public Set<String> perform(ReadGraph graph) throws DatabaseException {
52                                 Resource type = graph.getPossibleObject(table, DistrictNetworkResource.getInstance(graph).TechType_TechTypeTable_HasComponentType);
53                                 if (type == null)
54                                         return Collections.emptySet();
55                                 
56                                 Map<String, PropertyInfo> props = graph.syncRequest(new PropertyInfoMapOfType(type), TransientCacheListener.instance());
57                                 Set<String> result = new HashSet<>();
58                                 
59                                 Map<String, Map<String, String>> data = graph.syncRequest(new TechTypeTableData(table), TransientCacheListener.instance());
60                                 for (String code : data.keySet()) {
61                                         LOGGER.trace("  type code {}", code);
62                                         Map<String, String> values = data.get(code);
63                                         for (String propertyName : values.keySet()) {
64                                                 PropertyInfo info = props.get(propertyName);
65                                                 
66                                                 // Allow property names to start with an underscore
67                                                 if (info == null)
68                                                         info = props.get("_" + propertyName);
69                                                 
70                                                 if (info == null) {
71                                                         LOGGER.trace("    {} - no property", propertyName);
72                                                         continue;
73                                                 }
74                                                 
75                                                 Datatype dt = info.requiredDatatype;
76                                                 if (dt == null || !(dt instanceof NumberType))
77                                                         continue;  // Only check ranges of numerical properties
78                                                 
79                                                 String range = dt.metadata.get("range");
80                                                 if (range != null) {
81                                                         Range rng;
82                                                         try {
83                                                                 rng = Range.valueOf(range);
84                                                         } catch (RangeException e1) {
85                                                                 LOGGER.error("Invalid range string {} for property {}", range, propertyName, e1);
86                                                                 continue;
87                                                         }
88                                                         
89                                                         String valueString = values.get(propertyName).replace(",", ".");
90                                                         try {
91                                                                 Double num = Double.valueOf(valueString);
92                                                                 NumberBinding binding = (NumberBinding)info.defaultBinding;
93                                                                 Number value = (Number) binding.create(num);
94                                                                 
95                                                                 if (!rng.contains(value)) {
96                                                                         LOGGER.trace("    {} - range violation {} / {}", propertyName, valueString, range);
97                                                                         result.add(code + "/" + propertyName);
98                                                                 } else {
99                                                                         LOGGER.trace("    {} - valid value {} / {}", propertyName, valueString, range);
100                                                                 }
101                                                         } catch (NumberFormatException e) {
102                                                                 // Nothing to do here, treat non-numeric strings as missing values
103                                                                 LOGGER.trace("    {} - no value {} / {}", propertyName, valueString, range);
104                                                         } catch (BindingException e) {
105                                                                 LOGGER.error("Binding error for property {}", propertyName, e);
106                                                         }
107                                                 }
108                                         }
109                                 }
110                                 
111                                 return result;
112                         }
113                 });
114         }
115
116         private static class PropertyInfoMapOfType extends ResourceRead<Map<String, PropertyInfo>> {
117                 protected PropertyInfoMapOfType(Resource type) {
118                         super(type);
119                 }
120         
121                 @Override
122                 public Map<String, PropertyInfo> perform(ReadGraph graph) throws DatabaseException {
123                         Map<String, PropertyInfo> result = new HashMap<String, PropertyInfo>();
124                         for (Resource prop : graph.getObjects(resource, Layer0.getInstance(graph).DomainOf)) {
125                                 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(prop), TransientCacheListener.instance());
126                                 result.put(info.name, info);
127                         }
128                         
129                         return result;
130                 }
131         }
132 }