source: josm/trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java@ 11386

Last change on this file since 11386 was 10818, checked in by simon04, 8 years ago

fix #6332 - Update user and timestamp of OSM objects after upload

  • Property svn:eol-style set to native
File size: 7.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.IOException;
7import java.io.StringReader;
8import java.util.Collection;
9import java.util.Collections;
10import java.util.Date;
11import java.util.HashMap;
12import java.util.HashSet;
13import java.util.Map;
14import java.util.Set;
15
16import javax.xml.parsers.ParserConfigurationException;
17
18import org.openstreetmap.josm.data.osm.Changeset;
19import org.openstreetmap.josm.data.osm.DataSet;
20import org.openstreetmap.josm.data.osm.OsmPrimitive;
21import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
22import org.openstreetmap.josm.data.osm.PrimitiveId;
23import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
24import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
25import org.openstreetmap.josm.gui.progress.ProgressMonitor;
26import org.openstreetmap.josm.tools.CheckParameterUtil;
27import org.openstreetmap.josm.tools.Utils;
28import org.openstreetmap.josm.tools.XmlParsingException;
29import org.xml.sax.Attributes;
30import org.xml.sax.InputSource;
31import org.xml.sax.Locator;
32import org.xml.sax.SAXException;
33import org.xml.sax.helpers.DefaultHandler;
34
35public class DiffResultProcessor {
36
37 private static class DiffResultEntry {
38 private long newId;
39 private int newVersion;
40 }
41
42 /**
43 * mapping from old id to new id and version, the result of parsing the diff result
44 * replied by the server
45 */
46 private final Map<PrimitiveId, DiffResultEntry> diffResults = new HashMap<>();
47 /**
48 * the set of processed primitives *after* the new id, the new version and the new changeset id is set
49 */
50 private final Set<OsmPrimitive> processed;
51 /**
52 * the collection of primitives being uploaded
53 */
54 private final Collection<? extends OsmPrimitive> primitives;
55
56 /**
57 * Creates a diff result reader
58 *
59 * @param primitives the collection of primitives which have been uploaded. If null,
60 * assumes an empty collection.
61 */
62 public DiffResultProcessor(Collection<? extends OsmPrimitive> primitives) {
63 if (primitives == null) {
64 primitives = Collections.emptyList();
65 }
66 this.primitives = primitives;
67 this.processed = new HashSet<>();
68 }
69
70 /**
71 * Parse the response from a diff upload to the OSM API.
72 *
73 * @param diffUploadResponse the response. Must not be null.
74 * @param progressMonitor a progress monitor. Defaults to {@link NullProgressMonitor#INSTANCE} if null
75 * @throws IllegalArgumentException if diffUploadRequest is null
76 * @throws XmlParsingException if the diffUploadRequest can't be parsed successfully
77 *
78 */
79 public void parse(String diffUploadResponse, ProgressMonitor progressMonitor) throws XmlParsingException {
80 if (progressMonitor == null) {
81 progressMonitor = NullProgressMonitor.INSTANCE;
82 }
83 CheckParameterUtil.ensureParameterNotNull(diffUploadResponse, "diffUploadResponse");
84 try {
85 progressMonitor.beginTask(tr("Parsing response from server..."));
86 InputSource inputSource = new InputSource(new StringReader(diffUploadResponse));
87 Utils.parseSafeSAX(inputSource, new Parser());
88 } catch (XmlParsingException e) {
89 throw e;
90 } catch (IOException | ParserConfigurationException | SAXException e) {
91 throw new XmlParsingException(e);
92 } finally {
93 progressMonitor.finishTask();
94 }
95 }
96
97 /**
98 * Postprocesses the diff result read and parsed from the server.
99 *
100 * Uploaded objects are assigned their new id (if they got assigned a new
101 * id by the server), their new version (if the version was incremented),
102 * and the id of the changeset to which they were uploaded.
103 *
104 * @param cs the current changeset. Ignored if null.
105 * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
106 * @return the collection of processed primitives
107 */
108 protected Set<OsmPrimitive> postProcess(Changeset cs, ProgressMonitor monitor) {
109 if (monitor == null) {
110 monitor = NullProgressMonitor.INSTANCE;
111 }
112 DataSet ds = null;
113 if (!primitives.isEmpty()) {
114 ds = primitives.iterator().next().getDataSet();
115 }
116 if (ds != null) {
117 ds.beginUpdate();
118 }
119 try {
120 monitor.beginTask("Postprocessing uploaded data ...");
121 monitor.setTicksCount(primitives.size());
122 monitor.setTicks(0);
123 for (OsmPrimitive p : primitives) {
124 monitor.worked(1);
125 DiffResultEntry entry = diffResults.get(p.getPrimitiveId());
126 if (entry == null) {
127 continue;
128 }
129 processed.add(p);
130 if (!p.isDeleted()) {
131 p.setOsmId(entry.newId, entry.newVersion);
132 p.setVisible(true);
133 } else {
134 p.setVisible(false);
135 }
136 if (cs != null && !cs.isNew()) {
137 p.setChangesetId(cs.getId());
138 p.setUser(cs.getUser());
139 // TODO is there a way to obtain the timestamp for non-closed changesets?
140 p.setTimestamp(Utils.firstNonNull(cs.getClosedAt(), new Date()));
141 }
142 }
143 return processed;
144 } finally {
145 if (ds != null) {
146 ds.endUpdate();
147 }
148 monitor.finishTask();
149 }
150 }
151
152 private class Parser extends DefaultHandler {
153 private Locator locator;
154
155 @Override
156 public void setDocumentLocator(Locator locator) {
157 this.locator = locator;
158 }
159
160 protected void throwException(String msg) throws XmlParsingException {
161 throw new XmlParsingException(msg).rememberLocation(locator);
162 }
163
164 @Override
165 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
166 try {
167 switch (qName) {
168 case "diffResult":
169 // the root element, ignore
170 break;
171 case "node":
172 case "way":
173 case "relation":
174 PrimitiveId id = new SimplePrimitiveId(
175 Long.parseLong(atts.getValue("old_id")),
176 OsmPrimitiveType.fromApiTypeName(qName)
177 );
178 DiffResultEntry entry = new DiffResultEntry();
179 if (atts.getValue("new_id") != null) {
180 entry.newId = Long.parseLong(atts.getValue("new_id"));
181 }
182 if (atts.getValue("new_version") != null) {
183 entry.newVersion = Integer.parseInt(atts.getValue("new_version"));
184 }
185 diffResults.put(id, entry);
186 break;
187 default:
188 throwException(tr("Unexpected XML element with name ''{0}''", qName));
189 }
190 } catch (NumberFormatException e) {
191 throw new XmlParsingException(e).rememberLocation(locator);
192 }
193 }
194 }
195}
Note: See TracBrowser for help on using the repository browser.