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