├── README.md
├── SampleListenerImplementation
└── RESTMeteringFilter.java
├── WeakConcurrentHashMap.java
└── WeakConcurrentHashMapListener.java
/README.md:
--------------------------------------------------------------------------------
1 | # WeakConcurrentHashMap
2 |
3 | A Weak Concurrent Hash Map Solution which stores the keys and values only for a specific amount of time, and then expires after that
4 | time.
5 |
6 |
7 |
8 | // Create a Map Object
9 | long expiryInMillis = 1 * 60 * 1000; // 1 minute
10 | WeakConcurrentHashMap<String, Long> map = new WeakConcurrentHashMap<String, Long>(expiryInMillis);
11 |
12 | // Use it
13 | map.put("key", valueObject);
14 | Long valueObject = map.get("key");
15 |
16 | // quit using it
17 | map.quitMap();
18 |
19 |
20 | And to check if the map is alive
21 |
22 |
23 | if (map.isAlive()) {
24 | // Your operations on map
25 | }
26 |
27 |
28 |
29 | Listener Implementation
30 |
31 |
32 |
33 | class MyMapListener implements WeakConcurrentHashMapListener {
34 |
35 | @Override
36 | public void notifyOnAdd(String key, Long value) {
37 | System.out.println("New key added to map. Key : " + key + ", Value : " + value);
38 | }
39 |
40 | @Override
41 | public void notifyOnRemoval(String key, Long value) {
42 | RestLogger.info("Key Removed from Map Key: " + key + ", Value : " + value);
43 | }
44 | }
45 |
46 |
47 | @author Vivekananthan M (vivekjustthink@gmail.com)
48 |
--------------------------------------------------------------------------------
/SampleListenerImplementation/RESTMeteringFilter.java:
--------------------------------------------------------------------------------
1 | import java.io.IOException;
2 |
3 | import javax.ws.rs.container.ContainerRequestContext;
4 | import javax.ws.rs.container.ContainerRequestFilter;
5 | import javax.ws.rs.ext.Provider;
6 |
7 | import WeakConcurrentHashMap;
8 | import WeakConcurrentHashMapListener;
9 |
10 | /**
11 | * This servlet filter is used to track the number of api hits module wise on the FE Side. For now it just prints the api hit count once in 5 mintues in the FE logs.
12 | *
13 | * @author Vivekananthan M
14 | *
15 | */
16 | @Provider
17 | public class RESTMeteringFilter implements ContainerRequestFilter {
18 |
19 | private WeakConcurrentHashMap apiCounter = new WeakConcurrentHashMap<>(5 * 60 * 1000); // Keys in the map will expire in 5 minutes
20 |
21 | public RESTMeteringFilter() {
22 | apiCounter.registerRemovalListener(new PrintAPIHits());
23 | }
24 |
25 | @Override
26 | public void filter(ContainerRequestContext paramContainerRequestContext) throws IOException
27 | {
28 | RestLogger.debug("Processing Request for Metering. URI " + paramContainerRequestContext.getUriInfo().getPath()); //No I18N
29 | String uriHit = paramContainerRequestContext.getUriInfo().getPath();
30 |
31 | if(uriHit != null) {
32 | String[] pathList = uriHit.split("/");
33 | String key = null;
34 | if(pathList.length >= 4) {
35 | key = pathList[2] + "/" + pathList[3];
36 | } else {
37 | key = pathList[pathList.length-1];
38 | }
39 |
40 | if(key != null && !key.isEmpty()) {
41 | if(apiCounter.containsKey(key)) {
42 | apiCounter.put(key, apiCounter.get(key) + 1);
43 | } else {
44 | apiCounter.put(key, 1l);
45 | }
46 | }
47 | }
48 | }
49 | }
50 |
51 | class PrintAPIHits implements WeakConcurrentHashMapListener {
52 |
53 | @Override
54 | public void notifyOnAdd(String key, Long value) {}
55 |
56 | @Override
57 | public void notifyOnRemoval(String key, Long value) {
58 | System.out.println("Refreshing API Hits " + key + " : " + value);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/WeakConcurrentHashMap.java:
--------------------------------------------------------------------------------
1 | import java.util.Date;
2 | import java.util.Map;
3 | import java.util.concurrent.ConcurrentHashMap;
4 |
5 | /**
6 | * A Weak Concurrent Hash Map Solution which stores the keys and values only for a specific amount of time, and then expires after that
7 | * time.
8 | *
9 | *
10 | *
11 | * // Create a Map Object
12 | * long expiryInMillis = 1 * 60 * 1000; // 1 minute
13 | * WeakConcurrentHashMap<String, Object> map = new WeakConcurrentHashMap<String, Object>(expiryInMillis);
14 | *
15 | * // Use it
16 | * map.put("key", valueObject);
17 | * Object valueObject = map.get("key");
18 | *
19 | * // quit using it
20 | * map.quitMap();
21 | *
22 | *
23 | * And to check if the map is alive
24 | *
25 | *
26 | * if (map.isAlive()) {
27 | * // Your operations on map
28 | * }
29 | *
30 | *
31 | * @author Vivekananthan M
32 | *
33 | * @param
34 | * @param
35 | */
36 | public class WeakConcurrentHashMap extends ConcurrentHashMap {
37 |
38 | private static final long serialVersionUID = 1L;
39 |
40 | private Map timeMap = new ConcurrentHashMap();
41 | private WeakConcurrentHashMapListener listener;
42 | private long expiryInMillis;
43 | private boolean mapAlive = true;
44 |
45 | public WeakConcurrentHashMap() {
46 | this.expiryInMillis = 10000;
47 | initialize();
48 | }
49 |
50 | public WeakConcurrentHashMap(WeakConcurrentHashMapListener listener) {
51 | this.listener = listener;
52 | this.expiryInMillis = 10000;
53 | initialize();
54 | }
55 |
56 | public WeakConcurrentHashMap(long expiryInMillis) {
57 | this.expiryInMillis = expiryInMillis;
58 | initialize();
59 | }
60 |
61 | public WeakConcurrentHashMap(long expiryInMillis, WeakConcurrentHashMapListener listener) {
62 | this.expiryInMillis = expiryInMillis;
63 | this.listener = listener;
64 | initialize();
65 | }
66 |
67 | void initialize() {
68 | new CleanerThread().start();
69 | }
70 |
71 | public void registerRemovalListener(WeakConcurrentHashMapListener listener) {
72 | this.listener = listener;
73 | }
74 |
75 | /**
76 | * {@inheritDoc}
77 | *
78 | * @throws IllegalStateException if trying to insert values into map after quiting
79 | */
80 | @Override
81 | public V put(K key, V value) {
82 | if (!mapAlive) {
83 | throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); // No I18N
84 | }
85 | Date date = new Date();
86 | timeMap.put(key, date.getTime());
87 | V returnVal = super.put(key, value);
88 | if (listener != null) {
89 | listener.notifyOnAdd(key, value);
90 | }
91 | return returnVal;
92 | }
93 |
94 | /**
95 | * {@inheritDoc}
96 | *
97 | * @throws IllegalStateException if trying to insert values into map after quiting
98 | */
99 | @Override
100 | public void putAll(Map extends K, ? extends V> m) {
101 | if (!mapAlive) {
102 | throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); // No I18N
103 | }
104 | for (K key : m.keySet()) {
105 | put(key, m.get(key));
106 | }
107 | }
108 |
109 | /**
110 | * {@inheritDoc}
111 | *
112 | * @throws IllegalStateException if trying to insert values into map after quiting
113 | */
114 | @Override
115 | public V putIfAbsent(K key, V value) {
116 | if (!mapAlive) {
117 | throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); // No I18N
118 | }
119 | if (!containsKey(key)) {
120 | return put(key, value);
121 | } else {
122 | return get(key);
123 | }
124 | }
125 |
126 | /**
127 | * Should call this method when it's no longer required
128 | */
129 | public void quitMap() {
130 | mapAlive = false;
131 | }
132 |
133 | public boolean isAlive() {
134 | return mapAlive;
135 | }
136 |
137 | /**
138 | *
139 | * This thread performs the cleaning operation on the concurrent hashmap once in a specified interval. This wait interval is half of the
140 | * time from the expiry time.
141 | *
142 | *
143 | */
144 | class CleanerThread extends Thread {
145 |
146 | @Override
147 | public void run() {
148 | while (mapAlive) {
149 | cleanMap();
150 | try {
151 | Thread.sleep(expiryInMillis / 2);
152 | } catch (InterruptedException e) {
153 | e.printStackTrace();
154 | }
155 | }
156 | }
157 |
158 | private void cleanMap() {
159 | long currentTime = new Date().getTime();
160 | for (K key : timeMap.keySet()) {
161 | if (currentTime > (timeMap.get(key) + expiryInMillis)) {
162 | V value = remove(key);
163 | timeMap.remove(key);
164 | if (listener != null) {
165 | listener.notifyOnRemoval(key, value);
166 | }
167 | }
168 | }
169 | }
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/WeakConcurrentHashMapListener.java:
--------------------------------------------------------------------------------
1 | public interface WeakConcurrentHashMapListener {
2 | public void notifyOnAdd(K key, V value);
3 | public void notifyOnRemoval(K key, V value);
4 | }
5 |
--------------------------------------------------------------------------------