source: josm/trunk/src/org/openstreetmap/josm/io/ValidatorErrorWriter.java@ 16088

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

fix #18853 - Close OsmWriter after writing XML output streams (patch by hiddewie, modified)

File size: 6.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import java.io.BufferedWriter;
5import java.io.IOException;
6import java.io.OutputStream;
7import java.io.OutputStreamWriter;
8import java.io.PrintWriter;
9import java.nio.charset.StandardCharsets;
10import java.util.ArrayList;
11import java.util.Collection;
12import java.util.Date;
13import java.util.HashMap;
14import java.util.List;
15import java.util.Map;
16import java.util.Map.Entry;
17import java.util.Set;
18import java.util.TreeSet;
19import java.util.stream.Collectors;
20
21import org.openstreetmap.josm.command.AddPrimitivesCommand;
22import org.openstreetmap.josm.command.ChangePropertyCommand;
23import org.openstreetmap.josm.command.ChangePropertyKeyCommand;
24import org.openstreetmap.josm.command.Command;
25import org.openstreetmap.josm.command.DeleteCommand;
26import org.openstreetmap.josm.data.coor.LatLon;
27import org.openstreetmap.josm.data.osm.OsmPrimitive;
28import org.openstreetmap.josm.data.validation.OsmValidator;
29import org.openstreetmap.josm.data.validation.Severity;
30import org.openstreetmap.josm.data.validation.Test;
31import org.openstreetmap.josm.data.validation.TestError;
32import org.openstreetmap.josm.tools.LanguageInfo;
33import org.openstreetmap.josm.tools.Logging;
34import org.openstreetmap.josm.tools.date.DateUtils;
35
36/**
37 * Class to write a collection of validator errors out to XML.
38 * The format is inspired by the
39 * <a href="https://wiki.openstreetmap.org/wiki/Osmose#Issues_file_format">Osmose API issues file format</a>
40 * @since 12667
41 */
42public class ValidatorErrorWriter extends XmlWriter {
43
44 /**
45 * Constructs a new {@code ValidatorErrorWriter} that will write to the given {@link PrintWriter}.
46 * @param out PrintWriter to write XML to
47 */
48 public ValidatorErrorWriter(PrintWriter out) {
49 super(out);
50 }
51
52 /**
53 * Constructs a new {@code ValidatorErrorWriter} that will write to a given {@link OutputStream}.
54 * @param out OutputStream to write XML to
55 */
56 public ValidatorErrorWriter(OutputStream out) {
57 super(new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8))));
58 }
59
60 /**
61 * Write validator errors to designated output target
62 * @param validationErrors Test error collection to write
63 * @throws IOException in case of I/O error
64 */
65 public void write(Collection<TestError> validationErrors) throws IOException {
66 Set<Test> analysers = validationErrors.stream().map(TestError::getTester).collect(Collectors.toCollection(TreeSet::new));
67 String timestamp = DateUtils.fromDate(new Date());
68
69 out.println("<?xml version='1.0' encoding='UTF-8'?>");
70 out.println("<analysers generator='JOSM' timestamp='"+timestamp+"'>");
71
72 try (OsmWriter osmWriter = OsmWriterFactory.createOsmWriter(out, true, OsmChangeBuilder.DEFAULT_API_VERSION)) {
73 String lang = LanguageInfo.getJOSMLocaleCode();
74
75 for (Test test : analysers) {
76 out.println(" <analyser timestamp='" + timestamp + "' name='" + XmlWriter.encode(test.getName()) + "'>");
77 // Build map of test error classes for the current test
78 Map<ErrorClass, List<TestError>> map = new HashMap<>();
79 for (Entry<Severity, Map<String, Map<String, List<TestError>>>> e1 :
80 OsmValidator.getErrorsBySeverityMessageDescription(validationErrors, e -> e.getTester() == test).entrySet()) {
81 for (Entry<String, Map<String, List<TestError>>> e2 : e1.getValue().entrySet()) {
82 ErrorClass errorClass = new ErrorClass(e1.getKey(), e2.getKey());
83 List<TestError> list = map.get(errorClass);
84 if (list == null) {
85 list = new ArrayList<>();
86 map.put(errorClass, list);
87 }
88 e2.getValue().values().forEach(list::addAll);
89 }
90 }
91 // Write classes
92 for (ErrorClass ec : map.keySet()) {
93 out.println(" <class id='" + ec.id + "' level='" + ec.severity.getLevel() + "'>");
94 out.println(" <classtext lang='" + XmlWriter.encode(lang) + "' title='" + XmlWriter.encode(ec.message) + "'/>");
95 out.println(" </class>");
96 }
97
98 // Write errors
99 for (Entry<ErrorClass, List<TestError>> entry : map.entrySet()) {
100 for (TestError error : entry.getValue()) {
101 LatLon ll = error.getPrimitives().iterator().next().getBBox().getCenter();
102 out.println(" <error class='" + entry.getKey().id + "'>");
103 out.print(" <location");
104 osmWriter.writeLatLon(ll);
105 out.println("/>");
106 for (OsmPrimitive p : error.getPrimitives()) {
107 p.accept(osmWriter);
108 }
109 out.println(" <text lang='" + XmlWriter.encode(lang) +
110 "' value='" + XmlWriter.encode(error.getDescription()) + "'/>");
111 if (error.isFixable()) {
112 out.println(" <fixes>");
113 Command fix = error.getFix();
114 if (fix instanceof AddPrimitivesCommand) {
115 Logging.info("TODO: {0}", fix);
116 } else if (fix instanceof DeleteCommand) {
117 Logging.info("TODO: {0}", fix);
118 } else if (fix instanceof ChangePropertyCommand) {
119 Logging.info("TODO: {0}", fix);
120 } else if (fix instanceof ChangePropertyKeyCommand) {
121 Logging.info("TODO: {0}", fix);
122 } else {
123 Logging.warn("Unsupported command type: {0}", fix);
124 }
125 out.println(" </fixes>");
126 }
127 out.println(" </error>");
128 }
129 }
130
131 out.println(" </analyser>");
132 }
133 }
134
135 out.println("</analysers>");
136 out.flush();
137 }
138
139 private static class ErrorClass {
140 static int idCounter;
141 final Severity severity;
142 final String message;
143 final int id;
144
145 ErrorClass(Severity severity, String message) {
146 this.severity = severity;
147 this.message = message;
148 this.id = ++idCounter;
149 }
150 }
151}
Note: See TracBrowser for help on using the repository browser.