source: josm/trunk/src/org/openstreetmap/josm/data/validation/tests/ConditionalKeys.java@ 7308

Last change on this file since 7308 was 7005, checked in by Don-vip, 10 years ago

see #8465 - use diamond operator where applicable

File size: 7.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.validation.tests;
3
4import org.openstreetmap.josm.data.osm.OsmPrimitive;
5import org.openstreetmap.josm.data.validation.Severity;
6import org.openstreetmap.josm.data.validation.Test;
7import org.openstreetmap.josm.data.validation.TestError;
8import org.openstreetmap.josm.tools.Predicates;
9import org.openstreetmap.josm.tools.Utils;
10
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collection;
14import java.util.HashSet;
15import java.util.List;
16import java.util.Set;
17import java.util.regex.Matcher;
18import java.util.regex.Pattern;
19
20import static org.openstreetmap.josm.tools.I18n.tr;
21
22public class ConditionalKeys extends Test.TagTest {
23
24 final OpeningHourTest openingHourTest = new OpeningHourTest();
25 static final Set<String> RESTRICTION_TYPES = new HashSet<>(Arrays.asList("oneway", "toll", "noexit", "maxspeed", "minspeed",
26 "maxweight", "maxaxleload", "maxheight", "maxwidth", "maxlength", "overtaking", "maxgcweight", "maxgcweightrating", "fee"));
27 static final Set<String> RESTRICTION_VALUES = new HashSet<>(Arrays.asList("yes", "official", "designated", "destination",
28 "delivery", "permissive", "private", "agricultural", "forestry", "no"));
29 static final Set<String> TRANSPORT_MODES = new HashSet<>(Arrays.asList("access", "foot", "ski", "inline_skates", "ice_skates",
30 "horse", "vehicle", "bicycle", "carriage", "trailer", "caravan", "motor_vehicle", "motorcycle", "moped", "mofa",
31 "motorcar", "motorhome", "psv", "bus", "taxi", "tourist_bus", "goods", "hgv", "agricultural", "atv", "snowmobile"
32 /*,"hov","emergency","hazmat","disabled"*/));
33
34 /**
35 * Constructs a new {@code ConditionalKeys}.
36 */
37 public ConditionalKeys() {
38 super(tr("Conditional Keys"), tr("Tests for the correct usage of ''*:conditional'' tags."));
39 }
40
41 @Override
42 public void initialize() throws Exception {
43 super.initialize();
44 openingHourTest.initialize();
45 }
46
47 public static boolean isRestrictionType(String part) {
48 return RESTRICTION_TYPES.contains(part);
49 }
50
51 public static boolean isRestrictionValue(String part) {
52 return RESTRICTION_VALUES.contains(part);
53 }
54
55 public static boolean isTransportationMode(String part) {
56 // http://wiki.openstreetmap.org/wiki/Key:access#Transport_mode_restrictions
57 return TRANSPORT_MODES.contains(part);
58 }
59
60 public static boolean isDirection(String part) {
61 return "forward".equals(part) || "backward".equals(part);
62 }
63
64 public boolean isKeyValid(String key) {
65 // <restriction-type>[:<transportation mode>][:<direction>]:conditional
66 // -- or -- <transportation mode> [:<direction>]:conditional
67 if (!key.endsWith(":conditional")) {
68 return false;
69 }
70 final String[] parts = key.replaceAll(":conditional", "").split(":");
71 return parts.length == 3 && isRestrictionType(parts[0]) && isTransportationMode(parts[1]) && isDirection(parts[2])
72 || parts.length == 1 && (isRestrictionType(parts[0]) || isTransportationMode(parts[0]))
73 || parts.length == 2 && (
74 isRestrictionType(parts[0]) && (isTransportationMode(parts[1]) || isDirection(parts[1]))
75 || isTransportationMode(parts[0]) && isDirection(parts[1]));
76 }
77
78 public boolean isValueValid(String key, String value) {
79 return validateValue(key, value) == null;
80 }
81
82 static class ConditionalParsingException extends RuntimeException {
83 ConditionalParsingException(String message) {
84 super(message);
85 }
86 }
87
88 public static class ConditionalValue {
89 public final String restrictionValue;
90 public final Collection<String> conditions;
91
92 public ConditionalValue(String restrictionValue, Collection<String> conditions) {
93 this.restrictionValue = restrictionValue;
94 this.conditions = conditions;
95 }
96
97 public static List<ConditionalValue> parse(String value) throws ConditionalParsingException {
98 // <restriction-value> @ <condition>[;<restriction-value> @ <condition>]
99 final List<ConditionalValue> r = new ArrayList<>();
100 final Pattern part = Pattern.compile("([^@\\p{Space}][^@]*?)" + "\\s*@\\s*" + "(\\([^)\\p{Space}][^)]+?\\)|[^();\\p{Space}][^();]*?)\\s*");
101 final Matcher m = Pattern.compile("(" + part + ")(;\\s*" + part + ")*").matcher(value);
102 if (!m.matches()) {
103 throw new ConditionalParsingException(tr("Does not match pattern ''restriction value @ condition''"));
104 } else {
105 int i = 2;
106 while (i + 1 <= m.groupCount() && m.group(i + 1) != null) {
107 final String restrictionValue = m.group(i);
108 final String[] conditions = m.group(i + 1).replace("(", "").replace(")", "").split("\\s+(AND|and)\\s+");
109 r.add(new ConditionalValue(restrictionValue, Arrays.asList(conditions)));
110 i += 3;
111 }
112 }
113 return r;
114 }
115 }
116
117 public String validateValue(String key, String value) {
118 try {
119 for (final ConditionalValue conditional : ConditionalValue.parse(value)) {
120 // validate restriction value
121 if (isTransportationMode(key.split(":")[0]) && !isRestrictionValue(conditional.restrictionValue)) {
122 return tr("{0} is not a valid restriction value", conditional.restrictionValue);
123 }
124 // validate opening hour if the value contains an hour (heuristic)
125 for (final String condition : conditional.conditions) {
126 if (condition.matches(".*[0-9]:[0-9]{2}.*")) {
127 final List<OpeningHourTest.OpeningHoursTestError> errors = openingHourTest.checkOpeningHourSyntax(
128 "", condition, OpeningHourTest.CheckMode.TIME_RANGE, true);
129 if (!errors.isEmpty()) {
130 return errors.get(0).getMessage();
131 }
132 }
133 }
134 }
135 } catch (ConditionalParsingException ex) {
136 return ex.getMessage();
137 }
138 return null;
139 }
140
141 public List<TestError> validatePrimitive(OsmPrimitive p) {
142 final List<TestError> errors = new ArrayList<>();
143 for (final String key : Utils.filter(p.keySet(), Predicates.stringMatchesPattern(Pattern.compile(".*:conditional$")))) {
144 if (!isKeyValid(key)) {
145 errors.add(new TestError(this, Severity.WARNING, tr("Wrong syntax in {0} key", key), 3201, p));
146 continue;
147 }
148 final String value = p.get(key);
149 final String error = validateValue(key, value);
150 if (error != null) {
151 errors.add(new TestError(this, Severity.WARNING, tr("Error in {0} value: {1}", key, error), 3202, p));
152 }
153 }
154 return errors;
155 }
156
157 @Override
158 public void check(OsmPrimitive p) {
159 errors.addAll(validatePrimitive(p));
160 }
161}
Note: See TracBrowser for help on using the repository browser.