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