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.logic;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.concurrent.ConcurrentHashMap;
25  import org.apache.commons.lang3.tuple.Pair;
26  import org.apache.syncope.common.lib.SyncopeClientException;
27  import org.apache.syncope.common.lib.request.AnyCR;
28  import org.apache.syncope.common.lib.request.AnyObjectCR;
29  import org.apache.syncope.common.lib.request.AnyUR;
30  import org.apache.syncope.common.lib.request.GroupCR;
31  import org.apache.syncope.common.lib.request.UserCR;
32  import org.apache.syncope.common.lib.to.AnyTO;
33  import org.apache.syncope.common.lib.to.PropagationStatus;
34  import org.apache.syncope.common.lib.to.ProvisioningResult;
35  import org.apache.syncope.common.lib.types.ClientExceptionType;
36  import org.apache.syncope.core.logic.api.LogicActions;
37  import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
38  import org.apache.syncope.core.persistence.api.dao.RealmDAO;
39  import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
40  import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
41  import org.apache.syncope.core.persistence.api.entity.AnyType;
42  import org.apache.syncope.core.persistence.api.entity.Realm;
43  import org.apache.syncope.core.provisioning.java.utils.TemplateUtils;
44  import org.apache.syncope.core.spring.implementation.ImplementationManager;
45  
46  public abstract class AbstractAnyLogic<TO extends AnyTO, C extends AnyCR, U extends AnyUR>
47          extends AbstractResourceAssociator<TO> {
48  
49      protected static final String REST_CONTEXT = "REST";
50  
51      protected final RealmDAO realmDAO;
52  
53      protected final AnyTypeDAO anyTypeDAO;
54  
55      protected final TemplateUtils templateUtils;
56  
57      protected final Map<String, LogicActions> perContextActions = new ConcurrentHashMap<>();
58  
59      public AbstractAnyLogic(
60              final RealmDAO realmDAO,
61              final AnyTypeDAO anyTypeDAO,
62              final TemplateUtils templateUtils) {
63  
64          this.realmDAO = realmDAO;
65          this.anyTypeDAO = anyTypeDAO;
66          this.templateUtils = templateUtils;
67      }
68  
69      protected List<LogicActions> getActions(final Realm realm) {
70          List<LogicActions> result = new ArrayList<>();
71  
72          realm.getActions().forEach(impl -> {
73              try {
74                  result.add(ImplementationManager.build(
75                          impl,
76                          () -> perContextActions.get(impl.getKey()),
77                          instance -> perContextActions.put(impl.getKey(), instance)));
78              } catch (Exception e) {
79                  LOG.warn("While building {}", impl, e);
80              }
81          });
82  
83          return result;
84      }
85  
86      @SuppressWarnings("unchecked")
87      protected Pair<C, List<LogicActions>> beforeCreate(final C input) {
88          Realm realm = realmDAO.findByFullPath(input.getRealm());
89          if (realm == null) {
90              SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
91              sce.getElements().add(input.getRealm());
92              throw sce;
93          }
94  
95          AnyType anyType = null;
96          if (input instanceof UserCR) {
97              anyType = anyTypeDAO.findUser();
98          } else if (input instanceof GroupCR) {
99              anyType = anyTypeDAO.findGroup();
100         } else if (input instanceof AnyObjectCR) {
101             anyType = anyTypeDAO.find(((AnyObjectCR) input).getType());
102         }
103         if (anyType == null) {
104             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidAnyType);
105             throw sce;
106         }
107 
108         C anyCR = input;
109 
110         templateUtils.apply(anyCR, realm.getTemplate(anyType));
111 
112         List<LogicActions> actions = getActions(realm);
113         for (LogicActions action : actions) {
114             anyCR = action.beforeCreate(anyCR);
115         }
116 
117         LOG.debug("Input: {}\nOutput: {}\n", input, anyCR);
118 
119         return Pair.of(anyCR, actions);
120     }
121 
122     @SuppressWarnings("unchecked")
123     protected Pair<U, List<LogicActions>> beforeUpdate(final U input, final String realmPath) {
124         Realm realm = realmDAO.findByFullPath(realmPath);
125         if (realm == null) {
126             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
127             sce.getElements().add(realmPath);
128             throw sce;
129         }
130 
131         U update = input;
132 
133         List<LogicActions> actions = getActions(realm);
134         for (LogicActions action : actions) {
135             update = action.beforeUpdate(update);
136         }
137 
138         LOG.debug("Input: {}\nOutput: {}\n", input, update);
139 
140         return Pair.of(update, actions);
141     }
142 
143     @SuppressWarnings("unchecked")
144     protected Pair<TO, List<LogicActions>> beforeDelete(final TO input) {
145         Realm realm = realmDAO.findByFullPath(input.getRealm());
146         if (realm == null) {
147             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
148             sce.getElements().add(input.getRealm());
149             throw sce;
150         }
151 
152         TO any = input;
153 
154         List<LogicActions> actions = getActions(realm);
155         for (LogicActions action : actions) {
156             any = action.beforeDelete(any);
157         }
158 
159         LOG.debug("Input: {}\nOutput: {}\n", input, any);
160 
161         return Pair.of(any, actions);
162     }
163 
164     @SuppressWarnings("unchecked")
165     protected ProvisioningResult<TO> afterCreate(
166             final TO input, final List<PropagationStatus> statuses, final List<LogicActions> actions) {
167 
168         TO any = input;
169 
170         for (LogicActions action : actions) {
171             any = action.afterCreate(any, statuses);
172         }
173 
174         ProvisioningResult<TO> result = new ProvisioningResult<>();
175         result.setEntity(any);
176         result.getPropagationStatuses().addAll(statuses);
177 
178         return result;
179     }
180 
181     protected ProvisioningResult<TO> afterUpdate(
182             final TO input,
183             final List<PropagationStatus> statuses,
184             final List<LogicActions> actions) {
185 
186         TO any = input;
187 
188         for (LogicActions action : actions) {
189             any = action.afterUpdate(any, statuses);
190         }
191 
192         ProvisioningResult<TO> result = new ProvisioningResult<>();
193         result.setEntity(any);
194         result.getPropagationStatuses().addAll(statuses);
195 
196         return result;
197     }
198 
199     @SuppressWarnings("unchecked")
200     protected ProvisioningResult<TO> afterDelete(
201             final TO input, final List<PropagationStatus> statuses, final List<LogicActions> actions) {
202 
203         TO any = input;
204 
205         for (LogicActions action : actions) {
206             any = action.afterDelete(any, statuses);
207         }
208 
209         ProvisioningResult<TO> result = new ProvisioningResult<>();
210         result.setEntity(any);
211         result.getPropagationStatuses().addAll(statuses);
212 
213         return result;
214     }
215 
216     public abstract TO read(String key);
217 
218     public abstract Pair<Integer, List<TO>> search(
219             SearchCond searchCond,
220             int page, int size, List<OrderByClause> orderBy,
221             String realm,
222             boolean recursive,
223             boolean details);
224 
225     public abstract ProvisioningResult<TO> update(U updateReq, boolean nullPriorityAsync);
226 
227     public abstract ProvisioningResult<TO> delete(String key, boolean nullPriorityAsync);
228 }