001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.imagery;
003
004import java.io.IOException;
005import java.io.StringReader;
006import java.net.URL;
007import java.util.List;
008import java.util.concurrent.Callable;
009import java.util.concurrent.TimeUnit;
010
011import org.openstreetmap.gui.jmapviewer.tilesources.BingAerialTileSource;
012import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;
013import org.openstreetmap.josm.Main;
014import org.openstreetmap.josm.gui.util.GuiHelper;
015import org.openstreetmap.josm.io.CacheCustomContent;
016import org.openstreetmap.josm.tools.HttpClient;
017import org.xml.sax.InputSource;
018
019/**
020 * Bing TileSource with cached attribution
021 *
022 * @author Wiktor Niesiobędzki
023 * @since 8526
024 */
025public class CachedAttributionBingAerialTileSource extends BingAerialTileSource {
026    private Runnable attributionDownloadedTask;
027
028    /**
029     * Creates tile source
030     * @param info ImageryInfo description of this tile source
031     */
032    public CachedAttributionBingAerialTileSource(ImageryInfo info) {
033        super(info);
034    }
035
036    /**
037     * Creates tile source
038     * @param info ImageryInfo description of this tile source
039     * @param attributionDownloadedTask runnable to be executed once attribution is loaded
040     */
041
042    public CachedAttributionBingAerialTileSource(TileSourceInfo info, Runnable attributionDownloadedTask) {
043        super(info);
044        this.attributionDownloadedTask = attributionDownloadedTask;
045    }
046
047    class BingAttributionData extends CacheCustomContent<IOException> {
048
049        BingAttributionData() {
050            super("bing.attribution.xml", CacheCustomContent.INTERVAL_HOURLY);
051        }
052
053        @Override
054        protected byte[] updateData() throws IOException {
055            URL u = getAttributionUrl();
056            final String r = HttpClient.create(u).connect().fetchContent();
057            Main.info("Successfully loaded Bing attribution data.");
058            return r.getBytes("UTF-8");
059        }
060    }
061
062    @Override
063    protected Callable<List<Attribution>> getAttributionLoaderCallable() {
064        return () -> {
065            BingAttributionData attributionLoader = new BingAttributionData();
066            int waitTimeSec = 1;
067            while (true) {
068                try {
069                    String xml = attributionLoader.updateIfRequiredString();
070                    List<Attribution> ret = parseAttributionText(new InputSource(new StringReader(xml)));
071                    if (attributionDownloadedTask != null) {
072                        GuiHelper.runInEDT(attributionDownloadedTask);
073                        attributionDownloadedTask = null;
074                    }
075                    return ret;
076                } catch (IOException ex) {
077                    Main.warn(ex, "Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds.");
078                    Thread.sleep(TimeUnit.SECONDS.toMillis(waitTimeSec));
079                    waitTimeSec *= 2;
080                }
081            }
082        };
083    }
084}