source: josm/trunk/src/org/openstreetmap/josm/io/OsmReader.java@ 12698

Last change on this file since 12698 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: 26.3 KB
RevLine 
[8378]1// License: GPL. For details, see LICENSE file.
[283]2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
[10212]6import java.io.IOException;
[283]7import java.io.InputStream;
[4413]8import java.io.InputStreamReader;
[2852]9import java.text.MessageFormat;
[362]10import java.util.ArrayList;
[283]11import java.util.Collection;
[6316]12import java.util.List;
[10223]13import java.util.Objects;
[4413]14import java.util.regex.Matcher;
15import java.util.regex.Pattern;
[283]16
[4530]17import javax.xml.stream.Location;
[4413]18import javax.xml.stream.XMLInputFactory;
19import javax.xml.stream.XMLStreamConstants;
20import javax.xml.stream.XMLStreamException;
[4530]21import javax.xml.stream.XMLStreamReader;
[319]22
[286]23import org.openstreetmap.josm.data.Bounds;
[7575]24import org.openstreetmap.josm.data.DataSource;
[283]25import org.openstreetmap.josm.data.coor.LatLon;
[11435]26import org.openstreetmap.josm.data.osm.AbstractPrimitive;
[4414]27import org.openstreetmap.josm.data.osm.Changeset;
[283]28import org.openstreetmap.josm.data.osm.DataSet;
[11709]29import org.openstreetmap.josm.data.osm.DataSet.UploadPolicy;
[582]30import org.openstreetmap.josm.data.osm.Node;
[2932]31import org.openstreetmap.josm.data.osm.NodeData;
[2444]32import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
[2932]33import org.openstreetmap.josm.data.osm.PrimitiveData;
[343]34import org.openstreetmap.josm.data.osm.Relation;
[2932]35import org.openstreetmap.josm.data.osm.RelationData;
[4490]36import org.openstreetmap.josm.data.osm.RelationMemberData;
[4414]37import org.openstreetmap.josm.data.osm.Tagged;
[283]38import org.openstreetmap.josm.data.osm.User;
39import org.openstreetmap.josm.data.osm.Way;
[2932]40import org.openstreetmap.josm.data.osm.WayData;
[2604]41import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
[1811]42import org.openstreetmap.josm.gui.progress.ProgressMonitor;
[2852]43import org.openstreetmap.josm.tools.CheckParameterUtil;
[12620]44import org.openstreetmap.josm.tools.Logging;
[12588]45import org.openstreetmap.josm.tools.UncheckedParseException;
[11435]46import org.openstreetmap.josm.tools.Utils;
[7299]47import org.openstreetmap.josm.tools.date.DateUtils;
[283]48
49/**
[2115]50 * Parser for the Osm Api. Read from an input stream and construct a dataset out of it.
[283]51 *
[4413]52 * For each xml element, there is a dedicated method.
53 * The XMLStreamReader cursor points to the start of the element, when the method is
54 * entered, and it must point to the end of the same element, when it is exited.
[283]55 */
[4490]56public class OsmReader extends AbstractReader {
[4413]57
[4530]58 protected XMLStreamReader parser;
[4413]59
[5859]60 protected boolean cancel;
61
[4645]62 /** Used by plugins to register themselves as data postprocessors. */
[8126]63 private static volatile List<OsmServerReadPostprocessor> postprocessors;
[4645]64
[9231]65 /** Register a new postprocessor.
66 * @param pp postprocessor
67 * @see #deregisterPostprocessor
68 */
[4645]69 public static void registerPostprocessor(OsmServerReadPostprocessor pp) {
70 if (postprocessors == null) {
[7005]71 postprocessors = new ArrayList<>();
[4645]72 }
73 postprocessors.add(pp);
74 }
75
[9231]76 /**
77 * Deregister a postprocessor previously registered with {@link #registerPostprocessor}.
78 * @param pp postprocessor
79 * @see #registerPostprocessor
80 */
[4645]81 public static void deregisterPostprocessor(OsmServerReadPostprocessor pp) {
82 if (postprocessors != null) {
83 postprocessors.remove(pp);
84 }
85 }
86
[1772]87 /**
[4530]88 * constructor (for private and subclasses use only)
[1811]89 *
[5881]90 * @see #parseDataSet(InputStream, ProgressMonitor)
[1772]91 */
[4530]92 protected OsmReader() {
[8415]93 // Restricts visibility
[1772]94 }
95
[4530]96 protected void setParser(XMLStreamReader parser) {
[4413]97 this.parser = parser;
[1690]98 }
[1353]99
[6621]100 protected void throwException(String msg, Throwable th) throws XMLStreamException {
[10235]101 throw new XmlStreamParsingException(msg, parser.getLocation(), th);
[6621]102 }
103
[4413]104 protected void throwException(String msg) throws XMLStreamException {
[10235]105 throw new XmlStreamParsingException(msg, parser.getLocation());
[4413]106 }
[1677]107
[4530]108 protected void parse() throws XMLStreamException {
[4413]109 int event = parser.getEventType();
110 while (true) {
111 if (event == XMLStreamConstants.START_ELEMENT) {
[4530]112 parseRoot();
[4645]113 } else if (event == XMLStreamConstants.END_ELEMENT)
[4413]114 return;
115 if (parser.hasNext()) {
116 event = parser.next();
117 } else {
118 break;
119 }
120 }
121 parser.close();
122 }
[4645]123
[4530]124 protected void parseRoot() throws XMLStreamException {
[7012]125 if ("osm".equals(parser.getLocalName())) {
[4530]126 parseOsm();
127 } else {
128 parseUnknown();
129 }
130 }
[2070]131
[4413]132 private void parseOsm() throws XMLStreamException {
133 String v = parser.getAttributeValue(null, "version");
134 if (v == null) {
135 throwException(tr("Missing mandatory attribute ''{0}''.", "version"));
[2070]136 }
[7013]137 if (!"0.6".equals(v)) {
[4413]138 throwException(tr("Unsupported version: {0}", v));
139 }
[4414]140 ds.setVersion(v);
[5025]141 String upload = parser.getAttributeValue(null, "upload");
142 if (upload != null) {
[11709]143 for (UploadPolicy policy : UploadPolicy.values()) {
144 if (policy.getXmlFlag().equalsIgnoreCase(upload)) {
145 ds.setUploadPolicy(policy);
146 break;
147 }
148 }
[5025]149 }
[4413]150 String generator = parser.getAttributeValue(null, "generator");
[4414]151 Long uploadChangesetId = null;
152 if (parser.getAttributeValue(null, "upload-changeset") != null) {
153 uploadChangesetId = getLong("upload-changeset");
154 }
[4413]155 while (true) {
156 int event = parser.next();
[6070]157
[5859]158 if (cancel) {
159 cancel = false;
[6621]160 throw new OsmParsingCanceledException(tr("Reading was canceled"), parser.getLocation());
[5859]161 }
[6070]162
[4413]163 if (event == XMLStreamConstants.START_ELEMENT) {
[7012]164 switch (parser.getLocalName()) {
165 case "bounds":
[4413]166 parseBounds(generator);
[7012]167 break;
168 case "node":
[4413]169 parseNode();
[7012]170 break;
171 case "way":
[4413]172 parseWay();
[7012]173 break;
174 case "relation":
[4413]175 parseRelation();
[7012]176 break;
177 case "changeset":
[4414]178 parseChangeset(uploadChangesetId);
[7012]179 break;
180 default:
[4530]181 parseUnknown();
[4413]182 }
[4645]183 } else if (event == XMLStreamConstants.END_ELEMENT)
[4413]184 return;
185 }
186 }
[2070]187
[4413]188 private void parseBounds(String generator) throws XMLStreamException {
189 String minlon = parser.getAttributeValue(null, "minlon");
190 String minlat = parser.getAttributeValue(null, "minlat");
191 String maxlon = parser.getAttributeValue(null, "maxlon");
192 String maxlat = parser.getAttributeValue(null, "maxlat");
193 String origin = parser.getAttributeValue(null, "origin");
194 if (minlon != null && maxlon != null && minlat != null && maxlat != null) {
195 if (origin == null) {
196 origin = generator;
197 }
198 Bounds bounds = new Bounds(
199 Double.parseDouble(minlat), Double.parseDouble(minlon),
200 Double.parseDouble(maxlat), Double.parseDouble(maxlon));
201 if (bounds.isOutOfTheWorld()) {
202 Bounds copy = new Bounds(bounds);
203 bounds.normalize();
[12620]204 Logging.info("Bbox " + copy + " is out of the world, normalized to " + bounds);
[4413]205 }
206 DataSource src = new DataSource(bounds, origin);
[11627]207 ds.addDataSource(src);
[4413]208 } else {
[8510]209 throwException(tr("Missing mandatory attributes on element ''bounds''. " +
[12138]210 "Got minlon=''{0}'',minlat=''{1}'',maxlon=''{2}'',maxlat=''{3}'', origin=''{4}''.",
[4413]211 minlon, minlat, maxlon, maxlat, origin
212 ));
[2070]213 }
[4413]214 jumpToEnd();
215 }
[1169]216
[4532]217 protected Node parseNode() throws XMLStreamException {
[4413]218 NodeData nd = new NodeData();
[5326]219 String lat = parser.getAttributeValue(null, "lat");
220 String lon = parser.getAttributeValue(null, "lon");
[12087]221 LatLon ll = null;
[5326]222 if (lat != null && lon != null) {
[12136]223 try {
224 ll = new LatLon(Double.parseDouble(lat), Double.parseDouble(lon));
225 nd.setCoor(ll);
226 } catch (NumberFormatException e) {
[12620]227 Logging.trace(e);
[12136]228 }
[5326]229 }
[4413]230 readCommon(nd);
[12136]231 if (lat != null && lon != null && (ll == null || !ll.isValid())) {
[12087]232 throwException(tr("Illegal value for attributes ''lat'', ''lon'' on node with ID {0}. Got ''{1}'', ''{2}''.",
233 Long.toString(nd.getId()), lat, lon));
234 }
[4413]235 Node n = new Node(nd.getId(), nd.getVersion());
236 n.setVisible(nd.isVisible());
237 n.load(nd);
238 externalIdMap.put(nd.getPrimitiveId(), n);
239 while (true) {
240 int event = parser.next();
241 if (event == XMLStreamConstants.START_ELEMENT) {
[7012]242 if ("tag".equals(parser.getLocalName())) {
[4413]243 parseTag(n);
244 } else {
[4530]245 parseUnknown();
[4413]246 }
[4645]247 } else if (event == XMLStreamConstants.END_ELEMENT)
[4532]248 return n;
[4413]249 }
250 }
[3129]251
[4532]252 protected Way parseWay() throws XMLStreamException {
[4413]253 WayData wd = new WayData();
254 readCommon(wd);
255 Way w = new Way(wd.getId(), wd.getVersion());
256 w.setVisible(wd.isVisible());
257 w.load(wd);
258 externalIdMap.put(wd.getPrimitiveId(), w);
[1690]259
[7005]260 Collection<Long> nodeIds = new ArrayList<>();
[4413]261 while (true) {
262 int event = parser.next();
263 if (event == XMLStreamConstants.START_ELEMENT) {
[7012]264 switch (parser.getLocalName()) {
265 case "nd":
[4413]266 nodeIds.add(parseWayNode(w));
[7012]267 break;
268 case "tag":
[4413]269 parseTag(w);
[7012]270 break;
271 default:
[4530]272 parseUnknown();
[4413]273 }
274 } else if (event == XMLStreamConstants.END_ELEMENT) {
275 break;
276 }
277 }
[6093]278 if (w.isDeleted() && !nodeIds.isEmpty()) {
[12620]279 Logging.info(tr("Deleted way {0} contains nodes", w.getUniqueId()));
[7005]280 nodeIds = new ArrayList<>();
[4413]281 }
282 ways.put(wd.getUniqueId(), nodeIds);
[4532]283 return w;
[4413]284 }
[1690]285
[4413]286 private long parseWayNode(Way w) throws XMLStreamException {
287 if (parser.getAttributeValue(null, "ref") == null) {
288 throwException(
289 tr("Missing mandatory attribute ''{0}'' on <nd> of way {1}.", "ref", w.getUniqueId())
290 );
291 }
292 long id = getLong("ref");
293 if (id == 0) {
294 throwException(
295 tr("Illegal value of attribute ''ref'' of element <nd>. Got {0}.", id)
296 );
297 }
298 jumpToEnd();
299 return id;
300 }
[1169]301
[4532]302 protected Relation parseRelation() throws XMLStreamException {
[4413]303 RelationData rd = new RelationData();
304 readCommon(rd);
305 Relation r = new Relation(rd.getId(), rd.getVersion());
306 r.setVisible(rd.isVisible());
307 r.load(rd);
308 externalIdMap.put(rd.getPrimitiveId(), r);
[343]309
[7005]310 Collection<RelationMemberData> members = new ArrayList<>();
[4413]311 while (true) {
312 int event = parser.next();
313 if (event == XMLStreamConstants.START_ELEMENT) {
[7012]314 switch (parser.getLocalName()) {
315 case "member":
[4413]316 members.add(parseRelationMember(r));
[7012]317 break;
318 case "tag":
[4413]319 parseTag(r);
[7012]320 break;
321 default:
[4530]322 parseUnknown();
[4413]323 }
324 } else if (event == XMLStreamConstants.END_ELEMENT) {
325 break;
326 }
327 }
[6093]328 if (r.isDeleted() && !members.isEmpty()) {
[12620]329 Logging.info(tr("Deleted relation {0} contains members", r.getUniqueId()));
[7005]330 members = new ArrayList<>();
[4413]331 }
332 relations.put(rd.getUniqueId(), members);
[4532]333 return r;
[4413]334 }
[283]335
[4413]336 private RelationMemberData parseRelationMember(Relation r) throws XMLStreamException {
[4490]337 OsmPrimitiveType type = null;
338 long id = 0;
[4413]339 String value = parser.getAttributeValue(null, "ref");
340 if (value == null) {
[8510]341 throwException(tr("Missing attribute ''ref'' on member in relation {0}.", r.getUniqueId()));
[4413]342 }
343 try {
[4490]344 id = Long.parseLong(value);
[8510]345 } catch (NumberFormatException e) {
[8540]346 throwException(tr("Illegal value for attribute ''ref'' on member in relation {0}. Got {1}", Long.toString(r.getUniqueId()),
347 value), e);
[4413]348 }
349 value = parser.getAttributeValue(null, "type");
350 if (value == null) {
[4490]351 throwException(tr("Missing attribute ''type'' on member {0} in relation {1}.", Long.toString(id), Long.toString(r.getUniqueId())));
[4413]352 }
353 try {
[4490]354 type = OsmPrimitiveType.fromApiTypeName(value);
[8510]355 } catch (IllegalArgumentException e) {
[8509]356 throwException(tr("Illegal value for attribute ''type'' on member {0} in relation {1}. Got {2}.",
357 Long.toString(id), Long.toString(r.getUniqueId()), value), e);
[4413]358 }
[10308]359 String role = parser.getAttributeValue(null, "role");
[1677]360
[4490]361 if (id == 0) {
[4413]362 throwException(tr("Incomplete <member> specification with ref=0"));
363 }
364 jumpToEnd();
[4490]365 return new RelationMemberData(role, type, id);
[4413]366 }
[1169]367
[4414]368 private void parseChangeset(Long uploadChangesetId) throws XMLStreamException {
369
[5996]370 Long id = null;
371 if (parser.getAttributeValue(null, "id") != null) {
372 id = getLong("id");
373 }
374 // Read changeset info if neither upload-changeset nor id are set, or if they are both set to the same value
[10223]375 if (Objects.equals(id, uploadChangesetId)) {
[5996]376 uploadChangeset = new Changeset(id != null ? id.intValue() : 0);
[4414]377 while (true) {
378 int event = parser.next();
379 if (event == XMLStreamConstants.START_ELEMENT) {
[7012]380 if ("tag".equals(parser.getLocalName())) {
[4414]381 parseTag(uploadChangeset);
382 } else {
[4530]383 parseUnknown();
[4414]384 }
[4645]385 } else if (event == XMLStreamConstants.END_ELEMENT)
[4414]386 return;
387 }
388 } else {
389 jumpToEnd(false);
390 }
391 }
392
393 private void parseTag(Tagged t) throws XMLStreamException {
[4413]394 String key = parser.getAttributeValue(null, "k");
395 String value = parser.getAttributeValue(null, "v");
396 if (key == null || value == null) {
397 throwException(tr("Missing key or value attribute in tag."));
[11435]398 } else if (Utils.isStripEmpty(key) && t instanceof AbstractPrimitive) {
399 // #14199: Empty keys as ignored by AbstractPrimitive#put, but it causes problems to fix existing data
400 // Drop the tag on import, but flag the primitive as modified
401 ((AbstractPrimitive) t).setModified(true);
[9087]402 } else {
403 t.put(key.intern(), value.intern());
[4413]404 }
405 jumpToEnd();
406 }
[1169]407
[4530]408 protected void parseUnknown(boolean printWarning) throws XMLStreamException {
[9326]409 final String element = parser.getLocalName();
410 if (printWarning && ("note".equals(element) || "meta".equals(element))) {
411 // we know that Overpass API returns those elements
[12620]412 Logging.debug(tr("Undefined element ''{0}'' found in input stream. Skipping.", element));
[9326]413 } else if (printWarning) {
[12620]414 Logging.info(tr("Undefined element ''{0}'' found in input stream. Skipping.", element));
[4414]415 }
[4413]416 while (true) {
417 int event = parser.next();
418 if (event == XMLStreamConstants.START_ELEMENT) {
[4530]419 parseUnknown(false); /* no more warning for inner elements */
[4645]420 } else if (event == XMLStreamConstants.END_ELEMENT)
[4413]421 return;
422 }
423 }
[1169]424
[4530]425 protected void parseUnknown() throws XMLStreamException {
426 parseUnknown(true);
[4413]427 }
428
[4414]429 /**
430 * When cursor is at the start of an element, moves it to the end tag of that element.
431 * Nested content is skipped.
432 *
[4856]433 * This is basically the same code as parseUnknown(), except for the warnings, which
[4414]434 * are displayed for inner elements and not at top level.
[9231]435 * @param printWarning if {@code true}, a warning message will be printed if an unknown element is met
[8926]436 * @throws XMLStreamException if there is an error processing the underlying XML source
[4414]437 */
438 private void jumpToEnd(boolean printWarning) throws XMLStreamException {
[4413]439 while (true) {
440 int event = parser.next();
441 if (event == XMLStreamConstants.START_ELEMENT) {
[4530]442 parseUnknown(printWarning);
[4645]443 } else if (event == XMLStreamConstants.END_ELEMENT)
[4413]444 return;
[1690]445 }
[4413]446 }
[283]447
[4414]448 private void jumpToEnd() throws XMLStreamException {
449 jumpToEnd(true);
450 }
451
[4413]452 private User createUser(String uid, String name) throws XMLStreamException {
453 if (uid == null) {
454 if (name == null)
455 return null;
456 return User.createLocalUser(name);
[1690]457 }
[4413]458 try {
459 long id = Long.parseLong(uid);
460 return User.createOsmUser(id, name);
[8510]461 } catch (NumberFormatException e) {
[6621]462 throwException(MessageFormat.format("Illegal value for attribute ''uid''. Got ''{0}''.", uid), e);
[4413]463 }
464 return null;
465 }
[283]466
[4413]467 /**
468 * Read out the common attributes and put them into current OsmPrimitive.
[9231]469 * @param current primitive to update
[8926]470 * @throws XMLStreamException if there is an error processing the underlying XML source
[4413]471 */
472 private void readCommon(PrimitiveData current) throws XMLStreamException {
473 current.setId(getLong("id"));
474 if (current.getUniqueId() == 0) {
475 throwException(tr("Illegal object with ID=0."));
[1690]476 }
[1677]477
[4413]478 String time = parser.getAttributeValue(null, "timestamp");
[8461]479 if (time != null && !time.isEmpty()) {
[8582]480 current.setRawTimestamp((int) (DateUtils.tsFromString(time)/1000));
[4413]481 }
[1169]482
[4413]483 String user = parser.getAttributeValue(null, "user");
484 String uid = parser.getAttributeValue(null, "uid");
485 current.setUser(createUser(uid, user));
[2070]486
[4413]487 String visible = parser.getAttributeValue(null, "visible");
488 if (visible != null) {
489 current.setVisible(Boolean.parseBoolean(visible));
490 }
491
492 String versionString = parser.getAttributeValue(null, "version");
493 int version = 0;
494 if (versionString != null) {
495 try {
496 version = Integer.parseInt(versionString);
[8510]497 } catch (NumberFormatException e) {
[7869]498 throwException(tr("Illegal value for attribute ''version'' on OSM primitive with ID {0}. Got {1}.",
499 Long.toString(current.getUniqueId()), versionString), e);
[1690]500 }
[7012]501 switch (ds.getVersion()) {
502 case "0.6":
[6936]503 if (version <= 0 && !current.isNew()) {
[7869]504 throwException(tr("Illegal value for attribute ''version'' on OSM primitive with ID {0}. Got {1}.",
505 Long.toString(current.getUniqueId()), versionString));
[6936]506 } else if (version < 0 && current.isNew()) {
[12620]507 Logging.warn(tr("Normalizing value of attribute ''version'' of element {0} to {2}, API version is ''{3}''. Got {1}.",
[7869]508 current.getUniqueId(), version, 0, "0.6"));
[4413]509 version = 0;
[2070]510 }
[7012]511 break;
512 default:
[4413]513 // should not happen. API version has been checked before
514 throwException(tr("Unknown or unsupported API version. Got {0}.", ds.getVersion()));
[2070]515 }
[4413]516 } else {
517 // version expected for OSM primitives with an id assigned by the server (id > 0), since API 0.6
[7012]518 if (!current.isNew() && ds.getVersion() != null && "0.6".equals(ds.getVersion())) {
[4413]519 throwException(tr("Missing attribute ''version'' on OSM primitive with ID {0}.", Long.toString(current.getUniqueId())));
[2070]520 }
[4413]521 }
522 current.setVersion(version);
[2604]523
[4413]524 String action = parser.getAttributeValue(null, "action");
525 if (action == null) {
526 // do nothing
[7012]527 } else if ("delete".equals(action)) {
[4413]528 current.setDeleted(true);
529 current.setModified(current.isVisible());
[7012]530 } else if ("modify".equals(action)) {
[4413]531 current.setModified(true);
532 }
533
534 String v = parser.getAttributeValue(null, "changeset");
535 if (v == null) {
536 current.setChangesetId(0);
537 } else {
538 try {
539 current.setChangesetId(Integer.parseInt(v));
[7081]540 } catch (IllegalArgumentException e) {
[12620]541 Logging.debug(e.getMessage());
[6936]542 if (current.isNew()) {
[4413]543 // for a new primitive we just log a warning
[12620]544 Logging.info(tr("Illegal value for attribute ''changeset'' on new object {1}. Got {0}. Resetting to 0.",
[8540]545 v, current.getUniqueId()));
[4413]546 current.setChangesetId(0);
547 } else {
548 // for an existing primitive this is a problem
[6621]549 throwException(tr("Illegal value for attribute ''changeset''. Got {0}.", v), e);
[2604]550 }
[7081]551 } catch (IllegalStateException e) {
552 // thrown for positive changeset id on new primitives
[12620]553 Logging.debug(e);
554 Logging.info(e.getMessage());
[7081]555 current.setChangesetId(0);
[4413]556 }
[7081]557 if (current.getChangesetId() <= 0) {
[6936]558 if (current.isNew()) {
[4413]559 // for a new primitive we just log a warning
[12620]560 Logging.info(tr("Illegal value for attribute ''changeset'' on new object {1}. Got {0}. Resetting to 0.",
[8540]561 v, current.getUniqueId()));
[4413]562 current.setChangesetId(0);
563 } else {
564 // for an existing primitive this is a problem
565 throwException(tr("Illegal value for attribute ''changeset''. Got {0}.", v));
[2604]566 }
567 }
[1690]568 }
[4413]569 }
[283]570
[4413]571 private long getLong(String name) throws XMLStreamException {
572 String value = parser.getAttributeValue(null, name);
573 if (value == null) {
[8510]574 throwException(tr("Missing required attribute ''{0}''.", name));
[4413]575 }
576 try {
577 return Long.parseLong(value);
[8510]578 } catch (NumberFormatException e) {
579 throwException(tr("Illegal long value for attribute ''{0}''. Got ''{1}''.", name, value), e);
[4413]580 }
581 return 0; // should not happen
582 }
583
[6621]584 /**
585 * Exception thrown after user cancelation.
586 */
[10235]587 private static final class OsmParsingCanceledException extends XmlStreamParsingException implements ImportCancelException {
[6621]588 /**
589 * Constructs a new {@code OsmParsingCanceledException}.
590 * @param msg The error message
591 * @param location The parser location
592 */
[8836]593 OsmParsingCanceledException(String msg, Location location) {
[6621]594 super(msg, location);
595 }
596 }
597
[11919]598 @Override
[4530]599 protected DataSet doParseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
[2604]600 if (progressMonitor == null) {
601 progressMonitor = NullProgressMonitor.INSTANCE;
602 }
[10615]603 ProgressMonitor.CancelListener cancelListener = () -> cancel = true;
[5859]604 progressMonitor.addCancelListener(cancelListener);
[2852]605 CheckParameterUtil.ensureParameterNotNull(source, "source");
[1690]606 try {
[2070]607 progressMonitor.beginTask(tr("Prepare OSM data...", 2));
[2751]608 progressMonitor.indeterminateSubTask(tr("Parsing OSM data..."));
[3372]609
[7033]610 try (InputStreamReader ir = UTFInputStreamReader.create(source)) {
[10702]611 XMLInputFactory factory = XMLInputFactory.newInstance();
612 // do not try to load external entities
613 factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
614 factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
615 setParser(factory.createXMLStreamReader(ir));
[7033]616 parse();
617 }
[2070]618 progressMonitor.worked(1);
[1353]619
[2751]620 progressMonitor.indeterminateSubTask(tr("Preparing data set..."));
[4530]621 prepareDataSet();
[1811]622 progressMonitor.worked(1);
[4645]623
624 // iterate over registered postprocessors and give them each a chance
625 // to modify the dataset we have just loaded.
626 if (postprocessors != null) {
627 for (OsmServerReadPostprocessor pp : postprocessors) {
628 pp.postprocessDataSet(getDataSet(), progressMonitor);
629 }
630 }
[4530]631 return getDataSet();
[8510]632 } catch (IllegalDataException e) {
[2070]633 throw e;
[12588]634 } catch (XmlStreamParsingException | UncheckedParseException e) {
[2070]635 throw new IllegalDataException(e.getMessage(), e);
[8510]636 } catch (XMLStreamException e) {
[4413]637 String msg = e.getMessage();
638 Pattern p = Pattern.compile("Message: (.+)");
639 Matcher m = p.matcher(msg);
640 if (m.find()) {
641 msg = m.group(1);
642 }
[4645]643 if (e.getLocation() != null)
[8509]644 throw new IllegalDataException(tr("Line {0} column {1}: ",
645 e.getLocation().getLineNumber(), e.getLocation().getColumnNumber()) + msg, e);
[4645]646 else
[4413]647 throw new IllegalDataException(msg, e);
[10212]648 } catch (IOException e) {
[2070]649 throw new IllegalDataException(e);
[1811]650 } finally {
651 progressMonitor.finishTask();
[5859]652 progressMonitor.removeCancelListener(cancelListener);
[1811]653 }
[1690]654 }
[4645]655
[4530]656 /**
657 * Parse the given input source and return the dataset.
658 *
659 * @param source the source input stream. Must not be null.
[5266]660 * @param progressMonitor the progress monitor. If null, {@link NullProgressMonitor#INSTANCE} is assumed
[4530]661 *
662 * @return the dataset with the parsed data
[8509]663 * @throws IllegalDataException if an error was found while parsing the data from the source
[8291]664 * @throws IllegalArgumentException if source is null
[4530]665 */
666 public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
667 return new OsmReader().doParseDataSet(source, progressMonitor);
668 }
[283]669}
Note: See TracBrowser for help on using the repository browser.