2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.sdc.common.datastructure;
23 import static org.apache.commons.lang3.StringUtils.EMPTY;
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;
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;
42 import fj.data.Either;
45 * Class For Functional interfaces And Functional Methods
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());
56 * This is an interface of a List that implements Serializable
62 public interface SerializableList<T> extends List<T>, Serializable {
66 * @author mshitrit Consumer that takes two parameters
70 public interface ConsumerTwoParam<T1, T2> {
72 * Same Accept method, but takes two parameters
77 void accept(T1 t1, T2 t2);
81 * @author mshitrit Function that takes two parameters
86 public interface FunctionTwoParam<T1, T2, R> {
88 * Same apply method, but takes two parameters
94 R apply(T1 t1, T2 t2);
98 * @author mshitrit Function that throws an exception
103 public interface FunctionThrows<T, R, E extends Exception> {
105 * Same apply method, but throws an exception
110 R apply(T t) throws E;
113 public interface FunctionTwoParamThrows<T1, T2, R, E extends Exception> {
115 * Same apply method, but throws an exception
121 R apply(T1 t1, T2 t2) throws E;
125 * @author mshitrit Supplier that throws an exception
129 public interface SupplierThrows<R, E extends Exception> {
131 * Same get method, but throws an exception
140 * @author mshitrit Consumer that throws an exception
144 public interface ConsumerThrows<T, E extends Exception> {
146 * Same accept, but throws an exception
151 void accept(T t) throws E;
155 * @author mshitrit Runnable that throws an exception
158 public interface RunnableThrows<E extends Exception> {
160 * Same run, but throws an exception
168 * Runs a method that declares throwing an Exception and has a return value.
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>
183 public static <R, E extends Exception> R swallowException(SupplierThrows<R, E> methodToRun) {
185 return methodToRun.get();
186 } catch (Exception e) {
187 throw new FunctionalAttException(e);
192 * Runs a method that declares throwing an Exception without return value.
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>
202 public static <E extends Exception> void swallowException(RunnableThrows<E> methodToRun) {
204 SupplierThrows<Boolean, E> runnableWrapper = () -> {
208 swallowException(runnableWrapper);
211 private static class FunctionalAttException extends RuntimeException {
212 private static final long serialVersionUID = 1L;
214 private FunctionalAttException(Exception e) {
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
225 * If Exception Occurred keeps retrying until it passes or until 10 seconds
227 * If last retry result caused an exception - it is thrown.
231 * @param resultVerifier
232 * verifier for the method result
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);
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
246 * If Exception Occurred keeps retrying until it passes or until maxWait
248 * If last retry result caused an exception - it is thrown.
252 * @param resultVerifier
253 * verifier for the method result
255 * @param retryIntervalMS
258 public static <R> R retryMethodOnResult(Supplier<R> methodToRun, Function<R, Boolean> resultVerifier,
259 long maxWaitMS, long retryIntervalMS) {
260 boolean stopSearch = false;
263 FunctionalAttException functionalExceotion = null;
264 boolean isExceptionInLastTry = false;
265 while (!stopSearch) {
267 ret = methodToRun.get();
268 stopSearch = resultVerifier.apply(ret);
269 isExceptionInLastTry = false;
270 } catch (Exception e) {
271 functionalExceotion = new FunctionalAttException(e);
272 isExceptionInLastTry = true;
275 sleep(retryIntervalMS);
276 timeElapsed += retryIntervalMS;
277 if (timeElapsed > maxWaitMS) {
283 if (isExceptionInLastTry) {
284 throw functionalExceotion;
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
298 * If last retry result caused an exception - it is thrown.
302 * @param resultVerifier
303 * verifier for the method result
307 public static <R> R retryMethodOnResult(Supplier<R> methodToRun, Function<R, Boolean> resultVerifier,
309 boolean stopSearch = false;
311 int retriesCount = 0;
312 FunctionalAttException functionalExceotion = null;
313 boolean isExceptionInLastTry = false;
314 while (!stopSearch) {
316 ret = methodToRun.get();
317 stopSearch = resultVerifier.apply(ret);
318 isExceptionInLastTry = false;
319 } catch (Exception e) {
320 functionalExceotion = new FunctionalAttException(e);
321 isExceptionInLastTry = true;
323 if (++retriesCount >= maxRetries) {
328 if (isExceptionInLastTry) {
329 throw functionalExceotion;
335 public static <R> R retryMethodOnException(SupplierThrows<R, Exception> methodToRun,
336 Function<Exception, Boolean> exceptionVerifier, long maxRetries) throws Exception {
337 boolean stopSearch = false;
339 int retriesCount = 0;
340 Exception exception = null;
341 while (!stopSearch) {
344 ret = methodToRun.get();
347 catch (Exception e) {
349 stopSearch = exceptionVerifier.apply(e);
352 if (++retriesCount >= maxRetries) {
357 if (exception != null) {
366 * Runs the given method.<br>
367 * In case exception occurred runs the method again either until succeed or
368 * until 10 seconds pass.
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);
381 * Runs the given method.<br>
382 * In case exception occurred runs the method again either until succeed or
383 * until 10 seconds pass.
388 public static void retryMethodOnException(Runnable methodToRun) {
389 Function<Boolean, Boolean> dummyVerifier = someResult -> true;
390 Supplier<Boolean> dummySupplier = () -> {
394 retryMethodOnResult(dummySupplier, dummyVerifier, DEFAULT_MAX_WAIT_TIME_MS, DEFAULT_REDO_INTERVAL_TIME_MS);
398 * Same as Thread.sleep but throws a FunctionalAttException
399 * (RuntimeException) instead of InterruptedException.<br>
403 public static void sleep(long millis) {
404 swallowException(() -> Thread.sleep(millis));
409 * Converts Either containing right value to another either with different
410 * type of left value and the same type of right value.
412 * @param eitherToConvert
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");
419 return Either.right(eitherToConvert.right().value());
425 * Converts Either containing left value to another either with different
426 * type of right value and the same type of left value.
428 * @param eitherToConvert
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");
435 return Either.left(eitherToConvert.left().value());
441 * Returns enum value for a field <br>
445 * @param enumValueGetter
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);
455 public static <T extends Enum<T>> T getEnumValueByFieldValue(String fieldValue, T[] values,
456 Function<T, String> enumValueGetter, T defaultValue, boolean isCaseSensetive ){
458 final Predicate<? super T> predicate;
459 if( isCaseSensetive ){
460 predicate = e -> fieldValue.equals(enumValueGetter.apply(e));
463 predicate = e -> fieldValue.equalsIgnoreCase(enumValueGetter.apply(e));
465 Optional<T> optionalFound =
466 // Stream of values of enum
467 Arrays.asList(values).stream().
468 // Filter in the one that match the field
473 ret = optionalFound.isPresent() ? optionalFound.get() : defaultValue;
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>
487 * - if 0 or lower no timeout is used
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());
495 ExecutorService pool = Executors.newSingleThreadExecutor();
496 Future<T> future = pool.submit(supplier::get);
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);
514 public static <T> F<T, Boolean> convertToFunction(Consumer<T> consumer) {
519 } catch (Exception e) {
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.
532 * @param resultOnException
535 public static <T, E extends Exception> Optional<T> wrapWithTryCatch(RunnableThrows<E> runnable,
536 T resultOnException) {
537 Optional<T> optionalError;
540 optionalError = Optional.empty();
541 } catch (Exception e) {
543 optionalError = Optional.of(resultOnException);
545 return optionalError;
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>
555 * @param maxWaitTimeMs
556 * @param retryIntervalMS
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");
562 StopWatch watch = new StopWatch();
565 boolean isLastTry = false;
567 isLastTry = watch.getTime() + retryIntervalMS > maxWaitTimeMs;
575 } catch (Exception e) {
576 wrapWithTryCatch(() -> Thread.sleep(retryIntervalMS));
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.
593 public static <E extends Exception> void wrapWithTryCatch(RunnableThrows<E> runnable) {
594 wrapWithTryCatch(runnable, null);
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);