diff --git a/caching/README.md b/caching/README.md
index bd6e05f77..9c4d11b9e 100644
--- a/caching/README.md
+++ b/caching/README.md
@@ -43,39 +43,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);
}
```
@@ -171,30 +161,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();
@@ -225,34 +228,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);
}
@@ -272,24 +280,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() { /* ... */ }
@@ -300,16 +319,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

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 eb610dbc9..d1e75c155 100644
--- a/caching/pom.xml
+++ b/caching/pom.xml
@@ -38,19 +38,14 @@
+ * 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(() -> { - OptionalDBManager 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 MapDBManager 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
* 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..a82876469
--- /dev/null
+++ b/caching/src/test/java/com/iluwatar/caching/database/MongoDbTest.java
@@ -0,0 +1,83 @@
+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.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