59ba6cd7740d9376a53e90c005e963d8e59dc8c9
[ccsdk/sli/core.git] / sli / provider-base / src / main / java / org / onap / ccsdk / sli / core / sli / provider / base / SvcLogicExpressionResolver.java
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
48         public static String evaluate(SvcLogicExpression expr, SvcLogicNode node,
49                         SvcLogicContext ctx) throws SvcLogicException {
50                 if (expr == null) {
51                         return (null);
52                 }
53
54         
55
56                 if (expr instanceof SvcLogicAtom) {
57                         SvcLogicAtom atom = (SvcLogicAtom) expr;
58
59                         AtomType atomType = atom.getAtomType();
60                         switch (atomType) {
61                         case NUMBER:
62                         case STRING:
63                                 return (atom.toString());
64                         case CONTEXT_VAR:
65                         case IDENTIFIER:
66         
67                                 String varName = resolveVariableName(atom, node, ctx);
68                                 
69                                 if (atomType == AtomType.CONTEXT_VAR)
70                                 {
71                                         
72                                         String varValue = ctx.getAttribute(varName);
73                                         
74                                         if (varValue == null) {
75                                                 LOG.trace("Context variable $"+varName+" unset - treating as empty string");
76                                                 varValue = "";
77                                         }
78                                                 
79                                         return (varValue);
80                                 }
81                                 SvcLogicExpression parm = node.getParameter(varName);
82                                 if (parm != null) {                             
83                                         return (evaluate(parm, node, ctx));
84                                 }
85                                 else
86                                 {
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                                         LOG.trace("SvcLogicBinaryExpression as no operator and one operand - evaluating its operand");
102                                         return(evaluate(operands.get(0), node, ctx));
103                                 }
104                                 else
105                                 {
106                                         if (operands.isEmpty())
107                                         {
108                                                 LOG.error("SvcLogicBinaryExpression has no operators and no operands - evaluating value as null");
109                                         }
110                                         else
111                                         {
112                                                 LOG.error("SvcLogicBinaryExpression has no operators and "+operands.size()+" operands - evaluating value as null");
113                                         }
114                                         return(null);
115                                 }
116                         }
117                         switch (operators.get(0)) {
118                                 case addOp:
119                                 case subOp:
120                                 case multOp:
121                                 case divOp:
122                                         return(evalArithExpression(binExpr, node, ctx));
123                                 case equalOp:
124                                 case neOp:
125                                 case ltOp:
126                                 case leOp:
127                                 case gtOp:
128                                 case geOp:
129                                         return (evalCompareExpression(binExpr, node, ctx));
130                                 case andOp:
131                                 case orOp:
132                                         return(evalLogicExpression(binExpr, node, ctx));
133
134                                 default:
135                                         return(null);
136                         }
137                 }
138                 else if (expr instanceof SvcLogicFunctionCall)
139                 {
140                         return(evalFunctionCall((SvcLogicFunctionCall)expr, node, ctx));
141                 }
142                 else
143                 {
144                         throw new SvcLogicException("Unrecognized expression type ["+expr+"]");
145                 }
146         }
147
148         private static String evalArithExpression(SvcLogicBinaryExpression binExpr, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException {
149                 List<SvcLogicExpression> operands = binExpr.getOperands();
150                 List<OperatorType> operators = binExpr.getOperators();
151                 if (operands.size() != (operators.size()+1))
152                 {
153                         throw new SvcLogicException(INVALID_EXPRESSION_MSG+binExpr+")");
154                 }       
155                 String retval = evaluate(operands.get(0), node, ctx);
156                 String retsval = retval;
157                 long retlval = 0;
158                 boolean valueIsLong = false;
159
160                 int i = 1;
161                 try
162                 {
163                         
164                         if ((retval.length() > 0) && StringUtils.isNumeric(retval))
165                         {
166                                 retlval = Long.parseLong(retval);
167                                 valueIsLong = true;
168                         }
169                         for (OperatorType operator: operators)
170                         {
171                                 String curOperandValue = evaluate(operands.get(i++), node, ctx);
172                                 switch(operator) {
173                                 case addOp:
174                                         retsval = retsval + curOperandValue;
175                                         if (valueIsLong)
176                                         {
177                                                 if ((curOperandValue.length() > 0) && StringUtils.isNumeric(curOperandValue) )
178                                                 {
179                                                         retlval = retlval + Long.parseLong(curOperandValue);
180                                                 }
181                                                 else
182                                                 {
183                                                         valueIsLong = false;
184                                                 }
185                                         }
186                                         break;
187                                 case subOp:
188                                         retlval = retlval - Long.parseLong(curOperandValue);
189                                         break;
190                                 case multOp:
191                                         retlval = retlval * Long.parseLong(curOperandValue);
192                                         break;
193                                 case divOp:
194                                         retlval = retlval / Long.parseLong(curOperandValue);
195                                         break;
196                                 }
197
198                         }
199                 }
200                 catch (NumberFormatException e1)
201                 {
202                         throw new SvcLogicException("Illegal value in arithmetic expression", e1);
203                 }
204                 
205                 if (valueIsLong)
206                 {
207                         return("" + retlval);
208                 }
209                 else
210                 {
211                         return(retsval);
212                 }
213                 
214         }
215
216
217         
218         private static String evalCompareExpression(SvcLogicBinaryExpression expr, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException
219         {
220
221                 List<OperatorType> operators = expr.getOperators();
222                 List<SvcLogicExpression> operands = expr.getOperands();
223                 
224                 if ((operators.size() != 1) || (operands.size() != 2))
225                 {
226                         throw new SvcLogicException ("Invalid comparison expression : "+expr);
227                 }
228                 
229                 OperatorType operator = operators.get(0);
230                 String op1Value = evaluate(operands.get(0), node, ctx);
231                 String op2Value = evaluate(operands.get(1), node, ctx);
232                 
233                 if ((StringUtils.isNotEmpty(op1Value) && StringUtils.isNumeric(op1Value) && StringUtils.isNotEmpty(op2Value) && StringUtils.isNumeric(op2Value)))
234                 {
235                         try
236                         {
237                                 double op1dbl = Double.parseDouble(op1Value);
238                                 double op2dbl = Double.parseDouble(op2Value);
239                                 
240                                 switch(operator)
241                                 {
242                                 case equalOp:
243                                         return(Boolean.toString(op1dbl == op2dbl));
244                                 case neOp:
245                                         return(Boolean.toString(op1dbl != op2dbl));
246                                 case ltOp:
247                                         return(Boolean.toString(op1dbl < op2dbl));
248                                 case leOp:
249                                         return(Boolean.toString(op1dbl <= op2dbl));
250                                 case gtOp:
251                                         return(Boolean.toString(op1dbl > op2dbl));
252                                 case geOp:
253                                         return(Boolean.toString(op1dbl >= op2dbl));
254                                 default:
255                                         return(null);
256                                 }
257                         }
258                         catch (NumberFormatException e)
259                         {
260                                 throw new SvcLogicException("Caught exception trying to compare numeric values", e);
261                         }
262                 }
263                 else
264                 {
265                         
266                         int compResult = 0;
267                         
268                         if (op1Value == null) {
269                                 compResult = -1;
270                         } else if (op2Value == null ) {
271                                 compResult = 1;
272                         } else {
273                                 compResult = op1Value.compareToIgnoreCase(op2Value);
274                         }
275                         
276                         switch(operator)
277                         {
278                         case equalOp:
279                                 return(Boolean.toString(compResult == 0));
280                         case neOp:
281                                 return(Boolean.toString(compResult != 0));
282                         case ltOp:
283                                 return(Boolean.toString(compResult < 0));
284                         case leOp:
285                                 return(Boolean.toString(compResult <= 0));
286                         case gtOp:
287                                 return(Boolean.toString(compResult > 0));
288                         case geOp:
289                                 return(Boolean.toString(compResult >= 0));
290                         default:
291                                 return(null);
292                         }
293                 }
294                 
295         }
296         
297         private static String evalLogicExpression(SvcLogicBinaryExpression expr, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException
298         {
299                 boolean retval;
300                 
301                 List<SvcLogicExpression> operands = expr.getOperands();
302                 List<OperatorType> operators = expr.getOperators();
303                 
304                 if (operands.size() != (operators.size()+1))
305                 {
306                         throw new SvcLogicException(INVALID_EXPRESSION_MSG+expr+")");
307                 }
308                 
309                 try
310                 {
311                         retval = Boolean.parseBoolean(evaluate(operands.get(0), node, ctx));
312                         int i = 1;
313                         for (OperatorType operator : operators)
314                         {
315                                 if (operator == OperatorType.andOp)
316                                 {
317                                         retval = retval && Boolean.parseBoolean(evaluate(operands.get(i++), node, ctx));
318                                 }
319                                 else
320                                 {
321
322                                         retval = retval || Boolean.parseBoolean(evaluate(operands.get(i++), node, ctx));
323                                 }
324                                 
325                         }
326                 }
327                 catch (Exception e)
328                 {
329                         throw new SvcLogicException(INVALID_EXPRESSION_MSG+expr+")");
330                 }
331                 
332                 
333                 return(Boolean.toString(retval));
334         }
335         
336         private static String evalFunctionCall(SvcLogicFunctionCall func, SvcLogicNode node, SvcLogicContext ctx) throws SvcLogicException
337         {
338                 String funcName = func.getFunctionName();
339                 List<SvcLogicExpression> operands = func.getOperands();
340                 
341                 if ("length".equalsIgnoreCase(funcName))
342                 {
343                         
344                         if (operands.size() == 1)
345                         {
346                                 String opValue = evaluate(operands.get(0), node, ctx);
347                                 return(""+opValue.length());
348                         }
349                         else
350                         {
351                                 throw new SvcLogicException("Invalid call to length() function");
352                         }
353                 }
354                 else if ("substr".equalsIgnoreCase(funcName))
355                 {
356                         if (operands.size() == 3)
357                         {
358                                 String op1Value = evaluate(operands.get(0), node, ctx);
359                                 String op2Value = evaluate(operands.get(1), node, ctx);
360                                 String op3Value = evaluate(operands.get(2), node, ctx);
361                                 
362                                 if (!StringUtils.isNumeric(op2Value) || !StringUtils.isNumeric(op3Value))
363                                 {
364                                         throw new SvcLogicException("Invalid arguments to substr() function");
365                                 }
366                                 
367                                 try
368                                 {
369                                         return(op1Value.substring(Integer.parseInt(op2Value), Integer.parseInt(op3Value)));
370                                 }
371                                 catch (Exception e)
372                                 {
373                                         throw new SvcLogicException("Caught exception trying to take substring", e);
374                                 }
375                         }
376                         else
377                         {
378
379                                 throw new SvcLogicException("Invalid call to substr() function");
380                         }
381                         
382                 }
383                 else if ("toUpperCase".equalsIgnoreCase(funcName))
384                 {
385                         if (operands.size() == 1)
386                         {
387                                 String opValue = evaluate(operands.get(0), node, ctx);
388                                 if (opValue != null) {
389                                         return(opValue.toUpperCase());
390                                 } else {
391                                         return("");
392                                 }
393                         }
394                         else
395                         {
396                                 throw new SvcLogicException("Invalid call to toUpperCase() function");
397                         }
398                 }
399                 else if ("toLowerCase".equalsIgnoreCase(funcName))
400                 {
401                         if (operands.size() == 1)
402                         {
403                                 String opValue = evaluate(operands.get(0), node, ctx);
404                                 if (opValue != null) {
405                                         return(opValue.toLowerCase());
406                                 } else {
407                                         return("");
408                                 }
409                         }
410                         else
411                         {
412                                 throw new SvcLogicException("Invalid call to toLowerCase() function");
413                         }
414                 }
415                 else if ("convertBase".equalsIgnoreCase(funcName)) {
416                         int fromBase = 10;
417                         int toBase = 10;
418                         String srcString = "";
419                         
420                         if (operands.size() == 2)
421                         {
422                                 fromBase = 10;
423                                 srcString = evaluate(operands.get(0), node, ctx);
424                                 toBase = Integer.parseInt(evaluate(operands.get(1), node, ctx));
425                         } else if (operands.size() == 3) {
426
427                                 srcString = evaluate(operands.get(0), node, ctx);
428                                 fromBase = Integer.parseInt(evaluate(operands.get(1), node, ctx));
429                                 toBase = Integer.parseInt(evaluate(operands.get(2), node, ctx));
430                         } else {
431                                 throw new SvcLogicException("Invalid call to convertBase() function");
432                         }
433                         
434                         long srcValue = Long.parseLong(srcString, fromBase);
435                         return(Long.toString(srcValue, toBase));
436                 }
437                 else
438                 {
439                         throw new SvcLogicException("Unrecognized function ("+funcName+")");
440                 }
441                 
442         }
443         
444         public static String evaluateAsKey(SvcLogicExpression expr, SvcLogicNode node,
445                         SvcLogicContext ctx) throws SvcLogicException {
446                 if (expr == null) {
447                         return (null);
448                 }
449
450         
451
452                 if (expr instanceof SvcLogicAtom) {
453                         SvcLogicAtom atom = (SvcLogicAtom) expr;
454
455                         AtomType atomType = atom.getAtomType();
456                         StringBuffer varNameBuff = new StringBuffer();
457                         switch (atomType) {
458                         case NUMBER:
459                                 return (atom.toString());
460                         case STRING:
461                                 return("'"+atom.toString()+"'");
462                         case CONTEXT_VAR:
463                         case IDENTIFIER:
464                                 boolean needDot = false;
465                 for (SvcLogicExpression term : atom.getOperands())
466                 {
467                         if (needDot)
468                         {
469                                 varNameBuff.append(".");
470                         }
471                         if (term instanceof SvcLogicVariableTerm)
472                         {
473                                 SvcLogicVariableTerm vterm = (SvcLogicVariableTerm) term;
474                                 varNameBuff.append(vterm.getName());
475                                 if (vterm.numOperands() > 0)
476                                 {
477                                         varNameBuff.append("[");
478                                         varNameBuff.append(evaluate(vterm.getSubscript(), node, ctx));
479                                         varNameBuff.append("]");
480                                         
481                                 }
482                         }
483                         else
484                         {
485                                 varNameBuff.append(term.toString());
486                         }
487                         needDot = true;
488                 }
489
490                                 String varName = varNameBuff.toString();
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 }