fixing warnings from checkstyle in common-app-api
[sdc.git] / common-app-api / src / main / java / org / openecomp / sdc / common / datastructure / FunctionalInterfaces.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.common.datastructure;
22
23 import fj.F;
24 import fj.data.Either;
25 import org.apache.commons.lang3.math.NumberUtils;
26 import org.openecomp.sdc.common.log.wrappers.Logger;
27
28 import java.io.Serializable;
29 import java.util.Arrays;
30 import java.util.List;
31 import java.util.Optional;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.ExecutorService;
34 import java.util.concurrent.Executors;
35 import java.util.concurrent.Future;
36 import java.util.concurrent.TimeUnit;
37 import java.util.concurrent.TimeoutException;
38 import java.util.function.Consumer;
39 import java.util.function.Function;
40 import java.util.function.Predicate;
41 import java.util.function.Supplier;
42
43 /**
44  * Class For Functional interfaces And Functional Methods
45  *
46  * @author mshitrit
47  */
48 public class FunctionalInterfaces {
49     private static final int DEFAULT_REDO_INTERVAL_TIME_MS = 50;
50     private static final int DEFAULT_MAX_WAIT_TIME_MS = 10000;
51     private static final Logger LOGGER = Logger.getLogger(FunctionalInterfaces.class.getName());
52
53     /**
54      * This is an interface of a List that implements Serializable
55      *
56      * @param <T>
57      * @author mshitrit
58      */
59     public interface SerializableList<T> extends List<T>, Serializable {
60     }
61
62     /**
63      * @param <T1>
64      * @param <T2>
65      * @author mshitrit Consumer that takes two parameters
66      */
67     public interface ConsumerTwoParam<T1, T2> {
68         /**
69          * Same Accept method, but takes two parameters
70          *
71          * @param t1
72          * @param t2
73          */
74         void accept(T1 t1, T2 t2);
75     }
76
77     /**
78      * @param <T1>
79      * @param <T2>
80      * @param <R>
81      * @author mshitrit Function that takes two parameters
82      */
83     public interface FunctionTwoParam<T1, T2, R> {
84         /**
85          * Same apply method, but takes two parameters
86          *
87          * @param t1
88          * @param t2
89          * @return
90          */
91         R apply(T1 t1, T2 t2);
92     }
93
94     /**
95      * @param <T>
96      * @param <R>
97      * @param <E>
98      * @author mshitrit Function that throws an exception
99      */
100     public interface FunctionThrows<T, R, E extends Exception> {
101         /**
102          * Same apply method, but throws an exception
103          *
104          * @param t
105          * @return
106          */
107         R apply(T t) throws E;
108     }
109
110     public interface FunctionTwoParamThrows<T1, T2, R, E extends Exception> {
111         /**
112          * Same apply method, but throws an exception
113          *
114          * @param t1
115          * @param t2
116          * @return
117          */
118         R apply(T1 t1, T2 t2) throws E;
119     }
120
121     /**
122      * @param <R>
123      * @param <E>
124      * @author mshitrit Supplier that throws an exception
125      */
126     public interface SupplierThrows<R, E extends Exception> {
127         /**
128          * Same get method, but throws an exception
129          *
130          * @return
131          * @throws E
132          */
133         R get() throws E;
134     }
135
136     /**
137      * @param <T>
138      * @param <E>
139      * @author mshitrit Consumer that throws an exception
140      */
141     public interface ConsumerThrows<T, E extends Exception> {
142         /**
143          * Same accept, but throws an exception
144          *
145          * @param t
146          * @throws E
147          */
148         void accept(T t) throws E;
149     }
150
151     /**
152      * @param <E>
153      * @author mshitrit Runnable that throws an exception
154      */
155     public interface RunnableThrows<E extends Exception> {
156         /**
157          * Same run, but throws an exception
158          *
159          * @throws E
160          */
161         void run() throws E;
162     }
163
164     /**
165      * Runs a method that declares throwing an Exception and has a return value.
166      * <br>
167      * In case Exception Occurred replaces it with FunctionalAttException. <br>
168      * This is useful for two cases:<br>
169      * 1.using methods that throws exceptions in streams.<br>
170      * 2.replacing declared exception with undeclared exception (Runtime).<br>
171      * See below Use Case:<br>
172      * Instead of: intList.stream().map(e -> fooThrowsAndReturnsBoolean(e)); -
173      * does not compile !<br>
174      * Use This : intList.stream().map(e -> swallowException( () ->
175      * fooThrowsAndReturnsBoolean(e))); - compiles !<br>
176      *
177      * @param methodToRun
178      * @return
179      */
180     public static <R, E extends Exception> R swallowException(SupplierThrows<R, E> methodToRun) {
181         try {
182             return methodToRun.get();
183         } catch (Exception e) {
184             throw new FunctionalAttException(e);
185         }
186     }
187
188     /**
189      * Runs a method that declares throwing an Exception without return value.
190      * <br>
191      * In case Exception Occurred replaces it with FunctionalAttException. <br>
192      * This is useful for two cases:<br>
193      * 1.using methods that throws exceptions in streams.<br>
194      * 2.replacing declared exception with undeclared exception (Runtime).<br>
195      * See below Use Case:<br>
196      *
197      * @param methodToRun
198      */
199     public static <E extends Exception> void swallowException(RunnableThrows<E> methodToRun) {
200
201         SupplierThrows<Boolean, E> runnableWrapper = () -> {
202             methodToRun.run();
203             return true;
204         };
205         swallowException(runnableWrapper);
206     }
207
208     private static class FunctionalAttException extends RuntimeException {
209         private static final long serialVersionUID = 1L;
210
211         private FunctionalAttException(Exception e) {
212             super(e);
213         }
214     }
215
216     /**
217      * Runs the given method.<br>
218      * Verify the method result against the resultVerifier.<br>
219      * If verification passed returns the result.<br>
220      * If Verification failed keeps retrying until it passes or until 10 seconds
221      * pass.<br>
222      * If Exception Occurred keeps retrying until it passes or until 10 seconds
223      * pass,<br>
224      * If last retry result caused an exception - it is thrown.
225      *
226      * @param methodToRun    given Method
227      * @param resultVerifier verifier for the method result
228      * @return
229      */
230     public static <R> R retryMethodOnResult(Supplier<R> methodToRun, Function<R, Boolean> resultVerifier) {
231         return retryMethodOnResult(methodToRun, resultVerifier, DEFAULT_MAX_WAIT_TIME_MS,
232                 DEFAULT_REDO_INTERVAL_TIME_MS);
233     }
234
235     /**
236      * Runs the given method.<br>
237      * Verify the method result against the resultVerifier.<br>
238      * If verification passed returns the result.<br>
239      * If Verification failed keeps retrying until it passes or until maxWait
240      * pass.<br>
241      * If Exception Occurred keeps retrying until it passes or until maxWait
242      * pass,<br>
243      * If last retry result caused an exception - it is thrown.
244      *
245      * @param methodToRun     given Method
246      * @param resultVerifier  verifier for the method result
247      * @param maxWaitMS
248      * @param retryIntervalMS
249      * @return
250      */
251     public static <R> R retryMethodOnResult(Supplier<R> methodToRun, Function<R, Boolean> resultVerifier,
252                                             long maxWaitMS, long retryIntervalMS) {
253         boolean stopSearch = false;
254         R ret = null;
255         int timeElapsed = 0;
256         FunctionalAttException functionalExceotion = null;
257         boolean isExceptionInLastTry = false;
258         while (!stopSearch) {
259             try {
260                 ret = methodToRun.get();
261                 stopSearch = resultVerifier.apply(ret);
262                 isExceptionInLastTry = false;
263             } catch (Exception e) {
264                 functionalExceotion = new FunctionalAttException(e);
265                 isExceptionInLastTry = true;
266
267             } finally {
268                 sleep(retryIntervalMS);
269                 timeElapsed += retryIntervalMS;
270                 if (timeElapsed > maxWaitMS) {
271                     stopSearch = true;
272                 }
273             }
274
275         }
276         if (isExceptionInLastTry) {
277             throw functionalExceotion;
278         } else {
279             return ret;
280         }
281
282     }
283
284     /**
285      * Runs the given method.<br>
286      * Verify the method result against the resultVerifier.<br>
287      * If verification passed returns the result.<br>
288      * If Verification failed keeps retrying until maxRetries reached.<br>
289      * If Exception Occurred keeps retrying until it passes or until maxRetries
290      * reached,<br>
291      * If last retry result caused an exception - it is thrown.
292      *
293      * @param methodToRun    given Method
294      * @param resultVerifier verifier for the method result
295      * @param maxRetries
296      * @return
297      */
298     public static <R> R retryMethodOnResult(Supplier<R> methodToRun, Function<R, Boolean> resultVerifier,
299                                             long maxRetries) {
300         boolean stopSearch = false;
301         R ret = null;
302         int retriesCount = 0;
303         FunctionalAttException functionalExceotion = null;
304         boolean isExceptionInLastTry = false;
305         while (!stopSearch) {
306             try {
307                 ret = methodToRun.get();
308                 stopSearch = resultVerifier.apply(ret);
309                 isExceptionInLastTry = false;
310             } catch (Exception e) {
311                 functionalExceotion = new FunctionalAttException(e);
312                 isExceptionInLastTry = true;
313             } finally {
314                 if (++retriesCount >= maxRetries) {
315                     stopSearch = true;
316                 }
317             }
318         }
319         if (isExceptionInLastTry) {
320             throw functionalExceotion;
321         } else {
322             return ret;
323         }
324     }
325
326     public static <R> R retryMethodOnException(SupplierThrows<R, Exception> methodToRun,
327                                                Function<Exception, Boolean> exceptionVerifier, long maxRetries) throws Exception {
328         boolean stopSearch = false;
329         R ret = null;
330         int retriesCount = 0;
331         Exception exception = null;
332         while (!stopSearch) {
333             try {
334                 exception = null;
335                 ret = methodToRun.get();
336                 stopSearch = true;
337             } catch (Exception e) {
338                 exception = e;
339                 stopSearch = exceptionVerifier.apply(e);
340             } finally {
341                 if (++retriesCount >= maxRetries) {
342                     stopSearch = true;
343                 }
344             }
345         }
346         if (exception != null) {
347             throw exception;
348         } else {
349             return ret;
350         }
351     }
352
353     /**
354      * Runs the given method.<br>
355      * In case exception occurred runs the method again either until succeed or
356      * until 10 seconds pass.
357      *
358      * @param methodToRun given method
359      * @return
360      */
361
362     public static <R> R retryMethodOnException(Supplier<R> methodToRun) {
363         Function<R, Boolean> dummyVerifier = someResult -> true;
364         return retryMethodOnResult(methodToRun, dummyVerifier, DEFAULT_MAX_WAIT_TIME_MS, DEFAULT_REDO_INTERVAL_TIME_MS);
365     }
366
367     /**
368      * Runs the given method.<br>
369      * In case exception occurred runs the method again either until succeed or
370      * until 10 seconds pass.
371      *
372      * @param methodToRun given method
373      */
374     public static void retryMethodOnException(Runnable methodToRun) {
375         Function<Boolean, Boolean> dummyVerifier = someResult -> true;
376         Supplier<Boolean> dummySupplier = () -> {
377             methodToRun.run();
378             return true;
379         };
380         retryMethodOnResult(dummySupplier, dummyVerifier, DEFAULT_MAX_WAIT_TIME_MS, DEFAULT_REDO_INTERVAL_TIME_MS);
381     }
382
383     /**
384      * Same as Thread.sleep but throws a FunctionalAttException
385      * (RuntimeException) instead of InterruptedException.<br>
386      *
387      * @param millis
388      */
389     public static void sleep(long millis) {
390         swallowException(() -> Thread.sleep(millis));
391
392     }
393
394     /**
395      * Converts Either containing right value to another either with different
396      * type of left value and the same type of right value.
397      *
398      * @param eitherToConvert
399      * @return
400      */
401     public static <T1, T2, T3> Either<T1, T2> convertEitherRight(Either<T3, T2> eitherToConvert) {
402         if (eitherToConvert.isLeft()) {
403             throw new UnsupportedOperationException("Can not convert either right value because it has left value");
404         } else {
405             return Either.right(eitherToConvert.right().value());
406         }
407
408     }
409
410     /**
411      * Converts Either containing left value to another either with different
412      * type of right value and the same type of left value.
413      *
414      * @param eitherToConvert
415      * @return
416      */
417     public static <T1, T2, T3> Either<T1, T2> convertEitherLeft(Either<T1, T3> eitherToConvert) {
418         if (eitherToConvert.isLeft()) {
419             throw new UnsupportedOperationException("Can not convert either left value because it has right value");
420         } else {
421             return Either.left(eitherToConvert.left().value());
422         }
423
424     }
425
426     /**
427      * Returns enum value for a field <br>
428      *
429      * @param fieldValue
430      * @param values
431      * @param enumValueGetter
432      * @return
433      */
434     public static <T extends Enum<T>> T getEnumValueByFieldValue(String fieldValue, T[] values,
435                                                                  Function<T, String> enumValueGetter, T defaultValue) {
436         return getEnumValueByFieldValue(fieldValue, values, enumValueGetter, defaultValue, true);
437
438     }
439
440
441     public static <T extends Enum<T>> T getEnumValueByFieldValue(String fieldValue, T[] values,
442                                                                  Function<T, String> enumValueGetter, T defaultValue, boolean isCaseSensetive) {
443
444         final Predicate<? super T> predicate;
445         if (isCaseSensetive) {
446             predicate = e -> fieldValue.equals(enumValueGetter.apply(e));
447         } else {
448             predicate = e -> fieldValue.equalsIgnoreCase(enumValueGetter.apply(e));
449         }
450         Optional<T> optionalFound =
451                 // Stream of values of enum
452                 Arrays.asList(values).stream().
453                         // Filter in the one that match the field
454                                 filter(predicate).
455                         // collect
456                                 findAny();
457         T ret;
458         ret = optionalFound.isPresent() ? optionalFound.get() : defaultValue;
459         return ret;
460
461     }
462
463     /**
464      * This method runs the given method.<br>
465      * In case given method finished running within timeoutInMs limit it returns
466      * Either which left value is the result of the method that ran.<br>
467      * In case given method did not finish running within timeoutInMs limit it
468      * returns Either which right value is false. <br>
469      *
470      * @param supplier
471      * @param timeoutInMs - if 0 or lower no timeout is used
472      * @return
473      */
474     public static <T> Either<T, Boolean> runMethodWithTimeOut(Supplier<T> supplier, long timeoutInMs) {
475         Either<T, Boolean> result;
476         if (timeoutInMs <= NumberUtils.LONG_ZERO) {
477             result = Either.left(supplier.get());
478         } else {
479             ExecutorService pool = Executors.newSingleThreadExecutor();
480             Future<T> future = pool.submit(supplier::get);
481             try {
482                 T calcValue = future.get(timeoutInMs, TimeUnit.MILLISECONDS);
483                 result = Either.left(calcValue);
484             } catch (InterruptedException e) {
485                 LOGGER.debug("InterruptedException in runMethodWithTimeOut", e);
486                 Thread.currentThread().interrupt();
487                 result = Either.right(false);
488             } catch (ExecutionException | TimeoutException e) {
489                 LOGGER.debug("method run was canceled because it has passed its time limit of {} MS", timeoutInMs, e);
490                 result = Either.right(false);
491             } finally {
492                 pool.shutdownNow();
493             }
494         }
495         return result;
496     }
497
498     public static <T> F<T, Boolean> convertToFunction(Consumer<T> consumer) {
499         return t -> {
500             try {
501                 consumer.accept(t);
502                 return true;
503             } catch (Exception e) {
504                 return false;
505             }
506         };
507     }
508
509 }