[8168] | 1 | // License: GPL. For details, see LICENSE file.
|
---|
| 2 | package org.openstreetmap.josm.data.imagery;
|
---|
| 3 |
|
---|
| 4 | import java.util.Map;
|
---|
[8397] | 5 | import java.util.concurrent.ThreadPoolExecutor;
|
---|
| 6 | import java.util.concurrent.TimeUnit;
|
---|
[8168] | 7 |
|
---|
| 8 | import org.apache.commons.jcs.access.behavior.ICacheAccess;
|
---|
| 9 | import org.openstreetmap.gui.jmapviewer.Tile;
|
---|
| 10 | import org.openstreetmap.gui.jmapviewer.interfaces.CachedTileLoader;
|
---|
| 11 | import org.openstreetmap.gui.jmapviewer.interfaces.TileJob;
|
---|
| 12 | import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
|
---|
| 13 | import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
|
---|
| 14 | import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
|
---|
| 15 | import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
|
---|
[8403] | 16 | import org.openstreetmap.josm.data.cache.HostLimitQueue;
|
---|
[8168] | 17 | import org.openstreetmap.josm.data.preferences.IntegerProperty;
|
---|
[10877] | 18 | import org.openstreetmap.josm.tools.CheckParameterUtil;
|
---|
[8602] | 19 | import org.openstreetmap.josm.tools.Utils;
|
---|
[8168] | 20 |
|
---|
| 21 | /**
|
---|
| 22 | * Wrapper class that bridges between JCS cache and Tile Loaders
|
---|
| 23 | *
|
---|
[10723] | 24 | * @author Wiktor Niesiobędzki
|
---|
[8168] | 25 | */
|
---|
[9004] | 26 | public class TMSCachedTileLoader implements TileLoader, CachedTileLoader {
|
---|
[8168] | 27 |
|
---|
[8526] | 28 | protected final ICacheAccess<String, BufferedImageCacheEntry> cache;
|
---|
| 29 | protected final int connectTimeout;
|
---|
| 30 | protected final int readTimeout;
|
---|
| 31 | protected final Map<String, String> headers;
|
---|
| 32 | protected final TileLoaderListener listener;
|
---|
[8459] | 33 |
|
---|
[8403] | 34 | /**
|
---|
[8598] | 35 | * overrides the THREAD_LIMIT in superclass, as we want to have separate limit and pool for TMS
|
---|
[8403] | 36 | */
|
---|
[8168] | 37 |
|
---|
[8397] | 38 | public static final IntegerProperty THREAD_LIMIT = new IntegerProperty("imagery.tms.tmsloader.maxjobs", 25);
|
---|
[8168] | 39 |
|
---|
| 40 | /**
|
---|
[8403] | 41 | * Limit definition for per host concurrent connections
|
---|
| 42 | */
|
---|
| 43 | public static final IntegerProperty HOST_LIMIT = new IntegerProperty("imagery.tms.tmsloader.maxjobsperhost", 6);
|
---|
| 44 |
|
---|
| 45 | /**
|
---|
[8397] | 46 | * separate from JCS thread pool for TMS loader, so we can have different thread pools for default JCS
|
---|
| 47 | * and for TMS imagery
|
---|
| 48 | */
|
---|
[8734] | 49 | private static ThreadPoolExecutor DEFAULT_DOWNLOAD_JOB_DISPATCHER = getNewThreadPoolExecutor("TMS-downloader-%d");
|
---|
[8397] | 50 |
|
---|
[8598] | 51 |
|
---|
[8526] | 52 | private ThreadPoolExecutor downloadExecutor = DEFAULT_DOWNLOAD_JOB_DISPATCHER;
|
---|
[8459] | 53 |
|
---|
[8397] | 54 | /**
|
---|
[8168] | 55 | * Constructor
|
---|
| 56 | * @param listener called when tile loading has finished
|
---|
[8598] | 57 | * @param cache of the cache
|
---|
[8168] | 58 | * @param connectTimeout to remote resource
|
---|
| 59 | * @param readTimeout to remote resource
|
---|
[8459] | 60 | * @param headers HTTP headers to be sent along with request
|
---|
[8168] | 61 | */
|
---|
[8598] | 62 | public TMSCachedTileLoader(TileLoaderListener listener, ICacheAccess<String, BufferedImageCacheEntry> cache,
|
---|
[11453] | 63 | int connectTimeout, int readTimeout, Map<String, String> headers) {
|
---|
[10877] | 64 | CheckParameterUtil.ensureParameterNotNull(cache, "cache");
|
---|
[8598] | 65 | this.cache = cache;
|
---|
[8168] | 66 | this.connectTimeout = connectTimeout;
|
---|
| 67 | this.readTimeout = readTimeout;
|
---|
| 68 | this.headers = headers;
|
---|
| 69 | this.listener = listener;
|
---|
| 70 | }
|
---|
| 71 |
|
---|
[8526] | 72 | /**
|
---|
[8734] | 73 | * @param nameFormat see {@link Utils#newThreadFactory(String, int)}
|
---|
[8526] | 74 | * @param workers number of worker thread to keep
|
---|
| 75 | * @return new ThreadPoolExecutor that will use a @see HostLimitQueue based queue
|
---|
| 76 | */
|
---|
[8734] | 77 | public static ThreadPoolExecutor getNewThreadPoolExecutor(String nameFormat, int workers) {
|
---|
[11438] | 78 | HostLimitQueue workQueue = new HostLimitQueue(HOST_LIMIT.get().intValue());
|
---|
| 79 | ThreadPoolExecutor executor = new ThreadPoolExecutor(
|
---|
| 80 | 0, // 0 so for unused thread pools threads will eventually die, freeing also the threadpool
|
---|
[8526] | 81 | workers, // do not this number of threads
|
---|
[11438] | 82 | 300, // keepalive for thread
|
---|
[8526] | 83 | TimeUnit.SECONDS,
|
---|
[11438] | 84 | workQueue,
|
---|
[8734] | 85 | Utils.newThreadFactory(nameFormat, Thread.NORM_PRIORITY)
|
---|
[8526] | 86 | );
|
---|
[11438] | 87 | workQueue.setExecutor(executor);
|
---|
| 88 | return executor;
|
---|
[8526] | 89 | }
|
---|
| 90 |
|
---|
| 91 | /**
|
---|
| 92 | * @param name name of threads
|
---|
| 93 | * @return new ThreadPoolExecutor that will use a @see HostLimitQueue based queue, with default number of threads
|
---|
| 94 | */
|
---|
| 95 | public static ThreadPoolExecutor getNewThreadPoolExecutor(String name) {
|
---|
| 96 | return getNewThreadPoolExecutor(name, THREAD_LIMIT.get().intValue());
|
---|
| 97 | }
|
---|
| 98 |
|
---|
[8168] | 99 | @Override
|
---|
| 100 | public TileJob createTileLoaderJob(Tile tile) {
|
---|
[8397] | 101 | return new TMSCachedTileLoaderJob(listener, tile, cache,
|
---|
[8526] | 102 | connectTimeout, readTimeout, headers, getDownloadExecutor());
|
---|
[8168] | 103 | }
|
---|
| 104 |
|
---|
| 105 | @Override
|
---|
[8186] | 106 | public void clearCache(TileSource source) {
|
---|
[8846] | 107 | this.cache.remove(source.getName() + ':');
|
---|
[8168] | 108 | }
|
---|
| 109 |
|
---|
[8397] | 110 | /**
|
---|
| 111 | * @return cache statistics as string
|
---|
| 112 | */
|
---|
[8168] | 113 | public String getStats() {
|
---|
| 114 | return cache.getStats();
|
---|
| 115 | }
|
---|
[8397] | 116 |
|
---|
| 117 | /**
|
---|
| 118 | * cancels all outstanding tasks in the queue. This rollbacks the state of the tiles in the queue
|
---|
| 119 | * to loading = false / loaded = false
|
---|
| 120 | */
|
---|
[8737] | 121 | @Override
|
---|
[8397] | 122 | public void cancelOutstandingTasks() {
|
---|
[8510] | 123 | for (Runnable r: downloadExecutor.getQueue()) {
|
---|
[8403] | 124 | if (downloadExecutor.remove(r) && r instanceof TMSCachedTileLoaderJob) {
|
---|
[8510] | 125 | ((TMSCachedTileLoaderJob) r).handleJobCancellation();
|
---|
[8397] | 126 | }
|
---|
| 127 | }
|
---|
| 128 | }
|
---|
[8526] | 129 |
|
---|
| 130 | /**
|
---|
| 131 | * Sets the download executor that will be used to download tiles instead of default one.
|
---|
| 132 | * You can use {@link #getNewThreadPoolExecutor} to create a new download executor with separate
|
---|
| 133 | * queue from default.
|
---|
| 134 | *
|
---|
[8530] | 135 | * @param downloadExecutor download executor that will be used to download tiles
|
---|
[8526] | 136 | */
|
---|
| 137 | public void setDownloadExecutor(ThreadPoolExecutor downloadExecutor) {
|
---|
| 138 | this.downloadExecutor = downloadExecutor;
|
---|
| 139 | }
|
---|
| 140 |
|
---|
| 141 | /**
|
---|
| 142 | * @return download executor that is used by this factory
|
---|
| 143 | */
|
---|
| 144 | public ThreadPoolExecutor getDownloadExecutor() {
|
---|
| 145 | return downloadExecutor;
|
---|
| 146 | }
|
---|
[8168] | 147 | }
|
---|