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;
24 import fj.data.Either;
25 import org.apache.commons.lang3.math.NumberUtils;
26 import org.openecomp.sdc.common.log.wrappers.Logger;
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;
44 * Class For Functional interfaces And Functional Methods
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());
54 * This is an interface of a List that implements Serializable
59 public interface SerializableList<T> extends List<T>, Serializable {
65 * @author mshitrit Consumer that takes two parameters
67 public interface ConsumerTwoParam<T1, T2> {
69 * Same Accept method, but takes two parameters
74 void accept(T1 t1, T2 t2);
81 * @author mshitrit Function that takes two parameters
83 public interface FunctionTwoParam<T1, T2, R> {
85 * Same apply method, but takes two parameters
91 R apply(T1 t1, T2 t2);
98 * @author mshitrit Function that throws an exception
100 public interface FunctionThrows<T, R, E extends Exception> {
102 * Same apply method, but throws an exception
107 R apply(T t) throws E;
110 public interface FunctionTwoParamThrows<T1, T2, R, E extends Exception> {
112 * Same apply method, but throws an exception
118 R apply(T1 t1, T2 t2) throws E;
124 * @author mshitrit Supplier that throws an exception
126 public interface SupplierThrows<R, E extends Exception> {
128 * Same get method, but throws an exception
139 * @author mshitrit Consumer that throws an exception
141 public interface ConsumerThrows<T, E extends Exception> {
143 * Same accept, but throws an exception
148 void accept(T t) throws E;
153 * @author mshitrit Runnable that throws an exception
155 public interface RunnableThrows<E extends Exception> {
157 * Same run, but throws an exception
165 * Runs a method that declares throwing an Exception and has a return value.
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>
180 public static <R, E extends Exception> R swallowException(SupplierThrows<R, E> methodToRun) {
182 return methodToRun.get();
183 } catch (Exception e) {
184 throw new FunctionalAttException(e);
189 * Runs a method that declares throwing an Exception without return value.
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>
199 public static <E extends Exception> void swallowException(RunnableThrows<E> methodToRun) {
201 SupplierThrows<Boolean, E> runnableWrapper = () -> {
205 swallowException(runnableWrapper);
208 private static class FunctionalAttException extends RuntimeException {
209 private static final long serialVersionUID = 1L;
211 private FunctionalAttException(Exception e) {
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
222 * If Exception Occurred keeps retrying until it passes or until 10 seconds
224 * If last retry result caused an exception - it is thrown.
226 * @param methodToRun given Method
227 * @param resultVerifier verifier for the method result
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);
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
241 * If Exception Occurred keeps retrying until it passes or until maxWait
243 * If last retry result caused an exception - it is thrown.
245 * @param methodToRun given Method
246 * @param resultVerifier verifier for the method result
248 * @param retryIntervalMS
251 public static <R> R retryMethodOnResult(Supplier<R> methodToRun, Function<R, Boolean> resultVerifier,
252 long maxWaitMS, long retryIntervalMS) {
253 boolean stopSearch = false;
256 FunctionalAttException functionalExceotion = null;
257 boolean isExceptionInLastTry = false;
258 while (!stopSearch) {
260 ret = methodToRun.get();
261 stopSearch = resultVerifier.apply(ret);
262 isExceptionInLastTry = false;
263 } catch (Exception e) {
264 functionalExceotion = new FunctionalAttException(e);
265 isExceptionInLastTry = true;
268 sleep(retryIntervalMS);
269 timeElapsed += retryIntervalMS;
270 if (timeElapsed > maxWaitMS) {
276 if (isExceptionInLastTry) {
277 throw functionalExceotion;
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
291 * If last retry result caused an exception - it is thrown.
293 * @param methodToRun given Method
294 * @param resultVerifier verifier for the method result
298 public static <R> R retryMethodOnResult(Supplier<R> methodToRun, Function<R, Boolean> resultVerifier,
300 boolean stopSearch = false;
302 int retriesCount = 0;
303 FunctionalAttException functionalExceotion = null;
304 boolean isExceptionInLastTry = false;
305 while (!stopSearch) {
307 ret = methodToRun.get();
308 stopSearch = resultVerifier.apply(ret);
309 isExceptionInLastTry = false;
310 } catch (Exception e) {
311 functionalExceotion = new FunctionalAttException(e);
312 isExceptionInLastTry = true;
314 if (++retriesCount >= maxRetries) {
319 if (isExceptionInLastTry) {
320 throw functionalExceotion;
326 public static <R> R retryMethodOnException(SupplierThrows<R, Exception> methodToRun,
327 Function<Exception, Boolean> exceptionVerifier, long maxRetries) throws Exception {
328 boolean stopSearch = false;
330 int retriesCount = 0;
331 Exception exception = null;
332 while (!stopSearch) {
335 ret = methodToRun.get();
337 } catch (Exception e) {
339 stopSearch = exceptionVerifier.apply(e);
341 if (++retriesCount >= maxRetries) {
346 if (exception != null) {
354 * Runs the given method.<br>
355 * In case exception occurred runs the method again either until succeed or
356 * until 10 seconds pass.
358 * @param methodToRun given method
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);
368 * Runs the given method.<br>
369 * In case exception occurred runs the method again either until succeed or
370 * until 10 seconds pass.
372 * @param methodToRun given method
374 public static void retryMethodOnException(Runnable methodToRun) {
375 Function<Boolean, Boolean> dummyVerifier = someResult -> true;
376 Supplier<Boolean> dummySupplier = () -> {
380 retryMethodOnResult(dummySupplier, dummyVerifier, DEFAULT_MAX_WAIT_TIME_MS, DEFAULT_REDO_INTERVAL_TIME_MS);
384 * Same as Thread.sleep but throws a FunctionalAttException
385 * (RuntimeException) instead of InterruptedException.<br>
389 public static void sleep(long millis) {
390 swallowException(() -> Thread.sleep(millis));
395 * Converts Either containing right value to another either with different
396 * type of left value and the same type of right value.
398 * @param eitherToConvert
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");
405 return Either.right(eitherToConvert.right().value());
411 * Converts Either containing left value to another either with different
412 * type of right value and the same type of left value.
414 * @param eitherToConvert
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");
421 return Either.left(eitherToConvert.left().value());
427 * Returns enum value for a field <br>
431 * @param enumValueGetter
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);
441 public static <T extends Enum<T>> T getEnumValueByFieldValue(String fieldValue, T[] values,
442 Function<T, String> enumValueGetter, T defaultValue, boolean isCaseSensetive) {
444 final Predicate<? super T> predicate;
445 if (isCaseSensetive) {
446 predicate = e -> fieldValue.equals(enumValueGetter.apply(e));
448 predicate = e -> fieldValue.equalsIgnoreCase(enumValueGetter.apply(e));
450 Optional<T> optionalFound =
451 // Stream of values of enum
452 Arrays.asList(values).stream().
453 // Filter in the one that match the field
458 ret = optionalFound.isPresent() ? optionalFound.get() : defaultValue;
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>
471 * @param timeoutInMs - if 0 or lower no timeout is used
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());
479 ExecutorService pool = Executors.newSingleThreadExecutor();
480 Future<T> future = pool.submit(supplier::get);
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);
498 public static <T> F<T, Boolean> convertToFunction(Consumer<T> consumer) {
503 } catch (Exception e) {