Ticket #11216: jcs-cache-v1.patch
File jcs-cache-v1.patch, 27.3 KB (added by , 9 years ago) |
---|
-
build.xml
220 220 destdir="build" target="1.7" source="1.7" debug="on" includeantruntime="false" createMissingPackageInfoClass="false" encoding="iso-8859-1"> 221 221 <!-- get rid of "internal proprietary API" warning --> 222 222 <compilerarg value="-XDignore.symbol.file"/> 223 <exclude name="org/apache/commons/jcs/admin/**"/> 224 <exclude name="org/apache/commons/jcs/auxiliary/disk/jdbc/**"/> 225 <exclude name="org/apache/commons/jcs/auxiliary/remote/**"/> 226 <exclude name="org/apache/commons/jcs/utils/servlet/**"/> 227 <exclude name="org/apache/commons/logging/impl/AvalonLogger.java"/> 228 <exclude name="org/apache/commons/logging/impl/Log4JLogger.java"/> 229 <exclude name="org/apache/commons/logging/impl/LogKitLogger.java"/> 230 <exclude name="org/apache/commons/logging/impl/ServletContextCleaner.java"/> 223 231 </javac> 224 232 <!-- JMapViewer/JOSM --> 225 233 <javac srcdir="${src.dir}" excludes="com/**,oauth/**,org/apache/commons/**,org/glassfish/**,org/openstreetmap/gui/jmapviewer/Demo.java" … … 581 589 </java> 582 590 </target> 583 591 </project> 592 -
src/org/apache/commons
-
src/org/openstreetmap/gui/jmapviewer/OsmFileCacheTileLoader.java
Property changes on: src/org/apache/commons ___________________________________________________________________ Modified: svn:externals ## -1 +1,3 ## -codec http://svn.apache.org/repos/asf/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec +http://svn.apache.org/repos/asf/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec codec +http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs jcs +http://svn.apache.org/repos/asf/commons/proper/logging/trunk/src/main/java/org/apache/commons/logging logging
1 1 // License: GPL. For details, see Readme.txt file. 2 2 package org.openstreetmap.gui.jmapviewer; 3 3 4 import java.io.BufferedReader;5 4 import java.io.ByteArrayInputStream; 6 5 import java.io.ByteArrayOutputStream; 7 6 import java.io.File; 8 import java.io.FileInputStream;9 import java.io.FileNotFoundException;10 import java.io.FileOutputStream;11 7 import java.io.IOException; 12 8 import java.io.InputStream; 13 import java.io.InputStreamReader;14 import java.io.OutputStreamWriter;15 import java.io.PrintWriter;16 9 import java.net.HttpURLConnection; 17 10 import java.net.URL; 18 11 import java.net.URLConnection; 19 12 import java.nio.charset.Charset; 20 import java.util.HashMap;21 import java.util.Map;22 import java.util.Map.Entry;23 13 import java.util.Random; 24 14 import java.util.logging.Level; 25 15 import java.util.logging.Logger; 26 16 17 import org.apache.commons.jcs.access.behavior.ICacheAccess; 18 import org.apache.commons.jcs.engine.behavior.ICacheElement; 19 import org.apache.commons.jcs.engine.behavior.IElementAttributes; 27 20 import org.openstreetmap.gui.jmapviewer.interfaces.CachedTileLoader; 28 21 import org.openstreetmap.gui.jmapviewer.interfaces.TileClearController; 29 22 import org.openstreetmap.gui.jmapviewer.interfaces.TileJob; … … 31 24 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; 32 25 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; 33 26 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource.TileUpdate; 27 import org.openstreetmap.josm.data.imagery.cache.CacheEntry; 28 import org.openstreetmap.josm.data.imagery.cache.CacheEntryAttributes; 29 import org.openstreetmap.josm.data.imagery.cache.TileCacheManager; 34 30 35 31 /** 36 32 * A {@link TileLoader} implementation that loads tiles from OSM via HTTP and … … 57 53 // even if the refresh from the server fails. 58 54 protected static final long ABSOLUTE_EXPIRE_TIME_LIMIT = Long.MAX_VALUE; // unlimited 59 55 60 protected String cacheDirBase; 61 62 protected final Map<TileSource, File> sourceCacheDirMap; 56 protected ICacheAccess<String, CacheEntry> cache; 63 57 64 58 65 59 public static File getDefaultCacheDir() throws SecurityException { … … 70 64 } catch (SecurityException e) { 71 65 log.log(Level.WARNING, 72 66 "Failed to access system property ''java.io.tmpdir'' for security reasons. Exception was: " 73 + e.toString());67 + e.toString()); 74 68 throw e; // rethrow 75 69 } 76 70 try { … … 97 91 */ 98 92 public OsmFileCacheTileLoader(TileLoaderListener map, File cacheDir) throws IOException { 99 93 super(map); 100 if (cacheDir == null || (!cacheDir.exists() && !cacheDir.mkdirs())) 101 throw new IOException("Cannot access cache directory"); 102 103 log.finest("Tile cache directory: " + cacheDir); 104 cacheDirBase = cacheDir.getAbsolutePath(); 105 sourceCacheDirMap = new HashMap<>(); 94 cache = TileCacheManager.getCache("TMS"); 106 95 } 107 96 108 97 /** … … 119 108 return new FileLoadJob(tile); 120 109 } 121 110 122 protected File getSourceCacheDir(TileSource source) {123 File dir = sourceCacheDirMap.get(source);124 if (dir == null) {125 dir = new File(cacheDirBase, source.getName().replaceAll("[\\\\/:*?\"<>|]", "_"));126 if (!dir.exists()) {127 dir.mkdirs();128 }129 }130 return dir;131 }132 133 111 protected class FileLoadJob implements TileJob { 134 112 InputStream input = null; 135 113 136 114 Tile tile; 137 File tileCacheDir; 138 File tileFile = null; 139 File tagsFile = null; 140 Long fileMtime = null; 115 ICacheElement<String, CacheEntry> element; 116 CacheEntryAttributes elementAttributes; 141 117 Long now = null; // current time in milliseconds (keep consistent value for the whole run) 142 118 143 119 public FileLoadJob(Tile tile) { … … 159 135 tile.loading = true; 160 136 } 161 137 now = System.currentTimeMillis(); 162 tileCacheDir = getSourceCacheDir(tile.getSource());163 tileFile = getTileFile();164 tagsFile = getTagsFile();165 138 166 loadTagsFromFile(); 139 element = cache.getCacheElement(tile.getKey()); 140 elementAttributes = getCacheEntryAttributes(element); 167 141 168 142 if (isCacheValid() && (isNoTileAtZoom() || loadTileFromFile())) { 169 143 log.log(Level.FINE, "TMS - found in tile cache: {0}", tile); … … 204 178 protected boolean loadOrUpdateTile() { 205 179 try { 206 180 URLConnection urlConn = loadTileFromOsm(tile); 207 if (fileMtime != null && now - fileMtime <= ABSOLUTE_EXPIRE_TIME_LIMIT) { 181 182 if (now - elementAttributes.getLastModification() <= ABSOLUTE_EXPIRE_TIME_LIMIT) { 208 183 switch (tile.getSource().getTileUpdate()) { 209 184 case IfModifiedSince: 210 urlConn.setIfModifiedSince( fileMtime);185 urlConn.setIfModifiedSince(elementAttributes.getLastModification()); 211 186 break; 212 187 case LastModified: 213 if (!isOsmTileNewer( fileMtime)) {188 if (!isOsmTileNewer(elementAttributes.getLastModification())) { 214 189 log.log(Level.FINE, "TMS - LastModified test: local version is up to date: {0}", tile); 215 tileFile.setLastModified(now);190 elementAttributes.setLastModification(now); 216 191 return true; 217 192 } 218 193 break; … … 221 196 } 222 197 } 223 198 if (tile.getSource().getTileUpdate() == TileUpdate.ETag || tile.getSource().getTileUpdate() == TileUpdate.IfNoneMatch) { 224 String fileETag = tile.getValue("etag");199 String fileETag = elementAttributes.getEtag(); 225 200 if (fileETag != null) { 226 201 switch (tile.getSource().getTileUpdate()) { 227 202 case IfNoneMatch: … … 230 205 case ETag: 231 206 if (hasOsmTileETag(fileETag)) { 232 207 log.log(Level.FINE, "TMS - ETag test: local version is up to date: {0}", tile); 233 tileFile.setLastModified(now);208 elementAttributes.setLastModification(now); 234 209 return true; 235 210 } 236 211 default: 237 212 break; 238 213 } 239 214 } 240 tile.putValue("etag",urlConn.getHeaderField("ETag"));215 elementAttributes.setEtag(urlConn.getHeaderField("ETag")); 241 216 } 242 217 if (urlConn instanceof HttpURLConnection && ((HttpURLConnection)urlConn).getResponseCode() == 304) { 243 218 // If isModifiedSince or If-None-Match has been set … … 253 228 break; 254 229 } 255 230 loadTileFromFile(); 256 tileFile.setLastModified(now);231 elementAttributes.setLastModification(now); 257 232 return true; 258 233 } 259 234 260 235 loadTileMetadata(tile, urlConn); 261 saveTagsToFile();262 236 263 if ( "no-tile".equals(tile.getValue("tile-info")))237 if (elementAttributes.isNoTileAtZoom()) 264 238 { 265 239 log.log(Level.FINE, "TMS - No tile: tile-info=no-tile: {0}", tile); 266 240 tile.setError("No tile at this zoom level"); 241 cache.put(tile.getKey(), new CacheEntry(new byte[]{}), elementAttributes); 267 242 return true; 268 243 } else { 269 244 for (int i = 0; i < 5; ++i) { … … 274 249 byte[] buffer = loadTileInBuffer(urlConn); 275 250 if (buffer != null) { 276 251 tile.loadImage(new ByteArrayInputStream(buffer)); 277 saveTileToFile(buffer);252 cache.put(tile.getKey(), new CacheEntry(buffer), elementAttributes); 278 253 log.log(Level.FINE, "TMS - downloaded tile from server: {0}", tile.getUrl()); 279 254 return true; 280 255 } … … 294 269 return false; 295 270 } 296 271 272 273 private void loadTileMetadata(Tile tile, URLConnection urlConn) { 274 elementAttributes.setNoTileAtZoom("no-tile".equals(urlConn.getHeaderField("X-VE-Tile-Info"))); 275 276 Long lng = urlConn.getExpiration(); 277 if (lng.equals(0L)) { 278 try { 279 String str = urlConn.getHeaderField("Cache-Control"); 280 if (str != null) { 281 for (String token: str.split(",")) { 282 if (token.startsWith("max-age=")) { 283 lng = Long.parseLong(token.substring(8)) * 1000 + 284 System.currentTimeMillis(); 285 } 286 } 287 } 288 } catch (NumberFormatException e) {} //ignore malformed Cache-Control headers 289 } 290 291 elementAttributes.setExpirationTime(lng); 292 } 293 294 private final CacheEntryAttributes getCacheEntryAttributes(ICacheElement e) { 295 if (e != null) { 296 IElementAttributes ea = e.getElementAttributes(); 297 return (CacheEntryAttributes) ea; 298 } else { 299 CacheEntryAttributes ret = new CacheEntryAttributes(); 300 ret.setLastModification(now); 301 ret.setExpirationTime(now + DEFAULT_EXPIRE_TIME); 302 return ret; 303 } 304 } 305 297 306 protected boolean isCacheValid() { 298 Long expires = null; 299 if (tileFile.exists()) { 300 fileMtime = tileFile.lastModified(); 301 } else if (tagsFile.exists()) { 302 fileMtime = tagsFile.lastModified(); 303 } else 307 if (element == null) 304 308 return false; 305 309 306 try { 307 expires = Long.parseLong(tile.getValue("expires")); 308 } catch (NumberFormatException e) {} 310 long expires = elementAttributes.getExpirationTime(); 309 311 310 312 // check by expire date set by server 311 if (expires != null && !expires.equals(0L)) {313 if (expires != 0L) { 312 314 // put a limit to the expire time (some servers send a value 313 315 // that is too large) 314 expires = Math.min(expires, fileMtime+ EXPIRE_TIME_SERVER_LIMIT);316 expires = Math.min(expires, elementAttributes.getCreateTime() + EXPIRE_TIME_SERVER_LIMIT); 315 317 if (now > expires) { 316 log.log(Level.FINE, "TMS - Tile has expired -> not valid {0}", tile);318 log.log(Level.FINE, "TMS - Tile has expired ({0})-> not valid {1}", new Object[]{Long.toString(expires), tile}); 317 319 return false; 318 320 } 319 321 } else { 320 322 // check by file modification date 321 if (now - fileMtime> DEFAULT_EXPIRE_TIME) {323 if (now - elementAttributes.getLastModification() > DEFAULT_EXPIRE_TIME) { 322 324 log.log(Level.FINE, "TMS - Tile has expired, maximum file age reached {0}", tile); 323 325 return false; 324 326 } … … 327 329 } 328 330 329 331 protected boolean isNoTileAtZoom() { 330 if ( "no-tile".equals(tile.getValue("tile-info"))) {332 if (elementAttributes.isNoTileAtZoom()) { 331 333 // do not remove file - keep the information, that there is no tile, for further requests 332 334 // the code above will check, if this information is still valid 333 335 log.log(Level.FINE, "TMS - Tile valid, but no file, as no tiles at this level {0}", tile); … … 338 340 } 339 341 340 342 protected boolean loadTileFromFile() { 341 if (!tileFile.exists()) 342 return false; 343 344 try (FileInputStream fin = new FileInputStream(tileFile)) { 343 try (InputStream fin = new ByteArrayInputStream(element.getVal().getContent())) { 345 344 if (fin.available() == 0) 346 345 throw new IOException("File empty"); 347 346 tile.loadImage(fin); 348 347 return true; 349 348 } catch (Exception e) { 350 349 log.log(Level.WARNING, "TMS - Error while loading image from tile cache: {0}; {1}", new Object[]{e.getMessage(), tile}); 351 tileFile.delete();352 if (tagsFile.exists()) {353 tagsFile.delete();354 }355 tileFile = null;356 fileMtime = null;357 350 } 358 351 return false; 359 352 } … … 428 421 return true; 429 422 return (osmETag.equals(eTag)); 430 423 } 431 432 protected File getTileFile() {433 return new File(tileCacheDir + "/" + tile.getZoom() + "_" + tile.getXtile() + "_" + tile.getYtile() + "."434 + tile.getSource().getTileType());435 }436 437 protected File getTagsFile() {438 return new File(tileCacheDir + "/" + tile.getZoom() + "_" + tile.getXtile() + "_" + tile.getYtile() + "."439 + TAGS_FILE_EXT);440 }441 442 protected void saveTileToFile(byte[] rawData) {443 File file = getTileFile();444 file.getParentFile().mkdirs();445 try (FileOutputStream f = new FileOutputStream(file)) {446 f.write(rawData);447 } catch (Exception e) {448 log.log(Level.SEVERE, "Failed to save tile content: {0}", e.getLocalizedMessage());449 }450 }451 452 protected void saveTagsToFile() {453 File tagsFile = getTagsFile();454 tagsFile.getParentFile().mkdirs();455 if (tile.getMetadata() == null) {456 tagsFile.delete();457 return;458 }459 try (PrintWriter f = new PrintWriter(new OutputStreamWriter(new FileOutputStream(tagsFile), TAGS_CHARSET))) {460 for (Entry<String, String> entry : tile.getMetadata().entrySet()) {461 f.println(entry.getKey() + "=" + entry.getValue());462 }463 } catch (Exception e) {464 System.err.println("Failed to save tile tags: " + e.getLocalizedMessage());465 }466 }467 468 protected boolean loadTagsFromFile() {469 File tagsFile = getTagsFile();470 try (BufferedReader f = new BufferedReader(new InputStreamReader(new FileInputStream(tagsFile), TAGS_CHARSET))) {471 for (String line = f.readLine(); line != null; line = f.readLine()) {472 final int i = line.indexOf('=');473 if (i == -1 || i == 0) {474 System.err.println("Malformed tile tag in file '" + tagsFile.getName() + "':" + line);475 continue;476 }477 tile.putValue(line.substring(0,i),line.substring(i+1));478 }479 } catch (FileNotFoundException e) {480 } catch (Exception e) {481 System.err.println("Failed to load tile tags: " + e.getLocalizedMessage());482 }483 484 return true;485 }486 424 } 487 425 488 public String getCacheDirBase() {489 return cacheDirBase;490 }491 426 492 public void setTileCacheDir(String tileCacheDir) {493 File dir = new File(tileCacheDir);494 dir.mkdirs();495 this.cacheDirBase = dir.getAbsolutePath();496 }497 427 498 428 @Override 499 429 public void clearCache(TileSource source) { … … 502 432 503 433 @Override 504 434 public void clearCache(TileSource source, TileClearController controller) { 505 File dir = getSourceCacheDir(source); 506 if (dir != null) { 507 if (controller != null) controller.initClearDir(dir); 508 if (dir.isDirectory()) { 509 File[] files = dir.listFiles(); 510 if (controller != null) controller.initClearFiles(files); 511 for (File file : files) { 512 if (controller != null && controller.cancel()) return; 513 file.delete(); 514 if (controller != null) controller.fileDeleted(file); 515 } 516 } 517 dir.delete(); 518 } 435 cache.clear(); 519 436 if (controller != null) controller.clearFinished(); 520 437 } 521 438 } -
src/org/openstreetmap/gui/jmapviewer/TMSFileCacheTileLoader.java
3 3 4 4 import java.io.File; 5 5 import java.io.IOException; 6 6 7 import org.openstreetmap.gui.jmapviewer.interfaces.TileJob; 7 8 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; 8 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;9 9 10 10 /** 11 11 * Reworked version of the OsmFileCacheTileLoader. … … 30 30 super(tile); 31 31 } 32 32 33 @Override34 protected File getTileFile() {35 return getDataFile(tile.getSource().getTileType());36 }37 38 @Override39 protected File getTagsFile() {40 return getDataFile(TAGS_FILE_EXT);41 }42 43 protected File getDataFile(String ext) {44 int nDigits = (int) Math.ceil(Math.log10(1 << tile.getZoom()));45 String x = String.format("%0" + nDigits + "d", tile.getXtile());46 String y = String.format("%0" + nDigits + "d", tile.getYtile());47 File path = new File(tileCacheDir, "z" + tile.getZoom());48 for (int i=0; i<nDigits; i++) {49 String component = "x" + x.substring(i, i+1) + "y" + y.substring(i, i+1);50 if (i == nDigits -1 ) {51 component += "." + ext;52 }53 path = new File(path, component);54 }55 return path;56 }57 }58 33 59 @Override60 protected File getSourceCacheDir(TileSource source) {61 File dir = sourceCacheDirMap.get(source);62 if (dir == null) {63 String id = source.getId();64 if (id != null) {65 dir = new File(cacheDirBase, id);66 } else {67 dir = new File(cacheDirBase, source.getName().replaceAll("[\\\\/:*?\"<>|]", "_"));68 }69 if (!dir.exists()) {70 dir.mkdirs();71 }72 }73 return dir;74 34 } 75 76 35 } -
src/org/openstreetmap/josm/data/imagery/cache/CacheEntry.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.imagery.cache; 3 4 import java.io.Serializable; 5 6 public class CacheEntry implements Serializable { 7 private static final long serialVersionUID = 1L; //version 8 private byte[] content; 9 10 public CacheEntry(byte[] content) { 11 this.content = content; 12 } 13 14 public byte[] getContent() { 15 return content; 16 } 17 } -
src/org/openstreetmap/josm/data/imagery/cache/CacheEntryAttributes.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.imagery.cache; 3 4 import org.apache.commons.jcs.engine.ElementAttributes; 5 6 public class CacheEntryAttributes extends ElementAttributes { 7 private boolean noTileAtZoom = false; 8 private String Etag = null; 9 private long lastModification = 0; 10 private long expirationTime = 0; 11 12 13 public boolean isNoTileAtZoom() { 14 return noTileAtZoom; 15 } 16 public void setNoTileAtZoom(boolean noTileAtZoom) { 17 this.noTileAtZoom = noTileAtZoom; 18 } 19 public String getEtag() { 20 return Etag; 21 } 22 public void setEtag(String etag) { 23 Etag = etag; 24 } 25 public long getLastModification() { 26 return lastModification; 27 } 28 public void setLastModification(long lastModification) { 29 this.lastModification = lastModification; 30 } 31 public long getExpirationTime() { 32 return expirationTime; 33 } 34 public void setExpirationTime(long expirationTime) { 35 this.expirationTime = expirationTime; 36 } 37 38 } -
src/org/openstreetmap/josm/data/imagery/cache/TileCacheManager.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.imagery.cache; 3 4 import java.io.File; 5 import java.io.IOException; 6 import java.util.Properties; 7 8 import org.apache.commons.jcs.access.CacheAccess; 9 import org.apache.commons.jcs.access.behavior.ICacheAccess; 10 import org.apache.commons.jcs.engine.control.CompositeCache; 11 import org.apache.commons.jcs.engine.control.CompositeCacheManager; 12 import org.openstreetmap.josm.Main; 13 14 public abstract class TileCacheManager { 15 16 private static volatile CompositeCacheManager cacheManager = null; 17 private static long maxObjectTTL = 1000L * 60 * 60 * 24 * 31; // 31 days 18 19 // average tile size is about 20kb 20 // 1000 is around 20MB under this assumptions 21 private static long maxObjectsInMemory = 1000; 22 private static long maxObjectsOnDisk = 100000; 23 24 private static void initialize() throws IOException { 25 File cacheDir = new File(Main.pref.getCacheDirectory(), "jcs"); 26 27 if ((!cacheDir.exists() && !cacheDir.mkdirs())) 28 throw new IOException("Cannot access cache directory"); 29 30 CompositeCacheManager cm = CompositeCacheManager.getUnconfiguredInstance(); 31 Properties props = new Properties(); 32 props.setProperty("jcs.default", "DC"); 33 props.setProperty("jcs.default.cacheattributes", org.apache.commons.jcs.engine.CompositeCacheAttributes.class.getCanonicalName()); 34 props.setProperty("jcs.default.cacheattributes.MaxObjects", Long.toString(maxObjectsInMemory)); 35 props.setProperty("jcs.default.cacheattributes.UseMemoryShrinker", "true"); 36 props.setProperty("jcs.default.cacheattributes.DiskUsagePatternName", "UPDATE"); // store elements on disk on put 37 props.setProperty("jcs.default.elementattributes", CacheEntryAttributes.class.getCanonicalName()); 38 props.setProperty("jcs.default.elementattributes.IsEternal", "false"); 39 props.setProperty("jcs.default.elementattributes.MaxLife", Long.toString(maxObjectTTL)); 40 props.setProperty("jcs.default.elementattributes.IdleTime", Long.toString(maxObjectTTL)); 41 props.setProperty("jcs.default.elementattributes.IsSpool", "true"); 42 43 props.setProperty("jcs.auxiliary.DC", org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheFactory.class.getCanonicalName()); 44 props.setProperty("jcs.auxiliary.DC.attributes", org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheAttributes.class.getCanonicalName()); 45 props.setProperty("jcs.auxiliary.DC.attributes.DiskPath", cacheDir.getAbsolutePath()); 46 props.setProperty("jcs.auxiliary.DC.attributes.maxKeySize", Long.toString(maxObjectsOnDisk)); 47 props.setProperty("jcs.auxiliary.DC.attributes.blockSizeBytes", "1024"); 48 49 50 cm.configure(props); 51 cacheManager = cm; 52 } 53 54 public static ICacheAccess<String, CacheEntry> getCache(String cacheName) throws IOException { 55 if (cacheManager != null) 56 return getCacheInner(cacheName); 57 58 synchronized (TileCacheManager.class) { 59 if (cacheManager == null) 60 initialize(); 61 return getCacheInner(cacheName); 62 } 63 } 64 65 private static ICacheAccess<String, CacheEntry> getCacheInner(String cacheName) { 66 CompositeCache<String, CacheEntry> cc = cacheManager.getCache(cacheName); 67 return new CacheAccess<String, CacheEntry>(cc); 68 } 69 70 }