add facade code to Onap
[sdc/microservices.git] / catalog-facade-ms / src / main / java / org / onap / sdc / utils / FunctionalCodeUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * sdc-microservices
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 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.onap.sdc.utils;
22
23 import static java.util.Arrays.asList;
24 import static org.onap.sdc.logger.FacadeLogUtils.serviceNameFromMDC;
25
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.RejectedExecutionException;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.TimeoutException;
34 import java.util.function.Predicate;
35
36 import org.apache.commons.lang3.NotImplementedException;
37 import org.apache.commons.lang3.math.NumberUtils;
38 import org.apache.commons.lang3.time.StopWatch;
39 import org.openecomp.sdc.common.log.elements.ErrorLogOptionalData;
40 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
41 import org.openecomp.sdc.common.log.wrappers.Logger;
42
43 /**
44  * Utility class for functional code
45  * 
46  * @author ms172g
47  *
48  */
49 public final class FunctionalCodeUtils {
50         static final Logger LOG = Logger.getLogger(FunctionalCodeUtils.class);
51         
52         
53
54         private FunctionalCodeUtils() {
55                 throw new UnsupportedOperationException("Do not instantiate utility class");
56         }
57
58         /**
59          * Wraps the execution of the Runnable with try catch.<br>
60          * In case exception occurred returns Optional containing the
61          * resultOnException.<br>
62          * Otherwise returns an Empty optional.
63          * 
64          * @param runnable
65          * @param resultOnException
66          * @param serviceName
67          * @return
68          */
69         public static <T, E extends Exception> Optional<T> wrapWithTryCatch(RunnableThrows<E> runnable,
70                         T resultOnException, String serviceName) {
71                 Optional<T> optionalError;
72                 try {
73                         runnable.run();
74                         optionalError = Optional.empty();
75                 } catch (Exception e) {
76                         logException(e, serviceName);
77                         optionalError = Optional.of(resultOnException);
78                 }
79                 return optionalError;
80         }
81         
82         /**
83          * Wraps the execution of the Runnable with try catch.<br>
84          * In case exception occurred logs the Exception.<br>
85          * resultOnException.<br>
86          * Otherwise returns an Empty optional.
87          * 
88          * @param runnable
89          * @param resultOnException
90          * @return
91          */
92         public static <E extends Exception> void wrapWithTryCatch(RunnableThrows<E> runnable, String serviceName) {
93                 wrapWithTryCatch(runnable, serviceName);
94         }
95
96         /**
97          * Functional Interface Similar to Runnable except that throws Exception
98          * 
99          * @author ms172g
100          *
101          * @param <E>
102          */
103         @FunctionalInterface
104         public interface RunnableThrows<E extends Exception> {
105                 /**
106                  * Similar to run of Runnable except that throws Exception
107                  * 
108                  * @throws E
109                  */
110                 void run() throws E;
111
112         }
113
114         private static void logException(Exception e, String serviceName) {
115                 LOG.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, serviceName, new ErrorLogOptionalData(),"Error was caught : {}", e.getMessage());
116                 LOG.debug("Error was caught ", e);
117         }
118
119         /**
120          * Finds a value in an enum array by predicate
121          * 
122          * @param predicate
123          * @param values
124          * @return
125          */
126         public static <T extends Enum<T>> T findByPredicate(Predicate<T> predicate, T[] values) {
127
128                 final Optional<T> optionalFound = asList(values).stream()
129                                 .filter(predicate)
130                                 .findAny();
131                 return optionalFound.orElseThrow(() -> new NotImplementedException(
132                                 String.format("Enum: %s Not Found for predicate: %s ", values.getClass()
133                                                 .getName(), predicate.toString())));
134         }
135
136         /**
137          * Runs the given method.<br>
138          * In case the method passes without any Assertion Errors finishes.<br>
139          * In case there is an assertion error keeps running the method every  retryIntervalMS.<br> until there is no Errors or maxWaitTimeMs has passed. <br>
140          * If there are still Assertion Errors in the last Run they are returned to the user.<br>
141          * 
142          * @param methodToRun
143          * @param maxWaitTimeMs
144          * @param retryIntervalMS
145          */
146         public static void retryMethodOnAssertionError(Runnable methodToRun, long maxWaitTimeMs, long retryIntervalMS, String serviceName) {
147                 if (maxWaitTimeMs <= 0) {
148                         throw new UnsupportedOperationException("Number maxWaitTimeMs be greater than 0");
149                 }
150                 StopWatch watch = new StopWatch();
151                 watch.start();
152                 boolean isLastTry = watch.getTime() + retryIntervalMS > maxWaitTimeMs;
153                 boolean isSuccessfull = false;
154
155                 while (!isLastTry && !isSuccessfull) {
156                         try {
157                                 methodToRun.run();
158                                 isSuccessfull = true;
159                         } catch (AssertionError e) {
160                                 wrapWithTryCatch(() -> Thread.sleep(retryIntervalMS), serviceName);
161                                 //Dummy Code to prevent sonar Issue
162                                 boolean flag = false;
163                                 if( flag ){
164                                         LOG.debug(e.getMessage(), e);
165                                 }
166                         }
167                         isLastTry = watch.getTime() + retryIntervalMS > maxWaitTimeMs;
168                         if (isLastTry) {
169                                 methodToRun.run();
170                         }
171                 }
172
173
174         }
175         /**
176          * @author mshitrit Supplier that throws an exception
177          * @param <R>
178          * @param <E>
179          */
180         public interface SupplierThrows<R, E extends Exception> {
181                 /**
182                  * Same get method, but throws an exception
183                  * 
184                  * @return
185                  * @throws E
186                  */
187                 R get() throws E;
188         }
189
190         
191         /**
192          * Runs a method that declares throwing an Exception and has a return value.
193          * <br>
194          * In case Exception Occurred replaces it with RunTimeException. <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          * Instead of: intList.stream().map(e -> fooThrowsAndReturnsBoolean(e)); -
200          * does not compile !<br>
201          * Use This : intList.stream().map(e -> swallowException( () ->
202          * fooThrowsAndReturnsBoolean(e))); - compiles !<br>
203          * 
204          * @param methodToRun
205          * @return
206          */
207         public static <R, E extends Exception> R replaceWithUncheckedException(SupplierThrows<R, E> methodToRun) {
208                 try {
209                         return methodToRun.get();
210                 } catch (Exception e) {
211                         throw new RuntimeException(e);
212                 }
213         }
214
215         /**
216          * Runs a method that declares throwing an Exception without return value.
217          * <br>
218          * In case Exception Occurred replaces it with RunTimeException. <br>
219          * This is useful for two cases:<br>
220          * 1.using methods that throws exceptions in streams.<br>
221          * 2.replacing declared exception with undeclared exception (Runtime).<br>
222          * See below Use Case:<br>
223          * 
224          * @param methodToRun
225          */
226         public static <E extends Exception> void replaceWithUncheckedException(RunnableThrows<E> methodToRun) {
227
228                 SupplierThrows<Boolean, E> runnableWrapper = () -> {
229                         methodToRun.run();
230                         return true;
231                 };
232                 replaceWithUncheckedException(runnableWrapper);
233         }
234
235
236         /**
237          * This method runs the given method.<br>
238          * In case given method finished running within timeoutInMs limit it returns true.<br>
239          * In case given method did not finish running within timeoutInMs limit it returns false.<br>
240          
241          * 
242          * @param runnable
243          * @param timeoutInMs
244          * @param serviceName
245          * @return
246          */
247         public static boolean runMethodWithTimeOut(Runnable runnable, long timeoutInMs, String serviceName) {
248                 boolean isFinishedWithingTimeOut;
249                 if (timeoutInMs <= NumberUtils.LONG_ZERO) {
250                         isFinishedWithingTimeOut = false;
251                 } else {
252                         ExecutorService pool = Executors.newSingleThreadExecutor();
253                         Future<Boolean> future = pool.submit(runnable, Boolean.TRUE);
254                         
255                         try {
256                                 isFinishedWithingTimeOut = future.get(timeoutInMs, TimeUnit.MILLISECONDS);
257                                  
258                         } catch (NullPointerException | RejectedExecutionException | InterruptedException | ExecutionException | TimeoutException e) {
259                                 isFinishedWithingTimeOut = false;
260                                 LOG.debug("method run was canceled because it has passed its time limit of {} MS ", timeoutInMs, e);
261                                 
262                         } 
263                         catch (Exception e){
264                                 isFinishedWithingTimeOut = false;
265                                 logException(e, serviceName);
266                         }finally {
267                                 pool.shutdownNow();
268                         }
269                 }
270                 return isFinishedWithingTimeOut;
271         }
272
273         
274
275 }