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

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

findbugs - EI_EXPOSE_REP2 + javadoc

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