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