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 20:44:01 +03:00
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"> <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> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId> <groupId>com.iluwatar</groupId>
<version>1.24.0-SNAPSHOT</version> <artifactId>java-design-patterns</artifactId>
<version>1.26.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>monitor</artifactId> <artifactId>monitor</artifactId>
<dependencies> <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; package com.iluwatar.monitor;
import java.util.Arrays; 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 { public class Bank {
private int[] accounts; private final int[] accounts;
Logger logger;
public Bank(int accountNum, int baseAmount, Logger logger) { /**
this.logger = logger; * Constructor.
accounts = new int[accountNum]; *
Arrays.fill(accounts, baseAmount); * @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) { * Transfer amounts from one account to another.
accounts[accountB] += amount; *
accounts[accountA] -= amount; * @param accountA - source account
logger.info("Transferred from account :" + accountA + " to account :" + accountB + " , amount :" + amount + " . balance :" + getBalance()); * @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; * Calculates the total balance.
for (int account : accounts) { *
balance += account; * @return 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 *The MIT License
* Copyright © 2014-2021 Ilkka Seppälä *Copyright © 2014-2021 Ilkka Seppälä
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy *Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal *of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights *in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is *copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: *furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in *The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. *all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *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 *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. *THE SOFTWARE.
*/ */
package com.iluwatar.monitor; package com.iluwatar.monitor;
import java.util.*; import java.security.SecureRandom;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; 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 * <p>Bank is a simple class that transfers money from an account to another account using {@link
* {@link Bank#transfer}. It can also return the balance of the bank account stored in the bank.</p> * 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 class Main {
public static void main(String[] args) { /**
Logger logger = Logger.getLogger("monitor"); * Runner to perform a bunch of transfers and handle exception.
var bank = new Bank(4, 1000, logger); *
Runnable runnable = () -> { * @param bank bank object
try { */
Thread.sleep((long) (Math.random() * 1000)); public static void runner(Bank bank) {
Random random = new Random(); try {
for (int i = 0; i < 1000000; i++) SecureRandom random = new SecureRandom();
bank.transfer(random.nextInt(4), random.nextInt(4), (int) (Math.random() * 1000)); Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) { for (int i = 0; i < 1000000; i++) {
logger.info(e.getMessage()); bank.transfer(random.nextInt(4), random.nextInt(4), random.nextInt());
} }
}; } catch (InterruptedException e) {
ExecutorService executorService = Executors.newFixedThreadPool(5); LOGGER.info(e.getMessage());
for (int i = 0; i < 5; i++) { Thread.currentThread().interrupt();
executorService.execute(runnable);
}
} }
} }
/**
* 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> </properties>
<modules> <modules>
<module>abstract-factory</module> <module>abstract-factory</module>
<module>monitor</module>
<module>tls</module> <module>tls</module>
<module>builder</module> <module>builder</module>
<module>factory-method</module> <module>factory-method</module>