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   
7   import java.io.IOException;
8   import java.sql.SQLException;
9   import java.util.ArrayList;
10  import java.util.Comparator;
11  import java.util.ConcurrentModificationException;
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.dao.exception.DuplicateEntityException;
23  import net.avcompris.commons3.dao.impl.AbstractDao;
24  import net.avcompris.commons3.utils.Clock;
25  import net.avcompris.examples.users3.dao.UserDto;
26  import net.avcompris.examples.users3.dao.UsersDao;
27  import net.avcompris.examples.users3.dao.UsersDto;
28  import net.avcompris.examples.users3.dao.UsersDtoQuery;
29  import net.avcompris.examples.users3.dao.UsersDtoQuery.SortBy;
30  import net.avcompris.examples.users3.dao.impl.MutableUserDto;
31  import net.avcompris.examples.users3.dao.impl.MutableUsersDto;
32  import net.avcompris.examples.users3.query.UserFiltering;
33  
34  @Component
35  public final class UsersDaoInMemory extends AbstractDao implements UsersDao {
36  
37  	private final Map<String, MutableUserDto> users = new ConcurrentHashMap<>();
38  
39  	@Autowired
40  	public UsersDaoInMemory(final Clock clock) {
41  
42  		super(clock);
43  	}
44  
45  	@Override
46  	public UsersDto getUsers(final UsersDtoQuery query) throws SQLException, IOException {
47  
48  		checkNotNull(query, "query");
49  
50  		final UserFiltering filtering = query.getFiltering();
51  		final SortBy[] sortBys = query.getSortBys();
52  		final int start = query.getStart();
53  		final int limit = query.getLimit();
54  
55  		final List<UserDto> extract = new ArrayList<>();
56  
57  		for (final MutableUserDto user : users.values()) {
58  
59  			if (filtering == null || match(user, filtering)) {
60  
61  				extract.add(user);
62  			}
63  		}
64  
65  		final MutableUsersDto users = instantiate(MutableUsersDto.class) //
66  				.setTotal(extract.size());
67  
68  		final Comparator<? super UserDto> comparator = Comparators.get(sortBys);
69  
70  		extract.sort(comparator);
71  
72  		int offset = 0;
73  
74  		for (final UserDto user : extract) {
75  
76  			if (offset >= start + limit) {
77  
78  				break;
79  
80  			} else if (offset >= start) {
81  
82  				users.addToResults(user);
83  			}
84  
85  			++offset;
86  		}
87  
88  		return users;
89  	}
90  
91  	@Override
92  	public void createUser(final String username, //
93  			final String rolename, //
94  			@Nullable final String preferredLang, //
95  			@Nullable final String preferredTimeZone, //
96  			final boolean enabled //
97  	) throws SQLException, IOException, DuplicateEntityException {
98  
99  		checkNotNull(username, "username");
100 		checkNotNull(rolename, "rolename");
101 
102 		final DateTime now = clock.now();
103 
104 		final MutableUserDto user = instantiate(MutableUserDto.class) //
105 				.setUsername(username) //
106 				.setRolename(rolename) //
107 				.setPreferredLang(preferredLang) //
108 				.setPreferredTimeZone(preferredTimeZone) //
109 				.setEnabled(enabled) //
110 				.setCreatedAt(now) //
111 				.setUpdatedAt(now) //
112 				.setRevision(1);
113 
114 		final UserDto old = users.putIfAbsent(username, user);
115 
116 		if (old != null) {
117 			throw new DuplicateEntityException("username: " + username);
118 		}
119 	}
120 
121 	@Override
122 	@Nullable
123 	public UserDto getUser(final String username) throws SQLException, IOException {
124 
125 		checkNotNull(username, "username");
126 
127 		final MutableUserDto userDto = users.get(username);
128 
129 		if (userDto == null) {
130 			return null;
131 		}
132 
133 		return userDto;
134 	}
135 
136 	@Override
137 	public void setLastActiveAt(final String username, final DateTime lastActiveAt) throws SQLException, IOException {
138 
139 		checkNotNull(username, "username");
140 		checkNotNull(lastActiveAt, "lastActiveAt");
141 
142 		final MutableUserDto userDto = users.get(username);
143 
144 		if (userDto == null) {
145 			return;
146 		}
147 
148 		userDto.setLastActiveAt(lastActiveAt);
149 	}
150 
151 	@Override
152 	public void updateUser(final String username, //
153 			final String rolename, //
154 			@Nullable final String preferredLang, //
155 			@Nullable final String preferredTimeZone, //
156 			final boolean enabled, //
157 			final int fromRevision //
158 	) throws SQLException, IOException {
159 
160 		checkNotNull(username, "username");
161 		checkNotNull(rolename, "rolename");
162 
163 		final MutableUserDto dto = users.get(username);
164 
165 		if (dto == null) { // TODO What do we really expect here?
166 			return;
167 		}
168 
169 		final int actualRevision = dto.getRevision();
170 
171 		if (actualRevision != fromRevision) {
172 			throw new ConcurrentModificationException(
173 					"revision should be: " + fromRevision + ", but was: " + actualRevision);
174 		}
175 
176 		final DateTime now = clock.now();
177 
178 		dto.setUpdatedAt(now) //
179 				.setRolename(rolename) //
180 				.setEnabled(enabled) //
181 				.setRevision(fromRevision + 1);
182 
183 		if (preferredLang != null) {
184 			dto.setPreferredLang(preferredLang);
185 		}
186 
187 		if (preferredTimeZone != null) {
188 			dto.setPreferredTimeZone(preferredTimeZone);
189 		}
190 	}
191 
192 	@Override
193 	public void deleteUser(final String username) throws SQLException, IOException {
194 
195 		checkNotNull(username, "username");
196 
197 		users.remove(username);
198 	}
199 }