2930e09cfea22f427229f0ebce0cd7949f629425
[aaf/authz.git] / authz-core / src / main / java / com / att / cache / Cache.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aai\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * Copyright © 2017 Amdocs\r
7  * * ===========================================================================\r
8  * * Licensed under the Apache License, Version 2.0 (the "License");\r
9  * * you may not use this file except in compliance with the License.\r
10  * * You may obtain a copy of the License at\r
11  * * \r
12  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
13  * * \r
14  *  * Unless required by applicable law or agreed to in writing, software\r
15  * * distributed under the License is distributed on an "AS IS" BASIS,\r
16  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
17  * * See the License for the specific language governing permissions and\r
18  * * limitations under the License.\r
19  * * ============LICENSE_END====================================================\r
20  * *\r
21  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
22  * *\r
23  ******************************************************************************/\r
24 package com.att.cache;\r
25 \r
26 import java.util.ArrayList;\r
27 import java.util.Date;\r
28 import java.util.HashMap;\r
29 import java.util.HashSet;\r
30 import java.util.List;\r
31 import java.util.Map;\r
32 import java.util.Set;\r
33 import java.util.Timer;\r
34 import java.util.TimerTask;\r
35 import java.util.concurrent.ConcurrentHashMap;\r
36 import java.util.logging.Level;\r
37 \r
38 import com.att.inno.env.Env;\r
39 import com.att.inno.env.Trans;\r
40 \r
41 /**\r
42  * Create and maintain a Map of Maps used for Caching\r
43  * \r
44  *\r
45  * @param <TRANS>\r
46  * @param <DATA>\r
47  */\r
48 public class Cache<TRANS extends Trans, DATA> {\r
49         private static Clean clean;\r
50         private static Timer cleanseTimer;\r
51 \r
52         public static final String CACHE_HIGH_COUNT = "CACHE_HIGH_COUNT";\r
53         public static final String CACHE_CLEAN_INTERVAL = "CACHE_CLEAN_INTERVAL";\r
54 //      public static final String CACHE_MIN_REFRESH_INTERVAL = "CACHE_MIN_REFRESH_INTERVAL";\r
55 \r
56         private static final Map<String,Map<String,Dated>> cacheMap;\r
57 \r
58         static {\r
59                 cacheMap = new HashMap<String,Map<String,Dated>>();\r
60         }\r
61 \r
62         /**\r
63          * Dated Class - store any Data with timestamp\r
64          * \r
65          *\r
66          */\r
67         public final static class Dated { \r
68                 public Date timestamp;\r
69                 public List<?> data;\r
70                 \r
71                 public Dated(List<?> data) {\r
72                         timestamp = new Date();\r
73                         this.data = data;\r
74                 }\r
75 \r
76                 public <T> Dated(T t) {\r
77                         timestamp = new Date();\r
78                         ArrayList<T> al = new ArrayList<T>(1);\r
79                         al.add(t);\r
80                         data = al;\r
81                 }\r
82 \r
83                 public void touch() {\r
84                         timestamp = new Date();\r
85                 }\r
86         }\r
87         \r
88         public static Map<String,Dated> obtain(String key) {\r
89                 Map<String, Dated> m = cacheMap.get(key);\r
90                 if(m==null) {\r
91                         m = new ConcurrentHashMap<String, Dated>();\r
92                         synchronized(cacheMap) {\r
93                                 cacheMap.put(key, m);\r
94                         }\r
95                 }\r
96                 return m;\r
97         }\r
98 \r
99         /**\r
100          * Clean will examine resources, and remove those that have expired.\r
101          * \r
102          * If "highs" have been exceeded, then we'll expire 10% more the next time.  This will adjust after each run\r
103          * without checking contents more than once, making a good average "high" in the minimum speed.\r
104          * \r
105          *\r
106          */\r
107         private final static class Clean extends TimerTask {\r
108                 private final Env env;\r
109                 private Set<String> set;\r
110                 \r
111                 // The idea here is to not be too restrictive on a high, but to Expire more items by \r
112                 // shortening the time to expire.  This is done by judiciously incrementing "advance"\r
113                 // when the "highs" are exceeded.  This effectively reduces numbers of cached items quickly.\r
114                 private final int high;\r
115                 private long advance;\r
116                 private final long timeInterval;\r
117                 \r
118                 public Clean(Env env, long cleanInterval, int highCount) {\r
119                         this.env = env;\r
120                         high = highCount;\r
121                         timeInterval = cleanInterval;\r
122                         advance = 0;\r
123                         set = new HashSet<String>();\r
124                 }\r
125                 \r
126                 public synchronized void add(String key) {\r
127                         set.add(key);\r
128                 }\r
129 \r
130                 public void run() {\r
131                         int count = 0;\r
132                         int total = 0;\r
133                         // look at now.  If we need to expire more by increasing "now" by "advance"\r
134                         Date now = new Date(System.currentTimeMillis() + advance);\r
135                         \r
136                         \r
137                         for(String name : set) {\r
138                                 Map<String,Dated> map = cacheMap.get(name);\r
139                                 if(map!=null) for(Map.Entry<String,Dated> me : map.entrySet()) {\r
140                                         ++total;\r
141                                         if(me.getValue().timestamp.before(now)) {\r
142                                                 map.remove(me.getKey());\r
143                                                 ++count;\r
144                                         }\r
145                                 }\r
146 //                              if(count>0) {\r
147 //                                      env.info().log(Level.INFO, "Cache removed",count,"expired",name,"Elements");\r
148 //                              }\r
149                         }\r
150                         \r
151                         if(count>0) {\r
152                                 env.info().log(Level.INFO, "Cache removed",count,"expired Cached Elements out of", total);\r
153                         }\r
154 \r
155                         // If High (total) is reached during this period, increase the number of expired services removed for next time.\r
156                         // There's no point doing it again here, as there should have been cleaned items.\r
157                         if(total>high) {\r
158                                 // advance cleanup by 10%, without getting greater than timeInterval.\r
159                                 advance = Math.min(timeInterval, advance+(timeInterval/10));\r
160                         } else {\r
161                                 // reduce advance by 10%, without getting lower than 0.\r
162                                 advance = Math.max(0, advance-(timeInterval/10));\r
163                         }\r
164                 }\r
165         }\r
166 \r
167         public static synchronized void startCleansing(Env env, String ... keys) {\r
168                 if(cleanseTimer==null) {\r
169                         cleanseTimer = new Timer("Cache Cleanup Timer");\r
170                         int cleanInterval = Integer.parseInt(env.getProperty(CACHE_CLEAN_INTERVAL,"60000")); // 1 minute clean cycles \r
171                         int highCount = Integer.parseInt(env.getProperty(CACHE_HIGH_COUNT,"5000"));\r
172                         cleanseTimer.schedule(clean = new Clean(env, cleanInterval, highCount), cleanInterval, cleanInterval);\r
173                 }\r
174                 \r
175                 for(String key : keys) {\r
176                         clean.add(key);\r
177                 }\r
178         }\r
179 \r
180         public static void stopTimer() {\r
181                 if(cleanseTimer!=null) {\r
182                         cleanseTimer.cancel();\r
183                         cleanseTimer = null;\r
184                 }\r
185         }\r
186 \r
187         public static void addShutdownHook() {\r
188                 Runtime.getRuntime().addShutdownHook(new Thread() {\r
189                         @Override\r
190                         public void run() {\r
191                                 Cache.stopTimer();\r
192                         }\r
193                 }); \r
194         }\r
195 \r
196 }\r