source: josm/trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java@ 8526

Last change on this file since 8526 was 8526, checked in by wiktorn, 9 years ago

Introduce WMS layer based on TMS. (closes: #11255)

HEADS UP: After this patch you need to manually remove JAX-B generated file/class: org/w3/_2001/xmlschema/Adapter1.java to compile the tree again.

  • create AbstractTileSourceLayer based on TMSLayer as a base for TMS, WMS and (future) WMTS layers, (addresses #11459)
  • WMS layer now uses JCS Caching (closes: #7363)
  • introduce new conversion methods in TileSource, that convert both X and Y (lat and lon) in one call. This is necessary for other than PseudoMercator projections
    • introduce TileXY class that represents X and Y indexes of tile in tile matrix/space
    • mark old conversion methods as deprecated
    • refactor JMapViewer and JOSM to new methods
    • change use of Coordinate class to ICoordinate where appropiate
  • extract CachedAttributionBingAerialTileSource to separate file
  • create TemplatedWMSTileSource that provides the WMS Layer with square (according to current projection) tiles (closes: #11572, closes: #7682, addresses: #5454)
  • implemented precaching imagery along GPX track for AbstractTileSourceLayer, so now it work for both - WMS and TMS (closes: #9154)
  • implemented common righ-click menu on map view, as well on layer list (closes #3591)
  • create separate build commands for JMapViewer classes to easily spot, when josm classes are used within JMapViewer
  • remove unnecessary classes of previous WMS implementation - GeorefImage, wms-cache.xsd (and JAXB task from build), WMSCache, WMSRequest, WMSGrabber, HTMLGrabber, WMSException
File size: 6.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.imagery;
3
4import java.io.IOException;
5import java.util.Map;
6import java.util.concurrent.ThreadPoolExecutor;
7import java.util.concurrent.TimeUnit;
8
9import org.apache.commons.jcs.access.behavior.ICacheAccess;
10import org.openstreetmap.gui.jmapviewer.Tile;
11import org.openstreetmap.gui.jmapviewer.interfaces.CachedTileLoader;
12import org.openstreetmap.gui.jmapviewer.interfaces.TileCache;
13import org.openstreetmap.gui.jmapviewer.interfaces.TileJob;
14import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
15import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
16import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
17import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
18import org.openstreetmap.josm.data.cache.HostLimitQueue;
19import org.openstreetmap.josm.data.cache.JCSCacheManager;
20import org.openstreetmap.josm.data.cache.JCSCachedTileLoaderJob;
21import org.openstreetmap.josm.data.preferences.IntegerProperty;
22
23/**
24 * @author Wiktor Niesiobędzki
25 *
26 * Wrapper class that bridges between JCS cache and Tile Loaders
27 *
28 */
29public class TMSCachedTileLoader implements TileLoader, CachedTileLoader, TileCache {
30
31 protected final ICacheAccess<String, BufferedImageCacheEntry> cache;
32 protected final int connectTimeout;
33 protected final int readTimeout;
34 protected final Map<String, String> headers;
35 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);
42
43 /**
44 * overrides the THREAD_LIMIT in superclass, as we want to have separate limit and pool for TMS
45 */
46 public static final IntegerProperty THREAD_LIMIT = new IntegerProperty("imagery.tms.tmsloader.maxjobs", 25);
47
48 /**
49 * Limit definition for per host concurrent connections
50 */
51 public static final IntegerProperty HOST_LIMIT = new IntegerProperty("imagery.tms.tmsloader.maxjobsperhost", 6);
52
53 /**
54 * separate from JCS thread pool for TMS loader, so we can have different thread pools for default JCS
55 * and for TMS imagery
56 */
57 private static ThreadPoolExecutor DEFAULT_DOWNLOAD_JOB_DISPATCHER = getNewThreadPoolExecutor("TMS downloader");
58
59 private ThreadPoolExecutor downloadExecutor = DEFAULT_DOWNLOAD_JOB_DISPATCHER;
60
61 /**
62 * Constructor
63 * @param listener called when tile loading has finished
64 * @param name of the cache
65 * @param connectTimeout to remote resource
66 * @param readTimeout to remote resource
67 * @param headers HTTP headers to be sent along with request
68 * @param cacheDir where cache file shall reside
69 * @throws IOException when cache initialization fails
70 */
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);
77 this.connectTimeout = connectTimeout;
78 this.readTimeout = readTimeout;
79 this.headers = headers;
80 this.listener = listener;
81 }
82
83 /**
84 * @param name name of the threads
85 * @param workers number of worker thread to keep
86 * @return new ThreadPoolExecutor that will use a @see HostLimitQueue based queue
87 */
88 public static ThreadPoolExecutor getNewThreadPoolExecutor(String name, int workers) {
89 return new ThreadPoolExecutor(
90 workers, // keep the thread number constant
91 workers, // do not this number of threads
92 30, // keepalive for thread
93 TimeUnit.SECONDS,
94 new HostLimitQueue(HOST_LIMIT.get().intValue()),
95 JCSCachedTileLoaderJob.getNamedThreadFactory(name)
96 );
97 }
98
99 /**
100 * @param name name of threads
101 * @return new ThreadPoolExecutor that will use a @see HostLimitQueue based queue, with default number of threads
102 */
103 public static ThreadPoolExecutor getNewThreadPoolExecutor(String name) {
104 return getNewThreadPoolExecutor(name, THREAD_LIMIT.get().intValue());
105 }
106
107 @Override
108 public TileJob createTileLoaderJob(Tile tile) {
109 return new TMSCachedTileLoaderJob(listener, tile, cache,
110 connectTimeout, readTimeout, headers, getDownloadExecutor());
111 }
112
113 @Override
114 public void clearCache(TileSource source) {
115 this.cache.clear();
116 }
117
118 @Override
119 public Tile getTile(TileSource source, int x, int y, int z) {
120 return createTileLoaderJob(new Tile(source, x, y, z)).getTile();
121 }
122
123 @Override
124 public void addTile(Tile tile) {
125 createTileLoaderJob(tile).getTile();
126 }
127
128 @Override
129 public int getTileCount() {
130 return 0;
131 }
132
133 @Override
134 public void clear() {
135 cache.clear();
136 }
137
138 /**
139 * @return cache statistics as string
140 */
141 public String getStats() {
142 return cache.getStats();
143 }
144
145 /**
146 * cancels all outstanding tasks in the queue. This rollbacks the state of the tiles in the queue
147 * to loading = false / loaded = false
148 */
149 public void cancelOutstandingTasks() {
150 for (Runnable r: downloadExecutor.getQueue()) {
151 if (downloadExecutor.remove(r) && r instanceof TMSCachedTileLoaderJob) {
152 ((TMSCachedTileLoaderJob) r).handleJobCancellation();
153 }
154 }
155 }
156
157 /**
158 * Sets the download executor that will be used to download tiles instead of default one.
159 * You can use {@link #getNewThreadPoolExecutor} to create a new download executor with separate
160 * queue from default.
161 *
162 * @param downloadExecutor
163 */
164 public void setDownloadExecutor(ThreadPoolExecutor downloadExecutor) {
165 this.downloadExecutor = downloadExecutor;
166 }
167
168 /**
169 * @return download executor that is used by this factory
170 */
171 public ThreadPoolExecutor getDownloadExecutor() {
172 return downloadExecutor;
173 }
174
175}
Note: See TracBrowser for help on using the repository browser.