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