001/* 
002 * JKNIV, utils - Helper utilities for jdk code.
003 * 
004 * Copyright (C) 2017, the original author or authors.
005 *
006 * This library is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 2.1 of the License.
010 * 
011 * This library is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 * 
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with this library; if not, write to the Free Software Foundation, Inc., 
018 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
019 */
020package net.sf.jkniv.cache;
021
022import java.util.concurrent.TimeUnit;
023
024import org.slf4j.Logger;
025import org.slf4j.LoggerFactory;
026
027import net.sf.jkniv.asserts.Assertable;
028import net.sf.jkniv.asserts.AssertsFactory;
029
030/*
031
032 no expiry    - this means cache mappings will never expire,
033 time-to-live - this means cache mappings will expire after a fixed duration following their creation,
034 time-to-idle - this means cache mappings will expire after a fixed duration following the time they were last accessed.
035
036 */
037/**
038 * Cache policy using concepts from Time to live (TTL) to limit the lifetime of data.
039 * 
040 * @author Alisson Gomes
041 * @since 0.6.0
042 */
043public class TTLCachePolicy implements CachePolicy
044{
045    private static final Logger LOG = LoggerFactory.getLogger(TTLCachePolicy.class);
046    private static final Assertable notNull = AssertsFactory.getNotNull();
047
048    private final static long KB_FACTOR = 1000;
049    private final static long KIB_FACTOR = 1024;
050    private final static long MB_FACTOR = 1000 * KB_FACTOR;
051    private final static long MIB_FACTOR = 1024 * KIB_FACTOR;
052    private final static long GB_FACTOR = 1000 * MB_FACTOR;
053    private final static long GIB_FACTOR = 1024 * MIB_FACTOR;
054    
055    
056        //private long timestamp;
057    private long ttl;   // time-to-live
058    private long tti;   // time-to-idle
059    private long size;
060    private long sizeof;
061    
062    /**
063     * Build a policy with TTL as parameter to keep the objects alive in cache
064     * @param ttl time in seconds
065     */
066    public TTLCachePolicy(long ttl)
067    {
068        this(ttl, DEFAULT_TTI);
069    }
070    
071    /**
072     * Build a policy with TTL and TTI as parameter to keep the objects alive in cache
073     * @param ttl time-to-live in seconds
074     * @param tti time-to-idle in seconds
075     */
076    public TTLCachePolicy(long ttl, long tti)
077    {
078        this(ttl, tti, TimeUnit.SECONDS);
079    }
080
081    /**
082     * Build a policy with TTL and TTI as parameter to keep the objects alive in cache
083     * @param ttl time-to-live in seconds
084     * @param tti time-to-idle in seconds
085     * @param unit time unit for TTL and TTI
086     */
087    public TTLCachePolicy(long ttl, long tti, TimeUnit unit)
088    {
089        this(ttl, tti, unit, DEFAULT_SIZE, DEFAULT_SIZEOF+"");
090    }
091
092    /**
093     * Build a policy with TTL and TTI as parameter to keep the objects alive in cache
094     * @param ttl time-to-live in seconds
095     * @param tti time-to-idle in seconds
096     * @param size limit for number of object
097     * @param sizeof limit for size for sum of objects
098     */
099    public TTLCachePolicy(long ttl, long tti, long size, String sizeof)
100    {
101        this(ttl, tti, TimeUnit.SECONDS, size, sizeof);
102    }
103    /**
104     * Build a policy with TTL and TTI as parameter to keep the objects alive in cache
105     * @param ttl time-to-live in seconds
106     * @param tti time-to-idle in seconds
107     * @param unit time unit for TTL and TTI
108     * @param size limit for number of object
109     * @param sizeof limit for size for sum of objects
110     */
111    public TTLCachePolicy(long ttl, long tti, TimeUnit unit, long size, String sizeof)
112    {
113        notNull.verify(unit, sizeof);
114        this.ttl = unit.toMillis(ttl);
115        this.tti = unit.toMillis(tti);
116        this.size = size;
117        this.sizeof = toBytes(sizeof);
118    }
119
120    @Override
121    public boolean isAlive(long ttl)
122    {
123        if (this.ttl < 0)
124            return true;
125
126        return !expireTTL(ttl);
127    }
128    
129    @Override
130    public boolean isAlive(long ttl, long tti)
131    {
132        if (this.ttl < 0)
133            return true;
134        
135        if (expireTTL(ttl))
136            return false;
137
138        if (this.tti < 0)
139            return true;
140
141        if (expireTTI(tti))
142            return false;
143        
144        return true;
145    }
146    
147    private boolean expireTTL(long ttl)
148    {
149        boolean ret = ((ttl + this.ttl) <= System.currentTimeMillis());
150        if(LOG.isDebugEnabled())
151            LOG.debug("Cache Expire TTL[{}] timestamp data [{}] current [{}] resting = {} => {}", (ttl + this.ttl), ttl, System.currentTimeMillis(), (System.currentTimeMillis()-(ttl + this.ttl)), ret);
152        return ret;
153    }
154    
155    private boolean expireTTI(long tti)
156    {
157        boolean ret = ((tti + this.tti) <= System.currentTimeMillis());
158        if(LOG.isDebugEnabled())
159            LOG.debug("Cache Expire TTI[{}] timestamp data [{}] current [{}] resting = {} => {}", (tti + this.tti), tti, System.currentTimeMillis(), (System.currentTimeMillis()-(tti + this.tti)), ret);
160        return ret;
161    }
162    
163    // FIXME implements limit from CachePolicy
164    @Override
165    public long size()
166    {
167        return this.size;
168    }
169    
170    // FIXME implements sizeof from CachePolicy
171    @Override
172    public long sizeof()
173    {
174        return this.sizeof;
175    }
176
177    @Override
178    public String toString()
179    {
180        return "TTLCachePolicy [ttl=" + ttl + ", tti=" + tti + ", size=" + size + ", sizeof=" + sizeof + "]";
181    }
182    
183
184    /**
185     * 
186     * @param sizeof <size>[g|G|m|M|k|K]
187     * @return
188     */
189    private long toBytes(String sizeof) 
190    {
191        long bytes = -1L; // without sizeof limits
192        String sizeofNormalized = (sizeof != null ? sizeof.toLowerCase() : "");
193        String sizeofNumber = (sizeof.length() > 1 ? sizeof.substring(0, sizeof.length()-1) : "");
194        if (sizeofNormalized.endsWith("k"))
195            bytes = KIB_FACTOR * Long.valueOf(sizeofNumber);
196        else if (sizeofNormalized.endsWith("m"))
197            bytes = MIB_FACTOR * Long.valueOf(sizeofNumber);
198        else if (sizeofNormalized.endsWith("g"))
199            bytes = GIB_FACTOR * Long.valueOf(sizeofNumber);
200        else if (sizeofNormalized.length() > 0)
201            bytes = Long.valueOf(sizeofNormalized);
202        
203        return bytes;
204    }
205}