001 /* 002 * Copyright (C) 2008-2010 by Holger Arndt 003 * 004 * This file is part of the Universal Java Matrix Package (UJMP). 005 * See the NOTICE file distributed with this work for additional 006 * information regarding copyright ownership and licensing. 007 * 008 * UJMP is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation; either version 2 011 * of the License, or (at your option) any later version. 012 * 013 * UJMP is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU Lesser General Public License for more details. 017 * 018 * You should have received a copy of the GNU Lesser General Public 019 * License along with UJMP; if not, write to the 020 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 021 * Boston, MA 02110-1301 USA 022 */ 023 024 package org.ujmp.ehcache; 025 026 import java.io.Closeable; 027 import java.io.File; 028 import java.io.Flushable; 029 import java.io.IOException; 030 import java.util.HashSet; 031 import java.util.Set; 032 033 import net.sf.ehcache.Cache; 034 import net.sf.ehcache.CacheManager; 035 import net.sf.ehcache.Element; 036 import net.sf.ehcache.bootstrap.BootstrapCacheLoader; 037 import net.sf.ehcache.config.CacheConfiguration; 038 import net.sf.ehcache.config.Configuration; 039 import net.sf.ehcache.config.DiskStoreConfiguration; 040 import net.sf.ehcache.event.RegisteredEventListeners; 041 import net.sf.ehcache.store.MemoryStoreEvictionPolicy; 042 043 import org.ujmp.core.collections.AbstractMap; 044 import org.ujmp.core.interfaces.Erasable; 045 046 public class EhcacheMap<K, V> extends AbstractMap<K, V> implements Erasable, 047 Flushable, Closeable { 048 private static final long serialVersionUID = -2405059234958626645L; 049 050 private int maxElementsInMemory = 1000; 051 052 private final int maxElementsOnDisk = Integer.MAX_VALUE - 1; 053 054 private boolean overflowToDisk = true; 055 056 private final boolean eternal = true; 057 058 private final boolean diskPersistent = true; 059 060 private transient File diskStorePath = null; 061 062 private transient String name = null; 063 064 private transient final RegisteredEventListeners registeredEventListeners = null; 065 066 private final int timeToLiveSeconds = Integer.MAX_VALUE - 1; 067 068 private final int timeToIdleSeconds = 120; 069 070 private final int diskSpoolBufferSizeMB = 16; 071 072 private final int diskExpiryThreadIntervalSeconds = 300; 073 074 private final MemoryStoreEvictionPolicy memoryStoreEvictionPolicy = MemoryStoreEvictionPolicy.LFU; 075 076 private transient CacheManager manager = null; 077 078 private transient Cache cache = null; 079 080 private static long runningId = System.currentTimeMillis(); 081 082 private final BootstrapCacheLoader bootstrapCacheLoader = null; 083 084 public EhcacheMap() throws IOException { 085 this(null); 086 } 087 088 public EhcacheMap(String name) throws IOException { 089 this(name, null, true); 090 } 091 092 public EhcacheMap(boolean overFlowToDisk) throws IOException { 093 this(null, null, overFlowToDisk); 094 } 095 096 public EhcacheMap(String name, boolean overFlowToDisk) throws IOException { 097 this(name, null, overFlowToDisk); 098 } 099 100 public EhcacheMap(String name, File path, boolean overFlowToDisk) 101 throws IOException { 102 runningId++; 103 System.setProperty("net.sf.ehcache.enableShutdownHook", "true"); 104 this.diskStorePath = path; 105 this.overflowToDisk = overFlowToDisk; 106 this.name = name; 107 } 108 109 public boolean isOverflowToDisk() { 110 return overflowToDisk; 111 } 112 113 public void setOverflowToDisk(boolean overflowToDisk) { 114 this.overflowToDisk = overflowToDisk; 115 } 116 117 public String getName() { 118 if (name == null) { 119 name = "ehcache" + runningId; 120 } 121 return name; 122 } 123 124 public int getMaxElementsInMemory() { 125 return maxElementsInMemory; 126 } 127 128 public void setMaxElementsInMemory(int maxElementsInMemory) { 129 this.maxElementsInMemory = maxElementsInMemory; 130 } 131 132 public File getPath() { 133 if (diskStorePath == null) { 134 try { 135 diskStorePath = File.createTempFile(getName(), ".tmp"); 136 diskStorePath.delete(); 137 diskStorePath.mkdir(); 138 new File(diskStorePath + System.getProperty("file.separator") 139 + getName() + ".data").deleteOnExit(); 140 new File(diskStorePath + System.getProperty("file.separator") 141 + getName() + ".index").deleteOnExit(); 142 } catch (Exception e) { 143 e.printStackTrace(); 144 throw new RuntimeException(e); 145 } 146 } 147 return diskStorePath; 148 } 149 150 private CacheManager getCacheManager() { 151 if (manager == null) { 152 Configuration config = new Configuration(); 153 CacheConfiguration cacheconfig = new CacheConfiguration(getName(), 154 maxElementsInMemory); 155 cacheconfig 156 .setDiskExpiryThreadIntervalSeconds(diskExpiryThreadIntervalSeconds); 157 cacheconfig.setDiskPersistent(diskPersistent); 158 cacheconfig.setEternal(eternal); 159 cacheconfig.setMaxElementsOnDisk(maxElementsOnDisk); 160 cacheconfig 161 .setMemoryStoreEvictionPolicyFromObject(memoryStoreEvictionPolicy); 162 cacheconfig.setOverflowToDisk(overflowToDisk); 163 cacheconfig.setTimeToIdleSeconds(timeToIdleSeconds); 164 cacheconfig.setTimeToLiveSeconds(timeToLiveSeconds); 165 166 DiskStoreConfiguration diskStoreConfigurationParameter = new DiskStoreConfiguration(); 167 diskStoreConfigurationParameter 168 .setPath(getPath().getAbsolutePath()); 169 config.addDiskStore(diskStoreConfigurationParameter); 170 config.setDefaultCacheConfiguration(cacheconfig); 171 manager = new CacheManager(config); 172 } 173 return manager; 174 } 175 176 private Cache getCache() { 177 if (cache == null) { 178 Cache c = new Cache(getName(), maxElementsInMemory, 179 memoryStoreEvictionPolicy, overflowToDisk, getPath() 180 .getAbsolutePath(), eternal, timeToLiveSeconds, 181 timeToIdleSeconds, diskPersistent, 182 diskExpiryThreadIntervalSeconds, registeredEventListeners, 183 bootstrapCacheLoader, maxElementsOnDisk, 184 diskSpoolBufferSizeMB); 185 getCacheManager().addCache(c); 186 cache = getCacheManager().getCache(getName()); 187 } 188 return cache; 189 } 190 191 public void clear() { 192 getCache().removeAll(); 193 getCache().flush(); 194 } 195 196 public boolean containsKey(Object key) { 197 return getCache().isKeyInCache(key); 198 } 199 200 public boolean containsValue(Object value) { 201 return getCache().isValueInCache(value); 202 } 203 204 @SuppressWarnings("unchecked") 205 public synchronized V get(Object key) { 206 Element e = getCache().get(key); 207 if (e != null) { 208 return (V) e.getValue(); 209 } else { 210 return null; 211 } 212 } 213 214 @SuppressWarnings("unchecked") 215 public Set<K> keySet() { 216 return new HashSet<K>(getCache().getKeys()); 217 } 218 219 public synchronized V put(K key, V value) { 220 Element e = new Element(key, value); 221 getCache().put(e); 222 return null; 223 } 224 225 public synchronized V remove(Object key) { 226 getCache().remove(key); 227 return null; 228 } 229 230 public int size() { 231 return getCache().getSize(); 232 } 233 234 public void finalize() { 235 try { 236 erase(); 237 } catch (IOException e) { 238 } 239 } 240 241 public void erase() throws IOException { 242 close(); 243 getCacheManager().shutdown(); 244 } 245 246 public void flush() throws IOException { 247 getCache().flush(); 248 } 249 250 public void close() throws IOException { 251 getCacheManager().removeCache(getCache().getName()); 252 } 253 }