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