Changeset 8433 in josm


Ignore:
Timestamp:
2015-05-28T22:00:41+02:00 (9 years ago)
Author:
wiktorn
Message:

Clean up handling of various error situations. Closes #11494

Location:
trunk/src/org/openstreetmap/josm/data
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java

    r8425 r8433  
    8585    public static ThreadFactory getNamedThreadFactory(final String name) {
    8686        return new ThreadFactory(){
     87            @Override
    8788            public Thread newThread(Runnable r) {
    8889                Thread t = Executors.defaultThreadFactory().newThread(r);
     
    185186        if (first || force) {
    186187            ensureCacheElement();
    187             if (!force && cacheElement != null && isCacheElementValid() && (isObjectLoadable())) {
     188            if (!force && cacheElement != null && isCacheElementValid() && isObjectLoadable()) {
    188189                // we got something in cache, and it's valid, so lets return it
    189190                log.log(Level.FINE, "JCS - Returning object from cache: {0}", getCacheKey());
     
    215216
    216217    /**
     218     * Simple implementation. All errors should be cached as empty. Though some JDK (JDK8 on Windows for example)
     219     * doesn't return 4xx error codes, instead they do throw an FileNotFoundException or IOException
    217220     *
    218      * @return cache object as empty, regardless of what remote resource has returned (ex. based on headers)
    219      */
    220     protected boolean cacheAsEmpty(Map<String, List<String>> headers, int statusCode, byte[] content) {
    221         return false;
     221     * @return true if we should put empty object into cache, regardless of what remote resource has returned
     222     */
     223    protected boolean cacheAsEmpty() {
     224        return attributes.getResponseCode() < 500;
    222225    }
    223226
     
    262265    }
    263266
    264 
    265267    private void finishLoading(LoadResult result) {
    266268        Set<ICachedLoaderListener> listeners = null;
     
    272274            return;
    273275        }
    274         try {
    275             for (ICachedLoaderListener l: listeners) {
    276                 l.loadingFinished(cacheData, attributes, result);
    277             }
    278         } catch (Exception e) {
    279             log.log(Level.WARNING, "JCS - Error while loading object from cache: {0}; {1}", new Object[]{e.getMessage(), getUrl()});
    280             Main.warn(e);
    281             for (ICachedLoaderListener l: listeners) {
    282                 l.loadingFinished(cacheData, attributes, LoadResult.FAILURE);
    283             }
    284 
    285         }
    286 
     276        for (ICachedLoaderListener l: listeners) {
     277            l.loadingFinished(cacheData, attributes, result);
     278        }
    287279    }
    288280
     
    362354                byte[] raw = read(urlConn);
    363355
    364                 if (!cacheAsEmpty(urlConn.getHeaderFields(), urlConn.getResponseCode(), raw) &&
    365                         raw != null && raw.length > 0) {
     356                if (isResponseLoadable(urlConn.getHeaderFields(), urlConn.getResponseCode(), raw)) {
    366357                    // we need to check cacheEmpty, so for cases, when data is returned, but we want to store
    367358                    // as empty (eg. empty tile images) to save some space
     
    371362                            new Object[] {getCacheKey(), raw.length, getUrl()});
    372363                    return true;
    373                 } else {
     364                } else if (cacheAsEmpty()) {
    374365                    cacheData = createCacheEntry(new byte[]{});
    375366                    cache.put(getCacheKey(), cacheData, attributes);
    376367                    log.log(Level.FINE, "JCS - Caching empty object {0}", getUrl());
    377368                    return true;
     369                } else {
     370                    log.log(Level.FINE, "JCS - failure during load - reponse is not loadable nor cached as empty");
     371                    return false;
    378372                }
    379373            }
    380374        } catch (FileNotFoundException e) {
    381375            log.log(Level.FINE, "JCS - Caching empty object as server returned 404 for: {0}", getUrl());
    382             cache.put(getCacheKey(), createCacheEntry(new byte[]{}), attributes);
    383             return handleNotFound();
     376            attributes.setResponseCode(404);
     377            boolean doCache = isResponseLoadable(null, 404, null) || cacheAsEmpty();
     378            if (doCache) {
     379                cacheData = createCacheEntry(new byte[]{});
     380                cache.put(getCacheKey(), cacheData, attributes);
     381            }
     382            return doCache;
     383        } catch (IOException e) {
     384            log.log(Level.FINE, "JCS - IOExecption during communication with server for: {0}", getUrl());
     385            attributes.setResponseCode(499); // set dummy error code
     386            boolean doCache = isResponseLoadable(null, 499, null) || cacheAsEmpty(); //generic 499 error code returned
     387            if (doCache) {
     388                cacheData = createCacheEntry(new byte[]{});
     389                cache.put(getCacheKey(), createCacheEntry(new byte[]{}), attributes);
     390            }
     391            return doCache;
    384392        } catch (Exception e) {
    385393            log.log(Level.WARNING, "JCS - Exception during download {0}",  getUrl());
     
    392400
    393401    /**
    394      *  @return if we should treat this object as properly loaded
    395      */
    396     protected abstract boolean handleNotFound();
     402     * Check if the object is loadable. This means, if the data will be parsed, and if this response
     403     * will finish as successful retrieve.
     404     *
     405     * This simple implementation doesn't load empty response, nor client (4xx) and server (5xx) errors
     406     *
     407     * @param headerFields headers sent by server
     408     * @param responseCode http status code
     409     * @param raw data read from server
     410     * @return true if object should be cached and returned to listener
     411     */
     412    protected boolean isResponseLoadable(Map<String, List<String>> headerFields, int responseCode, byte[] raw) {
     413        if (raw == null || raw.length == 0 || responseCode >= 400) {
     414            return false;
     415        }
     416        return true;
     417    }
    397418
    398419    protected abstract V createCacheEntry(byte[] content);
  • trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java

    r8425 r8433  
    137137
    138138    @Override
    139     protected boolean cacheAsEmpty(Map<String, List<String>> headers, int statusCode, byte[] content) {
    140         // cacheAsEmpty is called for every successful download, so we can put
    141         // metadata handling here
     139    protected boolean isResponseLoadable(Map<String, List<String>> headers, int statusCode, byte[] content) {
    142140        attributes.setMetadata(tile.getTileSource().getMetadata(headers));
    143141        if (tile.getTileSource().isNoTileAtZoom(headers, statusCode, content)) {
    144142            attributes.setNoTileAtZoom(true);
    145             return true;
    146         }
    147         return false;
     143            return false; // do no try to load data from no-tile at zoom, cache empty object instead
     144        }
     145        return super.isResponseLoadable(headers, statusCode, content);
     146    }
     147
     148    @Override
     149    protected boolean cacheAsEmpty() {
     150        return isNoTileAtZoom() || super.cacheAsEmpty();
    148151    }
    149152
     
    171174            listeners = inProgress.remove(getCacheKey());
    172175        }
     176        boolean status = result.equals(LoadResult.SUCCESS);
    173177
    174178        try {
     
    194198                    if (!isNoTileAtZoom() && httpStatusCode >= 400) {
    195199                        tile.setError(tr("HTTP error {0} when loading tiles", httpStatusCode));
     200                        status = false;
    196201                    }
    197202                    break;
     
    207212            if (listeners != null) { // listeners might be null, if some other thread notified already about success
    208213                for(TileLoaderListener l: listeners) {
    209                     l.tileLoadingFinished(tile, result.equals(LoadResult.SUCCESS));
     214                    l.tileLoadingFinished(tile, status);
    210215                }
    211216            }
     
    259264    }
    260265
    261     @Override
    262     protected boolean handleNotFound() {
    263         if (tile.getSource().isNoTileAtZoom(null, 404, null)) {
    264             tile.setError("No tile at this zoom level");
    265             tile.putValue("tile-info", "no-tile");
    266             return true;
    267         }
    268         return false;
    269     }
    270 
    271266    /**
    272267     * For TMS use BaseURL as settings discovery, so for different paths, we will have different settings (useful for developer servers)
Note: See TracChangeset for help on using the changeset viewer.