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 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;
38 import org.apache.commons.lang3.math.NumberUtils;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 import fj.data.Either;
46 * Class For Functional interfaces And Functional Methods
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);
57 * This is an interface of a List that implements Serializable
63 public interface SerializableList<T> extends List<T>, Serializable {
67 * @author mshitrit Consumer that takes two parameters
71 public interface ConsumerTwoParam<T1, T2> {
73 * Same Accept method, but takes two parameters
78 void accept(T1 t1, T2 t2);
82 * @author mshitrit Function that takes two parameters
87 public interface FunctionTwoParam<T1, T2, R> {
89 * Same apply method, but takes two parameters
95 R apply(T1 t1, T2 t2);
99 * @author mshitrit Function that throws an exception
104 public interface FunctionThrows<T, R, E extends Exception> {
106 * Same apply method, but throws an exception
111 R apply(T t) throws E;
114 public interface FunctionTwoParamThrows<T1, T2, R, E extends Exception> {
116 * Same apply method, but throws an exception
122 R apply(T1 t1, T2 t2) throws E;
126 * @author mshitrit Supplier that throws an exception
130 public interface SupplierThrows<R, E extends Exception> {
132 * Same get method, but throws an exception
141 * @author mshitrit Consumer that throws an exception
145 public interface ConsumerThrows<T, E extends Exception> {
147 * Same accept, but throws an exception
152 void accept(T t) throws E;
156 * @author mshitrit Runnable that throws an exception
159 public interface RunnableThrows<E extends Exception> {
161 * Same run, but throws an exception
169 * Runs a method that declares throwing an Exception and has a return value.
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>
184 public static <R, E extends Exception> R swallowException(SupplierThrows<R, E> methodToRun) {
186 final R result = methodToRun.get();
188 } catch (Exception e) {
189 throw new FunctionalAttException(e);
194 * Runs a method that declares throwing an Exception without return value.
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>
204 public static <E extends Exception> void swallowException(RunnableThrows<E> methodToRun) {
206 SupplierThrows<Boolean, E> runnableWrapper = () -> {
210 swallowException(runnableWrapper);
213 private static class FunctionalAttException extends RuntimeException {
214 private static final long serialVersionUID = 1L;
216 private FunctionalAttException(Exception e) {
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
227 * If Exception Occurred keeps retrying until it passes or until 10 seconds
229 * If last retry result caused an exception - it is thrown.
233 * @param resultVerifier
234 * verifier for the method result
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);
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
248 * If Exception Occurred keeps retrying until it passes or until maxWait
250 * If last retry result caused an exception - it is thrown.
254 * @param resultVerifier
255 * verifier for the method result
257 * @param retryIntervalMS
260 public static <R> R retryMethodOnResult(Supplier<R> methodToRun, Function<R, Boolean> resultVerifier,
261 long maxWaitMS, long retryIntervalMS) {
262 boolean stopSearch = false;
265 FunctionalAttException functionalExceotion = null;
266 boolean isExceptionInLastTry = false;
267 while (!stopSearch) {
269 ret = methodToRun.get();
270 stopSearch = resultVerifier.apply(ret);
271 isExceptionInLastTry = false;
272 } catch (Exception e) {
273 functionalExceotion = new FunctionalAttException(e);
274 isExceptionInLastTry = true;
277 sleep(retryIntervalMS);
278 timeElapsed += retryIntervalMS;
279 if (timeElapsed > maxWaitMS) {
285 if (isExceptionInLastTry) {
286 throw functionalExceotion;
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
300 * If last retry result caused an exception - it is thrown.
304 * @param resultVerifier
305 * verifier for the method result
309 public static <R> R retryMethodOnResult(Supplier<R> methodToRun, Function<R, Boolean> resultVerifier,
311 boolean stopSearch = false;
313 int retriesCount = 0;
314 FunctionalAttException functionalExceotion = null;
315 boolean isExceptionInLastTry = false;
316 while (!stopSearch) {
318 ret = methodToRun.get();
319 stopSearch = resultVerifier.apply(ret);
320 isExceptionInLastTry = false;
321 } catch (Exception e) {
322 functionalExceotion = new FunctionalAttException(e);
323 isExceptionInLastTry = true;
325 if (++retriesCount >= maxRetries) {
330 if (isExceptionInLastTry) {
331 throw functionalExceotion;
337 public static <R> R retryMethodOnException(SupplierThrows<R, Exception> methodToRun,
338 Function<Exception, Boolean> exceptionVerifier, long maxRetries) throws Exception {
339 boolean stopSearch = false;
341 int retriesCount = 0;
342 Exception exception = null;
343 while (!stopSearch) {
346 ret = methodToRun.get();
349 catch (Exception e) {
351 stopSearch = exceptionVerifier.apply(e);
354 if (++retriesCount >= maxRetries) {
359 if (exception != null) {
368 * Runs the given method.<br>
369 * In case exception occurred runs the method again either until succeed or
370 * until 10 seconds pass.
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);
383 * Runs the given method.<br>
384 * In case exception occurred runs the method again either until succeed or
385 * until 10 seconds pass.
390 public static void retryMethodOnException(Runnable methodToRun) {
391 Function<Boolean, Boolean> dummyVerifier = someResult -> true;
392 Supplier<Boolean> dummySupplier = () -> {
396 retryMethodOnResult(dummySupplier, dummyVerifier, DEFAULT_MAX_WAIT_TIME_MS, DEFAULT_REDO_INTERVAL_TIME_MS);
400 * Same as Thread.sleep but throws a FunctionalAttException
401 * (RuntimeException) instead of InterruptedException.<br>
405 public static void sleep(long millis) {
406 swallowException(() -> Thread.sleep(millis));
411 * Converts Either containing right value to another either with different
412 * type of left value and the same type of right value.
414 * @param eitherToConvert
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");
421 return Either.right(eitherToConvert.right().value());
427 * Converts Either containing left value to another either with different
428 * type of right value and the same type of left value.
430 * @param eitherToConvert
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");
437 return Either.left(eitherToConvert.left().value());
443 * Returns enum value for a field <br>
447 * @param enumValueGetter
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);
457 public static <T extends Enum<T>> T getEnumValueByFieldValue(String fieldValue, T[] values,
458 Function<T, String> enumValueGetter, T defaultValue, boolean isCaseSensetive ){
460 final Predicate<? super T> predicate;
461 if( isCaseSensetive ){
462 predicate = e -> fieldValue.equals(enumValueGetter.apply(e));
465 predicate = e -> fieldValue.equalsIgnoreCase(enumValueGetter.apply(e));
467 Optional<T> optionalFound =
468 // Stream of values of enum
469 Arrays.asList(values).stream().
470 // Filter in the one that match the field
475 ret = optionalFound.isPresent() ? optionalFound.get() : defaultValue;
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>
489 * - if 0 or lower no timeout is used
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());
497 ExecutorService pool = Executors.newSingleThreadExecutor();
498 Future<T> future = pool.submit(supplier::get);
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);
512 public static <T> F<T, Boolean> convertToFunction(Consumer<T> consumer) {
513 F<T, Boolean> func = t -> {
517 } catch (Exception e) {