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

Last change on this file since 10604 was 10463, checked in by Don-vip, 8 years ago

sonar - squid:S1166 - Exception handlers should preserve the original exceptions

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