diff --git a/docker/dockerfile-with-git/.gitmodules b/docker/dockerfile-with-git/.gitmodules new file mode 100644 index 0000000000..aa3911dfc3 --- /dev/null +++ b/docker/dockerfile-with-git/.gitmodules @@ -0,0 +1,4 @@ +[submodule "project"] + path = project + url = https://github.com/eugenp/tutorials.git + branch = master \ No newline at end of file diff --git a/docker/dockerfile-with-git/Dockerfile b/docker/dockerfile-with-git/Dockerfile new file mode 100644 index 0000000000..91dfee3bc6 --- /dev/null +++ b/docker/dockerfile-with-git/Dockerfile @@ -0,0 +1,13 @@ +ADD . /project/ +ADD /build/ /project/ +ADD /output/project.jar /project/ + +ADD ssh-private-key /root/.ssh/id_rsa +RUN git clone git@github.com:eugenp/tutorials.git + +ARG username=$GIT_USERNAME +ARG password=$GIT_PASSWORD +RUN git clone https://username:password@github.com:eugenp/tutorials.git + +VOLUME /build/ /project/ + diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application.yaml b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application.yaml new file mode 100644 index 0000000000..aeb33f797a --- /dev/null +++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application.yaml @@ -0,0 +1,14 @@ +spring: + h2: + console: + enabled: true + path: /h2-console + console.settings.trace: false + spring.h2.console.settings.web-allow-others: false + datasource: + url: jdbc:h2:mem:mydb + username: sa + password: password + driverClassName: org.h2.Driver + jpa: + spring.jpa.database-platform: org.hibernate.dialect.H2Dialect diff --git a/rule-engines/evrete/pom.xml b/rule-engines/evrete/pom.xml new file mode 100644 index 0000000000..819a912c43 --- /dev/null +++ b/rule-engines/evrete/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + com.baeldung.evrete + evrete + 1.0 + evrete + + + 2.1.04 + + + + com.baeldung + rule-engines + 1.0.0-SNAPSHOT + + + + + + org.evrete + evrete-core + ${evrete.version} + + + + org.evrete + evrete-dsl-java + ${evrete.version} + + + \ No newline at end of file diff --git a/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/IntroductionAJR.java b/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/IntroductionAJR.java new file mode 100644 index 0000000000..287d083311 --- /dev/null +++ b/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/IntroductionAJR.java @@ -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 customers = Arrays.asList( + new Customer("Customer A"), + new Customer("Customer B"), + new Customer("Customer C") + ); + + Random random = new Random(); + Collection 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(); + } +} diff --git a/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/IntroductionInline.java b/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/IntroductionInline.java new file mode 100644 index 0000000000..8867a72d23 --- /dev/null +++ b/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/IntroductionInline.java @@ -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 customers = Arrays.asList( + new Customer("Customer A"), + new Customer("Customer B"), + new Customer("Customer C") + ); + + Random random = new Random(); + Collection 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(); + } +} diff --git a/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/model/Customer.java b/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/model/Customer.java new file mode 100644 index 0000000000..9a60850d7c --- /dev/null +++ b/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/model/Customer.java @@ -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; + } +} diff --git a/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/model/Invoice.java b/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/model/Invoice.java new file mode 100644 index 0000000000..3be4fd2908 --- /dev/null +++ b/rule-engines/evrete/src/main/java/com/baeldung/evrete/introduction/model/Invoice.java @@ -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; + } +} diff --git a/rule-engines/evrete/src/main/resources/logback.xml b/rule-engines/evrete/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/rule-engines/evrete/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/rule-engines/evrete/src/main/resources/rules/SalesRuleset.java b/rule-engines/evrete/src/main/resources/rules/SalesRuleset.java new file mode 100644 index 0000000000..d36aca9c4d --- /dev/null +++ b/rule-engines/evrete/src/main/resources/rules/SalesRuleset.java @@ -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()); + } +} \ No newline at end of file diff --git a/rule-engines/evrete/src/test/java/com/baeldung/evrete/introduction/IntroductionAJRUnitTest.java b/rule-engines/evrete/src/test/java/com/baeldung/evrete/introduction/IntroductionAJRUnitTest.java new file mode 100644 index 0000000000..955dbb2fe1 --- /dev/null +++ b/rule-engines/evrete/src/test/java/com/baeldung/evrete/introduction/IntroductionAJRUnitTest.java @@ -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 customers = Arrays.asList( + new Customer("Customer A"), + new Customer("Customer B"), + new Customer("Customer C") + ); + Collection sessionData = new LinkedList<>(customers); + + HashMap 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; + } + + } +} \ No newline at end of file diff --git a/rule-engines/evrete/src/test/java/com/baeldung/evrete/introduction/IntroductionInlineUnitTest.java b/rule-engines/evrete/src/test/java/com/baeldung/evrete/introduction/IntroductionInlineUnitTest.java new file mode 100644 index 0000000000..0a6aac83bd --- /dev/null +++ b/rule-engines/evrete/src/test/java/com/baeldung/evrete/introduction/IntroductionInlineUnitTest.java @@ -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 customers = Arrays.asList( + new Customer("Customer A"), + new Customer("Customer B"), + new Customer("Customer C") + ); + Collection sessionData = new LinkedList<>(customers); + + HashMap 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; + } + } +} \ No newline at end of file diff --git a/rule-engines/pom.xml b/rule-engines/pom.xml index db6b2e47ef..6d8a014128 100644 --- a/rule-engines/pom.xml +++ b/rule-engines/pom.xml @@ -15,6 +15,7 @@ easy-rules + evrete openl-tablets rulebook diff --git a/spring-web-modules/spring-mvc-webflow/pom.xml b/spring-web-modules/spring-mvc-webflow/pom.xml index 2e150e2d01..49037e7186 100644 --- a/spring-web-modules/spring-mvc-webflow/pom.xml +++ b/spring-web-modules/spring-mvc-webflow/pom.xml @@ -10,8 +10,8 @@ com.baeldung - parent-modules - 1.0.0-SNAPSHOT + spring-web-modules + 0.0.1-SNAPSHOT diff --git a/spring-web-modules/spring-mvc-xml/pom.xml b/spring-web-modules/spring-mvc-xml/pom.xml index 354d652095..e67052e0cd 100644 --- a/spring-web-modules/spring-mvc-xml/pom.xml +++ b/spring-web-modules/spring-mvc-xml/pom.xml @@ -10,8 +10,8 @@ com.baeldung - parent-modules - 1.0.0-SNAPSHOT + spring-web-modules + 0.0.1-SNAPSHOT diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/parallel/FirstParallelUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/parallel/FirstParallelUnitTest.java new file mode 100644 index 0000000000..8ac8a161ba --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/parallel/FirstParallelUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.parallel; + +import org.junit.jupiter.api.Test; + +public class FirstParallelUnitTest { + + @Test + public void first() throws Exception{ + System.out.println("FirstParallelUnitTest first() start => " + Thread.currentThread().getName()); + Thread.sleep(500); + System.out.println("FirstParallelUnitTest first() end => " + Thread.currentThread().getName()); + } + + @Test + public void second() throws Exception{ + System.out.println("FirstParallelUnitTest second() start => " + Thread.currentThread().getName()); + Thread.sleep(500); + System.out.println("FirstParallelUnitTest second() end => " + Thread.currentThread().getName()); + } + +} diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/parallel/ParallelResourceLockUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/parallel/ParallelResourceLockUnitTest.java new file mode 100644 index 0000000000..ba607b2654 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/parallel/ParallelResourceLockUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.parallel; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.ResourceLock; + +import java.util.ArrayList; +import java.util.List; + +public class ParallelResourceLockUnitTest { + + private List resources; + + @BeforeEach + void before() { + resources = new ArrayList<>(); + resources.add("test"); + } + + @AfterEach + void after() { + resources.clear(); + } + + @Test + @ResourceLock(value = "resources") + public void first() throws Exception { + System.out.println("ParallelResourceLockUnitTest first() start => " + Thread.currentThread().getName()); + resources.add("first"); + System.out.println(resources); + Thread.sleep(500); + System.out.println("ParallelResourceLockUnitTest first() end => " + Thread.currentThread().getName()); + } + + @Test + @ResourceLock(value = "resources") + public void second() throws Exception { + System.out.println("ParallelResourceLockUnitTest second() start => " + Thread.currentThread().getName()); + resources.add("second"); + System.out.println(resources); + Thread.sleep(500); + System.out.println("ParallelResourceLockUnitTest second() end => " + Thread.currentThread().getName()); + } +} diff --git a/testing-modules/junit-5-advanced/src/test/java/com/baeldung/parallel/SecondParallelUnitTest.java b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/parallel/SecondParallelUnitTest.java new file mode 100644 index 0000000000..6a6a83fbd8 --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/java/com/baeldung/parallel/SecondParallelUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.parallel; + +import org.junit.jupiter.api.Test; + +public class SecondParallelUnitTest { + + @Test + public void first() throws Exception{ + System.out.println("SecondParallelUnitTest first() start => " + Thread.currentThread().getName()); + Thread.sleep(500); + System.out.println("SecondParallelUnitTest first() end => " + Thread.currentThread().getName()); + } + + @Test + public void second() throws Exception{ + System.out.println("SecondParallelUnitTest second() start => " + Thread.currentThread().getName()); + Thread.sleep(500); + System.out.println("SecondParallelUnitTest second() end => " + Thread.currentThread().getName()); + } + +} diff --git a/testing-modules/junit-5-advanced/src/test/resources/junit-platform.properties b/testing-modules/junit-5-advanced/src/test/resources/junit-platform.properties new file mode 100644 index 0000000000..42100f85da --- /dev/null +++ b/testing-modules/junit-5-advanced/src/test/resources/junit-platform.properties @@ -0,0 +1,4 @@ +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.config.strategy=dynamic +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = concurrent diff --git a/xstream/src/main/java/com/baeldung/initializer/SimpleXstreamInitializer.java b/xstream/src/main/java/com/baeldung/initializer/SimpleXstreamInitializer.java index c631726eb3..a391b0dca0 100644 --- a/xstream/src/main/java/com/baeldung/initializer/SimpleXstreamInitializer.java +++ b/xstream/src/main/java/com/baeldung/initializer/SimpleXstreamInitializer.java @@ -15,10 +15,18 @@ public class SimpleXstreamInitializer { } public XStream getXstreamJettisonMappedInstance() { - return new XStream(new JettisonMappedXmlDriver()); + XStream xstream = new XStream(new JettisonMappedXmlDriver()); + xstream.allowTypesByWildcard(new String[]{ + "com.baeldung.**" + }); + return xstream; } public XStream getXstreamJsonHierarchicalInstance() { - return new XStream(new JsonHierarchicalStreamDriver()); + XStream xstream = new XStream(new JsonHierarchicalStreamDriver()); + xstream.allowTypesByWildcard(new String[]{ + "com.baeldung.**" + }); + return xstream; } } \ No newline at end of file