Separate lang (#30)

* Separate all interfaces
This commit is contained in:
Kostya 2020-06-10 14:03:17 +03:00 committed by GitHub
parent f85dade3c0
commit 44be6b8481
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
107 changed files with 2489 additions and 1099 deletions

13
pom.xml
View File

@ -11,7 +11,7 @@
</parent>
<artifactId>fraudo</artifactId>
<version>0.0.14</version>
<version>0.0.15</version>
<name>Fraudo</name>
<description>Language for describing antifraud patterns</description>
@ -33,10 +33,9 @@
</scm>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>8</java.version>
<dockerfile.base.service.tag>bc95d0d6dc13c693acd2b274531a7d604b877bf3</dockerfile.base.service.tag>
<dockerfile.registry>${env.REGISTRY}</dockerfile.registry>
<hamcrest.junit.version>2.0.0.0</hamcrest.junit.version>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
</properties>
@ -79,6 +78,12 @@
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -1,187 +0,0 @@
grammar Fraudo;
parse
: fraud_rule* EOF
;
fraud_rule
: RULE_BLOCK (IDENTIFIER ':')? expression RETURN result (CATCH_ERROR catch_result)? SCOL
;
expression
: LPAREN expression RPAREN #parenExpression
| NOT expression #notExpression
| left=expression op=comparator right=expression #comparatorExpression
| left=expression op=binary right=expression #binaryExpression
| bool #boolExpression
| count #countExpression
| count_success #countSuccessExpression
| count_error #countErrorExpression
| count_chargeback #countChargebackExpression
| count_refund #countRefundExpression
| sum #sumExpression
| sum_success #sumSuccessExpression
| sum_error #sumErrorExpression
| sum_chargeback #sumChargebackExpression
| sum_refund #sumRefundExpression
| unique #uniqueExpression
| in #inFunctionExpression
| in_white_list #inWhiteListExpression
| in_black_list #inBlackListExpression
| in_grey_list #inGreyListExpression
| in_list #inListExpression
| like #likeFunctionExpression
| country #countryFunctionExpression
| country_by #countryByFunctionExpression
| amount #amountFunctionExpression
| currency #currencyFunctionExpression
| IDENTIFIER #identifierExpression
| DECIMAL #decimalExpression
| STRING #stringExpression
;
comparator
: GT | GE | LT | LE | EQ
;
binary
: AND | OR
;
bool
: TRUE | FALSE
;
amount
: 'amount' LPAREN RPAREN
;
currency
: 'currency' LPAREN RPAREN
;
count
: 'count' LPAREN STRING time_window (group_by)? RPAREN
;
count_success
: 'countSuccess' LPAREN STRING time_window (group_by)? RPAREN
;
count_error
: 'countError' LPAREN STRING time_window DELIMETER STRING (group_by)? RPAREN
;
count_chargeback
: 'countChargeback' LPAREN STRING time_window (group_by)? RPAREN
;
count_refund
: 'countRefund' LPAREN STRING time_window (group_by)? RPAREN
;
sum
: 'sum' LPAREN STRING time_window (group_by)? RPAREN
;
sum_success
: 'sumSuccess' LPAREN STRING time_window (group_by)? RPAREN
;
sum_error
: 'sumError' LPAREN STRING time_window DELIMETER STRING (group_by)? RPAREN
;
sum_chargeback
: 'sumChargeback' LPAREN STRING time_window (group_by)? RPAREN
;
sum_refund
: 'sumRefund' LPAREN STRING time_window (group_by)? RPAREN
;
unique
: 'unique' LPAREN STRING DELIMETER STRING time_window (group_by)? RPAREN
;
in
: 'in' LPAREN (country_by | STRING) DELIMETER string_list RPAREN
;
in_white_list
: 'inWhiteList' LPAREN string_list RPAREN
;
in_black_list
: 'inBlackList' LPAREN string_list RPAREN
;
in_grey_list
: 'inGreyList' LPAREN string_list RPAREN
;
in_list
: 'inList' LPAREN STRING DELIMETER string_list RPAREN
;
like
: 'like' LPAREN STRING DELIMETER STRING RPAREN
;
country
: 'country' LPAREN RPAREN
;
country_by
: 'countryBy' LPAREN STRING RPAREN
;
result
: 'accept' | '3ds' | 'highRisk' | 'decline' | 'notify'
;
catch_result
: 'accept' | '3ds' | 'highRisk' | 'notify'
;
string_list
: STRING (DELIMETER STRING | WS)*
;
time_window
: DELIMETER DECIMAL | DELIMETER DECIMAL DELIMETER DECIMAL
;
group_by
: DELIMETER string_list
;
STRING
: '"' (~["\r\n] | '""')* '"'
;
DELIMETER : ',' ;
COMMENT
: '#' ~[\r\n]* -> skip
;
RETURN : '->' ;
CATCH_ERROR: 'catch:' ;
RULE_BLOCK : 'rule:' ;
AND : 'AND' | 'and';
OR : 'OR' | 'or' ;
NOT : 'NOT' | 'not';
TRUE : 'TRUE' | 'true';
FALSE : 'FALSE' | 'false';
GT : '>' ;
GE : '>=' ;
LT : '<' ;
LE : '<=' ;
EQ : '=' ;
LPAREN : '(' ;
RPAREN : ')' ;
DECIMAL : '-'? [0-9]+ ( '.' [0-9]+ )? ;
IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]* ;
WS : [ \u000C\n]+ -> skip;
SCOL : ';';

View File

@ -0,0 +1,61 @@
grammar FraudoP2P;
import Fraudo;
//This rule override for run test in idea plugin
parse
: fraud_rule* EOF
;
expression
: booleanAndExpression ( OR booleanAndExpression )*
;
booleanAndExpression
: equalityExpression ( AND equalityExpression )*
;
equalityExpression
: relationalExpression
| stringExpression (EQ | NEQ) stringExpression
| NOT expression
| LPAREN expression RPAREN
;
stringExpression
: country_by
| currency
| STRING
;
relationalExpression
: unaryExpression (LT | LE | GT | GE | EQ | NEQ) unaryExpression
| in
| in_white_list
| in_black_list
| in_grey_list
| in_list
| like
;
unaryExpression
: integerExpression
| floatExpression
;
integerExpression
: count
| unique
| INTEGER
;
floatExpression
: sum
| amount
| INTEGER
| DECIMAL
;
in
: 'in' LPAREN (stringExpression) DELIMETER string_list RPAREN
;

View File

@ -0,0 +1,101 @@
grammar FraudoPayment;
import Fraudo;
//This rule override for run test in idea plugin
parse
: fraud_rule* EOF
;
expression
: booleanAndExpression ( OR booleanAndExpression )*
;
booleanAndExpression
: equalityExpression ( AND equalityExpression )*
;
equalityExpression
: relationalExpression
| stringExpression (EQ | NEQ) stringExpression
| NOT expression
| LPAREN expression RPAREN
;
stringExpression
: country_by
| currency
| STRING
;
relationalExpression
: unaryExpression (LT | LE | GT | GE | EQ | NEQ) unaryExpression
| in
| in_white_list
| in_black_list
| in_grey_list
| in_list
| like
;
unaryExpression
: integerExpression
| floatExpression
;
integerExpression
: count
| count_success
| count_error
| count_chargeback
| count_refund
| unique
| INTEGER
;
floatExpression
: sum
| sum_success
| sum_error
| sum_chargeback
| sum_refund
| amount
| INTEGER
| DECIMAL
;
count_success
: 'countSuccess' LPAREN STRING time_window (group_by)? RPAREN
;
count_error
: 'countError' LPAREN STRING time_window DELIMETER STRING (group_by)? RPAREN
;
count_chargeback
: 'countChargeback' LPAREN STRING time_window (group_by)? RPAREN
;
count_refund
: 'countRefund' LPAREN STRING time_window (group_by)? RPAREN
;
sum_success
: 'sumSuccess' LPAREN STRING time_window (group_by)? RPAREN
;
sum_error
: 'sumError' LPAREN STRING time_window DELIMETER STRING (group_by)? RPAREN
;
sum_chargeback
: 'sumChargeback' LPAREN STRING time_window (group_by)? RPAREN
;
sum_refund
: 'sumRefund' LPAREN STRING time_window (group_by)? RPAREN
;
in
: 'in' LPAREN (stringExpression) DELIMETER string_list RPAREN
;

View File

@ -0,0 +1,126 @@
grammar Fraudo;
parse
: fraud_rule* EOF
;
fraud_rule
: RULE_BLOCK (IDENTIFIER ':')? expression RETURN result (CATCH_ERROR catch_result)? SCOL
;
expression
: LPAREN expression RPAREN #parenExpression
;
comparator
: GT | GE | LT | LE | EQ
;
binary
: AND | OR
;
bool
: TRUE | FALSE
;
amount
: 'amount' LPAREN RPAREN
;
currency
: 'currency' LPAREN RPAREN
;
count
: 'count' LPAREN STRING time_window (group_by)? RPAREN
;
sum
: 'sum' LPAREN STRING time_window (group_by)? RPAREN
;
unique
: 'unique' LPAREN STRING DELIMETER STRING time_window (group_by)? RPAREN
;
in
: 'in' LPAREN (country_by | STRING) DELIMETER string_list RPAREN
;
in_white_list
: 'inWhiteList' LPAREN string_list RPAREN
;
in_black_list
: 'inBlackList' LPAREN string_list RPAREN
;
in_grey_list
: 'inGreyList' LPAREN string_list RPAREN
;
in_list
: 'inList' LPAREN STRING DELIMETER string_list RPAREN
;
like
: 'like' LPAREN STRING DELIMETER STRING RPAREN
;
country_by
: 'countryBy' LPAREN STRING RPAREN
;
result
: 'accept' | '3ds' | 'highRisk' | 'decline' | 'notify'
;
catch_result
: 'accept' | '3ds' | 'highRisk' | 'notify'
;
string_list
: STRING (DELIMETER STRING | WS)*
;
time_window
: DELIMETER INTEGER | DELIMETER INTEGER DELIMETER INTEGER
;
group_by
: DELIMETER string_list
;
STRING
: '"' (~["\r\n] | '""')* '"'
;
DELIMETER : ',' ;
COMMENT
: '#' ~[\r\n]* -> skip
;
RETURN : '->' ;
CATCH_ERROR: 'catch:' ;
RULE_BLOCK : 'rule:' ;
AND : 'AND' | 'and';
OR : 'OR' | 'or' ;
NOT : 'NOT' | 'not';
TRUE : 'TRUE' | 'true';
FALSE : 'FALSE' | 'false';
GT : '>' ;
GE : '>=' ;
LT : '<' ;
LE : '<=' ;
EQ : '=' ;
NEQ : '!=' ;
LPAREN : '(' ;
RPAREN : ')' ;
DECIMAL : '-'? ('0'..'9')+ '.' ('0'..'9')+;
INTEGER : '-'? ('0'..'9')+;
IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]* ;
WS : [ \u000C\n]+ -> skip;
SCOL : ';';
BOOLEAN : TRUE | FALSE;

View File

@ -8,12 +8,4 @@ public interface CountAggregator<T, U> {
Integer count(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
Integer countSuccess(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
Integer countError(U checkedField, T model, TimeWindow timeWindow, String errorCode, List<U> fields);
Integer countChargeback(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
Integer countRefund(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
}

View File

@ -8,12 +8,4 @@ public interface SumAggregator<T, U> {
Double sum(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
Double sumSuccess(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
Double sumError(U checkedField, T model, TimeWindow timeWindow, String errorCode, List<U> fields);
Double sumChargeback(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
Double sumRefund(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
}

View File

@ -1,36 +0,0 @@
package com.rbkmoney.fraudo.constant;
import java.util.HashMap;
import java.util.Map;
public enum P2PCheckedField {
EMAIL("email"),
IP("ip"),
FINGERPRINT("fingerprint"),
COUNTRY_BANK("country_bank"),
BIN("bin"),
PAN("pan"),
CURRENCY("currency"),
IDENTITY_ID("identity_id"),
CARD_TOKEN_FROM("card_token_from"),
CARD_TOKEN_TO("card_token_to");
private String value;
private static Map<String, P2PCheckedField> valueMap = new HashMap<>();
static {
for (P2PCheckedField value : P2PCheckedField.values()) {
valueMap.put(value.value, value);
}
}
P2PCheckedField(String value) {
this.value = value;
}
public static P2PCheckedField getByValue(String value) {
return valueMap.get(value);
}
}

View File

@ -1,39 +0,0 @@
package com.rbkmoney.fraudo.factory;
import com.rbkmoney.fraudo.aggregator.CountAggregator;
import com.rbkmoney.fraudo.aggregator.SumAggregator;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.finder.InListFinder;
import com.rbkmoney.fraudo.model.BaseModel;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.resolver.GroupByModelResolver;
import com.rbkmoney.fraudo.visitor.CountVisitor;
import com.rbkmoney.fraudo.visitor.CustomFuncVisitor;
import com.rbkmoney.fraudo.visitor.ListVisitor;
import com.rbkmoney.fraudo.visitor.SumVisitor;
import com.rbkmoney.fraudo.visitor.impl.*;
public class FirstFraudVisitorFactory implements FraudVisitorFactory {
@Override
public <T extends BaseModel, U> FirstFindVisitorImpl<T, U> createVisitor(
CountAggregator<T, U> countAggregator,
SumAggregator<T, U> sumAggregator,
UniqueValueAggregator<T, U> uniqueValueAggregator,
CountryResolver<U> countryResolver,
InListFinder<T, U> listFinder,
FieldResolver<T, U> fieldResolver,
GroupByModelResolver<T, U> groupByModelResolver) {
CountVisitor<T> countVisitor = new CountVisitorImpl<>(countAggregator, fieldResolver, groupByModelResolver);
SumVisitor<T> sumVisitor = new SumVisitorImpl<>(sumAggregator, fieldResolver, groupByModelResolver);
ListVisitor<T> listVisitor = new ListVisitorImpl<>(listFinder, fieldResolver);
CustomFuncVisitor<T> customFuncVisitor = new CustomFuncVisitorImpl<>(
uniqueValueAggregator,
countryResolver,
fieldResolver,
groupByModelResolver);
return new FirstFindVisitorImpl<>(countVisitor, sumVisitor, listVisitor, customFuncVisitor, fieldResolver);
}
}

View File

@ -1,23 +0,0 @@
package com.rbkmoney.fraudo.factory;
import com.rbkmoney.fraudo.aggregator.CountAggregator;
import com.rbkmoney.fraudo.aggregator.SumAggregator;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.finder.InListFinder;
import com.rbkmoney.fraudo.model.BaseModel;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.resolver.GroupByModelResolver;
import com.rbkmoney.fraudo.visitor.impl.FirstFindVisitorImpl;
public interface FraudVisitorFactory {
<T extends BaseModel, U> FirstFindVisitorImpl createVisitor(CountAggregator<T, U> countAggregator,
SumAggregator<T, U> sumAggregator,
UniqueValueAggregator<T, U> uniqueValueAggregator,
CountryResolver<U> countryResolver,
InListFinder<T, U> listFinder,
FieldResolver<T, U> fieldPairResolver,
GroupByModelResolver<T, U> groupByModelResolver);
}

View File

@ -0,0 +1,25 @@
package com.rbkmoney.fraudo.p2p.factory;
import com.rbkmoney.fraudo.aggregator.CountAggregator;
import com.rbkmoney.fraudo.aggregator.SumAggregator;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.finder.InListFinder;
import com.rbkmoney.fraudo.model.BaseModel;
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
import com.rbkmoney.fraudo.p2p.resolver.P2PTimeWindowResolver;
import com.rbkmoney.fraudo.p2p.visitor.impl.FirstFindP2PVisitorImpl;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
public interface FraudP2PVisitorFactory {
<T extends BaseModel, U> FirstFindP2PVisitorImpl<T, U> createVisitor(CountAggregator<T, U> countAggregator,
SumAggregator<T, U> sumAggregator,
UniqueValueAggregator<T, U> uniqueValueAggregator,
CountryResolver<U> countryResolver,
InListFinder<T, U> listFinder,
FieldResolver<T, U> fieldPairResolver,
P2PGroupResolver<T, U> paymentGroupResolver,
P2PTimeWindowResolver timeWindowResolver);
}

View File

@ -0,0 +1,38 @@
package com.rbkmoney.fraudo.p2p.factory;
import com.rbkmoney.fraudo.aggregator.CountAggregator;
import com.rbkmoney.fraudo.aggregator.SumAggregator;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.finder.InListFinder;
import com.rbkmoney.fraudo.model.BaseModel;
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
import com.rbkmoney.fraudo.p2p.resolver.P2PTimeWindowResolver;
import com.rbkmoney.fraudo.p2p.visitor.CountP2PVisitor;
import com.rbkmoney.fraudo.p2p.visitor.CustomP2PFuncVisitor;
import com.rbkmoney.fraudo.p2p.visitor.ListP2PVisitor;
import com.rbkmoney.fraudo.p2p.visitor.SumP2PVisitor;
import com.rbkmoney.fraudo.p2p.visitor.impl.*;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
public class P2PFraudVisitorFactory implements FraudP2PVisitorFactory {
@Override
public <T extends BaseModel, U> FirstFindP2PVisitorImpl<T, U> createVisitor(
CountAggregator<T, U> countAggregator,
SumAggregator<T, U> sumAggregator,
UniqueValueAggregator<T, U> uniqueValueAggregator,
CountryResolver<U> countryResolver,
InListFinder<T, U> listFinder,
FieldResolver<T, U> fieldResolver,
P2PGroupResolver<T, U> groupResolver,
P2PTimeWindowResolver timeWindowResolver) {
CountP2PVisitor<T> countVisitor = new CountP2PVisitorImpl<>(countAggregator, fieldResolver, groupResolver, timeWindowResolver);
SumP2PVisitor<T> sumVisitor = new SumP2PVisitorImpl<>(sumAggregator, fieldResolver, groupResolver, timeWindowResolver);
ListP2PVisitor<T> listVisitor = new ListP2PVisitorImpl<>(listFinder, fieldResolver);
CustomP2PFuncVisitor<T> customFuncVisitor = new CustomP2PFuncVisitorImpl<>(uniqueValueAggregator, countryResolver,
fieldResolver, groupResolver, timeWindowResolver);
return new FirstFindP2PVisitorImpl<>(countVisitor, sumVisitor, listVisitor, customFuncVisitor, fieldResolver);
}
}

View File

@ -0,0 +1,48 @@
package com.rbkmoney.fraudo.p2p.generator;
import com.rbkmoney.fraudo.FraudoP2PParser;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.function.Function;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CommonP2PKeyGenerator {
static <T> String generateKeyGroupedFunction(TerminalNode string,
ParseTree parseTree,
FraudoP2PParser.Time_windowContext timeWindowContext,
FraudoP2PParser.Group_byContext groupByContext,
Function<String, T> resolve) {
String countTarget = TextUtil.safeGetText(string);
return new StringBuilder()
.append(parseTree)
.append(countTarget)
.append(resolve.apply(countTarget))
.append(timeWindowContext != null ? timeWindowContext.children : "")
.append(groupByContext != null ? groupByContext.string_list().children : "")
.toString();
}
static <T> String generateKeyGroupedTwoFieldFunction(TerminalNode firstField,
TerminalNode secondField,
ParseTree parseTree,
FraudoP2PParser.Time_windowContext timeWindowContext,
FraudoP2PParser.Group_byContext groupByContext,
Function<String, T> resolve) {
String target = TextUtil.safeGetText(firstField);
String errorCode = TextUtil.safeGetText(secondField);
return new StringBuilder()
.append(parseTree)
.append(target)
.append(errorCode)
.append(resolve.apply(target))
.append(timeWindowContext != null ? timeWindowContext.children : "")
.append(groupByContext != null ? groupByContext.string_list().children : "")
.toString();
}
}

View File

@ -0,0 +1,20 @@
package com.rbkmoney.fraudo.p2p.generator;
import com.rbkmoney.fraudo.FraudoP2PParser;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.function.Function;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CountP2PKeyGenerator {
public static <T> String generate(FraudoP2PParser.CountContext ctx, Function<String, T> resolve) {
return CommonP2PKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
ctx.children.get(0),
ctx.time_window(),
ctx.group_by(),
resolve);
}
}

View File

@ -0,0 +1,19 @@
package com.rbkmoney.fraudo.p2p.generator;
import com.rbkmoney.fraudo.FraudoP2PParser;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CountryP2PKeyGenerator {
public static String generate(FraudoP2PParser.Country_byContext ctx) {
String fieldName = TextUtil.safeGetText(ctx.STRING());
return new StringBuilder()
.append(ctx.children.get(0))
.append(fieldName)
.toString();
}
}

View File

@ -0,0 +1,17 @@
package com.rbkmoney.fraudo.p2p.generator;
import com.rbkmoney.fraudo.FraudoP2PParser;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RuleP2PKeyGenerator {
public static String generateRuleKey(FraudoP2PParser.Fraud_ruleContext fraudRuleContext, int index) {
if (fraudRuleContext.IDENTIFIER() != null && !fraudRuleContext.IDENTIFIER().getText().isEmpty()) {
return fraudRuleContext.IDENTIFIER().getText();
}
return String.valueOf(index);
}
}

View File

@ -0,0 +1,20 @@
package com.rbkmoney.fraudo.p2p.generator;
import com.rbkmoney.fraudo.FraudoP2PParser;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.function.Function;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class SumP2PKeyGenerator {
public static <T> String generate(FraudoP2PParser.SumContext ctx, Function<String, T> resolve) {
return CommonP2PKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
ctx.children.get(0),
ctx.time_window(),
ctx.group_by(),
resolve);
}
}

View File

@ -0,0 +1,22 @@
package com.rbkmoney.fraudo.p2p.generator;
import com.rbkmoney.fraudo.FraudoP2PParser;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.function.Function;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class UniqueP2PKeyGenerator {
public static <T> String generate(FraudoP2PParser.UniqueContext ctx, Function<String, T> resolve) {
return CommonP2PKeyGenerator.generateKeyGroupedTwoFieldFunction(
ctx.STRING(0),
ctx.STRING(1),
ctx.children.get(0),
ctx.time_window(),
ctx.group_by(),
resolve);
}
}

View File

@ -1,6 +1,7 @@
package com.rbkmoney.fraudo.resolver;
package com.rbkmoney.fraudo.p2p.resolver;
import com.rbkmoney.fraudo.FraudoParser;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.resolver.GroupFieldsResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.RequiredArgsConstructor;
@ -8,12 +9,14 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static com.rbkmoney.fraudo.FraudoP2PParser.Group_byContext;
@RequiredArgsConstructor
public class GroupByModelResolver<T, U> implements GroupFieldsResolver<U> {
public class P2PGroupResolver<T, U> implements GroupFieldsResolver<Group_byContext, U> {
private final FieldResolver<T, U> fieldResolver;
public List<U> resolve(FraudoParser.Group_byContext groupByContext) {
public List<U> resolve(Group_byContext groupByContext) {
List<U> fields = new ArrayList<>();
if (groupByContext != null
&& groupByContext.string_list() != null

View File

@ -0,0 +1,28 @@
package com.rbkmoney.fraudo.p2p.resolver;
import com.rbkmoney.fraudo.model.TimeWindow;
import com.rbkmoney.fraudo.resolver.TimeWindowResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.List;
import static com.rbkmoney.fraudo.FraudoP2PParser.Time_windowContext;
public class P2PTimeWindowResolver implements TimeWindowResolver<Time_windowContext> {
@Override
public TimeWindow resolve(Time_windowContext ctx) {
TimeWindow.TimeWindowBuilder builder = TimeWindow.builder();
List<TerminalNode> times = ctx.INTEGER();
String startWindow = TextUtil.safeGetText(times.get(0));
if (times.size() == 2) {
String endWindow = TextUtil.safeGetText(times.get(1));
builder.endWindowTime(Long.valueOf(endWindow));
}
return builder
.startWindowTime(Long.valueOf(startWindow))
.build();
}
}

View File

@ -0,0 +1,9 @@
package com.rbkmoney.fraudo.p2p.visitor;
import com.rbkmoney.fraudo.FraudoP2PParser;
public interface CountP2PVisitor<T> {
Integer visitCount(FraudoP2PParser.CountContext ctx, T model);
}

View File

@ -0,0 +1,13 @@
package com.rbkmoney.fraudo.p2p.visitor;
import com.rbkmoney.fraudo.FraudoP2PParser;
public interface CustomP2PFuncVisitor<T> {
String visitCountryBy(FraudoP2PParser.Country_byContext ctx, T model);
boolean visitLike(FraudoP2PParser.LikeContext ctx, T model);
Integer visitUnique(FraudoP2PParser.UniqueContext ctx, T model);
}

View File

@ -0,0 +1,15 @@
package com.rbkmoney.fraudo.p2p.visitor;
import com.rbkmoney.fraudo.FraudoP2PParser;
public interface ListP2PVisitor<T> {
Boolean visitInWhiteList(FraudoP2PParser.In_white_listContext ctx, T model);
Boolean visitInBlackList(FraudoP2PParser.In_black_listContext ctx, T model);
Boolean visitInGreyList(FraudoP2PParser.In_grey_listContext ctx, T model);
Boolean visitInList(FraudoP2PParser.In_listContext ctx, T model);
}

View File

@ -0,0 +1,9 @@
package com.rbkmoney.fraudo.p2p.visitor;
import com.rbkmoney.fraudo.FraudoP2PParser;
public interface SumP2PVisitor<T> {
Double visitSum(FraudoP2PParser.SumContext ctx, T model);
}

View File

@ -0,0 +1,32 @@
package com.rbkmoney.fraudo.p2p.visitor.impl;
import com.rbkmoney.fraudo.aggregator.CountAggregator;
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
import com.rbkmoney.fraudo.p2p.resolver.P2PTimeWindowResolver;
import com.rbkmoney.fraudo.p2p.visitor.CountP2PVisitor;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.RequiredArgsConstructor;
import static com.rbkmoney.fraudo.FraudoP2PParser.CountContext;
@RequiredArgsConstructor
public class CountP2PVisitorImpl<T, U> implements CountP2PVisitor<T> {
private final CountAggregator<T, U> countAggregator;
private final FieldResolver<T, U> fieldResolver;
private final P2PGroupResolver<T, U> groupResolver;
private final P2PTimeWindowResolver timeWindowResolver;
@Override
public Integer visitCount(CountContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return countAggregator.count(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by())
);
}
}

View File

@ -0,0 +1,52 @@
package com.rbkmoney.fraudo.p2p.visitor.impl;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.model.Pair;
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
import com.rbkmoney.fraudo.p2p.resolver.P2PTimeWindowResolver;
import com.rbkmoney.fraudo.p2p.visitor.CustomP2PFuncVisitor;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.RequiredArgsConstructor;
import static com.rbkmoney.fraudo.FraudoP2PParser.*;
@RequiredArgsConstructor
public class CustomP2PFuncVisitorImpl<T, U> implements CustomP2PFuncVisitor<T> {
private final UniqueValueAggregator<T, U> uniqueValueAggregator;
private final CountryResolver<U> countryResolver;
private final FieldResolver<T, U> fieldResolver;
private final P2PGroupResolver<T, U> groupResolver;
private final P2PTimeWindowResolver timeWindowResolver;
@Override
public String visitCountryBy(Country_byContext ctx, T model) {
String fieldName = TextUtil.safeGetText(ctx.STRING());
Pair<U, String> resolve = fieldResolver.resolve(fieldName, model);
return countryResolver.resolveCountry(resolve.getFirst(), resolve.getSecond());
}
@Override
public boolean visitLike(LikeContext ctx, T model) {
String fieldName = TextUtil.safeGetText(ctx.STRING(0));
String fieldValue = fieldResolver.resolve(fieldName, model).getSecond();
String pattern = TextUtil.safeGetText(ctx.STRING(1));
return fieldValue.matches(pattern);
}
@Override
public Integer visitUnique(UniqueContext ctx, T model) {
String field = TextUtil.safeGetText(ctx.STRING(0));
String fieldBy = TextUtil.safeGetText(ctx.STRING(1));
return uniqueValueAggregator.countUniqueValue(
fieldResolver.resolveName(field),
model,
fieldResolver.resolveName(fieldBy),
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by())
);
}
}

View File

@ -0,0 +1,291 @@
package com.rbkmoney.fraudo.p2p.visitor.impl;
import com.rbkmoney.fraudo.FraudoP2PBaseVisitor;
import com.rbkmoney.fraudo.FraudoP2PParser.*;
import com.rbkmoney.fraudo.FraudoPaymentParser;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.exception.NotImplementedOperatorException;
import com.rbkmoney.fraudo.exception.NotValidContextException;
import com.rbkmoney.fraudo.exception.UnknownResultException;
import com.rbkmoney.fraudo.model.BaseModel;
import com.rbkmoney.fraudo.model.ResultModel;
import com.rbkmoney.fraudo.p2p.generator.*;
import com.rbkmoney.fraudo.p2p.visitor.CountP2PVisitor;
import com.rbkmoney.fraudo.p2p.visitor.CustomP2PFuncVisitor;
import com.rbkmoney.fraudo.p2p.visitor.ListP2PVisitor;
import com.rbkmoney.fraudo.p2p.visitor.SumP2PVisitor;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import com.rbkmoney.fraudo.visitor.TemplateVisitor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@RequiredArgsConstructor
public class FirstFindP2PVisitorImpl<T extends BaseModel, U> extends FraudoP2PBaseVisitor<Object> implements TemplateVisitor<T, ResultModel> {
private ThreadLocal<Map<String, Object>> localFuncCache = ThreadLocal.withInitial(HashMap::new);
private ThreadLocal<T> threadLocalModel = new ThreadLocal<>();
private final CountP2PVisitor<T> countVisitor;
private final SumP2PVisitor<T> sumVisitor;
private final ListP2PVisitor<T> listVisitor;
private final CustomP2PFuncVisitor<T> customFuncVisitor;
private final FieldResolver<T, U> fieldResolver;
@Override
public void close() {
localFuncCache.remove();
threadLocalModel.remove();
}
@Override
public ResultStatus visitFraud_rule(Fraud_ruleContext ctx) {
try {
if (visitExpression(ctx.expression())) {
return ResultStatus.getByValue(ctx.result().getText());
}
} catch (Exception e) {
log.error("Error when FastFraudVisitorImpl visitFraud_rule e: ", e);
if (ctx.catch_result() != null && ctx.catch_result().getText() != null) {
return ResultStatus.getByValue(ctx.catch_result().getText());
}
return ResultStatus.NOTIFY;
}
return ResultStatus.NORMAL;
}
@Override
public ResultModel visitParse(ParseContext ctx) {
List<String> notifications = new ArrayList<>();
for (int i = 0; i < ctx.fraud_rule().size(); i++) {
Fraud_ruleContext fraudRuleContext = ctx.fraud_rule().get(i);
ResultStatus result = (ResultStatus) visit(fraudRuleContext);
String key = RuleP2PKeyGenerator.generateRuleKey(fraudRuleContext, i);
if (result == null) {
throw new UnknownResultException(fraudRuleContext.getText());
} else if (result == ResultStatus.NOTIFY) {
notifications.add(key);
} else if (result != ResultStatus.NORMAL) {
return new ResultModel(result, key, notifications);
}
}
return new ResultModel(ResultStatus.NORMAL, notifications);
}
@Override
public ResultModel visit(ParseTree tree, T model) {
try {
validateModel(model);
threadLocalModel.set(model);
return (ResultModel) visit(tree);
} finally {
localFuncCache.get().clear();
}
}
private void validateModel(T model) {
if (model == null) {
log.error("Model is not init!");
throw new NotValidContextException();
}
}
@Override
public Boolean visitExpression(ExpressionContext ctx) {
if (ctx.OR() != null && !ctx.OR().isEmpty()) {
boolean result = false;
for (BooleanAndExpressionContext booleanAndExpressionContext : ctx.booleanAndExpression()) {
result = result || (Boolean) visit(booleanAndExpressionContext);
if (result) {
return result;
}
}
return result;
}
return visitBooleanAndExpression(ctx.booleanAndExpression(0));
}
@Override
public Boolean visitBooleanAndExpression(BooleanAndExpressionContext ctx) {
if (ctx.AND() != null && !ctx.AND().isEmpty()) {
boolean result = true;
for (EqualityExpressionContext equalityExpressionContext : ctx.equalityExpression()) {
result = result && visitEqualityExpression(equalityExpressionContext);
if (!result) {
return result;
}
}
return result;
}
return visitEqualityExpression(ctx.equalityExpression(0));
}
@Override
public Boolean visitEqualityExpression(EqualityExpressionContext ctx) {
if (ctx.stringExpression() != null && !ctx.stringExpression().isEmpty()) {
String left = visitStringExpression(ctx.stringExpression(0));
String right = visitStringExpression(ctx.stringExpression(1));
if (ctx.EQ() != null) {
return left.equals(right);
} else if (ctx.NEQ() != null) {
return !left.equals(right);
}
} else if (ctx.NOT() != null) {
return !(Boolean) visit(ctx.expression());
} else if (ctx.LPAREN() != null) {
return (Boolean) visit(ctx.expression());
}
return visitRelationalExpression(ctx.relationalExpression());
}
@Override
public Boolean visitRelationalExpression(RelationalExpressionContext ctx) {
if (ctx.unaryExpression() != null && !ctx.unaryExpression().isEmpty()) {
Double left = visitUnaryExpression(ctx.unaryExpression(0));
Double right = visitUnaryExpression(ctx.unaryExpression(1));
if (ctx.EQ() != null) {
return left.equals(right);
} else if (ctx.NEQ() != null) {
return !left.equals(right);
} else if (ctx.GE() != null) {
return left >= right;
} else if (ctx.LT() != null) {
return left < right;
} else if (ctx.GT() != null) {
return left > right;
} else if (ctx.LE() != null) {
return left <= right;
}
}
return (Boolean) visitChildren(ctx);
}
@Override
public Double visitUnaryExpression(UnaryExpressionContext ctx) {
if (ctx.floatExpression() != null) {
return visitFloatExpression(ctx.floatExpression());
} else if (ctx.integerExpression() != null) {
return Double.valueOf(visitIntegerExpression(ctx.integerExpression()));
}
throw new NotImplementedOperatorException(ctx.getText());
}
@Override
public Double visitFloatExpression(FloatExpressionContext ctx) {
if (ctx.INTEGER() != null) {
return Double.valueOf(TextUtil.safeGetText(ctx.INTEGER()));
} else if (ctx.DECIMAL() != null) {
return Double.valueOf(TextUtil.safeGetText(ctx.DECIMAL()));
}
return (Double) visitChildren(ctx);
}
@Override
public Integer visitIntegerExpression(IntegerExpressionContext ctx) {
if (ctx.INTEGER() != null) {
return Integer.valueOf(TextUtil.safeGetText(ctx.INTEGER()));
}
return (Integer) visitChildren(ctx);
}
@Override
public String visitStringExpression(StringExpressionContext ctx) {
if (ctx.STRING() != null) {
return TextUtil.safeGetText(ctx.STRING());
}
return (String) visitChildren(ctx);
}
@Override
public Integer visitCount(CountContext ctx) {
String key = CountP2PKeyGenerator.generate(ctx, fieldResolver::resolveName);
return (Integer) localFuncCache.get().computeIfAbsent(
key,
s -> countVisitor.visitCount(ctx, threadLocalModel.get())
);
}
@Override
public Double visitAmount(AmountContext ctx) {
return Double.valueOf(threadLocalModel.get().getAmount());
}
@Override
public Double visitSum(SumContext ctx) {
String key = SumP2PKeyGenerator.generate(ctx, fieldResolver::resolveName);
return (Double) localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSum(ctx, threadLocalModel.get())
);
}
@Override
public String visitCurrency(CurrencyContext ctx) {
return threadLocalModel.get().getCurrency();
}
@Override
public Boolean visitIn_white_list(In_white_listContext ctx) {
return listVisitor.visitInWhiteList(ctx, threadLocalModel.get());
}
@Override
public Boolean visitIn_black_list(In_black_listContext ctx) {
return listVisitor.visitInBlackList(ctx, threadLocalModel.get());
}
@Override
public Boolean visitIn_grey_list(In_grey_listContext ctx) {
return listVisitor.visitInGreyList(ctx, threadLocalModel.get());
}
@Override
public Boolean visitIn_list(In_listContext ctx) {
return listVisitor.visitInList(ctx, threadLocalModel.get());
}
@Override
public Boolean visitIn(InContext ctx) {
String fieldValue;
if (ctx.stringExpression().STRING() != null && ctx.stringExpression().getText() != null
&& !ctx.stringExpression().STRING().getText().isEmpty()) {
String field = TextUtil.safeGetText(ctx.stringExpression().STRING());
fieldValue = fieldResolver.resolve(field, threadLocalModel.get()).getSecond();
} else {
fieldValue = (String) visitChildren(ctx.stringExpression());
}
return ctx.string_list().STRING().stream()
.anyMatch(s -> fieldValue.equals(TextUtil.safeGetText(s)));
}
@Override
public Integer visitUnique(UniqueContext ctx) {
String key = UniqueP2PKeyGenerator.generate(ctx, fieldResolver::resolveName);
return (Integer) localFuncCache.get().computeIfAbsent(
key,
s -> customFuncVisitor.visitUnique(ctx, threadLocalModel.get())
);
}
@Override
public Boolean visitLike(LikeContext ctx) {
return customFuncVisitor.visitLike(ctx, threadLocalModel.get());
}
@Override
public String visitCountry_by(Country_byContext ctx) {
String key = CountryP2PKeyGenerator.generate(ctx);
return (String) localFuncCache.get().computeIfAbsent(
key,
s -> customFuncVisitor.visitCountryBy(ctx, threadLocalModel.get())
);
}
}

View File

@ -0,0 +1,58 @@
package com.rbkmoney.fraudo.p2p.visitor.impl;
import com.rbkmoney.fraudo.finder.InListFinder;
import com.rbkmoney.fraudo.model.Pair;
import com.rbkmoney.fraudo.p2p.visitor.ListP2PVisitor;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.RequiredArgsConstructor;
import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
import static com.rbkmoney.fraudo.FraudoP2PParser.*;
@RequiredArgsConstructor
public class ListP2PVisitorImpl<T, U> implements ListP2PVisitor<T> {
private final InListFinder<T, U> listFinder;
private final FieldResolver<T, U> fieldResolver;
@Override
public Boolean visitInWhiteList(In_white_listContext ctx, T model) {
return findInList(ctx.string_list().STRING(), model, listFinder::findInWhiteList);
}
@Override
public Boolean visitInBlackList(In_black_listContext ctx, T model) {
return findInList(ctx.string_list().STRING(), model, listFinder::findInBlackList);
}
@Override
public Boolean visitInGreyList(In_grey_listContext ctx, T model) {
return findInList(ctx.string_list().STRING(), model, listFinder::findInGreyList);
}
@Override
public Boolean visitInList(In_listContext ctx, T model) {
List<Pair<U, String>> checkedFields = initCheckedFields(model, ctx.string_list().STRING());
String name = TextUtil.safeGetText(ctx.STRING());
return listFinder.findInList(name, checkedFields, model);
}
private List<Pair<U, String>> initCheckedFields(T model, List<TerminalNode> string) {
List<String> fields = string.stream()
.map(TextUtil::safeGetText)
.collect(Collectors.toList());
return fields.stream()
.map(s -> fieldResolver.resolve(s, model))
.collect(Collectors.toList());
}
private Boolean findInList(List<TerminalNode> nodes, T model, BiPredicate<List<Pair<U, String>>, T> biPredicate) {
List<Pair<U, String>> checkedFields = initCheckedFields(model, nodes);
return biPredicate.test(checkedFields, model);
}
}

View File

@ -0,0 +1,33 @@
package com.rbkmoney.fraudo.p2p.visitor.impl;
import com.rbkmoney.fraudo.aggregator.SumAggregator;
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
import com.rbkmoney.fraudo.p2p.visitor.SumP2PVisitor;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.resolver.TimeWindowResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.RequiredArgsConstructor;
import static com.rbkmoney.fraudo.FraudoP2PParser.SumContext;
import static com.rbkmoney.fraudo.FraudoP2PParser.Time_windowContext;
@RequiredArgsConstructor
public class SumP2PVisitorImpl<T, U> implements SumP2PVisitor<T> {
private final SumAggregator<T, U> sumAggregator;
private final FieldResolver<T, U> fieldResolver;
private final P2PGroupResolver<T, U> paymentGroupResolver;
private final TimeWindowResolver<Time_windowContext> timeWindowResolver;
@Override
public Double visitSum(SumContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return sumAggregator.sum(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
paymentGroupResolver.resolve(ctx.group_by())
);
}
}

View File

@ -0,0 +1,18 @@
package com.rbkmoney.fraudo.payment.aggregator;
import com.rbkmoney.fraudo.aggregator.CountAggregator;
import com.rbkmoney.fraudo.model.TimeWindow;
import java.util.List;
public interface CountPaymentAggregator<T, U> extends CountAggregator<T, U> {
Integer countSuccess(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
Integer countError(U checkedField, T model, TimeWindow timeWindow, String errorCode, List<U> fields);
Integer countChargeback(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
Integer countRefund(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
}

View File

@ -0,0 +1,18 @@
package com.rbkmoney.fraudo.payment.aggregator;
import com.rbkmoney.fraudo.aggregator.SumAggregator;
import com.rbkmoney.fraudo.model.TimeWindow;
import java.util.List;
public interface SumPaymentAggregator<T, U> extends SumAggregator<T, U> {
Double sumSuccess(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
Double sumError(U checkedField, T model, TimeWindow timeWindow, String errorCode, List<U> fields);
Double sumChargeback(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
Double sumRefund(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
}

View File

@ -0,0 +1,25 @@
package com.rbkmoney.fraudo.payment.factory;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.finder.InListFinder;
import com.rbkmoney.fraudo.model.BaseModel;
import com.rbkmoney.fraudo.payment.aggregator.CountPaymentAggregator;
import com.rbkmoney.fraudo.payment.aggregator.SumPaymentAggregator;
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
import com.rbkmoney.fraudo.payment.visitor.impl.FirstFindVisitorImpl;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
public interface FraudVisitorFactory {
<T extends BaseModel, U> FirstFindVisitorImpl<T, U> createVisitor(CountPaymentAggregator<T, U> countPaymentAggregator,
SumPaymentAggregator<T, U> sumPaymentAggregator,
UniqueValueAggregator<T, U> uniqueValueAggregator,
CountryResolver<U> countryResolver,
InListFinder<T, U> listFinder,
FieldResolver<T, U> fieldPairResolver,
PaymentGroupResolver<T, U> paymentGroupResolver,
PaymentTimeWindowResolver timeWindowResolver);
}

View File

@ -0,0 +1,38 @@
package com.rbkmoney.fraudo.payment.factory;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.finder.InListFinder;
import com.rbkmoney.fraudo.model.BaseModel;
import com.rbkmoney.fraudo.payment.aggregator.CountPaymentAggregator;
import com.rbkmoney.fraudo.payment.aggregator.SumPaymentAggregator;
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
import com.rbkmoney.fraudo.payment.visitor.CountVisitor;
import com.rbkmoney.fraudo.payment.visitor.CustomFuncVisitor;
import com.rbkmoney.fraudo.payment.visitor.ListVisitor;
import com.rbkmoney.fraudo.payment.visitor.SumVisitor;
import com.rbkmoney.fraudo.payment.visitor.impl.*;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
public class FraudVisitorFactoryImpl implements FraudVisitorFactory {
@Override
public <T extends BaseModel, U> FirstFindVisitorImpl<T, U> createVisitor(
CountPaymentAggregator<T, U> countPaymentAggregator,
SumPaymentAggregator<T, U> sumPaymentAggregator,
UniqueValueAggregator<T, U> uniqueValueAggregator,
CountryResolver<U> countryResolver,
InListFinder<T, U> listFinder,
FieldResolver<T, U> fieldResolver,
PaymentGroupResolver<T, U> paymentGroupResolver,
PaymentTimeWindowResolver timeWindowResolver) {
CountVisitor<T> countVisitor = new CountVisitorImpl<>(countPaymentAggregator, fieldResolver, paymentGroupResolver, timeWindowResolver);
SumVisitor<T> sumVisitor = new SumVisitorImpl<>(sumPaymentAggregator, fieldResolver, paymentGroupResolver, timeWindowResolver);
ListVisitor<T> listVisitor = new ListVisitorImpl<>(listFinder, fieldResolver);
CustomFuncVisitor<T> customFuncVisitor = new CustomFuncVisitorImpl<>(
uniqueValueAggregator, countryResolver, fieldResolver, paymentGroupResolver, timeWindowResolver);
return new FirstFindVisitorImpl<>(countVisitor, sumVisitor, listVisitor, customFuncVisitor, fieldResolver);
}
}

View File

@ -1,17 +1,17 @@
package com.rbkmoney.fraudo.utils.key.generator;
package com.rbkmoney.fraudo.payment.generator;
import com.rbkmoney.fraudo.FraudoParser;
import com.rbkmoney.fraudo.FraudoPaymentParser;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RuleKeyGenerator {
public static String generateRuleKey(FraudoParser.Fraud_ruleContext fraudRuleContext) {
public static String generateRuleKey(FraudoPaymentParser.Fraud_ruleContext fraudRuleContext, int index) {
if (fraudRuleContext.IDENTIFIER() != null && !fraudRuleContext.IDENTIFIER().getText().isEmpty()) {
return fraudRuleContext.IDENTIFIER().getText();
}
return String.valueOf(fraudRuleContext.getRuleIndex());
return String.valueOf(index);
}
}

View File

@ -0,0 +1,32 @@
package com.rbkmoney.fraudo.payment.resolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.resolver.GroupFieldsResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.RequiredArgsConstructor;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static com.rbkmoney.fraudo.FraudoPaymentParser.Group_byContext;
@RequiredArgsConstructor
public class PaymentGroupResolver<T, U> implements GroupFieldsResolver<Group_byContext, U> {
private final FieldResolver<T, U> fieldResolver;
public List<U> resolve(Group_byContext groupByContext) {
List<U> fields = new ArrayList<>();
if (groupByContext != null
&& groupByContext.string_list() != null
&& groupByContext.string_list().STRING() != null
&& !groupByContext.string_list().STRING().isEmpty()) {
fields = groupByContext.string_list().STRING().stream()
.map(terminalNode -> fieldResolver.resolveName(TextUtil.safeGetText(terminalNode)))
.collect(Collectors.toList());
}
return fields;
}
}

View File

@ -0,0 +1,27 @@
package com.rbkmoney.fraudo.payment.resolver;
import com.rbkmoney.fraudo.FraudoPaymentParser;
import com.rbkmoney.fraudo.model.TimeWindow;
import com.rbkmoney.fraudo.resolver.TimeWindowResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.List;
public class PaymentTimeWindowResolver implements TimeWindowResolver<FraudoPaymentParser.Time_windowContext> {
@Override
public TimeWindow resolve(FraudoPaymentParser.Time_windowContext ctx) {
TimeWindow.TimeWindowBuilder builder = TimeWindow.builder();
List<TerminalNode> times = ctx.INTEGER();
String startWindow = TextUtil.safeGetText(times.get(0));
if (times.size() == 2) {
String endWindow = TextUtil.safeGetText(times.get(1));
builder.endWindowTime(Long.valueOf(endWindow));
}
return builder
.startWindowTime(Long.valueOf(startWindow))
.build();
}
}

View File

@ -0,0 +1,17 @@
package com.rbkmoney.fraudo.payment.visitor;
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
public interface CountVisitor<T> {
Integer visitCount(CountContext ctx, T model);
Integer visitCountSuccess(Count_successContext ctx, T model);
Integer visitCountError(Count_errorContext ctx, T model);
Integer visitCountChargeback(Count_chargebackContext ctx, T model);
Integer visitCountRefund(Count_refundContext ctx, T model);
}

View File

@ -0,0 +1,13 @@
package com.rbkmoney.fraudo.payment.visitor;
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
public interface CustomFuncVisitor<T> {
String visitCountryBy(Country_byContext ctx, T model);
boolean visitLike(LikeContext ctx, T model);
Integer visitUnique(UniqueContext ctx, T model);
}

View File

@ -0,0 +1,15 @@
package com.rbkmoney.fraudo.payment.visitor;
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
public interface ListVisitor<T> {
Boolean visitInWhiteList(In_white_listContext ctx, T model);
Boolean visitInBlackList(In_black_listContext ctx, T model);
Boolean visitInGreyList(In_grey_listContext ctx, T model);
Boolean visitInList(In_listContext ctx, T model);
}

View File

@ -0,0 +1,17 @@
package com.rbkmoney.fraudo.payment.visitor;
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
public interface SumVisitor<T> {
Double visitSum(SumContext ctx, T model);
Double visitSumSuccess(Sum_successContext ctx, T model);
Double visitSumError(Sum_errorContext ctx, T model);
Double visitSumChargeback(Sum_chargebackContext ctx, T model);
Double visitSumRefund(Sum_refundContext ctx, T model);
}

View File

@ -0,0 +1,78 @@
package com.rbkmoney.fraudo.payment.visitor.impl;
import com.rbkmoney.fraudo.FraudoPaymentParser;
import com.rbkmoney.fraudo.FraudoPaymentParser;
import com.rbkmoney.fraudo.payment.aggregator.CountPaymentAggregator;
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
import com.rbkmoney.fraudo.payment.visitor.CountVisitor;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class CountVisitorImpl<T, U> implements CountVisitor<T> {
private final CountPaymentAggregator<T, U> countPaymentAggregator;
private final FieldResolver<T, U> fieldResolver;
private final PaymentGroupResolver<T, U> groupResolver;
private final PaymentTimeWindowResolver timeWindowResolver;
@Override
public Integer visitCount(FraudoPaymentParser.CountContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return countPaymentAggregator.count(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by())
);
}
@Override
public Integer visitCountSuccess(FraudoPaymentParser.Count_successContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return countPaymentAggregator.countSuccess(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by())
);
}
@Override
public Integer visitCountError(FraudoPaymentParser.Count_errorContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING(0));
String errorCode = TextUtil.safeGetText(ctx.STRING(1));
return countPaymentAggregator.countError(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
errorCode,
groupResolver.resolve(ctx.group_by())
);
}
@Override
public Integer visitCountChargeback(FraudoPaymentParser.Count_chargebackContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return countPaymentAggregator.countChargeback(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by())
);
}
@Override
public Integer visitCountRefund(FraudoPaymentParser.Count_refundContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return countPaymentAggregator.countRefund(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by())
);
}
}

View File

@ -0,0 +1,52 @@
package com.rbkmoney.fraudo.payment.visitor.impl;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.model.Pair;
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
import com.rbkmoney.fraudo.payment.visitor.CustomFuncVisitor;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.RequiredArgsConstructor;
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
@RequiredArgsConstructor
public class CustomFuncVisitorImpl<T, U> implements CustomFuncVisitor<T> {
private final UniqueValueAggregator<T, U> uniqueValueAggregator;
private final CountryResolver<U> countryResolver;
private final FieldResolver<T, U> fieldResolver;
private final PaymentGroupResolver<T, U> groupResolver;
private final PaymentTimeWindowResolver timeWindowResolver;
@Override
public String visitCountryBy(Country_byContext ctx, T model) {
String fieldName = TextUtil.safeGetText(ctx.STRING());
Pair<U, String> resolve = fieldResolver.resolve(fieldName, model);
return countryResolver.resolveCountry(resolve.getFirst(), resolve.getSecond());
}
@Override
public boolean visitLike(LikeContext ctx, T model) {
String fieldName = TextUtil.safeGetText(ctx.STRING(0));
String fieldValue = fieldResolver.resolve(fieldName, model).getSecond();
String pattern = TextUtil.safeGetText(ctx.STRING(1));
return fieldValue.matches(pattern);
}
@Override
public Integer visitUnique(UniqueContext ctx, T model) {
String field = TextUtil.safeGetText(ctx.STRING(0));
String fieldBy = TextUtil.safeGetText(ctx.STRING(1));
return uniqueValueAggregator.countUniqueValue(
fieldResolver.resolveName(field),
model,
fieldResolver.resolveName(fieldBy),
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by())
);
}
}

View File

@ -0,0 +1,368 @@
package com.rbkmoney.fraudo.payment.visitor.impl;
import com.rbkmoney.fraudo.FraudoPaymentBaseVisitor;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.exception.NotImplementedOperatorException;
import com.rbkmoney.fraudo.exception.NotValidContextException;
import com.rbkmoney.fraudo.exception.UnknownResultException;
import com.rbkmoney.fraudo.model.BaseModel;
import com.rbkmoney.fraudo.model.ResultModel;
import com.rbkmoney.fraudo.payment.generator.RuleKeyGenerator;
import com.rbkmoney.fraudo.payment.visitor.CountVisitor;
import com.rbkmoney.fraudo.payment.visitor.CustomFuncVisitor;
import com.rbkmoney.fraudo.payment.visitor.ListVisitor;
import com.rbkmoney.fraudo.payment.visitor.SumVisitor;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import com.rbkmoney.fraudo.utils.key.generator.CountKeyGenerator;
import com.rbkmoney.fraudo.utils.key.generator.CountryKeyGenerator;
import com.rbkmoney.fraudo.utils.key.generator.SumKeyGenerator;
import com.rbkmoney.fraudo.utils.key.generator.UniqueKeyGenerator;
import com.rbkmoney.fraudo.visitor.TemplateVisitor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
@Slf4j
@RequiredArgsConstructor
public class FirstFindVisitorImpl<T extends BaseModel, U> extends FraudoPaymentBaseVisitor<Object> implements TemplateVisitor<T, ResultModel> {
private ThreadLocal<Map<String, Object>> localFuncCache = ThreadLocal.withInitial(HashMap::new);
private ThreadLocal<T> threadLocalModel = new ThreadLocal<>();
private final CountVisitor<T> countVisitor;
private final SumVisitor<T> sumVisitor;
private final ListVisitor<T> listVisitor;
private final CustomFuncVisitor<T> customFuncVisitor;
private final FieldResolver<T, U> fieldResolver;
@Override
public void close() {
localFuncCache.remove();
threadLocalModel.remove();
}
@Override
public ResultStatus visitFraud_rule(Fraud_ruleContext ctx) {
try {
if (visitExpression(ctx.expression())) {
return ResultStatus.getByValue(ctx.result().getText());
}
} catch (Exception e) {
log.error("Error when FastFraudVisitorImpl visitFraud_rule e: ", e);
if (ctx.catch_result() != null && ctx.catch_result().getText() != null) {
return ResultStatus.getByValue(ctx.catch_result().getText());
}
return ResultStatus.NOTIFY;
}
return ResultStatus.NORMAL;
}
@Override
public ResultModel visitParse(ParseContext ctx) {
List<String> notifications = new ArrayList<>();
for (int i = 0; i < ctx.fraud_rule().size(); i++) {
Fraud_ruleContext fraudRuleContext = ctx.fraud_rule().get(i);
ResultStatus result = (ResultStatus) visit(fraudRuleContext);
String key = RuleKeyGenerator.generateRuleKey(fraudRuleContext, i);
if (result == null) {
throw new UnknownResultException(fraudRuleContext.getText());
} else if (result == ResultStatus.NOTIFY) {
notifications.add(key);
} else if (result != ResultStatus.NORMAL) {
return new ResultModel(result, key, notifications);
}
}
return new ResultModel(ResultStatus.NORMAL, notifications);
}
@Override
public ResultModel visit(ParseTree tree, T model) {
try {
validateModel(model);
threadLocalModel.set(model);
return (ResultModel) visit(tree);
} finally {
localFuncCache.get().clear();
}
}
private void validateModel(T model) {
if (model == null) {
log.error("Model is not init!");
throw new NotValidContextException();
}
}
@Override
public Boolean visitExpression(ExpressionContext ctx) {
if (ctx.OR() != null && !ctx.OR().isEmpty()) {
boolean result = false;
for (BooleanAndExpressionContext booleanAndExpressionContext : ctx.booleanAndExpression()) {
result = result || (Boolean) visit(booleanAndExpressionContext);
if (result) {
return result;
}
}
return result;
}
return visitBooleanAndExpression(ctx.booleanAndExpression(0));
}
@Override
public Boolean visitBooleanAndExpression(BooleanAndExpressionContext ctx) {
if (ctx.AND() != null && !ctx.AND().isEmpty()) {
boolean result = true;
for (EqualityExpressionContext equalityExpressionContext : ctx.equalityExpression()) {
result = result && visitEqualityExpression(equalityExpressionContext);
if (!result) {
return result;
}
}
return result;
}
return visitEqualityExpression(ctx.equalityExpression(0));
}
@Override
public Boolean visitEqualityExpression(EqualityExpressionContext ctx) {
if (ctx.stringExpression() != null && !ctx.stringExpression().isEmpty()) {
String left = visitStringExpression(ctx.stringExpression(0));
String right = visitStringExpression(ctx.stringExpression(1));
if (ctx.EQ() != null) {
return left.equals(right);
} else if (ctx.NEQ() != null) {
return !left.equals(right);
}
} else if (ctx.NOT() != null) {
return !(Boolean) visit(ctx.expression());
} else if (ctx.LPAREN() != null) {
return (Boolean) visit(ctx.expression());
}
return visitRelationalExpression(ctx.relationalExpression());
}
@Override
public Boolean visitRelationalExpression(RelationalExpressionContext ctx) {
if (ctx.unaryExpression() != null && !ctx.unaryExpression().isEmpty()) {
Double left = visitUnaryExpression(ctx.unaryExpression(0));
Double right = visitUnaryExpression(ctx.unaryExpression(1));
if (ctx.EQ() != null) {
return left.equals(right);
} else if (ctx.NEQ() != null) {
return !left.equals(right);
} else if (ctx.GE() != null) {
return left >= right;
} else if (ctx.LT() != null) {
return left < right;
} else if (ctx.GT() != null) {
return left > right;
} else if (ctx.LE() != null) {
return left <= right;
}
}
return (Boolean) visitChildren(ctx);
}
@Override
public Double visitUnaryExpression(UnaryExpressionContext ctx) {
if (ctx.floatExpression() != null) {
return visitFloatExpression(ctx.floatExpression());
} else if (ctx.integerExpression() != null) {
return Double.valueOf(visitIntegerExpression(ctx.integerExpression()));
}
throw new NotImplementedOperatorException(ctx.getText());
}
@Override
public Double visitFloatExpression(FloatExpressionContext ctx) {
if (ctx.INTEGER() != null) {
return Double.valueOf(TextUtil.safeGetText(ctx.INTEGER()));
} else if (ctx.DECIMAL() != null) {
return Double.valueOf(TextUtil.safeGetText(ctx.DECIMAL()));
}
return (Double) visitChildren(ctx);
}
@Override
public Integer visitIntegerExpression(IntegerExpressionContext ctx) {
if (ctx.INTEGER() != null) {
return Integer.valueOf(TextUtil.safeGetText(ctx.INTEGER()));
}
return (Integer) visitChildren(ctx);
}
@Override
public String visitStringExpression(StringExpressionContext ctx) {
if (ctx.STRING() != null) {
return TextUtil.safeGetText(ctx.STRING());
}
return (String) visitChildren(ctx);
}
@Override
public Double visitAmount(AmountContext ctx) {
return Double.valueOf(threadLocalModel.get().getAmount());
}
@Override
public String visitCurrency(CurrencyContext ctx) {
return threadLocalModel.get().getCurrency();
}
@Override
public Boolean visitIn_white_list(In_white_listContext ctx) {
return listVisitor.visitInWhiteList(ctx, threadLocalModel.get());
}
@Override
public Boolean visitIn_black_list(In_black_listContext ctx) {
return listVisitor.visitInBlackList(ctx, threadLocalModel.get());
}
@Override
public Boolean visitIn_grey_list(In_grey_listContext ctx) {
return listVisitor.visitInGreyList(ctx, threadLocalModel.get());
}
@Override
public Boolean visitIn_list(In_listContext ctx) {
return listVisitor.visitInList(ctx, threadLocalModel.get());
}
@Override
public Boolean visitIn(InContext ctx) {
String fieldValue;
if (ctx.stringExpression().STRING() != null && ctx.stringExpression().getText() != null
&& !ctx.stringExpression().STRING().getText().isEmpty()) {
String field = TextUtil.safeGetText(ctx.stringExpression().STRING());
fieldValue = fieldResolver.resolve(field, threadLocalModel.get()).getSecond();
} else {
fieldValue = (String) visitChildren(ctx.stringExpression());
}
return ctx.string_list().STRING().stream()
.anyMatch(s -> fieldValue.equals(TextUtil.safeGetText(s)));
}
@Override
public Integer visitUnique(UniqueContext ctx) {
String key = UniqueKeyGenerator.generate(ctx, fieldResolver::resolveName);
return (Integer) localFuncCache.get().computeIfAbsent(
key,
s -> customFuncVisitor.visitUnique(ctx, threadLocalModel.get())
);
}
@Override
public Boolean visitLike(LikeContext ctx) {
return customFuncVisitor.visitLike(ctx, threadLocalModel.get());
}
@Override
public String visitCountry_by(Country_byContext ctx) {
String key = CountryKeyGenerator.generate(ctx);
return (String) localFuncCache.get().computeIfAbsent(
key,
s -> customFuncVisitor.visitCountryBy(ctx, threadLocalModel.get())
);
}
@Override
public Integer visitCount(CountContext ctx) {
String key = CountKeyGenerator.generate(ctx, fieldResolver::resolveName);
return (Integer) localFuncCache.get().computeIfAbsent(
key,
s -> countVisitor.visitCount(ctx, threadLocalModel.get())
);
}
@Override
public Integer visitCount_success(Count_successContext ctx) {
String key = CountKeyGenerator.generateSuccessKey(ctx, fieldResolver::resolveName);
return (Integer) localFuncCache.get().computeIfAbsent(
key,
s -> countVisitor.visitCountSuccess(ctx, threadLocalModel.get())
);
}
@Override
public Integer visitCount_error(Count_errorContext ctx) {
String key = CountKeyGenerator.generateErrorKey(ctx, fieldResolver::resolveName);
return (Integer) localFuncCache.get().computeIfAbsent(
key,
s -> countVisitor.visitCountError(ctx, threadLocalModel.get())
);
}
@Override
public Integer visitCount_chargeback(Count_chargebackContext ctx) {
String key = CountKeyGenerator.generateChargebackKey(ctx, fieldResolver::resolveName);
return (Integer) localFuncCache.get().computeIfAbsent(
key,
s -> countVisitor.visitCountChargeback(ctx, threadLocalModel.get())
);
}
@Override
public Integer visitCount_refund(Count_refundContext ctx) {
String key = CountKeyGenerator.generateRefundKey(ctx, fieldResolver::resolveName);
return (Integer) localFuncCache.get().computeIfAbsent(
key,
s -> countVisitor.visitCountRefund(ctx, threadLocalModel.get())
);
}
@Override
public Double visitSum(SumContext ctx) {
String key = SumKeyGenerator.generate(ctx, fieldResolver::resolveName);
return (Double) localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSum(ctx, threadLocalModel.get())
);
}
@Override
public Double visitSum_success(Sum_successContext ctx) {
String key = SumKeyGenerator.generateSuccessKey(ctx, fieldResolver::resolveName);
return (Double) localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSumSuccess(ctx, threadLocalModel.get())
);
}
@Override
public Double visitSum_error(Sum_errorContext ctx) {
String key = SumKeyGenerator.generateErrorKey(ctx, fieldResolver::resolveName);
return (Double) localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSumError(ctx, threadLocalModel.get())
);
}
@Override
public Double visitSum_chargeback(Sum_chargebackContext ctx) {
String key = SumKeyGenerator.generateChargebackKey(ctx, fieldResolver::resolveName);
return (Double) localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSumChargeback(ctx, threadLocalModel.get())
);
}
@Override
public Double visitSum_refund(Sum_refundContext ctx) {
String key = SumKeyGenerator.generateRefundKey(ctx, fieldResolver::resolveName);
return (Double) localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSumRefund(ctx, threadLocalModel.get())
);
}
}

View File

@ -1,11 +1,10 @@
package com.rbkmoney.fraudo.visitor.impl;
package com.rbkmoney.fraudo.payment.visitor.impl;
import com.rbkmoney.fraudo.FraudoParser;
import com.rbkmoney.fraudo.finder.InListFinder;
import com.rbkmoney.fraudo.model.Pair;
import com.rbkmoney.fraudo.payment.visitor.ListVisitor;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import com.rbkmoney.fraudo.visitor.ListVisitor;
import lombok.RequiredArgsConstructor;
import org.antlr.v4.runtime.tree.TerminalNode;
@ -13,6 +12,8 @@ import java.util.List;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
@RequiredArgsConstructor
public class ListVisitorImpl<T, U> implements ListVisitor<T> {
@ -20,22 +21,22 @@ public class ListVisitorImpl<T, U> implements ListVisitor<T> {
private final FieldResolver<T, U> fieldResolver;
@Override
public Boolean visitInWhiteList(FraudoParser.In_white_listContext ctx, T model) {
public Boolean visitInWhiteList(In_white_listContext ctx, T model) {
return findInList(ctx.string_list().STRING(), model, listFinder::findInWhiteList);
}
@Override
public Boolean visitInBlackList(FraudoParser.In_black_listContext ctx, T model) {
public Boolean visitInBlackList(In_black_listContext ctx, T model) {
return findInList(ctx.string_list().STRING(), model, listFinder::findInBlackList);
}
@Override
public Boolean visitInGreyList(FraudoParser.In_grey_listContext ctx, T model) {
public Boolean visitInGreyList(In_grey_listContext ctx, T model) {
return findInList(ctx.string_list().STRING(), model, listFinder::findInGreyList);
}
@Override
public Boolean visitInList(FraudoParser.In_listContext ctx, T model) {
public Boolean visitInList(In_listContext ctx, T model) {
List<Pair<U, String>> checkedFields = initCheckedFields(model, ctx.string_list().STRING());
String name = TextUtil.safeGetText(ctx.STRING());
return listFinder.findInList(name, checkedFields, model);

View File

@ -0,0 +1,76 @@
package com.rbkmoney.fraudo.payment.visitor.impl;
import com.rbkmoney.fraudo.payment.aggregator.SumPaymentAggregator;
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
import com.rbkmoney.fraudo.payment.visitor.SumVisitor;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.RequiredArgsConstructor;
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
@RequiredArgsConstructor
public class SumVisitorImpl<T, U> implements SumVisitor<T> {
private final SumPaymentAggregator<T, U> sumPaymentAggregator;
private final FieldResolver<T, U> fieldResolver;
private final PaymentGroupResolver<T, U> groupResolver;
private final PaymentTimeWindowResolver timeWindowResolver;
@Override
public Double visitSum(SumContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return sumPaymentAggregator.sum(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by())
);
}
@Override
public Double visitSumSuccess(Sum_successContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return sumPaymentAggregator.sumSuccess(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by()));
}
@Override
public Double visitSumError(Sum_errorContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING(0));
String errorCode = TextUtil.safeGetText(ctx.STRING(1));
return sumPaymentAggregator.sumError(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
errorCode,
groupResolver.resolve(ctx.group_by()));
}
@Override
public Double visitSumChargeback(Sum_chargebackContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return sumPaymentAggregator.sumChargeback(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by())
);
}
@Override
public Double visitSumRefund(Sum_refundContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return sumPaymentAggregator.sumRefund(
fieldResolver.resolveName(countTarget),
model,
timeWindowResolver.resolve(ctx.time_window()),
groupResolver.resolve(ctx.group_by())
);
}
}

View File

@ -2,8 +2,6 @@ package com.rbkmoney.fraudo.resolver;
public interface CountryResolver<T> {
String UNKNOWN_VALUE = "unknown";
String resolveCountry(T checkedField, String value);
}

View File

@ -1,11 +1,9 @@
package com.rbkmoney.fraudo.resolver;
import com.rbkmoney.fraudo.FraudoParser;
import java.util.List;
public interface GroupFieldsResolver<T> {
public interface GroupFieldsResolver<T, R> {
List<T> resolve(FraudoParser.Group_byContext groupByContext);
List<R> resolve(T groupByContext);
}

View File

@ -1,28 +1,9 @@
package com.rbkmoney.fraudo.resolver;
import com.rbkmoney.fraudo.FraudoParser;
import com.rbkmoney.fraudo.model.TimeWindow;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.List;
public interface TimeWindowResolver<T> {
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TimeWindowResolver {
public static TimeWindow resolve(FraudoParser.Time_windowContext ctx) {
TimeWindow.TimeWindowBuilder builder = TimeWindow.builder();
List<TerminalNode> times = ctx.DECIMAL();
String startWindow = TextUtil.safeGetText(times.get(0));
if (times.size() == 2) {
String endWindow = TextUtil.safeGetText(times.get(1));
builder.endWindowTime(Long.valueOf(endWindow));
}
return builder
.startWindowTime(Long.valueOf(startWindow))
.build();
}
TimeWindow resolve(T ctx);
}

View File

@ -1,10 +1,13 @@
package com.rbkmoney.fraudo.utils;
import com.rbkmoney.fraudo.exception.FieldUnsetException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.Optional;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TextUtil {
public static String safeGetText(TerminalNode field) {

View File

@ -1,6 +1,5 @@
package com.rbkmoney.fraudo.utils.key.generator;
import com.rbkmoney.fraudo.FraudoParser;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@ -9,13 +8,16 @@ import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.function.Function;
import static com.rbkmoney.fraudo.FraudoPaymentParser.Group_byContext;
import static com.rbkmoney.fraudo.FraudoPaymentParser.Time_windowContext;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CommonKeyGenerator {
static <T> String generateKeyGroupedFunction(TerminalNode string,
ParseTree parseTree,
FraudoParser.Time_windowContext timeWindowContext,
FraudoParser.Group_byContext groupByContext,
Time_windowContext timeWindowContext,
Group_byContext groupByContext,
Function<String, T> resolve) {
String countTarget = TextUtil.safeGetText(string);
return new StringBuilder()
@ -30,8 +32,8 @@ public class CommonKeyGenerator {
static <T> String generateKeyGroupedTwoFieldFunction(TerminalNode firstField,
TerminalNode secondField,
ParseTree parseTree,
FraudoParser.Time_windowContext timeWindowContext,
FraudoParser.Group_byContext groupByContext,
Time_windowContext timeWindowContext,
Group_byContext groupByContext,
Function<String, T> resolve) {
String target = TextUtil.safeGetText(firstField);
String errorCode = TextUtil.safeGetText(secondField);

View File

@ -1,17 +1,16 @@
package com.rbkmoney.fraudo.utils.key.generator;
import com.rbkmoney.fraudo.FraudoParser;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.antlr.v4.runtime.ParserRuleContext;
import java.util.function.Function;
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CountKeyGenerator {
public static <T> String generate(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.CountContext ctx = (FraudoParser.CountContext) context;
public static <T> String generate(CountContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
ctx.children.get(0),
ctx.time_window(),
@ -19,8 +18,7 @@ public class CountKeyGenerator {
resolve);
}
public static <T> String generateSuccessKey(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.Count_successContext ctx = (FraudoParser.Count_successContext) context;
public static <T> String generateSuccessKey(Count_successContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
ctx.children.get(0),
ctx.time_window(),
@ -28,8 +26,7 @@ public class CountKeyGenerator {
resolve);
}
public static <T> String generateErrorKey(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.Count_errorContext ctx = (FraudoParser.Count_errorContext) context;
public static <T> String generateErrorKey(Count_errorContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedTwoFieldFunction(ctx.STRING(0),
ctx.STRING(1),
ctx.children.get(0),
@ -38,8 +35,7 @@ public class CountKeyGenerator {
resolve);
}
public static <T> String generateChargebackKey(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.Count_chargebackContext ctx = (FraudoParser.Count_chargebackContext) context;
public static <T> String generateChargebackKey(Count_chargebackContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
ctx.children.get(0),
ctx.time_window(),
@ -47,8 +43,7 @@ public class CountKeyGenerator {
resolve);
}
public static <T> String generateRefundKey(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.Count_refundContext ctx = (FraudoParser.Count_refundContext) context;
public static <T> String generateRefundKey(Count_refundContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
ctx.children.get(0),
ctx.time_window(),

View File

@ -1,16 +1,14 @@
package com.rbkmoney.fraudo.utils.key.generator;
import com.rbkmoney.fraudo.FraudoParser;
import com.rbkmoney.fraudo.FraudoPaymentParser;
import com.rbkmoney.fraudo.utils.TextUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.antlr.v4.runtime.ParserRuleContext;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CountryKeyGenerator {
public static String generate(ParserRuleContext context) {
FraudoParser.Country_byContext ctx = (FraudoParser.Country_byContext) context;
public static String generate(FraudoPaymentParser.Country_byContext ctx) {
String fieldName = TextUtil.safeGetText(ctx.STRING());
return new StringBuilder()
.append(ctx.children.get(0))

View File

@ -1,17 +1,16 @@
package com.rbkmoney.fraudo.utils.key.generator;
import com.rbkmoney.fraudo.FraudoParser;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.antlr.v4.runtime.ParserRuleContext;
import java.util.function.Function;
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class SumKeyGenerator {
public static <T> String generate(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.SumContext ctx = (FraudoParser.SumContext) context;
public static <T> String generate(SumContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
ctx.children.get(0),
ctx.time_window(),
@ -19,8 +18,7 @@ public class SumKeyGenerator {
resolve);
}
public static <T> String generateSuccessKey(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.Sum_successContext ctx = (FraudoParser.Sum_successContext) context;
public static <T> String generateSuccessKey(Sum_successContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
ctx.children.get(0),
ctx.time_window(),
@ -28,8 +26,7 @@ public class SumKeyGenerator {
resolve);
}
public static <T> String generateErrorKey(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.Sum_errorContext ctx = (FraudoParser.Sum_errorContext) context;
public static <T> String generateErrorKey(Sum_errorContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedTwoFieldFunction(ctx.STRING(0),
ctx.STRING(1),
ctx.children.get(0),
@ -38,8 +35,7 @@ public class SumKeyGenerator {
resolve);
}
public static <T> String generateChargebackKey(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.Sum_chargebackContext ctx = (FraudoParser.Sum_chargebackContext) context;
public static <T> String generateChargebackKey(Sum_chargebackContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
ctx.children.get(0),
ctx.time_window(),
@ -47,8 +43,7 @@ public class SumKeyGenerator {
resolve);
}
public static <T> String generateRefundKey(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.Sum_refundContext ctx = (FraudoParser.Sum_refundContext) context;
public static <T> String generateRefundKey(Sum_refundContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
ctx.children.get(0),
ctx.time_window(),

View File

@ -1,17 +1,16 @@
package com.rbkmoney.fraudo.utils.key.generator;
import com.rbkmoney.fraudo.FraudoParser;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.antlr.v4.runtime.ParserRuleContext;
import java.util.function.Function;
import static com.rbkmoney.fraudo.FraudoPaymentParser.UniqueContext;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class UniqueKeyGenerator {
public static <T> String generate(ParserRuleContext context, Function<String, T> resolve) {
FraudoParser.UniqueContext ctx = (FraudoParser.UniqueContext) context;
public static <T> String generate(UniqueContext ctx, Function<String, T> resolve) {
return CommonKeyGenerator.generateKeyGroupedTwoFieldFunction(
ctx.STRING(0),
ctx.STRING(1),

View File

@ -1,17 +0,0 @@
package com.rbkmoney.fraudo.visitor;
import com.rbkmoney.fraudo.FraudoParser;
public interface CountVisitor<T> {
Integer visitCount(FraudoParser.CountContext ctx, T model);
Integer visitCountSuccess(FraudoParser.Count_successContext ctx, T model);
Integer visitCountError(FraudoParser.Count_errorContext ctx, T model);
Integer visitCountChargeback(FraudoParser.Count_chargebackContext ctx, T model);
Integer visitCountRefund(FraudoParser.Count_refundContext ctx, T model);
}

View File

@ -1,15 +0,0 @@
package com.rbkmoney.fraudo.visitor;
import com.rbkmoney.fraudo.FraudoParser;
public interface CustomFuncVisitor<T> {
String visitCountryBy(FraudoParser.Country_byContext ctx, T model);
boolean visitIn(FraudoParser.InContext ctx, T model);
boolean visitLike(FraudoParser.LikeContext ctx, T model);
Integer visitUnique(FraudoParser.UniqueContext ctx, T model);
}

View File

@ -1,15 +0,0 @@
package com.rbkmoney.fraudo.visitor;
import com.rbkmoney.fraudo.FraudoParser;
public interface ListVisitor<T> {
Boolean visitInWhiteList(FraudoParser.In_white_listContext ctx, T model);
Boolean visitInBlackList(FraudoParser.In_black_listContext ctx, T model);
Boolean visitInGreyList(FraudoParser.In_grey_listContext ctx, T model);
Boolean visitInList(FraudoParser.In_listContext ctx, T model);
}

View File

@ -1,17 +0,0 @@
package com.rbkmoney.fraudo.visitor;
import com.rbkmoney.fraudo.FraudoParser;
public interface SumVisitor<T> {
Double visitSum(FraudoParser.SumContext ctx, T model);
Double visitSumSuccess(FraudoParser.Sum_successContext ctx, T model);
Double visitSumError(FraudoParser.Sum_errorContext ctx, T model);
Double visitSumChargeback(FraudoParser.Sum_chargebackContext ctx, T model);
Double visitSumRefund(FraudoParser.Sum_refundContext ctx, T model);
}

View File

@ -1,12 +1,12 @@
package com.rbkmoney.fraudo.visitor;
import com.rbkmoney.fraudo.model.BaseModel;
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.Closeable;
import java.util.Map;
public interface TemplateVisitor<T extends BaseModel> extends Closeable {
public interface TemplateVisitor<T, R> extends Closeable {
Object visit(ParseTree tree, T model);
R visit(ParseTree tree, T model);
}

View File

@ -1,76 +0,0 @@
package com.rbkmoney.fraudo.visitor.impl;
import com.rbkmoney.fraudo.FraudoParser;
import com.rbkmoney.fraudo.aggregator.CountAggregator;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.resolver.GroupFieldsResolver;
import com.rbkmoney.fraudo.resolver.TimeWindowResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import com.rbkmoney.fraudo.visitor.CountVisitor;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class CountVisitorImpl<T, U> implements CountVisitor<T> {
private final CountAggregator<T, U> countAggregator;
private final FieldResolver<T, U> fieldResolver;
private final GroupFieldsResolver<U> groupFieldsResolver;
@Override
public Integer visitCount(com.rbkmoney.fraudo.FraudoParser.CountContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return countAggregator.count(
fieldResolver.resolveName(countTarget),
model,
TimeWindowResolver.resolve(ctx.time_window()),
groupFieldsResolver.resolve(ctx.group_by())
);
}
@Override
public Integer visitCountSuccess(FraudoParser.Count_successContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return countAggregator.countSuccess(
fieldResolver.resolveName(countTarget),
model,
TimeWindowResolver.resolve(ctx.time_window()),
groupFieldsResolver.resolve(ctx.group_by())
);
}
@Override
public Integer visitCountError(FraudoParser.Count_errorContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING(0));
String errorCode = TextUtil.safeGetText(ctx.STRING(1));
return countAggregator.countError(
fieldResolver.resolveName(countTarget),
model,
TimeWindowResolver.resolve(ctx.time_window()),
errorCode,
groupFieldsResolver.resolve(ctx.group_by())
);
}
@Override
public Integer visitCountChargeback(FraudoParser.Count_chargebackContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return countAggregator.countChargeback(
fieldResolver.resolveName(countTarget),
model,
TimeWindowResolver.resolve(ctx.time_window()),
groupFieldsResolver.resolve(ctx.group_by())
);
}
@Override
public Integer visitCountRefund(FraudoParser.Count_refundContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return countAggregator.countRefund(
fieldResolver.resolveName(countTarget),
model,
TimeWindowResolver.resolve(ctx.time_window()),
groupFieldsResolver.resolve(ctx.group_by())
);
}
}

View File

@ -1,65 +0,0 @@
package com.rbkmoney.fraudo.visitor.impl;
import com.rbkmoney.fraudo.FraudoParser;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.model.Pair;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.resolver.GroupByModelResolver;
import com.rbkmoney.fraudo.resolver.TimeWindowResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import com.rbkmoney.fraudo.visitor.CustomFuncVisitor;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class CustomFuncVisitorImpl<T, U> implements CustomFuncVisitor<T> {
private final UniqueValueAggregator<T, U> uniqueValueAggregator;
private final CountryResolver<U> countryResolver;
private final FieldResolver<T, U> fieldResolver;
private final GroupByModelResolver<T, U> groupByModelResolver;
@Override
public String visitCountryBy(FraudoParser.Country_byContext ctx, T model) {
String fieldName = TextUtil.safeGetText(ctx.STRING());
Pair<U, String> resolve = fieldResolver.resolve(fieldName, model);
return countryResolver.resolveCountry(resolve.getFirst(), resolve.getSecond());
}
@Override
public boolean visitIn(FraudoParser.InContext ctx, T model) {
final String fieldValue;
if (ctx.STRING() != null && ctx.STRING().getText() != null && !ctx.STRING().getText().isEmpty()) {
String field = TextUtil.safeGetText(ctx.STRING());
fieldValue = fieldResolver.resolve(field, model).getSecond();
} else {
String fieldName = TextUtil.safeGetText(ctx.country_by().STRING());
Pair<U, String> resolve = fieldResolver.resolve(fieldName, model);
fieldValue = countryResolver.resolveCountry(resolve.getFirst(), resolve.getSecond());
}
return ctx.string_list().STRING().stream()
.anyMatch(s -> fieldValue.equals(TextUtil.safeGetText(s)));
}
@Override
public boolean visitLike(FraudoParser.LikeContext ctx, T model) {
String fieldName = TextUtil.safeGetText(ctx.STRING(0));
String fieldValue = fieldResolver.resolve(fieldName, model).getSecond();
String pattern = TextUtil.safeGetText(ctx.STRING(1));
return fieldValue.matches(pattern);
}
@Override
public Integer visitUnique(FraudoParser.UniqueContext ctx, T model) {
String field = TextUtil.safeGetText(ctx.STRING(0));
String fieldBy = TextUtil.safeGetText(ctx.STRING(1));
return uniqueValueAggregator.countUniqueValue(
fieldResolver.resolveName(field),
model,
fieldResolver.resolveName(fieldBy),
TimeWindowResolver.resolve(ctx.time_window()),
groupByModelResolver.resolve(ctx.group_by())
);
}
}

View File

@ -1,305 +0,0 @@
package com.rbkmoney.fraudo.visitor.impl;
import com.rbkmoney.fraudo.FraudoBaseVisitor;
import com.rbkmoney.fraudo.FraudoParser;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.exception.NotImplementedOperatorException;
import com.rbkmoney.fraudo.exception.NotValidContextException;
import com.rbkmoney.fraudo.exception.UnknownResultException;
import com.rbkmoney.fraudo.model.BaseModel;
import com.rbkmoney.fraudo.model.ResultModel;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import com.rbkmoney.fraudo.utils.key.generator.*;
import com.rbkmoney.fraudo.visitor.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@RequiredArgsConstructor
public class FirstFindVisitorImpl<T extends BaseModel, U> extends FraudoBaseVisitor<Object> implements TemplateVisitor<T> {
private ThreadLocal<Map<String, Object>> localFuncCache = ThreadLocal.withInitial(HashMap::new);
private ThreadLocal<T> threadLocalModel = new ThreadLocal<>();
private final CountVisitor<T> countVisitor;
private final SumVisitor<T> sumVisitor;
private final ListVisitor<T> listVisitor;
private final CustomFuncVisitor<T> customFuncVisitor;
private final FieldResolver<T, U> fieldResolver;
@Override
public void close() {
localFuncCache.remove();
threadLocalModel.remove();
}
@Override
public Object visit(ParseTree tree, T model) {
try {
validateModel(model);
threadLocalModel.set(model);
return super.visit(tree);
} finally {
localFuncCache.get().clear();
}
}
private void validateModel(T model) {
if (model == null) {
log.error("Model is not init!");
throw new NotValidContextException();
}
}
@Override
public Object visitFraud_rule(FraudoParser.Fraud_ruleContext ctx) {
try {
if (asBoolean(ctx.expression())) {
return ResultStatus.getByValue((String) super.visit(ctx.result()));
}
} catch (Exception e) {
log.error("Error when FastFraudVisitorImpl visitFraud_rule e: ", e);
if (ctx.catch_result() != null && ctx.catch_result().getText() != null) {
return ResultStatus.getByValue(ctx.catch_result().getText());
}
return ResultStatus.NOTIFY;
}
return ResultStatus.NORMAL;
}
@Override
public Object visitParse(FraudoParser.ParseContext ctx) {
List<String> notifications = new ArrayList<>();
for (FraudoParser.Fraud_ruleContext fraudRuleContext : ctx.fraud_rule()) {
ResultStatus result = (ResultStatus) visitFraud_rule(fraudRuleContext);
String key = RuleKeyGenerator.generateRuleKey(fraudRuleContext);
if (result == null) {
throw new UnknownResultException(fraudRuleContext.getText());
} else if (result == ResultStatus.NOTIFY) {
notifications.add(key);
} else if (result != ResultStatus.NORMAL) {
return new ResultModel(result, key, notifications);
}
}
return new ResultModel(ResultStatus.NORMAL, notifications);
}
@Override
public Object visitResult(FraudoParser.ResultContext ctx) {
return ctx.getText();
}
@Override
public Object visitDecimalExpression(FraudoParser.DecimalExpressionContext ctx) {
return Double.valueOf(ctx.DECIMAL().getText());
}
@Override
public Object visitStringExpression(FraudoParser.StringExpressionContext ctx) {
return TextUtil.safeGetText(ctx.STRING());
}
@Override
public Object visitNotExpression(FraudoParser.NotExpressionContext ctx) {
return !((Boolean) this.visit(ctx.expression()));
}
@Override
public Object visitParenExpression(FraudoParser.ParenExpressionContext ctx) {
return super.visit(ctx.expression());
}
@Override
public Object visitComparatorExpression(FraudoParser.ComparatorExpressionContext ctx) {
if (ctx.op.EQ() != null) {
return this.visit(ctx.left).equals(this.visit(ctx.right));
} else if (ctx.op.LE() != null) {
return asDouble(ctx.left) <= asDouble(ctx.right);
} else if (ctx.op.GE() != null) {
return asDouble(ctx.left) >= asDouble(ctx.right);
} else if (ctx.op.LT() != null) {
return asDouble(ctx.left) < asDouble(ctx.right);
} else if (ctx.op.GT() != null) {
return asDouble(ctx.left) > asDouble(ctx.right);
}
throw new NotImplementedOperatorException(ctx.op.getText());
}
@Override
public Object visitBinaryExpression(FraudoParser.BinaryExpressionContext ctx) {
if (ctx.op.AND() != null) {
return asBoolean(ctx.left) && asBoolean(ctx.right);
} else if (ctx.op.OR() != null) {
return asBoolean(ctx.left) || asBoolean(ctx.right);
}
throw new NotImplementedOperatorException(ctx.op.getText());
}
@Override
public Object visitBoolExpression(FraudoParser.BoolExpressionContext ctx) {
return Boolean.valueOf(ctx.getText());
}
@Override
public Object visitCount(FraudoParser.CountContext ctx) {
String key = CountKeyGenerator.generate(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> Double.valueOf(countVisitor.visitCount(ctx, threadLocalModel.get()))
);
}
@Override
public Object visitCount_success(FraudoParser.Count_successContext ctx) {
String key = CountKeyGenerator.generateSuccessKey(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> Double.valueOf(countVisitor.visitCountSuccess(ctx, threadLocalModel.get()))
);
}
@Override
public Object visitCount_error(FraudoParser.Count_errorContext ctx) {
String key = CountKeyGenerator.generateErrorKey(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> Double.valueOf(countVisitor.visitCountError(ctx, threadLocalModel.get()))
);
}
@Override
public Object visitCount_chargeback(FraudoParser.Count_chargebackContext ctx) {
String key = CountKeyGenerator.generateChargebackKey(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> Double.valueOf(countVisitor.visitCountChargeback(ctx, threadLocalModel.get()))
);
}
@Override
public Object visitCount_refund(FraudoParser.Count_refundContext ctx) {
String key = CountKeyGenerator.generateRefundKey(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> Double.valueOf(countVisitor.visitCountRefund(ctx, threadLocalModel.get()))
);
}
@Override
public Object visitSum(FraudoParser.SumContext ctx) {
String key = SumKeyGenerator.generate(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSum(ctx, threadLocalModel.get())
);
}
@Override
public Object visitSum_success(FraudoParser.Sum_successContext ctx) {
String key = SumKeyGenerator.generateSuccessKey(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSumSuccess(ctx, threadLocalModel.get())
);
}
@Override
public Object visitSum_error(FraudoParser.Sum_errorContext ctx) {
String key = SumKeyGenerator.generateErrorKey(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSumError(ctx, threadLocalModel.get())
);
}
@Override
public Object visitSum_chargeback(FraudoParser.Sum_chargebackContext ctx) {
String key = SumKeyGenerator.generateChargebackKey(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSumChargeback(ctx, threadLocalModel.get())
);
}
@Override
public Object visitSum_refund(FraudoParser.Sum_refundContext ctx) {
String key = SumKeyGenerator.generateRefundKey(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> sumVisitor.visitSumRefund(ctx, threadLocalModel.get())
);
}
@Override
public Object visitCountry_by(FraudoParser.Country_byContext ctx) {
String key = CountryKeyGenerator.generate(ctx);
return localFuncCache.get().computeIfAbsent(
key,
s -> customFuncVisitor.visitCountryBy(ctx, threadLocalModel.get())
);
}
@Override
public Object visitIn(FraudoParser.InContext ctx) {
return customFuncVisitor.visitIn(ctx, threadLocalModel.get());
}
@Override
public Object visitLike(FraudoParser.LikeContext ctx) {
return customFuncVisitor.visitLike(ctx, threadLocalModel.get());
}
@Override
public Object visitUnique(FraudoParser.UniqueContext ctx) {
String key = UniqueKeyGenerator.generate(ctx, fieldResolver::resolveName);
return localFuncCache.get().computeIfAbsent(
key,
s -> Double.valueOf(customFuncVisitor.visitUnique(ctx, threadLocalModel.get()))
);
}
@Override
public Object visitIn_white_list(FraudoParser.In_white_listContext ctx) {
return listVisitor.visitInWhiteList(ctx, threadLocalModel.get());
}
@Override
public Object visitIn_black_list(FraudoParser.In_black_listContext ctx) {
return listVisitor.visitInBlackList(ctx, threadLocalModel.get());
}
@Override
public Object visitIn_grey_list(FraudoParser.In_grey_listContext ctx) {
return listVisitor.visitInGreyList(ctx, threadLocalModel.get());
}
@Override
public Object visitIn_list(FraudoParser.In_listContext ctx) {
return listVisitor.visitInList(ctx, threadLocalModel.get());
}
@Override
public Object visitAmount(FraudoParser.AmountContext ctx) {
return Double.valueOf(threadLocalModel.get().getAmount());
}
@Override
public Object visitCurrency(FraudoParser.CurrencyContext ctx) {
return threadLocalModel.get().getCurrency();
}
private boolean asBoolean(FraudoParser.ExpressionContext ctx) {
return (boolean) visit(ctx);
}
private double asDouble(FraudoParser.ExpressionContext ctx) {
return (double) visit(ctx);
}
}

View File

@ -1,74 +0,0 @@
package com.rbkmoney.fraudo.visitor.impl;
import com.rbkmoney.fraudo.FraudoParser;
import com.rbkmoney.fraudo.aggregator.SumAggregator;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.resolver.GroupByModelResolver;
import com.rbkmoney.fraudo.resolver.TimeWindowResolver;
import com.rbkmoney.fraudo.utils.TextUtil;
import com.rbkmoney.fraudo.visitor.SumVisitor;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class SumVisitorImpl<T, U> implements SumVisitor<T> {
private final SumAggregator<T, U> sumAggregator;
private final FieldResolver<T, U> fieldResolver;
private final GroupByModelResolver<T, U> groupByModelResolver;
@Override
public Double visitSum(FraudoParser.SumContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return sumAggregator.sum(
fieldResolver.resolveName(countTarget),
model,
TimeWindowResolver.resolve(ctx.time_window()),
groupByModelResolver.resolve(ctx.group_by())
);
}
@Override
public Double visitSumSuccess(FraudoParser.Sum_successContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return sumAggregator.sumSuccess(
fieldResolver.resolveName(countTarget),
model,
TimeWindowResolver.resolve(ctx.time_window()),
groupByModelResolver.resolve(ctx.group_by()));
}
@Override
public Double visitSumError(FraudoParser.Sum_errorContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING(0));
String errorCode = TextUtil.safeGetText(ctx.STRING(1));
return sumAggregator.sumError(
fieldResolver.resolveName(countTarget),
model,
TimeWindowResolver.resolve(ctx.time_window()),
errorCode,
groupByModelResolver.resolve(ctx.group_by()));
}
@Override
public Double visitSumChargeback(FraudoParser.Sum_chargebackContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return sumAggregator.sumChargeback(
fieldResolver.resolveName(countTarget),
model,
TimeWindowResolver.resolve(ctx.time_window()),
groupByModelResolver.resolve(ctx.group_by())
);
}
@Override
public Double visitSumRefund(FraudoParser.Sum_refundContext ctx, T model) {
String countTarget = TextUtil.safeGetText(ctx.STRING());
return sumAggregator.sumRefund(
fieldResolver.resolveName(countTarget),
model,
TimeWindowResolver.resolve(ctx.time_window()),
groupByModelResolver.resolve(ctx.group_by())
);
}
}

View File

@ -1,17 +1,19 @@
package com.rbkmoney.fraudo;
import com.rbkmoney.fraudo.aggregator.CountAggregator;
import com.rbkmoney.fraudo.aggregator.SumAggregator;
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.test.constant.PaymentCheckedField;
import com.rbkmoney.fraudo.factory.FirstFraudVisitorFactory;
import com.rbkmoney.fraudo.finder.InListFinder;
import com.rbkmoney.fraudo.test.model.PaymentModel;
import com.rbkmoney.fraudo.model.ResultModel;
import com.rbkmoney.fraudo.payment.aggregator.CountPaymentAggregator;
import com.rbkmoney.fraudo.payment.aggregator.SumPaymentAggregator;
import com.rbkmoney.fraudo.payment.factory.FraudVisitorFactoryImpl;
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.FieldResolver;
import com.rbkmoney.fraudo.resolver.GroupByModelResolver;
import com.rbkmoney.fraudo.test.payout.PaymentModelFieldResolver;
import com.rbkmoney.fraudo.test.constant.PaymentCheckedField;
import com.rbkmoney.fraudo.test.model.PaymentModel;
import com.rbkmoney.fraudo.test.payment.PaymentModelFieldResolver;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.mockito.Mock;
@ -22,46 +24,48 @@ import java.io.InputStream;
public class AbstractPaymentTest {
@Mock
CountAggregator<PaymentModel, PaymentCheckedField> countAggregator;
CountPaymentAggregator<PaymentModel, PaymentCheckedField> countPaymentAggregator;
@Mock
SumAggregator<PaymentModel, PaymentCheckedField> sumAggregator;
SumPaymentAggregator<PaymentModel, PaymentCheckedField> sumPaymentAggregator;
@Mock
UniqueValueAggregator<PaymentModel, PaymentCheckedField> uniqueValueAggregator;
@Mock
CountryResolver<PaymentCheckedField> countryResolver;
@Mock
InListFinder<PaymentModel, PaymentCheckedField> inListFinder;
@Mock
PaymentTimeWindowResolver timeWindowResolver;
private FieldResolver<PaymentModel, PaymentCheckedField> fieldResolver = new PaymentModelFieldResolver();
private GroupByModelResolver<PaymentModel, PaymentCheckedField> groupByModelResolver = new GroupByModelResolver<>(fieldResolver);
private PaymentGroupResolver<PaymentModel, PaymentCheckedField> paymentGroupResolver = new PaymentGroupResolver<>(fieldResolver);
ResultModel parseAndVisit(InputStream resourceAsStream) throws IOException {
com.rbkmoney.fraudo.FraudoParser.ParseContext parse = getParseContext(resourceAsStream);
ParseContext parse = getParseContext(resourceAsStream);
return invokeParse(parse);
}
ResultModel invokeParse(com.rbkmoney.fraudo.FraudoParser.ParseContext parse) {
ResultModel invokeParse(ParseContext parse) {
PaymentModel model = new PaymentModel();
return invoke(parse, model);
}
ResultModel invoke(com.rbkmoney.fraudo.FraudoParser.ParseContext parse, PaymentModel model) {
return (ResultModel) new FirstFraudVisitorFactory()
ResultModel invoke(ParseContext parse, PaymentModel model) {
return new FraudVisitorFactoryImpl()
.createVisitor(
countAggregator,
sumAggregator,
countPaymentAggregator,
sumPaymentAggregator,
uniqueValueAggregator,
countryResolver,
inListFinder,
fieldResolver,
groupByModelResolver)
paymentGroupResolver,
timeWindowResolver)
.visit(parse, model);
}
com.rbkmoney.fraudo.FraudoParser.ParseContext getParseContext(InputStream resourceAsStream) throws IOException {
com.rbkmoney.fraudo.FraudoLexer lexer = new com.rbkmoney.fraudo.FraudoLexer(new ANTLRInputStream(resourceAsStream));
com.rbkmoney.fraudo.FraudoParser parser = new com.rbkmoney.fraudo.FraudoParser(new CommonTokenStream(lexer));
ParseContext getParseContext(InputStream resourceAsStream) throws IOException {
com.rbkmoney.fraudo.FraudoPaymentLexer lexer = new com.rbkmoney.fraudo.FraudoPaymentLexer(new ANTLRInputStream(resourceAsStream));
com.rbkmoney.fraudo.FraudoPaymentParser parser = new com.rbkmoney.fraudo.FraudoPaymentParser(new CommonTokenStream(lexer));
return parser.parse();
}

View File

@ -1,5 +1,6 @@
package com.rbkmoney.fraudo;
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.model.ResultModel;
import org.junit.Before;
@ -22,19 +23,19 @@ public class CountTest extends AbstractPaymentTest {
@Test
public void countTest() throws Exception {
InputStream resourceAsStream = CountTest.class.getResourceAsStream("/rules/count.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
when(countAggregator.countError(anyObject(), any(), any(), anyString(), any())).thenReturn(6);
when(countAggregator.countSuccess(anyObject(), any(), any(), any())).thenReturn(4);
when(countAggregator.countChargeback(anyObject(), any(), any(), any())).thenReturn(0);
when(countAggregator.countRefund(anyObject(), any(), any(), any())).thenReturn(1);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
when(countPaymentAggregator.countError(anyObject(), any(), any(), anyString(), any())).thenReturn(6);
when(countPaymentAggregator.countSuccess(anyObject(), any(), any(), any())).thenReturn(4);
when(countPaymentAggregator.countChargeback(anyObject(), any(), any(), any())).thenReturn(0);
when(countPaymentAggregator.countRefund(anyObject(), any(), any(), any())).thenReturn(1);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
assertEquals("1", result.getRuleChecked());
assertEquals("0", result.getRuleChecked());
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(9);
when(countAggregator.countError(anyObject(), any(), any(), anyString(), any())).thenReturn(6);
when(countAggregator.countSuccess(anyObject(), any(), any(), any())).thenReturn(6);
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(9);
when(countPaymentAggregator.countError(anyObject(), any(), any(), anyString(), any())).thenReturn(6);
when(countPaymentAggregator.countSuccess(anyObject(), any(), any(), any())).thenReturn(6);
result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
@ -43,24 +44,24 @@ public class CountTest extends AbstractPaymentTest {
@Test
public void countCargeRefundTest() throws Exception {
InputStream resourceAsStream = CountTest.class.getResourceAsStream("/rules/count_chargeback_refund.frd");
when(countAggregator.countChargeback(anyObject(), any(), any(), any())).thenReturn(3);
when(countAggregator.countRefund(anyObject(), any(), any(), any())).thenReturn(5);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
when(countPaymentAggregator.countChargeback(anyObject(), any(), any(), any())).thenReturn(3);
when(countPaymentAggregator.countRefund(anyObject(), any(), any(), any())).thenReturn(5);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
assertEquals("1", result.getRuleChecked());
assertEquals("0", result.getRuleChecked());
}
@Test
public void countGroupByTest() throws Exception {
InputStream resourceAsStream = CountTest.class.getResourceAsStream("/rules/countGroupBy.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
assertEquals("1", result.getRuleChecked());
assertEquals("0", result.getRuleChecked());
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
result = invokeParse(parseContext);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
}
@ -68,33 +69,33 @@ public class CountTest extends AbstractPaymentTest {
@Test
public void countTimeWindowGroupByTest() throws Exception {
InputStream resourceAsStream = CountTest.class.getResourceAsStream("/rules/countTimeWindowGroupBy.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
assertEquals("1", result.getRuleChecked());
assertEquals("0", result.getRuleChecked());
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
result = invokeParse(parseContext);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
resourceAsStream = CountTest.class.getResourceAsStream("/rules/countTimeWindowGroupBy_2.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
parseContext = getParseContext(resourceAsStream);
result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
assertEquals("1", result.getRuleChecked());
assertEquals("0", result.getRuleChecked());
}
@Test
public void countCardTokenTest() throws Exception {
InputStream resourceAsStream = CountTest.class.getResourceAsStream("/rules/count_card_token.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
verify(countAggregator, times(1)).count(anyObject(), any(), any(), any());
verify(countPaymentAggregator, times(1)).count(anyObject(), any(), any(), any());
}
}

View File

@ -1,14 +1,14 @@
package com.rbkmoney.fraudo;
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.exception.UnknownResultException;
import com.rbkmoney.fraudo.test.model.PaymentModel;
import com.rbkmoney.fraudo.model.ResultModel;
import com.rbkmoney.fraudo.test.model.PaymentModel;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import static org.junit.Assert.assertEquals;
@ -27,7 +27,7 @@ public class CustomTest extends AbstractPaymentTest {
@Test
public void threeDsTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/three_ds.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
ResultModel result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.THREE_DS, result.getResultStatus());
}
@ -35,7 +35,7 @@ public class CustomTest extends AbstractPaymentTest {
@Test
public void highRiskTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/highRisk.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
ResultModel result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.HIGH_RISK, result.getResultStatus());
}
@ -79,7 +79,7 @@ public class CustomTest extends AbstractPaymentTest {
@Test
public void inTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/in.frd");
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
PaymentModel model = new PaymentModel();
model.setEmail(TEST_GMAIL_RU);
ResultModel result = invoke(parseContext, model);
@ -91,17 +91,28 @@ public class CustomTest extends AbstractPaymentTest {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/in_country.frd");
when(countryResolver.resolveCountry(any(), anyString())).thenReturn("RU");
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
PaymentModel model = new PaymentModel();
model.setAmount(500L);
ResultModel result = invoke(parseContext, model);
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
}
@Test
public void inCurrencyTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/in_currency.frd");
ParseContext parseContext = getParseContext(resourceAsStream);
PaymentModel model = new PaymentModel();
model.setCurrency("EUR");
ResultModel result = invoke(parseContext, model);
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
}
@Test
public void amountTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/amount.frd");
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
PaymentModel model = new PaymentModel();
model.setAmount(56L);
model.setCurrency("RUB");
@ -117,7 +128,7 @@ public class CustomTest extends AbstractPaymentTest {
public void catchTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/catch.frd");
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenThrow(new UnknownResultException("as"));
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
}
@ -125,7 +136,7 @@ public class CustomTest extends AbstractPaymentTest {
@Test
public void likeTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/like.frd");
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
PaymentModel model = new PaymentModel();
model.setEmail(TEST_GMAIL_RU);
model.setBin("553619");
@ -141,7 +152,7 @@ public class CustomTest extends AbstractPaymentTest {
@Test
public void inNotTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/in_not.frd");
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
PaymentModel model = new PaymentModel();
model.setEmail(TEST_GMAIL_RU);
ResultModel result = invoke(parseContext, model);
@ -152,7 +163,7 @@ public class CustomTest extends AbstractPaymentTest {
public void uniqCountTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/count_uniq.frd");
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenReturn(2);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
}
@ -161,7 +172,7 @@ public class CustomTest extends AbstractPaymentTest {
public void uniqCountGroupByTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/count_uniqGroupBy_window.frd");
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenReturn(2);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());

View File

@ -1,5 +1,6 @@
package com.rbkmoney.fraudo;
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.model.ResultModel;
import org.junit.Assert;
@ -22,7 +23,7 @@ public class ListTest extends AbstractPaymentTest {
@Test
public void whiteBlackListTest() throws Exception {
InputStream resourceAsStream = ListTest.class.getResourceAsStream("/rules/whitelist.frd");
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
Mockito.when(inListFinder.findInWhiteList(anyList(), anyObject())).thenReturn(true);
ResultModel result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.DECLINE, result.getResultStatus());
@ -38,7 +39,7 @@ public class ListTest extends AbstractPaymentTest {
@Test
public void greyListTest() throws Exception {
InputStream resourceAsStream = ListTest.class.getResourceAsStream("/rules/greyList.frd");
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
Mockito.when(inListFinder.findInGreyList(anyList(), anyObject())).thenReturn(true);
ResultModel result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
@ -47,7 +48,7 @@ public class ListTest extends AbstractPaymentTest {
@Test
public void namingListTest() throws Exception {
InputStream resourceAsStream = ListTest.class.getResourceAsStream("/rules/namingList.frd");
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
Mockito.when(inListFinder.findInList(anyString(), anyList(), anyObject())).thenReturn(true);
ResultModel result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.ACCEPT, result.getResultStatus());

View File

@ -1,8 +1,9 @@
package com.rbkmoney.fraudo;
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.test.model.PaymentModel;
import com.rbkmoney.fraudo.model.ResultModel;
import com.rbkmoney.fraudo.test.model.PaymentModel;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
@ -33,7 +34,7 @@ public class RealTimerTest extends AbstractPaymentTest {
CountDownLatch countDownLatch = new CountDownLatch(1);
mockAggr(countDownLatch);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
PaymentModel model = new PaymentModel();
model.setAmount(MILLISTIME_FAST_FUNC);
@ -55,7 +56,7 @@ public class RealTimerTest extends AbstractPaymentTest {
CountDownLatch countDownLatch = new CountDownLatch(1);
mockAggr(countDownLatch);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
ParseContext parseContext = getParseContext(resourceAsStream);
PaymentModel model = new PaymentModel();
model.setAmount(MILLISTIME_FAST_FUNC);
@ -73,25 +74,25 @@ public class RealTimerTest extends AbstractPaymentTest {
}
private void mockAggr(CountDownLatch countDownLatch) {
when(countAggregator.count(any(), any(), any(), any()))
when(countPaymentAggregator.count(any(), any(), any(), any()))
.thenAnswer((Answer<Integer>) invocationOnMock -> {
Thread.sleep(TIME_CALL_AGGR_FUNC);
countDownLatch.countDown();
return 1;
});
when(countAggregator.countSuccess(any(), any(), any(), any()))
when(countPaymentAggregator.countSuccess(any(), any(), any(), any()))
.thenAnswer((Answer<Integer>) invocationOnMock -> {
Thread.sleep(TIME_CALL_AGGR_FUNC);
countDownLatch.countDown();
return 1;
});
when(sumAggregator.sum(any(), any(), any(), any()))
when(sumPaymentAggregator.sum(any(), any(), any(), any()))
.thenAnswer((Answer<Double>) invocationOnMock -> {
Thread.sleep(TIME_CALL_AGGR_FUNC);
return 10000.0;
});
when(sumAggregator.sumSuccess(any(), any(), any(), any()))
when(sumPaymentAggregator.sumSuccess(any(), any(), any(), any()))
.thenAnswer((Answer<Double>) invocationOnMock -> {
Thread.sleep(TIME_CALL_AGGR_FUNC);
return 10000.0;

View File

@ -1,5 +1,6 @@
package com.rbkmoney.fraudo;
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.model.ResultModel;
import org.junit.Assert;
@ -22,17 +23,17 @@ public class SumTest extends AbstractPaymentTest {
@Test
public void sumTest() throws Exception {
InputStream resourceAsStream = SumTest.class.getResourceAsStream("/rules/sum.frd");
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
Mockito.when(sumAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(524.0);
Mockito.when(sumAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(4.0);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
Mockito.when(sumPaymentAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
Mockito.when(sumPaymentAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(524.0);
Mockito.when(sumPaymentAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(4.0);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
Assert.assertEquals(1, result.getNotificationsRule().size());
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
Mockito.when(sumAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(504.0);
Mockito.when(sumAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(501.0);
Mockito.when(sumPaymentAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
Mockito.when(sumPaymentAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(504.0);
Mockito.when(sumPaymentAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(501.0);
result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
@ -42,9 +43,9 @@ public class SumTest extends AbstractPaymentTest {
@Test
public void sumChargeRefundTest() throws Exception {
InputStream resourceAsStream = SumTest.class.getResourceAsStream("/rules/sum_chargeback_refund.frd");
Mockito.when(sumAggregator.sumChargeback(anyObject(), any(), any(), any())).thenReturn(10000.60);
Mockito.when(sumAggregator.sumRefund(anyObject(), any(), any(), any())).thenReturn(10000.60);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
Mockito.when(sumPaymentAggregator.sumChargeback(anyObject(), any(), any(), any())).thenReturn(10000.60);
Mockito.when(sumPaymentAggregator.sumRefund(anyObject(), any(), any(), any())).thenReturn(10000.60);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
}
@ -52,17 +53,17 @@ public class SumTest extends AbstractPaymentTest {
@Test
public void sumGroupByTest() throws Exception {
InputStream resourceAsStream = SumTest.class.getResourceAsStream("/rules/sumGroupBy.frd");
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
Mockito.when(sumAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(524.0);
Mockito.when(sumAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(4.0);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
Mockito.when(sumPaymentAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
Mockito.when(sumPaymentAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(524.0);
Mockito.when(sumPaymentAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(4.0);
ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
Assert.assertEquals(1, result.getNotificationsRule().size());
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
Mockito.when(sumAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(504.0);
Mockito.when(sumAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(501.0);
Mockito.when(sumPaymentAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
Mockito.when(sumPaymentAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(504.0);
Mockito.when(sumPaymentAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(501.0);
result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());

View File

@ -1,15 +1,16 @@
package com.rbkmoney.fraudo;
package com.rbkmoney.fraudo.p2p;
import com.rbkmoney.fraudo.aggregator.CountAggregator;
import com.rbkmoney.fraudo.aggregator.SumAggregator;
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
import com.rbkmoney.fraudo.test.constant.P2PCheckedField;
import com.rbkmoney.fraudo.factory.FirstFraudVisitorFactory;
import com.rbkmoney.fraudo.finder.InListFinder;
import com.rbkmoney.fraudo.test.model.P2PModel;
import com.rbkmoney.fraudo.model.ResultModel;
import com.rbkmoney.fraudo.p2p.factory.P2PFraudVisitorFactory;
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
import com.rbkmoney.fraudo.p2p.resolver.P2PTimeWindowResolver;
import com.rbkmoney.fraudo.resolver.CountryResolver;
import com.rbkmoney.fraudo.resolver.GroupByModelResolver;
import com.rbkmoney.fraudo.test.constant.P2PCheckedField;
import com.rbkmoney.fraudo.test.model.P2PModel;
import com.rbkmoney.fraudo.test.p2p.P2PModelFieldResolver;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
@ -30,23 +31,25 @@ public class AbstractP2PTest {
CountryResolver<P2PCheckedField> countryResolver;
@Mock
InListFinder<P2PModel, P2PCheckedField> listFinder;
@Mock
P2PTimeWindowResolver timeWindowResolver;
private P2PModelFieldResolver fieldResolver = new P2PModelFieldResolver();
private GroupByModelResolver<P2PModel, P2PCheckedField> groupByModelResolver = new GroupByModelResolver<>(fieldResolver);
private P2PGroupResolver<P2PModel, P2PCheckedField> paymentGroupResolver = new P2PGroupResolver<>(fieldResolver);
ResultModel parseAndVisit(InputStream resourceAsStream) throws IOException {
com.rbkmoney.fraudo.FraudoParser.ParseContext parse = getParseContext(resourceAsStream);
com.rbkmoney.fraudo.FraudoP2PParser.ParseContext parse = getParseContext(resourceAsStream);
return invokeParse(parse);
}
ResultModel invokeParse(com.rbkmoney.fraudo.FraudoParser.ParseContext parse) {
ResultModel invokeParse(com.rbkmoney.fraudo.FraudoP2PParser.ParseContext parse) {
P2PModel model = new P2PModel();
return invoke(parse, model);
}
ResultModel invoke(com.rbkmoney.fraudo.FraudoParser.ParseContext parse, P2PModel model) {
return (ResultModel) new FirstFraudVisitorFactory()
ResultModel invoke(com.rbkmoney.fraudo.FraudoP2PParser.ParseContext parse, P2PModel model) {
return new P2PFraudVisitorFactory()
.createVisitor(
countAggregator,
sumAggregator,
@ -54,13 +57,14 @@ public class AbstractP2PTest {
countryResolver,
listFinder,
fieldResolver,
groupByModelResolver)
paymentGroupResolver,
timeWindowResolver)
.visit(parse, model);
}
com.rbkmoney.fraudo.FraudoParser.ParseContext getParseContext(InputStream resourceAsStream) throws IOException {
com.rbkmoney.fraudo.FraudoLexer lexer = new com.rbkmoney.fraudo.FraudoLexer(new ANTLRInputStream(resourceAsStream));
com.rbkmoney.fraudo.FraudoParser parser = new com.rbkmoney.fraudo.FraudoParser(new CommonTokenStream(lexer));
com.rbkmoney.fraudo.FraudoP2PParser.ParseContext getParseContext(InputStream resourceAsStream) throws IOException {
com.rbkmoney.fraudo.FraudoP2PLexer lexer = new com.rbkmoney.fraudo.FraudoP2PLexer(new ANTLRInputStream(resourceAsStream));
com.rbkmoney.fraudo.FraudoP2PParser parser = new com.rbkmoney.fraudo.FraudoP2PParser(new CommonTokenStream(lexer));
return parser.parse();
}

View File

@ -0,0 +1,91 @@
package com.rbkmoney.fraudo.p2p;
import com.rbkmoney.fraudo.FraudoP2PParser;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.model.ResultModel;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.InputStream;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.*;
public class CountP2PTest extends AbstractP2PTest {
public static final String FIRST_RULE_INDEX = "0";
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void countTest() throws Exception {
InputStream resourceAsStream = CountP2PTest.class.getResourceAsStream("/rules/p2p/count.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
Mockito.when(listFinder.findInWhiteList(any(), any())).thenReturn(true);
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
assertEquals(FIRST_RULE_INDEX, result.getRuleChecked());
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(14);
result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
}
@Test
public void countGroupByTest() throws Exception {
InputStream resourceAsStream = CountP2PTest.class.getResourceAsStream("/rules/p2p/countGroupBy.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
assertEquals(FIRST_RULE_INDEX, result.getRuleChecked());
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
result = invokeParse(parseContext);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
}
@Test
public void countTimeWindowGroupByTest() throws Exception {
InputStream resourceAsStream = CountP2PTest.class.getResourceAsStream("/rules/p2p/countTimeWindowGroupBy.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
assertEquals(FIRST_RULE_INDEX, result.getRuleChecked());
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
result = invokeParse(parseContext);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
resourceAsStream = CountP2PTest.class.getResourceAsStream("/rules/p2p/countTimeWindowGroupBy_2.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
parseContext = getParseContext(resourceAsStream);
result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
assertEquals(FIRST_RULE_INDEX, result.getRuleChecked());
}
@Test
public void countCardTokenTest() throws Exception {
InputStream resourceAsStream = CountP2PTest.class.getResourceAsStream("/rules/p2p/count_card_token.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
verify(countAggregator, times(1)).count(anyObject(), any(), any(), any());
}
}

View File

@ -0,0 +1,209 @@
package com.rbkmoney.fraudo.p2p;
import com.rbkmoney.fraudo.CustomTest;
import com.rbkmoney.fraudo.FraudoP2PParser;
import com.rbkmoney.fraudo.FraudoPaymentParser;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.exception.UnknownResultException;
import com.rbkmoney.fraudo.model.ResultModel;
import com.rbkmoney.fraudo.test.model.P2PModel;
import com.rbkmoney.fraudo.test.model.PaymentModel;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import java.io.InputStream;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
public class CustomP2PTest extends AbstractP2PTest {
public static final String TEST_GMAIL_RU = "test@gmail.ru";
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void threeDsTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/three_ds.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
ResultModel result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.THREE_DS, result.getResultStatus());
}
@Test
public void highRiskTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/highRisk.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
ResultModel result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.HIGH_RISK, result.getResultStatus());
}
@Test
public void notifyTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/notify.frd");
ResultModel result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
assertEquals(1, result.getNotificationsRule().size());
}
@Test
public void declineTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/decline.frd");
ResultModel result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
assertEquals("test_11", result.getRuleChecked());
}
@Test
public void acceptTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/accept.frd");
ResultModel result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
}
@Test
public void ruleIsNotFireTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/rule_is_not_fire.frd");
ResultModel result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
}
@Test(expected = UnknownResultException.class)
public void notImplOperatorTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/unknownResult.frd");
parseAndVisit(resourceAsStream);
}
@Test
public void inTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/in.frd");
when(countryResolver.resolveCountry(any(), anyString())).thenReturn("SD");
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
P2PModel model = new P2PModel();
model.setEmail(TEST_GMAIL_RU);
model.setBin("123213");
ResultModel result = invoke(parseContext, model);
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
}
@Test
public void inCurrencyTest() throws Exception {
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/p2p/in_currency.frd");
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
P2PModel model = new P2PModel();
model.setCurrency("EUR");
ResultModel result = invoke(parseContext, model);
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
}
@Test
public void inCountryTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/in_country.frd");
when(countryResolver.resolveCountry(any(), anyString())).thenReturn("RU");
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
P2PModel model = new P2PModel();
model.setAmount(500L);
ResultModel result = invoke(parseContext, model);
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
}
@Test
public void amountTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/amount.frd");
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
P2PModel model = new P2PModel();
model.setAmount(56L);
model.setCurrency("RUB");
ResultModel result = invoke(parseContext, model);
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
model.setCurrency("USD");
result = invoke(parseContext, model);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
}
@Test
public void catchTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/catch.frd");
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenThrow(new UnknownResultException("as"));
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
}
@Test
public void likeTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/like.frd");
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
P2PModel model = new P2PModel();
model.setEmail(TEST_GMAIL_RU);
model.setBin("553619");
model.setPan("9137");
ResultModel result = invoke(parseContext, model);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
model.setPan("9111");
result = invoke(parseContext, model);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
}
@Test
public void inNotTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/in_not.frd");
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
P2PModel model = new P2PModel();
model.setEmail(TEST_GMAIL_RU);
ResultModel result = invoke(parseContext, model);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
}
@Test
public void uniqCountTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/count_uniq.frd");
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenReturn(2);
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
}
@Test
public void uniqCountGroupByTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/count_uniqGroupBy_window.frd");
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenReturn(2);
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
verify(uniqueValueAggregator, times(1)).countUniqueValue(any(), any(), any(), any(), any());
}
@Test
public void eqCountryTest() throws Exception {
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/eq_country.frd");
when(countryResolver.resolveCountry(any(), anyString())).thenReturn("RU");
ResultModel result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
assertEquals(1, result.getNotificationsRule().size());
when(countryResolver.resolveCountry(any(), anyString())).thenReturn("US");
resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/eq_country.frd");
result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
assertEquals(0, result.getNotificationsRule().size());
resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/accept_with_notify.frd");
result = parseAndVisit(resourceAsStream);
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
assertEquals(2, result.getNotificationsRule().size());
}
}

View File

@ -1,8 +1,8 @@
package com.rbkmoney.fraudo;
package com.rbkmoney.fraudo.p2p;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.test.model.P2PModel;
import com.rbkmoney.fraudo.model.ResultModel;
import com.rbkmoney.fraudo.test.model.P2PModel;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
@ -29,11 +29,11 @@ public class P2PTest extends AbstractP2PTest {
@Test
public void timingTest() throws Exception {
InputStream resourceAsStream = P2PTest.class.getResourceAsStream("/rules/p2p_template.frd");
InputStream resourceAsStream = P2PTest.class.getResourceAsStream("/rules/p2p/p2p_template.frd");
CountDownLatch countDownLatch = new CountDownLatch(1);
mockAggr(countDownLatch);
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
com.rbkmoney.fraudo.FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
P2PModel model = new P2PModel();
model.setAmount(MILLISTIME_FAST_FUNC);
@ -57,23 +57,12 @@ public class P2PTest extends AbstractP2PTest {
countDownLatch.countDown();
return 1;
});
when(countAggregator.countSuccess(any(), any(), any(), any()))
.thenAnswer((Answer<Integer>) invocationOnMock -> {
Thread.sleep(TIME_CALL_AGGR_FUNC);
countDownLatch.countDown();
return 1;
});
when(sumAggregator.sum(any(), any(), any(), any()))
.thenAnswer((Answer<Double>) invocationOnMock -> {
Thread.sleep(TIME_CALL_AGGR_FUNC);
return 10000.0;
});
when(sumAggregator.sumSuccess(any(), any(), any(), any()))
.thenAnswer((Answer<Double>) invocationOnMock -> {
Thread.sleep(TIME_CALL_AGGR_FUNC);
return 10000.0;
});
when(listFinder.findInBlackList(anyList(), anyObject()))
.thenAnswer((Answer<Boolean>) invocationOnMock -> {

View File

@ -0,0 +1,38 @@
package com.rbkmoney.fraudo.p2p;
import com.rbkmoney.fraudo.FraudoP2PParser;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.model.ResultModel;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.InputStream;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.*;
public class ParenP2PTest extends AbstractP2PTest {
public static final String FIRST_RULE_INDEX = "0";
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void countCardTokenTest() throws Exception {
InputStream resourceAsStream = ParenP2PTest.class.getResourceAsStream("/rules/p2p/paren.frd");
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
verify(countAggregator, times(2)).count(anyObject(), any(), any(), any());
}
}

View File

@ -0,0 +1,56 @@
package com.rbkmoney.fraudo.p2p;
import com.rbkmoney.fraudo.FraudoP2PParser;
import com.rbkmoney.fraudo.constant.ResultStatus;
import com.rbkmoney.fraudo.model.ResultModel;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.InputStream;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
public class SumP2PTest extends AbstractP2PTest {
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void sumTest() throws Exception {
InputStream resourceAsStream = SumP2PTest.class.getResourceAsStream("/rules/p2p/sum.frd");
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
Assert.assertEquals(1, result.getNotificationsRule().size());
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
Assert.assertEquals(0, result.getNotificationsRule().size());
}
@Test
public void sumGroupByTest() throws Exception {
InputStream resourceAsStream = SumP2PTest.class.getResourceAsStream("/rules/p2p/sumGroupBy.frd");
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
ResultModel result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
Assert.assertEquals(1, result.getNotificationsRule().size());
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
result = invokeParse(parseContext);
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
Assert.assertEquals(0, result.getNotificationsRule().size());
}
}

View File

@ -1,4 +1,4 @@
package com.rbkmoney.fraudo.test.payout;
package com.rbkmoney.fraudo.test.payment;
import com.rbkmoney.fraudo.exception.UnresolvableFieldException;
import com.rbkmoney.fraudo.resolver.FieldResolver;

View File

@ -0,0 +1,3 @@
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<root level="warn">
<appender-ref ref="CONSOLE"/>
</root>
<logger name="com.rbkmoney" level="ALL"/>
</configuration>

View File

@ -0,0 +1,2 @@
rule: in(currency(), "RUB", "EUR")
-> accept;

View File

@ -0,0 +1,2 @@
rule: 3 > 2 AND 1 = 1
-> accept;

View File

@ -0,0 +1,8 @@
rule: 12 > 3
-> notify;
rule: 12 > 3
-> notify;
rule: 12 > 3
-> accept;

View File

@ -0,0 +1,2 @@
rule: amount() < 100 AND currency() = "RUB"
-> accept;

View File

@ -0,0 +1,3 @@
rule: unique("email", "ip") < 4
-> accept
catch: decline;

View File

@ -0,0 +1,2 @@
rule: count("ip", 1444) >= 10 AND count("ip", 1444) < 10 OR sum("ip", 1444) >= 10500.50 AND inWhiteList("email")
-> decline;

View File

@ -0,0 +1,2 @@
rule: count("ip", 1444, "party_id") >= 10
-> decline;

View File

@ -0,0 +1,2 @@
rule: count("ip", 1444, 60, "party_id") >= 10
-> decline;

View File

@ -0,0 +1,2 @@
rule: count("ip", 1444, 60, "partyId", "shop_id") >= 10
-> decline;

View File

@ -0,0 +1,2 @@
rule: count("card_token", 1444) >= 10 AND count("card_token", 1444) >= 9
-> decline;

View File

@ -0,0 +1,2 @@
rule: unique("email", "ip", 1444) < 4
-> decline;

View File

@ -0,0 +1,3 @@
rule: unique("email", "ip", 1444, 123, "party_id", "shop_id") < 4
AND unique("email", "ip", 1444, 123, "party_id", "shop_id") < 4
-> decline;

View File

@ -0,0 +1,2 @@
rule:test_11: 3 > 2 AND 1 = 1
-> decline;

View File

@ -0,0 +1,2 @@
rule: countryBy("ip") = "RU"
-> notify;

View File

@ -0,0 +1,5 @@
rule: 3 > 2 AND 1 > 1
-> decline;
rule: count("email", 10) <= 10 AND count("ip", 1444) = 10
-> highRisk;

View File

@ -0,0 +1,2 @@
rule: in("email", "test@gmail", "test@gmail.ru") and in(countryBy("bin"), "AS", "SD", "TR", "WE", "SD", "CD", "KL", "EW", "VF", "XZ", "CD")
-> accept;

View File

@ -0,0 +1,2 @@
rule: in(countryBy("ip"), "RU", "EN")
-> accept;

View File

@ -0,0 +1,2 @@
rule: in(currency(), "RUB", "EUR")
-> accept;

View File

@ -0,0 +1,2 @@
rule: in("email", "testgmail", "test@g")
-> notify;

View File

@ -0,0 +1 @@
rule:cb:like("bin", "5536.*") AND in("pan","9137")->decline;

View File

@ -0,0 +1,2 @@
rule: 3 > 2 AND 1 = 1
-> notify;

Some files were not shown because too many files have changed in this diff Show More