6
6
import jakarta .persistence .EntityManager ;
7
7
import jakarta .persistence .PersistenceContext ;
8
8
import jakarta .persistence .PersistenceContextType ;
9
+ import jakarta .persistence .Query ;
9
10
import jakarta .transaction .Transactional ;
10
11
import lombok .Getter ;
11
12
import lombok .extern .slf4j .Slf4j ;
31
32
import java .util .function .Consumer ;
32
33
import java .util .function .Function ;
33
34
import java .util .stream .Collectors ;
35
+ import java .util .stream .Stream ;
34
36
35
37
/**
36
38
* Cache synchronization from SQL cache to database.
@@ -85,9 +87,9 @@ private void updateUserToGroupInternal(final CacheUser entity, final CacheGroup
85
87
/**
86
88
* Associate a subgroup to a group using the cache groups to prevent duplicate entries.
87
89
*/
88
- private void updateGroupToGroupInternal (final CacheGroup subGroup , final CacheGroup group , final Set <String > cacheGroups ) {
89
- if (!cacheGroups .contains (group .getId ())) {
90
- // New membership
90
+ private void updateGroupToGroupInternal (final CacheGroup subGroup , final CacheGroup group , final Set <String > cacheSubGroups ) {
91
+ if (!cacheSubGroups .contains (subGroup .getId ())) {
92
+ // New membership to put in cache
91
93
final var membership = new CacheMembership ();
92
94
membership .setSubGroup (subGroup );
93
95
membership .setGroup (group );
@@ -117,7 +119,7 @@ public void create(final UserOrg user) {
117
119
// Set the company if defined
118
120
entity .setCompany (Optional .ofNullable (user .getCompany ()).map (c -> {
119
121
final var company = new CacheCompany ();
120
- company .setId (user . getCompany () );
122
+ company .setId (c );
121
123
return company ;
122
124
}).orElse (null ));
123
125
em .persist (entity );
@@ -176,37 +178,34 @@ private CacheUser createInternal(final UserOrg user, final Map<String, CacheUser
176
178
177
179
@ Override
178
180
public void delete (final CompanyOrg company ) {
179
- em .createQuery ("DELETE FROM CacheCompany WHERE id=:id" ).setParameter ("id" , company .getId ()).executeUpdate ();
180
- em .flush ();
181
- em .clear ();
181
+ removeAll (em .createQuery ("FROM CacheCompany WHERE id=:id" ).setParameter ("id" , company .getId ()));
182
182
}
183
183
184
184
@ Override
185
185
public void delete (final GroupOrg group ) {
186
- em .createQuery ("DELETE FROM CacheProjectGroup WHERE group.id=:id" ).setParameter ("id" , group .getId ())
187
- .executeUpdate ();
188
- em .createQuery ("DELETE FROM CacheMembership WHERE group.id=:id OR subGroup.id=:id" )
189
- .setParameter ("id" , group .getId ()).executeUpdate ();
190
- em .createQuery ("DELETE FROM CacheGroup WHERE id=:id" ).setParameter ("id" , group .getId ()).executeUpdate ();
186
+ removeAll (
187
+ em .createQuery ("FROM CacheMembership WHERE group.id=:id OR subGroup.id=:id" ).setParameter ("id" , group .getId ()),
188
+ em .createQuery ("FROM CacheProjectGroup WHERE group.id=:id" ).setParameter ("id" , group .getId ()),
189
+ em .createQuery ("FROM CacheGroup WHERE id=:id" ).setParameter ("id" , group .getId ())
190
+ );
191
+ }
192
+
193
+ private void removeAll (Query ... queries ) {
194
+ Stream .of (queries ).map (Query ::getResultList ).forEach (l -> l .forEach (em ::remove ));
191
195
em .flush ();
192
- em .clear ();
193
196
}
194
197
195
198
@ Override
196
199
public void delete (final UserOrg user ) {
197
- em .createQuery ("DELETE FROM CacheMembership WHERE user.id=:id" ).setParameter ("id" , user .getId ())
198
- .executeUpdate ();
199
- em .createQuery ("DELETE FROM CacheUser WHERE id=:id" ).setParameter ("id" , user .getId ()).executeUpdate ();
200
- em .flush ();
201
- em .clear ();
200
+ removeAll (
201
+ em .createQuery ("FROM CacheMembership WHERE user.id=:id" ).setParameter ("id" , user .getId ()),
202
+ em .createQuery ("FROM CacheUser WHERE id=:id" ).setParameter ("id" , user .getId ())
203
+ );
202
204
}
203
205
204
206
@ Override
205
207
public void empty (final GroupOrg group ) {
206
- em .createQuery ("DELETE FROM CacheMembership WHERE group.id=:id" ).setParameter ("id" , group .getId ())
207
- .executeUpdate ();
208
- em .flush ();
209
- em .clear ();
208
+ removeAll (em .createQuery ("FROM CacheMembership WHERE group.id=:id" ).setParameter ("id" , group .getId ()));
210
209
}
211
210
212
211
/**
@@ -229,16 +228,22 @@ private int persistUsersAndMemberships(final Map<String, UserOrg> users, final M
229
228
final Map <String , CacheCompany > cacheCompanies ) {
230
229
final var cacheUsers = em .createQuery ("FROM CacheUser" , CacheUser .class )
231
230
.getResultList ().stream ().collect (Collectors .toMap (CacheUser ::getId , Function .identity ()));
232
- final var userMemberships = em .createQuery ("FROM CacheMembership WHERE user is not null" , CacheMembership .class )
233
- .getResultList ().stream ().collect (
234
- Collectors .groupingBy (c -> c .getUser ().getId (),
235
- Collectors .mapping (c -> c .getGroup ().getId (),
236
- Collectors .toSet ())));
237
- final var groupMemberships = em .createQuery ("FROM CacheMembership WHERE subGroup is not null" , CacheMembership .class )
238
- .getResultList ().stream ().collect (
239
- Collectors .groupingBy (c -> c .getGroup ().getId (),
240
- Collectors .mapping (c -> c .getSubGroup ().getId (),
241
- Collectors .toSet ())));
231
+
232
+ final var userMemberships = em .createQuery ("FROM CacheMembership WHERE user is not null" , CacheMembership .class ).getResultList ();
233
+ final var groupMemberships = em .createQuery ("FROM CacheMembership WHERE subGroup is not null" , CacheMembership .class ).getResultList ();
234
+
235
+ // Remove duplicates
236
+ groupMemberships .stream ().collect (Collectors .groupingBy (c -> c .getSubGroup ().getId () + "-" + c .getGroup ()))
237
+ .values ().stream ().filter (l -> l .size () > 1 ).forEach (l -> l .stream ().skip (1 ).forEach (em ::remove ));
238
+ userMemberships .stream ().collect (Collectors .groupingBy (c -> c .getUser ().getId () + "-" + c .getGroup ()))
239
+ .values ().stream ().filter (l -> l .size () > 1 ).forEach (l -> l .stream ().skip (1 ).forEach (em ::remove ));
240
+
241
+
242
+ final var membershipsByUser = userMemberships .stream ().collect (
243
+ Collectors .groupingBy (c -> c .getUser ().getId (), Collectors .mapping (c -> c .getGroup ().getId (), Collectors .toSet ())));
244
+ final var membershipsByGroup = groupMemberships .stream ().collect (
245
+ Collectors .groupingBy (c -> c .getGroup ().getId (), Collectors .mapping (c -> c .getSubGroup ().getId (), Collectors .toSet ())));
246
+
242
247
var memberships = 0 ;
243
248
244
249
// Persist users and memberships
@@ -247,7 +252,7 @@ private int persistUsersAndMemberships(final Map<String, UserOrg> users, final M
247
252
final var entity = createInternal (user , cacheUsers , cacheCompanies );
248
253
249
254
// Create/update membership
250
- final var cacheUserGroups = userMemberships .getOrDefault (user .getId (), Collections .emptySet ());
255
+ final var cacheUserGroups = membershipsByUser .getOrDefault (user .getId (), Collections .emptySet ());
251
256
for (final var group : user .getGroups ()) {
252
257
updateUserToGroupInternal (entity , cacheGroups .get (group ), cacheUserGroups );
253
258
}
@@ -267,7 +272,7 @@ private int persistUsersAndMemberships(final Map<String, UserOrg> users, final M
267
272
// Persist subgroups and memberships
268
273
for (final var group : groups .values ()) {
269
274
final var cachedGroup = cacheGroups .get (group .getId ());
270
- final var cacheSubGroups = groupMemberships .getOrDefault (group .getId (), Collections .emptySet ());
275
+ final var cacheSubGroups = membershipsByGroup .getOrDefault (group .getId (), Collections .emptySet ());
271
276
for (final var subGroup : group .getSubGroups ()) {
272
277
updateGroupToGroupInternal (cacheGroups .get (subGroup ), cachedGroup , cacheSubGroups );
273
278
}
@@ -298,36 +303,42 @@ private int persistUsersAndMemberships(final Map<String, UserOrg> users, final M
298
303
* @return the amount of persisted relations.
299
304
*/
300
305
private int persistProjectGroups (final Map <String , CacheGroup > groups ) {
301
- final var entities = em .createQuery ("FROM CacheProjectGroup WHERE group is not null" , CacheProjectGroup .class )
302
- .getResultList ().stream ().collect (
303
- Collectors .groupingBy (c -> c .getProject ().getId (),
304
- Collectors .mapping (c -> c .getGroup ().getId (),
305
- Collectors .toSet ())));
306
-
307
- final var allProjectGroup = cacheProjectGroupRepository .findAllProjectGroup ();
308
- for (final var projectGroup : allProjectGroup ) {
309
- final var projectId = (int ) projectGroup [0 ];
310
- final var groupId = (String ) projectGroup [1 ];
311
- final var projectGroupIds = entities .get (projectId );
312
- if ((projectGroupIds == null || !projectGroupIds .contains (groupId )) && groups .containsKey (groupId )) {
313
- // New association
314
- final var project = new Project ();
315
- project .setId (projectId );
316
- final var entity = new CacheProjectGroup ();
317
- entity .setProject (project );
318
- entity .setGroup (groups .get (groupId ));
319
- em .persist (entity );
320
- }
321
-
322
- // Purge the old entries
323
- if (projectGroupIds != null ) {
324
- projectGroupIds .remove (groupId );
306
+ final var cachedProjectGroups = em .createQuery ("FROM CacheProjectGroup WHERE group is not null" , CacheProjectGroup .class )
307
+ .getResultList ();
308
+
309
+ // Remove duplicates
310
+ cachedProjectGroups .stream ().collect (Collectors .groupingBy (c -> c .getProject ().getId () + "-" + c .getGroup ()))
311
+ .values ().stream ().filter (l -> l .size () > 1 ).forEach (l -> l .stream ().skip (1 ).forEach (em ::remove ));
312
+
313
+ // Create missing cached project groups as needed
314
+ final var cachedProjectGroupsByProject = cachedProjectGroups .stream ().collect (
315
+ Collectors .groupingBy (c -> c .getProject ().getId (),
316
+ Collectors .mapping (c -> c .getGroup ().getId (), Collectors .toSet ())));
317
+ final var allProjectGroups = cacheProjectGroupRepository .findAllProjectGroup ().stream ().collect (
318
+ Collectors .groupingBy (pg -> (Integer ) pg [0 ],
319
+ Collectors .mapping (pg -> (String ) pg [1 ], Collectors .toSet ())));
320
+ for (final var projectGroups : allProjectGroups .entrySet ()) {
321
+ final var projectId = projectGroups .getKey ();
322
+ final var groupIds = projectGroups .getValue ();
323
+ final var cachedProjectGroupIds = cachedProjectGroupsByProject .get (projectId );
324
+ for (final var groupId : groupIds ) {
325
+ if ((cachedProjectGroupIds == null || !cachedProjectGroupIds .contains (groupId )) && groups .containsKey (groupId )) {
326
+ // New association
327
+ final var project = new Project ();
328
+ project .setId (projectId );
329
+ final var entity = new CacheProjectGroup ();
330
+ entity .setProject (project );
331
+ entity .setGroup (groups .get (groupId ));
332
+ em .persist (entity );
333
+ } else if (cachedProjectGroupIds != null ) {
334
+ cachedProjectGroupIds .remove (groupId );
335
+ }
325
336
}
326
337
}
327
338
328
339
// Remove old memberships
329
- entities .keySet ().forEach (project ->
330
- entities .get (project ).forEach (group -> {
340
+ cachedProjectGroupsByProject .keySet ().forEach (project ->
341
+ cachedProjectGroupsByProject .get (project ).forEach (group -> {
331
342
log .info ("Deleting removed cache entry {}#{}-{}" , CacheProjectGroup .class .getSimpleName (), project , group );
332
343
em .createQuery ("DELETE FROM CacheProjectGroup WHERE project.id=:project and group.id=:group" )
333
344
.setParameter ("project" , project )
@@ -337,19 +348,19 @@ private int persistProjectGroups(final Map<String, CacheGroup> groups) {
337
348
);
338
349
339
350
340
- return allProjectGroup .size ();
351
+ return allProjectGroups .size ();
341
352
}
342
353
343
354
@ Override
344
355
public void removeGroupFromGroup (final GroupOrg subGroup , final GroupOrg group ) {
345
- em .createQuery ("DELETE FROM CacheMembership WHERE subGroup.id=:subGroup AND group.id=:group" )
346
- .setParameter (GROUP_ATTRIBUTE , group .getId ()).setParameter ("subGroup" , subGroup .getId ()). executeUpdate ( );
356
+ removeAll ( em .createQuery ("FROM CacheMembership WHERE subGroup.id=:subGroup AND group.id=:group" )
357
+ .setParameter (GROUP_ATTRIBUTE , group .getId ()).setParameter ("subGroup" , subGroup .getId ()));
347
358
}
348
359
349
360
@ Override
350
361
public void removeUserFromGroup (final UserOrg user , final GroupOrg group ) {
351
- em .createQuery ("DELETE FROM CacheMembership WHERE user.id=:user AND group.id=:group" )
352
- .setParameter (GROUP_ATTRIBUTE , group .getId ()).setParameter (USER_ATTRIBUTE , user .getId ()). executeUpdate ( );
362
+ removeAll ( em .createQuery ("FROM CacheMembership WHERE user.id=:user AND group.id=:group" )
363
+ .setParameter (GROUP_ATTRIBUTE , group .getId ()).setParameter (USER_ATTRIBUTE , user .getId ()));
353
364
}
354
365
355
366
private void deleteBatch (Class <?> cls , List <String > ids , Consumer <List <String >> batchConsumer ) {
0 commit comments