1 package net.avcompris.examples.users3.dao.impl;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4 import static net.avcompris.commons.query.impl.FilteringsFactory.match;
5 import static net.avcompris.commons3.databeans.DataBeans.instantiate;
6 import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric;
7
8 import java.io.IOException;
9 import java.sql.SQLException;
10 import java.util.ArrayList;
11 import java.util.Comparator;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.concurrent.ConcurrentHashMap;
15
16 import javax.annotation.Nullable;
17
18 import org.joda.time.DateTime;
19 import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.stereotype.Component;
21
22 import net.avcompris.commons3.api.UserSessionFiltering;
23 import net.avcompris.commons3.dao.impl.AbstractDao;
24 import net.avcompris.commons3.utils.Clock;
25 import net.avcompris.examples.users3.dao.AuthDao;
26 import net.avcompris.examples.users3.dao.UserSessionDto;
27 import net.avcompris.examples.users3.dao.UserSessionsDto;
28 import net.avcompris.examples.users3.dao.UserSessionsDtoQuery;
29 import net.avcompris.examples.users3.dao.UserSessionsDtoQuery.SortBy;
30
31 @Component
32 public final class AuthDaoInMemory extends AbstractDao implements AuthDao {
33
34 private static final int SESSION_TIMEOUT_MINUTES = 60;
35
36 private final Map<String, String> passwords = new ConcurrentHashMap<>();
37 private final Map<String, MutableUserSessionDto> sessions = new ConcurrentHashMap<>();
38
39 @Autowired
40 public AuthDaoInMemory(final Clock clock) {
41
42 super(clock);
43 }
44
45 @Override
46 public void setUserPassword(final String username, final String password) throws SQLException, IOException {
47
48 checkNotNull(username, "username");
49 checkNotNull(password, "password");
50
51 passwords.put(username, password);
52 }
53
54 @Override
55 public void removeUserPassword(final String username) throws SQLException, IOException {
56
57 checkNotNull(username, "username");
58
59 passwords.remove(username);
60 }
61
62 @Override
63 @Nullable
64 public String getUsernameByAuthorization(final String authorization, final DateTime updatedAt)
65 throws SQLException, IOException {
66
67 checkNotNull(authorization, "authorization");
68 checkNotNull(updatedAt, "updatedAt");
69
70
71
72 return null;
73 }
74
75 @Override
76 @Nullable
77 public String getUsernameBySessionId(final String userSessionId, final DateTime updatedAt)
78 throws SQLException, IOException {
79
80 checkNotNull(userSessionId, "userSessionId");
81 checkNotNull(updatedAt, "updatedAt");
82
83 final MutableUserSessionDto session = sessions.get(userSessionId);
84
85 if (session == null || session.getExpiredAt() != null) {
86
87 return null;
88 }
89
90 session.setUpdatedAt(updatedAt);
91
92 final DateTime expiresAt = session.getExpiresAt();
93
94 if (updatedAt.isAfter(expiresAt)) {
95
96 session.setExpiredAt(updatedAt);
97
98 return null;
99 }
100
101 session.setExpiresAt(updatedAt.plusMinutes(SESSION_TIMEOUT_MINUTES));
102
103 return session.getUsername();
104 }
105
106 @Override
107 public boolean isValidUserPassword(final String username, final String password) throws SQLException, IOException {
108
109 checkNotNull(username, "username");
110 checkNotNull(password, "password");
111
112 return passwords.containsKey(username)
113 && password.contentEquals(passwords.get(username));
114 }
115
116 @Override
117 public UserSessionDto newUserSession(final String username, final DateTime createdAt)
118 throws SQLException, IOException {
119
120 checkNotNull(username, "username");
121 checkNotNull(createdAt, "createdAt");
122
123 final MutableUserSessionDto dto = instantiate(MutableUserSessionDto.class)
124 .setUsername(username)
125 .setCreatedAt(createdAt)
126 .setUpdatedAt(createdAt)
127 .setExpiresAt(createdAt.plusMinutes(SESSION_TIMEOUT_MINUTES));
128
129 return retryUntil(4_000, 0, () -> {
130
131 final String userSessionId = "S-"
132 + System.currentTimeMillis() + "-"
133 + randomAlphanumeric(20);
134
135 dto.setUserSessionId(userSessionId);
136
137 final UserSessionDto old = sessions.putIfAbsent(userSessionId, dto);
138
139 return old == null ? dto : null;
140 });
141 }
142
143 @Override
144 @Nullable
145 public UserSessionDto getUserSession(final String userSessionId, final DateTime updatedAt)
146 throws SQLException, IOException {
147
148 checkNotNull(userSessionId, "userSessionId");
149 checkNotNull(updatedAt, "updatedAt");
150
151 final MutableUserSessionDto session = sessions.get(userSessionId);
152
153 if (session == null) {
154
155 return null;
156 }
157
158 if (session.getExpiredAt() == null) {
159
160 session.setUpdatedAt(updatedAt);
161
162 final DateTime expiresAt = session.getExpiresAt();
163
164 if (updatedAt.isAfter(expiresAt)) {
165
166 session.setExpiredAt(updatedAt);
167
168 } else {
169
170 session.setExpiresAt(updatedAt.plusMinutes(SESSION_TIMEOUT_MINUTES));
171 }
172 }
173
174 return session;
175 }
176
177 @Override
178 public void terminateSession(final String userSessionId, @Nullable final DateTime updatedAt,
179 final DateTime expiredAt) throws SQLException, IOException {
180
181 checkNotNull(userSessionId, "userSessionId");
182 checkNotNull(expiredAt, "expiredAt");
183
184 final MutableUserSessionDto session = sessions.get(userSessionId);
185
186 if (session == null || session.getExpiredAt() != null) {
187
188 return;
189 }
190
191 if (updatedAt != null) {
192
193 session.setUpdatedAt(updatedAt);
194 }
195
196 session.setExpiredAt(expiredAt);
197 }
198
199 @Override
200 @Nullable
201 public DateTime getLastActiveAt(final String username) throws SQLException, IOException {
202
203 checkNotNull(username, "username");
204
205 DateTime maxLastActiveAt = null;
206
207 for (final UserSessionDto session : sessions.values()) {
208
209 if (!username.contentEquals(session.getUsername())) {
210 continue;
211 }
212
213 final DateTime lastActiveAt = session.getUpdatedAt();
214
215 if (maxLastActiveAt == null || lastActiveAt.isAfter(maxLastActiveAt)) {
216 maxLastActiveAt = lastActiveAt;
217 }
218 }
219
220 return maxLastActiveAt;
221 }
222
223 @Override
224 public UserSessionsDto getUserSessions(final UserSessionsDtoQuery query) throws SQLException, IOException {
225
226 checkNotNull(query, "query");
227
228 final UserSessionFiltering filtering = query.getFiltering();
229 final SortBy[] sortBys = query.getSortBys();
230 final int start = query.getStart();
231 final int limit = query.getLimit();
232
233 final List<UserSessionDto> extract = new ArrayList<>();
234
235 for (final MutableUserSessionDto session : sessions.values()) {
236
237 if (filtering == null || match(session, filtering)) {
238
239 extract.add(session);
240 }
241 }
242
243 final MutableUserSessionsDto sessions = instantiate(MutableUserSessionsDto.class)
244 .setTotal(extract.size());
245
246 final Comparator<? super UserSessionDto> comparator = Comparators.get(sortBys);
247
248 extract.sort(comparator);
249
250 int offset = 0;
251
252 for (final UserSessionDto session : extract) {
253
254 if (offset >= start + limit) {
255
256 break;
257
258 } else if (offset >= start) {
259
260 sessions.addToResults(session);
261 }
262
263 ++offset;
264 }
265
266 return sessions;
267 }
268 }