Ticket #11216: zoom_NPE_fixes.patch

File zoom_NPE_fixes.patch, 8.7 KB (added by wiktorn, 4 years ago)

Patch for NPE when BingAttribution is not loaded, and for not showing tiles at overzoom

  • src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java

    diff --git src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java
    index 6db0ec3..d636de4 100644
    import java.io.IOException; 
    77import java.io.InputStream;
    88import java.net.HttpURLConnection;
    99import java.net.MalformedURLException;
     10import java.net.URL;
    1011import java.net.URLConnection;
    1112import java.util.HashSet;
    1213import java.util.Map;
    public abstract class JCSCachedTileLoaderJob<K, V extends CacheEntry> implements 
    125126    @Override
    126127    public void submit(ICachedLoaderListener listener) {
    127128        boolean first = false;
    128         String url = getUrl().toString();
    129         if (url == null) {
     129        URL url = getUrl();
     130        String deduplicationKey = null;
     131        if (url != null) {
     132            // url might be null, for example when Bing Attribution is not loaded yet
     133            deduplicationKey = url.toString();
     134        }
     135        if (deduplicationKey == null) {
    130136            log.log(Level.WARNING, "No url returned for: {0}, skipping", getCacheKey());
    131137            return;
    132138        }
    133139        synchronized (inProgress) {
    134             Set<ICachedLoaderListener> newListeners = inProgress.get(url);
     140            Set<ICachedLoaderListener> newListeners = inProgress.get(deduplicationKey);
    135141            if (newListeners == null) {
    136142                newListeners = new HashSet<>();
    137                 inProgress.put(url, newListeners);
     143                inProgress.put(deduplicationKey, newListeners);
    138144                first = true;
    139145            }
    140146            newListeners.add(listener);
    public abstract class JCSCachedTileLoaderJob<K, V extends CacheEntry> implements 
    161167    }
    162168
    163169    /**
    164      * 
     170     *
    165171     * @return checks if object from cache has sufficient data to be returned
    166172     */
    167173    protected boolean isObjectLoadable() {
    public abstract class JCSCachedTileLoaderJob<K, V extends CacheEntry> implements 
    170176    }
    171177
    172178    /**
    173      * 
     179     *
    174180     * @return cache object as empty, regardless of what remote resource has returned (ex. based on headers)
    175181     */
    176182    protected boolean cacheAsEmpty() {
    public abstract class JCSCachedTileLoaderJob<K, V extends CacheEntry> implements 
    263269        return true;
    264270    }
    265271
     272    /**
     273     * @return true if object was successfully downloaded, false, if there was a loading failure
     274     */
     275
    266276    private boolean loadObject() {
    267277        try {
    268278            // if we have object in cache, and host doesn't support If-Modified-Since nor If-None-Match
    public abstract class JCSCachedTileLoaderJob<K, V extends CacheEntry> implements 
    315325                    log.log(Level.FINE, "JCS - downloaded key: {0}, length: {1}, url: {2}",
    316326                            new Object[] {getCacheKey(), raw.length, getUrl()});
    317327                    return true;
    318                 } else {
     328                } else  {
    319329                    cacheData = createCacheEntry(new byte[]{});
    320330                    cache.put(getCacheKey(), cacheData, attributes);
    321331                    log.log(Level.FINE, "JCS - Caching empty object {0}", getUrl());
    public abstract class JCSCachedTileLoaderJob<K, V extends CacheEntry> implements 
    325335        } catch (FileNotFoundException e) {
    326336            log.log(Level.FINE, "JCS - Caching empty object as server returned 404 for: {0}", getUrl());
    327337            cache.put(getCacheKey(), createCacheEntry(new byte[]{}), attributes);
    328             handleNotFound();
    329             return true;
     338            return handleNotFound();
    330339        } catch (Exception e) {
    331340            log.log(Level.WARNING, "JCS - Exception during download " + getUrl(), e);
    332341        }
    public abstract class JCSCachedTileLoaderJob<K, V extends CacheEntry> implements 
    335344
    336345    }
    337346
    338     protected abstract void handleNotFound();
     347    /**
     348     *  @return if we should treat this object as properly loaded
     349     */
     350    protected abstract boolean handleNotFound();
    339351
    340352    protected abstract V createCacheEntry(byte[] content);
    341353
  • src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java

    diff --git src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java
    index 7d40dac..d2709aa 100644
    import org.openstreetmap.josm.data.preferences.IntegerProperty; 
    1818
    1919/**
    2020 * @author Wiktor Niesiobędzki
    21  * 
     21 *
    2222 * Wrapper class that bridges between JCS cache and Tile Loaders
    2323 *
    2424 */
    public class TMSCachedTileLoader implements TileLoader, CachedTileLoader, TileCa 
    7272
    7373    @Override
    7474    public void addTile(Tile tile) {
    75         createTileLoaderJob(tile).submit();
     75        createTileLoaderJob(tile).getTile();
    7676    }
    7777
    7878    @Override
  • src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java

    diff --git src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java
    index 0159714..cb7754f 100644
    public class TMSCachedTileLoaderJob extends JCSCachedTileLoaderJob<String, Buffe 
    124124        if (cacheData != null) {
    125125            byte[] content = cacheData.getContent();
    126126            try {
    127                 return (content != null && content.length > 0) || cacheData.getImage() != null || cacheAsEmpty();
     127                return content != null || cacheData.getImage() != null || cacheAsEmpty();
    128128            } catch (IOException e) {
    129129                log.log(Level.WARNING, "JCS TMS - error loading from cache for tile {0}: {1}", new Object[] {tile.getKey(), e.getMessage()});
    130130            }
    public class TMSCachedTileLoaderJob extends JCSCachedTileLoaderJob<String, Buffe 
    142142            tile.putValue("tile-info", "no-tile");
    143143            return true;
    144144        }
    145         return false;
     145        return false; // as there is no other cache to cache the Tile, also cache other empty requests
    146146    }
    147147
    148148    @Override
    public class TMSCachedTileLoaderJob extends JCSCachedTileLoaderJob<String, Buffe 
    158158    @Override
    159159    public void loadingFinished(CacheEntry object, boolean success) {
    160160        try {
    161             loadTile(object);
     161            loadTile(object, success);
    162162            if (listener != null) {
    163163                listener.tileLoadingFinished(tile, success);
    164164            }
    public class TMSCachedTileLoaderJob extends JCSCachedTileLoaderJob<String, Buffe 
    177177     * @return tile or null, if nothing (useful) was found in cache
    178178     */
    179179    public Tile getCachedTile() {
    180         BufferedImageCacheEntry data = super.get();
     180        BufferedImageCacheEntry data = get();
    181181        if (isObjectLoadable()) {
    182182            try {
    183183                loadTile(data);
    public class TMSCachedTileLoaderJob extends JCSCachedTileLoaderJob<String, Buffe 
    192192        }
    193193    }
    194194
    195     private void loadTile(CacheEntry object) throws IOException {
     195    // loads tile when calling back from cache
     196    private void loadTile(CacheEntry object, boolean success) throws IOException {
    196197        tile.finishLoading();
    197198        if (object != null) {
    198199            byte[] content = object.getContent();
    public class TMSCachedTileLoaderJob extends JCSCachedTileLoaderJob<String, Buffe 
    200201                tile.loadImage(new ByteArrayInputStream(content));
    201202            }
    202203        }
     204        if (!success) {
     205            tile.setError("Problem loading tile");
     206        }
    203207    }
    204208
     209    // loads tile when geting stright from cache
    205210    private void loadTile(BufferedImageCacheEntry object) throws IOException {
    206211        tile.finishLoading();
    207         if (object != null) {
     212        if (cacheAsEmpty() || object != null) { // if cache as empty object, do not try to load image
    208213            if (object.getImage() != null) {
    209214                tile.setImage(object.getImage());
    210215            }
    public class TMSCachedTileLoaderJob extends JCSCachedTileLoaderJob<String, Buffe 
    212217    }
    213218
    214219    @Override
    215     protected void handleNotFound() {
     220    protected boolean handleNotFound() {
    216221        tile.setError("No tile at this zoom level");
    217222        tile.putValue("tile-info", "no-tile");
     223        return true;
    218224    }
    219225
     226    /**
     227     * For TMS use BaseURL as settings discovery, so for different paths, we will have different settings (useful for developer servers)
     228     *
     229     * @return base URL of TMS or server url as defined in super class
     230     */
    220231    @Override
    221232    protected String getServerKey() {
    222233        TileSource ts = tile.getSource();