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 new Callable<List<Attribution>>() {
064
065            @Override
066            public List<Attribution> call() throws Exception {
067                BingAttributionData attributionLoader = new BingAttributionData();
068                int waitTimeSec = 1;
069                while (true) {
070                    try {
071                        String xml = attributionLoader.updateIfRequiredString();
072                        List<Attribution> ret = parseAttributionText(new InputSource(new StringReader(xml)));
073                        if (attributionDownloadedTask != null) {
074                            GuiHelper.runInEDT(attributionDownloadedTask);
075                            attributionDownloadedTask = null;
076                        }
077                        return ret;
078                    } catch (IOException ex) {
079                        Main.warn(ex, "Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds.");
080                        Thread.sleep(waitTimeSec * 1000L);
081                        waitTimeSec *= 2;
082                    }
083                }
084            }
085        };
086    }
087}