Changeset 36237 in osm


Ignore:
Timestamp:
2024-04-04T07:22:56+02:00 (8 months ago)
Author:
GerdP
Message:

fix #23584: Reverter plugin crash

  • correct fixNodesWithoutCoordinates so that it retrieves the same data as before the use of the multifetch API
  • improve handling of rc 404 from multifetch
  • move duplicated code into new method readMultiObjectsOrNextOlder() which handles the case that a multifetch did not retrieve all wanted objects
Location:
applications/editors/josm/plugins/reverter/src/reverter
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/reverter/src/reverter/ChangesetReverter.java

    r36233 r36237  
    55import static org.openstreetmap.josm.tools.I18n.trn;
    66
    7 import java.net.HttpURLConnection;
    87import java.util.ArrayList;
    98import java.util.Arrays;
     
    4746import org.openstreetmap.josm.gui.util.GuiHelper;
    4847import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
    49 import org.openstreetmap.josm.io.OsmApiException;
    5048import org.openstreetmap.josm.io.OsmServerChangesetReader;
    5149import org.openstreetmap.josm.io.OsmTransferException;
    52 import org.openstreetmap.josm.tools.Logging;
    5350
    5451/**
     
    204201    }
    205202
    206     private static void readObjectVersion(OsmServerMultiObjectReader rdr, PrimitiveId id, int version, ProgressMonitor progressMonitor)
    207             throws OsmTransferException {
    208         boolean readOK = false;
    209         while (!readOK && version >= 1) {
    210             try {
    211                 rdr.readObject(id, version, progressMonitor.createSubTaskMonitor(1, true));
    212                 readOK = true;
    213             } catch (OsmApiException e) {
    214                 if (e.getResponseCode() != HttpURLConnection.HTTP_FORBIDDEN) {
    215                     throw e;
    216                 }
    217                 String message = "Version " + version + " of " + id + " is unauthorized";
    218                 Logging.info(version <= 1 ? message : message + ", requesting previous one");
    219                 version--;
    220             }
    221         }
    222         if (!readOK) {
    223             Logging.warn("Cannot retrieve any previous version of "+id);
    224         }
    225     }
    226 
    227203    /**
    228204     * fetch objects that were updated or deleted by changeset
     
    238214                        trn("Downloading history for {0} object", "Downloading history for {0} objects", num, num)), num + 1);
    239215        try {
    240             HashMap<Long, Integer> nodeList = new HashMap<>(),
    241                     wayList = new HashMap<>(),
    242                     relationList = new HashMap<>();
     216            HashMap<Long, Integer> nodeList = new HashMap<>();
     217            HashMap<Long, Integer> wayList = new HashMap<>();
     218            HashMap<Long, Integer> relationList = new HashMap<>();
    243219
    244220            for (HashSet<HistoryOsmPrimitive> collection : Arrays.asList(updated, deleted)) {
     
    256232                }
    257233            }
    258             rdr.readMultiObjects(OsmPrimitiveType.NODE, nodeList, progressMonitor);
    259             rdr.readMultiObjects(OsmPrimitiveType.WAY, wayList, progressMonitor);
    260             rdr.readMultiObjects(OsmPrimitiveType.RELATION, relationList, progressMonitor);
    261             if (progressMonitor.isCanceled()) return;
    262             // If multi-read failed, retry with regular read
    263             for (Map.Entry<Long, Integer> entry : nodeList.entrySet()) {
    264                 if (progressMonitor.isCanceled()) return;
    265                 readObjectVersion(rdr, new SimplePrimitiveId(entry.getKey(), OsmPrimitiveType.NODE), entry.getValue(), progressMonitor);
    266             }
    267             for (Map.Entry<Long, Integer> entry : wayList.entrySet()) {
    268                 if (progressMonitor.isCanceled()) return;
    269                 readObjectVersion(rdr, new SimplePrimitiveId(entry.getKey(), OsmPrimitiveType.WAY), entry.getValue(), progressMonitor);
    270             }
    271             for (Map.Entry<Long, Integer> entry : relationList.entrySet()) {
    272                 if (progressMonitor.isCanceled()) return;
    273                 readObjectVersion(rdr, new SimplePrimitiveId(entry.getKey(), OsmPrimitiveType.RELATION), entry.getValue(), progressMonitor);
    274             }
     234            rdr.readMultiObjectsOrNextOlder(OsmPrimitiveType.NODE, nodeList, progressMonitor);
     235            rdr.readMultiObjectsOrNextOlder(OsmPrimitiveType.WAY, wayList, progressMonitor);
     236            rdr.readMultiObjectsOrNextOlder(OsmPrimitiveType.RELATION, relationList, progressMonitor);
    275237            if (progressMonitor.isCanceled()) return;
    276238            nds = rdr.parseOsm(progressMonitor.createSubTaskMonitor(1, true));
     
    513475        // Remove primitives where we already know the LatLon.
    514476        nodes.removeIf(n -> {
     477            if (n.isDeleted() || n.isLatLonKnown())
     478                return true;
    515479            PrimitiveId id = n.getPrimitiveId();
    516480            OsmPrimitive p = ds.getPrimitiveById(id);
    517             return !(p instanceof Node) || ((Node) p).isLatLonKnown();
     481            return !(p instanceof Node) || ((Node) p).isLatLonKnown() || p.getVersion() <= 1;
    518482        });
     483
    519484        progressMonitor.worked(num - nodes.size());
    520485
     
    524489                .collect(Collectors.toMap(AbstractPrimitive::getUniqueId,
    525490                        id -> Math.max(1, Optional.ofNullable(ds.getPrimitiveById(id)).orElse(id).getVersion() - 1)));
     491
    526492        try {
    527493            while (!versionMap.isEmpty()) {
     
    529495                final ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(num, false);
    530496                subMonitor.beginTask(tr("Fetching multi-objects"), versionMap.size());
    531                 rds.readMultiObjects(OsmPrimitiveType.NODE, versionMap, subMonitor);
     497                rds.readMultiObjectsOrNextOlder(OsmPrimitiveType.NODE, versionMap, subMonitor);
    532498                subMonitor.finishTask();
    533499                final DataSet history = rds.parseOsm(progressMonitor.createSubTaskMonitor(0, false));
     500                ds.update(() -> updateNodes(progressMonitor, nodes, versionMap, history));
     501                versionMap.values().removeIf(i -> i <= 1);
    534502                versionMap.replaceAll((key, value) -> value - 1);
    535                 versionMap.values().removeIf(i -> i <= 0);
    536                 ds.update(() -> updateNodes(progressMonitor, nodes, versionMap, history));
    537503                if (progressMonitor.isCanceled()) {
    538504                    break;
     
    555521            if (!n.isDeleted() && !n.isLatLonKnown()) {
    556522                final Node historyNode = (Node) history.getPrimitiveById(n);
    557                 if (historyNode != null && historyNode.isLatLonKnown()
    558                         && changeset.getClosedAt().isAfter(historyNode.getInstant())) {
    559                     n.load(historyNode.save());
    560                     versionMap.remove(n.getUniqueId());
    561                     progressMonitor.worked(1);
     523                if (historyNode != null) {
     524                    if (historyNode.isLatLonKnown()
     525                            && changeset.getClosedAt().isAfter(historyNode.getInstant())) {
     526                        n.load(historyNode.save());
     527                        progressMonitor.worked(1);
     528                    } else {
     529                        versionMap.put(n.getId(), historyNode.getVersion());
     530                    }
    562531                }
    563532            }
  • applications/editors/josm/plugins/reverter/src/reverter/OsmServerMultiObjectReader.java

    r36230 r36237  
    66import java.io.IOException;
    77import java.io.InputStream;
     8import java.net.HttpURLConnection;
    89import java.util.ArrayList;
    910import java.util.List;
     
    1617import org.openstreetmap.josm.gui.progress.ProgressMonitor;
    1718import org.openstreetmap.josm.io.IllegalDataException;
     19import org.openstreetmap.josm.io.OsmApiException;
    1820import org.openstreetmap.josm.io.OsmServerReader;
    1921import org.openstreetmap.josm.io.OsmTransferException;
     
    5052     * @return The queries to make
    5153     */
    52     private static List<String> makeQueryStrings(OsmPrimitiveType type, Map<Long,Integer> list) {
     54    private static List<String> makeQueryStrings(OsmPrimitiveType type, Map<Long, Integer> list) {
    5355        // This is a "worst-case" calculation. Keep it fast (and err higher rather than lower), not accurate.
    5456        final int expectedSize = (int) (list.entrySet().stream().mapToLong(entry ->
     
    6365        List<String> result = new ArrayList<>(expectedSize + 1);
    6466        StringBuilder sb = new StringBuilder();
    65         int cnt=0;
    66         for (Map.Entry<Long,Integer> entry : list.entrySet()) {
     67        int cnt = 0;
     68        for (Map.Entry<Long, Integer> entry : list.entrySet()) {
    6769            if (cnt == 0) {
    6870                sb.append(type.getAPIName());
     
    8385            }
    8486        }
    85         if (cnt>0) {
     87        if (cnt > 0) {
    8688            result.add(sb.toString());
    8789        }
     
    109111
    110112    /**
    111      * Parse many objects
     113     * Parse many objects.
    112114     * @param type The object type (<i>must</i> be common between all objects)
    113      * @param list The map of object id to object version
     115     * @param list The map of object id to object version. Successfully retrieved objects are removed.
    114116     * @param progressMonitor The progress monitor to update
    115117     * @throws OsmTransferException If there is an issue getting the data
    116118     */
    117     public void readMultiObjects(OsmPrimitiveType type, Map<Long,Integer> list, ProgressMonitor progressMonitor) throws OsmTransferException {
    118         for (String query : makeQueryStrings(type,list)) {
     119    public void readMultiObjects(OsmPrimitiveType type, Map<Long, Integer> list, ProgressMonitor progressMonitor) throws OsmTransferException {
     120        for (String query : makeQueryStrings(type, list)) {
    119121            if (progressMonitor.isCanceled()) {
    120122                return;
     
    130132                Logging.warn(e);
    131133                throw new OsmTransferException(e);
     134            } catch (OsmApiException e) {
     135                Logging.warn(e);
     136                // allow to continue further bulk requests
     137                if (e.getResponseCode() != HttpURLConnection.HTTP_FORBIDDEN
     138                        && e.getResponseCode() != HttpURLConnection.HTTP_NOT_FOUND) {
     139                    throw e;
     140                }
    132141            } finally {
    133142                rdr.callback = null;
    134143            }
     144        }
     145    }
     146
     147    /**
     148     * Parse many objects. If redacted elements are requested the method tries to retrieve the next older version.
     149     * @param type The object type (<i>must</i> be common between all objects)
     150     * @param list The map of object id to object version. Successfully retrieved objects are removed.
     151     * @param progressMonitor The progress monitor to update
     152     * @throws OsmTransferException If there is an issue getting the data
     153     */
     154    public void readMultiObjectsOrNextOlder(OsmPrimitiveType type, Map<Long, Integer> list,
     155            ProgressMonitor progressMonitor) throws OsmTransferException {
     156        readMultiObjects(type, list, progressMonitor);
     157        // If multi-read failed, retry with regular read
     158        for (Map.Entry<Long, Integer> entry : list.entrySet()) {
     159            if (progressMonitor.isCanceled()) return;
     160            readObjectVersion(type, entry.getKey(), entry.getValue(), progressMonitor);
     161        }
     162    }
     163
     164    private void readObjectVersion(OsmPrimitiveType type, long id, int version, ProgressMonitor progressMonitor)
     165            throws OsmTransferException {
     166        boolean readOK = false;
     167        while (!readOK && version >= 1) {
     168            try {
     169                readObject(id, version, type, progressMonitor.createSubTaskMonitor(1, true));
     170                readOK = true;
     171            } catch (OsmApiException e) {
     172                if (e.getResponseCode() != HttpURLConnection.HTTP_FORBIDDEN) {
     173                    throw e;
     174                }
     175                String message = "Version " + version + " of " + id + " is unauthorized";
     176                Logging.info(version <= 1 ? message : message + ", requesting previous one");
     177                version--;
     178            }
     179        }
     180        if (!readOK) {
     181            Logging.warn("Cannot retrieve any previous version of {1} {2}", type, id);
    135182        }
    136183    }
Note: See TracChangeset for help on using the changeset viewer.