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

Last change on this file since 10300 was 10300, checked in by Don-vip, 8 years ago

sonar - Performance - Method passes constant String of length 1 to character overridden method + add unit tests/javadoc

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