11package io .github .javacoded78 .jwthumble .storage ;
22
33import io .github .javacoded78 .jwthumble .config .TokenParameters ;
4+ import lombok .Getter ;
45
6+ import java .util .Date ;
57import java .util .Map ;
6- import java .util .concurrent .ConcurrentHashMap ;import java .util .concurrent .atomic .AtomicBoolean ;
8+ import java .util .concurrent .ConcurrentHashMap ;
9+ import java .util .concurrent .Executors ;
10+ import java .util .concurrent .ScheduledExecutorService ;
11+ import java .util .concurrent .TimeUnit ;
12+ import java .util .concurrent .atomic .AtomicBoolean ;
713
814/**
915 * Basic implementation of TokenStorage.
@@ -13,13 +19,32 @@ public class TokenStorageImpl implements TokenStorage {
1319 /**
1420 * Inner map of key-value pairs.
1521 */
16- private final ConcurrentHashMap <String , String > tokens ;
22+ private final ConcurrentHashMap <String , TokenEntry > tokens ;
23+
24+ /**
25+ * Scheduled executor for cleanup tokens.
26+ */
27+ private final ScheduledExecutorService scheduler ;
1728
1829 /**
1930 * Creates an object.
2031 */
2132 public TokenStorageImpl () {
2233 this .tokens = new ConcurrentHashMap <>();
34+ this .scheduler = Executors .newSingleThreadScheduledExecutor ();
35+ scheduler .scheduleAtFixedRate (
36+ () -> {
37+ Date date = new Date ();
38+ for (Map .Entry <String , TokenEntry > entry : tokens .entrySet ()) {
39+ if (entry .getValue ().isAfter (date )) {
40+ tokens .remove (entry .getKey ());
41+ }
42+ }
43+ },
44+ 0 ,
45+ 1 ,
46+ TimeUnit .SECONDS
47+ );
2348 }
2449
2550 private String subjectTokenKey (final String subject ,
@@ -34,7 +59,8 @@ public void save(final String token,
3459 params .getSubject (),
3560 params .getType ()
3661 );
37- tokens .put (tokenKey , token );
62+ TokenEntry entry = new TokenEntry (token , params .getExpiredAt ());
63+ tokens .put (tokenKey , entry );
3864 }
3965
4066 @ Override
@@ -44,7 +70,11 @@ public boolean exists(final String token,
4470 params .getSubject (),
4571 params .getType ()
4672 );
47- return token .equals (tokens .get (tokenKey ));
73+ TokenEntry entry = tokens .get (tokenKey );
74+ if (entry == null ) {
75+ return false ;
76+ }
77+ return token .equals (entry .token );
4878 }
4979
5080 @ Override
@@ -53,14 +83,18 @@ public String get(final TokenParameters params) {
5383 params .getSubject (),
5484 params .getType ()
5585 );
56- return tokens .get (tokenKey );
86+ TokenEntry entry = tokens .get (tokenKey );
87+ if (entry == null ) {
88+ return null ;
89+ }
90+ return entry .token ;
5791 }
5892
5993 @ Override
6094 public boolean remove (final String token ) {
6195 AtomicBoolean deleted = new AtomicBoolean (false );
62- for (Map .Entry <String , String > entry : tokens .entrySet ()) {
63- if (entry .getValue ().equals (token )) {
96+ for (Map .Entry <String , TokenEntry > entry : tokens .entrySet ()) {
97+ if (entry .getValue ().token . equals (token )) {
6498 tokens .remove (entry .getKey ());
6599 deleted .set (true );
66100 return true ;
@@ -78,4 +112,29 @@ public boolean remove(final TokenParameters params) {
78112 return tokens .remove (tokenKey ) != null ;
79113 }
80114
115+ @ Getter
116+ private static class TokenEntry {
117+
118+ /**
119+ * Token.
120+ */
121+ private final String token ;
122+
123+ /**
124+ * Expiration date.
125+ */
126+ private final Date expiredAt ;
127+
128+ TokenEntry (final String token ,
129+ final Date expiredAt ) {
130+ this .token = token ;
131+ this .expiredAt = expiredAt ;
132+ }
133+
134+ public boolean isAfter (final Date date ) {
135+ return expiredAt .after (date );
136+ }
137+
138+ }
139+
81140}
0 commit comments