diff --git a/.all-contributorsrc b/.all-contributorsrc index 656110aae..5a91ce748 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1586,6 +1586,51 @@ "contributions": [ "code" ] + }, + { + "login": "tan31989", + "name": "Nagaraj Tantri", + "avatar_url": "https://avatars.githubusercontent.com/u/3784194?v=4", + "profile": "https://stackoverflow.com/users/308565/nagaraj-tantri", + "contributions": [ + "code" + ] + }, + { + "login": "frascu", + "name": "Francesco Scuccimarri", + "avatar_url": "https://avatars.githubusercontent.com/u/7107651?v=4", + "profile": "http://scuccimarri.it", + "contributions": [ + "code" + ] + }, + { + "login": "Conhan93", + "name": "Conny Hansson", + "avatar_url": "https://avatars.githubusercontent.com/u/71334757?v=4", + "profile": "https://github.com/Conhan93", + "contributions": [ + "doc" + ] + }, + { + "login": "muklasr", + "name": "Muklas Rahmanto", + "avatar_url": "https://avatars.githubusercontent.com/u/43443753?v=4", + "profile": "http://muklasr.medium.com", + "contributions": [ + "translation" + ] + }, + { + "login": "VxDxK", + "name": "Vadim", + "avatar_url": "https://avatars.githubusercontent.com/u/38704817?v=4", + "profile": "https://github.com/VxDxK", + "contributions": [ + "translation" + ] } ], "contributorsPerLine": 4, diff --git a/README.md b/README.md index 1218e739b..a87c3d87c 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,12 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-174-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-179-orange.svg?style=flat-square)](#contributors-)
-Read in different language : [**zh**](localization/zh/README.md), [**ko**](localization/ko/README.md), [**fr**](localization/fr/README.md), [**tr**](localization/tr/README.md), [**ar**](localization/ar/README.md), [**es**](localization/es/README.md), [**pt**](localization/pt/README.md) +Read in different language : [**zh**](localization/zh/README.md), [**ko**](localization/ko/README.md), [**fr**](localization/fr/README.md), [**tr**](localization/tr/README.md), [**ar**](localization/ar/README.md), [**es**](localization/es/README.md), [**pt**](localization/pt/README.md), [**id**](localization/id/README.md), [**ru**](localization/ru/README.md)
@@ -336,6 +336,13 @@ This project is licensed under the terms of the MIT license.
karthikbhat13

πŸ’»
Morteza Adigozalpour

πŸ’» +
Nagaraj Tantri

πŸ’» +
Francesco Scuccimarri

πŸ’» + + +
Conny Hansson

πŸ“– +
Muklas Rahmanto

🌍 +
Vadim

🌍 diff --git a/active-object/README.md b/active-object/README.md index f339586fe..a505f1bda 100644 --- a/active-object/README.md +++ b/active-object/README.md @@ -8,7 +8,7 @@ tags: ## Intent -The active object design pattern decouples method execution from method invocation for objects that each reside in their thread of control. The goal is to introduce concurrency, by using asynchronous method invocation and a scheduler for handling requests. +The active object design pattern decouples method execution from method invocation for objects that each reside in their thread of control. The goal is to introduce concurrency, by using asynchronous method invocation, and a scheduler for handling requests. ## Explanation @@ -67,7 +67,7 @@ public abstract class ActiveCreature{ requests.put(new Runnable() { @Override public void run() { - logger.info("{} has started to roam and the wastelands.",name()); + logger.info("{} has started to roam the wastelands.",name()); } } ); @@ -79,7 +79,7 @@ public abstract class ActiveCreature{ } ``` -We can see that any class that will extend the ActiveCreature class will have its own thread of control to execute and invocate methods. +We can see that any class that will extend the ActiveCreature class will have its own thread of control to invoke and execute methods. For example, the Orc class: @@ -93,7 +93,7 @@ public class Orc extends ActiveCreature { } ``` -Now, we can create multiple creatures such as Orcs, tell them to eat and roam and they will execute it on their own thread of control: +Now, we can create multiple creatures such as Orcs, tell them to eat and roam, and they will execute it on their own thread of control: ```java public static void main(String[] args) { diff --git a/active-object/src/main/java/com/iluwatar/activeobject/ActiveCreature.java b/active-object/src/main/java/com/iluwatar/activeobject/ActiveCreature.java index 479dc0643..9be60505d 100644 --- a/active-object/src/main/java/com/iluwatar/activeobject/ActiveCreature.java +++ b/active-object/src/main/java/com/iluwatar/activeobject/ActiveCreature.java @@ -82,7 +82,7 @@ public abstract class ActiveCreature { } /** - * Roam in the wastelands. + * Roam the wastelands. * @throws InterruptedException due to firing a new Runnable. */ public void roam() throws InterruptedException { diff --git a/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java b/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java index 2ffa9cd42..fa229832b 100644 --- a/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java +++ b/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java @@ -48,7 +48,7 @@ class AggregatorTest { @BeforeEach public void setup() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); } /** diff --git a/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java b/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java index 94e76583e..2f71ee4f4 100644 --- a/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java +++ b/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java @@ -48,7 +48,7 @@ class ApiGatewayTest { @BeforeEach public void setup() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); } /** diff --git a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java index b644e0e23..495cb6b6e 100644 --- a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java +++ b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java @@ -68,7 +68,7 @@ class ThreadAsyncExecutorTest { @BeforeEach void setUp() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); } /** diff --git a/caching/README.md b/caching/README.md index c34bdecf5..e7b472a5f 100644 --- a/caching/README.md +++ b/caching/README.md @@ -40,39 +40,29 @@ Wikipedia says: **Programmatic Example** Let's first look at the data layer of our application. The interesting classes are `UserAccount` -which is a simple Java object containing the user account details, and `DbManager` which handles -reading and writing of these objects to/from MongoDB database. +which is a simple Java object containing the user account details, and `DbManager` interface which handles +reading and writing of these objects to/from database. ```java -@Setter -@Getter +@Data @AllArgsConstructor @ToString +@EqualsAndHashCode public class UserAccount { private String userId; private String userName; private String additionalInfo; } -@Slf4j -public final class DbManager { +public interface DbManager { - private static MongoClient mongoClient; - private static MongoDatabase db; - - private DbManager() { /*...*/ } - - public static void createVirtualDb() { /*...*/ } - - public static void connect() throws ParseException { /*...*/ } - - public static UserAccount readFromDb(String userId) { /*...*/ } - - public static void writeToDb(UserAccount userAccount) { /*...*/ } - - public static void updateDb(UserAccount userAccount) { /*...*/ } - - public static void upsertDb(UserAccount userAccount) { /*...*/ } + void connect(); + void disconnect(); + + UserAccount readFromDb(String userId); + UserAccount writeToDb(UserAccount userAccount); + UserAccount updateDb(UserAccount userAccount); + UserAccount upsertDb(UserAccount userAccount); } ``` @@ -168,30 +158,43 @@ strategies. @Slf4j public class CacheStore { + private static final int CAPACITY = 3; private static LruCache cache; + private final DbManager dbManager; /* ... details omitted ... */ - public static UserAccount readThrough(String userId) { + public UserAccount readThrough(final String userId) { if (cache.contains(userId)) { - LOGGER.info("# Cache Hit!"); + LOGGER.info("# Found in Cache!"); return cache.get(userId); } - LOGGER.info("# Cache Miss!"); - UserAccount userAccount = DbManager.readFromDb(userId); + LOGGER.info("# Not found in cache! Go to DB!!"); + UserAccount userAccount = dbManager.readFromDb(userId); cache.set(userId, userAccount); return userAccount; } - public static void writeThrough(UserAccount userAccount) { + public void writeThrough(final UserAccount userAccount) { if (cache.contains(userAccount.getUserId())) { - DbManager.updateDb(userAccount); + dbManager.updateDb(userAccount); } else { - DbManager.writeToDb(userAccount); + dbManager.writeToDb(userAccount); } cache.set(userAccount.getUserId(), userAccount); } + public void writeAround(final UserAccount userAccount) { + if (cache.contains(userAccount.getUserId())) { + dbManager.updateDb(userAccount); + // Cache data has been updated -- remove older + cache.invalidate(userAccount.getUserId()); + // version from cache. + } else { + dbManager.writeToDb(userAccount); + } + } + public static void clearCache() { if (cache != null) { cache.clear(); @@ -222,34 +225,39 @@ class. public final class AppManager { private static CachingPolicy cachingPolicy; + private final DbManager dbManager; + private final CacheStore cacheStore; private AppManager() { } - public static void initDb(boolean useMongoDb) { /* ... */ } + public void initDb() { /* ... */ } public static void initCachingPolicy(CachingPolicy policy) { /* ... */ } public static void initCacheCapacity(int capacity) { /* ... */ } - public static UserAccount find(String userId) { - if (cachingPolicy == CachingPolicy.THROUGH || cachingPolicy == CachingPolicy.AROUND) { - return CacheStore.readThrough(userId); + public UserAccount find(final String userId) { + LOGGER.info("Trying to find {} in cache", userId); + if (cachingPolicy == CachingPolicy.THROUGH + || cachingPolicy == CachingPolicy.AROUND) { + return cacheStore.readThrough(userId); } else if (cachingPolicy == CachingPolicy.BEHIND) { - return CacheStore.readThroughWithWriteBackPolicy(userId); + return cacheStore.readThroughWithWriteBackPolicy(userId); } else if (cachingPolicy == CachingPolicy.ASIDE) { return findAside(userId); } return null; } - public static void save(UserAccount userAccount) { + public void save(final UserAccount userAccount) { + LOGGER.info("Save record!"); if (cachingPolicy == CachingPolicy.THROUGH) { - CacheStore.writeThrough(userAccount); + cacheStore.writeThrough(userAccount); } else if (cachingPolicy == CachingPolicy.AROUND) { - CacheStore.writeAround(userAccount); + cacheStore.writeAround(userAccount); } else if (cachingPolicy == CachingPolicy.BEHIND) { - CacheStore.writeBehind(userAccount); + cacheStore.writeBehind(userAccount); } else if (cachingPolicy == CachingPolicy.ASIDE) { saveAside(userAccount); } @@ -269,24 +277,35 @@ Here is what we do in the main class of the application. @Slf4j public class App { - public static void main(String[] args) { - AppManager.initDb(false); - AppManager.initCacheCapacity(3); - var app = new App(); + public static void main(final String[] args) { + boolean isDbMongo = isDbMongo(args); + if(isDbMongo){ + LOGGER.info("Using the Mongo database engine to run the application."); + } else { + LOGGER.info("Using the 'in Memory' database to run the application."); + } + App app = new App(isDbMongo); app.useReadAndWriteThroughStrategy(); + String splitLine = "=============================================="; + LOGGER.info(splitLine); app.useReadThroughAndWriteAroundStrategy(); + LOGGER.info(splitLine); app.useReadThroughAndWriteBehindStrategy(); + LOGGER.info(splitLine); app.useCacheAsideStategy(); + LOGGER.info(splitLine); } public void useReadAndWriteThroughStrategy() { LOGGER.info("# CachingPolicy.THROUGH"); - AppManager.initCachingPolicy(CachingPolicy.THROUGH); + appManager.initCachingPolicy(CachingPolicy.THROUGH); + var userAccount1 = new UserAccount("001", "John", "He is a boy."); - AppManager.save(userAccount1); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("001"); - AppManager.find("001"); + + appManager.save(userAccount1); + LOGGER.info(appManager.printCacheContent()); + appManager.find("001"); + appManager.find("001"); } public void useReadThroughAndWriteAroundStrategy() { /* ... */ } @@ -297,16 +316,6 @@ public class App { } ``` -Finally, here is some of the console output from the program. - -``` -12:32:53.845 [main] INFO com.iluwatar.caching.App - # CachingPolicy.THROUGH -12:32:53.900 [main] INFO com.iluwatar.caching.App - ---CACHE CONTENT-- -UserAccount(userId=001, userName=John, additionalInfo=He is a boy.) ----- -``` - ## Class diagram ![alt text](./etc/caching.png "Caching") diff --git a/caching/docker-compose.yml b/caching/docker-compose.yml new file mode 100644 index 000000000..6b6494690 --- /dev/null +++ b/caching/docker-compose.yml @@ -0,0 +1,11 @@ +version: '3.7' +services: + mongodb_container: + image: mongo:latest + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: rootpassword + ports: + - 27017:27017 + volumes: + - ./mongo-data/:/data/db \ No newline at end of file diff --git a/caching/etc/caching.png b/caching/etc/caching.png deleted file mode 100644 index b6ed703ab..000000000 Binary files a/caching/etc/caching.png and /dev/null differ diff --git a/caching/pom.xml b/caching/pom.xml index 0491bb4e1..e56da709f 100644 --- a/caching/pom.xml +++ b/caching/pom.xml @@ -39,19 +39,21 @@ test - org.mongodb - mongodb-driver - 3.12.1 + org.mockito + mockito-junit-jupiter + 3.12.4 + test + + + org.mockito + mockito-all + 1.10.19 + test org.mongodb - mongodb-driver-core - 3.0.4 - - - org.mongodb - bson - 3.0.4 + mongo-java-driver + 3.4.1 AppManager --> CacheStore/LRUCache/CachingPolicy --> DBManager} + * {@literal App --> AppManager --> CacheStore/LRUCache/CachingPolicy --> + * DBManager} + *

+ * + *

+ * There are 2 ways to launch the application. + * - to use "in Memory" database. + * - to use the MongoDb as a database + * + * To run the application with "in Memory" database, just launch it without parameters + * Example: 'java -jar app.jar' + * + * To run the application with MongoDb you need to be installed the MongoDb + * in your system, or to launch it in the docker container. + * You may launch docker container from the root of current module with command: + * 'docker-compose up' + * Then you can start the application with parameter --mongo + * Example: 'java -jar app.jar --mongo' *

* * @see CacheStore @@ -61,23 +65,67 @@ import lombok.extern.slf4j.Slf4j; */ @Slf4j public class App { + /** + * Constant parameter name to use mongoDB. + */ + private static final String USE_MONGO_DB = "--mongo"; + /** + * Application manager. + */ + private final AppManager appManager; + + /** + * Constructor of current App. + * + * @param isMongo boolean + */ + public App(final boolean isMongo) { + DbManager dbManager = DbManagerFactory.initDb(isMongo); + appManager = new AppManager(dbManager); + appManager.initDb(); + } /** * Program entry point. * * @param args command line args */ - public static void main(String[] args) { - AppManager.initDb(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests + public static void main(final String[] args) { + // VirtualDB (instead of MongoDB) was used in running the JUnit tests // and the App class to avoid Maven compilation errors. Set flag to // true to run the tests with MongoDB (provided that MongoDB is // installed and socket connection is open). - AppManager.initCacheCapacity(3); - var app = new App(); + boolean isDbMongo = isDbMongo(args); + if (isDbMongo) { + LOGGER.info("Using the Mongo database engine to run the application."); + } else { + LOGGER.info("Using the 'in Memory' database to run the application."); + } + App app = new App(isDbMongo); app.useReadAndWriteThroughStrategy(); + String splitLine = "=============================================="; + LOGGER.info(splitLine); app.useReadThroughAndWriteAroundStrategy(); + LOGGER.info(splitLine); app.useReadThroughAndWriteBehindStrategy(); + LOGGER.info(splitLine); app.useCacheAsideStategy(); + LOGGER.info(splitLine); + } + + /** + * Check the input parameters. if + * + * @param args input params + * @return true if there is "--mongo" parameter in arguments + */ + private static boolean isDbMongo(final String[] args) { + for (String arg : args) { + if (arg.equals(USE_MONGO_DB)) { + return true; + } + } + return false; } /** @@ -85,14 +133,14 @@ public class App { */ public void useReadAndWriteThroughStrategy() { LOGGER.info("# CachingPolicy.THROUGH"); - AppManager.initCachingPolicy(CachingPolicy.THROUGH); + appManager.initCachingPolicy(CachingPolicy.THROUGH); var userAccount1 = new UserAccount("001", "John", "He is a boy."); - AppManager.save(userAccount1); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("001"); - AppManager.find("001"); + appManager.save(userAccount1); + LOGGER.info(appManager.printCacheContent()); + appManager.find("001"); + appManager.find("001"); } /** @@ -100,21 +148,21 @@ public class App { */ public void useReadThroughAndWriteAroundStrategy() { LOGGER.info("# CachingPolicy.AROUND"); - AppManager.initCachingPolicy(CachingPolicy.AROUND); + appManager.initCachingPolicy(CachingPolicy.AROUND); var userAccount2 = new UserAccount("002", "Jane", "She is a girl."); - AppManager.save(userAccount2); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("002"); - LOGGER.info(AppManager.printCacheContent()); - userAccount2 = AppManager.find("002"); + appManager.save(userAccount2); + LOGGER.info(appManager.printCacheContent()); + appManager.find("002"); + LOGGER.info(appManager.printCacheContent()); + userAccount2 = appManager.find("002"); userAccount2.setUserName("Jane G."); - AppManager.save(userAccount2); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("002"); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("002"); + appManager.save(userAccount2); + LOGGER.info(appManager.printCacheContent()); + appManager.find("002"); + LOGGER.info(appManager.printCacheContent()); + appManager.find("002"); } /** @@ -122,23 +170,31 @@ public class App { */ public void useReadThroughAndWriteBehindStrategy() { LOGGER.info("# CachingPolicy.BEHIND"); - AppManager.initCachingPolicy(CachingPolicy.BEHIND); + appManager.initCachingPolicy(CachingPolicy.BEHIND); - var userAccount3 = new UserAccount("003", "Adam", "He likes food."); - var userAccount4 = new UserAccount("004", "Rita", "She hates cats."); - var userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard."); + var userAccount3 = new UserAccount("003", + "Adam", + "He likes food."); + var userAccount4 = new UserAccount("004", + "Rita", + "She hates cats."); + var userAccount5 = new UserAccount("005", + "Isaac", + "He is allergic to mustard."); - AppManager.save(userAccount3); - AppManager.save(userAccount4); - AppManager.save(userAccount5); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("003"); - LOGGER.info(AppManager.printCacheContent()); - UserAccount userAccount6 = new UserAccount("006", "Yasha", "She is an only child."); - AppManager.save(userAccount6); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("004"); - LOGGER.info(AppManager.printCacheContent()); + appManager.save(userAccount3); + appManager.save(userAccount4); + appManager.save(userAccount5); + LOGGER.info(appManager.printCacheContent()); + appManager.find("003"); + LOGGER.info(appManager.printCacheContent()); + UserAccount userAccount6 = new UserAccount("006", + "Yasha", + "She is an only child."); + appManager.save(userAccount6); + LOGGER.info(appManager.printCacheContent()); + appManager.find("004"); + LOGGER.info(appManager.printCacheContent()); } /** @@ -146,20 +202,26 @@ public class App { */ public void useCacheAsideStategy() { LOGGER.info("# CachingPolicy.ASIDE"); - AppManager.initCachingPolicy(CachingPolicy.ASIDE); - LOGGER.info(AppManager.printCacheContent()); + appManager.initCachingPolicy(CachingPolicy.ASIDE); + LOGGER.info(appManager.printCacheContent()); - var userAccount3 = new UserAccount("003", "Adam", "He likes food."); - var userAccount4 = new UserAccount("004", "Rita", "She hates cats."); - var userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard."); - AppManager.save(userAccount3); - AppManager.save(userAccount4); - AppManager.save(userAccount5); + var userAccount3 = new UserAccount("003", + "Adam", + "He likes food."); + var userAccount4 = new UserAccount("004", + "Rita", + "She hates cats."); + var userAccount5 = new UserAccount("005", + "Isaac", + "He is allergic to mustard."); + appManager.save(userAccount3); + appManager.save(userAccount4); + appManager.save(userAccount5); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("003"); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("004"); - LOGGER.info(AppManager.printCacheContent()); + LOGGER.info(appManager.printCacheContent()); + appManager.find("003"); + LOGGER.info(appManager.printCacheContent()); + appManager.find("004"); + LOGGER.info(appManager.printCacheContent()); } } diff --git a/caching/src/main/java/com/iluwatar/caching/AppManager.java b/caching/src/main/java/com/iluwatar/caching/AppManager.java index 68c8a0d36..53489c83b 100644 --- a/caching/src/main/java/com/iluwatar/caching/AppManager.java +++ b/caching/src/main/java/com/iluwatar/caching/AppManager.java @@ -23,65 +23,80 @@ package com.iluwatar.caching; -import java.text.ParseException; +import com.iluwatar.caching.database.DbManager; + import java.util.Optional; + import lombok.extern.slf4j.Slf4j; /** - * AppManager helps to bridge the gap in communication between the main class and the application's - * back-end. DB connection is initialized through this class. The chosen caching strategy/policy is - * also initialized here. Before the cache can be used, the size of the cache has to be set. - * Depending on the chosen caching policy, AppManager will call the appropriate function in the - * CacheStore class. + * AppManager helps to bridge the gap in communication between the main class + * and the application's back-end. DB connection is initialized through this + * class. The chosen caching strategy/policy is also initialized here. + * Before the cache can be used, the size of the cache has to be set. + * Depending on the chosen caching policy, AppManager will call the + * appropriate function in the CacheStore class. */ @Slf4j -public final class AppManager { +public class AppManager { + /** + * Caching Policy. + */ + private CachingPolicy cachingPolicy; + /** + * Database Manager. + */ + private final DbManager dbManager; + /** + * Cache Store. + */ + private final CacheStore cacheStore; - private static CachingPolicy cachingPolicy; - - private AppManager() { + /** + * Constructor. + * + * @param newDbManager database manager + */ + public AppManager(final DbManager newDbManager) { + this.dbManager = newDbManager; + this.cacheStore = new CacheStore(newDbManager); } /** - * Developer/Tester is able to choose whether the application should use MongoDB as its underlying - * data storage or a simple Java data structure to (temporarily) store the data/objects during - * runtime. + * Developer/Tester is able to choose whether the application should use + * MongoDB as its underlying data storage or a simple Java data structure + * to (temporarily) store the data/objects during runtime. */ - public static void initDb(boolean useMongoDb) { - if (useMongoDb) { - try { - DbManager.connect(); - } catch (ParseException e) { - LOGGER.error("Error connecting to MongoDB", e); - } - } else { - DbManager.createVirtualDb(); - } + public void initDb() { + dbManager.connect(); } /** * Initialize caching policy. + * + * @param policy is a {@link CachingPolicy} */ - public static void initCachingPolicy(CachingPolicy policy) { + public void initCachingPolicy(final CachingPolicy policy) { cachingPolicy = policy; if (cachingPolicy == CachingPolicy.BEHIND) { - Runtime.getRuntime().addShutdownHook(new Thread(CacheStore::flushCache)); + Runtime.getRuntime().addShutdownHook(new Thread(cacheStore::flushCache)); } - CacheStore.clearCache(); - } - - public static void initCacheCapacity(int capacity) { - CacheStore.initCapacity(capacity); + cacheStore.clearCache(); } /** * Find user account. + * + * @param userId String + * @return {@link UserAccount} */ - public static UserAccount find(String userId) { - if (cachingPolicy == CachingPolicy.THROUGH || cachingPolicy == CachingPolicy.AROUND) { - return CacheStore.readThrough(userId); + public UserAccount find(final String userId) { + LOGGER.info("Trying to find {} in cache", userId); + if (cachingPolicy == CachingPolicy.THROUGH + || cachingPolicy == CachingPolicy.AROUND) { + return cacheStore.readThrough(userId); } else if (cachingPolicy == CachingPolicy.BEHIND) { - return CacheStore.readThroughWithWriteBackPolicy(userId); + return cacheStore.readThroughWithWriteBackPolicy(userId); } else if (cachingPolicy == CachingPolicy.ASIDE) { return findAside(userId); } @@ -90,41 +105,55 @@ public final class AppManager { /** * Save user account. + * + * @param userAccount {@link UserAccount} */ - public static void save(UserAccount userAccount) { + public void save(final UserAccount userAccount) { + LOGGER.info("Save record!"); if (cachingPolicy == CachingPolicy.THROUGH) { - CacheStore.writeThrough(userAccount); + cacheStore.writeThrough(userAccount); } else if (cachingPolicy == CachingPolicy.AROUND) { - CacheStore.writeAround(userAccount); + cacheStore.writeAround(userAccount); } else if (cachingPolicy == CachingPolicy.BEHIND) { - CacheStore.writeBehind(userAccount); + cacheStore.writeBehind(userAccount); } else if (cachingPolicy == CachingPolicy.ASIDE) { saveAside(userAccount); } } - public static String printCacheContent() { - return CacheStore.print(); + /** + * Returns String. + * + * @return String + */ + public String printCacheContent() { + return cacheStore.print(); } /** * Cache-Aside save user account helper. + * + * @param userAccount {@link UserAccount} */ - private static void saveAside(UserAccount userAccount) { - DbManager.updateDb(userAccount); - CacheStore.invalidate(userAccount.getUserId()); + private void saveAside(final UserAccount userAccount) { + dbManager.updateDb(userAccount); + cacheStore.invalidate(userAccount.getUserId()); } /** * Cache-Aside find user account helper. + * + * @param userId String + * @return {@link UserAccount} */ - private static UserAccount findAside(String userId) { - return Optional.ofNullable(CacheStore.get(userId)) - .or(() -> { - Optional userAccount = Optional.ofNullable(DbManager.readFromDb(userId)); - userAccount.ifPresent(account -> CacheStore.set(userId, account)); - return userAccount; - }) - .orElse(null); + private UserAccount findAside(final String userId) { + return Optional.ofNullable(cacheStore.get(userId)) + .or(() -> { + Optional userAccount = + Optional.ofNullable(dbManager.readFromDb(userId)); + userAccount.ifPresent(account -> cacheStore.set(userId, account)); + return userAccount; + }) + .orElse(null); } } diff --git a/caching/src/main/java/com/iluwatar/caching/CacheStore.java b/caching/src/main/java/com/iluwatar/caching/CacheStore.java index 156f024d4..3d59d73de 100644 --- a/caching/src/main/java/com/iluwatar/caching/CacheStore.java +++ b/caching/src/main/java/com/iluwatar/caching/CacheStore.java @@ -23,9 +23,11 @@ package com.iluwatar.caching; +import com.iluwatar.caching.database.DbManager; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; /** @@ -33,16 +35,34 @@ import lombok.extern.slf4j.Slf4j; */ @Slf4j public class CacheStore { + /** + * Cache capacity. + */ + private static final int CAPACITY = 3; - private static LruCache cache; + /** + * Lru cache see {@link LruCache}. + */ + private LruCache cache; + /** + * DbManager. + */ + private final DbManager dbManager; - private CacheStore() { + /** + * Cache Store. + * @param dataBaseManager {@link DbManager} + */ + public CacheStore(final DbManager dataBaseManager) { + this.dbManager = dataBaseManager; + initCapacity(CAPACITY); } /** * Init cache capacity. + * @param capacity int */ - public static void initCapacity(int capacity) { + public void initCapacity(final int capacity) { if (cache == null) { cache = new LruCache(capacity); } else { @@ -52,57 +72,64 @@ public class CacheStore { /** * Get user account using read-through cache. + * @param userId {@link String} + * @return {@link UserAccount} */ - public static UserAccount readThrough(String userId) { + public UserAccount readThrough(final String userId) { if (cache.contains(userId)) { - LOGGER.info("# Cache Hit!"); + LOGGER.info("# Found in Cache!"); return cache.get(userId); } - LOGGER.info("# Cache Miss!"); - UserAccount userAccount = DbManager.readFromDb(userId); + LOGGER.info("# Not found in cache! Go to DB!!"); + UserAccount userAccount = dbManager.readFromDb(userId); cache.set(userId, userAccount); return userAccount; } /** * Get user account using write-through cache. + * @param userAccount {@link UserAccount} */ - public static void writeThrough(UserAccount userAccount) { + public void writeThrough(final UserAccount userAccount) { if (cache.contains(userAccount.getUserId())) { - DbManager.updateDb(userAccount); + dbManager.updateDb(userAccount); } else { - DbManager.writeToDb(userAccount); + dbManager.writeToDb(userAccount); } cache.set(userAccount.getUserId(), userAccount); } /** * Get user account using write-around cache. + * @param userAccount {@link UserAccount} */ - public static void writeAround(UserAccount userAccount) { + public void writeAround(final UserAccount userAccount) { if (cache.contains(userAccount.getUserId())) { - DbManager.updateDb(userAccount); - cache.invalidate(userAccount.getUserId()); // Cache data has been updated -- remove older + dbManager.updateDb(userAccount); + // Cache data has been updated -- remove older + cache.invalidate(userAccount.getUserId()); // version from cache. } else { - DbManager.writeToDb(userAccount); + dbManager.writeToDb(userAccount); } } /** * Get user account using read-through cache with write-back policy. + * @param userId {@link String} + * @return {@link UserAccount} */ - public static UserAccount readThroughWithWriteBackPolicy(String userId) { + public UserAccount readThroughWithWriteBackPolicy(final String userId) { if (cache.contains(userId)) { - LOGGER.info("# Cache Hit!"); + LOGGER.info("# Found in cache!"); return cache.get(userId); } - LOGGER.info("# Cache Miss!"); - UserAccount userAccount = DbManager.readFromDb(userId); + LOGGER.info("# Not found in Cache!"); + UserAccount userAccount = dbManager.readFromDb(userId); if (cache.isFull()) { LOGGER.info("# Cache is FULL! Writing LRU data to DB..."); UserAccount toBeWrittenToDb = cache.getLruData(); - DbManager.upsertDb(toBeWrittenToDb); + dbManager.upsertDb(toBeWrittenToDb); } cache.set(userId, userAccount); return userAccount; @@ -110,12 +137,13 @@ public class CacheStore { /** * Set user account. + * @param userAccount {@link UserAccount} */ - public static void writeBehind(UserAccount userAccount) { + public void writeBehind(final UserAccount userAccount) { if (cache.isFull() && !cache.contains(userAccount.getUserId())) { LOGGER.info("# Cache is FULL! Writing LRU data to DB..."); UserAccount toBeWrittenToDb = cache.getLruData(); - DbManager.upsertDb(toBeWrittenToDb); + dbManager.upsertDb(toBeWrittenToDb); } cache.set(userAccount.getUserId(), userAccount); } @@ -123,7 +151,7 @@ public class CacheStore { /** * Clears cache. */ - public static void clearCache() { + public void clearCache() { if (cache != null) { cache.clear(); } @@ -132,44 +160,51 @@ public class CacheStore { /** * Writes remaining content in the cache into the DB. */ - public static void flushCache() { + public void flushCache() { LOGGER.info("# flushCache..."); Optional.ofNullable(cache) .map(LruCache::getCacheDataInListForm) .orElse(List.of()) - .forEach(DbManager::updateDb); + .forEach(dbManager::updateDb); + dbManager.disconnect(); } /** * Print user accounts. + * @return {@link String} */ - public static String print() { + public String print() { return Optional.ofNullable(cache) .map(LruCache::getCacheDataInListForm) .orElse(List.of()) .stream() .map(userAccount -> userAccount.toString() + "\n") - .collect(Collectors.joining("", "\n--CACHE CONTENT--\n", "----\n")); + .collect(Collectors.joining("", "\n--CACHE CONTENT--\n", "----")); } /** * Delegate to backing cache store. + * @param userId {@link String} + * @return {@link UserAccount} */ - public static UserAccount get(String userId) { + public UserAccount get(final String userId) { return cache.get(userId); } /** * Delegate to backing cache store. + * @param userId {@link String} + * @param userAccount {@link UserAccount} */ - public static void set(String userId, UserAccount userAccount) { + public void set(final String userId, final UserAccount userAccount) { cache.set(userId, userAccount); } /** * Delegate to backing cache store. + * @param userId {@link String} */ - public static void invalidate(String userId) { + public void invalidate(final String userId) { cache.invalidate(userId); } } diff --git a/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java b/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java index 0a42cf812..d24ad0173 100644 --- a/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java +++ b/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java @@ -32,10 +32,25 @@ import lombok.Getter; @AllArgsConstructor @Getter public enum CachingPolicy { + /** + * Through. + */ THROUGH("through"), + /** + * AROUND. + */ AROUND("around"), + /** + * BEHIND. + */ BEHIND("behind"), + /** + * ASIDE. + */ ASIDE("aside"); + /** + * Policy value. + */ private final String policy; } diff --git a/caching/src/main/java/com/iluwatar/caching/DbManager.java b/caching/src/main/java/com/iluwatar/caching/DbManager.java deleted file mode 100644 index d02234969..000000000 --- a/caching/src/main/java/com/iluwatar/caching/DbManager.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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.caching; - -import com.iluwatar.caching.constants.CachingConstants; -import com.mongodb.MongoClient; -import com.mongodb.client.MongoDatabase; -import com.mongodb.client.model.UpdateOptions; -import java.text.ParseException; -import java.util.HashMap; -import java.util.Map; -import lombok.extern.slf4j.Slf4j; -import org.bson.Document; - -/** - *

DBManager handles the communication with the underlying data store i.e. Database. It contains - * the implemented methods for querying, inserting, and updating data. MongoDB was used as the - * database for the application.

- * - *

Developer/Tester is able to choose whether the application should use MongoDB as its - * underlying data storage (connect()) or a simple Java data structure to (temporarily) store the - * data/objects during runtime (createVirtualDB()).

- */ -@Slf4j -public final class DbManager { - - private static MongoClient mongoClient; - private static MongoDatabase db; - private static boolean useMongoDB; - - private static Map virtualDB; - - private DbManager() { - } - - /** - * Create DB. - */ - public static void createVirtualDb() { - useMongoDB = false; - virtualDB = new HashMap<>(); - } - - /** - * Connect to DB. - */ - public static void connect() throws ParseException { - useMongoDB = true; - mongoClient = new MongoClient(); - db = mongoClient.getDatabase("test"); - } - - /** - * Read user account from DB. - */ - public static UserAccount readFromDb(String userId) { - if (!useMongoDB) { - if (virtualDB.containsKey(userId)) { - return virtualDB.get(userId); - } - return null; - } - if (db == null) { - try { - connect(); - } catch (ParseException e) { - LOGGER.error("Error connecting to MongoDB", e); - } - } - var iterable = db - .getCollection(CachingConstants.USER_ACCOUNT) - .find(new Document(CachingConstants.USER_ID, userId)); - if (iterable == null) { - return null; - } - Document doc = iterable.first(); - String userName = doc.getString(CachingConstants.USER_NAME); - String appInfo = doc.getString(CachingConstants.ADD_INFO); - return new UserAccount(userId, userName, appInfo); - } - - /** - * Write user account to DB. - */ - public static void writeToDb(UserAccount userAccount) { - if (!useMongoDB) { - virtualDB.put(userAccount.getUserId(), userAccount); - return; - } - if (db == null) { - try { - connect(); - } catch (ParseException e) { - LOGGER.error("Error connecting to MongoDB", e); - } - } - db.getCollection(CachingConstants.USER_ACCOUNT).insertOne( - new Document(CachingConstants.USER_ID, userAccount.getUserId()) - .append(CachingConstants.USER_NAME, userAccount.getUserName()) - .append(CachingConstants.ADD_INFO, userAccount.getAdditionalInfo()) - ); - } - - /** - * Update DB. - */ - public static void updateDb(UserAccount userAccount) { - if (!useMongoDB) { - virtualDB.put(userAccount.getUserId(), userAccount); - return; - } - if (db == null) { - try { - connect(); - } catch (ParseException e) { - LOGGER.error("Error connecting to MongoDB", e); - } - } - db.getCollection(CachingConstants.USER_ACCOUNT).updateOne( - new Document(CachingConstants.USER_ID, userAccount.getUserId()), - new Document("$set", new Document(CachingConstants.USER_NAME, userAccount.getUserName()) - .append(CachingConstants.ADD_INFO, userAccount.getAdditionalInfo()))); - } - - /** - * Insert data into DB if it does not exist. Else, update it. - */ - public static void upsertDb(UserAccount userAccount) { - if (!useMongoDB) { - virtualDB.put(userAccount.getUserId(), userAccount); - return; - } - if (db == null) { - try { - connect(); - } catch (ParseException e) { - LOGGER.error("Error connecting to MongoDB", e); - } - } - db.getCollection(CachingConstants.USER_ACCOUNT).updateOne( - new Document(CachingConstants.USER_ID, userAccount.getUserId()), - new Document("$set", - new Document(CachingConstants.USER_ID, userAccount.getUserId()) - .append(CachingConstants.USER_NAME, userAccount.getUserName()) - .append(CachingConstants.ADD_INFO, userAccount.getAdditionalInfo()) - ), - new UpdateOptions().upsert(true) - ); - } -} diff --git a/caching/src/main/java/com/iluwatar/caching/LruCache.java b/caching/src/main/java/com/iluwatar/caching/LruCache.java index a320e35dc..70450d929 100644 --- a/caching/src/main/java/com/iluwatar/caching/LruCache.java +++ b/caching/src/main/java/com/iluwatar/caching/LruCache.java @@ -29,41 +29,83 @@ import java.util.List; import java.util.Map; import lombok.extern.slf4j.Slf4j; + /** - * Data structure/implementation of the application's cache. The data structure consists of a hash - * table attached with a doubly linked-list. The linked-list helps in capturing and maintaining the - * LRU data in the cache. When a data is queried (from the cache), added (to the cache), or updated, - * the data is moved to the front of the list to depict itself as the most-recently-used data. The - * LRU data is always at the end of the list. + * Data structure/implementation of the application's cache. The data structure + * consists of a hash table attached with a doubly linked-list. The linked-list + * helps in capturing and maintaining the LRU data in the cache. When a data is + * queried (from the cache), added (to the cache), or updated, the data is + * moved to the front of the list to depict itself as the most-recently-used + * data. The LRU data is always at the end of the list. */ @Slf4j public class LruCache { - + /** + * Static class Node. + */ static class Node { - String userId; - UserAccount userAccount; - Node previous; - Node next; + /** + * user id. + */ + private final String userId; + /** + * User Account. + */ + private UserAccount userAccount; + /** + * previous. + */ + private Node previous; + /** + * next. + */ + private Node next; - public Node(String userId, UserAccount userAccount) { - this.userId = userId; - this.userAccount = userAccount; + /** + * Node definition. + * + * @param id String + * @param account {@link UserAccount} + */ + Node(final String id, final UserAccount account) { + this.userId = id; + this.userAccount = account; } } - int capacity; - Map cache = new HashMap<>(); - Node head; - Node end; + /** + * Capacity of Cache. + */ + private int capacity; + /** + * Cache {@link HashMap}. + */ + private Map cache = new HashMap<>(); + /** + * Head. + */ + private Node head; + /** + * End. + */ + private Node end; - public LruCache(int capacity) { - this.capacity = capacity; + /** + * Constructor. + * + * @param cap Integer. + */ + public LruCache(final int cap) { + this.capacity = cap; } /** * Get user account. + * + * @param userId String + * @return {@link UserAccount} */ - public UserAccount get(String userId) { + public UserAccount get(final String userId) { if (cache.containsKey(userId)) { var node = cache.get(userId); remove(node); @@ -75,8 +117,10 @@ public class LruCache { /** * Remove node from linked list. + * + * @param node {@link Node} */ - public void remove(Node node) { + public void remove(final Node node) { if (node.previous != null) { node.previous.next = node.next; } else { @@ -91,8 +135,10 @@ public class LruCache { /** * Move node to the front of the list. + * + * @param node {@link Node} */ - public void setHead(Node node) { + public void setHead(final Node node) { node.next = head; node.previous = null; if (head != null) { @@ -106,8 +152,11 @@ public class LruCache { /** * Set user account. + * + * @param userAccount {@link UserAccount} + * @param userId {@link String} */ - public void set(String userId, UserAccount userAccount) { + public void set(final String userId, final UserAccount userAccount) { if (cache.containsKey(userId)) { var old = cache.get(userId); old.userAccount = userAccount; @@ -127,25 +176,43 @@ public class LruCache { } } - public boolean contains(String userId) { + /** + * Check if Cache contains the userId. + * + * @param userId {@link String} + * @return boolean + */ + public boolean contains(final String userId) { return cache.containsKey(userId); } /** * Invalidate cache for user. + * + * @param userId {@link String} */ - public void invalidate(String userId) { + public void invalidate(final String userId) { var toBeRemoved = cache.remove(userId); if (toBeRemoved != null) { - LOGGER.info("# {} has been updated! Removing older version from cache...", userId); + LOGGER.info("# {} has been updated! " + + "Removing older version from cache...", userId); remove(toBeRemoved); } } + /** + * Check if the cache is full. + * @return boolean + */ public boolean isFull() { return cache.size() >= capacity; } + /** + * Get LRU data. + * + * @return {@link UserAccount} + */ public UserAccount getLruData() { return end.userAccount; } @@ -161,6 +228,8 @@ public class LruCache { /** * Returns cache data in list form. + * + * @return {@link List} */ public List getCacheDataInListForm() { var listOfCacheData = new ArrayList(); @@ -174,10 +243,14 @@ public class LruCache { /** * Set cache capacity. + * + * @param newCapacity int */ - public void setCapacity(int newCapacity) { + public void setCapacity(final int newCapacity) { if (capacity > newCapacity) { - clear(); // Behavior can be modified to accommodate for decrease in cache size. For now, we'll + // Behavior can be modified to accommodate + // for decrease in cache size. For now, we'll + clear(); // just clear the cache. } else { this.capacity = newCapacity; diff --git a/caching/src/main/java/com/iluwatar/caching/UserAccount.java b/caching/src/main/java/com/iluwatar/caching/UserAccount.java index 3681a931b..1ec3af228 100644 --- a/caching/src/main/java/com/iluwatar/caching/UserAccount.java +++ b/caching/src/main/java/com/iluwatar/caching/UserAccount.java @@ -24,19 +24,28 @@ package com.iluwatar.caching; import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; +import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.ToString; /** * Entity class (stored in cache and DB) used in the application. */ -@Setter -@Getter +@Data @AllArgsConstructor @ToString +@EqualsAndHashCode public class UserAccount { + /** + * User Id. + */ private String userId; + /** + * User Name. + */ private String userName; + /** + * Additional Info. + */ private String additionalInfo; } diff --git a/caching/src/main/java/com/iluwatar/caching/constants/CachingConstants.java b/caching/src/main/java/com/iluwatar/caching/constants/CachingConstants.java index 797a561fd..69cd63fef 100644 --- a/caching/src/main/java/com/iluwatar/caching/constants/CachingConstants.java +++ b/caching/src/main/java/com/iluwatar/caching/constants/CachingConstants.java @@ -26,11 +26,27 @@ package com.iluwatar.caching.constants; /** * Constant class for defining constants. */ -public class CachingConstants { - +public final class CachingConstants { + /** + * User Account. + */ public static final String USER_ACCOUNT = "user_accounts"; + /** + * User ID. + */ public static final String USER_ID = "userID"; + /** + * User Name. + */ public static final String USER_NAME = "userName"; + /** + * Additional Info. + */ public static final String ADD_INFO = "additionalInfo"; + /** + * Constructor. + */ + private CachingConstants() { + } } diff --git a/caching/src/main/java/com/iluwatar/caching/constants/package-info.java b/caching/src/main/java/com/iluwatar/caching/constants/package-info.java new file mode 100644 index 000000000..8ae963658 --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/constants/package-info.java @@ -0,0 +1,4 @@ +/** + * Constants. + */ +package com.iluwatar.caching.constants; diff --git a/caching/src/main/java/com/iluwatar/caching/database/DbManager.java b/caching/src/main/java/com/iluwatar/caching/database/DbManager.java new file mode 100644 index 000000000..14d7247f8 --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/database/DbManager.java @@ -0,0 +1,52 @@ +package com.iluwatar.caching.database; + +import com.iluwatar.caching.UserAccount; + +/** + *

DBManager handles the communication with the underlying data store i.e. + * Database. It contains the implemented methods for querying, inserting, + * and updating data. MongoDB was used as the database for the application.

+ */ +public interface DbManager { + /** + * Connect to DB. + */ + void connect(); + + /** + * Disconnect from DB. + */ + void disconnect(); + + /** + * Read from DB. + * + * @param userId {@link String} + * @return {@link UserAccount} + */ + UserAccount readFromDb(String userId); + + /** + * Write to DB. + * + * @param userAccount {@link UserAccount} + * @return {@link UserAccount} + */ + UserAccount writeToDb(UserAccount userAccount); + + /** + * Update record. + * + * @param userAccount {@link UserAccount} + * @return {@link UserAccount} + */ + UserAccount updateDb(UserAccount userAccount); + + /** + * Update record or Insert if not exists. + * + * @param userAccount {@link UserAccount} + * @return {@link UserAccount} + */ + UserAccount upsertDb(UserAccount userAccount); +} diff --git a/caching/src/main/java/com/iluwatar/caching/database/DbManagerFactory.java b/caching/src/main/java/com/iluwatar/caching/database/DbManagerFactory.java new file mode 100644 index 000000000..90ef432cc --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/database/DbManagerFactory.java @@ -0,0 +1,25 @@ +package com.iluwatar.caching.database; + +/** + * Creates the database connection accroding the input parameter. + */ +public final class DbManagerFactory { + /** + * Private constructor. + */ + private DbManagerFactory() { + } + + /** + * Init database. + * + * @param isMongo boolean + * @return {@link DbManager} + */ + public static DbManager initDb(final boolean isMongo) { + if (isMongo) { + return new MongoDb(); + } + return new VirtualDb(); + } +} diff --git a/caching/src/main/java/com/iluwatar/caching/database/MongoDb.java b/caching/src/main/java/com/iluwatar/caching/database/MongoDb.java new file mode 100644 index 000000000..a9dd006f8 --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/database/MongoDb.java @@ -0,0 +1,128 @@ +package com.iluwatar.caching.database; + +import static com.iluwatar.caching.constants.CachingConstants.ADD_INFO; +import static com.iluwatar.caching.constants.CachingConstants.USER_ACCOUNT; +import static com.iluwatar.caching.constants.CachingConstants.USER_ID; +import static com.iluwatar.caching.constants.CachingConstants.USER_NAME; + +import com.iluwatar.caching.UserAccount; +import com.iluwatar.caching.constants.CachingConstants; +import com.mongodb.MongoClient; +import com.mongodb.MongoClientOptions; +import com.mongodb.MongoCredential; +import com.mongodb.ServerAddress; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.UpdateOptions; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.bson.Document; + +/** + * Implementation of DatabaseManager. + * implements base methods to work with MongoDb. + */ +@Slf4j +public class MongoDb implements DbManager { + private static final String DATABASE_NAME = "admin"; + private static final String MONGO_USER = "root"; + private static final String MONGO_PASSWORD = "rootpassword"; + private MongoClient client; + private MongoDatabase db; + + /** + * Connect to Db. Check th connection + */ + @Override + public void connect() { + MongoCredential mongoCredential = MongoCredential.createCredential(MONGO_USER, + DATABASE_NAME, + MONGO_PASSWORD.toCharArray()); + MongoClientOptions options = MongoClientOptions.builder().build(); + client = new MongoClient(new ServerAddress(), List.of(mongoCredential), options); + db = client.getDatabase(DATABASE_NAME); + } + + @Override + public void disconnect() { + client.close(); + } + + /** + * Read data from DB. + * + * @param userId {@link String} + * @return {@link UserAccount} + */ + @Override + public UserAccount readFromDb(final String userId) { + var iterable = db + .getCollection(CachingConstants.USER_ACCOUNT) + .find(new Document(USER_ID, userId)); + if (iterable.first() == null) { + return null; + } + Document doc = iterable.first(); + if (doc != null) { + String userName = doc.getString(USER_NAME); + String appInfo = doc.getString(ADD_INFO); + return new UserAccount(userId, userName, appInfo); + } else { + return null; + } + } + + /** + * Write data to DB. + * + * @param userAccount {@link UserAccount} + * @return {@link UserAccount} + */ + @Override + public UserAccount writeToDb(final UserAccount userAccount) { + db.getCollection(USER_ACCOUNT).insertOne( + new Document(USER_ID, userAccount.getUserId()) + .append(USER_NAME, userAccount.getUserName()) + .append(ADD_INFO, userAccount.getAdditionalInfo()) + ); + return userAccount; + } + + /** + * Update DB. + * + * @param userAccount {@link UserAccount} + * @return {@link UserAccount} + */ + @Override + public UserAccount updateDb(final UserAccount userAccount) { + Document id = new Document(USER_ID, userAccount.getUserId()); + Document dataSet = new Document(USER_NAME, userAccount.getUserName()) + .append(ADD_INFO, userAccount.getAdditionalInfo()); + db.getCollection(CachingConstants.USER_ACCOUNT) + .updateOne(id, new Document("$set", dataSet)); + return userAccount; + } + + /** + * Update data if exists. + * + * @param userAccount {@link UserAccount} + * @return {@link UserAccount} + */ + @Override + public UserAccount upsertDb(final UserAccount userAccount) { + String userId = userAccount.getUserId(); + String userName = userAccount.getUserName(); + String additionalInfo = userAccount.getAdditionalInfo(); + db.getCollection(CachingConstants.USER_ACCOUNT).updateOne( + new Document(USER_ID, userId), + new Document("$set", + new Document(USER_ID, userId) + .append(USER_NAME, userName) + .append(ADD_INFO, additionalInfo) + ), + new UpdateOptions().upsert(true) + ); + return userAccount; + } +} diff --git a/caching/src/main/java/com/iluwatar/caching/database/VirtualDb.java b/caching/src/main/java/com/iluwatar/caching/database/VirtualDb.java new file mode 100644 index 000000000..0c9a14ec9 --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/database/VirtualDb.java @@ -0,0 +1,78 @@ +package com.iluwatar.caching.database; + +import com.iluwatar.caching.UserAccount; + +import java.util.HashMap; +import java.util.Map; + +/** + * Implementation of DatabaseManager. + * implements base methods to work with hashMap as database. + */ +public class VirtualDb implements DbManager { + /** + * Virtual DataBase. + */ + private Map db; + + /** + * Creates new HashMap. + */ + @Override + public void connect() { + db = new HashMap<>(); + } + + @Override + public void disconnect() { + db = null; + } + + /** + * Read from Db. + * + * @param userId {@link String} + * @return {@link UserAccount} + */ + @Override + public UserAccount readFromDb(final String userId) { + if (db.containsKey(userId)) { + return db.get(userId); + } + return null; + } + + /** + * Write to DB. + * + * @param userAccount {@link UserAccount} + * @return {@link UserAccount} + */ + @Override + public UserAccount writeToDb(final UserAccount userAccount) { + db.put(userAccount.getUserId(), userAccount); + return userAccount; + } + + /** + * Update reecord in DB. + * + * @param userAccount {@link UserAccount} + * @return {@link UserAccount} + */ + @Override + public UserAccount updateDb(final UserAccount userAccount) { + return writeToDb(userAccount); + } + + /** + * Update. + * + * @param userAccount {@link UserAccount} + * @return {@link UserAccount} + */ + @Override + public UserAccount upsertDb(final UserAccount userAccount) { + return updateDb(userAccount); + } +} diff --git a/caching/src/main/java/com/iluwatar/caching/database/package-info.java b/caching/src/main/java/com/iluwatar/caching/database/package-info.java new file mode 100644 index 000000000..56deee71d --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/database/package-info.java @@ -0,0 +1,4 @@ +/** + * Database classes. + */ +package com.iluwatar.caching.database; diff --git a/caching/src/main/java/com/iluwatar/caching/package-info.java b/caching/src/main/java/com/iluwatar/caching/package-info.java new file mode 100644 index 000000000..00687084f --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/package-info.java @@ -0,0 +1,20 @@ +/** + * 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.caching; diff --git a/caching/src/test/java/com/iluwatar/caching/AppTest.java b/caching/src/test/java/com/iluwatar/caching/AppTest.java index 12b72d56a..a50b687c2 100644 --- a/caching/src/test/java/com/iluwatar/caching/AppTest.java +++ b/caching/src/test/java/com/iluwatar/caching/AppTest.java @@ -25,25 +25,21 @@ package com.iluwatar.caching; import org.junit.jupiter.api.Test; -import java.io.IOException; - import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; /** * Tests that Caching example runs without errors. */ class AppTest { - /** * Issue: Add at least one assertion to this test case. - * + *

* Solution: Inserted assertion to check whether the execution of the main method in {@link App} * throws an exception. */ @Test void shouldExecuteApplicationWithoutException() { - assertDoesNotThrow(() -> App.main(new String[]{})); } } diff --git a/caching/src/test/java/com/iluwatar/caching/CachingTest.java b/caching/src/test/java/com/iluwatar/caching/CachingTest.java index 8869a66ac..0c70e24de 100644 --- a/caching/src/test/java/com/iluwatar/caching/CachingTest.java +++ b/caching/src/test/java/com/iluwatar/caching/CachingTest.java @@ -23,11 +23,11 @@ package com.iluwatar.caching; -import static org.junit.jupiter.api.Assertions.assertNotNull; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNotNull; + /** * Application test */ @@ -43,32 +43,30 @@ class CachingTest { // to avoid Maven compilation errors. Set flag to true to run the // tests with MongoDB (provided that MongoDB is installed and socket // connection is open). - AppManager.initDb(false); - AppManager.initCacheCapacity(3); - app = new App(); + app = new App(false); } @Test void testReadAndWriteThroughStrategy() { - assertNotNull(app); + assertNotNull(app); app.useReadAndWriteThroughStrategy(); } @Test void testReadThroughAndWriteAroundStrategy() { - assertNotNull(app); + assertNotNull(app); app.useReadThroughAndWriteAroundStrategy(); } @Test void testReadThroughAndWriteBehindStrategy() { - assertNotNull(app); + assertNotNull(app); app.useReadThroughAndWriteBehindStrategy(); } @Test void testCacheAsideStrategy() { - assertNotNull(app); + assertNotNull(app); app.useCacheAsideStategy(); } } diff --git a/caching/src/test/java/com/iluwatar/caching/database/MongoDbTest.java b/caching/src/test/java/com/iluwatar/caching/database/MongoDbTest.java new file mode 100644 index 000000000..cfb2b718f --- /dev/null +++ b/caching/src/test/java/com/iluwatar/caching/database/MongoDbTest.java @@ -0,0 +1,84 @@ +package com.iluwatar.caching.database; + +import com.iluwatar.caching.UserAccount; +import com.iluwatar.caching.constants.CachingConstants; +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.internal.util.reflection.Whitebox; + +import static com.iluwatar.caching.constants.CachingConstants.ADD_INFO; +import static com.iluwatar.caching.constants.CachingConstants.USER_ID; +import static com.iluwatar.caching.constants.CachingConstants.USER_NAME; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +class MongoDbTest { + private static final String ID = "123"; + private static final String NAME = "Some user"; + private static final String ADDITIONAL_INFO = "Some app Info"; + + @Mock + MongoDatabase db; + private MongoDb mongoDb = new MongoDb(); + + private UserAccount userAccount; + + @BeforeEach + void init() { + db = mock(MongoDatabase.class); + Whitebox.setInternalState(mongoDb, "db", db); + userAccount = new UserAccount(ID, NAME, ADDITIONAL_INFO); + + + } + + @Test + void connect() { + assertDoesNotThrow(() -> mongoDb.connect()); + } + + @Test + void readFromDb() { + Document document = new Document(USER_ID, ID) + .append(USER_NAME, NAME) + .append(ADD_INFO, ADDITIONAL_INFO); + MongoCollection mongoCollection = mock(MongoCollection.class); + when(db.getCollection(CachingConstants.USER_ACCOUNT)).thenReturn(mongoCollection); + + FindIterable findIterable = mock(FindIterable.class); + when(mongoCollection.find(any(Document.class))).thenReturn(findIterable); + + when(findIterable.first()).thenReturn(document); + + assertEquals(mongoDb.readFromDb(ID),userAccount); + } + + @Test + void writeToDb() { + MongoCollection mongoCollection = mock(MongoCollection.class); + when(db.getCollection(CachingConstants.USER_ACCOUNT)).thenReturn(mongoCollection); + doNothing().when(mongoCollection).insertOne(any(Document.class)); + assertDoesNotThrow(()-> {mongoDb.writeToDb(userAccount);}); + } + + @Test + void updateDb() { + MongoCollection mongoCollection = mock(MongoCollection.class); + when(db.getCollection(CachingConstants.USER_ACCOUNT)).thenReturn(mongoCollection); + assertDoesNotThrow(()-> {mongoDb.updateDb(userAccount);}); + } + + @Test + void upsertDb() { + MongoCollection mongoCollection = mock(MongoCollection.class); + when(db.getCollection(CachingConstants.USER_ACCOUNT)).thenReturn(mongoCollection); + assertDoesNotThrow(()-> {mongoDb.upsertDb(userAccount);}); + } +} \ No newline at end of file diff --git a/command/README.md b/command/README.md index 3aafcc48a..f01ef3cd0 100644 --- a/command/README.md +++ b/command/README.md @@ -4,7 +4,6 @@ category: Behavioral language: en tags: - Gang of Four ---- ## Also known as diff --git a/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java b/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java index 9278c965b..ca1c936d0 100644 --- a/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java +++ b/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java @@ -46,7 +46,7 @@ class DataBusTest { @BeforeEach void setUp() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); } @Test diff --git a/localization/fr/README.md b/localization/fr/README.md index 1e09ce445..cfc9b55d9 100644 --- a/localization/fr/README.md +++ b/localization/fr/README.md @@ -48,7 +48,7 @@ que lorsqu’ils sont nΓ©cessaires pour une extensibilitΓ© pratique. Une fois que vous Γͺtes familiarisΓ© avec ces concepts, vous pouvez commencer Γ  explorer les [modΓ¨les de conception disponibles](https://java-design-patterns.com/patterns/) -par n’importe laquelle les approches suivantes : +par n’importe laquelle des approches suivantes : - Recherchez un modΓ¨le spΓ©cifique par son nom. Vous n’en trouvez pas ? Veuillez signaler un nouveau modΓ¨le [ici](https://github.com/iluwatar/java-design-patterns/issues). diff --git a/localization/id/README.md b/localization/id/README.md new file mode 100644 index 000000000..15ccd7729 --- /dev/null +++ b/localization/id/README.md @@ -0,0 +1,333 @@ + + +# Implementasi design patterns pada Java + +![Java CI](https://github.com/iluwatar/java-design-patterns/workflows/Java%20CI/badge.svg) +[![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md) +[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=ncloc)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) +[![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +[![All Contributors](https://img.shields.io/badge/all_contributors-176-orange.svg?style=flat-square)](#contributors-) + + +
+ +Baca dalam bahasa lain : [**zh**](localization/zh/README.md), [**ko**](localization/ko/README.md), [**fr**](localization/fr/README.md), [**tr**](localization/tr/README.md), [**ar**](localization/ar/README.md), [**es**](localization/es/README.md), [**pt**](localization/pt/README.md), [**id**](localization/id/README.md) + +
+ +# Pengenalan + +Design patterns adalah best practice yang dapat digunakan programmer untuk memecahkan masalah umum saat merancang aplikasi atau sistem. + +Design patterns dapat mempercepat proses pengembangan dengan menyediakan kode yang teruji, terbukti paradigma pengembangan. + +Menggunakan kembali design patterns membantu mencegah masalah-masalah kecil yang dapat menyebabkan masalah yang lebih besar, dan juga meningkatkan keterbacaan kode untuk programmer dan arsitek yang +familiar dengan pola. + + +# Mulai + +Situs ini menampilkan Design Patterns pada Java. Solusi-solusi yang terdapat pada situs ini telah dikembangkan oleh programmer dan arsitek yang berpengalaman dari komunitas open source. Pola-polanya dapat dilihat pada deskripsi atau dengan melihat source code mereka. Contoh-contoh source code memiliki komentar yang baik dan dapat dianggap sebagai tutorial pemrograman tentang cara menerapkan pola tertentu. Kami menggunakan teknologi Java open source yang populer dan telah terbukti. + +Sebelum anda masuk kedalam materinya, anda harus familiar dengan macam-macam [Software Design Principles](https://java-design-patterns.com/principles/). + +Semua desain seharusnya sesimpel mungkin. Anda harus mulai dengan KISS, YAGNI, dan prinsip Do The Simples Thing That Could Possibly Work. hanya boleh diperkenalkan ketika dibutuhkan untuk praktik +kemungkinan diperpanjang. + +Setelah Anda terbiasa dengan konsep-konsep ini, Anda dapat mulai belajar +[design patterns yang tersedia](https://java-design-patterns.com/patterns/) menggunakan cara-cara berikut + + - Cari spesifik pattern berdasarkan namanya. Apabila tidak menemukannya tolong lapor pattern baru [disini](https://github.com/iluwatar/java-design-patterns/issues). + - Gunakan tag-tag seperti `Performance`, `Gang of Four` atau `Data access`. + - Gunakan kategori dari pattern, `Creational`, `Behavioral`, dan sebagainya. + +Semoga Anda menemukan solusi Object-Oriented yang bermanfaat untuk arsitektur Anda dari yang disajikan di situs ini dan mempelajarinya dengan senang seperti kami mengembangkannya. + +# Cara berkontribusi + +Jika anda memiliki keinginan untuk berkontribusi pada proyek ini anda akan menemukan informasi yang revelan pada halaman [developer wiki](https://github.com/iluwatar/java-design-patterns/wiki). Kami akan membantu anda dan menjawab pertanyaan anda pada [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns). + +# License + +Proyek ini dilisensikan di bawah ketentuan lisensi MIT. + +# Contributors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Ilkka SeppΓ€lΓ€

πŸ“† 🚧 πŸ–‹

amit1307

πŸ’»

Narendra Pathai

πŸ’» πŸ€” πŸ‘€

Jeroen Meulemeester

πŸ’»

Joseph McCarthy

πŸ’»

Thomas

πŸ’»

Anurag Agarwal

πŸ’»

Markus Moser

🎨 πŸ’» πŸ€”

Sabiq Ihab

πŸ’»

Amit Dixit

πŸ’»

Piyush Kailash Chaudhari

πŸ’»

joshzambales

πŸ’»

Kamil Pietruszka

πŸ’»

Zafar Khaydarov

πŸ’» πŸ“–

Paul Campbell

πŸ’»

Argyro Sioziou

πŸ’»

TylerMcConville

πŸ’»

saksham93

πŸ’»

nikhilbarar

πŸ’»

Colin But

πŸ’»

Ruslan

πŸ’»

Juho Kang

πŸ’»

Dheeraj Mummareddy

πŸ’»

Bernardo Sulzbach

πŸ’»

Aleksandar Dudukovic

πŸ’»

Yusuf Aytaş

πŸ’»

MihΓ‘ly Kuprivecz

πŸ’»

Stanislav Kapinus

πŸ’»

GVSharma

πŸ’»

Srđan Paunović

πŸ’»

Petros G. Sideris

πŸ’»

Pramod Gupta

πŸ‘€

Amarnath Chandana

πŸ’»

Anurag870

πŸ’» πŸ“–

Wes Gilleland

πŸ’»

Harshraj Thakor

πŸ’»

Martin Vandenbussche

πŸ’»

Alexandru Somai

πŸ’»

Artur Mogozov

πŸ’»

anthony

πŸ’»

Christian Cygnus

πŸ’»

Dima Gubin

πŸ’»

Joshua Jimenez

πŸ’»

Kai Winter

πŸ’»

lbroman

πŸ’»

Przemek

πŸ’»

Prafful Agarwal

πŸ–‹

Sanket Panhale

πŸ–‹

staillebois

πŸ’»

KrisztiΓ‘n Nagy

πŸ’»

Alexander Ivanov

πŸ’»

Yosfik Alqadri

πŸ’»

AgustΓ­ Becerra MilΓ 

πŸ’»

Juan Manuel SuΓ‘rez

πŸ’»

Luigi Cortese

πŸ’»

Katarzyna Rzepecka

πŸ’»

adamski.pro

πŸ’»

Shengli Bai

πŸ’»

Boris

πŸ’»

Dmitry Avershin

πŸ’»

靳阳

πŸ’»

hoangnam2261

πŸ’»

Arpit Jain

πŸ’»

JΓ³n Ingi SveinbjΓΆrnsson

πŸ’»

Kirill Vlasov

πŸ’»

Mitchell Irvin

πŸ’»

Ranjeet

πŸ’»

PhoenixYip

πŸ’»

M Saif Asif

πŸ’»

kanwarpreet25

πŸ’»

Leon Mak

πŸ’»

Per Wramdemark

πŸ’»

Evan Sia Wai Suan

πŸ’»

AnaghaSasikumar

πŸ’»

Christoffer Hamberg

πŸ’»

Dominik Gruntz

πŸ’»

Hannes

πŸ’»

Leo GutiΓ©rrez RamΓ­rez

πŸ’»

Zhang WH

πŸ’»

Christopher O'Connell

πŸ’»

George Mavroeidis

πŸ’»

Hemant Bothra

πŸ’» 🎨

Kevin Peters

πŸ’»

George Aristy

πŸ’»

Mahendran Mookkiah

πŸ’»

Azureyjt

πŸ’»

gans

πŸ’»

Matt

πŸ–‹

Gopinath Langote

πŸ’»

Hoswey

πŸ’»

Amit Pandey

πŸ’»

gwildor28

πŸ–‹

η”°ζ΅©

πŸ–‹

Stamatis Pitsios

πŸ’»

qza

πŸ’»

Rodolfo Forte

πŸ–‹

Ankur Kaushal

πŸ’»

Ovidijus Okinskas

πŸ’»

Robert Kasperczyk

πŸ’»

Tapio Rautonen

πŸ’»

Yuri Orlov

πŸ’»

Varun Upadhyay

πŸ’»

Aditya Pal

πŸ’»

grzesiekkedzior

πŸ’» πŸ‘€

Sivasubramani M

πŸ’»

Sami Airaksinen

πŸ’»

Janne Sinivirta

πŸ’»

Boris-Chengbiao Zhou

πŸ–‹

Jacob Hein

πŸ–‹

Richard Jones

πŸ–‹

Rachel M. Carmena

πŸ–‹

Zaerald Denze Lungos

πŸ–‹

Lars Kappert

πŸ–‹

Mike Liu

🌍

Matt Dolan

πŸ’» πŸ‘€

Manan

πŸ‘€

Nishant Arora

πŸ’»

Peeyush

πŸ’»

Rakesh

πŸ’» πŸ‘€

Wei Seng

πŸ’»

Ashish Trivedi

πŸ’»

ζ΄ͺ月阳

πŸ’»

xdvrx1

πŸ‘€ πŸ€”

Subhrodip Mohanta

πŸ’» πŸ‘€ 🚧

Bethan Palmer

πŸ’»

Toxic Dreamz

πŸ’»

Edy Cu Tjong

πŸ“–

MichaΕ‚ KrzywaΕ„ski

πŸ’»

Stefan Birkner

πŸ’»

Fedor Skvorcov

πŸ’»

samilAyoub

πŸ’»

Vladislav Golubinov

πŸ’»

Swaraj

πŸ’»

Christoph Flick

πŸ“–

AscΓͺnio

πŸ‘€

Domenico Sibilio

πŸ“–

Akash Chandwani

πŸ‘€

Pavlo Manannikov

πŸ’»

Eiman

πŸ’»

Rocky

πŸ“–

Ibrahim ali abdelghany

πŸ‘€

Girish Kulkarni

πŸ“–

Omar Karazoun

πŸ’»

Jeff Evans

πŸ’»

Vivek Singh

πŸ’»

siavash

πŸ’»

ruchpeanuts

πŸ“–

warp125

🌍

KHADIR Tayeb

🌍

ignite1771

πŸ’»

Halil Demir

🌍

Rohit Singh

πŸ’»

byoungju94

πŸ’»

Moustafa Farhat

🌍

Martel Richard

πŸ’»

va1m

πŸ’»

Noam Greenshtain

πŸ’»

yonghong Xu

πŸ“–

jinishavora

πŸ‘€ πŸ’»

Elvys Soares

πŸ’»

zWeBrain

πŸ’»

δ½™ζž—ι’–

🌍

Alain

🌍

VR

πŸ“–

JackieNim

πŸ’»

EdisonE3

πŸ’»

Tao

πŸ’»

Juan Manuel Abate

🌍

Xenilo137

πŸ’»

Samuel Souza

πŸ’»

Marlo Henrique

🌍

AndriyPyzh

πŸ’»

karthikbhat13

πŸ’»

Morteza Adigozalpour

πŸ’»

Nagaraj Tantri

πŸ’»

Francesco Scuccimarri

πŸ’»
+ + + + + diff --git a/localization/ru/README.md b/localization/ru/README.md new file mode 100644 index 000000000..599a778f4 --- /dev/null +++ b/localization/ru/README.md @@ -0,0 +1,345 @@ + + +# Π¨Π°Π±Π»ΠΎΠ½Ρ‹ проСктирования Π½Π° Java + +![Java CI](https://github.com/iluwatar/java-design-patterns/workflows/Java%20CI/badge.svg) +[![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md) +[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=ncloc)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) +[![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +[![All Contributors](https://img.shields.io/badge/all_contributors-178-orange.svg?style=flat-square)](#contributors-) + + +# Π’Π²Π΅Π΄Π΅Π½ΠΈΠ΅ +Π¨Π°Π±Π»ΠΎΠ½Ρ‹ проСктирования - Π»ΡƒΡ‡ΡˆΠΈΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ для Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, Π²ΠΎΠ·Π½ΠΈΠΊΠ°ΡŽΡ‰ΠΈΡ… +Π²ΠΎ врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ прилоТСния ΠΈΠ»ΠΈ систСмы. + +Π¨Π°Π±Π»ΠΎΠ½Ρ‹ проСктирования ΠΌΠΎΠ³ΡƒΡ‚ ΡƒΡΠΊΠΎΡ€ΠΈΡ‚ΡŒ процСсс Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΏΡƒΡ‚Π΅ΠΌ прСдоставлСния +ΠΏΡ€ΠΎΠ²Π΅Ρ€Π΅Π½Π½Ρ‹Ρ… ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ/ΠΏΠ°Ρ€Π°Π΄ΠΈΠ³ΠΌ. + +ИспользованиС шаблонов ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ частых ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, ΠΈΠ·-Π·Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… +происходят ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹. А Π΅Ρ‰Π΅ это повысит Ρ‡ΠΈΡ‚Π°Π΅ΠΌΠΎΡΡ‚ΡŒ ΠΊΠΎΠ΄Π° для программистов ΠΈ +Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΠΎΡ€ΠΎΠ², Π·Π½Π°ΠΊΠΎΠΌΡ‹Ρ… с шаблонами. + +# Начало Ρ€Π°Π±ΠΎΡ‚Ρ‹ + +Π’ этом Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ Ρ€Π°Π·ΠΌΠ΅Ρ‰Π΅Π½Ρ‹ ΡˆΠ°Π±Π»ΠΎΠ½Ρ‹ проСктирования Π½Π° Java. Они Π±Ρ‹Π»ΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½Ρ‹ +программистами ΠΈΠ· open source сообщСства. Π¨Π°Π±Π»ΠΎΠ½ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π²Ρ‹Π±Ρ€Π°Π½ +ΠΈΠ· Π΅Π³ΠΎ описания ΠΈΠ»ΠΈ просмотром Π΅Π³ΠΎ исходного ΠΊΠΎΠ΄Π°. Код Ρ…ΠΎΡ€ΠΎΡˆΠΎ Π·Π°Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½, +Π΅Π³ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΡƒΡ‡Π΅Π±Π½ΠΈΠΊ ΠΏΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡŽ ΠΎ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌ шаблонС. +ΠœΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ самыС популярныС (ΠΏΡ€ΠΎΡˆΠ΅Π΄ΡˆΠΈΠ΅ огонь, Π²ΠΎΠ΄Ρƒ ΠΈ ΠΌΠ΅Π΄Π½Ρ‹Π΅ Ρ‚Ρ€ΡƒΠ±Ρ‹) Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ, +основанныС Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° ПО с ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΌ исходным ΠΊΠΎΠ΄ΠΎΠΌ. + +ΠŸΡ€Π΅ΠΆΠ΄Π΅ΠΌ Ρ‡Π΅ΠΌ Π½Ρ‹Ρ€Π½ΡƒΡ‚ΡŒ Π² ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π», Ρ‚Π΅Π±Π΅ слСдуСт ΠΎΠ·Π½Π°ΠΊΠΎΠΌΠΈΡ‚ΡŒΡΡ с Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹ΠΌΠΈ +[ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ°ΠΌΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ПО(Π°Π½Π³Π»)](https://java-design-patterns.com/principles/). + +ВсС конструкции Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ максимально простыми. НС Π΄Π΅Π»Π°ΠΉ лишнюю Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ, +которая скорСй всСго Π½Π΅ ΠΏΡ€ΠΈΠ³ΠΎΠ΄ΠΈΡ‚ΡŒΡΡ, Π° просто создай ΠΏΡ€ΠΎΡΡ‚ΡƒΡŽ ΡˆΡ‚ΡƒΠΊΡƒ, Ρ‡Ρ‚ΠΎ смоТСт +Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ. Π£ΡΠ»ΠΎΠΆΠ½ΡΡ‚ΡŒ ΠΈ Π²Π²ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½Ρ‹ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ, лишь ΠΊΠΎΠ³Π΄Π° ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΠΎΡΡ‚ΡŒ +Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π½ΡƒΠΆΠ½Π°. + +Как Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ·Π½Π°ΠΊΠΎΠΌΠΈΡ‚Π΅ΡΡŒ с этими концСпциями, приступайтС ΠΊ ΠΈΠ·ΡƒΡ‡Π΅Π½ΠΈΡŽ +[доступных шаблонов проСктирования(Π°Π½Π³Π»)](https://java-design-patterns.com/patterns/) Π»ΡŽΠ±Ρ‹ΠΌ +ΠΈΠ· ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ²: + +- Π˜Ρ‰ΠΈΡ‚Π΅ шаблон ΠΏΠΎ ΠΈΠΌΠ΅Π½ΠΈ. НС смогли Π½Π°ΠΉΡ‚ΠΈ Ρ‚Π°ΠΊΠΎΠΉ? Π‘ΠΎΠΎΠ±Ρ‰ΠΈΡ‚Π΅ ΠΎΠ± этом [здСсь](https://github.com/iluwatar/java-design-patterns/issues). +- Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ тэги, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ `Performance`, `Gang of Four` ΠΈΠ»ΠΈ `Data access`. +- Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ шаблонов `Creational`, `Behavioral` ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅. + +НадССмся ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΈΠ²Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ, прСдставлСнныС здСсь Π±ΡƒΠ΄ΡƒΡ‚ Π²Π°ΠΌ +ΠΏΠΎΠ»Π΅Π·Π½Ρ‹ ΠΈ Π½Π°ΠΉΠ΄ΡƒΡ‚ мСсто Π² Π²Π°ΡˆΠΈΡ… ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°Ρ…, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π²Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ Ρ‚Π°ΠΊΠΎΠ΅ ΠΆΠ΅ ΡƒΠ΄ΠΎΠ²ΠΎΠ»ΡŒΡΡ‚Π²ΠΈΠ΅ +ΠΎΡ‚ ΠΈΡ… изучСния, ΠΊΠ°ΠΊΠΎΠ΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ ΠΌΡ‹ Π²ΠΎ врСмя ΠΈΡ… Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ. + +# Как ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ участиС Π² Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ + +Если Π²Ρ‹ Π·Π°Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ участиС Π² ΠΆΠΈΠ·Π½ΠΈ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, вся полСзная информация находится Π½Π° +нашСй [Π²ΠΈΠΊΠΈ(Π°Π½Π³Π»)](https://github.com/iluwatar/java-design-patterns/wiki). ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠΌΠΎΡ‡ΡŒ +ΠΈ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π½Π° Ρ‚Π²ΠΎΠΈ вопросы Π² Ρ‡Π°Ρ‚Π΅ [Gitter](https://gitter.im/iluwatar/java-design-patterns). + +# ЛицСнзия + +ΠŸΡ€ΠΎΠ΅ΠΊΡ‚ основываСтся Π½Π° тСзисах Π»ΠΈΡ†Π΅Π½Π·ΠΈΠΈ MIT. + +# Π Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Ilkka SeppΓ€lΓ€

πŸ“† 🚧 πŸ–‹

amit1307

πŸ’»

Narendra Pathai

πŸ’» πŸ€” πŸ‘€

Jeroen Meulemeester

πŸ’»

Joseph McCarthy

πŸ’»

Thomas

πŸ’»

Anurag Agarwal

πŸ’»

Markus Moser

🎨 πŸ’» πŸ€”

Sabiq Ihab

πŸ’»

Amit Dixit

πŸ’»

Piyush Kailash Chaudhari

πŸ’»

joshzambales

πŸ’»

Kamil Pietruszka

πŸ’»

Zafar Khaydarov

πŸ’» πŸ“–

Paul Campbell

πŸ’»

Argyro Sioziou

πŸ’»

TylerMcConville

πŸ’»

saksham93

πŸ’»

nikhilbarar

πŸ’»

Colin But

πŸ’»

Ruslan

πŸ’»

Juho Kang

πŸ’»

Dheeraj Mummareddy

πŸ’»

Bernardo Sulzbach

πŸ’»

Aleksandar Dudukovic

πŸ’»

Yusuf Aytaş

πŸ’»

MihΓ‘ly Kuprivecz

πŸ’»

Stanislav Kapinus

πŸ’»

GVSharma

πŸ’»

Srđan Paunović

πŸ’»

Petros G. Sideris

πŸ’»

Pramod Gupta

πŸ‘€

Amarnath Chandana

πŸ’»

Anurag870

πŸ’» πŸ“–

Wes Gilleland

πŸ’»

Harshraj Thakor

πŸ’»

Martin Vandenbussche

πŸ’»

Alexandru Somai

πŸ’»

Artur Mogozov

πŸ’»

anthony

πŸ’»

Christian Cygnus

πŸ’»

Dima Gubin

πŸ’»

Joshua Jimenez

πŸ’»

Kai Winter

πŸ’»

lbroman

πŸ’»

Przemek

πŸ’»

Prafful Agarwal

πŸ–‹

Sanket Panhale

πŸ–‹

staillebois

πŸ’»

KrisztiΓ‘n Nagy

πŸ’»

Alexander Ivanov

πŸ’»

Yosfik Alqadri

πŸ’»

AgustΓ­ Becerra MilΓ 

πŸ’»

Juan Manuel SuΓ‘rez

πŸ’»

Luigi Cortese

πŸ’»

Katarzyna Rzepecka

πŸ’»

adamski.pro

πŸ’»

Shengli Bai

πŸ’»

Boris

πŸ’»

Dmitry Avershin

πŸ’»

靳阳

πŸ’»

hoangnam2261

πŸ’»

Arpit Jain

πŸ’»

JΓ³n Ingi SveinbjΓΆrnsson

πŸ’»

Kirill Vlasov

πŸ’»

Mitchell Irvin

πŸ’»

Ranjeet

πŸ’»

PhoenixYip

πŸ’»

M Saif Asif

πŸ’»

kanwarpreet25

πŸ’»

Leon Mak

πŸ’»

Per Wramdemark

πŸ’»

Evan Sia Wai Suan

πŸ’»

AnaghaSasikumar

πŸ’»

Christoffer Hamberg

πŸ’»

Dominik Gruntz

πŸ’»

Hannes

πŸ’»

Leo GutiΓ©rrez RamΓ­rez

πŸ’»

Zhang WH

πŸ’»

Christopher O'Connell

πŸ’»

George Mavroeidis

πŸ’»

Hemant Bothra

πŸ’» 🎨

Kevin Peters

πŸ’»

George Aristy

πŸ’»

Mahendran Mookkiah

πŸ’»

Azureyjt

πŸ’»

gans

πŸ’»

Matt

πŸ–‹

Gopinath Langote

πŸ’»

Hoswey

πŸ’»

Amit Pandey

πŸ’»

gwildor28

πŸ–‹

η”°ζ΅©

πŸ–‹

Stamatis Pitsios

πŸ’»

qza

πŸ’»

Rodolfo Forte

πŸ–‹

Ankur Kaushal

πŸ’»

Ovidijus Okinskas

πŸ’»

Robert Kasperczyk

πŸ’»

Tapio Rautonen

πŸ’»

Yuri Orlov

πŸ’»

Varun Upadhyay

πŸ’»

Aditya Pal

πŸ’»

grzesiekkedzior

πŸ’» πŸ‘€

Sivasubramani M

πŸ’»

Sami Airaksinen

πŸ’»

Janne Sinivirta

πŸ’»

Boris-Chengbiao Zhou

πŸ–‹

Jacob Hein

πŸ–‹

Richard Jones

πŸ–‹

Rachel M. Carmena

πŸ–‹

Zaerald Denze Lungos

πŸ–‹

Lars Kappert

πŸ–‹

Mike Liu

🌍

Matt Dolan

πŸ’» πŸ‘€

Manan

πŸ‘€

Nishant Arora

πŸ’»

Peeyush

πŸ’»

Rakesh

πŸ’» πŸ‘€

Wei Seng

πŸ’»

Ashish Trivedi

πŸ’»

ζ΄ͺ月阳

πŸ’»

xdvrx1

πŸ‘€ πŸ€”

Subhrodip Mohanta

πŸ’» πŸ‘€ 🚧

Bethan Palmer

πŸ’»

Toxic Dreamz

πŸ’»

Edy Cu Tjong

πŸ“–

MichaΕ‚ KrzywaΕ„ski

πŸ’»

Stefan Birkner

πŸ’»

Fedor Skvorcov

πŸ’»

samilAyoub

πŸ’»

Vladislav Golubinov

πŸ’»

Swaraj

πŸ’»

Christoph Flick

πŸ“–

AscΓͺnio

πŸ‘€

Domenico Sibilio

πŸ“–

Akash Chandwani

πŸ‘€

Pavlo Manannikov

πŸ’»

Eiman

πŸ’»

Rocky

πŸ“–

Ibrahim ali abdelghany

πŸ‘€

Girish Kulkarni

πŸ“–

Omar Karazoun

πŸ’»

Jeff Evans

πŸ’»

Vivek Singh

πŸ’»

siavash

πŸ’»

ruchpeanuts

πŸ“–

warp125

🌍

KHADIR Tayeb

🌍

ignite1771

πŸ’»

Halil Demir

🌍

Rohit Singh

πŸ’»

byoungju94

πŸ’»

Moustafa Farhat

🌍

Martel Richard

πŸ’»

va1m

πŸ’»

Noam Greenshtain

πŸ’»

yonghong Xu

πŸ“–

jinishavora

πŸ‘€ πŸ’»

Elvys Soares

πŸ’»

zWeBrain

πŸ’»

δ½™ζž—ι’–

🌍

Alain

🌍

VR

πŸ“–

JackieNim

πŸ’»

EdisonE3

πŸ’»

Tao

πŸ’»

Juan Manuel Abate

🌍

Xenilo137

πŸ’»

Samuel Souza

πŸ’»

Marlo Henrique

🌍

AndriyPyzh

πŸ’»

karthikbhat13

πŸ’»

Morteza Adigozalpour

πŸ’»

Nagaraj Tantri

πŸ’»

Francesco Scuccimarri

πŸ’»

Conny Hansson

πŸ“–

Muklas Rahmanto

🌍
+ + + + + diff --git a/pom.xml b/pom.xml index cfd0de127..3e5e51abf 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 1.7.30 1.2.3 1.1.0 - 1.11.289 + 1.12.13 2.0.1 2.12.3 2.3.1 @@ -71,8 +71,8 @@ 1.1.0 2.0.0 3.5.0 - 1.18.14 - 1.10.21 + 1.18.20 + 1.11.5 3.27.0-GA 3.0.0-M5 3.1.0 diff --git a/serverless/pom.xml b/serverless/pom.xml index 1cf2cb8a5..8ee367fa3 100644 --- a/serverless/pom.xml +++ b/serverless/pom.xml @@ -44,16 +44,6 @@ com.amazonaws aws-java-sdk-dynamodb ${aws-java-sdk-dynamodb.version} - - - com.amazonaws - aws-java-sdk-s3 - - - com.amazonaws - aws-java-sdk-kms - - com.amazonaws @@ -80,15 +70,15 @@ junit-jupiter-engine test + + org.mockito + mockito-core + test + - org.mockito - mockito-core - test - - - junit - junit - test + org.hamcrest + hamcrest-core + test diff --git a/serverless/src/test/java/com/iluwatar/serverless/baas/api/FindPersonApiHandlerTest.java b/serverless/src/test/java/com/iluwatar/serverless/baas/api/FindPersonApiHandlerTest.java index 8eb209e06..003fdf0df 100644 --- a/serverless/src/test/java/com/iluwatar/serverless/baas/api/FindPersonApiHandlerTest.java +++ b/serverless/src/test/java/com/iluwatar/serverless/baas/api/FindPersonApiHandlerTest.java @@ -23,6 +23,9 @@ package com.iluwatar.serverless.baas.api; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -32,31 +35,29 @@ import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.iluwatar.serverless.baas.model.Person; import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; /** * Unit tests for FindPersonApiHandler Created by dheeraj.mummar on 3/5/18. */ -@RunWith(MockitoJUnitRunner.class) -public class FindPersonApiHandlerTest { +class FindPersonApiHandlerTest { private FindPersonApiHandler findPersonApiHandler; @Mock private DynamoDBMapper dynamoDbMapper; - @Before + @BeforeEach public void setUp() { + MockitoAnnotations.openMocks(this); this.findPersonApiHandler = new FindPersonApiHandler(); this.findPersonApiHandler.setDynamoDbMapper(dynamoDbMapper); } @Test - public void handleRequest() { + void handleRequest() { findPersonApiHandler.handleRequest(apiGatewayProxyRequestEvent(), mock(Context.class)); verify(dynamoDbMapper, times(1)).load(Person.class, "37e7a1fe-3544-473d-b764-18128f02d72d"); } diff --git a/serverless/src/test/java/com/iluwatar/serverless/baas/api/SavePersonApiHandlerTest.java b/serverless/src/test/java/com/iluwatar/serverless/baas/api/SavePersonApiHandlerTest.java index bf4a59273..d9b12a71f 100644 --- a/serverless/src/test/java/com/iluwatar/serverless/baas/api/SavePersonApiHandlerTest.java +++ b/serverless/src/test/java/com/iluwatar/serverless/baas/api/SavePersonApiHandlerTest.java @@ -34,18 +34,18 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.iluwatar.serverless.baas.model.Address; import com.iluwatar.serverless.baas.model.Person; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; /** * Unit tests for SavePersonApiHandler Created by dheeraj.mummar on 3/4/18. */ -@RunWith(MockitoJUnitRunner.class) -public class SavePersonApiHandlerTest { +class SavePersonApiHandlerTest { private SavePersonApiHandler savePersonApiHandler; @@ -54,31 +54,32 @@ public class SavePersonApiHandlerTest { private final ObjectMapper objectMapper = new ObjectMapper(); - @Before + @BeforeEach public void setUp() { + MockitoAnnotations.openMocks(this); this.savePersonApiHandler = new SavePersonApiHandler(); this.savePersonApiHandler.setDynamoDbMapper(dynamoDbMapper); } @Test - public void handleRequestSavePersonSuccessful() throws JsonProcessingException { + void handleRequestSavePersonSuccessful() throws JsonProcessingException { var person = newPerson(); var body = objectMapper.writeValueAsString(person); var request = apiGatewayProxyRequestEvent(body); var ctx = mock(Context.class); var apiGatewayProxyResponseEvent = this.savePersonApiHandler.handleRequest(request, ctx); verify(dynamoDbMapper, times(1)).save(person); - Assert.assertNotNull(apiGatewayProxyResponseEvent); - Assert.assertEquals(Integer.valueOf(201), apiGatewayProxyResponseEvent.getStatusCode()); + assertNotNull(apiGatewayProxyResponseEvent); + assertEquals(Integer.valueOf(201), apiGatewayProxyResponseEvent.getStatusCode()); } @Test - public void handleRequestSavePersonException() { + void handleRequestSavePersonException() { var request = apiGatewayProxyRequestEvent("invalid sample request"); var ctx = mock(Context.class); var apiGatewayProxyResponseEvent = this.savePersonApiHandler.handleRequest(request, ctx); - Assert.assertNotNull(apiGatewayProxyResponseEvent); - Assert.assertEquals(Integer.valueOf(400), apiGatewayProxyResponseEvent.getStatusCode()); + assertNotNull(apiGatewayProxyResponseEvent); + assertEquals(Integer.valueOf(400), apiGatewayProxyResponseEvent.getStatusCode()); } private APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent(String body) {