View Javadoc
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  		// throw new NotImplementedException("");
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 }