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.provisioning.api;
20  
21  import java.io.Serializable;
22  import java.util.Collection;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.Map;
26  import java.util.Set;
27  import java.util.stream.Stream;
28  import org.apache.syncope.common.lib.types.ResourceOperation;
29  
30  /**
31   * Encapsulates operations to be performed on various resources.
32   *
33   * @param <T> key for propagation: could be simple resource or pair (resource, connObjectKeyValue) for linked accounts
34   */
35  public class PropagationByResource<T extends Serializable> implements Serializable {
36  
37      private static final long serialVersionUID = -5699740428104336636L;
38  
39      /**
40       * Resources for creation.
41       */
42      private final Set<T> toBeCreated;
43  
44      /**
45       * Resources for update.
46       */
47      private final Set<T> toBeUpdated;
48  
49      /**
50       * Resources for deletion.
51       */
52      private final Set<T> toBeDeleted;
53  
54      /**
55       * Mapping target resource names to old ConnObjectKeys (when applicable).
56       */
57      private final Map<String, String> oldConnObjectKeys;
58  
59      /**
60       * Default constructor.
61       */
62      public PropagationByResource() {
63          toBeCreated = new HashSet<>();
64          toBeUpdated = new HashSet<>();
65          toBeDeleted = new HashSet<>();
66  
67          oldConnObjectKeys = new HashMap<>();
68      }
69  
70      /**
71       * Avoid potential conflicts by not doing create or update on any resource for which a delete is requested, and by
72       * not doing any create on any resource for which an update is requested.
73       */
74      public final void purge() {
75          toBeCreated.removeAll(toBeDeleted);
76          toBeCreated.removeAll(toBeUpdated);
77  
78          toBeUpdated.removeAll(toBeDeleted);
79      }
80  
81      /**
82       * Add an element.
83       *
84       * @param type resource operation type
85       * @param key target resource
86       * @return whether the operation was successful or not
87       */
88      public final boolean add(final ResourceOperation type, final T key) {
89          Set<T> set;
90          switch (type) {
91              case CREATE:
92                  set = toBeCreated;
93                  break;
94  
95              case UPDATE:
96                  set = toBeUpdated;
97                  break;
98  
99              case DELETE:
100             default:
101                 set = toBeDeleted;
102                 break;
103         }
104 
105         return set.add(key);
106     }
107 
108     /**
109      * Add some elements.
110      *
111      * @param type resource operation type
112      * @param keys target resources
113      * @return whether the operation was successful or not
114      */
115     public boolean addAll(final ResourceOperation type, final Collection<T> keys) {
116         Set<T> set;
117         switch (type) {
118             case CREATE:
119                 set = toBeCreated;
120                 break;
121 
122             case UPDATE:
123                 set = toBeUpdated;
124                 break;
125 
126             case DELETE:
127             default:
128                 set = toBeDeleted;
129                 break;
130         }
131 
132         return set.addAll(keys);
133     }
134 
135     /**
136      * Remove an element.
137      *
138      * @param type resource operation type
139      * @param key target resource
140      * @return whether the operation was successful or not
141      */
142     public final boolean remove(final ResourceOperation type, final T key) {
143         boolean result = false;
144 
145         switch (type) {
146             case CREATE:
147                 result = toBeCreated.remove(key);
148                 break;
149 
150             case UPDATE:
151                 result = toBeUpdated.remove(key);
152                 break;
153 
154             case DELETE:
155                 result = toBeDeleted.remove(key);
156                 break;
157 
158             default:
159         }
160 
161         return result;
162     }
163 
164     /**
165      * Remove some elements.
166      *
167      * @param type resource operation type
168      * @param keys target resources
169      * @return whether the operation was successful or not
170      */
171     public boolean removeAll(final ResourceOperation type, final Set<T> keys) {
172         Set<T> set;
173         switch (type) {
174             case CREATE:
175                 set = toBeCreated;
176                 break;
177 
178             case UPDATE:
179                 set = toBeUpdated;
180                 break;
181 
182             case DELETE:
183             default:
184                 set = toBeDeleted;
185                 break;
186         }
187 
188         return set.removeAll(keys);
189     }
190 
191     /**
192      * Removes only the resource names in the underlying resource name sets that are contained in the specified
193      * collection.
194      *
195      * @param keys collection containing resource names to be retained in the underlying resource name sets
196      * @return {@code true} if the underlying resource name sets changed as a result of the call
197      * @see Collection#removeAll(java.util.Collection)
198      */
199     public boolean removeAll(final Collection<T> keys) {
200         return toBeCreated.removeAll(keys)
201                 || toBeUpdated.removeAll(keys)
202                 || toBeDeleted.removeAll(keys);
203     }
204 
205     /**
206      * Retains only the resource names in the underlying resource name sets that are contained in the specified
207      * collection.
208      *
209      * @param keys collection containing resource names to be retained in the underlying resource name sets
210      * @return {@code true} if the underlying resource name sets changed as a result of the call
211      * @see Collection#retainAll(java.util.Collection)
212      */
213     public boolean retainAll(final Collection<T> keys) {
214         return toBeCreated.retainAll(keys)
215                 || toBeUpdated.retainAll(keys)
216                 || toBeDeleted.retainAll(keys);
217     }
218 
219     public boolean contains(final ResourceOperation type, final T key) {
220         boolean result = false;
221 
222         switch (type) {
223             case CREATE:
224                 result = toBeCreated.contains(key);
225                 break;
226 
227             case UPDATE:
228                 result = toBeUpdated.contains(key);
229                 break;
230 
231             case DELETE:
232                 result = toBeDeleted.contains(key);
233                 break;
234 
235             default:
236         }
237 
238         return result;
239     }
240 
241     public boolean contains(final T key) {
242         return toBeCreated.contains(key)
243                 || toBeUpdated.contains(key)
244                 || toBeDeleted.contains(key);
245     }
246 
247     /**
248      * Get resources for a given resource operation type.
249      *
250      * @param type resource operation type
251      * @return resource matching the given type
252      */
253     public final Set<T> get(final ResourceOperation type) {
254         Set<T> result = Set.of();
255 
256         switch (type) {
257             case CREATE:
258                 result = toBeCreated;
259                 break;
260 
261             case UPDATE:
262                 result = toBeUpdated;
263                 break;
264 
265             case DELETE:
266                 result = toBeDeleted;
267                 break;
268 
269             default:
270         }
271 
272         return result;
273     }
274 
275     public Map<T, ResourceOperation> asMap() {
276         Map<T, ResourceOperation> result = new HashMap<>();
277         Stream.of(ResourceOperation.values()).
278                 forEach(operation -> get(operation).forEach(resource -> result.put(resource, operation)));
279 
280         return result;
281     }
282 
283     /**
284      * Set resources for a given resource operation type.
285      *
286      * @param type resource operation type
287      * @param keys to be set
288      */
289     public final void set(final ResourceOperation type, final Collection<T> keys) {
290 
291         switch (type) {
292             case CREATE:
293                 toBeCreated.clear();
294                 toBeCreated.addAll(keys);
295                 break;
296 
297             case UPDATE:
298                 toBeUpdated.clear();
299                 toBeUpdated.addAll(keys);
300                 break;
301 
302             case DELETE:
303                 toBeDeleted.clear();
304                 toBeDeleted.addAll(keys);
305                 break;
306 
307             default:
308         }
309     }
310 
311     /**
312      * Merge another resource operation instance into this instance.
313      *
314      * @param propByRes to be merged
315      */
316     public final void merge(final PropagationByResource<T> propByRes) {
317         if (propByRes != null) {
318             toBeCreated.addAll(propByRes.get(ResourceOperation.CREATE));
319             toBeUpdated.addAll(propByRes.get(ResourceOperation.UPDATE));
320             toBeDeleted.addAll(propByRes.get(ResourceOperation.DELETE));
321             oldConnObjectKeys.putAll(propByRes.getOldConnObjectKeys());
322         }
323     }
324 
325     /**
326      * Removes all of the operations.
327      */
328     public void clear() {
329         toBeCreated.clear();
330         toBeUpdated.clear();
331         toBeDeleted.clear();
332     }
333 
334     /**
335      * Whether no operations are present.
336      *
337      * @return true if no operations (create / update / delete) and no old connObjectKeys are present
338      */
339     public final boolean isEmpty() {
340         return toBeCreated.isEmpty() && toBeUpdated.isEmpty() && toBeDeleted.isEmpty() && oldConnObjectKeys.isEmpty();
341     }
342 
343     /**
344      * Fetch all old connObjectKeys.
345      *
346      * @return old connObjectKeys; can be empty
347      */
348     public Map<String, String> getOldConnObjectKeys() {
349         return oldConnObjectKeys;
350     }
351 
352     /**
353      * Fetch old connObjectKey for given resource name.
354      *
355      * @param resourceKey resource name
356      * @return old connObjectKey; can be null
357      */
358     public String getOldConnObjectKey(final String resourceKey) {
359         return oldConnObjectKeys.get(resourceKey);
360     }
361 
362     /**
363      * Add old ConnObjectKey for a given resource name.
364      *
365      * @param resourceKey resourceKey resource name
366      * @param oldConnObjectKey old ConnObjectKey
367      */
368     public void addOldConnObjectKey(final String resourceKey, final String oldConnObjectKey) {
369         if (resourceKey != null && oldConnObjectKey != null) {
370             oldConnObjectKeys.put(resourceKey, oldConnObjectKey);
371         }
372     }
373 
374     @Override
375     public String toString() {
376         return "To be Created: " + toBeCreated + ";\n"
377                 + "To be Updated: " + toBeUpdated + ";\n"
378                 + "To be Deleted: " + toBeDeleted + ";\n"
379                 + "Old connObjectKeys: " + oldConnObjectKeys;
380     }
381 }