fix: monitor pattern is not being built (#1956)

* fix: update the version in pom.xml

* fixes the checksyle error and adds javadoc

* fix: bugs and code-smells in sonarcloud

* replaced logger library with Slf4j

* fix tests and add a previously dropped method

* adds license

* fix: codesmells and bug

* replace Random with SecureRandom

* test: add tests for Main to improve coverage
This commit is contained in:
Arnab Sen
2022-04-16 23:14:01 +05:30
committed by GitHub
parent 3b87565fb6
commit b51bca1a67
7 changed files with 245 additions and 123 deletions
+2 -2
View File
@@ -21,9 +21,9 @@
<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>
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.24.0-SNAPSHOT</version>
<artifactId>java-design-patterns</artifactId>
<version>1.26.0-SNAPSHOT</version>
</parent>
<artifactId>monitor</artifactId>
<dependencies>
@@ -1,37 +1,87 @@
/*
*The MIT License
*Copyright © 2014-2021 Ilkka Seppälä
*
*Permission is hereby granted, free of charge, to any person obtaining a copy
*of this software and associated documentation files (the "Software"), to deal
*in the Software without restriction, including without limitation the rights
*to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*copies of the Software, and to permit persons to whom the Software is
*furnished to do so, subject to the following conditions:
*
*The above copyright notice and this permission notice shall be included in
*all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*THE SOFTWARE.
*/
package com.iluwatar.monitor;
import java.util.Arrays;
import java.util.logging.Logger;
import lombok.extern.slf4j.Slf4j;
// Bank class implements the Monitor pattern
/** Bank Definition. */
@Slf4j
public class Bank {
private int[] accounts;
Logger logger;
private final int[] accounts;
public Bank(int accountNum, int baseAmount, Logger logger) {
this.logger = logger;
accounts = new int[accountNum];
Arrays.fill(accounts, baseAmount);
}
/**
* Constructor.
*
* @param accountNum - account number
* @param baseAmount - base amount
*/
public Bank(int accountNum, int baseAmount) {
accounts = new int[accountNum];
Arrays.fill(accounts, baseAmount);
}
public synchronized void transfer(int accountA, int accountB, int amount) {
if (accounts[accountA] >= amount) {
accounts[accountB] += amount;
accounts[accountA] -= amount;
logger.info("Transferred from account :" + accountA + " to account :" + accountB + " , amount :" + amount + " . balance :" + getBalance());
}
/**
* Transfer amounts from one account to another.
*
* @param accountA - source account
* @param accountB - destination account
* @param amount - amount to be transferred
*/
public synchronized void transfer(int accountA, int accountB, int amount) {
if (accounts[accountA] >= amount) {
accounts[accountB] += amount;
accounts[accountA] -= amount;
LOGGER.info(
"Transferred from account: {} to account: {} , amount: {} , balance: {}",
accountA,
accountB,
amount,
getBalance());
}
}
public synchronized int getBalance() {
int balance = 0;
for (int account : accounts) {
balance += account;
}
return balance;
/**
* Calculates the total balance.
*
* @return balance
*/
public synchronized int getBalance() {
int balance = 0;
for (int account : accounts) {
balance += account;
}
return balance;
}
public int[] getAccounts() {
return accounts;
}
/**
* Get all accounts.
*
* @return accounts
*/
public int[] getAccounts() {
return accounts;
}
}
@@ -1,60 +1,73 @@
/*
* The MIT License
* Copyright © 2014-2021 Ilkka Seppälä
*The MIT License
*Copyright © 2014-2021 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*Permission is hereby granted, free of charge, to any person obtaining a copy
*of this software and associated documentation files (the "Software"), to deal
*in the Software without restriction, including without limitation the rights
*to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*copies of the Software, and to permit persons to whom the Software is
*furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*The above copyright notice and this permission notice shall be included in
*all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*THE SOFTWARE.
*/
package com.iluwatar.monitor;
import java.util.*;
import java.security.SecureRandom;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
import lombok.extern.slf4j.Slf4j;
/**
* <p>The Monitor pattern is used in concurrent algorithms to achieve mutual exclusion.</p>
* The Monitor pattern is used in concurrent algorithms to achieve mutual exclusion.
*
* <p>Bank is a simple class that transfers money from an account to another account using
* {@link Bank#transfer}. It can also return the balance of the bank account stored in the bank.</p>
* <p>Bank is a simple class that transfers money from an account to another account using {@link
* Bank#transfer}. It can also return the balance of the bank account stored in the bank.
*
* <p>Main class uses ThreadPool to run threads that do transactions on the bank accounts.</p>
* <p>Main class uses ThreadPool to run threads that do transactions on the bank accounts.
*/
@Slf4j
public class Main {
public static void main(String[] args) {
Logger logger = Logger.getLogger("monitor");
var bank = new Bank(4, 1000, logger);
Runnable runnable = () -> {
try {
Thread.sleep((long) (Math.random() * 1000));
Random random = new Random();
for (int i = 0; i < 1000000; i++)
bank.transfer(random.nextInt(4), random.nextInt(4), (int) (Math.random() * 1000));
} catch (InterruptedException e) {
logger.info(e.getMessage());
}
};
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
executorService.execute(runnable);
}
/**
* Runner to perform a bunch of transfers and handle exception.
*
* @param bank bank object
*/
public static void runner(Bank bank) {
try {
SecureRandom random = new SecureRandom();
Thread.sleep(random.nextInt(1000));
for (int i = 0; i < 1000000; i++) {
bank.transfer(random.nextInt(4), random.nextInt(4), random.nextInt());
}
} catch (InterruptedException e) {
LOGGER.info(e.getMessage());
Thread.currentThread().interrupt();
}
}
}
/**
* Program entry point.
*
* @param args command line args
*/
public static void main(String[] args) {
var bank = new Bank(4, 1000);
Runnable runnable = () -> runner(bank);
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
executorService.execute(runnable);
}
}
}
@@ -1,55 +0,0 @@
package com.iluwater.java;
import com.iluwatar.monitor.Bank;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.*;
import java.util.logging.Logger;
public class BankTest {
private static Bank bank;
private static final int ACCOUNT_NUM = 4;
private static final int BASE_AMOUNT = 1000;
private static final Logger LOGGER = Logger.getLogger("monitor");
@BeforeAll
public static void Setup() {
bank = new Bank(ACCOUNT_NUM, BASE_AMOUNT, LOGGER);
}
@Test
public void GetAccountHaveNotBeNull() {
assertNotNull(bank.getAccounts());
}
@Test
public void LengthOfAccountsHaveToEqualsToAccountNumConstant() {
assumeTrue(bank.getAccounts() != null);
assertEquals(ACCOUNT_NUM, bank.getAccounts().length);
}
@Test
public void TransferMethodHaveToTransferAmountFromAnAccountToOtherAccount() {
bank.transfer(0, 1, 1000);
int accounts[] = bank.getAccounts();
assertEquals(0, accounts[0]);
assertEquals(2000, 2000);
}
@Test
public void BalanceHaveToBeOK() {
assertEquals(4000, bank.getBalance());
}
@AfterAll
public static void TearDown() {
bank = null;
}
}
@@ -0,0 +1,71 @@
/*
*The MIT License
*Copyright © 2014-2021 Ilkka Seppälä
*
*Permission is hereby granted, free of charge, to any person obtaining a copy
*of this software and associated documentation files (the "Software"), to deal
*in the Software without restriction, including without limitation the rights
*to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*copies of the Software, and to permit persons to whom the Software is
*furnished to do so, subject to the following conditions:
*
*The above copyright notice and this permission notice shall be included in
*all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*THE SOFTWARE.
*/
package com.iluwatar.monitor;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.*;
public class BankTest {
private static final int ACCOUNT_NUM = 4;
private static final int BASE_AMOUNT = 1000;
private static Bank bank;
@BeforeAll
public static void Setup() {
bank = new Bank(ACCOUNT_NUM, BASE_AMOUNT);
}
@AfterAll
public static void TearDown() {
bank = null;
}
@Test
void GetAccountHaveNotBeNull() {
assertNotNull(bank.getAccounts());
}
@Test
void LengthOfAccountsHaveToEqualsToAccountNumConstant() {
assumeTrue(bank.getAccounts() != null);
assertEquals(ACCOUNT_NUM, bank.getAccounts().length);
}
@Test
void TransferMethodHaveToTransferAmountFromAnAccountToOtherAccount() {
bank.transfer(0, 1, 1000);
int[] accounts = bank.getAccounts();
assertEquals(0, accounts[0]);
assertEquals(2000, accounts[1]);
}
@Test
void BalanceHaveToBeOK() {
assertEquals(4000, bank.getBalance());
}
}
@@ -0,0 +1,42 @@
/*
*The MIT License
*Copyright © 2014-2021 Ilkka Seppälä
*
*Permission is hereby granted, free of charge, to any person obtaining a copy
*of this software and associated documentation files (the "Software"), to deal
*in the Software without restriction, including without limitation the rights
*to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*copies of the Software, and to permit persons to whom the Software is
*furnished to do so, subject to the following conditions:
*
*The above copyright notice and this permission notice shall be included in
*all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*THE SOFTWARE.
*/
package com.iluwatar.monitor;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/** Test if the application starts without throwing an exception. */
class MainTest {
@Test
void shouldExecuteApplicationWithoutException() {
assertDoesNotThrow(() -> Main.main(new String[] {}));
}
@Test
void RunnerExecuteWithoutException() {
var bank = new Bank(4, 1000);
assertDoesNotThrow(() -> Main.runner(bank));
}
}
+1
View File
@@ -85,6 +85,7 @@
</properties>
<modules>
<module>abstract-factory</module>
<module>monitor</module>
<module>tls</module>
<module>builder</module>
<module>factory-method</module>