0

I have problem where I need to validate a set of inputs against a business rule.

The set of inputs can be represented by a class like

public class RuleInput{
    public String payType;
    public String bank;
    public String brand;

    //....Getters and setters
}

My system client can configure many rules in my system. To configure rule i have defined a DSL like below

RULE1 - payType in ('NB,'CC') and bank in ('HDFC', 'CITI')
RULE2 - payType in ('NB') and (bank in ('HDFC','AXIS') or brand in ('VISA'))

Now Given ruleInput = RuleInput(NB,HDFC, VISA) and function

public boolean validateAgainstRule(String ruleId, RuleInput input);

Calling this like validateAgainstRule("RULE2" , ruleInput) should return true;

I am thinking of using ANTLR for the same(But I am very new to it). I tried to build a grammar like this

expression : 
    primary_expression
    | expression OR expression
    | expression AND expression
    | LPAREN expression RPAREN
    ;

primary_expression : //A simple expression
    simple
    ;

simple : TAG_EXPR | BIN_EXPR ;

TAG : 'payment_type' | 'issuer' | 'brand' ;
BIN_TAG : 'bins' ;

BIN_EXPR : BIN_TAG IN BIN_LIST ;
TAG_EXPR : TAG IN LIST ;

LIST : LPAREN TEXT (COMMA TEXT)* RPAREN ;
BIN_LIST :  LPAREN BIN (COMMA BIN)* RPAREN ;

IN : 'in' ;
OR : 'or' ;
AND : 'and' ;

LPAREN : '(' ;
RPAREN : ')' ;

COMMA : ',' ;
TEXT : [A-Z]+ ;
BIN : [0-9][0-9][0-9][0-9][0-9][0-9] ;

WS  : [ \t\r\n]+ -> skip ;

Can somebody help me to write the grammar for my requirement. I think I need even to use actions in the grammar for accepting inputs.

Note : I even thought of using drools, but I only have a single kind of rules, it will be heavy to use drools for this kind of a small problem. So thought of going with ANTLR only.

Ysak
  • 2,601
  • 6
  • 29
  • 53

1 Answers1

1

There are a couple things I don't understand in your grammar - it doesn't seem to match your DSL...

Here, try this instead:

rule : ID '-' expression ;

expression : '(' expression ')'           # parensExpr
           | expression 'and' expression  # andExpr
           | expression 'or' expression   # orExpr
           | simpleExpr                   # clauseExpr
           ;

simpleExpr : TAG 'in' '(' stringList ')' ;

stringList : STRING (',' STRING)* ;

TAG : 'payType' | 'bank' | 'brand';
STRING : '\'' [A-Za-z0-9]* '\\';
ID: [A-Za-z0-9]+;
WS: [ \t\r\n]+ -> skip ;

ANTLR will generate a base tree visitor class for you, use this to check your expression, or build an AST and check against that (this approach is better but longer to implement).

Lucas Trzesniewski
  • 50,214
  • 11
  • 107
  • 158
  • Thanks alot, this is what I was looking for, Since I was new to this, was not able to build one from scratch, Now i think I can build and evolve this to furnish my requirement. Accepting this as an answer – Ysak Mar 22 '15 at 13:01
  • I forgot to mention: the *"and"* expression is before the *"or"* expression for a good reason: it will affect precedence (*and* has usually more precedence than *or* in programming languages anyway) – Lucas Trzesniewski Mar 22 '15 at 13:11
  • I could able to get the rule syntax validated. But how can I validate a set of input against a rule. Lets say I need to validate RuleInput('NB','HDFC', 'VISA') against rule payType in ('NB') and (bank in ('HDFC','AXIS') or brand in ('VISA')) and should return true. Can you please light me something into that also. – Ysak Mar 22 '15 at 15:11
  • Like I said in the answer, use a visitor to evaluate the expression. Look [here](http://stackoverflow.com/questions/23092081/antlr4-visitor-pattern-on-simple-arithmetic-example) for an example for math expressions. You'd have to do the same thing on boolean expressions (and it's simpler). – Lucas Trzesniewski Mar 22 '15 at 15:15
  • Is there any way to get the stringList as HashSet from the SimpleExprContext or stringListContext – Ysak Mar 22 '15 at 15:49
  • Something like `new HashSet(stringListContext.GetTokens(YourLexer.STRING).Select(token => token.Text), StringComparer.OrdinalIgnoreCase))` should do it. (Oops, that's C# but you tagged your question as [java], sorry. Just write the Java equivalent). – Lucas Trzesniewski Mar 22 '15 at 16:54
  • Thank you so much Lucas, I could able to evaluate against the rules now. Thanks alot, you saved my many days. – Ysak Mar 22 '15 at 17:00