Roberto Sánchez
2014-01-21 d7a35d13cd691e6821f774b624e4203a404e67d9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package net.curisit.securis.utils;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * Cache implementation with TTL (time To Live) The objects are removed from cache when TTL is reached.
 * 
 * @author roberto <roberto.sanchez@curisit.net>
 */
@Singleton
public class CacheTTL {
   private static final Logger log = LoggerFactory.getLogger(CacheTTL.class);
   /**
    * Period before token expires, set in seconds.
    */
   private static int DEFAULT_CACHE_DURATION = 24 * 60 * 60;
   private Map<String, CachedObject> data = new HashMap<>();
   private Thread cleaningThread = null;
   @Inject
   public CacheTTL() {
       cleaningThread = new Thread(new Runnable() {
           @Override
           public void run() {
               while (CacheTTL.this.data != null) {
                   try {
                       // We check for expired object every 60 seconds
                       Thread.sleep(60 * 1000);
                   } catch (InterruptedException e) {
                       log.error("Exiting from Cache Thread");
                       data.clear();
                       return;
                   }
                   // log.info("Cheking expired objects " + new Date());
                   Date now = new Date();
                   List<String> keysToRemove = new ArrayList<>();
                   for (String key : CacheTTL.this.data.keySet()) {
                       CachedObject co = CacheTTL.this.data.get(key);
                       if (now.after(co.getExpireAt())) {
                           keysToRemove.add(key);
                       }
                   }
                   for (String key : keysToRemove) {
                       // If we try to remove directly in the previous loop an exception is thrown java.util.ConcurrentModificationException
                       CacheTTL.this.data.remove(key);
                   }
               }
           }
       });
       cleaningThread.start();
   }
   /**
    * 
    * @param key
    * @param obj
    * @param ttl
    *            Time To Live in seconds
    */
   public void set(String key, Object obj, int ttl) {
       Date expirationDate = new Date(new Date().getTime() + ttl * 1000);
       data.put(key, new CachedObject(expirationDate, obj));
   }
   public void set(String key, Object obj) {
       set(key, obj, DEFAULT_CACHE_DURATION);
   }
   public Object get(String key) {
       CachedObject co = data.get(key);
       return co == null ? null : co.getObject();
   }
   public <T> T get(String key, Class<T> type) {
       CachedObject co = data.get(key);
       return co == null ? null : co.getObject(type);
   }
   public <T> T remove(String key, Class<T> type) {
       CachedObject co = data.remove(key);
       return co == null ? null : co.getObject(type);
   }
   public Object remove(String key) {
       CachedObject co = data.remove(key);
       return co == null ? null : co.getObject();
   }
   public void clear() {
       data.clear();
   }
   private class CachedObject {
       Date expireAt;
       Object object;
       public CachedObject(Date date, Object obj) {
           expireAt = date;
           object = obj;
       }
       public Date getExpireAt() {
           return expireAt;
       }
       public Object getObject() {
           return object;
       }
       @SuppressWarnings("unchecked")
       public <T> T getObject(Class<T> type) {
           return (T) object;
       }
   }
}