001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.layer; 003 004import java.util.Map; 005import java.util.concurrent.ConcurrentHashMap; 006 007import org.apache.commons.jcs.access.CacheAccess; 008import org.apache.commons.jcs.access.behavior.ICacheAccess; 009import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; 010import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource; 011import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry; 012import org.openstreetmap.josm.data.cache.JCSCacheManager; 013import org.openstreetmap.josm.data.imagery.CachedTileLoaderFactory; 014import org.openstreetmap.josm.data.imagery.ImageryInfo; 015import org.openstreetmap.josm.data.imagery.TileLoaderFactory; 016import org.openstreetmap.josm.data.preferences.IntegerProperty; 017 018/** 019 * 020 * Class providing cache to other layers 021 * 022 * @author Wiktor Niesiobędzki 023 * @param <T> Tile Source class used by this Imagery Layer 024 * 025 */ 026public abstract class AbstractCachedTileSourceLayer<T extends AbstractTMSTileSource> extends AbstractTileSourceLayer<T> { 027 /** loader factory responsible for loading tiles for all layers */ 028 private static Map<String, TileLoaderFactory> loaderFactories = new ConcurrentHashMap<>(); 029 030 private static final String PREFERENCE_PREFIX = "imagery.cache."; 031 032 private static volatile TileLoaderFactory loaderFactoryOverride; 033 034 /** 035 * how many object on disk should be stored for TMS region in MB. 500 MB is default value 036 */ 037 public static final IntegerProperty MAX_DISK_CACHE_SIZE = new IntegerProperty(PREFERENCE_PREFIX + "max_disk_size", 512); 038 039 private ICacheAccess<String, BufferedImageCacheEntry> cache; 040 private volatile TileLoaderFactory loaderFactory; 041 042 /** 043 * Creates an instance of class based on InageryInfo 044 * 045 * @param info ImageryInfo describing the layer 046 */ 047 public AbstractCachedTileSourceLayer(ImageryInfo info) { 048 super(info); 049 050 if (loaderFactoryOverride != null) { 051 loaderFactory = loaderFactoryOverride; 052 } else { 053 String key = this.getClass().getCanonicalName(); 054 loaderFactory = loaderFactories.get(key); 055 if (loaderFactory == null) { 056 synchronized (AbstractCachedTileSourceLayer.class) { 057 // check again, maybe another thread initialized factory 058 loaderFactory = loaderFactories.get(key); 059 if (loaderFactory == null) { 060 loaderFactory = new CachedTileLoaderFactory(getCache(), getTileLoaderClass()); 061 loaderFactories.put(key, loaderFactory); 062 } 063 } 064 } 065 } 066 } 067 068 @Override 069 protected synchronized TileLoaderFactory getTileLoaderFactory() { 070 if (loaderFactory == null) { 071 loaderFactory = new CachedTileLoaderFactory(getCache(), getTileLoaderClass()); 072 } 073 return loaderFactory; 074 } 075 076 /** 077 * @return cache used by this layer 078 */ 079 private synchronized ICacheAccess<String, BufferedImageCacheEntry> getCache() { 080 if (cache != null) { 081 return cache; 082 } 083 cache = JCSCacheManager.getCache(getCacheName(), 084 0, 085 getDiskCacheSize(), 086 CachedTileLoaderFactory.PROP_TILECACHE_DIR.get()); 087 return cache; 088 } 089 090 /** 091 * Plugins that wish to set custom tile loader should call this method 092 * @param newLoaderFactory that will be used to load tiles 093 */ 094 095 public static synchronized void setTileLoaderFactory(TileLoaderFactory newLoaderFactory) { 096 loaderFactoryOverride = newLoaderFactory; 097 } 098 099 /** 100 * Returns tile loader factory for cache region and specified TileLoader class 101 * @param name of the cache region 102 * @param klazz type of the TileLoader 103 * @return factory returning cached tile loaders using specified cache and TileLoaders 104 */ 105 public static TileLoaderFactory getTileLoaderFactory(String name, Class<? extends TileLoader> klazz) { 106 CacheAccess<String, BufferedImageCacheEntry> cache = getCache(name); 107 if (cache == null) { 108 return null; 109 } 110 return new CachedTileLoaderFactory(cache, klazz); 111 } 112 113 /** 114 * @param name of cache region 115 * @return cache configured object for specified cache region 116 */ 117 public static CacheAccess<String, BufferedImageCacheEntry> getCache(String name) { 118 return JCSCacheManager.getCache(name, 119 0, 120 MAX_DISK_CACHE_SIZE.get() * 1024, // MAX_DISK_CACHE_SIZE is in MB, needs to by in sync with getDiskCacheSize 121 CachedTileLoaderFactory.PROP_TILECACHE_DIR.get()); 122 } 123 124 protected abstract Class<? extends TileLoader> getTileLoaderClass(); 125 126 protected int getDiskCacheSize() { 127 return MAX_DISK_CACHE_SIZE.get() * 1024; 128 } 129 130 protected abstract String getCacheName(); 131}