source: josm/trunk/src/org/openstreetmap/josm/tools/template_engine/ContextSwitchTemplate.java@ 16488

Last change on this file since 16488 was 16488, checked in by simon04, 4 years ago

fix #19281, see #19174 - Use Objects.hash where it is not used (patch by hiddewie, modified)

  • Property svn:eol-style set to native
File size: 14.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools.template_engine;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.Collections;
9import java.util.List;
10import java.util.Objects;
11import java.util.stream.Collectors;
12import java.util.stream.Stream;
13
14import org.openstreetmap.josm.data.osm.Node;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.data.osm.Relation;
17import org.openstreetmap.josm.data.osm.RelationMember;
18import org.openstreetmap.josm.data.osm.Way;
19import org.openstreetmap.josm.data.osm.search.SearchCompiler.And;
20import org.openstreetmap.josm.data.osm.search.SearchCompiler.Child;
21import org.openstreetmap.josm.data.osm.search.SearchCompiler.Match;
22import org.openstreetmap.josm.data.osm.search.SearchCompiler.Not;
23import org.openstreetmap.josm.data.osm.search.SearchCompiler.Or;
24import org.openstreetmap.josm.data.osm.search.SearchCompiler.Parent;
25
26/**
27 * The context switch offers possibility to use tags of referenced primitive when constructing primitive name.
28 * @author jttt
29 * @since 4546
30 */
31public class ContextSwitchTemplate implements TemplateEntry {
32
33 private static final TemplateEngineDataProvider EMPTY_PROVIDER = new TemplateEngineDataProvider() {
34 @Override
35 public Object getTemplateValue(String name, boolean special) {
36 return null;
37 }
38
39 @Override
40 public Collection<String> getTemplateKeys() {
41 return Collections.emptyList();
42 }
43
44 @Override
45 public boolean evaluateCondition(Match condition) {
46 return false;
47 }
48 };
49
50 private abstract static class ContextProvider extends Match {
51 protected Match condition;
52
53 abstract List<OsmPrimitive> getPrimitives(OsmPrimitive root);
54
55 @Override
56 public int hashCode() {
57 return Objects.hash(condition);
58 }
59
60 @Override
61 public boolean equals(Object obj) {
62 if (this == obj)
63 return true;
64 if (obj == null || getClass() != obj.getClass())
65 return false;
66 ContextProvider other = (ContextProvider) obj;
67 if (condition == null) {
68 if (other.condition != null)
69 return false;
70 } else if (!condition.equals(other.condition))
71 return false;
72 return true;
73 }
74 }
75
76 private static class ParentSet extends ContextProvider {
77 private final Match childCondition;
78
79 ParentSet(Match child) {
80 this.childCondition = child;
81 }
82
83 @Override
84 public boolean match(OsmPrimitive osm) {
85 throw new UnsupportedOperationException();
86 }
87
88 @Override
89 List<OsmPrimitive> getPrimitives(OsmPrimitive root) {
90 List<OsmPrimitive> children;
91 if (childCondition instanceof ContextProvider) {
92 children = ((ContextProvider) childCondition).getPrimitives(root);
93 } else if (childCondition.match(root)) {
94 children = Collections.singletonList(root);
95 } else {
96 children = Collections.emptyList();
97 }
98
99 return children.stream()
100 .flatMap(child -> child.getReferrers(true).stream())
101 .filter(parent -> condition == null || condition.match(parent))
102 .collect(Collectors.toList());
103 }
104
105 @Override
106 public int hashCode() {
107 return Objects.hash(super.hashCode(), childCondition);
108 }
109
110 @Override
111 public boolean equals(Object obj) {
112 if (this == obj)
113 return true;
114 if (!super.equals(obj) || getClass() != obj.getClass())
115 return false;
116 ParentSet other = (ParentSet) obj;
117 if (childCondition == null) {
118 if (other.childCondition != null)
119 return false;
120 } else if (!childCondition.equals(other.childCondition))
121 return false;
122 return true;
123 }
124 }
125
126 private static class ChildSet extends ContextProvider {
127 private final Match parentCondition;
128
129 ChildSet(Match parentCondition) {
130 this.parentCondition = parentCondition;
131 }
132
133 @Override
134 public boolean match(OsmPrimitive osm) {
135 throw new UnsupportedOperationException();
136 }
137
138 @Override
139 List<OsmPrimitive> getPrimitives(OsmPrimitive root) {
140 List<OsmPrimitive> parents;
141 if (parentCondition instanceof ContextProvider) {
142 parents = ((ContextProvider) parentCondition).getPrimitives(root);
143 } else if (parentCondition.match(root)) {
144 parents = Collections.singletonList(root);
145 } else {
146 parents = Collections.emptyList();
147 }
148 List<OsmPrimitive> result = new ArrayList<>();
149 for (OsmPrimitive p: parents) {
150 if (p instanceof Way) {
151 for (Node n: ((Way) p).getNodes()) {
152 if (condition != null && condition.match(n)) {
153 result.add(n);
154 }
155 result.add(n);
156 }
157 } else if (p instanceof Relation) {
158 for (RelationMember rm: ((Relation) p).getMembers()) {
159 if (condition != null && condition.match(rm.getMember())) {
160 result.add(rm.getMember());
161 }
162 }
163 }
164 }
165 return result;
166 }
167
168 @Override
169 public int hashCode() {
170 return Objects.hash(super.hashCode(), parentCondition);
171 }
172
173 @Override
174 public boolean equals(Object obj) {
175 if (this == obj)
176 return true;
177 if (!super.equals(obj) || getClass() != obj.getClass())
178 return false;
179 ChildSet other = (ChildSet) obj;
180 if (parentCondition == null) {
181 if (other.parentCondition != null)
182 return false;
183 } else if (!parentCondition.equals(other.parentCondition))
184 return false;
185 return true;
186 }
187 }
188
189 private static class OrSet extends ContextProvider {
190 private final ContextProvider lhs;
191 private final ContextProvider rhs;
192
193 OrSet(ContextProvider lhs, ContextProvider rhs) {
194 this.lhs = lhs;
195 this.rhs = rhs;
196 }
197
198 @Override
199 public boolean match(OsmPrimitive osm) {
200 throw new UnsupportedOperationException();
201 }
202
203 @Override
204 List<OsmPrimitive> getPrimitives(OsmPrimitive root) {
205 return Stream.concat(lhs.getPrimitives(root).stream(), rhs.getPrimitives(root).stream())
206 .filter(o -> condition == null || condition.match(o))
207 .distinct()
208 .collect(Collectors.toList());
209 }
210
211 @Override
212 public int hashCode() {
213 return Objects.hash(super.hashCode(), lhs, rhs);
214 }
215
216 @Override
217 public boolean equals(Object obj) {
218 if (this == obj)
219 return true;
220 if (!super.equals(obj) || getClass() != obj.getClass())
221 return false;
222 OrSet other = (OrSet) obj;
223 if (lhs == null) {
224 if (other.lhs != null)
225 return false;
226 } else if (!lhs.equals(other.lhs))
227 return false;
228 if (rhs == null) {
229 if (other.rhs != null)
230 return false;
231 } else if (!rhs.equals(other.rhs))
232 return false;
233 return true;
234 }
235 }
236
237 private static class AndSet extends ContextProvider {
238 private final ContextProvider lhs;
239 private final ContextProvider rhs;
240
241 AndSet(ContextProvider lhs, ContextProvider rhs) {
242 this.lhs = lhs;
243 this.rhs = rhs;
244 }
245
246 @Override
247 public boolean match(OsmPrimitive osm) {
248 throw new UnsupportedOperationException();
249 }
250
251 @Override
252 List<OsmPrimitive> getPrimitives(OsmPrimitive root) {
253 List<OsmPrimitive> lhsList = lhs.getPrimitives(root);
254 return rhs.getPrimitives(root).stream()
255 .filter(lhsList::contains)
256 .filter(o -> condition == null || condition.match(o))
257 .collect(Collectors.toList());
258 }
259
260 @Override
261 public int hashCode() {
262 return Objects.hash(lhs, rhs);
263 }
264
265 @Override
266 public boolean equals(Object obj) {
267 if (this == obj)
268 return true;
269 if (!super.equals(obj) || getClass() != obj.getClass())
270 return false;
271 AndSet other = (AndSet) obj;
272 if (lhs == null) {
273 if (other.lhs != null)
274 return false;
275 } else if (!lhs.equals(other.lhs))
276 return false;
277 if (rhs == null) {
278 if (other.rhs != null)
279 return false;
280 } else if (!rhs.equals(other.rhs))
281 return false;
282 return true;
283 }
284 }
285
286 private final ContextProvider context;
287 private final TemplateEntry template;
288
289 private static Match transform(Match m, int searchExpressionPosition) throws ParseError {
290 if (m instanceof Parent) {
291 Match child = transform(((Parent) m).getOperand(), searchExpressionPosition);
292 return new ParentSet(child);
293 } else if (m instanceof Child) {
294 Match parent = transform(((Child) m).getOperand(), searchExpressionPosition);
295 return new ChildSet(parent);
296 } else if (m instanceof And) {
297 Match lhs = transform(((And) m).getLhs(), searchExpressionPosition);
298 Match rhs = transform(((And) m).getRhs(), searchExpressionPosition);
299
300 if (lhs instanceof ContextProvider && rhs instanceof ContextProvider)
301 return new AndSet((ContextProvider) lhs, (ContextProvider) rhs);
302 else if (lhs instanceof ContextProvider) {
303 ContextProvider cp = (ContextProvider) lhs;
304 if (cp.condition == null) {
305 cp.condition = rhs;
306 } else {
307 cp.condition = new And(cp.condition, rhs);
308 }
309 return cp;
310 } else if (rhs instanceof ContextProvider) {
311 ContextProvider cp = (ContextProvider) rhs;
312 if (cp.condition == null) {
313 cp.condition = lhs;
314 } else {
315 cp.condition = new And(lhs, cp.condition);
316 }
317 return cp;
318 } else
319 return m;
320 } else if (m instanceof Or) {
321 Match lhs = transform(((Or) m).getLhs(), searchExpressionPosition);
322 Match rhs = transform(((Or) m).getRhs(), searchExpressionPosition);
323
324 if (lhs instanceof ContextProvider && rhs instanceof ContextProvider)
325 return new OrSet((ContextProvider) lhs, (ContextProvider) rhs);
326 else if (lhs instanceof ContextProvider)
327 throw new ParseError(
328 tr("Error in search expression on position {0} - right side of or(|) expression must return set of primitives",
329 searchExpressionPosition));
330 else if (rhs instanceof ContextProvider)
331 throw new ParseError(
332 tr("Error in search expression on position {0} - left side of or(|) expression must return set of primitives",
333 searchExpressionPosition));
334 else
335 return m;
336 } else if (m instanceof Not) {
337 Match match = transform(((Not) m).getMatch(), searchExpressionPosition);
338 if (match instanceof ContextProvider)
339 throw new ParseError(
340 tr("Error in search expression on position {0} - not(-) cannot be used in this context",
341 searchExpressionPosition));
342 else
343 return m;
344 } else
345 return m;
346 }
347
348 /**
349 * Constructs a new {@code ContextSwitchTemplate}.
350 * @param match match
351 * @param template template
352 * @param searchExpressionPosition search expression position
353 * @throws ParseError if a parse error occurs, or if the match transformation returns the same primitive
354 */
355 public ContextSwitchTemplate(Match match, TemplateEntry template, int searchExpressionPosition) throws ParseError {
356 Match m = transform(match, searchExpressionPosition);
357 if (!(m instanceof ContextProvider))
358 throw new ParseError(
359 tr("Error in search expression on position {0} - expression must return different then current primitive",
360 searchExpressionPosition));
361 else {
362 context = (ContextProvider) m;
363 }
364 this.template = template;
365 }
366
367 @Override
368 public void appendText(StringBuilder result, TemplateEngineDataProvider dataProvider) {
369 if (dataProvider instanceof OsmPrimitive) {
370 List<OsmPrimitive> primitives = context.getPrimitives((OsmPrimitive) dataProvider);
371 if (primitives != null && !primitives.isEmpty()) {
372 template.appendText(result, primitives.get(0));
373 }
374 }
375 template.appendText(result, EMPTY_PROVIDER);
376 }
377
378 @Override
379 public boolean isValid(TemplateEngineDataProvider dataProvider) {
380 if (dataProvider instanceof OsmPrimitive) {
381 List<OsmPrimitive> primitives = context.getPrimitives((OsmPrimitive) dataProvider);
382 if (primitives != null && !primitives.isEmpty()) {
383 return template.isValid(primitives.get(0));
384 }
385 }
386 return false;
387 }
388
389 @Override
390 public int hashCode() {
391 return Objects.hash(context, template);
392 }
393
394 @Override
395 public boolean equals(Object obj) {
396 if (this == obj)
397 return true;
398 if (obj == null || getClass() != obj.getClass())
399 return false;
400 ContextSwitchTemplate other = (ContextSwitchTemplate) obj;
401 if (context == null) {
402 if (other.context != null)
403 return false;
404 } else if (!context.equals(other.context))
405 return false;
406 if (template == null) {
407 if (other.template != null)
408 return false;
409 } else if (!template.equals(other.template))
410 return false;
411 return true;
412 }
413}
Note: See TracBrowser for help on using the repository browser.