Changeset 8598 in josm


Ignore:
Timestamp:
2015-07-12T23:55:18+02:00 (9 years ago)
Author:
wiktorn
Message:

TileSource:

  • added method - getTileId that returns unique identifier for the tile, that should not collide with other tile sources
  • added JavaDocs

JCSCacheManager:

  • moved from object count limit to object size limit
  • fixed bug with unnecessary re-creation of auxilary cache, that could result in cache corruption/loss of current cache data

CachedTileLoaderFactory, WMSCachedTileLoader, TMSCachedTileLoader

  • un-abstract CachedTileLoaderFactory, use reflection to create TileLoaders
  • adjust constructors

TMSCachedTileLoader, AbstractCachedTileSourceLayer:

  • move cache related settings to AbstractCachedTileSourceLayer
  • move cache instation to AbstractCachedTileSourceLayer
  • make "flush tile cache" command clear only one tile source

TMSCachedTileLoaderJob:

  • make "flush tile cache" command clear only one tile source
  • reorder methods

TemplatedWMSTileSource:

  • java docs
  • inline of private methods: getTileXMax, getTileYMax
  • fix sonar issues
  • make WMS layer zoom levels closer to TMS (addresses: #11459)

WMTSTileSource:

  • fix Sonar issues
  • use topLeftCorner in X/Y tile max calculations instead of world bounds (fixes issues with WMTS-es, for which topLeftCorner lies outside projection world bounds)

AbstractTileSourceLayer:

  • draw warning, when min-zoom-level is set, and tiles are not loaded due to too many tiles on screen

TMSLayer, WMSLayer, WMTSLayer:

  • expose access to cache object for ImageryPreferences

CacheContentsPanel:

  • add panel for managing cache regions and tile sources within the regions

CommonSettingsPanel, TMSSettingsPanel:

  • move settings common to all imagery layers from TMSSettingsPanel to CommonSettingsPanel
Location:
trunk
Files:
3 added
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/MapRectifierWMSmenuAction.java

    r8510 r8598  
    235235    private void addWMSLayer(String title, String url) {
    236236        WMSLayer layer = new WMSLayer(new ImageryInfo(title, url));
    237         layer.checkGrabberType();
    238237        Main.main.addLayer(layer);
    239238    }
  • trunk/src/org/openstreetmap/josm/data/cache/JCSCacheManager.java

    r8514 r8598  
    1515import org.apache.commons.jcs.access.CacheAccess;
    1616import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
    17 import org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCache;
     17import org.apache.commons.jcs.auxiliary.AuxiliaryCacheFactory;
     18import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes;
    1819import org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes;
    1920import org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory;
     
    3536 */
    3637public final class JCSCacheManager {
    37     private static final Logger log = FeatureAdapter.getLogger(JCSCacheManager.class.getCanonicalName());
     38    private static final Logger LOG = FeatureAdapter.getLogger(JCSCacheManager.class.getCanonicalName());
    3839
    3940    private static volatile CompositeCacheManager cacheManager = null;
    4041    private static long maxObjectTTL        = Long.MAX_VALUE;
    4142    private static final String PREFERENCE_PREFIX = "jcs.cache";
    42     private static final IndexedDiskCacheFactory diskCacheFactory = new IndexedDiskCacheFactory();
     43    private static final AuxiliaryCacheFactory diskCacheFactory = new IndexedDiskCacheFactory();
    4344    private static FileLock cacheDirLock = null;
    4445
     
    6162        File cacheDirLockPath = new File(cacheDir, ".lock");
    6263        if (!cacheDirLockPath.exists() && !cacheDirLockPath.createNewFile()) {
    63             log.log(Level.WARNING, "Cannot create cache dir lock file");
     64            LOG.log(Level.WARNING, "Cannot create cache dir lock file");
    6465        }
    6566        cacheDirLock = new FileOutputStream(cacheDirLockPath).getChannel().tryLock();
    6667
    6768        if (cacheDirLock == null)
    68             log.log(Level.WARNING, "Cannot lock cache directory. Will not use disk cache");
     69            LOG.log(Level.WARNING, "Cannot lock cache directory. Will not use disk cache");
    6970
    7071        // raising logging level gives ~500x performance gain
    7172        // http://westsworld.dk/blog/2008/01/jcs-and-performance/
    72         Logger jcsLog = Logger.getLogger("org.apache.commons.jcs");
     73        final Logger jcsLog = Logger.getLogger("org.apache.commons.jcs");
    7374        jcsLog.setLevel(Level.INFO);
    7475        jcsLog.setUseParentHandlers(false);
     
    9293            @Override
    9394            public void flush() {
     95                // nothing to be done on flush
    9496            }
    9597
    9698            @Override
    9799            public void close() {
     100                // nothing to be done on close
    98101            }
    99102        });
     
    131134     * @param cacheName         region name
    132135     * @param maxMemoryObjects  number of objects to keep in memory
    133      * @param maxDiskObjects    number of objects to keep on disk (if cachePath provided)
     136     * @param maxDiskObjects    maximum size of the objects stored on disk in kB
    134137     * @param cachePath         path to disk cache. if null, no disk cache will be created
    135138     * @return cache access object
     
    153156
    154157        if (cachePath != null && cacheDirLock != null) {
    155             IndexedDiskCacheAttributes diskAttributes = getDiskCacheAttributes(maxDiskObjects, cachePath);
     158            IDiskCacheAttributes diskAttributes = getDiskCacheAttributes(maxDiskObjects, cachePath);
    156159            diskAttributes.setCacheName(cacheName);
    157             IndexedDiskCache<K, V> diskCache = diskCacheFactory.createCache(diskAttributes, cacheManager, null, new StandardSerializer());
    158 
    159             cc.setAuxCaches(new AuxiliaryCache[]{diskCache});
     160            try {
     161                if (cc.getAuxCaches().length == 0) {
     162                    AuxiliaryCache<K, V> diskCache = diskCacheFactory.createCache(diskAttributes, cacheManager, null, new StandardSerializer());
     163                    cc.setAuxCaches(new AuxiliaryCache[]{diskCache});
     164                }
     165            } catch (Exception e) {
     166                throw new RuntimeException(e);
     167            }
    160168        }
    161169        return new CacheAccess<K, V>(cc);
     
    173181    }
    174182
    175     private static IndexedDiskCacheAttributes getDiskCacheAttributes(int maxDiskObjects, String cachePath) {
     183    private static IDiskCacheAttributes getDiskCacheAttributes(int maxDiskObjects, String cachePath) {
    176184        IndexedDiskCacheAttributes ret = new IndexedDiskCacheAttributes();
     185        ret.setDiskLimitType(IDiskCacheAttributes.DiskLimitType.SIZE);
    177186        ret.setMaxKeySize(maxDiskObjects);
    178187        if (cachePath != null) {
    179188            File path = new File(cachePath);
    180189            if (!path.exists() && !path.mkdirs()) {
    181                 log.log(Level.WARNING, "Failed to create cache path: {0}", cachePath);
     190                LOG.log(Level.WARNING, "Failed to create cache path: {0}", cachePath);
    182191            } else {
    183192                ret.setDiskPath(path);
  • trunk/src/org/openstreetmap/josm/data/imagery/CachedTileLoaderFactory.java

    r8530 r8598  
    33
    44import java.io.File;
    5 import java.io.IOException;
    6 import java.util.HashMap;
     5import java.lang.reflect.Constructor;
     6import java.lang.reflect.InvocationTargetException;
    77import java.util.Map;
     8import java.util.concurrent.ConcurrentHashMap;
    89
     10import org.apache.commons.jcs.access.behavior.ICacheAccess;
    911import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
    1012import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
    1113import org.openstreetmap.josm.Main;
    1214import org.openstreetmap.josm.data.Version;
     15import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
    1316import org.openstreetmap.josm.data.preferences.StringProperty;
    1417
     
    1922 * @since 8526
    2023 */
    21 public abstract class CachedTileLoaderFactory implements TileLoaderFactory {
     24public class CachedTileLoaderFactory implements TileLoaderFactory {
    2225    /**
    2326     * Keeps the cache directory where
    2427     */
    2528    public static final StringProperty PROP_TILECACHE_DIR = getTileCacheDir();
    26     private String cacheName;
     29    private ICacheAccess<String, BufferedImageCacheEntry> cache;
     30    private Constructor<? extends TileLoader> tileLoaderConstructor;
    2731
    2832    /**
    29      * @param cacheName name of the cache region, that the created loader will use
     33     * @param cache cache instance which will be used by tile loaders created by this tile loader
     34     * @param tileLoaderClass tile loader class that will be created
     35     *
    3036     */
    31     public CachedTileLoaderFactory(String cacheName) {
    32         this.cacheName = cacheName;
     37    public CachedTileLoaderFactory(ICacheAccess<String, BufferedImageCacheEntry> cache, Class<? extends TileLoader> tileLoaderClass) {
     38        this.cache = cache;
     39        try {
     40            tileLoaderConstructor = tileLoaderClass.getConstructor(
     41                    TileLoaderListener.class,
     42                    ICacheAccess.class,
     43                    int.class,
     44                    int.class,
     45                    Map.class);
     46        } catch (NoSuchMethodException | SecurityException e) {
     47            Main.warn(e);
     48            throw new RuntimeException(e);
     49        }
    3350    }
    3451
     
    5067    @Override
    5168    public TileLoader makeTileLoader(TileLoaderListener listener, Map<String, String> inputHeaders) {
    52         Map<String, String> headers = new HashMap<>();
     69        Map<String, String> headers = new ConcurrentHashMap<>();
    5370        headers.put("User-Agent", Version.getInstance().getFullAgentString());
    5471        headers.put("Accept", "text/html, image/png, image/jpeg, image/gif, */*");
     
    5673            headers.putAll(inputHeaders);
    5774
    58         try {
    59             return getLoader(listener, cacheName,
    60                     Main.pref.getInteger("socket.timeout.connect", 15) * 1000,
    61                     Main.pref.getInteger("socket.timeout.read", 30) * 1000,
    62                     headers,
    63                     PROP_TILECACHE_DIR.get());
    64         } catch (IOException e) {
    65             Main.warn(e);
    66         }
    67         return null;
     75        return getLoader(listener, cache,
     76                Main.pref.getInteger("socket.timeout.connect", 15) * 1000,
     77                Main.pref.getInteger("socket.timeout.read", 30) * 1000,
     78                headers);
    6879    }
    6980
    70     protected abstract TileLoader getLoader(TileLoaderListener listener, String cacheName, int connectTimeout, int readTimeout,
    71             Map<String, String> headers, String cacheDir) throws IOException;
     81    protected TileLoader getLoader(TileLoaderListener listener, ICacheAccess<String, BufferedImageCacheEntry> cache,
     82            int connectTimeout, int readTimeout, Map<String, String> headers) {
     83        try {
     84            return tileLoaderConstructor.newInstance(
     85                    listener,
     86                    cache,
     87                    connectTimeout,
     88                    readTimeout,
     89                    headers);
     90        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
     91            Main.warn(e);
     92            throw new RuntimeException(e);
     93        }
     94    }
    7295}
  • trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java

    r8530 r8598  
    1717import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
    1818import org.openstreetmap.josm.data.cache.HostLimitQueue;
    19 import org.openstreetmap.josm.data.cache.JCSCacheManager;
    2019import org.openstreetmap.josm.data.cache.JCSCachedTileLoaderJob;
    2120import org.openstreetmap.josm.data.preferences.IntegerProperty;
     
    3433    protected final Map<String, String> headers;
    3534    protected final TileLoaderListener listener;
    36     private static final String PREFERENCE_PREFIX   = "imagery.tms.cache.";
    37 
    38     /**
    39      * how many object on disk should be stored for TMS region. Average tile size is about 20kb. 25000 is around 500MB under this assumption
    40      */
    41     public static final IntegerProperty MAX_OBJECTS_ON_DISK = new IntegerProperty(PREFERENCE_PREFIX + "max_objects_disk", 25000);
    4235
    4336    /**
    4437     * overrides the THREAD_LIMIT in superclass, as we want to have separate limit and pool for TMS
    4538     */
     39
    4640    public static final IntegerProperty THREAD_LIMIT = new IntegerProperty("imagery.tms.tmsloader.maxjobs", 25);
    4741
     
    5145    public static final IntegerProperty HOST_LIMIT = new IntegerProperty("imagery.tms.tmsloader.maxjobsperhost", 6);
    5246
     47
    5348    /**
    5449     * separate from JCS thread pool for TMS loader, so we can have different thread pools for default JCS
     
    5752    private static ThreadPoolExecutor DEFAULT_DOWNLOAD_JOB_DISPATCHER = getNewThreadPoolExecutor("TMS downloader");
    5853
     54
    5955    private ThreadPoolExecutor downloadExecutor = DEFAULT_DOWNLOAD_JOB_DISPATCHER;
    6056
     
    6258     * Constructor
    6359     * @param listener          called when tile loading has finished
    64      * @param name              of the cache
     60     * @param cache              of the cache
    6561     * @param connectTimeout    to remote resource
    6662     * @param readTimeout       to remote resource
    6763     * @param headers           HTTP headers to be sent along with request
    68      * @param cacheDir          where cache file shall reside
    6964     * @throws IOException      when cache initialization fails
    7065     */
    71     public TMSCachedTileLoader(TileLoaderListener listener, String name, int connectTimeout, int readTimeout,
    72             Map<String, String> headers, String cacheDir) throws IOException {
    73         this.cache = JCSCacheManager.getCache(name,
    74                 200, // use fairly small memory cache, as cached objects are quite big, as they contain BufferedImages
    75                 MAX_OBJECTS_ON_DISK.get(),
    76                 cacheDir);
     66    public TMSCachedTileLoader(TileLoaderListener listener, ICacheAccess<String, BufferedImageCacheEntry> cache,
     67            int connectTimeout, int readTimeout, Map<String, String> headers) throws IOException {
     68        this.cache = cache;
    7769        this.connectTimeout = connectTimeout;
    7870        this.readTimeout = readTimeout;
     
    113105    @Override
    114106    public void clearCache(TileSource source) {
    115         this.cache.clear();
     107        this.cache.remove(source.getName() + ":");
    116108    }
    117109
  • trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java

    r8510 r8598  
    8585    @Override
    8686    public String getCacheKey() {
    87         if (tile != null)
    88             return tile.getKey();
     87        if (tile != null) {
     88            TileSource tileSource = tile.getTileSource();
     89            String tsName = tileSource.getName();
     90            if (tsName == null) {
     91                tsName = "";
     92            }
     93            return tsName.replace(":", "_") + ":" + tileSource.getTileId(tile.getZoom(), tile.getXtile(), tile.getYtile());
     94        }
    8995        return null;
    9096    }
     
    128134    }
    129135
    130     private boolean isNoTileAtZoom() {
    131         if (attributes == null) {
    132             LOG.warning("Cache attributes are null");
    133         }
    134         return attributes != null && attributes.isNoTileAtZoom();
    135     }
    136 
    137136    @Override
    138137    protected boolean isResponseLoadable(Map<String, List<String>> headers, int statusCode, byte[] content) {
     
    148147    protected boolean cacheAsEmpty() {
    149148        return isNoTileAtZoom() || super.cacheAsEmpty();
    150     }
    151 
    152     private boolean handleNoTileAtZoom() {
    153         if (isNoTileAtZoom()) {
    154             LOG.log(Level.FINE, "JCS TMS - Tile valid, but no file, as no tiles at this level {0}", tile);
    155             tile.setError("No tile at this zoom level");
    156             tile.putValue("tile-info", "no-tile");
    157             return true;
    158         }
    159         return false;
    160149    }
    161150
     
    231220
    232221    /**
     222     * For TMS use BaseURL as settings discovery, so for different paths, we will have different settings (useful for developer servers)
     223     *
     224     * @return base URL of TMS or server url as defined in super class
     225     */
     226    @Override
     227    protected String getServerKey() {
     228        TileSource ts = tile.getSource();
     229        if (ts instanceof AbstractTMSTileSource) {
     230            return ((AbstractTMSTileSource) ts).getBaseUrl();
     231        }
     232        return super.getServerKey();
     233    }
     234
     235    @Override
     236    protected BufferedImageCacheEntry createCacheEntry(byte[] content) {
     237        return new BufferedImageCacheEntry(content);
     238    }
     239
     240    @Override
     241    public void submit() {
     242        submit(false);
     243    }
     244
     245    @Override
     246    protected CacheEntryAttributes parseHeaders(URLConnection urlConn) {
     247        CacheEntryAttributes ret = super.parseHeaders(urlConn);
     248        // keep the expiration time between MINIMUM_EXPIRES and MAXIMUM_EXPIRES, so we will cache the tiles
     249        // at least for some short period of time, but not too long
     250        if (ret.getExpirationTime() < MINIMUM_EXPIRES) {
     251            ret.setExpirationTime(now + MINIMUM_EXPIRES);
     252        }
     253        if (ret.getExpirationTime() > MAXIMUM_EXPIRES) {
     254            ret.setExpirationTime(now + MAXIMUM_EXPIRES);
     255        }
     256        return ret;
     257    }
     258
     259    /**
    233260     * Method for getting the tile from cache only, without trying to reach remote resource
    234261     * @return tile or null, if nothing (useful) was found in cache
     
    272299    }
    273300
    274     /**
    275      * For TMS use BaseURL as settings discovery, so for different paths, we will have different settings (useful for developer servers)
    276      *
    277      * @return base URL of TMS or server url as defined in super class
    278      */
    279     @Override
    280     protected String getServerKey() {
    281         TileSource ts = tile.getSource();
    282         if (ts instanceof AbstractTMSTileSource) {
    283             return ((AbstractTMSTileSource) ts).getBaseUrl();
    284         }
    285         return super.getServerKey();
    286     }
    287 
    288     @Override
    289     protected BufferedImageCacheEntry createCacheEntry(byte[] content) {
    290         return new BufferedImageCacheEntry(content);
    291     }
    292 
    293     @Override
    294     public void submit() {
    295         submit(false);
    296     }
    297 
    298     @Override
    299     protected CacheEntryAttributes parseHeaders(URLConnection urlConn) {
    300         CacheEntryAttributes ret = super.parseHeaders(urlConn);
    301         // keep the expiration time between MINIMUM_EXPIRES and MAXIMUM_EXPIRES, so we will cache the tiles
    302         // at least for some short period of time, but not too long
    303         if (ret.getExpirationTime() < MINIMUM_EXPIRES) {
    304             ret.setExpirationTime(now + MINIMUM_EXPIRES);
    305         }
    306         if (ret.getExpirationTime() > MAXIMUM_EXPIRES) {
    307             ret.setExpirationTime(now + MAXIMUM_EXPIRES);
    308         }
    309         return ret;
    310     }
     301    private boolean handleNoTileAtZoom() {
     302        if (isNoTileAtZoom()) {
     303            LOG.log(Level.FINE, "JCS TMS - Tile valid, but no file, as no tiles at this level {0}", tile);
     304            tile.setError("No tile at this zoom level");
     305            tile.putValue("tile-info", "no-tile");
     306            return true;
     307        }
     308        return false;
     309    }
     310
     311    private boolean isNoTileAtZoom() {
     312        if (attributes == null) {
     313            LOG.warning("Cache attributes are null");
     314        }
     315        return attributes != null && attributes.isNoTileAtZoom();
     316    }
     317
     318
    311319}
  • trunk/src/org/openstreetmap/josm/data/imagery/TemplatedWMSTileSource.java

    r8584 r8598  
    55
    66import java.awt.Point;
    7 import java.io.IOException;
    87import java.text.DecimalFormat;
    98import java.text.DecimalFormatSymbols;
    109import java.text.NumberFormat;
    11 import java.util.HashMap;
    1210import java.util.List;
    1311import java.util.Locale;
    1412import java.util.Map;
     13import java.util.concurrent.ConcurrentHashMap;
    1514import java.util.regex.Matcher;
    1615import java.util.regex.Pattern;
     
    3736 */
    3837public class TemplatedWMSTileSource extends TMSTileSource implements TemplatedTileSource {
    39     private Map<String, String> headers = new HashMap<>();
    40     private List<String> serverProjections;
     38    private Map<String, String> headers = new ConcurrentHashMap<>();
     39    private final List<String> serverProjections;
    4140    private EastNorth topLeftCorner;
    4241
    43     private static final String COOKIE_HEADER   = "Cookie";
    4442    private static final String PATTERN_HEADER  = "\\{header\\(([^,]+),([^}]+)\\)\\}";
    4543    private static final String PATTERN_PROJ    = "\\{proj(\\([^})]+\\))?\\}";
     
    6967    }
    7068
     69    /**
     70     * Initializes class with current projection in JOSM. This call is needed every time projection changes.
     71     */
    7172    public void initProjection() {
    7273        initProjection(Main.getProjection());
    7374    }
    7475
     76    /**
     77     * Initializes class with projection in JOSM. This call is needed every time projection changes.
     78     * @param proj new projection that shall be used for computations
     79     */
    7580    public void initProjection(Projection proj) {
    7681        Bounds bounds = proj.getWorldBoundsLatLon();
     
    9398
    9499    @Override
    95     public String getTileUrl(int zoom, int tilex, int tiley) throws IOException {
     100    public String getTileUrl(int zoom, int tilex, int tiley) {
    96101        String myProjCode = Main.getProjection().toCode();
    97102
     
    225230    @Override
    226231    public int getTileXMax(int zoom) {
    227         return getTileXMax(zoom, Main.getProjection());
     232        Projection proj = Main.getProjection();
     233        double scale = getDegreesPerTile(zoom);
     234        Bounds bounds = Main.getProjection().getWorldBoundsLatLon();
     235        EastNorth min = proj.latlon2eastNorth(bounds.getMin());
     236        EastNorth max = proj.latlon2eastNorth(bounds.getMax());
     237        return (int) Math.ceil(Math.abs(max.getX() - min.getX()) / scale);
    228238    }
    229239
     
    233243    }
    234244
    235     //TODO: cache this method with projection code as the key
    236245    @Override
    237246    public int getTileYMax(int zoom) {
    238         return getTileYMax(zoom, Main.getProjection());
     247        Projection proj = Main.getProjection();
     248        double scale = getDegreesPerTile(zoom);
     249        Bounds bounds = Main.getProjection().getWorldBoundsLatLon();
     250        EastNorth min = proj.latlon2eastNorth(bounds.getMin());
     251        EastNorth max = proj.latlon2eastNorth(bounds.getMax());
     252        return (int) Math.ceil(Math.abs(max.getY() - min.getY()) / scale);
    239253    }
    240254
     
    347361        EastNorth min = proj.latlon2eastNorth(bounds.getMin());
    348362        EastNorth max = proj.latlon2eastNorth(bounds.getMax());
    349         int tilesPerZoom = (int) Math.pow(2, zoom);
    350         double ret = Math.max(
     363        int tilesPerZoom = (int) Math.pow(2, zoom - 1);
     364        return Math.max(
    351365                Math.abs(max.getY() - min.getY()) / tilesPerZoom,
    352366                Math.abs(max.getX() - min.getX()) / tilesPerZoom
    353367                );
    354 
    355         return ret;
    356     }
    357 
    358     private int getTileYMax(int zoom, Projection proj) {
    359         double scale = getDegreesPerTile(zoom);
    360         Bounds bounds = Main.getProjection().getWorldBoundsLatLon();
    361         EastNorth min = proj.latlon2eastNorth(bounds.getMin());
    362         EastNorth max = proj.latlon2eastNorth(bounds.getMax());
    363         return (int) Math.ceil(Math.abs(max.getY() - min.getY()) / scale);
    364     }
    365 
    366     private int getTileXMax(int zoom, Projection proj) {
    367         double scale = getDegreesPerTile(zoom);
    368         Bounds bounds = Main.getProjection().getWorldBoundsLatLon();
    369         EastNorth min = proj.latlon2eastNorth(bounds.getMin());
    370         EastNorth max = proj.latlon2eastNorth(bounds.getMax());
    371         return (int) Math.ceil(Math.abs(max.getX() - min.getX()) / scale);
     368    }
     369
     370    @Override
     371    public String getTileId(int zoom, int tilex, int tiley) {
     372        return getTileUrl(zoom, tilex, tiley);
    372373    }
    373374}
  • trunk/src/org/openstreetmap/josm/data/imagery/WMSCachedTileLoader.java

    r8530 r8598  
    55import java.util.Map;
    66
     7import org.apache.commons.jcs.access.behavior.ICacheAccess;
    78import org.openstreetmap.gui.jmapviewer.Tile;
    89import org.openstreetmap.gui.jmapviewer.interfaces.TileJob;
    910import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
    10 import org.openstreetmap.josm.data.preferences.IntegerProperty;
     11import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
    1112
    1213/**
     
    1920public class WMSCachedTileLoader extends TMSCachedTileLoader {
    2021
    21     /** limit of concurrent connections to WMS tile source (per source) */
    22     public static final IntegerProperty THREAD_LIMIT = new IntegerProperty("imagery.wms.simultaneousConnections", 3);
    23 
    2422    /**
    2523     * Creates a TileLoader with separate WMS downloader.
    2624     *
    2725     * @param listener that will be notified when tile is loaded
    28      * @param name name of the cache region
     26     * @param cache reference
    2927     * @param connectTimeout to tile source
    3028     * @param readTimeout from tile source
    3129     * @param headers to be sent with requests
    32      * @param cacheDir place to store the cache
    3330     * @throws IOException when there is a problem creating cache repository
    3431     */
    35     public WMSCachedTileLoader(TileLoaderListener listener, String name, int connectTimeout, int readTimeout,
    36             Map<String, String> headers, String cacheDir) throws IOException {
     32    public WMSCachedTileLoader(TileLoaderListener listener, ICacheAccess<String, BufferedImageCacheEntry> cache,
     33            int connectTimeout, int readTimeout, Map<String, String> headers) throws IOException {
    3734
    38         super(listener, name, connectTimeout, readTimeout, headers, cacheDir);
     35        super(listener, cache, connectTimeout, readTimeout, headers);
    3936        setDownloadExecutor(TMSCachedTileLoader.getNewThreadPoolExecutor("WMS downloader", THREAD_LIMIT.get()));
    4037    }
  • trunk/src/org/openstreetmap/josm/data/imagery/WMSCachedTileLoaderJob.java

    r8530 r8598  
    4040        String key = super.getCacheKey();
    4141        if (key != null) {
    42             return Main.getProjection().toCode() + key;
     42            return key + Main.getProjection().toCode();
    4343        }
    4444        return null;
  • trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java

    r8586 r8598  
    1515import java.util.Collection;
    1616import java.util.Comparator;
    17 import java.util.HashMap;
    1817import java.util.Map;
    1918import java.util.Set;
     
    2726import javax.swing.JPanel;
    2827import javax.swing.ListSelectionModel;
     28import javax.xml.XMLConstants;
    2929import javax.xml.namespace.QName;
    3030import javax.xml.parsers.DocumentBuilder;
    3131import javax.xml.parsers.DocumentBuilderFactory;
     32import javax.xml.parsers.ParserConfigurationException;
    3233import javax.xml.xpath.XPath;
    3334import javax.xml.xpath.XPathConstants;
     
    4344import org.openstreetmap.gui.jmapviewer.tilesources.TMSTileSource;
    4445import org.openstreetmap.josm.Main;
    45 import org.openstreetmap.josm.data.Bounds;
    4646import org.openstreetmap.josm.data.coor.EastNorth;
    4747import org.openstreetmap.josm.data.coor.LatLon;
     
    5353import org.openstreetmap.josm.tools.GBC;
    5454import org.openstreetmap.josm.tools.Utils;
    55 import org.w3c.dom.DOMException;
    5655import org.w3c.dom.Document;
    5756import org.w3c.dom.Node;
     
    7574
    7675    private static class TileMatrix {
    77         String identifier;
    78         double scaleDenominator;
    79         EastNorth topLeftCorner;
    80         int tileWidth;
    81         int tileHeight;
    82         public int matrixWidth = -1;
    83         public int matrixHeight = -1;
     76        private String identifier;
     77        private double scaleDenominator;
     78        private EastNorth topLeftCorner;
     79        private int tileWidth;
     80        private int tileHeight;
     81        private int matrixWidth = -1;
     82        private int matrixHeight = -1;
    8483    }
    8584
     
    9291            }
    9392        }); // sorted by zoom level
    94         String crs;
    95         String identifier;
     93        private String crs;
     94        private String identifier;
    9695    }
    9796
    9897    private static class Layer {
    99         String format;
    100         String name;
    101         Map<String, TileMatrixSet> tileMatrixSetByCRS = new ConcurrentHashMap<>();
    102         public String baseUrl;
    103         public String style;
     98        private String format;
     99        private String name;
     100        private Map<String, TileMatrixSet> tileMatrixSetByCRS = new ConcurrentHashMap<>();
     101        private String baseUrl;
     102        private String style;
    104103    }
    105104
     
    129128
    130129    private static final class SelectLayerDialog extends ExtendedDialog {
    131         private Layer[] layers;
    132         private JList<String> list;
    133 
    134         private SelectLayerDialog(Collection<Layer> layers) {
     130        private final Layer[] layers;
     131        private final JList<String> list;
     132
     133        public SelectLayerDialog(Collection<Layer> layers) {
    135134            super(Main.parent, tr("Select WMTS layer"), new String[]{tr("Add layers"), tr("Cancel")});
    136135            this.layers = layers.toArray(new Layer[]{});
     
    143142        }
    144143
    145         private String[] getLayerNames(Collection<Layer> layers) {
     144        private static final String[] getLayerNames(Collection<Layer> layers) {
    146145            Collection<String> ret = new ArrayList<>();
    147146            for (Layer layer: layers) {
     
    160159    }
    161160
    162     private Map<String, String> headers = new HashMap<>();
     161    private final Map<String, String> headers = new ConcurrentHashMap<>();
    163162    private Collection<Layer> layers;
    164163    private Layer currentLayer;
     
    177176        this.layers = getCapabilities();
    178177        if (layers.size() > 1) {
    179             SelectLayerDialog layerSelection = new SelectLayerDialog(layers);
     178            final SelectLayerDialog layerSelection = new SelectLayerDialog(layers);
    180179            if (layerSelection.showDialog().getValue() == 1) {
    181180                this.currentLayer = layerSelection.getSelectedLayer();
    182                 // TODO: save layer information into ImageryInfo / ImageryPreferences
     181                // TODO: save layer information into ImageryInfo / ImageryPreferences?
    183182            } else {
    184183                throw new IllegalArgumentException(); //user canceled operation
     
    205204    }
    206205
    207     private Collection<Layer> getCapabilities() throws IOException  {
     206    private Collection<Layer> getCapabilities() throws IOException {
    208207        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    209208        builderFactory.setValidating(false);
    210209        builderFactory.setNamespaceAware(false);
     210        try {
     211            builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
     212        } catch (ParserConfigurationException e) {
     213            //this should not happen
     214            throw new IllegalArgumentException(e);
     215        }
    211216        DocumentBuilder builder = null;
    212217        InputStream in = new CachedFile(baseUrl).
     
    266271    }
    267272
    268     private Map<String, TileMatrixSet> parseMatrices(NodeList nodeList) throws DOMException, XPathExpressionException {
     273    private Map<String, TileMatrixSet> parseMatrices(NodeList nodeList) throws XPathExpressionException {
    269274        Map<String, TileMatrixSet> ret = new ConcurrentHashMap<>();
    270275        for (int matrixSetId = 0; matrixSetId < nodeList.getLength(); matrixSetId++) {
     
    314319    }
    315320
    316     private int getOptionalIntegerByXpath(Node document, String xpathQuery) throws XPathExpressionException {
     321    private static int getOptionalIntegerByXpath(Node document, String xpathQuery) throws XPathExpressionException {
    317322        String ret = getStringByXpath(document, xpathQuery);
    318323        if (ret == null || "".equals(ret)) {
     
    374379
    375380    @Override
    376     public String getTileUrl(int zoom, int tilex, int tiley) throws IOException {
     381    public String getTileUrl(int zoom, int tilex, int tiley) {
    377382        String url;
    378383        switch (transferMode) {
     
    471476    @Override
    472477    public TileXY latLonToTileXY(double lat, double lon, int zoom) {
    473         Projection proj = Main.getProjection();
    474         EastNorth enPoint = proj.latlon2eastNorth(new LatLon(lat, lon));
    475478        TileMatrix matrix = getTileMatrix(zoom);
    476479        if (matrix == null) {
    477480            return new TileXY(0, 0);
    478481        }
     482
     483        Projection proj = Main.getProjection();
     484        EastNorth enPoint = proj.latlon2eastNorth(new LatLon(lat, lon));
    479485        double scale = matrix.scaleDenominator * this.crsScale;
    480486        return new TileXY(
     
    576582        return 0;
    577583    }
     584
     585    @Override
     586    public String getTileId(int zoom, int tilex, int tiley) {
     587        return getTileUrl(zoom, tilex, tiley);
     588    }
     589
    578590
    579591    /**
     
    617629
    618630        double scale = matrix.scaleDenominator * this.crsScale;
    619         Bounds bounds = proj.getWorldBoundsLatLon();
    620         EastNorth min = proj.latlon2eastNorth(bounds.getMin());
    621         EastNorth max = proj.latlon2eastNorth(bounds.getMax());
     631        EastNorth min = matrix.topLeftCorner;
     632        EastNorth max = proj.latlon2eastNorth(proj.getWorldBoundsLatLon().getMax());
    622633        return (int) Math.ceil(Math.abs(max.north() - min.north()) / scale);
    623634    }
     
    633644
    634645        double scale = matrix.scaleDenominator * this.crsScale;
    635         Bounds bounds = proj.getWorldBoundsLatLon();
    636         EastNorth min = proj.latlon2eastNorth(bounds.getMin());
    637         EastNorth max = proj.latlon2eastNorth(bounds.getMax());
     646        EastNorth min = matrix.topLeftCorner;
     647        EastNorth max = proj.latlon2eastNorth(proj.getWorldBoundsLatLon().getMax());
    638648        return (int) Math.ceil(Math.abs(max.east() - min.east()) / scale);
    639649    }
  • trunk/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java

    r8526 r8598  
    4040import org.openstreetmap.josm.data.imagery.ImageryInfo;
    4141import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
     42import org.openstreetmap.josm.data.imagery.TMSCachedTileLoader;
    4243import org.openstreetmap.josm.data.preferences.StringProperty;
     44import org.openstreetmap.josm.gui.layer.AbstractCachedTileSourceLayer;
    4345import org.openstreetmap.josm.gui.layer.TMSLayer;
    4446
     
    139141        headers.put("User-Agent", Version.getInstance().getFullAgentString());
    140142
    141         cachedLoader = TMSLayer.loaderFactory.makeTileLoader(this, headers);
     143        cachedLoader = AbstractCachedTileSourceLayer.getTileLoaderFactory("TMS", TMSCachedTileLoader.class).makeTileLoader(this, headers);
    142144
    143145        uncachedLoader = new OsmTileLoader(this);
  • trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java

    r8571 r8598  
    206206     */
    207207    public void clearTileCache(ProgressMonitor monitor) {
    208         tileCache.clear();
    209208        if (tileLoader instanceof CachedTileLoader) {
    210209            ((CachedTileLoader) tileLoader).clearCache(tileSource);
    211210        }
     211        // if we use TMSCachedTileLoader, we already cleared by tile source, this is needed
     212        // to prevent removal of additional objects
     213        if (!(tileLoader instanceof TMSCachedTileLoader)) {
     214            tileCache.clear();
     215        }
     216
    212217    }
    213218
     
    14091414            }
    14101415        }
     1416
     1417        if (zoom < getMinZoomLvl() && (ts.insane() || ts.tooLarge())) {
     1418            myDrawString(g, tr("zoom in to load any tiles"), 120, 120);
     1419        }
     1420
    14111421        if (noTilesAtZoom) {
    14121422            myDrawString(g, tr("No tiles at this zoom level"), 120, 120);
  • trunk/src/org/openstreetmap/josm/gui/layer/TMSLayer.java

    r8568 r8598  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.io.IOException;
    7 import java.util.Map;
    8 
     6import org.apache.commons.jcs.access.CacheAccess;
    97import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
    10 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
    118import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
    129import org.openstreetmap.gui.jmapviewer.tilesources.ScanexTileSource;
    1310import org.openstreetmap.gui.jmapviewer.tilesources.TMSTileSource;
    1411import org.openstreetmap.gui.jmapviewer.tilesources.TemplatedTMSTileSource;
     12import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
    1513import org.openstreetmap.josm.data.imagery.CachedAttributionBingAerialTileSource;
    16 import org.openstreetmap.josm.data.imagery.CachedTileLoaderFactory;
    1714import org.openstreetmap.josm.data.imagery.ImageryInfo;
    1815import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
    1916import org.openstreetmap.josm.data.imagery.TMSCachedTileLoader;
    20 import org.openstreetmap.josm.data.imagery.TileLoaderFactory;
    2117import org.openstreetmap.josm.data.preferences.BooleanProperty;
    2218import org.openstreetmap.josm.data.preferences.IntegerProperty;
     
    3228 *
    3329 */
    34 public class TMSLayer extends AbstractTileSourceLayer {
     30public class TMSLayer extends AbstractCachedTileSourceLayer {
     31    private static final String CACHE_REGION_NAME = "TMS";
     32
    3533    private static final String PREFERENCE_PREFIX = "imagery.tms";
    3634
     
    4543            true);
    4644
    47     /** loader factory responsible for loading tiles for this layer */
    48     public static TileLoaderFactory loaderFactory = new CachedTileLoaderFactory("TMS"){
    49 
    50         @Override
    51         protected TileLoader getLoader(TileLoaderListener listener, String cacheName, int connectTimeout,
    52                 int readTimeout, Map<String, String> headers, String cacheDir) throws IOException {
    53             return new TMSCachedTileLoader(listener, cacheName, connectTimeout, readTimeout, headers, cacheDir);
    54         }
    55 
    56     };
    57 
    5845    /**
    5946     * Create a layer based on ImageryInfo
     
    6451    }
    6552
    66     /**
    67      * Plugins that wish to set custom tile loader should call this method
    68      * @param newLoaderFactory that will be used to load tiles
    69      */
    70 
    71     public static void setTileLoaderFactory(TileLoaderFactory newLoaderFactory) {
    72         loaderFactory = newLoaderFactory;
    73     }
    74 
    75     @Override
    76     protected TileLoaderFactory getTileLoaderFactory() {
    77         return loaderFactory;
    78     }
    7953
    8054    /**
     
    136110    }
    137111
     112    @Override
     113    protected Class<? extends TileLoader> getTileLoaderClass() {
     114        return TMSCachedTileLoader.class;
     115    }
    138116
     117    @Override
     118    protected String getCacheName() {
     119        return CACHE_REGION_NAME;
     120    }
     121
     122    /**
     123     * @return cache for TMS region
     124     */
     125    public static CacheAccess<String, BufferedImageCacheEntry> getCache() {
     126        return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME);
     127    }
    139128
    140129}
  • trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java

    r8557 r8598  
    55
    66import java.awt.event.ActionEvent;
    7 import java.io.IOException;
    87import java.util.ArrayList;
    98import java.util.Arrays;
    109import java.util.List;
    1110import java.util.Map;
     11import java.util.Set;
     12import java.util.TreeSet;
    1213
    1314import javax.swing.AbstractAction;
    1415import javax.swing.Action;
    1516
     17import org.apache.commons.jcs.access.CacheAccess;
    1618import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
    17 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
    1819import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
    1920import org.openstreetmap.josm.Main;
    20 import org.openstreetmap.josm.data.imagery.CachedTileLoaderFactory;
     21import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
    2122import org.openstreetmap.josm.data.imagery.ImageryInfo;
    2223import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
    2324import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
    2425import org.openstreetmap.josm.data.imagery.TemplatedWMSTileSource;
    25 import org.openstreetmap.josm.data.imagery.TileLoaderFactory;
    2626import org.openstreetmap.josm.data.imagery.WMSCachedTileLoader;
    2727import org.openstreetmap.josm.data.preferences.BooleanProperty;
     
    3434 *
    3535 */
    36 public class WMSLayer extends AbstractTileSourceLayer {
     36public class WMSLayer extends AbstractCachedTileSourceLayer {
     37    private static final String PREFERENCE_PREFIX   = "imagery.wms.";
     38
    3739    /** default tile size for WMS Layer */
    38     public static final IntegerProperty PROP_IMAGE_SIZE = new IntegerProperty("imagery.wms.imageSize", 512);
     40    public static final IntegerProperty PROP_IMAGE_SIZE = new IntegerProperty(PREFERENCE_PREFIX + "imageSize", 512);
     41
    3942    /** should WMS layer autozoom in default mode */
    40     public static final BooleanProperty PROP_DEFAULT_AUTOZOOM = new BooleanProperty("imagery.wms.default_autozoom", true);
    41     private List<String> supportedProjections;
     43    public static final BooleanProperty PROP_DEFAULT_AUTOZOOM = new BooleanProperty(PREFERENCE_PREFIX + "default_autozoom", true);
     44
     45    /** limit of concurrent connections to WMS tile source (per source) */
     46    public static final IntegerProperty THREAD_LIMIT = new IntegerProperty(PREFERENCE_PREFIX + "simultaneousConnections", 3);
     47
     48    private static final String CACHE_REGION_NAME = "WMS";
     49
     50    private Set<String> supportedProjections;
    4251
    4352    /**
     
    4756    public WMSLayer(ImageryInfo info) {
    4857        super(info);
    49         this.supportedProjections = info.getServerProjections();
     58        this.supportedProjections = new TreeSet<>(info.getServerProjections());
     59        this.autoZoom = PROP_DEFAULT_AUTOZOOM.get();
     60
    5061    }
    5162
     
    6273
    6374    @Override
    64     protected TileSource getTileSource(ImageryInfo info) throws IllegalArgumentException {
     75    protected TileSource getTileSource(ImageryInfo info) {
    6576        if (info.getImageryType() == ImageryType.WMS && info.getUrl() != null) {
    6677            TemplatedWMSTileSource.checkUrl(info.getUrl());
     
    89100            ImageryLayerInfo.addLayer(new ImageryInfo(info));
    90101        }
    91     }
    92 
    93     /**
    94      * Checks that WMS layer is a grabber-compatible one (HTML or WMS).
    95      * @throws IllegalStateException if imagery time is neither HTML nor WMS
    96      * @since 8068
    97      */
    98     public void checkGrabberType() {
    99     }
    100 
    101     private static TileLoaderFactory loaderFactory = new CachedTileLoaderFactory("WMS") {
    102         @Override
    103         protected TileLoader getLoader(TileLoaderListener listener, String cacheName, int connectTimeout,
    104                 int readTimeout, Map<String, String> headers, String cacheDir) throws IOException {
    105             return new WMSCachedTileLoader(listener, cacheName, connectTimeout, readTimeout, headers, cacheDir);
    106         }
    107 
    108     };
    109 
    110     @Override
    111     protected TileLoaderFactory getTileLoaderFactory() {
    112         return loaderFactory;
    113102    }
    114103
     
    149138        }
    150139    }
     140
     141    /**
     142     * Checks that WMS layer is a grabber-compatible one (HTML or WMS).
     143     * @throws IllegalStateException if imagery time is neither HTML nor WMS
     144     * @since 8068
     145     * @deprecated not implemented anymore
     146     */
     147    @Deprecated
     148    public void checkGrabberType() {
     149        // not implemented
     150    }
     151
     152    @Override
     153    protected Class<? extends TileLoader> getTileLoaderClass() {
     154        return WMSCachedTileLoader.class;
     155    }
     156
     157    @Override
     158    protected String getCacheName() {
     159        return CACHE_REGION_NAME;
     160    }
     161
     162    /**
     163     * @return cache region for WMS layer
     164     */
     165    public static CacheAccess<String, BufferedImageCacheEntry> getCache() {
     166        return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME);
     167    }
    151168}
  • trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java

    r8586 r8598  
    33
    44import java.io.IOException;
    5 import java.util.Map;
    65
     6import org.apache.commons.jcs.access.CacheAccess;
    77import org.openstreetmap.gui.jmapviewer.TileXY;
    88import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
    99import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
    10 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
    1110import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
    1211import org.openstreetmap.josm.Main;
     12import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
    1313import org.openstreetmap.josm.data.coor.LatLon;
    14 import org.openstreetmap.josm.data.imagery.CachedTileLoaderFactory;
    1514import org.openstreetmap.josm.data.imagery.ImageryInfo;
    1615import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
    17 import org.openstreetmap.josm.data.imagery.TileLoaderFactory;
    1816import org.openstreetmap.josm.data.imagery.WMSCachedTileLoader;
    1917import org.openstreetmap.josm.data.imagery.WMTSTileSource;
     
    3230 *
    3331 */
    34 public class WMTSLayer extends AbstractTileSourceLayer {
     32public class WMTSLayer extends AbstractCachedTileSourceLayer {
    3533    /**
    3634     * default setting of autozoom per layer
    3735     */
    3836    public static final BooleanProperty PROP_DEFAULT_AUTOZOOM = new BooleanProperty("imagery.wmts.default_autozoom", true);
     37    private static final String CACHE_REGION_NAME = "WMTS";
    3938
    4039
     
    4544    public WMTSLayer(ImageryInfo info) {
    4645        super(info);
    47     }
    48 
    49     private static TileLoaderFactory loaderFactory = new CachedTileLoaderFactory("WMTS") {
    50         @Override
    51         protected TileLoader getLoader(TileLoaderListener listener, String cacheName, int connectTimeout,
    52                 int readTimeout, Map<String, String> headers, String cacheDir) throws IOException {
    53             return new WMSCachedTileLoader(listener, cacheName, connectTimeout, readTimeout, headers, cacheDir);
    54         }
    55 
    56     };
    57 
    58     @Override
    59     protected TileLoaderFactory getTileLoaderFactory() {
    60         return loaderFactory;
     46        autoZoom = PROP_DEFAULT_AUTOZOOM.get();
    6147    }
    6248
     
    126112        ((WMTSTileSource) tileSource).initProjection(newValue);
    127113    }
     114
     115    @Override
     116    protected Class<? extends TileLoader> getTileLoaderClass() {
     117        return WMSCachedTileLoader.class;
     118    }
     119
     120    @Override
     121    protected String getCacheName() {
     122        return CACHE_REGION_NAME;
     123    }
     124
     125    /**
     126     * @return cache region for WMTS layer
     127     */
     128    public static CacheAccess<String, BufferedImageCacheEntry> getCache() {
     129        return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME);
     130    }
    128131}
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/CommonSettingsPanel.java

    r7937 r8598  
    1515import javax.swing.JPanel;
    1616import javax.swing.JSlider;
     17import javax.swing.JSpinner;
     18import javax.swing.SpinnerNumberModel;
    1719
     20import org.openstreetmap.josm.data.imagery.CachedTileLoaderFactory;
     21import org.openstreetmap.josm.gui.layer.AbstractCachedTileSourceLayer;
    1822import org.openstreetmap.josm.gui.layer.ImageryLayer;
    1923import org.openstreetmap.josm.gui.widgets.JosmComboBox;
     24import org.openstreetmap.josm.gui.widgets.JosmTextField;
    2025import org.openstreetmap.josm.tools.ColorHelper;
    2126import org.openstreetmap.josm.tools.GBC;
     
    3136    private final JSlider fadeAmount = new JSlider(0, 100);
    3237    private final JosmComboBox<String> sharpen;
     38    private final JosmTextField tilecacheDir = new JosmTextField();
     39    private final JSpinner maxElementsOnDisk;
     40    private final JSpinner maxElementsInRam;
     41
    3342
    3443    /**
     
    3746    public CommonSettingsPanel() {
    3847        super(new GridBagLayout());
    39        
     48
     49        this.maxElementsInRam = new JSpinner(new SpinnerNumberModel(
     50                AbstractCachedTileSourceLayer.MEMORY_CACHE_SIZE.get().intValue(), 0, Integer.MAX_VALUE, 1));
     51        this.maxElementsOnDisk = new JSpinner(new SpinnerNumberModel(
     52                AbstractCachedTileSourceLayer.MAX_DISK_CACHE_SIZE.get().intValue(), 0, Integer.MAX_VALUE, 1));
     53
     54
    4055        this.btnFadeColor = new JButton();
    4156
     
    7287        add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
    7388        add(this.sharpen, GBC.eol().fill(GBC.HORIZONTAL));
     89
     90        add(new JLabel(tr("Tile cache directory: ")), GBC.std());
     91        add(GBC.glue(5, 0), GBC.std());
     92        add(tilecacheDir, GBC.eol().fill(GBC.HORIZONTAL));
     93
     94        add(new JLabel(tr("Maximum size of disk cache (per imagery) in MB: ")), GBC.std());
     95        add(GBC.glue(5, 0), GBC.std());
     96        add(this.maxElementsOnDisk, GBC.eol());
     97
     98        add(new JLabel(tr("Maximum number of objects in memory cache: ")), GBC.std());
     99        add(GBC.glue(5, 0), GBC.std());
     100        add(this.maxElementsInRam, GBC.eol());
    74101    }
    75    
     102
    76103    /**
    77104     * Loads the common settings.
     
    83110        this.fadeAmount.setValue(ImageryLayer.PROP_FADE_AMOUNT.get());
    84111        this.sharpen.setSelectedIndex(Math.max(0, Math.min(2, ImageryLayer.PROP_SHARPEN_LEVEL.get())));
     112        this.tilecacheDir.setText(CachedTileLoaderFactory.PROP_TILECACHE_DIR.get());
     113        this.maxElementsOnDisk.setValue(AbstractCachedTileSourceLayer.MAX_DISK_CACHE_SIZE.get());
     114        this.maxElementsInRam.setValue(AbstractCachedTileSourceLayer.MEMORY_CACHE_SIZE.get());
     115
    85116    }
    86    
     117
    87118    /**
    88119     * Saves the common settings.
     
    93124        ImageryLayer.PROP_FADE_COLOR.put(this.btnFadeColor.getBackground());
    94125        ImageryLayer.PROP_SHARPEN_LEVEL.put(sharpen.getSelectedIndex());
    95         return false;
     126        boolean restartRequired = false;
     127        if (!AbstractCachedTileSourceLayer.MAX_DISK_CACHE_SIZE.get().equals(this.maxElementsOnDisk.getValue())) {
     128            AbstractCachedTileSourceLayer.MAX_DISK_CACHE_SIZE.put((Integer) this.maxElementsOnDisk.getValue());
     129            restartRequired = true;
     130        }
     131
     132
     133        if (!CachedTileLoaderFactory.PROP_TILECACHE_DIR.get().equals(this.tilecacheDir.getText())) {
     134            restartRequired = true;
     135            CachedTileLoaderFactory.PROP_TILECACHE_DIR.put(this.tilecacheDir.getText());
     136        }
     137
     138        if (!AbstractCachedTileSourceLayer.MEMORY_CACHE_SIZE.get().equals(this.maxElementsInRam.getValue())) {
     139            AbstractCachedTileSourceLayer.MEMORY_CACHE_SIZE.put((Integer) this.maxElementsInRam.getValue());
     140        }
     141
     142
     143        return restartRequired;
    96144    }
    97145}
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreference.java

    r8568 r8598  
    7373public final class ImageryPreference extends DefaultTabPreferenceSetting {
    7474
     75    private ImageryProvidersPanel imageryProviders;
     76    private ImageryLayerInfo layerInfo;
     77
     78    private CommonSettingsPanel commonSettings;
     79    private WMSSettingsPanel wmsSettings;
     80    private TMSSettingsPanel tmsSettings;
     81
    7582    /**
    7683     * Factory used to create a new {@code ImageryPreference}.
     
    8794                false, new JTabbedPane());
    8895    }
    89 
    90     private ImageryProvidersPanel imageryProviders;
    91     private ImageryLayerInfo layerInfo;
    92 
    93     private CommonSettingsPanel commonSettings;
    94     private WMSSettingsPanel wmsSettings;
    95     private TMSSettingsPanel tmsSettings;
    9696
    9797    private void addSettingsSection(final JPanel p, String name, JPanel section) {
     
    131131        pane.addTab(tr("Settings"), buildSettingsPanel());
    132132        pane.addTab(tr("Offset bookmarks"), new OffsetBookmarksPanel(gui));
     133        pane.addTab(tr("Cache contents") , new CacheContentsPanel());
    133134        loadSettings();
    134135        p.add(pane, GBC.std().fill(GBC.BOTH));
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/TMSSettingsPanel.java

    r8540 r8598  
    1212import javax.swing.SpinnerNumberModel;
    1313
    14 import org.openstreetmap.josm.data.imagery.CachedTileLoaderFactory;
    1514import org.openstreetmap.josm.data.imagery.TMSCachedTileLoader;
    1615import org.openstreetmap.josm.data.imagery.TMSCachedTileLoaderJob;
    1716import org.openstreetmap.josm.gui.layer.TMSLayer;
    18 import org.openstreetmap.josm.gui.widgets.JosmTextField;
    1917import org.openstreetmap.josm.tools.GBC;
    2018
     
    3129    private final JSpinner maxZoomLvl;
    3230    private final JCheckBox addToSlippyMapChosser = new JCheckBox();
    33     private final JosmTextField tilecacheDir = new JosmTextField();
    34     private final JSpinner maxElementsOnDisk;
     31
    3532    private final JSpinner maxConcurrentDownloads;
    3633    private final JSpinner maxDownloadsPerHost;
     
    4643        maxZoomLvl = new JSpinner(new SpinnerNumberModel(
    4744                TMSLayer.PROP_MAX_ZOOM_LVL.get().intValue(), TMSLayer.MIN_ZOOM, TMSLayer.MAX_ZOOM, 1));
    48         maxElementsOnDisk = new JSpinner(new SpinnerNumberModel(
    49                 TMSCachedTileLoader.MAX_OBJECTS_ON_DISK.get().intValue(), 0, Integer.MAX_VALUE, 1));
    5045        maxConcurrentDownloads = new JSpinner(new SpinnerNumberModel(
    5146                TMSCachedTileLoaderJob.THREAD_LIMIT.get().intValue(), 0, Integer.MAX_VALUE, 1));
    5247        maxDownloadsPerHost = new JSpinner(new SpinnerNumberModel(
    5348                TMSCachedTileLoader.HOST_LIMIT.get().intValue(), 0, Integer.MAX_VALUE, 1));
     49
    5450
    5551        add(new JLabel(tr("Auto zoom by default: ")), GBC.std());
     
    7369        add(addToSlippyMapChosser, GBC.eol().fill(GBC.HORIZONTAL));
    7470
    75         add(new JLabel(tr("Tile cache directory: ")), GBC.std());
    76         add(GBC.glue(5, 0), GBC.std());
    77         add(tilecacheDir, GBC.eol().fill(GBC.HORIZONTAL));
    78 
    7971        add(new JLabel(tr("Maximum concurrent downloads: ")), GBC.std());
    8072        add(GBC.glue(5, 0), GBC.std());
     
    8476        add(GBC.glue(5, 0), GBC.std());
    8577        add(maxDownloadsPerHost, GBC.eol());
    86 
    87 
    88         add(new JLabel(tr("Maximum elements in disk cache: ")), GBC.std());
    89         add(GBC.glue(5, 0), GBC.std());
    90         add(this.maxElementsOnDisk, GBC.eol());
    9178
    9279    }
     
    10188        this.maxZoomLvl.setValue(TMSLayer.getMaxZoomLvl(null));
    10289        this.minZoomLvl.setValue(TMSLayer.getMinZoomLvl(null));
    103         this.tilecacheDir.setText(CachedTileLoaderFactory.PROP_TILECACHE_DIR.get());
    104         this.maxElementsOnDisk.setValue(TMSCachedTileLoader.MAX_OBJECTS_ON_DISK.get());
    10590        this.maxConcurrentDownloads.setValue(TMSCachedTileLoaderJob.THREAD_LIMIT.get());
    10691        this.maxDownloadsPerHost.setValue(TMSCachedTileLoader.HOST_LIMIT.get());
     
    11499        boolean restartRequired = false;
    115100
    116         if (TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get() != this.addToSlippyMapChosser.isSelected()) {
     101        if (!TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get().equals(this.addToSlippyMapChosser.isSelected())) {
    117102            restartRequired = true;
    118103        }
     
    122107        TMSLayer.setMaxZoomLvl((Integer) this.maxZoomLvl.getValue());
    123108        TMSLayer.setMinZoomLvl((Integer) this.minZoomLvl.getValue());
    124 
    125         if (!TMSCachedTileLoader.MAX_OBJECTS_ON_DISK.get().equals(this.maxElementsOnDisk.getValue())) {
    126             TMSCachedTileLoader.MAX_OBJECTS_ON_DISK.put((Integer) this.maxElementsOnDisk.getValue());
    127             restartRequired = true;
    128         }
    129109
    130110        if (!TMSCachedTileLoader.THREAD_LIMIT.get().equals(this.maxConcurrentDownloads.getValue())) {
     
    138118        }
    139119
    140         if (!CachedTileLoaderFactory.PROP_TILECACHE_DIR.get().equals(this.tilecacheDir.getText())) {
    141             restartRequired = true;
    142             CachedTileLoaderFactory.PROP_TILECACHE_DIR.put(this.tilecacheDir.getText());
    143         }
    144 
    145120        return restartRequired;
    146121    }
  • trunk/test/unit/org/openstreetmap/josm/data/imagery/WMTSTileSourceTest.java

    r8586 r8598  
    8989        verifyBounds(wallonieBounds, testSource, 6, 1063, 1219);
    9090        verifyBounds(wallonieBounds, testSource, 11, 17724, 20324);
    91         LatLon ll = new LatLon(testSource.tileXYToLatLon(1063, 1219, 6));
    92 
     91    }
     92
     93    @Test
     94    public void testWALLONIENoMatrixDimension() throws MalformedURLException, IOException {
     95        Main.setProjection(Projections.getProjectionByCode("EPSG:31370"));
     96        WMTSTileSource testSource = new WMTSTileSource(getImagery("test/data/wmts/WMTSCapabilities-Wallonie-nomatrixdimension.xml"));
     97        Bounds wallonieBounds = new Bounds(
     98                new LatLon(49.485372459967245, 2.840548314430268),
     99                new LatLon(50.820959517561256, 6.427849693016202)
     100                );
     101
     102        verifyBounds(wallonieBounds, testSource, 6, 1063, 1219);
     103        verifyBounds(wallonieBounds, testSource, 11, 17724, 20324);
    93104    }
    94105
Note: See TracChangeset for help on using the changeset viewer.