a3507947f3fd63446ccf60ae5cd7321ef12c8f9f
[ccsdk/sli.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : CCSDK
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
7  * ================================================================================
8  * Modifications Copyright (C) 2018 IBM.
9  * ================================================================================
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.ccsdk.sli.core.sli.provider.base;
25
26 import java.util.List;
27
28 import org.apache.commons.lang.StringUtils;
29 import org.onap.ccsdk.sli.core.sli.SvcLogicAtom;
30 import org.onap.ccsdk.sli.core.sli.SvcLogicBinaryExpression;
31 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
32 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
33 import org.onap.ccsdk.sli.core.sli.SvcLogicExpression;
34 import org.onap.ccsdk.sli.core.sli.SvcLogicFunctionCall;
35 import org.onap.ccsdk.sli.core.sli.SvcLogicNode;
36 import org.onap.ccsdk.sli.core.sli.SvcLogicVariableTerm;
37 import org.onap.ccsdk.sli.core.sli.SvcLogicAtom.AtomType;
38 import org.onap.ccsdk.sli.core.sli.SvcLogicBinaryExpression.OperatorType;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 public class SvcLogicExpressionResolver {
43
44         private static final Logger LOG = LoggerFactory
45                         .getLogger(SvcLogicExpressionResolver.class);
46         private static final String INVALID_EXPRESSION_MSG= "Invalid expression (";
47     private static final String EXPRESSION_DEBUG_PATTERN = "Expression: ({}) resolves to: (${}) which has the value: ({})";
48
49         public static String evaluate(SvcLogicExpression expr, SvcLogicNode node,
50                         SvcLogicContext ctx) throws SvcLogicException {
51                 if (expr == null) {
52                         return (null);
53                 }
54
55                 if (expr instanceof SvcLogicAtom) {
56                         SvcLogicAtom atom = (SvcLogicAtom) expr;
57
58                         AtomType atomType = atom.getAtomType();
59                         switch (atomType) {
60                         case NUMBER:
61                         case STRING:
62                                 return (atom.toString());
63                         case CONTEXT_VAR:
64                         case IDENTIFIER:
65
66                                 String varName = resolveVariableName(atom, node, ctx);
67
68                                 if (atomType == AtomType.CONTEXT_VAR)
69                                 {
70                                         String varValue = ctx.getAttribute(varName);
71                                         if (varValue == null) {
72                                                 LOG.trace("Context variable: ($"+varName+") unset - treating as empty string");
73                                                 varValue = "";
74                                         }
75                                         LOG.trace(EXPRESSION_DEBUG_PATTERN, expr, varName, varValue);
76                                         return (varValue);
77                                 }
78
79                                 SvcLogicExpression parm = node.getParameter(varName);
80                                 if (parm != null) {
81                                         String value = evaluate(parm, node, ctx);
82                     LOG.trace(EXPRESSION_DEBUG_PATTERN, expr, varName, value);
83                                         return value;
84                                 }
85                                 else {
86                     LOG.trace(EXPRESSION_DEBUG_PATTERN, expr, varName, varName);
87                                         return(varName);
88                                 }
89                         default:
90                                 return(null);
91                         }
92
93                 } else if (expr instanceof SvcLogicBinaryExpression) {
94                         SvcLogicBinaryExpression binExpr = (SvcLogicBinaryExpression) expr;
95                         List<OperatorType> operators = binExpr.getOperators();
96                         if (operators.isEmpty())
97                         {
98                                 List<SvcLogicExpression> operands = binExpr.getOperands();
99                                 if (operands.size() == 1)
100                                 {
101                                         return(evaluate(operands.get(0), node, ctx));
102                                 }
103                                 else
104                                 {
105                                         if (operands.isEmpty())
106                                         {
107                                                 LOG.error("SvcLogicBinaryExpression has no operators and no operands - evaluating value as null");
108                                         }
109                                         else
110                                         {
111                                                 LOG.error("SvcLogicBinaryExpression has no operators and "+operands.size()+" operands - evaluating value as null");
112                                         }
113                                         return(null);
114                                 }
115                         }
116                         switch (operators.get(0)) {
117                                 case addOp:
118                                 case subOp:
119                                 case multOp:
120                                 case divOp:
121                                         return(evalArithExpression(binExpr, node, ctx));
122                                 case equalOp:
123                                 case neOp:
124                                 case ltOp:
125                                 case leOp:
126                                 case gtOp:
127                                 case geOp:
128                                         return (evalCompareExpression(binExpr, node, ctx));
129                                 case andOp:
130                                 case orOp:
131                                         return(evalLogicExpression(binExpr, node, ctx));
132
133                                 default:
134                                         return(null);
135                         }
136                 }
137                 else if (expr instanceof SvcLogicFunctionCall)
138                 {
139                         return(evalFunctionCall((SvcLogicFunctionCall)expr, node, ctx));
140                 }
141                 else
142                 {
143                         throw new SvcLogicException("Unrecognized expression type ["+expr+"]");
144                 }
145         }
146
147         private static String evalArithExpression(SvcLogicBinaryExpression binExpr, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException {
148                 List<SvcLogicExpression> operands = binExpr.getOperands();
149                 List<OperatorType> operators = binExpr.getOperators();
150                 if (operands.size() != (operators.size()+1))
151                 {
152                         throw new SvcLogicException(INVALID_EXPRESSION_MSG+binExpr+")");
153                 }
154                 String retval = evaluate(operands.get(0), node, ctx);
155                 String retsval = retval;
156                 long retlval = 0;
157                 boolean valueIsLong = false;
158
159                 int i = 1;
160                 try
161                 {
162
163                         if ((retval.length() > 0) && StringUtils.isNumeric(retval))
164                         {
165                                 retlval = Long.parseLong(retval);
166                                 valueIsLong = true;
167                         }
168                         for (OperatorType operator: operators)
169                         {
170                                 String curOperandValue = evaluate(operands.get(i++), node, ctx);
171                                 switch(operator) {
172                                 case addOp:
173                                         retsval = retsval + curOperandValue;
174                                         if (valueIsLong)
175                                         {
176                                                 if ((curOperandValue.length() > 0) && StringUtils.isNumeric(curOperandValue) )
177                                                 {
178                                                         retlval = retlval + Long.parseLong(curOperandValue);
179                                                 }
180                                                 else
181                                                 {
182                                                         valueIsLong = false;
183                                                 }
184                                         }
185                                         break;
186                                 case subOp:
187                                         retlval = retlval - Long.parseLong(curOperandValue);
188                                         break;
189                                 case multOp:
190                                         retlval = retlval * Long.parseLong(curOperandValue);
191                                         break;
192                                 case divOp:
193                                         retlval = retlval / Long.parseLong(curOperandValue);
194                                         break;
195                                 }
196
197                         }
198                 }
199                 catch (NumberFormatException e1)
200                 {
201                         throw new SvcLogicException("Illegal value in arithmetic expression", e1);
202                 }
203
204                 if (valueIsLong)
205                 {
206                         return("" + retlval);
207                 }
208                 else
209                 {
210                         return(retsval);
211                 }
212
213         }
214
215
216
217         private static String evalCompareExpression(SvcLogicBinaryExpression expr, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException
218         {
219
220                 List<OperatorType> operators = expr.getOperators();
221                 List<SvcLogicExpression> operands = expr.getOperands();
222
223                 if ((operators.size() != 1) || (operands.size() != 2))
224                 {
225                         throw new SvcLogicException ("Invalid comparison expression : "+expr);
226                 }
227
228                 OperatorType operator = operators.get(0);
229                 String op1Value = evaluate(operands.get(0), node, ctx);
230                 String op2Value = evaluate(operands.get(1), node, ctx);
231
232                 if ((StringUtils.isNotEmpty(op1Value) && StringUtils.isNumeric(op1Value) && StringUtils.isNotEmpty(op2Value) && StringUtils.isNumeric(op2Value)))
233                 {
234                         try
235                         {
236                                 double op1dbl = Double.parseDouble(op1Value);
237                                 double op2dbl = Double.parseDouble(op2Value);
238
239                                 switch(operator)
240                                 {
241                                 case equalOp:
242                                         return(Boolean.toString(op1dbl == op2dbl));
243                                 case neOp:
244                                         return(Boolean.toString(op1dbl != op2dbl));
245                                 case ltOp:
246                                         return(Boolean.toString(op1dbl < op2dbl));
247                                 case leOp:
248                                         return(Boolean.toString(op1dbl <= op2dbl));
249                                 case gtOp:
250                                         return(Boolean.toString(op1dbl > op2dbl));
251                                 case geOp:
252                                         return(Boolean.toString(op1dbl >= op2dbl));
253                                 default:
254                                         return(null);
255                                 }
256                         }
257                         catch (NumberFormatException e)
258                         {
259                                 throw new SvcLogicException("Caught exception trying to compare numeric values", e);
260                         }
261                 }
262                 else
263                 {
264
265                         int compResult = 0;
266
267                         if (op1Value == null) {
268                                 compResult = -1;
269                         } else if (op2Value == null ) {
270                                 compResult = 1;
271                         } else {
272                                 compResult = op1Value.compareToIgnoreCase(op2Value);
273                         }
274
275                         switch(operator)
276                         {
277                         case equalOp:
278                                 return(Boolean.toString(compResult == 0));
279                         case neOp:
280                                 return(Boolean.toString(compResult != 0));
281                         case ltOp:
282                                 return(Boolean.toString(compResult < 0));
283                         case leOp:
284                                 return(Boolean.toString(compResult <= 0));
285                         case gtOp:
286                                 return(Boolean.toString(compResult > 0));
287                         case geOp:
288                                 return(Boolean.toString(compResult >= 0));
289                         default:
290                                 return(null);
291                         }
292                 }
293
294         }
295
296         private static String evalLogicExpression(SvcLogicBinaryExpression expr, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException
297         {
298                 boolean retval;
299
300                 List<SvcLogicExpression> operands = expr.getOperands();
301                 List<OperatorType> operators = expr.getOperators();
302
303                 if (operands.size() != (operators.size()+1))
304                 {
305                         throw new SvcLogicException(INVALID_EXPRESSION_MSG+expr+")");
306                 }
307
308                 try
309                 {
310                         retval = Boolean.parseBoolean(evaluate(operands.get(0), node, ctx));
311                         int i = 1;
312                         for (OperatorType operator : operators)
313                         {
314                                 if (operator == OperatorType.andOp)
315                                 {
316                                         retval = retval && Boolean.parseBoolean(evaluate(operands.get(i++), node, ctx));
317                                 }
318                                 else
319                                 {
320
321                                         retval = retval || Boolean.parseBoolean(evaluate(operands.get(i++), node, ctx));
322                                 }
323
324                         }
325                 }
326                 catch (Exception e)
327                 {
328                         throw new SvcLogicException(INVALID_EXPRESSION_MSG+expr+")");
329                 }
330
331
332                 return(Boolean.toString(retval));
333         }
334
335         private static String evalFunctionCall(SvcLogicFunctionCall func, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException
336         {
337                 String funcName = func.getFunctionName();
338                 List<SvcLogicExpression> operands = func.getOperands();
339
340                 if ("length".equalsIgnoreCase(funcName))
341                 {
342
343                         if (operands.size() == 1)
344                         {
345                                 String opValue = evaluate(operands.get(0), node, ctx);
346                                 return(""+opValue.length());
347                         }
348                         else
349                         {
350                                 throw new SvcLogicException("Invalid call to length() function");
351                         }
352                 }
353                 else if ("substr".equalsIgnoreCase(funcName))
354                 {
355                         if (operands.size() == 3)
356                         {
357                                 String op1Value = evaluate(operands.get(0), node, ctx);
358                                 String op2Value = evaluate(operands.get(1), node, ctx);
359                                 String op3Value = evaluate(operands.get(2), node, ctx);
360
361                                 if (!StringUtils.isNumeric(op2Value) || !StringUtils.isNumeric(op3Value))
362                                 {
363                                         throw new SvcLogicException("Invalid arguments to substr() function");
364                                 }
365
366                                 try
367                                 {
368                                         return(op1Value.substring(Integer.parseInt(op2Value), Integer.parseInt(op3Value)));
369                                 }
370                                 catch (Exception e)
371                                 {
372                                         throw new SvcLogicException("Caught exception trying to take substring", e);
373                                 }
374                         }
375                         else
376                         {
377
378                                 throw new SvcLogicException("Invalid call to substr() function");
379                         }
380
381                 }
382                 else if ("toUpperCase".equalsIgnoreCase(funcName))
383                 {
384                         if (operands.size() == 1)
385                         {
386                                 String opValue = evaluate(operands.get(0), node, ctx);
387                                 if (opValue != null) {
388                                         return(opValue.toUpperCase());
389                                 } else {
390                                         return("");
391                                 }
392                         }
393                         else
394                         {
395                                 throw new SvcLogicException("Invalid call to toUpperCase() function");
396                         }
397                 }
398                 else if ("toLowerCase".equalsIgnoreCase(funcName))
399                 {
400                         if (operands.size() == 1)
401                         {
402                                 String opValue = evaluate(operands.get(0), node, ctx);
403                                 if (opValue != null) {
404                                         return(opValue.toLowerCase());
405                                 } else {
406                                         return("");
407                                 }
408                         }
409                         else
410                         {
411                                 throw new SvcLogicException("Invalid call to toLowerCase() function");
412                         }
413                 }
414                 else if ("convertBase".equalsIgnoreCase(funcName)) {
415                         int fromBase = 10;
416                         int toBase = 10;
417                         String srcString = "";
418
419                         if (operands.size() == 2)
420                         {
421                                 fromBase = 10;
422                                 srcString = evaluate(operands.get(0), node, ctx);
423                                 toBase = Integer.parseInt(evaluate(operands.get(1), node, ctx));
424                         } else if (operands.size() == 3) {
425
426                                 srcString = evaluate(operands.get(0), node, ctx);
427                                 fromBase = Integer.parseInt(evaluate(operands.get(1), node, ctx));
428                                 toBase = Integer.parseInt(evaluate(operands.get(2), node, ctx));
429                         } else {
430                                 throw new SvcLogicException("Invalid call to convertBase() function");
431                         }
432
433                         long srcValue = Long.parseLong(srcString, fromBase);
434                         return(Long.toString(srcValue, toBase));
435                 }
436                 else
437                 {
438                         throw new SvcLogicException("Unrecognized function ("+funcName+")");
439                 }
440
441         }
442
443         public static String evaluateAsKey(SvcLogicExpression expr, SvcLogicNode node,
444                         SvcLogicContext ctx) throws SvcLogicException {
445                 if (expr == null) {
446                         return (null);
447                 }
448
449
450
451                 if (expr instanceof SvcLogicAtom) {
452                         SvcLogicAtom atom = (SvcLogicAtom) expr;
453
454                         AtomType atomType = atom.getAtomType();
455                         StringBuffer varNameBuff = new StringBuffer();
456                         switch (atomType) {
457                         case NUMBER:
458                                 return (atom.toString());
459                         case STRING:
460                                 return("'"+atom.toString()+"'");
461                         case CONTEXT_VAR:
462                         case IDENTIFIER:
463                                 boolean needDot = false;
464                 for (SvcLogicExpression term : atom.getOperands())
465                 {
466                         if (needDot)
467                         {
468                                 varNameBuff.append(".");
469                         }
470                         if (term instanceof SvcLogicVariableTerm)
471                         {
472                                 SvcLogicVariableTerm vterm = (SvcLogicVariableTerm) term;
473                                 varNameBuff.append(vterm.getName());
474                                 if (vterm.numOperands() > 0)
475                                 {
476                                         varNameBuff.append("[");
477                                         varNameBuff.append(evaluate(vterm.getSubscript(), node, ctx));
478                                         varNameBuff.append("]");
479
480                                 }
481                         }
482                         else
483                         {
484                                 varNameBuff.append(term.toString());
485                         }
486                         needDot = true;
487                 }
488
489                                 String varName = varNameBuff.toString();
490                                 String ctxValue = ctx.getAttribute(varName);
491                                 if (ctxValue == null)
492                                 {
493                                         return(null);
494                                 }
495                                 if (StringUtils.isNumeric(ctxValue))
496                                 {
497                                         return(ctxValue);
498                                 }
499                                 else
500                                 {
501                                         return("'"+ctxValue+"'");
502                                 }
503
504                         default:
505                                 return(null);
506                         }
507
508                 } else if (expr instanceof SvcLogicBinaryExpression) {
509                         SvcLogicBinaryExpression binExpr = (SvcLogicBinaryExpression) expr;
510                         List<OperatorType> operators = binExpr.getOperators();
511                         List<SvcLogicExpression> operands = binExpr.getOperands();
512                         if (operators.isEmpty())
513                         {
514                                 if (operands.size() == 1)
515                                 {
516                                         LOG.debug("SvcLogicBinaryExpression as no operator and one operand - evaluating its operand");
517                                         return(evaluateAsKey(operands.get(0), node, ctx));
518                                 }
519                                 else
520                                 {
521                                         if (operands.isEmpty())
522                                         {
523                                                 LOG.error("SvcLogicBinaryExpression has no operators and no operands - evaluating value as null");
524                                         }
525                                         else
526                                         {
527                                                 LOG.error("SvcLogicBinaryExpression has no operators and "+operands.size()+" operands - evaluating value as null");
528                                         }
529                                         return(null);
530                                 }
531                         }
532                         StringBuffer sbuff = new StringBuffer();
533                         sbuff.append(evaluateAsKey(operands.get(0), node, ctx));
534                         int i = 1;
535                         for (OperatorType operator : operators)
536                         {
537                                 sbuff.append(" ");
538                                 sbuff.append(operator.toString());
539                                 sbuff.append(" ");
540                                 sbuff.append(evaluateAsKey(operands.get(i++), node,ctx));
541                         }
542                         return(sbuff.toString());
543                 }
544                 else if (expr instanceof SvcLogicFunctionCall)
545                 {
546                         StringBuffer sbuff = new StringBuffer();
547                         SvcLogicFunctionCall funcCall = (SvcLogicFunctionCall) expr;
548                         sbuff.append(funcCall.getFunctionName());
549                         sbuff.append("(");
550                         boolean needComma = false;
551                         for (SvcLogicExpression operand : funcCall.getOperands())
552                         {
553                                 if (needComma)
554                                 {
555                                         sbuff.append(",");
556                                 }
557                                 else
558                                 {
559                                         needComma = true;
560                                 }
561                                 sbuff.append(evaluateAsKey(operand, node, ctx));
562                         }
563                         sbuff.append(")");
564                         return(sbuff.toString());
565                 }
566                 else
567                 {
568                         throw new SvcLogicException("Unrecognized expression type ["+expr+"]");
569                 }
570         }
571
572         public static String resolveVariableName(SvcLogicExpression atom, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException
573         {
574                 StringBuffer varNameBuff = new StringBuffer();
575
576                 boolean needDot = false;
577                 for (SvcLogicExpression term : atom.getOperands())
578                 {
579                         if (needDot)
580                         {
581                                 varNameBuff.append(".");
582                         }
583                         if (term instanceof SvcLogicVariableTerm)
584                         {
585                                 SvcLogicVariableTerm vterm = (SvcLogicVariableTerm) term;
586                                 varNameBuff.append(vterm.getName());
587                                 if (vterm.numOperands() > 0)
588                                 {
589                                         varNameBuff.append("[");
590                                         varNameBuff.append(evaluate(vterm.getSubscript(), node, ctx));
591                                         varNameBuff.append("]");
592                                 }
593                         }
594                         else
595                         {
596                                 varNameBuff.append(term.toString());
597                         }
598                         needDot = true;
599                 }
600                 return(varNameBuff.toString());
601         }
602
603 }