[CCSDK-245] RA: Refactor RA to make it generic
[ccsdk/sli/adaptors.git] / resource-assignment / provider / src / main / java / org / onap / ccsdk / sli / adaptors / util / expr / ExpressionEvaluator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                      reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.ccsdk.sli.adaptors.util.expr;
23
24 import java.util.Map;
25
26 public class ExpressionEvaluator {
27
28     public static long evalLong(String expr, Map<String, String> vars) {
29         return (long) evalFloat(expr, vars);
30     }
31
32     public static float evalFloat(String expr, Map<String, String> vars) {
33         expr = expr.trim();
34         int sl = expr.length();
35         if (sl == 0) {
36             throw new IllegalArgumentException("Cannot interpret empty string.");
37         }
38
39         // Remove parentheses if any
40         if (expr.charAt(0) == '(' && expr.charAt(sl - 1) == ')') {
41             return evalFloat(expr.substring(1, sl - 1), vars);
42         }
43
44         // Look for operators in the order of least priority
45         String[] sss = findOperator(expr, "-", true);
46         if (sss != null) {
47             return evalFloat(sss[0], vars) - evalFloat(sss[1], vars);
48         }
49
50         sss = findOperator(expr, "+", true);
51         if (sss != null) {
52             return evalFloat(sss[0], vars) + evalFloat(sss[1], vars);
53         }
54
55         sss = findOperator(expr, "/", true);
56         if (sss != null) {
57             return evalFloat(sss[0], vars) / evalFloat(sss[1], vars);
58         }
59
60         sss = findOperator(expr, "*", true);
61         if (sss != null) {
62             return evalFloat(sss[0], vars) * evalFloat(sss[1], vars);
63         }
64
65         // Check if expr is a number
66         try {
67             return Float.valueOf(expr);
68         } catch (Exception e) {
69         }
70
71         // Must be a variable
72         String v = vars.get(expr);
73         try {
74             return Float.valueOf(v);
75         } catch (Exception e) {
76         }
77         return 0;
78     }
79
80     public static String evalString(String expr, Map<String, String> vars) {
81         expr = expr.trim();
82         int sl = expr.length();
83         if (sl == 0) {
84             throw new IllegalArgumentException("Cannot interpret empty string.");
85         }
86
87         // Remove parentheses if any
88         if (expr.charAt(0) == '(' && expr.charAt(sl - 1) == ')') {
89             return evalString(expr.substring(1, sl - 1), vars);
90         }
91
92         // Look for operators in the order of least priority
93         String[] sss = findOperator(expr, "+", true);
94         if (sss != null) {
95             return evalString(sss[0], vars) + evalString(sss[1], vars);
96         }
97
98         // Check if expr is a number
99         try {
100             return Float.valueOf(expr).toString();
101         } catch (Exception e) {
102         }
103
104         // Check for quotes
105         if (expr.charAt(0) == '"' && expr.charAt(sl - 1) == '"') {
106             return expr.substring(1, sl - 1);
107         }
108         if (expr.charAt(0) == '\'' && expr.charAt(sl - 1) == '\'') {
109             return expr.substring(1, sl - 1);
110         }
111
112         // Must be a variable
113         String v = vars.get(expr);
114         return v != null ? v : "";
115     }
116
117     public static boolean evalBoolean(String expr, Map<String, String> vars) {
118         expr = expr.trim();
119         int sl = expr.length();
120         if (sl == 0) {
121             throw new IllegalArgumentException("Cannot interpret empty string.");
122         }
123
124         if (expr.equalsIgnoreCase("true")) {
125             return true;
126         }
127
128         if (expr.equalsIgnoreCase("false")) {
129             return false;
130         }
131
132         // Remove parentheses if any
133         if (expr.charAt(0) == '(' && expr.charAt(sl - 1) == ')') {
134             return evalBoolean(expr.substring(1, sl - 1), vars);
135         }
136
137         // Look for operators in the order of least priority
138         String[] sss = findOperator(expr, "or", true);
139         if (sss != null) {
140             return evalBoolean(sss[0], vars) || evalBoolean(sss[1], vars);
141         }
142
143         sss = findOperator(expr, "and", true);
144         if (sss != null) {
145             return evalBoolean(sss[0], vars) && evalBoolean(sss[1], vars);
146         }
147
148         sss = findOperator(expr, "not", true);
149         if (sss != null) {
150             return !evalBoolean(sss[1], vars);
151         }
152
153         sss = findOperator(expr, "!=", false);
154         if (sss == null) {
155             sss = findOperator(expr, "<>", false);
156         }
157         if (sss != null) {
158             return !evalString(sss[0], vars).equals(evalString(sss[1], vars));
159         }
160
161         sss = findOperator(expr, "==", false);
162         if (sss == null) {
163             sss = findOperator(expr, "=", false);
164         }
165         if (sss != null) {
166             return evalString(sss[0], vars).equals(evalString(sss[1], vars));
167         }
168
169         sss = findOperator(expr, ">=", false);
170         if (sss != null) {
171             return evalLong(sss[0], vars) >= evalLong(sss[1], vars);
172         }
173
174         sss = findOperator(expr, ">", false);
175         if (sss != null) {
176             return evalLong(sss[0], vars) > evalLong(sss[1], vars);
177         }
178
179         sss = findOperator(expr, "<=", false);
180         if (sss != null) {
181             return evalLong(sss[0], vars) <= evalLong(sss[1], vars);
182         }
183
184         sss = findOperator(expr, "<", false);
185         if (sss != null) {
186             return evalLong(sss[0], vars) < evalLong(sss[1], vars);
187         }
188
189         throw new IllegalArgumentException("Cannot interpret '" + expr + "': Invalid expression.");
190     }
191
192     private static String[] findOperator(String s, String op, boolean delimiterRequired) {
193         int opl = op.length();
194         int sl = s.length();
195         String delimiters = " \0\t\r\n()";
196         int pcount = 0, qcount = 0;
197         for (int i = 0; i < sl; i++) {
198             char c = s.charAt(i);
199             if (c == '(' && qcount == 0) {
200                 pcount++;
201             } else if (c == ')' && qcount == 0) {
202                 pcount--;
203                 if (pcount < 0) {
204                     throw new IllegalArgumentException("Cannot interpret '" + s + "': Parentheses do not match.");
205                 }
206             } else if (c == '\'') {
207                 qcount = (qcount + 1) % 2;
208             } else if (i <= sl - opl && pcount == 0 && qcount == 0) {
209                 String ss = s.substring(i, i + opl);
210                 if (ss.equalsIgnoreCase(op)) {
211                     boolean found = true;
212                     if (delimiterRequired) {
213                         // Check for delimiter before and after to make sure it is not part of another word
214                         char chbefore = '\0';
215                         if (i > 0) {
216                             chbefore = s.charAt(i - 1);
217                         }
218                         char chafter = '\0';
219                         if (i < sl - opl) {
220                             chafter = s.charAt(i + opl);
221                         }
222                         found = delimiters.indexOf(chbefore) >= 0 && delimiters.indexOf(chafter) >= 0;
223                     }
224                     if (found) {
225                         // We've found the operator, split the string
226                         String[] sss = new String[2];
227                         sss[0] = s.substring(0, i);
228                         sss[1] = s.substring(i + opl);
229                         return sss;
230                     }
231                 }
232             }
233         }
234         if (pcount > 0) {
235             throw new IllegalArgumentException("Cannot interpret '" + s + "': Parentheses do not match.");
236         }
237         if (qcount > 0) {
238             throw new IllegalArgumentException("Cannot interpret '" + s + "': No closing '.");
239         }
240         return null;
241     }
242
243     @SuppressWarnings("unused")
244     private static Object parseObject(String s) {
245         s = s.trim();
246         int sl = s.length();
247         if (sl == 0) {
248             throw new IllegalArgumentException("Cannot interpret empty string.");
249         }
250         if (s.equalsIgnoreCase("null")) {
251             return null;
252         }
253         if (s.charAt(0) == '\'') {
254             if (sl < 2 || s.charAt(sl - 1) != '\'') {
255                 throw new IllegalArgumentException("Cannot interpret '" + s + "': No closing '.");
256             }
257             return s.substring(1, sl - 1);
258         }
259         // Not in quotes - must be a number
260         try {
261             return Long.valueOf(s);
262         } catch (Exception e) {
263         }
264         try {
265             return Double.valueOf(s);
266         } catch (Exception e) {
267             throw new IllegalArgumentException("Cannot interpret '" + s + "': Invalid number.");
268         }
269     }
270 }