source: josm/trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java@ 12634

Last change on this file since 12634 was 12634, checked in by Don-vip, 7 years ago

see #15182 - deprecate Main.worker, replace it by gui.MainApplication.worker + code refactoring to make sure only editor packages use it

  • Property svn:eol-style set to native
File size: 8.9 KB
RevLine 
[7937]1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions.downloadtasks;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.Date;
7import java.util.HashMap;
8import java.util.Iterator;
9import java.util.Map;
[8332]10import java.util.Map.Entry;
[7937]11import java.util.concurrent.Future;
[11746]12import java.util.concurrent.RejectedExecutionException;
[8240]13import java.util.regex.Matcher;
14import java.util.regex.Pattern;
[7937]15
16import org.openstreetmap.josm.Main;
17import org.openstreetmap.josm.data.Bounds;
18import org.openstreetmap.josm.data.osm.DataSet;
19import org.openstreetmap.josm.data.osm.Node;
20import org.openstreetmap.josm.data.osm.NodeData;
21import org.openstreetmap.josm.data.osm.OsmPrimitive;
22import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
23import org.openstreetmap.josm.data.osm.PrimitiveData;
24import org.openstreetmap.josm.data.osm.PrimitiveId;
25import org.openstreetmap.josm.data.osm.RelationData;
26import org.openstreetmap.josm.data.osm.WayData;
27import org.openstreetmap.josm.data.osm.history.History;
28import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
29import org.openstreetmap.josm.data.osm.history.HistoryDataSetListener;
30import org.openstreetmap.josm.data.osm.history.HistoryNode;
31import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
32import org.openstreetmap.josm.data.osm.history.HistoryRelation;
33import org.openstreetmap.josm.data.osm.history.HistoryWay;
[12630]34import org.openstreetmap.josm.gui.MainApplication;
[7937]35import org.openstreetmap.josm.gui.history.HistoryLoadTask;
36import org.openstreetmap.josm.gui.progress.ProgressMonitor;
[8240]37import org.openstreetmap.josm.io.OsmApi;
[7937]38import org.openstreetmap.josm.io.OsmServerLocationReader;
39import org.openstreetmap.josm.io.OsmServerReader;
40import org.openstreetmap.josm.io.OsmTransferException;
[12620]41import org.openstreetmap.josm.tools.Logging;
[7937]42
43/**
44 * Task allowing to download OsmChange data (http://wiki.openstreetmap.org/wiki/OsmChange).
45 * @since 4530
46 */
47public class DownloadOsmChangeTask extends DownloadOsmTask {
48
[8240]49 private static final String OSM_WEBSITE_PATTERN = "https?://www\\.(osm|openstreetmap)\\.org/changeset/(\\p{Digit}+).*";
50
[7937]51 @Override
52 public String[] getPatterns() {
53 return new String[]{"https?://.*/api/0.6/changeset/\\p{Digit}+/download", // OSM API 0.6 changesets
[8240]54 OSM_WEBSITE_PATTERN, // OSM changesets
[7937]55 "https?://.*/.*\\.osc" // Remote .osc files
56 };
57 }
58
59 @Override
60 public String getTitle() {
61 return tr("Download OSM Change");
62 }
63
64 @Override
65 public Future<?> download(boolean newLayer, Bounds downloadArea,
66 ProgressMonitor progressMonitor) {
67 return null;
68 }
69
70 @Override
[10001]71 public Future<?> loadUrl(boolean newLayer, String url, ProgressMonitor progressMonitor) {
[8240]72 final Matcher matcher = Pattern.compile(OSM_WEBSITE_PATTERN).matcher(url);
73 if (matcher.matches()) {
74 url = OsmApi.getOsmApi().getBaseUrl() + "changeset/" + Long.parseLong(matcher.group(2)) + "/download";
75 }
[10001]76 downloadTask = new DownloadTask(newLayer, new OsmServerLocationReader(url), progressMonitor);
[7937]77 // Extract .osc filename from URL to set the new layer name
78 extractOsmFilename("https?://.*/(.*\\.osc)", url);
[12634]79 return MainApplication.worker.submit(downloadTask);
[7937]80 }
81
[11878]82 /**
83 * OsmChange download task.
84 */
[7937]85 protected class DownloadTask extends DownloadOsmTask.DownloadTask {
86
[11878]87 /**
88 * Constructs a new {@code DownloadTask}.
89 * @param newLayer if {@code true}, force download to a new layer
90 * @param reader OSM data reader
91 * @param progressMonitor progress monitor
92 */
93 public DownloadTask(boolean newLayer, OsmServerReader reader, ProgressMonitor progressMonitor) {
[7937]94 super(newLayer, reader, progressMonitor);
95 }
96
97 @Override
98 protected DataSet parseDataSet() throws OsmTransferException {
99 return reader.parseOsmChange(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
100 }
101
102 @Override
103 protected void finish() {
104 super.finish();
105 if (isFailed() || isCanceled() || downloadedData == null)
106 return; // user canceled download or error occurred
107 try {
108 // A changeset does not contain all referred primitives, this is the map of incomplete ones
109 // For each incomplete primitive, we'll have to get its state at date it was referred
110 Map<OsmPrimitive, Date> toLoad = new HashMap<>();
111 for (OsmPrimitive p : downloadedData.allNonDeletedPrimitives()) {
112 if (p.isIncomplete()) {
113 Date timestamp = null;
114 for (OsmPrimitive ref : p.getReferrers()) {
115 if (!ref.isTimestampEmpty()) {
116 timestamp = ref.getTimestamp();
117 break;
118 }
119 }
120 toLoad.put(p, timestamp);
121 }
122 }
123 if (isCanceled()) return;
124 // Let's load all required history
[12634]125 MainApplication.worker.submit(new HistoryLoaderAndListener(toLoad));
[11746]126 } catch (RejectedExecutionException e) {
[7937]127 rememberException(e);
128 setFailed(true);
129 }
130 }
131 }
132
133 /**
134 * Loads history and updates incomplete primitives.
135 */
[8419]136 private static final class HistoryLoaderAndListener extends HistoryLoadTask implements HistoryDataSetListener {
[7937]137
138 private final Map<OsmPrimitive, Date> toLoad;
139
[8332]140 private HistoryLoaderAndListener(Map<OsmPrimitive, Date> toLoad) {
[7937]141 this.toLoad = toLoad;
142 add(toLoad.keySet());
143 // Updating process is done after all history requests have been made
144 HistoryDataSet.getInstance().addHistoryDataSetListener(this);
145 }
146
147 @Override
148 public void historyUpdated(HistoryDataSet source, PrimitiveId id) {
149 Map<OsmPrimitive, Date> toLoadNext = new HashMap<>();
[8332]150 for (Iterator<Entry<OsmPrimitive, Date>> it = toLoad.entrySet().iterator(); it.hasNext();) {
151 Entry<OsmPrimitive, Date> entry = it.next();
152 OsmPrimitive p = entry.getKey();
[7937]153 History history = source.getHistory(p.getPrimitiveId());
[8332]154 Date date = entry.getValue();
[7937]155 // If the history has been loaded and a timestamp is known
156 if (history != null && date != null) {
157 // Lookup for the primitive version at the specified timestamp
158 HistoryOsmPrimitive hp = history.getByDate(date);
159 if (hp != null) {
[10308]160 PrimitiveData data;
[7937]161
162 switch (p.getType()) {
163 case NODE:
[11878]164 data = ((HistoryNode) hp).fillPrimitiveData(new NodeData());
[7937]165 break;
166 case WAY:
[11878]167 data = ((HistoryWay) hp).fillPrimitiveData(new WayData());
[7937]168 // Find incomplete nodes to load at next run
[11878]169 for (Long nodeId : ((HistoryWay) hp).getNodes()) {
[7937]170 if (p.getDataSet().getPrimitiveById(nodeId, OsmPrimitiveType.NODE) == null) {
171 Node n = new Node(nodeId);
172 p.getDataSet().addPrimitive(n);
173 toLoadNext.put(n, date);
174 }
175 }
176 break;
177 case RELATION:
[11878]178 data = ((HistoryRelation) hp).fillPrimitiveData(new RelationData());
[7937]179 break;
180 default: throw new AssertionError("Unknown primitive type");
181 }
182
183 // Load the history data
184 try {
185 p.load(data);
186 // Forget this primitive
187 it.remove();
188 } catch (AssertionError e) {
[12620]189 Logging.log(Logging.LEVEL_ERROR, "Cannot load "+p+':', e);
[7937]190 }
191 }
192 }
193 }
194 source.removeHistoryDataSetListener(this);
195 if (toLoadNext.isEmpty()) {
196 // No more primitive to update. Processing is finished
197 // Be sure all updated primitives are correctly drawn
[12630]198 MainApplication.getMap().repaint();
[7937]199 } else {
200 // Some primitives still need to be loaded
201 // Let's load all required history
[12634]202 MainApplication.worker.submit(new HistoryLoaderAndListener(toLoadNext));
[7937]203 }
204 }
205
206 @Override
207 public void historyDataSetCleared(HistoryDataSet source) {
[9989]208 // Do nothing
[7937]209 }
210 }
211}
Note: See TracBrowser for help on using the repository browser.