Changeset 16611 in josm


Ignore:
Timestamp:
2020-06-13T06:35:37+02:00 (8 weeks ago)
Author:
GerdP
Message:

fix #12303: When downloading objects with Overpass API, use recurse up to fetch referrers

  • new static method genOverpassQuery() to generate a single overpass query for all wanted objects
  • use POST instead of PUT to send the query
  • add handling for missing primitives (Overpass doesn't return invisible objects and doesn't a rc 404)
Location:
trunk
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadReferrersTask.java

    r16405 r16611  
    1515import javax.swing.SwingUtilities;
    1616
     17import org.openstreetmap.josm.data.Bounds;
    1718import org.openstreetmap.josm.data.osm.DataSet;
    1819import org.openstreetmap.josm.data.osm.DataSetMerger;
     
    2728import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2829import org.openstreetmap.josm.gui.progress.ProgressMonitor;
     30import org.openstreetmap.josm.io.MultiFetchOverpassObjectReader;
    2931import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
    3032import org.openstreetmap.josm.io.OsmServerBackreferenceReader;
    3133import org.openstreetmap.josm.io.OsmServerReader;
    3234import org.openstreetmap.josm.io.OsmTransferException;
     35import org.openstreetmap.josm.io.OverpassDownloadReader;
    3336import org.openstreetmap.josm.tools.CheckParameterUtil;
    3437import org.openstreetmap.josm.tools.ExceptionUtil;
     
    155158    protected void realRun() throws SAXException, IOException, OsmTransferException {
    156159        try {
    157             progressMonitor.setTicksCount(children.size());
    158             int i = 1;
    159             for (PrimitiveId p : children) {
    160                 if (canceled)
    161                     return;
    162                 String msg;
    163                 String id = Long.toString(p.getUniqueId());
    164                 switch(p.getType()) {
    165                 case NODE: msg = tr("({0}/{1}) Loading parents of node {2}", i, children.size(), id); break;
    166                 case WAY: msg = tr("({0}/{1}) Loading parents of way {2}", i, children.size(), id); break;
    167                 case RELATION: msg = tr("({0}/{1}) Loading parents of relation {2}", i, children.size(), id); break;
    168                 default: throw new AssertionError();
     160            if (Boolean.TRUE.equals(OverpassDownloadReader.FOR_MULTI_FETCH.get())) {
     161                String request = MultiFetchOverpassObjectReader.genOverpassQuery(children, false, true, false);
     162                reader = new OverpassDownloadReader(new Bounds(0, 0, 0, 0),
     163                        OverpassDownloadReader.OVERPASS_SERVER.get(), request);
     164                DataSet ds = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
     165                new DataSetMerger(parents, ds).merge();
     166            } else {
     167                progressMonitor.setTicksCount(children.size());
     168                int i = 1;
     169                for (PrimitiveId p : children) {
     170                    if (canceled)
     171                        return;
     172                    String msg;
     173                    String id = Long.toString(p.getUniqueId());
     174                    switch(p.getType()) {
     175                    case NODE: msg = tr("({0}/{1}) Loading parents of node {2}", i, children.size(), id); break;
     176                    case WAY: msg = tr("({0}/{1}) Loading parents of way {2}", i, children.size(), id); break;
     177                    case RELATION: msg = tr("({0}/{1}) Loading parents of relation {2}", i, children.size(), id); break;
     178                    default: throw new AssertionError();
     179                    }
     180                    progressMonitor.subTask(msg);
     181                    downloadParents(p.getUniqueId(), p.getType(), progressMonitor);
     182                    i++;
    169183                }
    170                 progressMonitor.subTask(msg);
    171                 downloadParents(p.getUniqueId(), p.getType(), progressMonitor);
    172                 i++;
    173             }
    174             Collection<Way> ways = parents.getWays();
    175 
    176             if (!ways.isEmpty()) {
    177                 // Collect incomplete nodes of parent ways
    178                 Set<Node> nodes = ways.stream().flatMap(w -> w.getNodes().stream().filter(OsmPrimitive::isIncomplete))
    179                         .collect(Collectors.toSet());
    180                 if (!nodes.isEmpty()) {
    181                     reader = MultiFetchServerObjectReader.create();
    182                     ((MultiFetchServerObjectReader) reader).append(nodes);
    183                     DataSet wayNodes = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
    184                     synchronized (this) { // avoid race condition in cancel()
    185                         reader = null;
     184                Collection<Way> ways = parents.getWays();
     185
     186                if (!ways.isEmpty()) {
     187                    // Collect incomplete nodes of parent ways
     188                    Set<Node> nodes = ways.stream().flatMap(w -> w.getNodes().stream().filter(OsmPrimitive::isIncomplete))
     189                            .collect(Collectors.toSet());
     190                    if (!nodes.isEmpty()) {
     191                        reader = MultiFetchServerObjectReader.create();
     192                        ((MultiFetchServerObjectReader) reader).append(nodes);
     193                        DataSet wayNodes = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
     194                        synchronized (this) { // avoid race condition in cancel()
     195                            reader = null;
     196                        }
     197                        new DataSetMerger(parents, wayNodes).merge();
    186198                    }
    187                     new DataSetMerger(parents, wayNodes).merge();
    188199                }
    189200            }
     
    194205        }
    195206    }
     207
    196208}
  • trunk/src/org/openstreetmap/josm/gui/io/DownloadPrimitivesWithReferrersTask.java

    r16553 r16611  
    1010import java.text.MessageFormat;
    1111import java.util.ArrayList;
     12import java.util.Collections;
    1213import java.util.HashSet;
     14import java.util.LinkedHashSet;
    1315import java.util.List;
    1416import java.util.Set;
     
    3234import org.openstreetmap.josm.gui.widgets.HtmlPanel;
    3335import org.openstreetmap.josm.gui.widgets.JosmTextArea;
     36import org.openstreetmap.josm.io.MultiFetchOverpassObjectReader;
    3437import org.openstreetmap.josm.io.OsmTransferException;
     38import org.openstreetmap.josm.io.OverpassDownloadReader;
    3539import org.openstreetmap.josm.tools.GBC;
    3640import org.xml.sax.SAXException;
     
    5155    /** Temporary layer where downloaded primitives are put */
    5256    private final OsmDataLayer tmpLayer;
    53     /** Reference to the task that download requested primitives */
    54     private DownloadPrimitivesTask mainTask;
    5557    /** Flag indicated that user ask for cancel this task */
    5658    private boolean canceled;
    5759    /** Reference to the task currently running */
    5860    private PleaseWaitRunnable currentTask;
     61
     62    /** set of missing ids, with overpass API these are also deleted objects */
     63    private Set<PrimitiveId> missingPrimitives;
    5964
    6065    /**
     
    102107    @Override
    103108    protected void realRun() throws SAXException, IOException, OsmTransferException {
     109        if (Boolean.TRUE.equals(OverpassDownloadReader.FOR_MULTI_FETCH.get())) {
     110            useOverpassApi();
     111        } else {
     112            useOSMApi();
     113        }
     114    }
     115
     116    private void useOverpassApi() {
     117        String request = MultiFetchOverpassObjectReader.genOverpassQuery(ids, true, downloadReferrers, full);
     118        currentTask = new DownloadFromOverpassTask(request, tmpLayer.data, getProgressMonitor().createSubTaskMonitor(1, false));
     119        currentTask.run();
     120        missingPrimitives = ids.stream()
     121                .filter(id -> tmpLayer.data.getPrimitiveById(id) == null)
     122                .collect(Collectors.toSet());
     123    }
     124
     125    private void useOSMApi() {
    104126        getProgressMonitor().setTicksCount(ids.size()+1);
    105127        // First, download primitives
    106         mainTask = new DownloadPrimitivesTask(tmpLayer, ids, full, getProgressMonitor().createSubTaskMonitor(1, false));
     128        DownloadPrimitivesTask mainTask = new DownloadPrimitivesTask(tmpLayer, ids, full,
     129                getProgressMonitor().createSubTaskMonitor(1, false));
    107130        synchronized (this) {
    108131            currentTask = mainTask;
     
    113136        }
    114137        currentTask.run();
     138
     139        missingPrimitives = mainTask.getMissingPrimitives();
     140
    115141        // Then, download referrers for each primitive
    116142        if (downloadReferrers && tmpLayer.data != null) {
     
    144170            layer.mergeFrom(tmpLayer);
    145171
     172        // Collect known deleted primitives
     173        final Set<PrimitiveId> del = new HashSet<>();
     174        DataSet ds = MainApplication.getLayerManager().getEditDataSet();
     175        for (PrimitiveId id : ids) {
     176            OsmPrimitive osm = ds.getPrimitiveById(id);
     177            if (osm != null && osm.isDeleted()) {
     178                del.add(id);
     179            }
     180        }
     181        final Set<PrimitiveId> errs;
     182        if (missingPrimitives != null) {
     183            errs = missingPrimitives.stream().filter(id -> !del.contains(id)).collect(Collectors.toCollection(LinkedHashSet::new));
     184        } else {
     185            errs = Collections.emptySet();
     186        }
     187
    146188        // Warm about missing primitives
    147         final Set<PrimitiveId> errs = mainTask.getMissingPrimitives();
    148         if (errs != null && !errs.isEmpty())
     189        if (!errs.isEmpty()) {
     190            final String assumedApiRC;
     191            if (Boolean.TRUE.equals(OverpassDownloadReader.FOR_MULTI_FETCH.get())) {
     192                assumedApiRC = trn("The server did not return data for the requested object, it was either deleted or does not exist.",
     193                        "The server did not return data for the requested objects, they were either deleted or do not exist.",
     194                        errs.size());
     195
     196            } else {
     197                assumedApiRC = tr("The server replied with response code 404.<br>"
     198                        + "This usually means, the server does not know an object with the requested id.");
     199            }
    149200            GuiHelper.runInEDTAndWait(() -> reportProblemDialog(errs,
    150201                    trn("Object could not be downloaded", "Some objects could not be downloaded", errs.size()),
     
    153204                            errs.size(),
    154205                            errs.size())
    155                             + tr("The server replied with response code 404.<br>"
    156                                  + "This usually means, the server does not know an object with the requested id."),
     206                            + assumedApiRC,
    157207                    tr("missing objects:"),
    158208                    JOptionPane.ERROR_MESSAGE
    159209                    ).showDialog());
     210        }
    160211
    161212        // Warm about deleted primitives
    162         final Set<PrimitiveId> del = new HashSet<>();
    163         DataSet ds = MainApplication.getLayerManager().getEditDataSet();
    164         for (PrimitiveId id : ids) {
    165             OsmPrimitive osm = ds.getPrimitiveById(id);
    166             if (osm != null && osm.isDeleted()) {
    167                 del.add(id);
    168             }
    169         }
    170213        if (!del.isEmpty())
    171214            GuiHelper.runInEDTAndWait(() -> reportProblemDialog(del,
     
    191234        }
    192235        List<PrimitiveId> downloaded = new ArrayList<>(ids);
    193         downloaded.removeAll(mainTask.getMissingPrimitives());
     236        downloaded.removeAll(missingPrimitives);
    194237        return downloaded;
    195238    }
  • trunk/src/org/openstreetmap/josm/io/MultiFetchOverpassObjectReader.java

    r16008 r16611  
    22package org.openstreetmap.josm.io;
    33
    4 import java.util.Map.Entry;
     4import java.util.Arrays;
     5import java.util.Collection;
     6import java.util.LinkedHashMap;
     7import java.util.List;
     8import java.util.Map;
    59import java.util.Set;
     10import java.util.TreeSet;
    611import java.util.stream.Collectors;
    712
    813import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     14import org.openstreetmap.josm.data.osm.PrimitiveId;
    915import org.openstreetmap.josm.tools.Logging;
    1016
     
    1521 */
    1622public class MultiFetchOverpassObjectReader extends MultiFetchServerObjectReader {
     23    private static final List<OsmPrimitiveType> wantedOrder = Arrays.asList(OsmPrimitiveType.RELATION,
     24            OsmPrimitiveType.WAY, OsmPrimitiveType.NODE);
    1725
    1826    private static String getPackageString(final OsmPrimitiveType type, Set<Long> idPackage) {
    1927        return idPackage.stream().map(String::valueOf)
    20                 .collect(Collectors.joining(",", type.getAPIName() + (idPackage.size() == 1 ? "(" : "(id:"), ");"));
     28                .collect(Collectors.joining(",", type.getAPIName() + (idPackage.size() == 1 ? "(" : "(id:"), ")"));
    2129    }
    2230
    2331    /**
    24      * Create a single query for all elements
    25      * @return the request string
     32     * Generate single overpass query to retrieve multiple primitives. Can be used to download parents,
     33     * children, the objects, or any combination of them.
     34     * @param ids the collection of ids
     35     * @param includeObjects if false, don't retrieve the primitives (e.g. only the referrers)
     36     * @param recurseUp if true, referrers (parents) of the objects are downloaded and all nodes of parent ways
     37     * @param recurseDownRelations true: yes, recurse down to retrieve complete relations
     38     * @return the overpass query
     39     * @since xxx
    2640     */
    27     protected String buildComplexRequestString() {
    28         StringBuilder sb = new StringBuilder();
    29         int countTypes = 0;
    30         for (Entry<OsmPrimitiveType, Set<Long>> e : primitivesMap.entrySet()) {
    31             if (!e.getValue().isEmpty()) {
    32                 countTypes++;
    33                 String list = getPackageString(e.getKey(), e.getValue());
    34                 switch (e.getKey()) {
    35                 case MULTIPOLYGON:
    36                 case RELATION:
     41    public static String genOverpassQuery(Collection<? extends PrimitiveId> ids, boolean includeObjects, boolean recurseUp,
     42            boolean recurseDownRelations) {
     43        Map<OsmPrimitiveType, Set<Long>> primitivesMap = new LinkedHashMap<>();
     44        Arrays.asList(OsmPrimitiveType.RELATION, OsmPrimitiveType.WAY, OsmPrimitiveType.NODE)
     45                .forEach(type -> primitivesMap.put(type, new TreeSet<>()));
     46        for (PrimitiveId p : ids) {
     47            primitivesMap.get(p.getType()).add(p.getUniqueId());
     48        }
     49        return genOverpassQuery(primitivesMap, includeObjects, recurseUp, recurseDownRelations);
     50    }
     51
     52    /**
     53     * Generate single overpass query to retrieve multiple primitives. Can be used to download parents,
     54     * children, the objects, or any combination of them.
     55     * @param primitivesMap map containing the primitives
     56     * @param includeObjects if false, don't retrieve the primitives (e.g. only the referrers)
     57     * @param recurseUp if true, referrers (parents) of the objects are downloaded and all nodes of parent ways
     58     * @param recurseDownRelations true: yes, recurse down to retrieve complete relations
     59     * @return the overpass query
     60     */
     61    protected static String genOverpassQuery(Map<OsmPrimitiveType, Set<Long>> primitivesMap, boolean includeObjects,
     62            boolean recurseUp, boolean recurseDownRelations) {
     63        if (!(includeObjects || recurseUp || recurseDownRelations))
     64            throw new IllegalArgumentException("At least one options must be true");
     65        StringBuilder sb = new StringBuilder(128);
     66        StringBuilder setsToInclude = new StringBuilder();
     67        StringBuilder up = new StringBuilder();
     68        String down = null;
     69        for (OsmPrimitiveType type : wantedOrder) {
     70            Set<Long> set = primitivesMap.get(type);
     71            if (!set.isEmpty()) {
     72                sb.append(getPackageString(type, set));
     73                if (type == OsmPrimitiveType.NODE) {
     74                    sb.append("->.n;");
     75                    if (includeObjects) {
     76                        setsToInclude.append(".n;");
     77                    }
     78                    if (recurseUp) {
     79                        up.append(".n;way(bn)->.wn;.n;rel(bn)->.rn;");
     80                        setsToInclude.append(".wn;node(w);.rn;");
     81                    }
     82                } else if (type == OsmPrimitiveType.WAY) {
     83                    sb.append("->.w;");
     84                    if (includeObjects) {
     85                        setsToInclude.append(".w;>;");
     86                    }
     87                    if (recurseUp) {
     88                        up.append(".w;rel(bw)->.pw;");
     89                        setsToInclude.append(".pw;");
     90                    }
     91                } else {
     92                    sb.append("->.r;");
     93                    if (includeObjects) {
     94                        setsToInclude.append(".r;");
     95                    }
     96                    if (recurseUp) {
     97                        up.append(".r;rel(br)->.pr;");
     98                        setsToInclude.append(".pr;");
     99                    }
    37100                    if (recurseDownRelations) {
    38                         sb.append('(').append(list);
    39                         sb.setLength(sb.length()-1); // remove semicolon
    40                         //recurse down only one level, see #18835
    41                         sb.append("->.r;.r;rel(r);.r;way(r);>;.r;node(r););");
    42                     } else {
    43                         sb.append(list);
     101                        // get complete ways and nodes of the relation and next level of sub relations
     102                        down = ".r;rel(r)->.rm;";
     103                        setsToInclude.append(".r;>;.rm;");
    44104                    }
    45                     break;
    46                 case CLOSEDWAY:
    47                 case WAY:
    48                     sb.append('(').append(list).append(">;);");
    49                     break;
    50                 case NODE:
    51                     sb.append(list);
    52105                }
    53106            }
    54107        }
     108        if (up.length() > 0) {
     109            sb.append(up);
     110        }
     111        if (down != null) {
     112            sb.append(down);
     113        }
     114        sb.append('(').append(setsToInclude).append(");");
     115
     116        sb.append("out meta;");
    55117        String query = sb.toString();
    56         if (countTypes > 1) {
    57             query = "(" + query + ");";
    58         }
    59         query += "out meta;";
    60118        Logging.debug("{0} {1}", "Generated Overpass query:", query);
    61119        return query;
  • trunk/src/org/openstreetmap/josm/io/MultiFetchServerObjectReader.java

    r16203 r16611  
    383383            if (this instanceof MultiFetchOverpassObjectReader) {
    384384                // calculate a single request for all the objects
    385                 String request = ((MultiFetchOverpassObjectReader) this).buildComplexRequestString();
     385                String request = MultiFetchOverpassObjectReader.genOverpassQuery(primitivesMap, true, false, recurseDownRelations);
    386386                if (isCanceled())
    387387                    return null;
    388388                OverpassDownloadReader reader = new OverpassDownloadReader(new Bounds(0, 0, 0, 0), getBaseUrl(), request);
    389                 DataSet ds = reader.parseOsm(progressMonitor.createSubTaskMonitor(n, false));
     389                DataSet ds = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
    390390                new DataSetMerger(outputDataSet, ds).merge();
    391391                checkMissing(outputDataSet, progressMonitor);
  • trunk/test/unit/org/openstreetmap/josm/io/MultiFetchOverpassObjectReaderTest.java

    r16009 r16611  
    55
    66import java.util.Arrays;
     7import java.util.List;
    78
    89import org.junit.Rule;
    910import org.junit.Test;
    1011import org.openstreetmap.josm.data.osm.Node;
     12import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1113import org.openstreetmap.josm.data.osm.Relation;
    1214import org.openstreetmap.josm.data.osm.Way;
     
    3133     */
    3234    @Test
     35    public void testBuildRequestNodesString() {
     36        List<OsmPrimitive> objects = Arrays.asList(new Node(123), new Node(126), new Node(130));
     37        String requestString;
     38        // nodes without parents
     39        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, false, false);
     40        assertEquals("node(id:123,126,130)->.n;(.n;);out meta;", requestString);
     41        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, false, true);
     42        assertEquals("node(id:123,126,130)->.n;(.n;);out meta;", requestString);
     43
     44        // nodes with parents
     45        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, true, false);
     46        assertEquals("node(id:123,126,130)->.n;.n;way(bn)->.wn;.n;rel(bn)->.rn;(.n;.wn;node(w);.rn;);out meta;",
     47                requestString);
     48        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, true, true);
     49        assertEquals("node(id:123,126,130)->.n;.n;way(bn)->.wn;.n;rel(bn)->.rn;(.n;.wn;node(w);.rn;);out meta;",
     50                requestString);
     51
     52        // simulate download referrers
     53        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, false, true, false);
     54        assertEquals("node(id:123,126,130)->.n;.n;way(bn)->.wn;.n;rel(bn)->.rn;(.wn;node(w);.rn;);out meta;",
     55                requestString);
     56
     57    }
     58
     59    /**
     60     * Test {@link MultiFetchOverpassObjectReader#buildRequestString}
     61     */
     62    @Test
    3363    public void testBuildRequestWaysString() {
    34         MultiFetchOverpassObjectReader reader = new MultiFetchOverpassObjectReader();
    35         reader.append(Arrays.asList(new Way(123), new Way(126), new Way(130)));
    36         String requestString = reader.buildComplexRequestString();
    37         assertEquals("(way(id:123,126,130);>;);out meta;", requestString);
     64        List<OsmPrimitive> objects = Arrays.asList(new Way(123), new Way(126), new Way(130));
     65        String requestString;
     66        // ways without parents (always with nodes)
     67        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, false, false);
     68        assertEquals("way(id:123,126,130)->.w;(.w;>;);out meta;", requestString);
     69        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, false, true);
     70        assertEquals("way(id:123,126,130)->.w;(.w;>;);out meta;", requestString);
     71
     72        // ways with parents (always with nodes)
     73        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, true, false);
     74        assertEquals("way(id:123,126,130)->.w;.w;rel(bw)->.pw;(.w;>;.pw;);out meta;", requestString);
     75        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, true, true);
     76        assertEquals("way(id:123,126,130)->.w;.w;rel(bw)->.pw;(.w;>;.pw;);out meta;", requestString);
     77
     78        // simulate download referrers
     79        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, false, true, false);
     80        assertEquals("way(id:123,126,130)->.w;.w;rel(bw)->.pw;(.pw;);out meta;", requestString);
     81
    3882    }
    3983
     
    4387    @Test
    4488    public void testBuildRequestRelationsString() {
    45         MultiFetchOverpassObjectReader reader = new MultiFetchOverpassObjectReader();
    46         reader.append(Arrays.asList(new Relation(123), new Relation(126), new Relation(130)));
    47         reader.setRecurseDownRelations(true);
    48         String requestString = reader.buildComplexRequestString();
    49         assertEquals("(relation(id:123,126,130)->.r;.r;rel(r);.r;way(r);>;.r;node(r););out meta;", requestString);
    50         reader.setRecurseDownRelations(false);
    51         requestString = reader.buildComplexRequestString();
    52         assertEquals("relation(id:123,126,130);out meta;", requestString);
     89        List<OsmPrimitive> objects = Arrays.asList(new Relation(123), new Relation(126), new Relation(130));
     90        String requestString;
     91        // objects without parents or children
     92        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, false, false);
     93        assertEquals("relation(id:123,126,130)->.r;(.r;);out meta;", requestString);
     94        // objects without parents, with children
     95        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, false, true);
     96        assertEquals("relation(id:123,126,130)->.r;.r;rel(r)->.rm;(.r;.r;>;.rm;);out meta;", requestString);
     97        // objects with parents, without children
     98        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, true, false);
     99        assertEquals("relation(id:123,126,130)->.r;.r;rel(br)->.pr;(.r;.pr;);out meta;", requestString);
     100        // objects with parents and with children
     101        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, true, true);
     102        assertEquals("relation(id:123,126,130)->.r;.r;rel(br)->.pr;.r;rel(r)->.rm;(.r;.pr;.r;>;.rm;);out meta;",
     103                requestString);
     104        // simulate download referrers
     105        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, false, true, false);
     106        assertEquals("relation(id:123,126,130)->.r;.r;rel(br)->.pr;(.pr;);out meta;", requestString);
     107
    53108    }
    54109
     
    58113    @Test
    59114    public void testBuildComplexString() {
    60         MultiFetchOverpassObjectReader reader = new MultiFetchOverpassObjectReader();
    61         reader.setRecurseDownRelations(true);
    62         reader.append(Arrays.asList(new Relation(123), new Relation(126), new Relation(130), new Way(88), new Way(99),
    63                 new Node(1)));
    64         String requestString = reader.buildComplexRequestString();
     115        List<OsmPrimitive> objects = Arrays.asList(new Relation(123), new Relation(126), new Relation(130), new Way(88), new Way(99),
     116                new Node(1));
     117        // all request strings should start with the same list of objects
     118        final String ids =  "relation(id:123,126,130)->.r;way(id:88,99)->.w;node(1)->.n;";
     119        String requestString;
     120
     121        // objects without parents (ways always with nodes)
     122        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, false, false);
     123        assertEquals(ids + "(.r;.w;>;.n;);out meta;", requestString);
     124        // objects without parents (ways always with nodes), recurse down one level for sub relations
     125        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, false, true);
     126        assertEquals(ids + ".r;rel(r)->.rm;(.r;.r;>;.rm;.w;>;.n;);out meta;", requestString);
     127
     128        // objects with parents
     129        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, true, false);
    65130        assertEquals(
    66                 "((relation(id:123,126,130)->.r;.r;rel(r);.r;way(r);>;.r;node(r););(way(id:88,99);>;);node(1););out meta;",
     131                ids + ".r;rel(br)->.pr;.w;rel(bw)->.pw;.n;way(bn)->.wn;.n;rel(bn)->.rn;(.r;.pr;.w;>;.pw;.n;.wn;node(w);.rn;);out meta;",
    67132                requestString);
    68         reader.setRecurseDownRelations(false);
    69         requestString = reader.buildComplexRequestString();
    70         assertEquals("(relation(id:123,126,130);(way(id:88,99);>;);node(1););out meta;", requestString);
     133
     134        // objects with parents, recurse down one level for sub relations
     135        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, true, true, true);
     136        assertEquals(ids + ".r;rel(br)->.pr;.w;rel(bw)->.pw;.n;way(bn)->.wn;.n;rel(bn)->.rn;.r;rel(r)->.rm;"
     137                + "(.r;.pr;.r;>;.rm;.w;>;.pw;.n;.wn;node(w);.rn;);out meta;", requestString);
     138        // simulate download referrers
     139        requestString = MultiFetchOverpassObjectReader.genOverpassQuery(objects, false, true, false);
     140        assertEquals(
     141                ids + ".r;rel(br)->.pr;.w;rel(bw)->.pw;.n;way(bn)->.wn;.n;rel(bn)->.rn;(.pr;.pw;.wn;node(w);.rn;);out meta;",
     142                requestString);
    71143    }
    72 
    73144}
Note: See TracChangeset for help on using the changeset viewer.