diff --git a/src/org/openstreetmap/josm/data/validation/ValidationTask.java b/src/org/openstreetmap/josm/data/validation/ValidationTask.java
index 02b857898..dbf80fb39 100644
a
|
b
|
package org.openstreetmap.josm.data.validation;
|
3 | 3 | |
4 | 4 | import org.openstreetmap.josm.data.osm.OsmPrimitive; |
5 | 5 | import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper; |
| 6 | import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker; |
6 | 7 | import org.openstreetmap.josm.gui.MainApplication; |
7 | 8 | import org.openstreetmap.josm.gui.MapFrame; |
8 | 9 | import org.openstreetmap.josm.gui.PleaseWaitRunnable; |
… |
… |
import org.openstreetmap.josm.gui.layer.ValidatorLayer;
|
10 | 11 | import org.openstreetmap.josm.gui.progress.ProgressMonitor; |
11 | 12 | import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor; |
12 | 13 | import org.openstreetmap.josm.gui.util.GuiHelper; |
| 14 | import org.openstreetmap.josm.tools.Logging; |
| 15 | import org.openstreetmap.josm.tools.Utils; |
13 | 16 | |
14 | 17 | import java.util.ArrayList; |
15 | 18 | import java.util.Collection; |
16 | 19 | import java.util.List; |
| 20 | import java.util.concurrent.ExecutionException; |
| 21 | import java.util.concurrent.ForkJoinPool; |
| 22 | import java.util.concurrent.Future; |
| 23 | import java.util.concurrent.atomic.AtomicInteger; |
| 24 | import java.util.function.Consumer; |
| 25 | import java.util.stream.Collectors; |
17 | 26 | |
18 | 27 | import static org.openstreetmap.josm.tools.I18n.tr; |
19 | 28 | |
… |
… |
import static org.openstreetmap.josm.tools.I18n.tr;
|
21 | 30 | * Asynchronous task for running a collection of tests against a collection of primitives |
22 | 31 | */ |
23 | 32 | public class ValidationTask extends PleaseWaitRunnable { |
24 | | private Collection<Test> tests; |
| 33 | private final ArrayList<Test> tests; |
25 | 34 | private final Collection<OsmPrimitive> validatedPrimitives; |
26 | 35 | private final Collection<OsmPrimitive> formerValidatedPrimitives; |
27 | 36 | private boolean canceled; |
28 | 37 | private List<TestError> errors; |
| 38 | private static final ForkJoinPool THREAD_POOL = Utils.newForkJoinPool( |
| 39 | ValidatorPrefHelper.PREFIX + ".numberOfThreads", "validator-%d", Thread.NORM_PRIORITY); |
29 | 40 | |
30 | 41 | /** |
31 | 42 | * Constructs a new {@code ValidationTask} |
… |
… |
public class ValidationTask extends PleaseWaitRunnable {
|
47 | 58 | super(tr("Validating"), progressMonitor, false /*don't ignore exceptions */); |
48 | 59 | this.validatedPrimitives = validatedPrimitives; |
49 | 60 | this.formerValidatedPrimitives = formerValidatedPrimitives; |
50 | | this.tests = tests; |
| 61 | this.tests = new ArrayList<>(tests); |
51 | 62 | } |
52 | 63 | |
53 | 64 | @Override |
… |
… |
public class ValidationTask extends PleaseWaitRunnable {
|
77 | 88 | if (tests == null || tests.isEmpty()) |
78 | 89 | return; |
79 | 90 | errors = new ArrayList<>(); |
80 | | getProgressMonitor().setTicksCount(tests.size() * validatedPrimitives.size()); |
81 | | int testCounter = 0; |
82 | | for (Test test : tests) { |
83 | | if (canceled) |
84 | | return; |
85 | | testCounter++; |
86 | | getProgressMonitor().setCustomText(tr("Test {0}/{1}: Starting {2}", testCounter, tests.size(), test.getName())); |
| 91 | |
| 92 | AtomicInteger testCounter = new AtomicInteger(); |
| 93 | runParallel(test -> { |
87 | 94 | test.setBeforeUpload(false); |
88 | 95 | test.setPartialSelection(formerValidatedPrimitives != null); |
89 | | test.startTest(getProgressMonitor().createSubTaskMonitor(validatedPrimitives.size(), false)); |
90 | | test.visit(validatedPrimitives); |
91 | | test.endTest(); |
92 | | errors.addAll(test.getErrors()); |
93 | | test.clear(); |
94 | | } |
95 | | tests = null; |
| 96 | test.startTest(null); |
| 97 | }); |
| 98 | runParallel(test -> { |
| 99 | getProgressMonitor().setCustomText(tr("Test {0}/{1}: Starting {2}", testCounter.incrementAndGet(), tests.size(), test.getName())); |
| 100 | if (test instanceof MapCSSTagChecker) { |
| 101 | // VARIANT 1 |
| 102 | validatedPrimitives.parallelStream() |
| 103 | .filter(test::isPrimitiveUsable) |
| 104 | .forEach(p -> p.accept(test)); |
| 105 | } else { |
| 106 | test.visit(validatedPrimitives); |
| 107 | } |
| 108 | }); |
| 109 | runParallel(Test::endTest); |
| 110 | errors = tests.stream().flatMap(test -> test.getErrors().stream()).collect(Collectors.toList()); |
| 111 | |
| 112 | runParallel(Test::clear); |
| 113 | tests.clear(); |
| 114 | tests.trimToSize(); |
| 115 | |
96 | 116 | if (Boolean.TRUE.equals(ValidatorPrefHelper.PREF_USE_IGNORE.get())) { |
97 | 117 | getProgressMonitor().setCustomText(""); |
98 | 118 | getProgressMonitor().subTask(tr("Updating ignored errors ...")); |
… |
… |
public class ValidationTask extends PleaseWaitRunnable {
|
103 | 123 | } |
104 | 124 | } |
105 | 125 | |
| 126 | private void runParallel(Consumer<Test> testConsumer) { |
| 127 | try { |
| 128 | Future<?> future = THREAD_POOL.submit(() -> tests.parallelStream().forEach(testConsumer)); |
| 129 | future.get(); |
| 130 | } catch (InterruptedException | ExecutionException e) { |
| 131 | if (e.getCause() instanceof RuntimeException) { |
| 132 | throw ((RuntimeException) e.getCause()); |
| 133 | } |
| 134 | Logging.warn(e); |
| 135 | Thread.currentThread().interrupt(); |
| 136 | } |
| 137 | } |
| 138 | |
106 | 139 | /** |
107 | 140 | * Gets the validation errors accumulated until this moment. |
108 | 141 | * @return The list of errors |
diff --git a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
index bf38cd13f..2442933c3 100644
a
|
b
|
public class MapCSSTagChecker extends Test.TagTest {
|
238 | 238 | */ |
239 | 239 | @Override |
240 | 240 | public void check(OsmPrimitive p) { |
241 | | for (TestError e : getErrorsForPrimitive(p, ValidatorPrefHelper.PREF_OTHER.get())) { |
242 | | addIfNotSimilar(e, errors); |
| 241 | Collection<TestError> errorsForPrimitive = getErrorsForPrimitive(p, ValidatorPrefHelper.PREF_OTHER.get()); |
| 242 | if (errorsForPrimitive.isEmpty()) { |
| 243 | return; |
| 244 | } |
| 245 | synchronized (errors) { |
| 246 | for (TestError e : errorsForPrimitive) { |
| 247 | addIfNotSimilar(e, errors); |
| 248 | } |
243 | 249 | } |
244 | 250 | } |
245 | 251 | |
… |
… |
public class MapCSSTagChecker extends Test.TagTest {
|
382 | 388 | mpAreaCache.clear(); |
383 | 389 | |
384 | 390 | Set<OsmPrimitive> surrounding = new HashSet<>(); |
385 | | for (Entry<String, Set<MapCSSTagCheckerRule>> entry : checks.entrySet()) { |
| 391 | // VARIANT 2 |
| 392 | checks.entrySet().parallelStream().forEach(entry -> { |
386 | 393 | if (isCanceled()) { |
387 | | break; |
| 394 | return; |
388 | 395 | } |
389 | 396 | if (urlPredicate != null && !urlPredicate.test(entry.getKey())) { |
390 | | continue; |
| 397 | return; |
391 | 398 | } |
392 | 399 | visit(entry.getKey(), entry.getValue(), selection, surrounding); |
393 | | } |
| 400 | }); |
394 | 401 | } |
395 | 402 | |
396 | 403 | /** |
… |
… |
public class MapCSSTagChecker extends Test.TagTest {
|
464 | 471 | if (tested.contains(p)) |
465 | 472 | continue; |
466 | 473 | Collection<TestError> additionalErrors = getErrorsForPrimitive(p, includeOtherSeverity); |
467 | | for (TestError e : additionalErrors) { |
468 | | if (e.getPrimitives().stream().anyMatch(tested::contains)) |
469 | | addIfNotSimilar(e, errors); |
| 474 | if (additionalErrors.isEmpty()) |
| 475 | continue; |
| 476 | synchronized (errors) { |
| 477 | for (TestError e : additionalErrors) { |
| 478 | if (e.getPrimitives().stream().anyMatch(tested::contains)) { |
| 479 | addIfNotSimilar(e, errors); |
| 480 | } |
| 481 | } |
470 | 482 | } |
471 | 483 | } |
472 | 484 | |