source: josm/trunk/src/org/openstreetmap/josm/data/osm/DatasetConsistencyTest.java@ 13420

Last change on this file since 13420 was 12620, checked in by Don-vip, 7 years ago

see #15182 - deprecate all Main logging methods and introduce suitable replacements in Logging for most of them

  • Property svn:eol-style set to native
File size: 8.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.PrintWriter;
7import java.io.StringWriter;
8import java.io.Writer;
9
10import org.openstreetmap.josm.tools.JosmRuntimeException;
11import org.openstreetmap.josm.tools.Logging;
12import org.openstreetmap.josm.tools.Utils;
13
14/**
15 * This class can be used to run consistency tests on dataset. Any errors found will be written to provided PrintWriter.
16 * <br>
17 * Texts here should not be translated because they're not intended for users but for josm developers.
18 * @since 2500
19 */
20public class DatasetConsistencyTest {
21
22 private static final int MAX_ERRORS = 100;
23 private final DataSet dataSet;
24 private final PrintWriter writer;
25 private int errorCount;
26
27 /**
28 * Constructs a new {@code DatasetConsistencyTest}.
29 * @param dataSet The dataset to test
30 * @param writer The writer used to write results
31 */
32 public DatasetConsistencyTest(DataSet dataSet, Writer writer) {
33 this.dataSet = dataSet;
34 this.writer = new PrintWriter(writer);
35 }
36
37 private void printError(String type, String message, Object... args) {
38 errorCount++;
39 if (errorCount <= MAX_ERRORS) {
40 writer.println('[' + type + "] " + String.format(message, args));
41 }
42 }
43
44 /**
45 * Checks that parent primitive is referred from its child members
46 */
47 public void checkReferrers() {
48 long startTime = System.currentTimeMillis();
49 // It's also error when referred primitive's dataset is null but it's already covered by referredPrimitiveNotInDataset check
50 for (Way way : dataSet.getWays()) {
51 if (!way.isDeleted()) {
52 for (Node n : way.getNodes()) {
53 if (n.getDataSet() != null && !n.getReferrers().contains(way)) {
54 printError("WAY NOT IN REFERRERS", "%s is part of %s but is not in referrers", n, way);
55 }
56 }
57 }
58 }
59
60 for (Relation relation : dataSet.getRelations()) {
61 if (!relation.isDeleted()) {
62 for (RelationMember m : relation.getMembers()) {
63 if (m.getMember().getDataSet() != null && !m.getMember().getReferrers().contains(relation)) {
64 printError("RELATION NOT IN REFERRERS", "%s is part of %s but is not in referrers", m.getMember(), relation);
65 }
66 }
67 }
68 }
69 printElapsedTime(startTime);
70 }
71
72 /**
73 * Checks for womplete ways with incomplete nodes.
74 */
75 public void checkCompleteWaysWithIncompleteNodes() {
76 long startTime = System.currentTimeMillis();
77 for (Way way : dataSet.getWays()) {
78 if (way.isUsable()) {
79 for (Node node : way.getNodes()) {
80 if (node.isIncomplete()) {
81 printError("USABLE HAS INCOMPLETE", "%s is usable but contains incomplete node '%s'", way, node);
82 }
83 }
84 }
85 }
86 printElapsedTime(startTime);
87 }
88
89 /**
90 * Checks for complete nodes without coordinates.
91 */
92 public void checkCompleteNodesWithoutCoordinates() {
93 long startTime = System.currentTimeMillis();
94 for (Node node : dataSet.getNodes()) {
95 if (!node.isIncomplete() && node.isVisible() && !node.isLatLonKnown()) {
96 printError("COMPLETE WITHOUT COORDINATES", "%s is not incomplete but has null coordinates", node);
97 }
98 }
99 printElapsedTime(startTime);
100 }
101
102 /**
103 * Checks that nodes can be retrieved through their coordinates.
104 */
105 public void searchNodes() {
106 long startTime = System.currentTimeMillis();
107 dataSet.getReadLock().lock();
108 try {
109 for (Node n : dataSet.getNodes()) {
110 // Call isDrawable() as an efficient replacement to previous checks (!deleted, !incomplete, getCoor() != null)
111 if (n.isDrawable() && !dataSet.containsNode(n)) {
112 printError("SEARCH NODES", "%s not found using Dataset.containsNode()", n);
113 }
114 }
115 } finally {
116 dataSet.getReadLock().unlock();
117 }
118 printElapsedTime(startTime);
119 }
120
121 /**
122 * Checks that ways can be retrieved through their bounding box.
123 */
124 public void searchWays() {
125 long startTime = System.currentTimeMillis();
126 dataSet.getReadLock().lock();
127 try {
128 for (Way w : dataSet.getWays()) {
129 if (!w.isIncomplete() && !w.isDeleted() && w.getNodesCount() >= 2 && !dataSet.containsWay(w)) {
130 printError("SEARCH WAYS", "%s not found using Dataset.containsWay()", w);
131 }
132 }
133 } finally {
134 dataSet.getReadLock().unlock();
135 }
136 printElapsedTime(startTime);
137 }
138
139 private void checkReferredPrimitive(OsmPrimitive primitive, OsmPrimitive parent) {
140 if (primitive.getDataSet() == null) {
141 printError("NO DATASET", "%s is referenced by %s but not found in dataset", primitive, parent);
142 } else if (dataSet.getPrimitiveById(primitive) == null) {
143 printError("REFERENCED BUT NOT IN DATA", "%s is referenced by %s but not found in dataset", primitive, parent);
144 } else if (dataSet.getPrimitiveById(primitive) != primitive) {
145 printError("DIFFERENT INSTANCE", "%s is different instance that referred by %s", primitive, parent);
146 }
147
148 if (primitive.isDeleted()) {
149 printError("DELETED REFERENCED", "%s refers to deleted primitive %s", parent, primitive);
150 }
151 }
152
153 /**
154 * Checks that referred primitives are present in dataset.
155 */
156 public void referredPrimitiveNotInDataset() {
157 long startTime = System.currentTimeMillis();
158 for (Way way : dataSet.getWays()) {
159 for (Node node : way.getNodes()) {
160 checkReferredPrimitive(node, way);
161 }
162 }
163
164 for (Relation relation : dataSet.getRelations()) {
165 for (RelationMember member : relation.getMembers()) {
166 checkReferredPrimitive(member.getMember(), relation);
167 }
168 }
169 printElapsedTime(startTime);
170 }
171
172 /**
173 * Checks for zero and one-node ways.
174 */
175 public void checkZeroNodesWays() {
176 long startTime = System.currentTimeMillis();
177 for (Way way : dataSet.getWays()) {
178 if (way.isUsable() && way.getNodesCount() == 0) {
179 printError("WARN - ZERO NODES", "Way %s has zero nodes", way);
180 } else if (way.isUsable() && way.getNodesCount() == 1) {
181 printError("WARN - NO NODES", "Way %s has only one node", way);
182 }
183 }
184 printElapsedTime(startTime);
185 }
186
187 private void printElapsedTime(long startTime) {
188 if (Logging.isDebugEnabled()) {
189 StackTraceElement item = Thread.currentThread().getStackTrace()[2];
190 String operation = getClass().getSimpleName() + '.' + item.getMethodName();
191 long elapsedTime = System.currentTimeMillis() - startTime;
192 Logging.debug(tr("Test ''{0}'' completed in {1}",
193 operation, Utils.getDurationString(elapsedTime)));
194 }
195 }
196
197 /**
198 * Runs test.
199 */
200 public void runTest() {
201 try {
202 long startTime = System.currentTimeMillis();
203 referredPrimitiveNotInDataset();
204 checkReferrers();
205 checkCompleteWaysWithIncompleteNodes();
206 checkCompleteNodesWithoutCoordinates();
207 searchNodes();
208 searchWays();
209 checkZeroNodesWays();
210 printElapsedTime(startTime);
211 if (errorCount > MAX_ERRORS) {
212 writer.println((errorCount - MAX_ERRORS) + " more...");
213 }
214
215 } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) {
216 writer.println("Exception during dataset integrity test:");
217 e.printStackTrace(writer);
218 Logging.warn(e);
219 }
220 }
221
222 /**
223 * Runs test on the given dataset.
224 * @param dataSet the dataset to test
225 * @return the errors as string
226 */
227 public static String runTests(DataSet dataSet) {
228 StringWriter writer = new StringWriter();
229 new DatasetConsistencyTest(dataSet, writer).runTest();
230 return writer.toString();
231 }
232}
Note: See TracBrowser for help on using the repository browser.