Ticket #14796: bing-attribution-3.patch

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

Some minor changes, performance is good if you don't call getAttribution() inside getTileUrl(), however the problem with initial load discourages me from recommending this fix.

  • 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..dabc204 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 final ExecutorService executor;
    5555
    5656    /**
    5757     * Constructs a new {@code BingAerialTileSource}.
    5858     */
    5959    public BingAerialTileSource() {
    60         super(new TileSourceInfo("Bing Aerial Maps", null, null));
     60        this(new TileSourceInfo("Bing Aerial Maps", null, null));
    6161    }
    6262
    6363    /**
    public BingAerialTileSource() {  
    6666     */
    6767    public BingAerialTileSource(TileSourceInfo info) {
    6868        super(info);
     69        attributions = new ArrayList<>();
     70        executor = Executors.newCachedThreadPool();
    6971    }
    7072
    7173    protected static class Attribution {
    public BingAerialTileSource(TileSourceInfo info) {  
    7981    @Override
    8082    public String getTileUrl(int zoom, int tilex, int tiley) throws IOException {
    8183        // make sure that attribution is loaded. otherwise subdomains is null.
    82         if (getAttribution() == null)
     84        if (attributions.isEmpty())
    8385            throw new IOException("Attribution is not loaded yet");
    8486
    8587        int t = (zoom + tilex + tiley) % subdomains.length;
    public String getTermsOfUseURL() {  
    234236        return "http://opengeodata.org/microsoft-imagery-details";
    235237    }
    236238
    237     protected Callable<List<Attribution>> getAttributionLoaderCallable() {
    238         return new Callable<List<Attribution>>() {
     239    protected List<Attribution> getAttribution() {
     240        final Supplier<List<Attribution>> loader = new Supplier<List<Attribution>>() {
    239241
    240242            @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                     }
     243            public List<Attribution> get() {
     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.");
    253250                }
     251                return null;
    254252            }
    255253        };
    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;
     254        CompletableFuture.supplyAsync(loader, executor).thenAccept(attr -> {
     255            attributions.clear();
     256            attributions.addAll(attr);
     257        });
     258        return attributions;
    277259    }
    278260
    279261    @Override