001/*
002 * Stallion Core: A Modern Web Framework
003 *
004 * Copyright (C) 2015 - 2016 Stallion Software LLC.
005 *
006 * This program is free software: you can redistribute it and/or modify it under the terms of the
007 * GNU General Public License as published by the Free Software Foundation, either version 2 of
008 * the License, or (at your option) any later version. This program is distributed in the hope that
009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
011 * License for more details. You should have received a copy of the GNU General Public License
012 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
013 *
014 *
015 *
016 */
017
018package io.stallion.services;
019
020import net.sf.ehcache.Cache;
021import net.sf.ehcache.CacheManager;
022import net.sf.ehcache.Ehcache;
023import net.sf.ehcache.Element;
024import net.sf.ehcache.config.CacheConfiguration;
025import net.sf.ehcache.config.Configuration;
026import net.sf.ehcache.config.PersistenceConfiguration;
027
028import java.util.Timer;
029import java.util.TimerTask;
030
031import static io.stallion.utils.Literals.*;
032import static io.stallion.Context.*;
033
034
035public class LocalMemoryCache {
036    private static CacheManager manager;
037    private static TimerTask evictThread;
038    private static Timer evictThreadTimer;
039
040
041
042    public static void start() {
043        if (manager == null) {
044            load();
045        }
046
047        // Every 5 minutes, evict all expired elements from the cache so they do not build up over time
048        evictThread = new TimerTask() {
049            public void run() {
050                Thread.currentThread().setName("stallion-ehcache-evict-task");
051                if (manager == null) {
052                    return;
053                }
054                for(String name: manager.getCacheNames()) {
055                    manager.getCache(name).evictExpiredElements();
056                }
057            }
058        };
059
060        evictThreadTimer = new Timer("stallion-ehcache-evict-timer");
061        evictThreadTimer.scheduleAtFixedRate(evictThread, 0, 5 * 60 * 1000);
062    }
063
064    public static void shutdown() {
065
066        if (evictThreadTimer != null) {
067            evictThreadTimer.cancel();
068            evictThreadTimer = null;
069        }
070        if (evictThread != null) {
071            evictThread.cancel();
072            evictThread = null;
073        }
074        if (manager != null) {
075            manager.shutdown();
076            manager = null;
077        }
078    }
079
080    public static void load() {
081
082        Configuration config = new Configuration();
083        config.setName("stallionLocalMemoryCache");
084        manager = CacheManager.create();
085    }
086
087    public static void initCache(String bucket) {
088        if (manager == null) {
089            load();
090        }
091        if (manager.getCache(bucket) != null) {
092            return;
093        }
094        synchronized(manager) {
095            if (manager.getCache(bucket) != null) {
096                return;
097            }
098            CacheConfiguration config = new CacheConfiguration();
099            config.setName(bucket);
100            // We have to do this way because there is no way to programmatically configure the
101            // sizeOfEngine
102            System.setProperty("net.sf.ehcache.sizeofengine.stallionLocalMemoryCache." + bucket, "io.stallion.dataAccess.filtering.EstimatedSizeOfEngine");
103
104            // Max cache size is 100MB
105            config.setMaxBytesLocalHeap(100 * 1000 * 1000L);
106            //config.setDiskPersistent(false);
107            //config.setMaxElementsOnDisk(0);
108            //config.setMaxBytesLocalDisk(0L);
109            config.setOverflowToOffHeap(false);
110            PersistenceConfiguration persistenceConfiguration = new PersistenceConfiguration();
111            persistenceConfiguration.strategy(PersistenceConfiguration.Strategy.NONE);
112            config.persistence(persistenceConfiguration);
113            manager.addCache(new Cache(config));
114        }
115    }
116
117    public static Object get(String key) {
118        return get("default", key);
119    }
120
121    public static Object get(String bucket, String key) {
122        bucket = or(bucket, "default");
123        if (manager == null) {
124            return null;
125        }
126        if (!manager.cacheExists(bucket)) {
127            return null;
128        }
129        Element element = manager.getCache(bucket).get(key);
130        if (element != null) {
131            return element.getObjectValue();
132        }
133        return null;
134    }
135    public static void set(String key, Object value, int timeoutSeconds) {
136        set("default", key, value, timeoutSeconds);
137    }
138    public static void set(String bucket, String key, Object value) {
139        set(bucket, key, value, 15);
140    }
141    public static void set(String bucket, String key, Object value, int timeoutSeconds) {
142        bucket = or(bucket, "default");
143        if (manager == null) {
144            load();
145        }
146        if (!manager.cacheExists(bucket)) {
147            initCache(bucket);
148        }
149        Element element = new Element(key, value);
150        element.setTimeToLive(timeoutSeconds);
151        manager.getCache(bucket).put(element);
152    }
153
154    public static void clearBucket(String bucket) {
155        if (manager.cacheExists(bucket) && manager.getCache(bucket).getSize() > 0) {
156            manager.getCache(bucket).removeAll();
157        }
158    }
159
160}