* BAEL-5143

* Modified as per PR comments

* The List<> type for session data is changed to a more generic Collection<>

* Version upgrade

Co-authored-by: 0swald <andrey.bichkevskiy@gmail.com>
This commit is contained in:
Andrey Bichkevski 2021-10-18 20:22:37 -05:00 committed by GitHub
parent 4dfe21a3dc
commit 025afb1f7d
10 changed files with 389 additions and 0 deletions

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.evrete</groupId>
<artifactId>evrete</artifactId>
<version>1.0</version>
<name>evrete</name>
<properties>
<evrete.version>2.1.04</evrete.version>
</properties>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>rule-engines</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<!-- Core library -->
<dependency>
<groupId>org.evrete</groupId>
<artifactId>evrete-core</artifactId>
<version>${evrete.version}</version>
</dependency>
<!-- Annotated Java classes -->
<dependency>
<groupId>org.evrete</groupId>
<artifactId>evrete-dsl-java</artifactId>
<version>${evrete.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,47 @@
package com.baeldung.evrete.introduction;
import com.baeldung.evrete.introduction.model.Customer;
import com.baeldung.evrete.introduction.model.Invoice;
import org.evrete.KnowledgeService;
import org.evrete.api.Knowledge;
import java.io.IOException;
import java.net.URL;
import java.util.*;
public class IntroductionAJR {
public static void main(String[] args) throws IOException {
ClassLoader classLoader = IntroductionAJR.class.getClassLoader();
KnowledgeService service = new KnowledgeService();
URL rulesetUrl = classLoader.getResource("rules/SalesRuleset.java");
Knowledge knowledge = service.newKnowledge(
"JAVA-SOURCE",
rulesetUrl
);
List<Customer> customers = Arrays.asList(
new Customer("Customer A"),
new Customer("Customer B"),
new Customer("Customer C")
);
Random random = new Random();
Collection<Object> sessionData = new LinkedList<>(customers);
for (int i = 0; i < 100_000; i++) {
Customer randomCustomer = customers.get(random.nextInt(customers.size()));
Invoice invoice = new Invoice(randomCustomer, 100 * random.nextDouble());
sessionData.add(invoice);
}
knowledge
.newStatelessSession()
.insert(sessionData)
.fire();
for (Customer c : customers) {
System.out.printf("%s:\t$%,.2f%n", c.getName(), c.getTotal());
}
service.shutdown();
}
}

View File

@ -0,0 +1,58 @@
package com.baeldung.evrete.introduction;
import org.evrete.KnowledgeService;
import org.evrete.api.Knowledge;
import com.baeldung.evrete.introduction.model.*;
import java.util.*;
public class IntroductionInline {
public static void main(String[] args) {
KnowledgeService service = new KnowledgeService();
Knowledge knowledge = service
.newKnowledge()
.newRule("Clear total sales")
.forEach("$c", Customer.class)
.execute(ctx -> {
Customer c = ctx.get("$c");
c.setTotal(0.0);
})
.newRule("Compute totals")
.forEach(
"$c", Customer.class,
"$i", Invoice.class
)
.where("$i.customer == $c")
.execute(ctx -> {
Customer c = ctx.get("$c");
Invoice i = ctx.get("$i");
c.addToTotal(i.getAmount());
});
List<Customer> customers = Arrays.asList(
new Customer("Customer A"),
new Customer("Customer B"),
new Customer("Customer C")
);
Random random = new Random();
Collection<Object> sessionData = new LinkedList<>(customers);
for (int i = 0; i < 100_000; i++) {
Customer randomCustomer = customers.get(random.nextInt(customers.size()));
Invoice invoice = new Invoice(randomCustomer, 100 * random.nextDouble());
sessionData.add(invoice);
}
knowledge
.newStatelessSession()
.insert(sessionData)
.fire();
for (Customer c : customers) {
System.out.printf("%s:\t$%,.2f%n", c.getName(), c.getTotal());
}
service.shutdown();
}
}

View File

@ -0,0 +1,26 @@
package com.baeldung.evrete.introduction.model;
public class Customer {
private double total = 0.0;
private final String name;
public Customer(String name) {
this.name = name;
}
public void addToTotal(double amount) {
this.total += amount;
}
public String getName() {
return name;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
}

View File

@ -0,0 +1,19 @@
package com.baeldung.evrete.introduction.model;
public class Invoice {
private final Customer customer;
private final double amount;
public Invoice(Customer customer, double amount) {
this.customer = customer;
this.amount = amount;
}
public Customer getCustomer() {
return customer;
}
public double getAmount() {
return amount;
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,20 @@
package org.abc.author1;
import com.baeldung.evrete.introduction.model.Customer;
import com.baeldung.evrete.introduction.model.Invoice;
import org.evrete.dsl.annotation.Rule;
import org.evrete.dsl.annotation.Where;
public class SalesRuleset {
@Rule
public void rule1(Customer $c) {
$c.setTotal(0.0);
}
@Rule
@Where("$i.customer == $c")
public void rule2(Customer $c, Invoice $i) {
$c.addToTotal($i.getAmount());
}
}

View File

@ -0,0 +1,80 @@
package com.baeldung.evrete.introduction;
import com.baeldung.evrete.introduction.model.Customer;
import com.baeldung.evrete.introduction.model.Invoice;
import org.evrete.KnowledgeService;
import org.evrete.api.Knowledge;
import org.evrete.api.RuleSession;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.io.IOException;
import java.util.*;
class IntroductionAJRUnitTest {
private static KnowledgeService service;
@BeforeAll
static void setUpClass() {
service = new KnowledgeService();
}
@AfterAll
static void shutDownClass() {
service.shutdown();
}
/**
* This test makes sure that each customer's actual total sales is equal to the amount
* computed by the rule engine
*/
@ParameterizedTest
@ValueSource(strings = {"true", "false"})
void sessionTotalsTest(String type) throws IOException {
boolean stateful = Boolean.parseBoolean(type);
ClassLoader classLoader = IntroductionAJR.class.getClassLoader();
KnowledgeService service = new KnowledgeService();
Knowledge knowledge = service
.newKnowledge(
"JAVA-SOURCE",
classLoader.getResource("rules/SalesRuleset.java")
);
List<Customer> customers = Arrays.asList(
new Customer("Customer A"),
new Customer("Customer B"),
new Customer("Customer C")
);
Collection<Object> sessionData = new LinkedList<>(customers);
HashMap<Customer, Double> actualTotals = new HashMap<>();
Random random = new Random();
for (int i = 0; i < 1_000; i++) {
Customer randomCustomer = customers.get(random.nextInt(customers.size()));
Invoice invoice = new Invoice(randomCustomer, random.nextInt(100));
sessionData.add(invoice);
Double d = actualTotals.get(randomCustomer);
if(d == null) {
d = 0.0;
}
d = d + invoice.getAmount();
actualTotals.put(randomCustomer, d);
}
RuleSession<?> session = stateful ? knowledge.newStatefulSession() : knowledge.newStatelessSession();
session
.insert(sessionData)
.fire();
for(Customer c : customers) {
double d1 = c.getTotal();
double d2 = actualTotals.get(c);
assert d1 == d2;
}
}
}

View File

@ -0,0 +1,90 @@
package com.baeldung.evrete.introduction;
import com.baeldung.evrete.introduction.model.Customer;
import com.baeldung.evrete.introduction.model.Invoice;
import org.evrete.KnowledgeService;
import org.evrete.api.Knowledge;
import org.evrete.api.RuleSession;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.util.*;
class IntroductionInlineUnitTest {
private static KnowledgeService service;
@BeforeAll
static void setUpClass() {
service = new KnowledgeService();
}
@AfterAll
static void shutDownClass() {
service.shutdown();
}
/**
* This test makes sure that each customer's actual total sales is equal to the amount
* computed by the rule engine
*/
@ParameterizedTest
@ValueSource(strings = {"true", "false"})
void sessionTotalsTest(String type) {
boolean stateful = Boolean.parseBoolean(type);
Knowledge knowledge = service
.newKnowledge()
.newRule("Clear customer's total sales")
.forEach("$c", Customer.class)
.execute(ctx -> {
Customer c = ctx.get("$c");
c.setTotal(0.0);
})
.newRule("Compute totals")
.forEach(
"$c", Customer.class,
"$i", Invoice.class
)
.where("$i.customer == $c")
.execute(ctx -> {
Customer c = ctx.get("$c");
Invoice i = ctx.get("$i");
c.addToTotal(i.getAmount());
});
List<Customer> customers = Arrays.asList(
new Customer("Customer A"),
new Customer("Customer B"),
new Customer("Customer C")
);
Collection<Object> sessionData = new LinkedList<>(customers);
HashMap<Customer, Double> actualTotals = new HashMap<>();
Random random = new Random();
for (int i = 0; i < 1_000; i++) {
Customer randomCustomer = customers.get(random.nextInt(customers.size()));
Invoice invoice = new Invoice(randomCustomer, random.nextInt(100));
sessionData.add(invoice);
Double d = actualTotals.get(randomCustomer);
if(d == null) {
d = 0.0;
}
d = d + invoice.getAmount();
actualTotals.put(randomCustomer, d);
}
RuleSession<?> session = stateful ? knowledge.newStatefulSession() : knowledge.newStatelessSession();
session
.insert(sessionData)
.fire();
for(Customer c : customers) {
double d1 = c.getTotal();
double d2 = actualTotals.get(c);
assert d1 == d2;
}
}
}

View File

@ -15,6 +15,7 @@
<modules>
<module>easy-rules</module>
<module>evrete</module>
<module>openl-tablets</module>
<module>rulebook</module>
<!-- <module>jess</module> --> <!-- requires dependencies which are not publicly available -->