Ticket #14796: bing-attribution-2.patch

File bing-attribution-2.patch, 5.3 KB (added by chris.tipper@…, 9 years ago)

bing-attribution-2.patch loads attribution asynchronously (tested briefly, initial load is erratic but continues successfully)

  • src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java

    diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
    index 47447f9..9a7b29a 100644
    a b  
    99import java.util.ArrayList;
    1010import java.util.List;
    1111import java.util.Locale;
    12 import java.util.concurrent.Callable;
    13 import java.util.concurrent.ExecutionException;
    14 import java.util.concurrent.Future;
    15 import java.util.concurrent.FutureTask;
    16 import java.util.concurrent.TimeUnit;
     12import java.util.concurrent.ExecutorService;
     13import java.util.concurrent.CompletableFuture;
     14import java.util.concurrent.Executors;
     15import java.util.function.Supplier;
    1716import java.util.regex.Pattern;
    1817
    1918import javax.imageio.ImageIO;
     
    4342public class BingAerialTileSource extends TMSTileSource {
    4443
    4544    private static final String API_KEY = "Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU";
    46     private static volatile Future<List<Attribution>> attributions; // volatile is required for getAttribution(), see below.
     45    private static volatile List<Attribution> attributions; // volatile is required for getAttribution(), see below.
    4746    private static String imageUrlTemplate;
    4847    private static Integer imageryZoomMax;
    4948    private static String[] subdomains;
     
    5251    private static final Pattern quadkeyPattern = Pattern.compile("\\{quadkey\\}");
    5352    private static final Pattern culturePattern = Pattern.compile("\\{culture\\}");
    5453    private String brandLogoUri;
     54    private ExecutorService executor;
    5555
    5656    /**
    5757     * Constructs a new {@code BingAerialTileSource}.
    5858     */
    5959    public BingAerialTileSource() {
    6060        super(new TileSourceInfo("Bing Aerial Maps", null, null));
     61        attributions = new ArrayList<>();
     62        executor = Executors.newCachedThreadPool();
    6163    }
    6264
    6365    /**
    public BingAerialTileSource() {  
    6668     */
    6769    public BingAerialTileSource(TileSourceInfo info) {
    6870        super(info);
     71        attributions = new ArrayList<>();
     72        executor = Executors.newCachedThreadPool();
    6973    }
    7074
    7175    protected static class Attribution {
    public BingAerialTileSource(TileSourceInfo info) {  
    7983    @Override
    8084    public String getTileUrl(int zoom, int tilex, int tiley) throws IOException {
    8185        // make sure that attribution is loaded. otherwise subdomains is null.
    82         if (getAttribution() == null)
     86        if (attributions.isEmpty())
    8387            throw new IOException("Attribution is not loaded yet");
    8488
    8589        int t = (zoom + tilex + tiley) % subdomains.length;
    public String getTermsOfUseURL() {  
    234238        return "http://opengeodata.org/microsoft-imagery-details";
    235239    }
    236240
    237     protected Callable<List<Attribution>> getAttributionLoaderCallable() {
    238         return new Callable<List<Attribution>>() {
     241    protected List<Attribution> getAttribution() {
     242        final Supplier<List<Attribution>> loader = new Supplier<List<Attribution>>() {
    239243
    240244            @Override
    241             public List<Attribution> call() throws Exception {
    242                 int waitTimeSec = 1;
    243                 while (true) {
    244                     try {
    245                         InputSource xml = new InputSource(getAttributionUrl().openStream());
    246                         List<Attribution> r = parseAttributionText(xml);
    247                         return r;
    248                     } catch (IOException ex) {
    249                         System.err.println("Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds.");
    250                         Thread.sleep(TimeUnit.SECONDS.toMillis(waitTimeSec));
    251                         waitTimeSec *= 2;
    252                     }
     245            public List<Attribution> get() {
     246                try {
     247                    InputSource xml = new InputSource(getAttributionUrl().openStream());
     248                    List<Attribution> r = parseAttributionText(xml);
     249                    return r;
     250                } catch (IOException ex) {
     251                    System.err.println("Could not connect to Bing API.");
    253252                }
     253                return null;
    254254            }
    255255        };
    256     }
    257 
    258     protected List<Attribution> getAttribution() {
    259         if (attributions == null) {
    260             // see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
    261             synchronized (BingAerialTileSource.class) {
    262                 if (attributions == null) {
    263                   final FutureTask<List<Attribution>> loader = new FutureTask<>(getAttributionLoaderCallable());
    264                   new Thread(loader, "bing-attribution-loader").start();
    265                   attributions = loader;
    266                 }
    267             }
    268         }
    269         try {
    270             return attributions.get();
    271         } catch (ExecutionException ex) {
    272             throw new RuntimeException(ex.getCause());
    273         } catch (InterruptedException ign) {
    274             System.err.println("InterruptedException: " + ign.getMessage());
    275         }
    276         return null;
     256        CompletableFuture.supplyAsync(loader, executor).thenAccept(attr -> {
     257            attributions.clear();
     258            attributions.addAll(attr);
     259        });
     260        return attributions;
    277261    }
    278262
    279263    @Override