|
10 | 10 | import io.jooby.SessionStore; |
11 | 11 | import io.jooby.SessionToken; |
12 | 12 |
|
13 | | -import javax.annotation.Nonnull; |
14 | 13 | import java.time.Duration; |
15 | 14 | import java.time.Instant; |
16 | 15 | import java.util.Iterator; |
17 | 16 | import java.util.Map; |
18 | 17 | import java.util.Optional; |
19 | 18 | import java.util.concurrent.ConcurrentHashMap; |
| 19 | +import java.util.function.Function; |
20 | 20 |
|
21 | | -public class MemorySessionStore implements SessionStore { |
22 | | - private static class SessionData { |
23 | | - private Instant lastAccessedTime; |
24 | | - private Instant creationTime; |
25 | | - private Map hash; |
| 21 | +public class MemorySessionStore extends SessionStore.InMemory { |
26 | 22 |
|
27 | | - public SessionData(Instant creationTime, Instant lastAccessedTime, Map hash) { |
28 | | - this.creationTime = creationTime; |
29 | | - this.lastAccessedTime = lastAccessedTime; |
30 | | - this.hash = hash; |
31 | | - } |
32 | | - } |
33 | | - |
34 | | - private ConcurrentHashMap<String, SessionData> sessions = new ConcurrentHashMap<>(); |
35 | | - |
36 | | - private SessionToken token; |
| 23 | + private ConcurrentHashMap<String, Data> sessions = new ConcurrentHashMap<>(); |
37 | 24 |
|
38 | 25 | private Duration timeout; |
39 | 26 |
|
40 | 27 | public MemorySessionStore(SessionToken token, Duration timeout) { |
41 | | - this.token = token; |
| 28 | + super(token); |
42 | 29 | this.timeout = Optional.ofNullable(timeout) |
43 | 30 | .filter(t -> t.toMillis() > 0) |
44 | 31 | .orElse(null); |
45 | 32 | } |
46 | 33 |
|
47 | | - @Override public Session newSession(Context ctx) { |
48 | | - String sessionId = token.newToken(); |
49 | | - SessionData data = sessions.computeIfAbsent(sessionId, sid -> { |
50 | | - Instant now = Instant.now(); |
51 | | - return new SessionData(now, now, new ConcurrentHashMap()); |
52 | | - }); |
| 34 | + @Override protected Data getOrCreate(String sessionId, |
| 35 | + Function<String, Data> factory) { |
| 36 | + return sessions.computeIfAbsent(sessionId, factory); |
| 37 | + } |
| 38 | + |
| 39 | + @Override protected Data getOrNull(String sessionId) { |
| 40 | + return sessions.get(sessionId); |
| 41 | + } |
53 | 42 |
|
54 | | - Session session = restore(ctx, sessionId, data); |
| 43 | + @Override protected Data remove(String sessionId) { |
| 44 | + return sessions.remove(sessionId); |
| 45 | + } |
55 | 46 |
|
56 | | - token.saveToken(ctx, sessionId); |
57 | | - return session; |
| 47 | + @Override protected void put(String sessionId, Data data) { |
| 48 | + sessions.put(sessionId, data); |
58 | 49 | } |
59 | 50 |
|
60 | 51 | @Override public Session findSession(Context ctx) { |
61 | 52 | purge(); |
62 | | - String sessionId = token.findToken(ctx); |
63 | | - if (sessionId == null) { |
64 | | - return null; |
65 | | - } |
66 | | - SessionData data = sessions.get(sessionId); |
67 | | - if (data != null) { |
68 | | - Session session = restore(ctx, sessionId, data); |
69 | | - token.saveToken(ctx, sessionId); |
70 | | - return session; |
71 | | - } |
72 | | - return null; |
| 53 | + return super.findSession(ctx); |
73 | 54 | } |
74 | 55 |
|
75 | 56 | /** |
76 | 57 | * Check for expired session and delete them. |
77 | 58 | */ |
78 | 59 | private void purge() { |
79 | 60 | if (timeout != null) { |
80 | | - Iterator<Map.Entry<String, SessionData>> iterator = sessions.entrySet().iterator(); |
81 | | - Instant now = Instant.now(); |
| 61 | + Iterator<Map.Entry<String, Data>> iterator = sessions.entrySet().iterator(); |
82 | 62 | while (iterator.hasNext()) { |
83 | | - Map.Entry<String, SessionData> entry = iterator.next(); |
84 | | - SessionData session = entry.getValue(); |
85 | | - Duration timeElapsed = Duration.between(session.lastAccessedTime, now); |
86 | | - if (timeElapsed.compareTo(timeout) > 0) { |
| 63 | + Map.Entry<String, Data> entry = iterator.next(); |
| 64 | + Data session = entry.getValue(); |
| 65 | + if (session.isExpired(timeout)) { |
87 | 66 | iterator.remove(); |
88 | 67 | } |
89 | 68 | } |
90 | 69 | } |
91 | 70 | } |
92 | 71 |
|
93 | | - @Override public void deleteSession(@Nonnull Context ctx, @Nonnull Session session) { |
94 | | - String sessionId = session.getId(); |
95 | | - sessions.remove(sessionId); |
96 | | - token.deleteToken(ctx, sessionId); |
97 | | - } |
98 | | - |
99 | | - @Override public void touchSession(@Nonnull Context ctx, @Nonnull Session session) { |
100 | | - saveSession(ctx, session); |
101 | | - token.saveToken(ctx, session.getId()); |
102 | | - } |
103 | | - |
104 | | - @Override public void saveSession(Context ctx, @Nonnull Session session) { |
105 | | - String sessionId = session.getId(); |
106 | | - sessions.put(sessionId, |
107 | | - new SessionData(session.getCreationTime(), Instant.now(), session.toMap())); |
108 | | - } |
109 | | - |
110 | | - @Override public void renewSessionId(@Nonnull Context ctx, @Nonnull Session session) { |
111 | | - String oldId = session.getId(); |
112 | | - String newId = token.newToken(); |
113 | | - session.setId(newId); |
114 | | - SessionData data = sessions.remove(oldId); |
115 | | - sessions.put(newId, data); |
116 | | - } |
117 | | - |
118 | 72 | public SessionStore setTimeout(Duration timeout) { |
119 | 73 | this.timeout = timeout; |
120 | 74 | return this; |
121 | 75 | } |
122 | 76 |
|
123 | | - private Session restore(Context ctx, String sessionId, SessionData data) { |
124 | | - return Session.create(ctx, sessionId, data.hash) |
125 | | - .setLastAccessedTime(data.lastAccessedTime) |
126 | | - .setCreationTime(data.creationTime); |
127 | | - } |
128 | 77 | } |
0 commit comments