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