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