source: josm/trunk/src/org/openstreetmap/josm/gui/io/AbstractPrimitiveTask.java@ 13652

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

fix #8039, see #10456 - fix bugs with non-downloadable layers

  • Property svn:eol-style set to native
File size: 7.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.io;
3
4import static org.openstreetmap.josm.tools.CheckParameterUtil.ensureParameterNotNull;
5
6import java.io.IOException;
7import java.util.Set;
8
9import org.openstreetmap.josm.actions.AutoScaleAction;
10import org.openstreetmap.josm.data.osm.DataSet;
11import org.openstreetmap.josm.data.osm.DataSetMerger;
12import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
13import org.openstreetmap.josm.data.osm.PrimitiveId;
14import org.openstreetmap.josm.data.osm.Relation;
15import org.openstreetmap.josm.data.osm.Way;
16import org.openstreetmap.josm.gui.ExceptionDialogUtil;
17import org.openstreetmap.josm.gui.MainApplication;
18import org.openstreetmap.josm.gui.PleaseWaitRunnable;
19import org.openstreetmap.josm.gui.layer.OsmDataLayer;
20import org.openstreetmap.josm.gui.progress.ProgressMonitor;
21import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor;
22import org.openstreetmap.josm.gui.util.GuiHelper;
23import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
24import org.openstreetmap.josm.io.OsmServerObjectReader;
25import org.openstreetmap.josm.io.OsmTransferException;
26import org.xml.sax.SAXException;
27
28/**
29 * Abstract superclass of download/update primitives tasks.
30 * @since 10129
31 */
32public abstract class AbstractPrimitiveTask extends PleaseWaitRunnable {
33
34 protected final DataSet ds = new DataSet();
35 protected boolean canceled;
36 protected Exception lastException;
37 private Set<PrimitiveId> missingPrimitives;
38
39 protected final OsmDataLayer layer;
40 protected MultiFetchServerObjectReader multiObjectReader;
41 protected OsmServerObjectReader objectReader;
42
43 private boolean zoom;
44 private boolean downloadRelations;
45 private boolean fullRelation;
46
47 protected AbstractPrimitiveTask(String title, OsmDataLayer layer) {
48 this(title, new PleaseWaitProgressMonitor(title), layer);
49 }
50
51 protected AbstractPrimitiveTask(String title, ProgressMonitor progressMonitor, OsmDataLayer layer) {
52 super(title, progressMonitor, false);
53 ensureParameterNotNull(layer, "layer");
54 this.layer = layer;
55 if (!layer.isDownloadable()) {
56 throw new IllegalArgumentException("Non-downloadable layer: " + layer);
57 }
58 }
59
60 protected abstract void initMultiFetchReader(MultiFetchServerObjectReader reader);
61
62 /**
63 * Sets whether the map view should zoom to impacted primitives at the end.
64 * @param zoom {@code true} if the map view should zoom to impacted primitives at the end
65 * @return {@code this}
66 */
67 public final AbstractPrimitiveTask setZoom(boolean zoom) {
68 this.zoom = zoom;
69 return this;
70 }
71
72 /**
73 * Sets whether .
74 * @param downloadRelations {@code true} if
75 * @param fullRelation {@code true} if a full download is required,
76 * i.e., a download including the immediate children of a relation.
77 * @return {@code this}
78 */
79 public final AbstractPrimitiveTask setDownloadRelations(boolean downloadRelations, boolean fullRelation) {
80 this.downloadRelations = downloadRelations;
81 this.fullRelation = fullRelation;
82 return this;
83 }
84
85 /**
86 * Replies the set of ids of all primitives for which a fetch request to the
87 * server was submitted but which are not available from the server (the server
88 * replied a return code of 404)
89 *
90 * @return the set of ids of missing primitives
91 */
92 public Set<PrimitiveId> getMissingPrimitives() {
93 return missingPrimitives;
94 }
95
96 @Override
97 protected void realRun() throws SAXException, IOException, OsmTransferException {
98 DataSet theirDataSet;
99 try {
100 synchronized (this) {
101 if (canceled)
102 return;
103 multiObjectReader = MultiFetchServerObjectReader.create();
104 }
105 initMultiFetchReader(multiObjectReader);
106 theirDataSet = multiObjectReader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
107 missingPrimitives = multiObjectReader.getMissingPrimitives();
108 synchronized (this) {
109 multiObjectReader = null;
110 }
111 new DataSetMerger(ds, theirDataSet).merge();
112
113 if (downloadRelations) {
114 loadIncompleteRelationMembers();
115 }
116
117 loadIncompleteNodes();
118 } catch (OsmTransferException e) {
119 if (canceled)
120 return;
121 lastException = e;
122 }
123 }
124
125 protected void loadIncompleteRelationMembers() throws OsmTransferException {
126 // if incomplete relation members exist, download them too
127 for (Relation r : ds.getRelations()) {
128 if (canceled)
129 return;
130 // Relations may be incomplete in case of nested relations if child relations are accessed before their parent
131 // (it may happen because "relations" has no deterministic sort order, see #10388)
132 if (r.isIncomplete() || r.hasIncompleteMembers()) {
133 synchronized (this) {
134 if (canceled)
135 return;
136 objectReader = new OsmServerObjectReader(r.getId(), OsmPrimitiveType.RELATION, fullRelation);
137 }
138 DataSet theirDataSet = objectReader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
139 synchronized (this) {
140 objectReader = null;
141 }
142 new DataSetMerger(ds, theirDataSet).merge();
143 }
144 }
145 }
146
147 protected void loadIncompleteNodes() throws OsmTransferException {
148 // a way loaded with MultiFetch may have incomplete nodes because at least one of its
149 // nodes isn't present in the local data set. We therefore fully load all ways with incomplete nodes.
150 for (Way w : ds.getWays()) {
151 if (canceled)
152 return;
153 if (w.hasIncompleteNodes()) {
154 synchronized (this) {
155 if (canceled)
156 return;
157 objectReader = new OsmServerObjectReader(w.getId(), OsmPrimitiveType.WAY, true /* full */);
158 }
159 DataSet theirDataSet = objectReader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
160 synchronized (this) {
161 objectReader = null;
162 }
163 new DataSetMerger(ds, theirDataSet).merge();
164 }
165 }
166 }
167
168 @Override
169 protected void cancel() {
170 canceled = true;
171 synchronized (this) {
172 if (multiObjectReader != null) {
173 multiObjectReader.cancel();
174 }
175 if (objectReader != null) {
176 objectReader.cancel();
177 }
178 }
179 }
180
181 @Override
182 protected void finish() {
183 if (canceled)
184 return;
185 if (lastException != null) {
186 ExceptionDialogUtil.explainException(lastException);
187 return;
188 }
189 GuiHelper.runInEDTAndWait(() -> {
190 layer.mergeFrom(ds);
191 if (zoom && MainApplication.getMap() != null)
192 AutoScaleAction.zoomTo(ds.allPrimitives());
193 layer.onPostDownloadFromServer();
194 });
195 }
196}
Note: See TracBrowser for help on using the repository browser.