1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.persistence.jpa.dao;
20
21 import java.time.OffsetDateTime;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.stream.Collectors;
29 import javax.persistence.NoResultException;
30 import javax.persistence.Query;
31 import javax.persistence.TypedQuery;
32 import org.apache.commons.lang3.tuple.Pair;
33 import org.apache.syncope.common.lib.types.AnyTypeKind;
34 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
35 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
36 import org.apache.syncope.core.persistence.api.dao.AnyMatchDAO;
37 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
38 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
39 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
40 import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
41 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
42 import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
43 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
44 import org.apache.syncope.core.persistence.api.dao.UserDAO;
45 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
46 import org.apache.syncope.core.persistence.api.entity.AnyType;
47 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
48 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
49 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
50 import org.apache.syncope.core.persistence.api.entity.ExternalResource;
51 import org.apache.syncope.core.persistence.api.entity.Realm;
52 import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
53 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
54 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
55 import org.apache.syncope.core.persistence.api.entity.group.Group;
56 import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
57 import org.apache.syncope.core.persistence.api.entity.user.UDynGroupMembership;
58 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
59 import org.apache.syncope.core.persistence.api.entity.user.User;
60 import org.apache.syncope.core.persistence.api.search.SearchCondConverter;
61 import org.apache.syncope.core.persistence.api.search.SearchCondVisitor;
62 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADynGroupMembership;
63 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAMembership;
64 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
65 import org.apache.syncope.core.persistence.jpa.entity.group.JPATypeExtension;
66 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUDynGroupMembership;
67 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUMembership;
68 import org.apache.syncope.core.provisioning.api.event.EntityLifecycleEvent;
69 import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
70 import org.apache.syncope.core.spring.security.AuthContextUtils;
71 import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
72 import org.identityconnectors.framework.common.objects.SyncDeltaType;
73 import org.springframework.context.ApplicationEventPublisher;
74 import org.springframework.transaction.annotation.Transactional;
75
76 public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
77
78 public static final String UDYNMEMB_TABLE = "UDynGroupMembers";
79
80 public static final String ADYNMEMB_TABLE = "ADynGroupMembers";
81
82 protected final ApplicationEventPublisher publisher;
83
84 protected final AnyMatchDAO anyMatchDAO;
85
86 protected final PlainAttrDAO plainAttrDAO;
87
88 protected final UserDAO userDAO;
89
90 protected final AnyObjectDAO anyObjectDAO;
91
92 protected final AnySearchDAO anySearchDAO;
93
94 protected final SearchCondVisitor searchCondVisitor;
95
96 public JPAGroupDAO(
97 final AnyUtilsFactory anyUtilsFactory,
98 final ApplicationEventPublisher publisher,
99 final PlainSchemaDAO plainSchemaDAO,
100 final DerSchemaDAO derSchemaDAO,
101 final DynRealmDAO dynRealmDAO,
102 final AnyMatchDAO anyMatchDAO,
103 final PlainAttrDAO plainAttrDAO,
104 final UserDAO userDAO,
105 final AnyObjectDAO anyObjectDAO,
106 final AnySearchDAO searchDAO,
107 final SearchCondVisitor searchCondVisitor) {
108
109 super(anyUtilsFactory, plainSchemaDAO, derSchemaDAO, dynRealmDAO);
110 this.publisher = publisher;
111 this.anyMatchDAO = anyMatchDAO;
112 this.plainAttrDAO = plainAttrDAO;
113 this.userDAO = userDAO;
114 this.anyObjectDAO = anyObjectDAO;
115 this.anySearchDAO = searchDAO;
116 this.searchCondVisitor = searchCondVisitor;
117 }
118
119 @Override
120 protected AnyUtils init() {
121 return anyUtilsFactory.getInstance(AnyTypeKind.GROUP);
122 }
123
124 @Transactional(readOnly = true)
125 @Override
126 public String findKey(final String name) {
127 Query query = entityManager().createNativeQuery("SELECT id FROM " + JPAGroup.TABLE + " WHERE name=?");
128 query.setParameter(1, name);
129
130 String key = null;
131
132 for (Object resultKey : query.getResultList()) {
133 key = resultKey instanceof Object[]
134 ? (String) ((Object[]) resultKey)[0]
135 : ((String) resultKey);
136 }
137
138 return key;
139 }
140
141 @Transactional(readOnly = true)
142 @Override
143 public OffsetDateTime findLastChange(final String key) {
144 return findLastChange(key, JPAGroup.TABLE);
145 }
146
147 @Override
148 public int count() {
149 Query query = entityManager().createQuery(
150 "SELECT COUNT(e) FROM " + anyUtils().anyClass().getSimpleName() + " e");
151 return ((Number) query.getSingleResult()).intValue();
152 }
153
154 @Override
155 public Map<String, Integer> countByRealm() {
156 Query query = entityManager().createQuery(
157 "SELECT e.realm, COUNT(e) FROM " + anyUtils().anyClass().getSimpleName() + " e GROUP BY e.realm");
158
159 @SuppressWarnings("unchecked")
160 List<Object[]> results = query.getResultList();
161 return results.stream().collect(Collectors.toMap(
162 result -> ((Realm) result[0]).getFullPath(),
163 result -> ((Number) result[1]).intValue()));
164 }
165
166 @Transactional(readOnly = true)
167 @Override
168 public void securityChecks(
169 final Set<String> authRealms,
170 final String key,
171 final String realm) {
172
173
174
175 boolean authorized = authRealms.stream().anyMatch(authRealm -> realm.startsWith(authRealm)
176 || authRealm.equals(RealmUtils.getGroupOwnerRealm(realm, key)));
177
178
179 if (!authorized) {
180 authorized = findDynRealms(key).stream().anyMatch(authRealms::contains);
181 }
182
183 if (authRealms.isEmpty() || !authorized) {
184 throw new DelegatedAdministrationException(realm, AnyTypeKind.GROUP.name(), key);
185 }
186 }
187
188 @Override
189 protected void securityChecks(final Group group) {
190 Set<String> authRealms = AuthContextUtils.getAuthorizations().
191 getOrDefault(IdRepoEntitlement.GROUP_READ, Set.of());
192
193 securityChecks(authRealms, group.getKey(), group.getRealm().getFullPath());
194 }
195
196 @Override
197 public Group findByName(final String name) {
198 TypedQuery<Group> query = entityManager().createQuery(
199 "SELECT e FROM " + anyUtils().anyClass().getSimpleName() + " e WHERE e.name = :name", Group.class);
200 query.setParameter("name", name);
201
202 Group result = null;
203 try {
204 result = query.getSingleResult();
205 } catch (NoResultException e) {
206 LOG.debug("No group found with name {}", name, e);
207 }
208
209 return result;
210 }
211
212 @Override
213 public List<String> findKeysByNamePattern(final String pattern) {
214 Query query = entityManager().createNativeQuery(
215 "SELECT id FROM " + JPAGroup.TABLE + " WHERE LOWER(name) LIKE LOWER(?1)");
216 query.setParameter(1, pattern);
217
218 @SuppressWarnings("unchecked")
219 List<Object> raw = query.getResultList();
220 return raw.stream().map(Object::toString).collect(Collectors.toList());
221 }
222
223 @Transactional(readOnly = true)
224 @Override
225 public List<Group> findOwnedByUser(final String userKey) {
226 User owner = userDAO.find(userKey);
227 if (owner == null) {
228 return List.of();
229 }
230
231 StringBuilder queryString = new StringBuilder("SELECT e FROM ").append(anyUtils().anyClass().getSimpleName())
232 .append(" e WHERE e.userOwner=:owner ");
233 userDAO.findAllGroupKeys(owner).forEach(groupKey -> queryString
234 .append("OR e.groupOwner.id='").append(groupKey).append("' "));
235
236 TypedQuery<Group> query = entityManager().createQuery(queryString.toString(), Group.class);
237 query.setParameter("owner", owner);
238
239 return query.getResultList();
240 }
241
242 @Transactional(readOnly = true)
243 @Override
244 public List<Group> findOwnedByGroup(final String groupKey) {
245 Group owner = find(groupKey);
246 if (owner == null) {
247 return List.of();
248 }
249
250 TypedQuery<Group> query = entityManager().createQuery(
251 "SELECT e FROM " + anyUtils().anyClass().getSimpleName() + " e WHERE e.groupOwner=:owner", Group.class);
252 query.setParameter("owner", owner);
253
254 return query.getResultList();
255 }
256
257 @Override
258 public List<AMembership> findAMemberships(final Group group) {
259 TypedQuery<AMembership> query = entityManager().createQuery(
260 "SELECT e FROM " + JPAAMembership.class.getSimpleName() + " e WHERE e.rightEnd=:group",
261 AMembership.class);
262 query.setParameter("group", group);
263
264 return query.getResultList();
265 }
266
267 @Override
268 public List<UMembership> findUMemberships(final Group group) {
269 TypedQuery<UMembership> query = entityManager().createQuery(
270 "SELECT e FROM " + JPAUMembership.class.getSimpleName() + " e WHERE e.rightEnd=:group",
271 UMembership.class);
272 query.setParameter("group", group);
273
274 return query.getResultList();
275 }
276
277 @Override
278 public List<Group> findAll(final int page, final int itemsPerPage) {
279 TypedQuery<Group> query = entityManager().createQuery(
280 "SELECT e FROM " + anyUtils().anyClass().getSimpleName() + " e ORDER BY e.id", Group.class);
281 query.setFirstResult(itemsPerPage * (page <= 0 ? 0 : page - 1));
282 query.setMaxResults(itemsPerPage);
283
284 return query.getResultList();
285 }
286
287 @Override
288 public List<String> findAllKeys(final int page, final int itemsPerPage) {
289 return findAllKeys(JPAGroup.TABLE, page, itemsPerPage);
290 }
291
292 protected SearchCond buildDynMembershipCond(final String baseCondFIQL) {
293 return SearchCondConverter.convert(searchCondVisitor, baseCondFIQL);
294 }
295
296 @Override
297 public Group saveAndRefreshDynMemberships(final Group group) {
298 Group merged = save(group);
299
300
301 clearUDynMembers(merged);
302 if (merged.getUDynMembership() != null) {
303 SearchCond cond = buildDynMembershipCond(merged.getUDynMembership().getFIQLCond());
304 int count = anySearchDAO.count(
305 merged.getRealm(), true, Set.of(merged.getRealm().getFullPath()), cond, AnyTypeKind.USER);
306 for (int page = 1; page <= (count / AnyDAO.DEFAULT_PAGE_SIZE) + 1; page++) {
307 List<User> matching = anySearchDAO.search(
308 merged.getRealm(),
309 true,
310 Set.of(merged.getRealm().getFullPath()),
311 cond,
312 page,
313 AnyDAO.DEFAULT_PAGE_SIZE,
314 List.of(),
315 AnyTypeKind.USER);
316
317 matching.forEach(user -> {
318 Query insert = entityManager().createNativeQuery("INSERT INTO " + UDYNMEMB_TABLE + " VALUES(?, ?)");
319 insert.setParameter(1, user.getKey());
320 insert.setParameter(2, merged.getKey());
321 insert.executeUpdate();
322
323 publisher.publishEvent(
324 new EntityLifecycleEvent<>(this, SyncDeltaType.UPDATE, user, AuthContextUtils.getDomain()));
325 });
326 }
327 }
328 clearADynMembers(merged);
329 merged.getADynMemberships().forEach(memb -> {
330 SearchCond cond = buildDynMembershipCond(memb.getFIQLCond());
331 int count = anySearchDAO.count(
332 merged.getRealm(), true, Set.of(merged.getRealm().getFullPath()), cond, AnyTypeKind.ANY_OBJECT);
333 for (int page = 1; page <= (count / AnyDAO.DEFAULT_PAGE_SIZE) + 1; page++) {
334 List<AnyObject> matching = anySearchDAO.search(
335 merged.getRealm(),
336 true,
337 Set.of(merged.getRealm().getFullPath()),
338 cond,
339 page,
340 AnyDAO.DEFAULT_PAGE_SIZE,
341 List.of(),
342 AnyTypeKind.ANY_OBJECT);
343
344 matching.forEach(any -> {
345 Query insert = entityManager().createNativeQuery(
346 "INSERT INTO " + ADYNMEMB_TABLE + " VALUES(?, ?, ?)");
347 insert.setParameter(1, any.getType().getKey());
348 insert.setParameter(2, any.getKey());
349 insert.setParameter(3, merged.getKey());
350 insert.executeUpdate();
351
352 publisher.publishEvent(
353 new EntityLifecycleEvent<>(this, SyncDeltaType.UPDATE, any, AuthContextUtils.getDomain()));
354 });
355 }
356 });
357
358 dynRealmDAO.refreshDynMemberships(merged);
359
360 return merged;
361 }
362
363 @Override
364 public void delete(final Group group) {
365 dynRealmDAO.removeDynMemberships(group.getKey());
366
367 findAMemberships(group).forEach(membership -> {
368 AnyObject leftEnd = membership.getLeftEnd();
369 leftEnd.remove(membership);
370 membership.setRightEnd(null);
371 leftEnd.getPlainAttrs(membership).forEach(attr -> {
372 leftEnd.remove(attr);
373 attr.setOwner(null);
374 attr.setMembership(null);
375 plainAttrDAO.delete(attr);
376 });
377
378 anyObjectDAO.save(leftEnd);
379 publisher.publishEvent(
380 new EntityLifecycleEvent<>(this, SyncDeltaType.UPDATE, leftEnd, AuthContextUtils.getDomain()));
381 });
382
383 findUMemberships(group).forEach(membership -> {
384 User leftEnd = membership.getLeftEnd();
385 leftEnd.remove(membership);
386 membership.setRightEnd(null);
387 leftEnd.getPlainAttrs(membership).forEach(attr -> {
388 leftEnd.remove(attr);
389 attr.setOwner(null);
390 attr.setMembership(null);
391
392 plainAttrDAO.delete(attr);
393 });
394
395 userDAO.save(leftEnd);
396 publisher.publishEvent(
397 new EntityLifecycleEvent<>(this, SyncDeltaType.UPDATE, leftEnd, AuthContextUtils.getDomain()));
398 });
399
400 clearUDynMembers(group);
401 clearADynMembers(group);
402
403 entityManager().remove(group);
404 }
405
406 @Override
407 public List<TypeExtension> findTypeExtensions(final AnyTypeClass anyTypeClass) {
408 TypedQuery<TypeExtension> query = entityManager().createQuery(
409 "SELECT e FROM " + JPATypeExtension.class.getSimpleName()
410 + " e WHERE :anyTypeClass MEMBER OF e.auxClasses", TypeExtension.class);
411 query.setParameter("anyTypeClass", anyTypeClass);
412
413 return query.getResultList();
414 }
415
416 @Transactional(readOnly = true)
417 @Override
418 public boolean existsAMembership(final String anyObjectKey, final String groupKey) {
419 Query query = entityManager().createNativeQuery(
420 "SELECT COUNT(*) FROM " + JPAAMembership.TABLE + " WHERE group_id=? AND anyobject_it=?");
421 query.setParameter(1, groupKey);
422 query.setParameter(2, anyObjectKey);
423
424 return ((Number) query.getSingleResult()).intValue() > 0;
425 }
426
427 @Transactional(readOnly = true)
428 @Override
429 public boolean existsUMembership(final String userKey, final String groupKey) {
430 Query query = entityManager().createNativeQuery(
431 "SELECT COUNT(*) FROM " + JPAUMembership.TABLE + " WHERE group_id=? AND user_id=?");
432 query.setParameter(1, groupKey);
433 query.setParameter(2, userKey);
434
435 return ((Number) query.getSingleResult()).intValue() > 0;
436 }
437
438 @Transactional(readOnly = true)
439 @Override
440 @SuppressWarnings("unchecked")
441 public List<String> findAMembers(final String groupKey) {
442 Query query = entityManager().createNativeQuery(
443 "SELECT anyObject_id FROM " + JPAAMembership.TABLE + " WHERE group_id=?");
444 query.setParameter(1, groupKey);
445
446 List<String> result = new ArrayList<>();
447 query.getResultList().stream().map(key -> key instanceof Object[]
448 ? (String) ((Object[]) key)[0]
449 : ((String) key)).
450 forEach(item -> result.add((String) item));
451 return result;
452 }
453
454 @Transactional(readOnly = true)
455 @Override
456 @SuppressWarnings("unchecked")
457 public List<String> findUMembers(final String groupKey) {
458 Query query = entityManager().createNativeQuery(
459 "SELECT user_id FROM " + JPAUMembership.TABLE + " WHERE group_id=?");
460 query.setParameter(1, groupKey);
461
462 List<String> result = new ArrayList<>();
463 query.getResultList().stream().map(key -> key instanceof Object[]
464 ? (String) ((Object[]) key)[0]
465 : ((String) key)).
466 forEach(item -> result.add((String) item));
467 return result;
468 }
469
470 @Override
471 @SuppressWarnings("unchecked")
472 public List<String> findADynMembers(final Group group) {
473 List<String> result = new ArrayList<>();
474
475 group.getADynMemberships().forEach(memb -> {
476 Query query = entityManager().createNativeQuery(
477 "SELECT any_id FROM " + ADYNMEMB_TABLE + " WHERE group_id=? AND anyType_id=?");
478 query.setParameter(1, group.getKey());
479 query.setParameter(2, memb.getAnyType().getKey());
480
481 query.getResultList().stream().map(key -> key instanceof Object[]
482 ? (String) ((Object[]) key)[0]
483 : ((String) key)).
484 filter(anyObject -> !result.contains((String) anyObject)).
485 forEach(anyObject -> result.add((String) anyObject));
486 });
487
488 return result;
489 }
490
491 @Override
492 public int countAMembers(final String groupKey) {
493 Query query = entityManager().createNativeQuery(
494 "SELECT COUNT(anyObject_id) FROM " + JPAAMembership.TABLE + " WHERE group_id=?");
495 query.setParameter(1, groupKey);
496
497 return ((Number) query.getSingleResult()).intValue();
498 }
499
500 @Override
501 public int countUMembers(final String groupKey) {
502 Query query = entityManager().createNativeQuery(
503 "SELECT COUNT(user_id) FROM " + JPAUMembership.TABLE + " WHERE group_id=?");
504 query.setParameter(1, groupKey);
505
506 return ((Number) query.getSingleResult()).intValue();
507 }
508
509 @Override
510 public int countADynMembers(final Group group) {
511 Query query = entityManager().createNativeQuery(
512 "SELECT COUNT(any_id) FROM " + ADYNMEMB_TABLE + " WHERE group_id=?");
513 query.setParameter(1, group.getKey());
514
515 return ((Number) query.getSingleResult()).intValue();
516 }
517
518 @Override
519 public int countUDynMembers(final Group group) {
520 if (group.getUDynMembership() == null) {
521 return 0;
522 }
523
524 Query query = entityManager().createNativeQuery(
525 "SELECT COUNT(any_id) FROM " + UDYNMEMB_TABLE + " WHERE group_id=?");
526 query.setParameter(1, group.getKey());
527
528 return ((Number) query.getSingleResult()).intValue();
529 }
530
531 @Override
532 public void clearADynMembers(final Group group) {
533 Query delete = entityManager().createNativeQuery("DELETE FROM " + ADYNMEMB_TABLE + " WHERE group_id=?");
534 delete.setParameter(1, group.getKey());
535 delete.executeUpdate();
536 }
537
538 protected List<ADynGroupMembership> findWithADynMemberships(final AnyType anyType) {
539 TypedQuery<ADynGroupMembership> query = entityManager().createQuery(
540 "SELECT e FROM " + JPAADynGroupMembership.class.getSimpleName() + " e WHERE e.anyType=:anyType",
541 ADynGroupMembership.class);
542 query.setParameter("anyType", anyType);
543 return query.getResultList();
544 }
545
546 @Transactional
547 @Override
548 public Pair<Set<String>, Set<String>> refreshDynMemberships(final AnyObject anyObject) {
549 Query query = entityManager().createNativeQuery(
550 "SELECT group_id FROM " + JPAGroupDAO.ADYNMEMB_TABLE + " WHERE any_id=?");
551 query.setParameter(1, anyObject.getKey());
552
553 Set<String> before = new HashSet<>();
554 Set<String> after = new HashSet<>();
555 findWithADynMemberships(anyObject.getType()).forEach(memb -> {
556 boolean matches = anyMatchDAO.matches(anyObject, buildDynMembershipCond(memb.getFIQLCond()));
557 if (matches) {
558 after.add(memb.getGroup().getKey());
559 }
560
561 Query find = entityManager().createNativeQuery(
562 "SELECT any_id FROM " + ADYNMEMB_TABLE + " WHERE group_id=? AND any_id=?");
563 find.setParameter(1, memb.getGroup().getKey());
564 find.setParameter(2, anyObject.getKey());
565 boolean existing = !find.getResultList().isEmpty();
566 if (existing) {
567 before.add(memb.getGroup().getKey());
568 }
569
570 if (matches && !existing) {
571 Query insert = entityManager().createNativeQuery(
572 "INSERT INTO " + ADYNMEMB_TABLE + " VALUES(?, ?, ?)");
573 insert.setParameter(1, anyObject.getType().getKey());
574 insert.setParameter(2, anyObject.getKey());
575 insert.setParameter(3, memb.getGroup().getKey());
576 insert.executeUpdate();
577 } else if (!matches && existing) {
578 Query delete = entityManager().createNativeQuery(
579 "DELETE FROM " + ADYNMEMB_TABLE + " WHERE group_id=? AND any_id=?");
580 delete.setParameter(1, memb.getGroup().getKey());
581 delete.setParameter(2, anyObject.getKey());
582 delete.executeUpdate();
583 }
584
585 publisher.publishEvent(new EntityLifecycleEvent<>(
586 this, SyncDeltaType.UPDATE, memb.getGroup(), AuthContextUtils.getDomain()));
587 });
588
589 return Pair.of(before, after);
590 }
591
592 @Override
593 public Set<String> removeDynMemberships(final AnyObject anyObject) {
594 List<Group> dynGroups = anyObjectDAO.findDynGroups(anyObject.getKey());
595
596 Query delete = entityManager().createNativeQuery("DELETE FROM " + ADYNMEMB_TABLE + " WHERE any_id=?");
597 delete.setParameter(1, anyObject.getKey());
598 delete.executeUpdate();
599
600 Set<String> before = new HashSet<>();
601 dynGroups.forEach(group -> {
602 before.add(group.getKey());
603
604 publisher.publishEvent(new EntityLifecycleEvent<>(
605 this, SyncDeltaType.UPDATE, group, AuthContextUtils.getDomain()));
606 });
607
608 return before;
609 }
610
611 @Override
612 @SuppressWarnings("unchecked")
613 public List<String> findUDynMembers(final Group group) {
614 if (group.getUDynMembership() == null) {
615 return List.of();
616 }
617
618 Query query = entityManager().createNativeQuery(
619 "SELECT any_id FROM " + UDYNMEMB_TABLE + " WHERE group_id=?");
620 query.setParameter(1, group.getKey());
621
622 List<String> result = new ArrayList<>();
623 query.getResultList().stream().map(key -> key instanceof Object[]
624 ? (String) ((Object[]) key)[0]
625 : ((String) key)).
626 forEach(user -> result.add((String) user));
627 return result;
628 }
629
630 @Override
631 public void clearUDynMembers(final Group group) {
632 Query delete = entityManager().createNativeQuery("DELETE FROM " + UDYNMEMB_TABLE + " WHERE group_id=?");
633 delete.setParameter(1, group.getKey());
634 delete.executeUpdate();
635 }
636
637 protected List<UDynGroupMembership> findWithUDynMemberships() {
638 TypedQuery<UDynGroupMembership> query = entityManager().createQuery(
639 "SELECT e FROM " + JPAUDynGroupMembership.class.getSimpleName() + " e",
640 UDynGroupMembership.class);
641
642 return query.getResultList();
643 }
644
645 @Transactional
646 @Override
647 public Pair<Set<String>, Set<String>> refreshDynMemberships(final User user) {
648 Query query = entityManager().createNativeQuery(
649 "SELECT group_id FROM " + JPAGroupDAO.UDYNMEMB_TABLE + " WHERE any_id=?");
650 query.setParameter(1, user.getKey());
651
652 Set<String> before = new HashSet<>();
653 Set<String> after = new HashSet<>();
654 findWithUDynMemberships().forEach(memb -> {
655 boolean matches = anyMatchDAO.matches(user, buildDynMembershipCond(memb.getFIQLCond()));
656 if (matches) {
657 after.add(memb.getGroup().getKey());
658 }
659
660 Query find = entityManager().createNativeQuery(
661 "SELECT any_id FROM " + UDYNMEMB_TABLE + " WHERE group_id=? AND any_id=?");
662 find.setParameter(1, memb.getGroup().getKey());
663 find.setParameter(2, user.getKey());
664 boolean existing = !find.getResultList().isEmpty();
665 if (existing) {
666 before.add(memb.getGroup().getKey());
667 }
668
669 if (matches && !existing) {
670 Query insert = entityManager().createNativeQuery(
671 "INSERT INTO " + UDYNMEMB_TABLE + " VALUES(?, ?)");
672 insert.setParameter(1, user.getKey());
673 insert.setParameter(2, memb.getGroup().getKey());
674 insert.executeUpdate();
675 } else if (!matches && existing) {
676 Query delete = entityManager().createNativeQuery(
677 "DELETE FROM " + UDYNMEMB_TABLE + " WHERE group_id=? AND any_id=?");
678 delete.setParameter(1, memb.getGroup().getKey());
679 delete.setParameter(2, user.getKey());
680 delete.executeUpdate();
681 }
682
683 publisher.publishEvent(new EntityLifecycleEvent<>(
684 this, SyncDeltaType.UPDATE, memb.getGroup(), AuthContextUtils.getDomain()));
685 });
686
687 return Pair.of(before, after);
688 }
689
690 @Override
691 public Set<String> removeDynMemberships(final User user) {
692 List<Group> dynGroups = userDAO.findDynGroups(user.getKey());
693
694 Query delete = entityManager().createNativeQuery("DELETE FROM " + UDYNMEMB_TABLE + " WHERE any_id=?");
695 delete.setParameter(1, user.getKey());
696 delete.executeUpdate();
697
698 Set<String> before = new HashSet<>();
699 dynGroups.forEach(group -> {
700 before.add(group.getKey());
701
702 publisher.publishEvent(new EntityLifecycleEvent<>(
703 this, SyncDeltaType.UPDATE, group, AuthContextUtils.getDomain()));
704 });
705
706 return before;
707 }
708
709 @Transactional(readOnly = true)
710 @Override
711 public Collection<String> findAllResourceKeys(final String key) {
712 return find(key).getResources().stream().map(ExternalResource::getKey).collect(Collectors.toList());
713 }
714 }