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

Last change on this file since 13650 was 13453, checked in by Don-vip, 6 years ago

fix #8039, fix #10456: final fixes for the read-only/locked layers:

  • rename "read-only" to "locked" (in XML and Java classes/interfaces)
  • add a new download policy (true/never) to allow private layers forbidding only to download data, but allowing everything else

This leads to:

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