1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\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
12 * * http://www.apache.org/licenses/LICENSE-2.0
\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
21 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
23 ******************************************************************************/
\r
24 package com.att.cache;
\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
38 import com.att.inno.env.Env;
\r
39 import com.att.inno.env.Trans;
\r
42 * Create and maintain a Map of Maps used for Caching
\r
48 public class Cache<TRANS extends Trans, DATA> {
\r
49 private static Clean clean;
\r
50 private static Timer cleanseTimer;
\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
56 private static final Map<String,Map<String,Dated>> cacheMap;
\r
59 cacheMap = new HashMap<String,Map<String,Dated>>();
\r
63 * Dated Class - store any Data with timestamp
\r
67 public final static class Dated {
\r
68 public Date timestamp;
\r
69 public List<?> data;
\r
71 public Dated(List<?> data) {
\r
72 timestamp = new Date();
\r
76 public <T> Dated(T t) {
\r
77 timestamp = new Date();
\r
78 ArrayList<T> al = new ArrayList<T>(1);
\r
83 public void touch() {
\r
84 timestamp = new Date();
\r
88 public static Map<String,Dated> obtain(String key) {
\r
89 Map<String, Dated> m = cacheMap.get(key);
\r
91 m = new ConcurrentHashMap<String, Dated>();
\r
92 synchronized(cacheMap) {
\r
93 cacheMap.put(key, m);
\r
100 * Clean will examine resources, and remove those that have expired.
\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
107 private final static class Clean extends TimerTask {
\r
108 private final Env env;
\r
109 private Set<String> set;
\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
118 public Clean(Env env, long cleanInterval, int highCount) {
\r
121 timeInterval = cleanInterval;
\r
123 set = new HashSet<String>();
\r
126 public synchronized void add(String key) {
\r
130 public void run() {
\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
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
141 if(me.getValue().timestamp.before(now)) {
\r
142 map.remove(me.getKey());
\r
147 // env.info().log(Level.INFO, "Cache removed",count,"expired",name,"Elements");
\r
152 env.info().log(Level.INFO, "Cache removed",count,"expired Cached Elements out of", total);
\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
158 // advance cleanup by 10%, without getting greater than timeInterval.
\r
159 advance = Math.min(timeInterval, advance+(timeInterval/10));
\r
161 // reduce advance by 10%, without getting lower than 0.
\r
162 advance = Math.max(0, advance-(timeInterval/10));
\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
175 for(String key : keys) {
\r
180 public static void stopTimer() {
\r
181 if(cleanseTimer!=null) {
\r
182 cleanseTimer.cancel();
\r
183 cleanseTimer = null;
\r
187 public static void addShutdownHook() {
\r
188 Runtime.getRuntime().addShutdownHook(new Thread() {
\r
190 public void run() {
\r