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