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    }