001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.imagery.vectortile.mapbox;
003
004import java.util.concurrent.ThreadPoolExecutor;
005
006import org.openstreetmap.gui.jmapviewer.Tile;
007import org.openstreetmap.gui.jmapviewer.interfaces.CachedTileLoader;
008import org.openstreetmap.gui.jmapviewer.interfaces.TileJob;
009import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
010import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
011import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
012import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
013import org.openstreetmap.josm.data.cache.JCSCachedTileLoaderJob;
014import org.openstreetmap.josm.data.imagery.TMSCachedTileLoader;
015import org.openstreetmap.josm.data.imagery.TileJobOptions;
016import org.openstreetmap.josm.data.preferences.IntegerProperty;
017import org.openstreetmap.josm.tools.CheckParameterUtil;
018
019import org.apache.commons.jcs3.access.behavior.ICacheAccess;
020
021/**
022 * A TileLoader class for MVT tiles
023 * @author Taylor Smock
024 * @since 17862
025 */
026public class MapboxVectorCachedTileLoader implements TileLoader, CachedTileLoader {
027    protected final ICacheAccess<String, BufferedImageCacheEntry> cache;
028    protected final TileLoaderListener listener;
029    protected final TileJobOptions options;
030    private static final IntegerProperty THREAD_LIMIT =
031            new IntegerProperty("imagery.vector.mvtloader.maxjobs", TMSCachedTileLoader.THREAD_LIMIT.getDefaultValue());
032    private static final ThreadPoolExecutor DEFAULT_DOWNLOAD_JOB_DISPATCHER =
033            TMSCachedTileLoader.getNewThreadPoolExecutor("MVT-downloader-%d", THREAD_LIMIT.get());
034
035    /**
036     * Constructor
037     * @param listener          called when tile loading has finished
038     * @param cache             of the cache
039     * @param options           tile job options
040     */
041    public MapboxVectorCachedTileLoader(TileLoaderListener listener, ICacheAccess<String, BufferedImageCacheEntry> cache,
042                                        TileJobOptions options) {
043        CheckParameterUtil.ensureParameterNotNull(cache, "cache");
044        this.cache = cache;
045        this.options = options;
046        this.listener = listener;
047    }
048
049    @Override
050    public void clearCache(TileSource source) {
051        this.cache.remove(source.getName() + ':');
052    }
053
054    @Override
055    public TileJob createTileLoaderJob(Tile tile) {
056        return new MapboxVectorCachedTileLoaderJob(
057                listener,
058                tile,
059                cache,
060                options,
061                getDownloadExecutor());
062    }
063
064    @Override
065    public void cancelOutstandingTasks() {
066        final ThreadPoolExecutor executor = getDownloadExecutor();
067        executor.getQueue().stream().filter(executor::remove).filter(MapboxVectorCachedTileLoaderJob.class::isInstance)
068                .map(MapboxVectorCachedTileLoaderJob.class::cast).forEach(JCSCachedTileLoaderJob::handleJobCancellation);
069    }
070
071    @Override
072    public boolean hasOutstandingTasks() {
073        return getDownloadExecutor().getTaskCount() > getDownloadExecutor().getCompletedTaskCount();
074    }
075
076    private static ThreadPoolExecutor getDownloadExecutor() {
077        return DEFAULT_DOWNLOAD_JOB_DISPATCHER;
078    }
079}