// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui.layer; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.jcs.access.CacheAccess; import org.apache.commons.jcs.access.behavior.ICacheAccess; import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry; import org.openstreetmap.josm.data.cache.JCSCacheManager; import org.openstreetmap.josm.data.imagery.CachedTileLoaderFactory; import org.openstreetmap.josm.data.imagery.ImageryInfo; import org.openstreetmap.josm.data.imagery.TileLoaderFactory; import org.openstreetmap.josm.data.preferences.IntegerProperty; /** * * Class providing cache to other layers * * @author Wiktor Niesiobędzki * @param <T> Tile Source class used by this Imagery Layer * */ public abstract class AbstractCachedTileSourceLayer<T extends AbstractTMSTileSource> extends AbstractTileSourceLayer<T> { /** loader factory responsible for loading tiles for all layers */ private static Map<String, TileLoaderFactory> loaderFactories = new ConcurrentHashMap<>(); private static final String PREFERENCE_PREFIX = "imagery.cache."; private static volatile TileLoaderFactory loaderFactoryOverride; /** * how many object on disk should be stored for TMS region in MB. 500 MB is default value */ public static final IntegerProperty MAX_DISK_CACHE_SIZE = new IntegerProperty(PREFERENCE_PREFIX + "max_disk_size", 512); private ICacheAccess<String, BufferedImageCacheEntry> cache; private volatile TileLoaderFactory loaderFactory; /** * Creates an instance of class based on InageryInfo * * @param info ImageryInfo describing the layer */ public AbstractCachedTileSourceLayer(ImageryInfo info) { super(info); if (loaderFactoryOverride != null) { loaderFactory = loaderFactoryOverride; } else { String key = this.getClass().getCanonicalName(); loaderFactory = loaderFactories.get(key); if (loaderFactory == null) { synchronized (AbstractCachedTileSourceLayer.class) { // check again, maybe another thread initialized factory loaderFactory = loaderFactories.get(key); if (loaderFactory == null) { loaderFactory = new CachedTileLoaderFactory(getCache(), getTileLoaderClass()); loaderFactories.put(key, loaderFactory); } } } } } @Override protected synchronized TileLoaderFactory getTileLoaderFactory() { if (loaderFactory == null) { loaderFactory = new CachedTileLoaderFactory(getCache(), getTileLoaderClass()); } return loaderFactory; } /** * @return cache used by this layer */ private synchronized ICacheAccess<String, BufferedImageCacheEntry> getCache() { if (cache != null) { return cache; } try { cache = JCSCacheManager.getCache(getCacheName(), 0, getDiskCacheSize(), CachedTileLoaderFactory.PROP_TILECACHE_DIR.get()); return cache; } catch (IOException e) { Main.warn(e); return null; } } /** * Plugins that wish to set custom tile loader should call this method * @param newLoaderFactory that will be used to load tiles */ public static synchronized void setTileLoaderFactory(TileLoaderFactory newLoaderFactory) { loaderFactoryOverride = newLoaderFactory; } /** * Returns tile loader factory for cache region and specified TileLoader class * @param name of the cache region * @param klazz type of the TileLoader * @return factory returning cached tile loaders using specified cache and TileLoaders */ public static TileLoaderFactory getTileLoaderFactory(String name, Class<? extends TileLoader> klazz) { CacheAccess<String, BufferedImageCacheEntry> cache = getCache(name); if (cache == null) { return null; } return new CachedTileLoaderFactory(cache, klazz); } /** * @param name of cache region * @return cache configured object for specified cache region */ public static CacheAccess<String, BufferedImageCacheEntry> getCache(String name) { try { return JCSCacheManager.getCache(name, 0, MAX_DISK_CACHE_SIZE.get() * 1024, // MAX_DISK_CACHE_SIZE is in MB, needs to by in sync with getDiskCacheSize CachedTileLoaderFactory.PROP_TILECACHE_DIR.get()); } catch (IOException e) { Main.warn(e); return null; } } protected abstract Class<? extends TileLoader> getTileLoaderClass(); protected int getDiskCacheSize() { return MAX_DISK_CACHE_SIZE.get() * 1024; } protected abstract String getCacheName(); }