diff --git a/libraries/pom.xml b/libraries/pom.xml
index 9093a2db03..6be4980b93 100644
--- a/libraries/pom.xml
+++ b/libraries/pom.xml
@@ -227,11 +227,16 @@
commons-io
${commons.io.version}
+
+ commons-chain
+ commons-chain
+ ${commons-chain.version}
+
commons-dbutils
commons-dbutils
${commons.dbutils.version}
-
+
org.apache.flink
flink-core
@@ -532,6 +537,7 @@
3.5
1.1
1.9.3
+ 1.2
1.9.2
1.2
3.21.0-GA
diff --git a/libraries/src/main/java/com/baeldung/commons/chain/AbstractDenominationDispenser.java b/libraries/src/main/java/com/baeldung/commons/chain/AbstractDenominationDispenser.java
new file mode 100644
index 0000000000..cbcf03c7d4
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/commons/chain/AbstractDenominationDispenser.java
@@ -0,0 +1,23 @@
+package com.baeldung.commons.chain;
+
+import org.apache.commons.chain.Command;
+import org.apache.commons.chain.Context;
+
+import static com.baeldung.commons.chain.AtmConstants.AMOUNT_LEFT_TO_BE_WITHDRAWN;
+
+public abstract class AbstractDenominationDispenser implements Command {
+
+ @Override
+ public boolean execute(Context context) throws Exception {
+ int amountLeftToBeWithdrawn = (int) context.get(AMOUNT_LEFT_TO_BE_WITHDRAWN);
+ if (amountLeftToBeWithdrawn >= getDenominationValue()) {
+ context.put(getDenominationString(), amountLeftToBeWithdrawn / getDenominationValue());
+ context.put(AMOUNT_LEFT_TO_BE_WITHDRAWN, amountLeftToBeWithdrawn % getDenominationValue());
+ }
+ return false;
+ }
+
+ protected abstract String getDenominationString();
+
+ protected abstract int getDenominationValue();
+}
\ No newline at end of file
diff --git a/libraries/src/main/java/com/baeldung/commons/chain/AtmCatalog.java b/libraries/src/main/java/com/baeldung/commons/chain/AtmCatalog.java
new file mode 100644
index 0000000000..768517e19a
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/commons/chain/AtmCatalog.java
@@ -0,0 +1,13 @@
+package com.baeldung.commons.chain;
+
+import org.apache.commons.chain.impl.CatalogBase;
+
+import static com.baeldung.commons.chain.AtmConstants.ATM_WITHDRAWAL_CHAIN;
+
+public class AtmCatalog extends CatalogBase {
+
+ public AtmCatalog() {
+ super();
+ addCommand(ATM_WITHDRAWAL_CHAIN, new AtmWithdrawalChain());
+ }
+}
\ No newline at end of file
diff --git a/libraries/src/main/java/com/baeldung/commons/chain/AtmConstants.java b/libraries/src/main/java/com/baeldung/commons/chain/AtmConstants.java
new file mode 100644
index 0000000000..d9425fcfac
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/commons/chain/AtmConstants.java
@@ -0,0 +1,10 @@
+package com.baeldung.commons.chain;
+
+public class AtmConstants {
+ public static final String TOTAL_AMOUNT_TO_BE_WITHDRAWN = "totalAmountToBeWithdrawn";
+ public static final String AMOUNT_LEFT_TO_BE_WITHDRAWN = "amountLeftToBeWithdrawn";
+ public static final String NO_OF_HUNDREDS_DISPENSED = "noOfHundredsDispensed";
+ public static final String NO_OF_FIFTIES_DISPENSED = "noOfFiftiesDispensed";
+ public static final String NO_OF_TENS_DISPENSED = "noOfTensDispensed";
+ public static final String ATM_WITHDRAWAL_CHAIN = "atmWithdrawalChain";
+}
\ No newline at end of file
diff --git a/libraries/src/main/java/com/baeldung/commons/chain/AtmRequestContext.java b/libraries/src/main/java/com/baeldung/commons/chain/AtmRequestContext.java
new file mode 100644
index 0000000000..ee089705ad
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/commons/chain/AtmRequestContext.java
@@ -0,0 +1,52 @@
+package com.baeldung.commons.chain;
+
+import org.apache.commons.chain.impl.ContextBase;
+
+public class AtmRequestContext extends ContextBase {
+
+ int totalAmountToBeWithdrawn;
+ int noOfHundredsDispensed;
+ int noOfFiftiesDispensed;
+ int noOfTensDispensed;
+ int amountLeftToBeWithdrawn;
+
+ public int getTotalAmountToBeWithdrawn() {
+ return totalAmountToBeWithdrawn;
+ }
+
+ public void setTotalAmountToBeWithdrawn(int totalAmountToBeWithdrawn) {
+ this.totalAmountToBeWithdrawn = totalAmountToBeWithdrawn;
+ }
+
+ public int getNoOfHundredsDispensed() {
+ return noOfHundredsDispensed;
+ }
+
+ public void setNoOfHundredsDispensed(int noOfHundredsDispensed) {
+ this.noOfHundredsDispensed = noOfHundredsDispensed;
+ }
+
+ public int getNoOfFiftiesDispensed() {
+ return noOfFiftiesDispensed;
+ }
+
+ public void setNoOfFiftiesDispensed(int noOfFiftiesDispensed) {
+ this.noOfFiftiesDispensed = noOfFiftiesDispensed;
+ }
+
+ public int getNoOfTensDispensed() {
+ return noOfTensDispensed;
+ }
+
+ public void setNoOfTensDispensed(int noOfTensDispensed) {
+ this.noOfTensDispensed = noOfTensDispensed;
+ }
+
+ public int getAmountLeftToBeWithdrawn() {
+ return amountLeftToBeWithdrawn;
+ }
+
+ public void setAmountLeftToBeWithdrawn(int amountLeftToBeWithdrawn) {
+ this.amountLeftToBeWithdrawn = amountLeftToBeWithdrawn;
+ }
+}
diff --git a/libraries/src/main/java/com/baeldung/commons/chain/AtmWithdrawalChain.java b/libraries/src/main/java/com/baeldung/commons/chain/AtmWithdrawalChain.java
new file mode 100644
index 0000000000..fdea5e5744
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/commons/chain/AtmWithdrawalChain.java
@@ -0,0 +1,14 @@
+package com.baeldung.commons.chain;
+
+import org.apache.commons.chain.impl.ChainBase;
+
+public class AtmWithdrawalChain extends ChainBase {
+
+ public AtmWithdrawalChain() {
+ super();
+ addCommand(new HundredDenominationDispenser());
+ addCommand(new FiftyDenominationDispenser());
+ addCommand(new TenDenominationDispenser());
+ addCommand(new AuditFilter());
+ }
+}
\ No newline at end of file
diff --git a/libraries/src/main/java/com/baeldung/commons/chain/AuditFilter.java b/libraries/src/main/java/com/baeldung/commons/chain/AuditFilter.java
new file mode 100644
index 0000000000..973e2d498e
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/commons/chain/AuditFilter.java
@@ -0,0 +1,18 @@
+package com.baeldung.commons.chain;
+
+import org.apache.commons.chain.Context;
+import org.apache.commons.chain.Filter;
+
+public class AuditFilter implements Filter {
+
+ @Override
+ public boolean postprocess(Context context, Exception exception) {
+ // Send notification to customer & bank.
+ return false;
+ }
+
+ @Override
+ public boolean execute(Context context) throws Exception {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/libraries/src/main/java/com/baeldung/commons/chain/FiftyDenominationDispenser.java b/libraries/src/main/java/com/baeldung/commons/chain/FiftyDenominationDispenser.java
new file mode 100644
index 0000000000..f0f5959764
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/commons/chain/FiftyDenominationDispenser.java
@@ -0,0 +1,15 @@
+package com.baeldung.commons.chain;
+
+import static com.baeldung.commons.chain.AtmConstants.NO_OF_FIFTIES_DISPENSED;
+
+public class FiftyDenominationDispenser extends AbstractDenominationDispenser {
+ @Override
+ protected String getDenominationString() {
+ return NO_OF_FIFTIES_DISPENSED;
+ }
+
+ @Override
+ protected int getDenominationValue() {
+ return 50;
+ }
+}
\ No newline at end of file
diff --git a/libraries/src/main/java/com/baeldung/commons/chain/HundredDenominationDispenser.java b/libraries/src/main/java/com/baeldung/commons/chain/HundredDenominationDispenser.java
new file mode 100644
index 0000000000..e65d0d34c9
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/commons/chain/HundredDenominationDispenser.java
@@ -0,0 +1,15 @@
+package com.baeldung.commons.chain;
+
+import static com.baeldung.commons.chain.AtmConstants.NO_OF_HUNDREDS_DISPENSED;
+
+public class HundredDenominationDispenser extends AbstractDenominationDispenser {
+ @Override
+ protected String getDenominationString() {
+ return NO_OF_HUNDREDS_DISPENSED;
+ }
+
+ @Override
+ protected int getDenominationValue() {
+ return 100;
+ }
+}
\ No newline at end of file
diff --git a/libraries/src/main/java/com/baeldung/commons/chain/TenDenominationDispenser.java b/libraries/src/main/java/com/baeldung/commons/chain/TenDenominationDispenser.java
new file mode 100644
index 0000000000..423440bc4d
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/commons/chain/TenDenominationDispenser.java
@@ -0,0 +1,15 @@
+package com.baeldung.commons.chain;
+
+import static com.baeldung.commons.chain.AtmConstants.NO_OF_TENS_DISPENSED;
+
+public class TenDenominationDispenser extends AbstractDenominationDispenser {
+ @Override
+ protected String getDenominationString() {
+ return NO_OF_TENS_DISPENSED;
+ }
+
+ @Override
+ protected int getDenominationValue() {
+ return 10;
+ }
+}
\ No newline at end of file
diff --git a/libraries/src/test/java/com/baeldung/commons/chain/AtmChainTest.java b/libraries/src/test/java/com/baeldung/commons/chain/AtmChainTest.java
new file mode 100644
index 0000000000..cd9a7baaf3
--- /dev/null
+++ b/libraries/src/test/java/com/baeldung/commons/chain/AtmChainTest.java
@@ -0,0 +1,37 @@
+package com.baeldung.commons.chain;
+
+import org.apache.commons.chain.Catalog;
+import org.apache.commons.chain.Command;
+import org.apache.commons.chain.Context;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static com.baeldung.commons.chain.AtmConstants.*;
+
+public class AtmChainTest {
+
+ public static final int EXPECTED_TOTAL_AMOUNT_TO_BE_WITHDRAWN = 460;
+ public static final int EXPECTED_AMOUNT_LEFT_TO_BE_WITHDRAWN = 0;
+ public static final int EXPECTED_NO_OF_HUNDREDS_DISPENSED = 4;
+ public static final int EXPECTED_NO_OF_FIFTIES_DISPENSED = 1;
+ public static final int EXPECTED_NO_OF_TENS_DISPENSED = 1;
+
+ @Test
+ public void givenInputsToContext_whenAppliedChain_thenExpectedContext() {
+ Context context = new AtmRequestContext();
+ context.put(TOTAL_AMOUNT_TO_BE_WITHDRAWN, 460);
+ context.put(AMOUNT_LEFT_TO_BE_WITHDRAWN, 460);
+ Catalog catalog = new AtmCatalog();
+ Command atmWithdrawalChain = catalog.getCommand(ATM_WITHDRAWAL_CHAIN);
+ try {
+ atmWithdrawalChain.execute(context);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ Assert.assertEquals(EXPECTED_TOTAL_AMOUNT_TO_BE_WITHDRAWN, (int) context.get(TOTAL_AMOUNT_TO_BE_WITHDRAWN));
+ Assert.assertEquals(EXPECTED_AMOUNT_LEFT_TO_BE_WITHDRAWN, (int) context.get(AMOUNT_LEFT_TO_BE_WITHDRAWN));
+ Assert.assertEquals(EXPECTED_NO_OF_HUNDREDS_DISPENSED, (int) context.get(NO_OF_HUNDREDS_DISPENSED));
+ Assert.assertEquals(EXPECTED_NO_OF_FIFTIES_DISPENSED, (int) context.get(NO_OF_FIFTIES_DISPENSED));
+ Assert.assertEquals(EXPECTED_NO_OF_TENS_DISPENSED, (int) context.get(NO_OF_TENS_DISPENSED));
+ }
+}
\ No newline at end of file