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