Update groupId to org.onap.ccsdk.sli
[ccsdk/sli/core.git] / sli / provider / src / main / java / org / onap / ccsdk / sli / core / sli / provider / SvcLogicExpressionResolver.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : CCSDK
4  * ================================================================================
5  * Copyright (C) 2017 ONAP
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.ccsdk.sli.core.sli.provider;
22
23 import java.util.List;
24
25 import org.apache.commons.lang.StringUtils;
26 import org.onap.ccsdk.sli.core.sli.SvcLogicAtom;
27 import org.onap.ccsdk.sli.core.sli.SvcLogicBinaryExpression;
28 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
29 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
30 import org.onap.ccsdk.sli.core.sli.SvcLogicExpression;
31 import org.onap.ccsdk.sli.core.sli.SvcLogicFunctionCall;
32 import org.onap.ccsdk.sli.core.sli.SvcLogicNode;
33 import org.onap.ccsdk.sli.core.sli.SvcLogicVariableTerm;
34 import org.onap.ccsdk.sli.core.sli.SvcLogicAtom.AtomType;
35 import org.onap.ccsdk.sli.core.sli.SvcLogicBinaryExpression.OperatorType;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 public class SvcLogicExpressionResolver {
40
41         private static final Logger LOG = LoggerFactory
42                         .getLogger(SvcLogicExpressionResolver.class);
43
44         public static String evaluate(SvcLogicExpression expr, SvcLogicNode node,
45                         SvcLogicContext ctx) throws SvcLogicException {
46                 if (expr == null) {
47                         return (null);
48                 }
49
50         
51
52                 if (expr instanceof SvcLogicAtom) {
53                         SvcLogicAtom atom = (SvcLogicAtom) expr;
54
55                         AtomType atomType = atom.getAtomType();
56                         switch (atomType) {
57                         case NUMBER:
58                         case STRING:
59                                 return (atom.toString());
60                         case CONTEXT_VAR:
61                         case IDENTIFIER:
62         
63                                 String varName = resolveVariableName(atom, node, ctx);
64                                 
65                                 if (atomType == AtomType.CONTEXT_VAR)
66                                 {
67                                         LOG.trace("Evaluating context variable $"+varName);
68                                         
69                                         String varValue = ctx.getAttribute(varName);
70                                         
71                                         if (varValue == null) {
72                                                 LOG.trace("Context variable $"+varName+" unset - treating as empty string");
73                                                 varValue = "";
74                                         }
75                                                 
76                                         return (varValue);
77                                 }
78                                 SvcLogicExpression parm = node.getParameter(varName);
79                                 if (parm != null) {
80                                         LOG.trace("Evaluating value of parameter "+varName+": "+parm.asParsedExpr());
81                                         
82                                         return (evaluate(parm, node, ctx));
83                                 }
84                                 else
85                                 {
86                                         return(varName);
87                                 }
88                         default:
89                                 return(null);
90                         }
91
92                 } else if (expr instanceof SvcLogicBinaryExpression) {
93                         SvcLogicBinaryExpression binExpr = (SvcLogicBinaryExpression) expr;
94                         List<OperatorType> operators = binExpr.getOperators();
95                         if (operators.isEmpty())
96                         {
97                                 List<SvcLogicExpression> operands = binExpr.getOperands();
98                                 if (operands.size() == 1)
99                                 {
100                                         LOG.trace("SvcLogicBinaryExpression as no operator and one operand - evaluating its operand");
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 ("+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 ("+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 ("+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                                 LOG.debug("Evaluating context variable $"+varName);
491                                 String ctxValue = ctx.getAttribute(varName);
492                                 if (ctxValue == null)
493                                 {
494                                         return(null);
495                                 }
496                                 if (StringUtils.isNumeric(ctxValue))
497                                 {
498                                         return(ctxValue);
499                                 }
500                                 else
501                                 {
502                                         return("'"+ctxValue+"'");
503                                 }
504         
505                         default:
506                                 return(null);
507                         }
508
509                 } else if (expr instanceof SvcLogicBinaryExpression) {
510                         SvcLogicBinaryExpression binExpr = (SvcLogicBinaryExpression) expr;
511                         List<OperatorType> operators = binExpr.getOperators();
512                         List<SvcLogicExpression> operands = binExpr.getOperands();
513                         if (operators.isEmpty())
514                         {
515                                 if (operands.size() == 1)
516                                 {
517                                         LOG.debug("SvcLogicBinaryExpression as no operator and one operand - evaluating its operand");
518                                         return(evaluateAsKey(operands.get(0), node, ctx));
519                                 }
520                                 else
521                                 {
522                                         if (operands.isEmpty())
523                                         {
524                                                 LOG.error("SvcLogicBinaryExpression has no operators and no operands - evaluating value as null");
525                                         }
526                                         else
527                                         {
528                                                 LOG.error("SvcLogicBinaryExpression has no operators and "+operands.size()+" operands - evaluating value as null");
529                                         }
530                                         return(null);
531                                 }
532                         }
533                         StringBuffer sbuff = new StringBuffer();
534                         sbuff.append(evaluateAsKey(operands.get(0), node, ctx));
535                         int i = 1;
536                         for (OperatorType operator : operators)
537                         {
538                                 sbuff.append(" ");
539                                 sbuff.append(operator.toString());
540                                 sbuff.append(" ");
541                                 sbuff.append(evaluateAsKey(operands.get(i++), node,ctx));
542                         }
543                         return(sbuff.toString());
544                 }
545                 else if (expr instanceof SvcLogicFunctionCall)
546                 {
547                         StringBuffer sbuff = new StringBuffer();
548                         SvcLogicFunctionCall funcCall = (SvcLogicFunctionCall) expr;
549                         sbuff.append(funcCall.getFunctionName());
550                         sbuff.append("(");
551                         boolean needComma = false;
552                         for (SvcLogicExpression operand : funcCall.getOperands())
553                         {
554                                 if (needComma)
555                                 {
556                                         sbuff.append(",");
557                                 }
558                                 else
559                                 {
560                                         needComma = true;
561                                 }
562                                 sbuff.append(evaluateAsKey(operand, node, ctx));
563                         }
564                         sbuff.append(")");
565                         return(sbuff.toString());
566                 }
567                 else
568                 {
569                         throw new SvcLogicException("Unrecognized expression type ["+expr+"]");
570                 }
571         }
572         
573         public static String resolveVariableName(SvcLogicExpression atom, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException
574         {
575                 StringBuffer varNameBuff = new StringBuffer();
576                 
577                 boolean needDot = false;
578                 for (SvcLogicExpression term : atom.getOperands())
579                 {
580                         if (needDot)
581                         {
582                                 varNameBuff.append(".");
583                         }
584                         if (term instanceof SvcLogicVariableTerm)
585                         {
586                                 SvcLogicVariableTerm vterm = (SvcLogicVariableTerm) term;
587                                 varNameBuff.append(vterm.getName());
588                                 if (vterm.numOperands() > 0)
589                                 {
590                                         varNameBuff.append("[");
591                                         varNameBuff.append(evaluate(vterm.getSubscript(), node, ctx));
592                                         varNameBuff.append("]");
593                                 }
594                         }
595                         else
596                         {
597                                 varNameBuff.append(term.toString());
598                         }
599                         needDot = true;
600                 }
601                 return(varNameBuff.toString());
602         }
603
604 }