1 package org.simantics.district.network.techtype;
3 import java.util.Collections;
4 import java.util.HashMap;
5 import java.util.HashSet;
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;
30 public class TechTypeValidationUtils {
31 private static final Logger LOGGER = LoggerFactory.getLogger(TechTypeValidationUtils.class);
34 * Return a set of invalid tech type table entries.
36 * The tech type table values are validated against any limits that have been
37 * defined for associated component type properties.
39 * Invalid entries are designated by strings of the form "<type_code>/<property_name>".
41 * @param table A tech type table resource
42 * @return A set of labels for invalid values
43 * @throws DatabaseException
45 public static Set<String> validateTechTypeTable(Resource table) throws DatabaseException {
46 LOGGER.trace("Validating resource table {}", table);
48 // Use a unique read - we don't want to pollute the cache with this
49 return Simantics.getSession().syncRequest(new UniqueRead<Set<String>>() {
51 public Set<String> perform(ReadGraph graph) throws DatabaseException {
52 Resource type = graph.getPossibleObject(table, DistrictNetworkResource.getInstance(graph).TechType_TechTypeTable_HasComponentType);
54 return Collections.emptySet();
56 Map<String, PropertyInfo> props = graph.syncRequest(new PropertyInfoMapOfType(type), TransientCacheListener.instance());
57 Set<String> result = new HashSet<>();
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);
66 // Allow property names to start with an underscore
68 info = props.get("_" + propertyName);
71 LOGGER.trace(" {} - no property", propertyName);
75 Datatype dt = info.requiredDatatype;
76 if (dt == null || !(dt instanceof NumberType))
77 continue; // Only check ranges of numerical properties
79 String range = dt.metadata.get("range");
83 rng = Range.valueOf(range);
84 } catch (RangeException e1) {
85 LOGGER.error("Invalid range string {} for property {}", range, propertyName, e1);
89 String valueString = values.get(propertyName).replace(",", ".");
91 Double num = Double.valueOf(valueString);
92 NumberBinding binding = (NumberBinding)info.defaultBinding;
93 Number value = (Number) binding.create(num);
95 if (!rng.contains(value)) {
96 LOGGER.trace(" {} - range violation {} / {}", propertyName, valueString, range);
97 result.add(code + "/" + propertyName);
99 LOGGER.trace(" {} - valid value {} / {}", propertyName, valueString, range);
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);
116 private static class PropertyInfoMapOfType extends ResourceRead<Map<String, PropertyInfo>> {
117 protected PropertyInfoMapOfType(Resource type) {
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);