View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.persistence.jpa.dao;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import javax.persistence.Query;
24  import javax.persistence.TypedQuery;
25  import org.apache.syncope.core.persistence.api.dao.AnyMatchDAO;
26  import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
27  import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
28  import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
29  import org.apache.syncope.core.persistence.api.dao.GroupDAO;
30  import org.apache.syncope.core.persistence.api.dao.UserDAO;
31  import org.apache.syncope.core.persistence.api.entity.Any;
32  import org.apache.syncope.core.persistence.api.entity.DynRealm;
33  import org.apache.syncope.core.persistence.api.search.SearchCondConverter;
34  import org.apache.syncope.core.persistence.api.search.SearchCondVisitor;
35  import org.apache.syncope.core.persistence.jpa.entity.JPADynRealm;
36  import org.apache.syncope.core.provisioning.api.event.EntityLifecycleEvent;
37  import org.apache.syncope.core.spring.security.AuthContextUtils;
38  import org.identityconnectors.framework.common.objects.SyncDeltaType;
39  import org.springframework.context.ApplicationEventPublisher;
40  import org.springframework.transaction.annotation.Transactional;
41  
42  public class JPADynRealmDAO extends AbstractDAO<DynRealm> implements DynRealmDAO {
43  
44      public static final String DYNMEMB_TABLE = "DynRealmMembers";
45  
46      protected final ApplicationEventPublisher publisher;
47  
48      protected final UserDAO userDAO;
49  
50      protected final GroupDAO groupDAO;
51  
52      protected final AnyObjectDAO anyObjectDAO;
53  
54      protected final AnySearchDAO searchDAO;
55  
56      protected final AnyMatchDAO anyMatchDAO;
57  
58      protected final SearchCondVisitor searchCondVisitor;
59  
60      public JPADynRealmDAO(
61              final ApplicationEventPublisher publisher,
62              final UserDAO userDAO,
63              final GroupDAO groupDAO,
64              final AnyObjectDAO anyObjectDAO,
65              final AnySearchDAO searchDAO,
66              final AnyMatchDAO anyMatchDAO,
67              final SearchCondVisitor searchCondVisitor) {
68  
69          this.publisher = publisher;
70          this.userDAO = userDAO;
71          this.groupDAO = groupDAO;
72          this.anyObjectDAO = anyObjectDAO;
73          this.searchDAO = searchDAO;
74          this.anyMatchDAO = anyMatchDAO;
75          this.searchCondVisitor = searchCondVisitor;
76      }
77  
78      @Override
79      public DynRealm find(final String key) {
80          return entityManager().find(JPADynRealm.class, key);
81      }
82  
83      @Override
84      public List<DynRealm> findAll() {
85          TypedQuery<DynRealm> query = entityManager().createQuery(
86                  "SELECT e FROM " + JPADynRealm.class.getSimpleName() + " e ", DynRealm.class);
87          return query.getResultList();
88      }
89  
90      @Override
91      public DynRealm save(final DynRealm dynRealm) {
92          return entityManager().merge(dynRealm);
93      }
94  
95      @SuppressWarnings("unchecked")
96      protected List<String> clearDynMembers(final DynRealm dynRealm) {
97          Query find = entityManager().createNativeQuery(
98                  "SELECT any_id FROM " + DYNMEMB_TABLE + " WHERE dynRealm_id=?");
99          find.setParameter(1, dynRealm.getKey());
100 
101         List<String> cleared = new ArrayList<>();
102         find.getResultList().stream().map(key -> key instanceof Object[]
103                 ? (String) ((Object[]) key)[0]
104                 : ((String) key)).
105                 forEach(key -> cleared.add((String) key));
106 
107         Query delete = entityManager().createNativeQuery("DELETE FROM " + DYNMEMB_TABLE + " WHERE dynRealm_id=?");
108         delete.setParameter(1, dynRealm.getKey());
109         delete.executeUpdate();
110 
111         return cleared;
112     }
113 
114     protected void notifyDynMembershipRemoval(final List<String> anyKeys) {
115         anyKeys.forEach(key -> {
116             Any<?> any = userDAO.find(key);
117             if (any == null) {
118                 any = groupDAO.find(key);
119             }
120             if (any == null) {
121                 any = anyObjectDAO.find(key);
122             }
123             if (any != null) {
124                 publisher.publishEvent(
125                         new EntityLifecycleEvent<>(this, SyncDeltaType.UPDATE, any, AuthContextUtils.getDomain()));
126             }
127         });
128     }
129 
130     @Override
131     public DynRealm saveAndRefreshDynMemberships(final DynRealm dynRealm) {
132         DynRealm merged = save(dynRealm);
133 
134         // refresh dynamic memberships
135         List<String> cleared = clearDynMembers(merged);
136 
137         merged.getDynMemberships().stream().map(memb -> searchDAO.search(
138                 SearchCondConverter.convert(searchCondVisitor, memb.getFIQLCond()), memb.getAnyType().getKind())).
139                 forEach(matching -> matching.forEach(any -> {
140 
141             Query insert = entityManager().createNativeQuery("INSERT INTO " + DYNMEMB_TABLE + " VALUES(?, ?)");
142             insert.setParameter(1, any.getKey());
143             insert.setParameter(2, merged.getKey());
144             insert.executeUpdate();
145 
146             publisher.publishEvent(
147                     new EntityLifecycleEvent<>(this, SyncDeltaType.UPDATE, any, AuthContextUtils.getDomain()));
148             cleared.remove(any.getKey());
149         }));
150 
151         notifyDynMembershipRemoval(cleared);
152 
153         return merged;
154     }
155 
156     @Override
157     public void delete(final String key) {
158         DynRealm dynRealm = find(key);
159         if (dynRealm == null) {
160             return;
161         }
162 
163         notifyDynMembershipRemoval(clearDynMembers(dynRealm));
164 
165         entityManager().remove(dynRealm);
166     }
167 
168     @Transactional
169     @Override
170     public void refreshDynMemberships(final Any<?> any) {
171         findAll().forEach(dynRealm -> dynRealm.getDynMembership(any.getType()).ifPresent(memb -> {
172             boolean matches = anyMatchDAO.matches(
173                     any, SearchCondConverter.convert(searchCondVisitor, memb.getFIQLCond()));
174 
175             Query find = entityManager().createNativeQuery(
176                     "SELECT dynRealm_id FROM " + DYNMEMB_TABLE + " WHERE any_id=?");
177             find.setParameter(1, any.getKey());
178             boolean existing = !find.getResultList().isEmpty();
179 
180             if (matches && !existing) {
181                 Query insert = entityManager().
182                         createNativeQuery("INSERT INTO " + DYNMEMB_TABLE + " VALUES(?, ?)");
183                 insert.setParameter(1, any.getKey());
184                 insert.setParameter(2, dynRealm.getKey());
185                 insert.executeUpdate();
186             } else if (!matches && existing) {
187                 Query delete = entityManager().createNativeQuery(
188                         "DELETE FROM " + DYNMEMB_TABLE + " WHERE dynRealm_id=? AND any_id=?");
189                 delete.setParameter(1, dynRealm.getKey());
190                 delete.setParameter(2, any.getKey());
191                 delete.executeUpdate();
192             }
193         }));
194     }
195 
196     @Override
197     public void removeDynMemberships(final String anyKey) {
198         Query delete = entityManager().createNativeQuery("DELETE FROM " + DYNMEMB_TABLE + " WHERE any_id=?");
199         delete.setParameter(1, anyKey);
200         delete.executeUpdate();
201     }
202 }