| 113 | @Override |
| 114 | public void realRun() throws IOException, SAXException, OsmTransferException { |
| 115 | super.realRun(); |
| 116 | final Map<OsmPrimitive, Instant> toLoadNext = new HashMap<>(); |
| 117 | final Map<OsmPrimitive, Instant> toLoad = getToLoad(dataSet); |
| 118 | while (!toLoad.isEmpty()) { |
| 119 | loadLastVersions(toLoad, toLoadNext); |
| 120 | toLoad.putAll(toLoadNext); |
| 121 | toLoadNext.clear(); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | /** |
| 126 | * This gets the last versions of references primitives. This may enough for many of the primitives. |
| 127 | * @param toLoad The primitives to load |
| 128 | * @param toLoadNext The primitives to load next (filled by this method) |
| 129 | */ |
| 130 | private void loadLastVersions(Map<OsmPrimitive, Instant> toLoad, Map<OsmPrimitive, Instant> toLoadNext) throws OsmTransferException { |
| 131 | final Map<OsmPrimitiveType, Map<OsmPrimitive, Instant>> typeMap = toLoad.entrySet().stream() |
| 132 | .collect(Collectors.groupingBy(entry -> entry.getKey().getType(), Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); |
| 133 | final Map<PrimitiveId, OsmPrimitive> idMap = toLoad.keySet().stream() |
| 134 | .collect(Collectors.toMap(OsmPrimitive::getPrimitiveId, Function.identity())); |
| 135 | for (OsmPrimitiveType type : Arrays.asList(OsmPrimitiveType.NODE, OsmPrimitiveType.WAY, OsmPrimitiveType.RELATION)) { |
| 136 | if (!typeMap.containsKey(type)) { |
| 137 | continue; |
| 138 | } |
| 139 | final MultiFetchServerObjectReader reader = MultiFetchServerObjectReader.create(); |
| 140 | typeMap.get(type).forEach((primitive, instant) -> reader.append(primitive)); |
| 141 | final DataSet ds = reader.parseOsm(this.progressMonitor.createSubTaskMonitor(1, false)); |
| 142 | switch (type) { |
| 143 | case NODE: |
| 144 | for (Node node : ds.getNodes()) { |
| 145 | Node original = (Node) idMap.get(node.getPrimitiveId()); |
| 146 | if (original != null && toLoad.get(original).isAfter(node.getInstant())) { |
| 147 | original.load(node.save()); |
| 148 | } |
| 149 | toLoad.remove(original); |
| 150 | } |
| 151 | break; |
| 152 | case WAY: |
| 153 | for (Way way : ds.getWays()) { |
| 154 | Way original = (Way) idMap.get(way.getPrimitiveId()); |
| 155 | if (original != null && toLoad.get(original).isAfter(way.getInstant())) { |
| 156 | Instant date = toLoad.get(original); |
| 157 | original.load(way.save()); |
| 158 | for (Long nodeId : way.getNodeIds()) { |
| 159 | if (way.getDataSet().getPrimitiveById(nodeId, OsmPrimitiveType.NODE) == null) { |
| 160 | Node n = new Node(nodeId); |
| 161 | way.getDataSet().addPrimitive(n); |
| 162 | toLoadNext.put(n, date); |
| 163 | } |
| 164 | } |
| 165 | } |
| 166 | toLoad.remove(original); |
| 167 | } |
| 168 | break; |
| 169 | case RELATION: |
| 170 | for (Relation relation : ds.getRelations()) { |
| 171 | Relation original = (Relation) idMap.get(relation.getPrimitiveId()); |
| 172 | if (original != null && toLoad.get(original).isAfter(relation.getInstant())) { |
| 173 | original.load(relation.save()); |
| 174 | } |
| 175 | toLoad.remove(relation); |
| 176 | } |
| 177 | break; |
| 178 | default: |
| 179 | throw new IllegalStateException("Only Node, Ways, and Relations should be returned by the API"); |
| 180 | } |
| 181 | } |
| 182 | } |
| 183 | |
114 | | Map<OsmPrimitive, Instant> toLoad = new HashMap<>(); |
115 | | for (OsmPrimitive p : downloadedData.allNonDeletedPrimitives()) { |
116 | | if (p.isIncomplete()) { |
117 | | Instant timestamp = p.getReferrers().stream() |
118 | | .filter(ref -> !ref.isTimestampEmpty()) |
119 | | .findFirst() |
120 | | .map(AbstractPrimitive::getInstant) |
121 | | .orElse(null); |
122 | | toLoad.put(p, timestamp); |
123 | | } |
124 | | } |
125 | | if (isCanceled()) return; |
126 | | // Let's load all required history |
127 | | MainApplication.worker.submit(new HistoryLoaderAndListener(toLoad)); |
128 | | } catch (RejectedExecutionException e) { |
129 | | rememberException(e); |
130 | | setFailed(true); |
| 192 | Map<OsmPrimitive, Instant> toLoad = getToLoad(downloadedData); |
| 193 | if (isCanceled()) return; |
| 194 | // Let's load all required history |
| 195 | MainApplication.worker.submit(new HistoryLoaderAndListener(toLoad)); |
| 196 | } catch (RejectedExecutionException e) { |
| 197 | rememberException(e); |
| 198 | setFailed(true); |
| 199 | } |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | /** |
| 204 | * Get the primitives to load more information |
| 205 | * @param ds The dataset to look for incomplete primitives from |
| 206 | * @return The objects that still need to be loaded |
| 207 | */ |
| 208 | private static Map<OsmPrimitive, Instant> getToLoad(DataSet ds) { |
| 209 | Map<OsmPrimitive, Instant> toLoad = new HashMap<>(); |
| 210 | for (OsmPrimitive p : ds.allNonDeletedPrimitives()) { |
| 211 | if (p.isIncomplete()) { |
| 212 | Instant timestamp = p.getReferrers().stream() |
| 213 | .filter(ref -> !ref.isTimestampEmpty()) |
| 214 | .findFirst() |
| 215 | .map(AbstractPrimitive::getInstant) |
| 216 | .orElse(null); |
| 217 | toLoad.put(p, timestamp); |