Ticket #17459: plugin-remove-corehacks.patch
File plugin-remove-corehacks.patch, 36.8 KB (added by , 5 years ago) |
---|
-
build.xml
3 3 <!-- enter the SVN commit message --> 4 4 <property name="commit.message" value="Reverter: Update MultiOsmReader to support null data after redaction"/> 5 5 <!-- enter the *lowest* JOSM version this plugin is currently compatible with --> 6 <property name="plugin.main.version" value=" 14153"/>6 <property name="plugin.main.version" value="xxx"/> 7 7 8 8 <!-- Configure these properties (replace "..." accordingly). 9 9 See https://josm.openstreetmap.de/wiki/DevelopersGuide/DevelopingPlugins -
src/reverter/ChangesetReverter.java
17 17 import org.openstreetmap.josm.data.conflict.Conflict; 18 18 import org.openstreetmap.josm.data.coor.LatLon; 19 19 import org.openstreetmap.josm.data.osm.Changeset; 20 import org.openstreetmap.josm.data.osm.ChangesetDataSet; 21 import org.openstreetmap.josm.data.osm.ChangesetDataSet.ChangesetDataSetEntry; 22 import org.openstreetmap.josm.data.osm.ChangesetDataSet.ChangesetModificationType; 20 23 import org.openstreetmap.josm.data.osm.DataSet; 21 24 import org.openstreetmap.josm.data.osm.Node; 22 25 import org.openstreetmap.josm.data.osm.OsmPrimitive; … … 23 26 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 24 27 import org.openstreetmap.josm.data.osm.PrimitiveId; 25 28 import org.openstreetmap.josm.data.osm.Relation; 26 import org.openstreetmap.josm.data.osm.RelationMember;27 29 import org.openstreetmap.josm.data.osm.RelationMemberData; 28 30 import org.openstreetmap.josm.data.osm.SimplePrimitiveId; 29 31 import org.openstreetmap.josm.data.osm.Way; … … 37 39 import org.openstreetmap.josm.gui.util.GuiHelper; 38 40 import org.openstreetmap.josm.io.MultiFetchServerObjectReader; 39 41 import org.openstreetmap.josm.io.OsmApiException; 42 import org.openstreetmap.josm.io.OsmServerChangesetReader; 40 43 import org.openstreetmap.josm.io.OsmTransferException; 41 44 import org.openstreetmap.josm.tools.Logging; 42 45 import org.openstreetmap.josm.tools.Utils; 43 46 44 import reverter.corehacks.ChangesetDataSet;45 import reverter.corehacks.ChangesetDataSet.ChangesetDataSetEntry;46 import reverter.corehacks.ChangesetDataSet.ChangesetModificationType;47 import reverter.corehacks.OsmServerChangesetReader;48 49 47 /** 50 48 * Fetches and stores data for reverting of specific changeset. 51 49 * @author Upliner … … 147 145 } 148 146 this.revertType = revertType; 149 147 150 OsmServerChangesetReader csr = new OsmServerChangesetReader( );148 OsmServerChangesetReader csr = new OsmServerChangesetReader(true, true); 151 149 monitor.beginTask("", 2); 152 changeset = csr.readChangeset(changesetId, monitor.createSubTaskMonitor(1, false));150 changeset = csr.readChangeset(changesetId, false, monitor.createSubTaskMonitor(1, false)); 153 151 if (MODERATOR_REDACTION_ACCOUNTS.contains(changeset.getUser().getId())) { 154 152 throw new RevertRedactedChangesetException(tr("It is not allowed to revert changeset from {0}", changeset.getUser().getName())); 155 153 } … … 225 223 for (HashSet<HistoryOsmPrimitive> collection : Arrays.asList(updated, deleted)) { 226 224 for (HistoryOsmPrimitive entry : collection) { 227 225 PrimitiveId id = entry.getPrimitiveId(); 228 readObjectVersion(rdr, id, cds.getEarliestVersion(id)-1, progressMonitor); 226 HistoryOsmPrimitive csPrimitive = cds.getPrimitive(id); 227 if (csPrimitive == null || csPrimitive.getVersion() == 1) 228 throw new OsmTransferException(tr("Unexpected data in changeset {1}" , changesetId)); 229 readObjectVersion(rdr, id, (int) cds.getPrimitive(id).getVersion() - 1, progressMonitor); 229 230 if (progressMonitor.isCanceled()) return; 230 231 } 231 232 } -
src/reverter/corehacks/ChangesetDataSet.java
1 // License: GPL. For details, see LICENSE file.2 package reverter.corehacks;3 4 import java.util.HashMap;5 import java.util.HashSet;6 import java.util.Iterator;7 import java.util.Map;8 import java.util.Map.Entry;9 import java.util.Set;10 11 import org.openstreetmap.josm.data.osm.PrimitiveId;12 import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;13 import org.openstreetmap.josm.tools.CheckParameterUtil;14 15 /**16 * A ChangesetDataSet holds the content of a changeset.17 */18 public class ChangesetDataSet {19 20 public enum ChangesetModificationType {21 CREATED,22 UPDATED,23 DELETED24 }25 26 public interface ChangesetDataSetEntry {27 ChangesetModificationType getModificationType();28 29 HistoryOsmPrimitive getPrimitive();30 31 int getEarliestVersion();32 }33 34 private final Map<PrimitiveId, Integer> earliestVersions = new HashMap<>();35 private final Map<PrimitiveId, HistoryOsmPrimitive> primitives = new HashMap<>();36 private final Map<PrimitiveId, ChangesetModificationType> modificationTypes = new HashMap<>();37 38 /**39 * Remembers a history primitive with the given modification type40 *41 * @param primitive the primitive. Must not be null.42 * @param cmt the modification type. Must not be null.43 * @throws IllegalArgumentException thrown if primitive is null44 * @throws IllegalArgumentException thrown if cmt is null45 */46 public void put(HistoryOsmPrimitive primitive, ChangesetModificationType cmt) throws IllegalArgumentException {47 CheckParameterUtil.ensureParameterNotNull(primitive, "primitive");48 CheckParameterUtil.ensureParameterNotNull(cmt, "cmt");49 PrimitiveId pid = primitive.getPrimitiveId();50 if (primitives.containsKey(pid)) {51 // Save only latest versions of primitives for reverter52 if (primitive.getVersion() < primitives.get(pid).getVersion()) {53 Integer earliest = earliestVersions.get(pid);54 if (earliest == null || primitive.getVersion() < earliest) {55 earliestVersions.put(pid, (int) primitive.getVersion());56 if (cmt == ChangesetModificationType.CREATED)57 modificationTypes.put(pid, cmt);58 }59 return;60 } else {61 if (modificationTypes.get(pid) == ChangesetModificationType.CREATED) {62 cmt = ChangesetModificationType.CREATED;63 }64 if (earliestVersions.get(pid) == null) {65 earliestVersions.put(pid, (int) primitives.get(pid).getVersion());66 }67 }68 }69 primitives.put(pid, primitive);70 modificationTypes.put(pid, cmt);71 }72 73 /**74 * Replies true if the changeset content contains the object with primitive <code>id</code>.75 * @param id the id.76 * @return true if the changeset content contains the object with primitive <code>id</code>77 */78 public boolean contains(PrimitiveId id) {79 if (id == null) return false;80 return primitives.containsKey(id);81 }82 83 /**84 * Replies the modification type for the object with id <code>id</code>. Replies null, if id is null or85 * if the object with id <code>id</code> isn't in the changeset content.86 *87 * @param id the id88 * @return the modification type89 */90 public ChangesetModificationType getModificationType(PrimitiveId id) {91 if (!contains(id)) return null;92 return modificationTypes.get(id);93 }94 95 public int getEarliestVersion(PrimitiveId id) {96 Integer earliestVersion = earliestVersions.get(id);97 if (earliestVersion == null) earliestVersion = (int) primitives.get(id).getVersion();98 return earliestVersion;99 }100 101 /**102 * Replies true if the primitive with id <code>id</code> was created in this103 * changeset. Replies false, if id is null.104 *105 * @param id the id106 * @return true if the primitive with id <code>id</code> was created in this107 * changeset.108 */109 public boolean isCreated(PrimitiveId id) {110 if (!contains(id)) return false;111 return ChangesetModificationType.CREATED.equals(getModificationType(id));112 }113 114 /**115 * Replies true if the primitive with id <code>id</code> was updated in this116 * changeset. Replies false, if id is null.117 *118 * @param id the id119 * @return true if the primitive with id <code>id</code> was updated in this120 * changeset.121 */122 public boolean isUpdated(PrimitiveId id) {123 if (!contains(id)) return false;124 return ChangesetModificationType.UPDATED.equals(getModificationType(id));125 }126 127 /**128 * Replies true if the primitive with id <code>id</code> was deleted in this129 * changeset. Replies false, if id is null.130 *131 * @param id the id132 * @return true if the primitive with id <code>id</code> was deleted in this133 * changeset.134 */135 public boolean isDeleted(PrimitiveId id) {136 if (!contains(id)) return false;137 return ChangesetModificationType.DELETED.equals(getModificationType(id));138 }139 140 /**141 * Replies the set of primitives with a specific modification type142 *143 * @param cmt the modification type. Must not be null.144 * @return the set of primitives145 * @throws IllegalArgumentException thrown if cmt is null146 */147 public Set<HistoryOsmPrimitive> getPrimitivesByModificationType(ChangesetModificationType cmt) throws IllegalArgumentException {148 CheckParameterUtil.ensureParameterNotNull(cmt, "cmt");149 HashSet<HistoryOsmPrimitive> ret = new HashSet<>();150 for (Entry<PrimitiveId, ChangesetModificationType> entry: modificationTypes.entrySet()) {151 if (entry.getValue().equals(cmt)) {152 ret.add(primitives.get(entry.getKey()));153 }154 }155 return ret;156 }157 158 /**159 * Replies the number of objects in the dataset160 *161 * @return the number of objects in the dataset162 */163 public int size() {164 return primitives.size();165 }166 167 /**168 * Replies the {@link HistoryOsmPrimitive} with id <code>id</code> from this169 * dataset. null, if there is no such primitive in the data set.170 *171 * @param id the id172 * @return the {@link HistoryOsmPrimitive} with id <code>id</code> from this173 * dataset174 */175 public HistoryOsmPrimitive getPrimitive(PrimitiveId id) {176 if (id == null) return null;177 return primitives.get(id);178 }179 180 public Iterator<ChangesetDataSetEntry> iterator() {181 return new DefaultIterator();182 }183 184 private static class DefaultChangesetDataSetEntry implements ChangesetDataSetEntry {185 private final ChangesetModificationType modificationType;186 private final HistoryOsmPrimitive primitive;187 private final int earliestVersion;188 189 DefaultChangesetDataSetEntry(ChangesetModificationType modificationType, HistoryOsmPrimitive primitive, int earliestVersion) {190 this.modificationType = modificationType;191 this.primitive = primitive;192 this.earliestVersion = earliestVersion;193 }194 195 @Override196 public ChangesetModificationType getModificationType() {197 return modificationType;198 }199 200 @Override201 public HistoryOsmPrimitive getPrimitive() {202 return primitive;203 }204 205 @Override206 public int getEarliestVersion() {207 return earliestVersion;208 }209 }210 211 private class DefaultIterator implements Iterator<ChangesetDataSetEntry> {212 private final Iterator<Entry<PrimitiveId, ChangesetModificationType>> typeIterator;213 214 DefaultIterator() {215 typeIterator = modificationTypes.entrySet().iterator();216 }217 218 @Override219 public boolean hasNext() {220 return typeIterator.hasNext();221 }222 223 @Override224 public ChangesetDataSetEntry next() {225 Entry<PrimitiveId, ChangesetModificationType> next = typeIterator.next();226 ChangesetModificationType type = next.getValue();227 HistoryOsmPrimitive primitive = primitives.get(next.getKey());228 Integer earliestVersion = earliestVersions.get(next.getKey());229 if (earliestVersion == null) earliestVersion = (int) primitive.getVersion();230 return new DefaultChangesetDataSetEntry(type, primitive, earliestVersion);231 }232 233 @Override234 public void remove() {235 throw new UnsupportedOperationException();236 }237 }238 } -
src/reverter/corehacks/OsmChangesetContentParser.java
1 // License: GPL. For details, see LICENSE file.2 package reverter.corehacks;3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 6 import java.io.IOException;7 import java.io.InputStream;8 import java.io.InputStreamReader;9 import java.io.StringReader;10 import java.io.UnsupportedEncodingException;11 import java.util.Date;12 13 import javax.xml.parsers.ParserConfigurationException;14 import javax.xml.parsers.SAXParserFactory;15 16 import org.openstreetmap.josm.data.coor.LatLon;17 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;18 import org.openstreetmap.josm.data.osm.RelationMemberData;19 import org.openstreetmap.josm.data.osm.User;20 import org.openstreetmap.josm.data.osm.history.HistoryNode;21 import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;22 import org.openstreetmap.josm.data.osm.history.HistoryRelation;23 import org.openstreetmap.josm.data.osm.history.HistoryWay;24 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;25 import org.openstreetmap.josm.gui.progress.ProgressMonitor;26 import org.openstreetmap.josm.tools.CheckParameterUtil;27 import org.openstreetmap.josm.tools.XmlParsingException;28 import org.openstreetmap.josm.tools.date.DateUtils;29 import org.xml.sax.Attributes;30 import org.xml.sax.InputSource;31 import org.xml.sax.Locator;32 import org.xml.sax.SAXException;33 import org.xml.sax.SAXParseException;34 import org.xml.sax.helpers.DefaultHandler;35 36 import reverter.corehacks.ChangesetDataSet.ChangesetModificationType;37 38 /**39 * Parser for OSM changeset content.40 *41 */42 public class OsmChangesetContentParser {43 44 private final InputSource source;45 private final ChangesetDataSet data;46 47 private class Parser extends DefaultHandler {48 49 /** the current primitive to be read */50 private HistoryOsmPrimitive currentPrimitive;51 /** the current change modification type */52 private ChangesetDataSet.ChangesetModificationType currentModificationType;53 54 private Locator locator;55 56 @Override57 public void setDocumentLocator(Locator locator) {58 this.locator = locator;59 }60 61 protected void throwException(String message) throws XmlParsingException {62 throw new XmlParsingException(63 message64 ).rememberLocation(locator);65 }66 67 protected void throwException(Exception e) throws XmlParsingException {68 throw new XmlParsingException(69 e70 ).rememberLocation(locator);71 }72 73 protected long getMandatoryAttributeLong(Attributes attr, String name) throws SAXException {74 String v = attr.getValue(name);75 if (v == null) {76 throwException(tr("Missing mandatory attribute ''{0}''.", name));77 }78 Long l = 0L;79 try {80 l = Long.parseLong(v);81 } catch (NumberFormatException e) {82 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));83 }84 if (l < 0) {85 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));86 }87 return l;88 }89 /*90 protected long getAttributeLong(Attributes attr, String name, long defaultValue) throws SAXException{91 String v = attr.getValue(name);92 if (v == null)93 return defaultValue;94 Long l = 0l;95 try {96 l = Long.parseLong(v);97 } catch(NumberFormatException e) {98 throwException(tr("Illegal value for attribute ''{0}'' of type long. Got ''{1}''.", name, v));99 }100 if (l < 0) {101 throwException(tr("Illegal value for attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));102 }103 return l;104 }105 */106 107 protected Double getAttributeDouble(Attributes attr, String name) throws SAXException {108 String v = attr.getValue(name);109 if (v == null) {110 return null;111 }112 double d = 0.0;113 try {114 d = Double.parseDouble(v);115 } catch (NumberFormatException e) {116 throwException(tr("Illegal value for attribute ''{0}'' of type double. Got ''{1}''.", name, v));117 }118 return d;119 }120 121 protected String getMandatoryAttributeString(Attributes attr, String name) throws SAXException {122 String v = attr.getValue(name);123 if (v == null) {124 throwException(tr("Missing mandatory attribute ''{0}''.", name));125 }126 return v;127 }128 /*129 protected String getAttributeString(Attributes attr, String name, String defaultValue) {130 String v = attr.getValue(name);131 if (v == null)132 return defaultValue;133 return v;134 }135 */136 137 protected boolean getMandatoryAttributeBoolean(Attributes attr, String name) throws SAXException {138 String v = attr.getValue(name);139 if (v == null) {140 throwException(tr("Missing mandatory attribute ''{0}''.", name));141 }142 if ("true".equals(v)) return true;143 if ("false".equals(v)) return false;144 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type boolean. Got ''{1}''.", name, v));145 // not reached146 return false;147 }148 149 protected HistoryOsmPrimitive createPrimitive(Attributes atts, OsmPrimitiveType type) throws SAXException {150 long id = getMandatoryAttributeLong(atts, "id");151 long version = getMandatoryAttributeLong(atts, "version");152 long changesetId = getMandatoryAttributeLong(atts, "changeset");153 boolean visible = getMandatoryAttributeBoolean(atts, "visible");154 String v = getMandatoryAttributeString(atts, "timestamp");155 Date timestamp = DateUtils.fromString(v);156 HistoryOsmPrimitive primitive = null;157 // Hack: reverter doesn't need user information, so always use User.getAnonymous()158 // TODO: Update OsmChangesetContentParser from the core or update core OsmChangesetContentParser to make it usable with reverter159 if (type.equals(OsmPrimitiveType.NODE)) {160 Double lat = getAttributeDouble(atts, "lat");161 Double lon = getAttributeDouble(atts, "lon");162 LatLon coor = (lat != null && lon != null) ? new LatLon(lat, lon) : null;163 primitive = new HistoryNode(164 id, version, visible, User.getAnonymous(), changesetId, timestamp, coor165 );166 167 } else if (type.equals(OsmPrimitiveType.WAY)) {168 primitive = new HistoryWay(169 id, version, visible, User.getAnonymous(), changesetId, timestamp170 );171 } else if (type.equals(OsmPrimitiveType.RELATION)) {172 primitive = new HistoryRelation(173 id, version, visible, User.getAnonymous(), changesetId, timestamp174 );175 }176 return primitive;177 }178 179 protected void startNode(Attributes atts) throws SAXException {180 currentPrimitive = createPrimitive(atts, OsmPrimitiveType.NODE);181 }182 183 protected void startWay(Attributes atts) throws SAXException {184 currentPrimitive = createPrimitive(atts, OsmPrimitiveType.WAY);185 }186 187 protected void startRelation(Attributes atts) throws SAXException {188 currentPrimitive = createPrimitive(atts, OsmPrimitiveType.RELATION);189 }190 191 protected void handleTag(Attributes atts) throws SAXException {192 String key = getMandatoryAttributeString(atts, "k");193 String value = getMandatoryAttributeString(atts, "v");194 currentPrimitive.put(key, value);195 }196 197 protected void handleNodeReference(Attributes atts) throws SAXException {198 long ref = getMandatoryAttributeLong(atts, "ref");199 ((HistoryWay) currentPrimitive).addNode(ref);200 }201 202 protected void handleMember(Attributes atts) throws SAXException {203 long ref = getMandatoryAttributeLong(atts, "ref");204 String v = getMandatoryAttributeString(atts, "type");205 OsmPrimitiveType type = null;206 try {207 type = OsmPrimitiveType.fromApiTypeName(v);208 } catch (IllegalArgumentException e) {209 throwException(tr("Illegal value for mandatory attribute ''{0}'' of type OsmPrimitiveType. Got ''{1}''.", "type", v));210 }211 String role = getMandatoryAttributeString(atts, "role");212 RelationMemberData member = new RelationMemberData(role, type, ref);213 ((HistoryRelation) currentPrimitive).addMember(member);214 }215 216 @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {217 if (qName.equals("node")) {218 startNode(atts);219 } else if (qName.equals("way")) {220 startWay(atts);221 } else if (qName.equals("relation")) {222 startRelation(atts);223 } else if (qName.equals("tag")) {224 handleTag(atts);225 } else if (qName.equals("nd")) {226 handleNodeReference(atts);227 } else if (qName.equals("member")) {228 handleMember(atts);229 } else if (qName.equals("osmChange")) {230 // do nothing231 } else if (qName.equals("create")) {232 currentModificationType = ChangesetModificationType.CREATED;233 } else if (qName.equals("modify")) {234 currentModificationType = ChangesetModificationType.UPDATED;235 } else if (qName.equals("delete")) {236 currentModificationType = ChangesetModificationType.DELETED;237 } else {238 System.err.println(tr("Warning: unsupported start element ''{0}'' in changeset content at position ({1},{2}). Skipping.",239 qName, locator.getLineNumber(), locator.getColumnNumber()));240 }241 }242 243 @Override244 public void endElement(String uri, String localName, String qName) throws SAXException {245 if (qName.equals("node")246 || qName.equals("way")247 || qName.equals("relation")) {248 if (currentModificationType == null) {249 throwException(250 tr("Illegal document structure. Found node, way, or relation outside of ''create'', ''modify'', or ''delete''."));251 }252 data.put(currentPrimitive, currentModificationType);253 } else if (qName.equals("osmChange")) {254 // do nothing255 } else if (qName.equals("create")) {256 currentModificationType = null;257 } else if (qName.equals("modify")) {258 currentModificationType = null;259 } else if (qName.equals("delete")) {260 currentModificationType = null;261 } else if (qName.equals("tag")) {262 // do nothing263 } else if (qName.equals("nd")) {264 // do nothing265 } else if (qName.equals("member")) {266 // do nothing267 } else {268 System.err.println(tr("Warning: unsupported end element ''{0}'' in changeset content at position ({1},{2}). Skipping.",269 qName, locator.getLineNumber(), locator.getColumnNumber()));270 }271 }272 273 @Override274 public void error(SAXParseException e) throws SAXException {275 throwException(e);276 }277 278 @Override279 public void fatalError(SAXParseException e) throws SAXException {280 throwException(e);281 }282 }283 284 /**285 * Create a parser286 *287 * @param source the input stream with the changeset content as XML document. Must not be null.288 * @throws IllegalArgumentException thrown if source is null.289 * @throws UnsupportedEncodingException if the named charset is not supported290 */291 public OsmChangesetContentParser(InputStream source) throws UnsupportedEncodingException {292 CheckParameterUtil.ensureParameterNotNull(source, "source");293 this.source = new InputSource(new InputStreamReader(source, "UTF-8"));294 data = new ChangesetDataSet();295 }296 297 public OsmChangesetContentParser(String source) {298 CheckParameterUtil.ensureParameterNotNull(source, "source");299 this.source = new InputSource(new StringReader(source));300 data = new ChangesetDataSet();301 }302 303 /**304 * Parses the content305 *306 * @param progressMonitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE}307 * if null308 * @return the parsed data309 * @throws XmlParsingException if something went wrong. Check for chained exceptions.310 */311 public ChangesetDataSet parse(ProgressMonitor progressMonitor) throws XmlParsingException {312 if (progressMonitor == null) {313 progressMonitor = NullProgressMonitor.INSTANCE;314 }315 try {316 progressMonitor.beginTask("");317 progressMonitor.indeterminateSubTask(tr("Parsing changeset content ..."));318 SAXParserFactory.newInstance().newSAXParser().parse(source, new Parser());319 } catch (XmlParsingException e) {320 throw e;321 } catch (ParserConfigurationException e) {322 throw new XmlParsingException(e);323 } catch (SAXException e) {324 throw new XmlParsingException(e);325 } catch (IOException e) {326 throw new XmlParsingException(e);327 } finally {328 progressMonitor.finishTask();329 }330 return data;331 }332 333 /**334 * Parses the content from the input source335 *336 * @return the parsed data337 * @throws XmlParsingException if something went wrong. Check for chained exceptions.338 */339 public ChangesetDataSet parse() throws XmlParsingException {340 return parse(null);341 }342 } -
src/reverter/corehacks/OsmServerChangesetReader.java
1 // License: GPL. For details, see LICENSE file.2 package reverter.corehacks;3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 import static org.openstreetmap.josm.tools.I18n.trn;6 7 import java.io.InputStream;8 import java.io.UnsupportedEncodingException;9 import java.text.MessageFormat;10 import java.util.ArrayList;11 import java.util.Collection;12 import java.util.Collections;13 import java.util.Iterator;14 import java.util.List;15 16 import org.openstreetmap.josm.data.osm.Changeset;17 import org.openstreetmap.josm.data.osm.DataSet;18 import org.openstreetmap.josm.data.osm.OsmPrimitive;19 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;20 import org.openstreetmap.josm.gui.progress.ProgressMonitor;21 import org.openstreetmap.josm.io.ChangesetQuery;22 import org.openstreetmap.josm.io.IllegalDataException;23 import org.openstreetmap.josm.io.OsmChangesetParser;24 import org.openstreetmap.josm.io.OsmServerReader;25 import org.openstreetmap.josm.io.OsmTransferException;26 import org.openstreetmap.josm.tools.CheckParameterUtil;27 import org.openstreetmap.josm.tools.XmlParsingException;28 29 /**30 * Reads the history of an {@link OsmPrimitive} from the OSM API server.31 *32 */33 public class OsmServerChangesetReader extends OsmServerReader {34 35 /**36 * constructor37 *38 */39 public OsmServerChangesetReader() {40 setDoAuthenticate(false);41 }42 43 /**44 * don't use - not implemented!45 *46 */47 @Override48 public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {49 return null;50 }51 52 /**53 * Queries a list54 * @param query the query specification. Must not be null.55 * @param monitor a progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null56 * @return the list of changesets read from the server or {@code null}57 * @throws IllegalArgumentException thrown if query is null58 * @throws OsmTransferException thrown if something goes wrong w59 */60 public List<Changeset> queryChangesets(ChangesetQuery query, ProgressMonitor monitor) throws OsmTransferException {61 CheckParameterUtil.ensureParameterNotNull(query, "query");62 if (monitor == null) {63 monitor = NullProgressMonitor.INSTANCE;64 }65 try {66 monitor.beginTask(tr("Reading changesets..."));67 StringBuilder sb = new StringBuilder();68 sb.append("changesets?").append(query.getQueryString());69 InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));70 if (in == null)71 return null;72 monitor.indeterminateSubTask(tr("Downloading changesets ..."));73 return OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));74 } catch (OsmTransferException e) {75 throw e;76 } catch (IllegalDataException e) {77 throw new OsmTransferException(e);78 } finally {79 monitor.finishTask();80 }81 }82 83 /**84 * Reads the changeset with id <code>id</code> from the server85 *86 * @param id the changeset id. id > 0 required.87 * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null88 * @return the changeset read89 * @throws OsmTransferException thrown if something goes wrong90 * @throws IllegalArgumentException if id <= 091 */92 public Changeset readChangeset(long id, ProgressMonitor monitor) throws OsmTransferException {93 if (id <= 0)94 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0 expected. Got ''{1}''.", "id", id));95 if (monitor == null) {96 monitor = NullProgressMonitor.INSTANCE;97 }98 try {99 monitor.beginTask(tr("Reading changeset {0} ...", id));100 StringBuilder sb = new StringBuilder();101 sb.append("changeset/").append(id);102 InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));103 if (in == null)104 return null;105 monitor.indeterminateSubTask(tr("Downloading changeset {0} ...", id));106 List<Changeset> changesets = OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));107 if (changesets == null || changesets.isEmpty())108 return null;109 return changesets.get(0);110 } catch (OsmTransferException e) {111 throw e;112 } catch (IllegalDataException e) {113 throw new OsmTransferException(e);114 } finally {115 monitor.finishTask();116 }117 }118 119 /**120 * Reads the changeset with id <code>id</code> from the server121 *122 * @param ids the collection of ids. Ignored if null. Only load changesets for ids > 0.123 * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null124 * @return the list of changesets read or an empty list or null in case of errors125 * @throws OsmTransferException thrown if something goes wrong126 * @throws IllegalArgumentException if id <= 0127 */128 public List<Changeset> readChangesets(Collection<Integer> ids, ProgressMonitor monitor) throws OsmTransferException {129 if (ids == null)130 return Collections.emptyList();131 if (monitor == null) {132 monitor = NullProgressMonitor.INSTANCE;133 }134 try {135 monitor.beginTask(trn("Downloading {0} changeset ...", "Downloading {0} changesets ...", ids.size(), ids.size()));136 monitor.setTicksCount(ids.size());137 List<Changeset> ret = new ArrayList<>();138 int i = 0;139 for (Iterator<Integer> it = ids.iterator(); it.hasNext();) {140 int id = it.next();141 if (id <= 0) {142 continue;143 }144 i++;145 StringBuilder sb = new StringBuilder();146 sb.append("changeset/").append(id);147 InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));148 if (in == null)149 return null;150 monitor.indeterminateSubTask(tr("({0}/{1}) Downloading changeset {2}...", i, ids.size(), id));151 List<Changeset> changesets = OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));152 if (changesets == null || changesets.isEmpty()) {153 continue;154 }155 ret.addAll(changesets);156 monitor.worked(1);157 }158 return ret;159 } catch (OsmTransferException e) {160 throw e;161 } catch (IllegalDataException e) {162 throw new OsmTransferException(e);163 } finally {164 monitor.finishTask();165 }166 }167 168 /**169 * Downloads the content of a changeset170 *171 * @param id the changeset id. >0 required.172 * @param monitor the progress monitor. {@link NullProgressMonitor#INSTANCE} assumed if null.173 * @return the changeset content174 * @throws IllegalArgumentException thrown if id <= 0175 * @throws OsmTransferException thrown if something went wrong176 */177 public ChangesetDataSet downloadChangeset(int id, ProgressMonitor monitor) throws OsmTransferException {178 if (id <= 0)179 throw new IllegalArgumentException(180 MessageFormat.format("Expected value of type integer > 0 for parameter ''{0}'', got {1}", "id", id));181 if (monitor == null) {182 monitor = NullProgressMonitor.INSTANCE;183 }184 try {185 monitor.beginTask(tr("Downloading changeset content"));186 StringBuilder sb = new StringBuilder();187 sb.append("changeset/").append(id).append("/download");188 InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));189 if (in == null)190 return null;191 monitor.setCustomText(tr("Downloading content for changeset {0} ...", id));192 OsmChangesetContentParser parser = new OsmChangesetContentParser(in);193 return parser.parse(monitor.createSubTaskMonitor(1, true));194 } catch (UnsupportedEncodingException | XmlParsingException e) {195 throw new OsmTransferException(e);196 } finally {197 monitor.finishTask();198 }199 }200 }