Changeset 5387 in josm


Ignore:
Timestamp:
2012-07-31T23:27:44+02:00 (12 years ago)
Author:
Don-vip
Message:

fix #7914 - Concurrent fetching of primitives

The default and maximum number of threads is set to 2, to comply with OSM API usage policy:
http://wiki.openstreetmap.org/wiki/API_usage_policy#Technical_Usage_Requirements

The property osm.download.threads`can be set to 1 do restore single-thread download (it may still be faster than before as we have a download thread and a thread that merges the primitives in the data set)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/io/MultiFetchServerObjectReader.java

    r5266 r5387  
    77import java.io.InputStream;
    88import java.net.HttpURLConnection;
     9import java.util.ArrayList;
    910import java.util.Collection;
    1011import java.util.HashSet;
    1112import java.util.Iterator;
    1213import java.util.LinkedHashSet;
     14import java.util.List;
    1315import java.util.NoSuchElementException;
    1416import java.util.Set;
    15 
     17import java.util.concurrent.Callable;
     18import java.util.concurrent.CompletionService;
     19import java.util.concurrent.ExecutionException;
     20import java.util.concurrent.Executor;
     21import java.util.concurrent.ExecutorCompletionService;
     22import java.util.concurrent.Executors;
     23import java.util.concurrent.Future;
     24
     25import org.openstreetmap.josm.Main;
    1626import org.openstreetmap.josm.data.osm.DataSet;
    1727import org.openstreetmap.josm.data.osm.DataSetMerger;
     
    4555 *    }
    4656 * </pre>
    47  *
    48  *
    4957 */
    5058public class MultiFetchServerObjectReader extends OsmServerReader{
     
    5462     * which should be safe according to the
    5563     * <a href="http://www.boutell.com/newfaq/misc/urllength.html">WWW FAQ</a>.
    56      *
    5764     */
    5865    static private int MAX_IDS_PER_REQUEST = 200;
     
    6572
    6673    /**
    67      * constructor
    68      *
     74     * Constructs a {@code MultiFetchServerObjectReader}.
    6975     */
    7076    public MultiFetchServerObjectReader() {
     
    101107     *
    102108     * @param ds  the dataset (must not be null)
    103      * @param id  the id
    104      * @exception IllegalArgumentException thrown, if ds is null
    105      * @exception NoSuchElementException thrown, if ds doesn't include an {@link OsmPrimitive} with
    106      *   id=<code>id</code>
     109     * @param id  the primitive id
     110     * @param type The primitive type. Must be one of {@link OsmPrimitiveType#NODE NODE}, {@link OsmPrimitiveType#WAY WAY}, {@link OsmPrimitiveType#RELATION RELATION}
     111     * @throws IllegalArgumentException if ds is null
     112     * @throws NoSuchElementException if ds does not include an {@link OsmPrimitive} with id=<code>id</code>
    107113     */
    108114    protected void remember(DataSet ds, long id, OsmPrimitiveType type) throws IllegalArgumentException, NoSuchElementException{
     
    116122    }
    117123
     124    /**
     125     * appends a {@link OsmPrimitive} id to the list of ids which will be fetched from the server.
     126     *
     127     * @param ds the {@link DataSet} to which the primitive belongs
     128     * @param id the primitive id
     129     * @param type The primitive type. Must be one of {@link OsmPrimitiveType#NODE NODE}, {@link OsmPrimitiveType#WAY WAY}, {@link OsmPrimitiveType#RELATION RELATION}
     130     * @return this
     131     */
    118132    public MultiFetchServerObjectReader append(DataSet ds, long id, OsmPrimitiveType type) {
     133        OsmPrimitive p = ds.getPrimitiveById(id,type);
    119134        switch(type) {
    120135        case NODE:
    121             Node n = (Node)ds.getPrimitiveById(id,type);
    122             appendNode(n);
    123             break;
     136            return appendNode((Node)p);
    124137        case WAY:
    125             Way w= (Way)ds.getPrimitiveById(id,type);
    126             appendWay(w);
    127             break;
     138            return appendWay((Way)p);
    128139        case RELATION:
    129             Relation r = (Relation)ds.getPrimitiveById(id,type);
    130             appendRelation(r);
    131             break;
     140            return appendRelation((Relation)p);
    132141        }
    133142        return this;
     
    135144
    136145    /**
    137      * appends a {@link Node}s id to the list of ids which will be fetched from the server.
     146     * appends a {@link Node} id to the list of ids which will be fetched from the server.
    138147     *
    139148     * @param node  the node (ignored, if null)
    140149     * @return this
    141      *
    142150     */
    143151    public MultiFetchServerObjectReader appendNode(Node node) {
     
    148156
    149157    /**
    150      * appends a {@link Way}s id and the list of ids of nodes the way refers to the list of ids which will be fetched from the server.
     158     * appends a {@link Way} id and the list of ids of nodes the way refers to the list of ids which will be fetched from the server.
    151159     *
    152160     * @param way the way (ignored, if null)
    153161     * @return this
    154      *
    155162     */
    156163    public MultiFetchServerObjectReader appendWay(Way way) {
     
    167174
    168175    /**
    169      * appends a {@link Relation}s id to the list of ids which will be fetched from the server.
     176     * appends a {@link Relation} id to the list of ids which will be fetched from the server.
    170177     *
    171178     * @param relation  the relation (ignored, if null)
    172179     * @return this
    173      *
    174180     */
    175181    protected MultiFetchServerObjectReader appendRelation(Relation relation) {
     
    192198    }
    193199
     200    /**
     201     * appends an {@link OsmPrimitive} to the list of ids which will be fetched from the server.
     202     * @param primitive the primitive
     203     * @return this
     204     */
    194205    public MultiFetchServerObjectReader append(OsmPrimitive primitive) {
    195         if (OsmPrimitiveType.from(primitive).equals(OsmPrimitiveType.NODE))
    196             return appendNode((Node)primitive);
    197         else if (OsmPrimitiveType.from(primitive).equals(OsmPrimitiveType.WAY))
    198             return appendWay((Way)primitive);
    199         else if (OsmPrimitiveType.from(primitive).equals(OsmPrimitiveType.RELATION))
    200             return appendRelation((Relation)primitive);
    201 
     206        if (primitive != null) {
     207            switch (OsmPrimitiveType.from(primitive)) {
     208                case NODE: return appendNode((Node)primitive);
     209                case WAY: return appendWay((Way)primitive);
     210                case RELATION: return appendRelation((Relation)primitive);
     211            }
     212        }
    202213        return this;
    203214    }
     
    209220     * @return this
    210221     *
    211      * @see #append(Node)
    212      * @see #append(Way)
    213      * @see #append(Relation)
    214      *
     222     * @see #append(OsmPrimitive)
    215223     */
    216224    public MultiFetchServerObjectReader append(Collection<? extends OsmPrimitive> primitives) {
     
    235243        if (ids.size() > MAX_IDS_PER_REQUEST) {
    236244            Iterator<Long> it = ids.iterator();
    237             for (int i =0;i<MAX_IDS_PER_REQUEST;i++) {
     245            for (int i=0; i<MAX_IDS_PER_REQUEST; i++) {
    238246                pkg.add(it.next());
    239247            }
     
    250258     * {@link OsmPrimitiveType}.
    251259     *
    252      * @param type the type
     260     * @param type The primitive type. Must be one of {@link OsmPrimitiveType#NODE NODE}, {@link OsmPrimitiveType#WAY WAY}, {@link OsmPrimitiveType#RELATION RELATION}
    253261     * @param idPackage  the package of ids
    254262     * @return the request string
    255263     */
    256     protected String buildRequestString(OsmPrimitiveType type, Set<Long> idPackage) {
     264    protected static String buildRequestString(OsmPrimitiveType type, Set<Long> idPackage) {
    257265        StringBuilder sb = new StringBuilder();
    258266        sb.append(type.getAPIName()).append("s?")
     
    260268
    261269        Iterator<Long> it = idPackage.iterator();
    262         for (int i=0; i< idPackage.size();i++) {
     270        for (int i=0; i<idPackage.size(); i++) {
    263271            sb.append(it.next());
    264272            if (i < idPackage.size()-1) {
     
    273281     * {@link OsmPrimitiveType}.
    274282     *
    275      * @param type the type
     283     * @param type The primitive type. Must be one of {@link OsmPrimitiveType#NODE NODE}, {@link OsmPrimitiveType#WAY WAY}, {@link OsmPrimitiveType#RELATION RELATION}
    276284     * @param id the id
    277285     * @return the request string
    278286     */
    279     protected String buildRequestString(OsmPrimitiveType type, long id) {
     287    protected static String buildRequestString(OsmPrimitiveType type, long id) {
    280288        StringBuilder sb = new StringBuilder();
    281289        sb.append(type.getAPIName()).append("s?")
     
    283291        .append(id);
    284292        return sb.toString();
    285     }
    286 
    287     /**
    288      * invokes a Multi Get for a set of ids and a given {@link OsmPrimitiveType}.
    289      * The retrieved primitives are merged to {@link #outputDataSet}.
    290      *
    291      * @param type the type
    292      * @param pkg the package of ids
    293      * @exception OsmTransferException thrown if an error occurs while communicating with the API server
    294      *
    295      */
    296     protected void multiGetIdPackage(OsmPrimitiveType type, Set<Long> pkg, ProgressMonitor progressMonitor) throws OsmTransferException {
    297         String request = buildRequestString(type, pkg);
    298         final InputStream in = getInputStream(request, NullProgressMonitor.INSTANCE);
    299         if (in == null) return;
    300         progressMonitor.subTask(tr("Downloading OSM data..."));
    301         try {
    302             DataSet loaded = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(pkg.size(), false));
    303             rememberNodesOfIncompleteWaysToLoad(loaded);
    304             merge(loaded);
    305         } catch(Exception e) {
    306             throw new OsmTransferException(e);
    307         }
    308     }
    309 
    310     /**
    311      * invokes a Multi Get for a single id and a given {@link OsmPrimitiveType}.
    312      * The retrieved primitive is merged to {@link #outputDataSet}.
    313      *
    314      * @param type the type
    315      * @param id the id
    316      * @exception OsmTransferException thrown if an error occurs while communicating with the API server
    317      *
    318      */
    319     protected void singleGetId(OsmPrimitiveType type, long id, ProgressMonitor progressMonitor) throws OsmTransferException {
    320         String request = buildRequestString(type, id);
    321         final InputStream in = getInputStream(request, NullProgressMonitor.INSTANCE);
    322         if (in == null)
    323             return;
    324         progressMonitor.subTask(tr("Downloading OSM data..."));
    325         try {
    326             DataSet loaded = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
    327             rememberNodesOfIncompleteWaysToLoad(loaded);
    328             merge(loaded);
    329         } catch(Exception e) {
    330             throw new OsmTransferException(e);
    331         }
    332     }
    333 
    334     /**
    335      * invokes a sequence of Multi Gets for individual ids in a set of ids and a given {@link OsmPrimitiveType}.
    336      * The retrieved primitives are merged to {@link #outputDataSet}.
    337      *
    338      * This method is used if one of the ids in pkg doesn't exist (the server replies with return code 404).
    339      * If the set is fetched with this method it is possible to find out which of the ids doesn't exist.
    340      * Unfortunatelly, the server does not provide an error header or an error body for a 404 reply.
    341      *
    342      * @param type the type
    343      * @param pkg the set of ids
    344      * @exception OsmTransferException thrown if an error occurs while communicating with the API server
    345      *
    346      */
    347     protected void singleGetIdPackage(OsmPrimitiveType type, Set<Long> pkg, ProgressMonitor progressMonitor) throws OsmTransferException {
    348         for (long id : pkg) {
    349             try {
    350                 String msg = "";
    351                 switch(type) {
    352                 case NODE: msg = tr("Fetching node with id {0} from ''{1}''", id, OsmApi.getOsmApi().getBaseUrl()); break;
    353                 case WAY: msg = tr("Fetching way with id {0} from ''{1}''", id, OsmApi.getOsmApi().getBaseUrl()); break;
    354                 case RELATION: msg = tr("Fetching relation with id {0} from ''{1}''", id, OsmApi.getOsmApi().getBaseUrl()); break;
    355                 }
    356                 progressMonitor.setCustomText(msg);
    357                 singleGetId(type, id, progressMonitor);
    358             } catch(OsmApiException e) {
    359                 if (e.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
    360                     System.out.println(tr("Server replied with response code 404 for id {0}. Skipping.", Long.toString(id)));
    361                     missingPrimitives.add(new SimplePrimitiveId(id, type));
    362                     continue;
    363                 }
    364                 throw e;
    365             }
    366         }
    367293    }
    368294
     
    383309     *
    384310     * @param from the other dataset
    385      *
    386311     */
    387312    protected void merge(DataSet from) {
     
    394319     *
    395320     * @param ids the set of ids
    396      * @param type the  type
    397      * @exception OsmTransferException thrown if an error occurs while communicating with the API server
    398      */
    399     protected void fetchPrimitives(Set<Long> ids, OsmPrimitiveType type, ProgressMonitor progressMonitor) throws OsmTransferException{
     321     * @param type The primitive type. Must be one of {@link OsmPrimitiveType#NODE NODE}, {@link OsmPrimitiveType#WAY WAY}, {@link OsmPrimitiveType#RELATION RELATION}
     322     * @throws OsmTransferException if an error occurs while communicating with the API server
     323     */
     324    protected void fetchPrimitives(Set<Long> ids, OsmPrimitiveType type, ProgressMonitor progressMonitor) throws OsmTransferException {
    400325        String msg = "";
    401         switch(type) {
    402         case NODE: msg = tr("Fetching a package of nodes from ''{0}''", OsmApi.getOsmApi().getBaseUrl()); break;
    403         case WAY:  msg = tr("Fetching a package of ways from ''{0}''", OsmApi.getOsmApi().getBaseUrl()); break;
    404         case RELATION:  msg = tr("Fetching a package of relations from ''{0}''", OsmApi.getOsmApi().getBaseUrl()); break;
     326        String baseUrl = OsmApi.getOsmApi().getBaseUrl();
     327        switch (type) {
     328            case NODE:     msg = tr("Fetching a package of nodes from ''{0}''",     baseUrl); break;
     329            case WAY:      msg = tr("Fetching a package of ways from ''{0}''",      baseUrl); break;
     330            case RELATION: msg = tr("Fetching a package of relations from ''{0}''", baseUrl); break;
    405331        }
    406332        progressMonitor.setTicksCount(ids.size());
    407333        progressMonitor.setTicks(0);
     334        // The complete set containg all primitives to fetch
    408335        Set<Long> toFetch = new HashSet<Long>(ids);
    409         while(! toFetch.isEmpty() && !isCanceled()) {
    410             Set<Long> pkg = extractIdPackage(toFetch);
     336        // Build a list of fetchers that will  download smaller sets containing only MAX_IDS_PER_REQUEST (200) primitives each.
     337        // we will run up to MAX_DOWNLOAD_THREADS concurrent fetchers.
     338        int threadsNumber = Main.pref.getInteger("osm.download.threads", OsmApi.MAX_DOWNLOAD_THREADS);
     339        threadsNumber = Math.min(Math.max(threadsNumber, 1), OsmApi.MAX_DOWNLOAD_THREADS);
     340        Executor exec = Executors.newFixedThreadPool(threadsNumber);
     341        CompletionService<FetchResult> ecs = new ExecutorCompletionService<FetchResult>(exec);
     342        List<Future<FetchResult>> jobs = new ArrayList<Future<FetchResult>>();
     343        while (!toFetch.isEmpty()) {
     344            jobs.add(ecs.submit(new Fetcher(type, extractIdPackage(toFetch), progressMonitor)));
     345        }
     346        // Run the fetchers
     347        for (int i = 0; i < jobs.size() && !isCanceled(); i++) {
    411348            progressMonitor.subTask(msg + "... " + progressMonitor.getTicks() + "/" + progressMonitor.getTicksCount());
    412349            try {
    413                 multiGetIdPackage(type, pkg, progressMonitor);
    414             } catch(OsmApiException e) {
    415                 if (e.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
    416                     System.out.println(tr("Server replied with response code 404, retrying with an individual request for each object."));
    417                     singleGetIdPackage(type, pkg, progressMonitor);
    418                 } else
    419                     throw e;
     350                FetchResult result = ecs.take().get();
     351                if (result.missingPrimitives != null) {
     352                    missingPrimitives.addAll(result.missingPrimitives);
     353                }
     354                if (result.dataSet != null && !isCanceled()) {
     355                    rememberNodesOfIncompleteWaysToLoad(result.dataSet);
     356                    merge(result.dataSet);
     357                }
     358            } catch (InterruptedException e) {
     359                e.printStackTrace();
     360            } catch (ExecutionException e) {
     361                e.printStackTrace();
     362            }
     363        }
     364        // Cancel requests if the user choosed to
     365        if (isCanceled()) {
     366            for (Future<FetchResult> job : jobs) {
     367                job.cancel(true);
    420368            }
    421369        }
     
    433381     *
    434382     * @return the parsed data
    435      * @exception OsmTransferException thrown if an error occurs while communicating with the API server
     383     * @throws OsmTransferException if an error occurs while communicating with the API server
    436384     * @see #getMissingPrimitives()
    437385     *
     
    443391        try {
    444392            missingPrimitives = new HashSet<PrimitiveId>();
    445             if (isCanceled())return null;
     393            if (isCanceled()) return null;
    446394            fetchPrimitives(ways,OsmPrimitiveType.WAY, progressMonitor);
    447             if (isCanceled())return null;
     395            if (isCanceled()) return null;
    448396            fetchPrimitives(nodes,OsmPrimitiveType.NODE, progressMonitor);
    449             if (isCanceled())return null;
     397            if (isCanceled()) return null;
    450398            fetchPrimitives(relations,OsmPrimitiveType.RELATION, progressMonitor);
    451399            if (outputDataSet != null) {
     
    468416        return missingPrimitives;
    469417    }
     418   
     419    /**
     420     * The class holding the results given by {@link Fetcher}.
     421     * It is only a wrapper of the resulting {@link DataSet} and the collection of {@link PrimitiveId} that could not have been loaded.
     422     */
     423    protected static class FetchResult {
     424       
     425        /**
     426         * The resulting data set
     427         */
     428        public final DataSet dataSet;
     429       
     430        /**
     431         * The collection of primitive ids that could not have been loaded
     432         */
     433        public final Set<PrimitiveId> missingPrimitives;
     434       
     435        /**
     436         * Constructs a {@code FetchResult}
     437         * @param dataSet The resulting data set
     438         * @param missingPrimitives The collection of primitive ids that could not have been loaded
     439         */
     440        public FetchResult(DataSet dataSet, Set<PrimitiveId> missingPrimitives) {
     441            this.dataSet = dataSet;
     442            this.missingPrimitives = missingPrimitives;
     443        }
     444    }
     445   
     446    /**
     447     * The class that actually download data from OSM API. Several instances of this class are used by {@link MultiFetchServerObjectReader} (one per set of primitives to fetch).
     448     * The inheritance of {@link OsmServerReader} is only explained by the need to have a distinct OSM connection by {@code Fetcher} instance.
     449     * @see FetchResult
     450     */
     451    protected static class Fetcher extends OsmServerReader implements Callable<FetchResult> {
     452
     453        private final Set<Long> pkg;
     454        private final OsmPrimitiveType type;
     455        private final ProgressMonitor progressMonitor;
     456
     457        /**
     458         * Constructs a {@code Fetcher}
     459         * @param type The primitive type. Must be one of {@link OsmPrimitiveType#NODE NODE}, {@link OsmPrimitiveType#WAY WAY}, {@link OsmPrimitiveType#RELATION RELATION}
     460         * @param idsPackage The set of primitives ids to fetch
     461         * @param progressMonitor The progress monitor
     462         */
     463        public Fetcher(OsmPrimitiveType type, Set<Long> idsPackage, ProgressMonitor progressMonitor) {
     464            this.pkg = idsPackage;
     465            this.type = type;
     466            this.progressMonitor = progressMonitor;
     467        }
     468
     469        @Override
     470        public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
     471            // This method is implemented because of the OsmServerReader inheritance, but not used, as the main target of this class is the call() method.
     472            return fetch(progressMonitor).dataSet;
     473        }
     474       
     475        @Override
     476        public FetchResult call() throws Exception {
     477            return fetch(progressMonitor);
     478        }
     479       
     480        /**
     481         * fetches the requested primitives and updates the specified progress monitor.
     482         * @param progressMonitor the progress monitor
     483         * @return the {@link FetchResult} of this operation
     484         * @throws OsmTransferException if an error occurs while communicating with the API server
     485         */
     486        protected FetchResult fetch(ProgressMonitor progressMonitor) throws OsmTransferException {
     487            try {
     488                return multiGetIdPackage(type, pkg, progressMonitor);
     489            } catch (OsmApiException e) {
     490                if (e.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
     491                    System.out.println(tr("Server replied with response code 404, retrying with an individual request for each object."));
     492                    return singleGetIdPackage(type, pkg, progressMonitor);
     493                } else {
     494                    throw e;
     495                }
     496            }
     497        }
     498       
     499        /**
     500         * invokes a Multi Get for a set of ids and a given {@link OsmPrimitiveType}.
     501         * The retrieved primitives are merged to {@link #outputDataSet}.
     502         *
     503         * @param type The primitive type. Must be one of {@link OsmPrimitiveType#NODE NODE}, {@link OsmPrimitiveType#WAY WAY}, {@link OsmPrimitiveType#RELATION RELATION}
     504         * @param pkg the package of ids
     505         * @return the {@link FetchResult} of this operation
     506         * @throws OsmTransferException if an error occurs while communicating with the API server
     507         */
     508        protected FetchResult multiGetIdPackage(OsmPrimitiveType type, Set<Long> pkg, ProgressMonitor progressMonitor) throws OsmTransferException {
     509            String request = buildRequestString(type, pkg);
     510            final InputStream in = getInputStream(request, NullProgressMonitor.INSTANCE);
     511            if (in == null) return null;
     512            progressMonitor.subTask(tr("Downloading OSM data..."));
     513            try {
     514                return new FetchResult(OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(pkg.size(), false)), null);
     515            } catch (Exception e) {
     516                throw new OsmTransferException(e);
     517            }
     518        }
     519
     520        /**
     521         * invokes a Multi Get for a single id and a given {@link OsmPrimitiveType}.
     522         * The retrieved primitive is merged to {@link #outputDataSet}.
     523         *
     524         * @param type The primitive type. Must be one of {@link OsmPrimitiveType#NODE NODE}, {@link OsmPrimitiveType#WAY WAY}, {@link OsmPrimitiveType#RELATION RELATION}
     525         * @param id the id
     526         * @return the {@link DataSet} resulting of this operation
     527         * @throws OsmTransferException if an error occurs while communicating with the API server
     528         */
     529        protected DataSet singleGetId(OsmPrimitiveType type, long id, ProgressMonitor progressMonitor) throws OsmTransferException {
     530            String request = buildRequestString(type, id);
     531            final InputStream in = getInputStream(request, NullProgressMonitor.INSTANCE);
     532            if (in == null) return null;
     533            progressMonitor.subTask(tr("Downloading OSM data..."));
     534            try {
     535                return OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
     536            } catch (Exception e) {
     537                throw new OsmTransferException(e);
     538            }
     539        }
     540
     541        /**
     542         * invokes a sequence of Multi Gets for individual ids in a set of ids and a given {@link OsmPrimitiveType}.
     543         * The retrieved primitives are merged to {@link #outputDataSet}.
     544         *
     545         * This method is used if one of the ids in pkg doesn't exist (the server replies with return code 404).
     546         * If the set is fetched with this method it is possible to find out which of the ids doesn't exist.
     547         * Unfortunately, the server does not provide an error header or an error body for a 404 reply.
     548         *
     549         * @param type The primitive type. Must be one of {@link OsmPrimitiveType#NODE NODE}, {@link OsmPrimitiveType#WAY WAY}, {@link OsmPrimitiveType#RELATION RELATION}
     550         * @param pkg the set of ids
     551         * @return the {@link FetchResult} of this operation
     552         * @throws OsmTransferException if an error occurs while communicating with the API server
     553         */
     554        protected FetchResult singleGetIdPackage(OsmPrimitiveType type, Set<Long> pkg, ProgressMonitor progressMonitor) throws OsmTransferException {
     555            FetchResult result = new FetchResult(new DataSet(), new HashSet<PrimitiveId>());
     556            String baseUrl = OsmApi.getOsmApi().getBaseUrl();
     557            for (long id : pkg) {
     558                try {
     559                    String msg = "";
     560                    switch (type) {
     561                        case NODE:     msg = tr("Fetching node with id {0} from ''{1}''",     id, baseUrl); break;
     562                        case WAY:      msg = tr("Fetching way with id {0} from ''{1}''",      id, baseUrl); break;
     563                        case RELATION: msg = tr("Fetching relation with id {0} from ''{1}''", id, baseUrl); break;
     564                    }
     565                    progressMonitor.setCustomText(msg);
     566                    result.dataSet.mergeFrom(singleGetId(type, id, progressMonitor));
     567                } catch (OsmApiException e) {
     568                    if (e.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
     569                        System.out.println(tr("Server replied with response code 404 for id {0}. Skipping.", Long.toString(id)));
     570                        result.missingPrimitives.add(new SimplePrimitiveId(id, type));
     571                    } else {
     572                        throw e;
     573                    }
     574                }
     575            }
     576            return result;
     577        }
     578    }
    470579}
Note: See TracChangeset for help on using the changeset viewer.