diff --git a/caching/src/main/java/com/iluwatar/caching/App.java b/caching/src/main/java/com/iluwatar/caching/App.java index f5df323aa..bddc1f1c6 100644 --- a/caching/src/main/java/com/iluwatar/caching/App.java +++ b/caching/src/main/java/com/iluwatar/caching/App.java @@ -23,6 +23,8 @@ package com.iluwatar.caching; +import com.iluwatar.caching.database.DbManager; +import com.iluwatar.caching.database.DbManagerFactory; import lombok.extern.slf4j.Slf4j; /** @@ -55,111 +57,138 @@ import lombok.extern.slf4j.Slf4j; * {@literal App --> AppManager --> CacheStore/LRUCache/CachingPolicy --> DBManager} *

* + *

+ * To run the application with MongoDb, just start it with parameter --mongo + * Example: java -jar app.jar --mongo + *

+ * * @see CacheStore * @see LruCache * @see CachingPolicy */ @Slf4j public class App { + private static final String USE_MONGO_DB = "--mongo"; + private DbManager dbManager; + private AppManager appManager; - /** - * 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 - // 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(); - app.useReadAndWriteThroughStrategy(); - app.useReadThroughAndWriteAroundStrategy(); - app.useReadThroughAndWriteBehindStrategy(); - app.useCacheAsideStategy(); - } + public App(boolean isMongo) { + dbManager = DbManagerFactory.initDb(isMongo); + appManager = new AppManager(dbManager); + appManager.initDb(); + } - /** - * Read-through and write-through. - */ - public void useReadAndWriteThroughStrategy() { - LOGGER.info("# CachingPolicy.THROUGH"); - AppManager.initCachingPolicy(CachingPolicy.THROUGH); + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(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). + App app = new App(isDbMongo(args)); + app.useReadAndWriteThroughStrategy(); + app.useReadThroughAndWriteAroundStrategy(); + app.useReadThroughAndWriteBehindStrategy(); + app.useCacheAsideStategy(); + } - var userAccount1 = new UserAccount("001", "John", "He is a boy."); + /** + * Check the input parameters. if + * @param args input params + * @return true if there is "--mongo" parameter in arguments + */ + private static boolean isDbMongo(String[] args) { + for (String arg : args) { + if (arg.equals(USE_MONGO_DB)) { + return true; + } + } + return false; + } - AppManager.save(userAccount1); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("001"); - AppManager.find("001"); - } + /** + * Read-through and write-through. + */ + public void useReadAndWriteThroughStrategy() { + LOGGER.info("# CachingPolicy.THROUGH"); + appManager.initCachingPolicy(CachingPolicy.THROUGH); - /** - * Read-through and write-around. - */ - public void useReadThroughAndWriteAroundStrategy() { - LOGGER.info("# CachingPolicy.AROUND"); - AppManager.initCachingPolicy(CachingPolicy.AROUND); + var userAccount1 = new UserAccount("001", "John", "He is a boy."); - var userAccount2 = new UserAccount("002", "Jane", "She is a girl."); + appManager.save(userAccount1); + LOGGER.info(appManager.printCacheContent()); + appManager.find("001"); + appManager.find("001"); + } - 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"); - } + /** + * Read-through and write-around. + */ + public void useReadThroughAndWriteAroundStrategy() { + LOGGER.info("# CachingPolicy.AROUND"); + appManager.initCachingPolicy(CachingPolicy.AROUND); - /** - * Read-through and write-behind. - */ - public void useReadThroughAndWriteBehindStrategy() { - LOGGER.info("# CachingPolicy.BEHIND"); - AppManager.initCachingPolicy(CachingPolicy.BEHIND); + var userAccount2 = new UserAccount("002", "Jane", "She is a girl."); - 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(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(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()); - } + /** + * Read-through and write-behind. + */ + public void useReadThroughAndWriteBehindStrategy() { + LOGGER.info("# CachingPolicy.BEHIND"); + appManager.initCachingPolicy(CachingPolicy.BEHIND); - /** - * Cache-Aside. - */ - public void useCacheAsideStategy() { - LOGGER.info("# CachingPolicy.ASIDE"); - 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."); - 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); + 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()); + } - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("003"); - LOGGER.info(AppManager.printCacheContent()); - AppManager.find("004"); - LOGGER.info(AppManager.printCacheContent()); - } + /** + * Cache-Aside. + */ + public void useCacheAsideStategy() { + LOGGER.info("# CachingPolicy.ASIDE"); + 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); + + 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..cca24014a 100644 --- a/caching/src/main/java/com/iluwatar/caching/AppManager.java +++ b/caching/src/main/java/com/iluwatar/caching/AppManager.java @@ -23,8 +23,9 @@ package com.iluwatar.caching; -import java.text.ParseException; import java.util.Optional; + +import com.iluwatar.caching.database.DbManager; import lombok.extern.slf4j.Slf4j; /** @@ -35,11 +36,15 @@ import lombok.extern.slf4j.Slf4j; * CacheStore class. */ @Slf4j -public final class AppManager { +public class AppManager { private static CachingPolicy cachingPolicy; + private final DbManager dbManager; + private final CacheStore cacheStore; - private AppManager() { + public AppManager(DbManager dbManager) { + this.dbManager = dbManager; + this.cacheStore = new CacheStore(dbManager); } /** @@ -47,41 +52,29 @@ public final class AppManager { * 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. */ - public static void initCachingPolicy(CachingPolicy policy) { + public void initCachingPolicy(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. */ - public static UserAccount find(String userId) { + public UserAccount find(String userId) { if (cachingPolicy == CachingPolicy.THROUGH || cachingPolicy == CachingPolicy.AROUND) { - return CacheStore.readThrough(userId); + 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); } @@ -91,38 +84,38 @@ public final class AppManager { /** * Save user account. */ - public static void save(UserAccount userAccount) { + public void save(UserAccount userAccount) { 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(); + public String printCacheContent() { + return cacheStore.print(); } /** * Cache-Aside save user account helper. */ - private static void saveAside(UserAccount userAccount) { - DbManager.updateDb(userAccount); - CacheStore.invalidate(userAccount.getUserId()); + private void saveAside(UserAccount userAccount) { + dbManager.updateDb(userAccount); + cacheStore.invalidate(userAccount.getUserId()); } /** * Cache-Aside find user account helper. */ - private static UserAccount findAside(String userId) { - return Optional.ofNullable(CacheStore.get(userId)) + private 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)); + 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..9d3bef747 100644 --- a/caching/src/main/java/com/iluwatar/caching/CacheStore.java +++ b/caching/src/main/java/com/iluwatar/caching/CacheStore.java @@ -26,6 +26,8 @@ package com.iluwatar.caching; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; + +import com.iluwatar.caching.database.DbManager; import lombok.extern.slf4j.Slf4j; /** @@ -33,16 +35,20 @@ import lombok.extern.slf4j.Slf4j; */ @Slf4j public class CacheStore { + private static final int CAPACITY = 3; private static LruCache cache; + private DbManager dbManager; - private CacheStore() { + public CacheStore(DbManager dbManager) { + this.dbManager = dbManager; + initCapacity(CAPACITY); } /** * Init cache capacity. */ - public static void initCapacity(int capacity) { + public void initCapacity(int capacity) { if (cache == null) { cache = new LruCache(capacity); } else { @@ -53,13 +59,13 @@ public class CacheStore { /** * Get user account using read-through cache. */ - public static UserAccount readThrough(String userId) { + public UserAccount readThrough(String userId) { if (cache.contains(userId)) { LOGGER.info("# Cache Hit!"); return cache.get(userId); } LOGGER.info("# Cache Miss!"); - UserAccount userAccount = DbManager.readFromDb(userId); + UserAccount userAccount = dbManager.readFromDb(userId); cache.set(userId, userAccount); return userAccount; } @@ -67,11 +73,11 @@ public class CacheStore { /** * Get user account using write-through cache. */ - public static void writeThrough(UserAccount userAccount) { + public void writeThrough(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); } @@ -79,30 +85,30 @@ public class CacheStore { /** * Get user account using write-around cache. */ - public static void writeAround(UserAccount userAccount) { + public void writeAround(UserAccount userAccount) { if (cache.contains(userAccount.getUserId())) { - DbManager.updateDb(userAccount); + dbManager.updateDb(userAccount); cache.invalidate(userAccount.getUserId()); // Cache data has been updated -- remove older // version from cache. } else { - DbManager.writeToDb(userAccount); + dbManager.writeToDb(userAccount); } } /** * Get user account using read-through cache with write-back policy. */ - public static UserAccount readThroughWithWriteBackPolicy(String userId) { + public UserAccount readThroughWithWriteBackPolicy(String userId) { if (cache.contains(userId)) { LOGGER.info("# Cache Hit!"); return cache.get(userId); } LOGGER.info("# Cache Miss!"); - UserAccount userAccount = DbManager.readFromDb(userId); + 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; @@ -111,11 +117,11 @@ public class CacheStore { /** * Set user account. */ - public static void writeBehind(UserAccount userAccount) { + public void writeBehind(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 +129,7 @@ public class CacheStore { /** * Clears cache. */ - public static void clearCache() { + public void clearCache() { if (cache != null) { cache.clear(); } @@ -132,18 +138,18 @@ 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); } /** * Print user accounts. */ - public static String print() { + public String print() { return Optional.ofNullable(cache) .map(LruCache::getCacheDataInListForm) .orElse(List.of()) @@ -155,21 +161,21 @@ public class CacheStore { /** * Delegate to backing cache store. */ - public static UserAccount get(String userId) { + public UserAccount get(String userId) { return cache.get(userId); } /** * Delegate to backing cache store. */ - public static void set(String userId, UserAccount userAccount) { + public void set(String userId, UserAccount userAccount) { cache.set(userId, userAccount); } /** * Delegate to backing cache store. */ - public static void invalidate(String userId) { + public void invalidate(String userId) { cache.invalidate(userId); } } 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/database/DbManager.java b/caching/src/main/java/com/iluwatar/caching/database/DbManager.java new file mode 100644 index 000000000..d1ec2dd3f --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/database/DbManager.java @@ -0,0 +1,16 @@ +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 { + void connect(); + UserAccount readFromDb(String userId); + UserAccount writeToDb(UserAccount userAccount); + UserAccount updateDb(UserAccount 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..0e6ed9fe1 --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/database/DbManagerFactory.java @@ -0,0 +1,10 @@ +package com.iluwatar.caching.database; + +public class DbManagerFactory { + public static DbManager initDb(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..50a5d805d --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/database/MongoDb.java @@ -0,0 +1,81 @@ +package com.iluwatar.caching.database; + +import com.iluwatar.caching.UserAccount; +import com.iluwatar.caching.constants.CachingConstants; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.UpdateOptions; +import org.bson.Document; + +/** + * Implementation of DatabaseManager. + * implements base methods to work with MongoDb. + */ +public class MongoDb implements DbManager { + private MongoDatabase db; + + @Override + public void connect() { + MongoClient mongoClient = new MongoClient(); + db = mongoClient.getDatabase("test"); + } + + @Override + public UserAccount readFromDb(String userId) { + if (db == null) { + connect(); + } + 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); + } + + @Override + public UserAccount writeToDb(UserAccount userAccount) { + if (db == null) { + connect(); + } + 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()) + ); + return userAccount; + } + + @Override + public UserAccount updateDb(UserAccount userAccount) { + if (db == null) { + connect(); + } + 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()))); + return userAccount; + } + + @Override + public UserAccount upsertDb(UserAccount userAccount) { + if (db == null) { + connect(); + } + 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) + ); + 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..af67225ad --- /dev/null +++ b/caching/src/main/java/com/iluwatar/caching/database/VirtualDb.java @@ -0,0 +1,44 @@ +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 { + private Map virtualDB; + + @Override + public void connect() { + virtualDB = new HashMap<>(); + } + + @Override + public UserAccount readFromDb(String userId) { + if (virtualDB.containsKey(userId)) { + return virtualDB.get(userId); + } + return null; + } + + @Override + public UserAccount writeToDb(UserAccount userAccount) { + virtualDB.put(userAccount.getUserId(), userAccount); + return userAccount; + } + + @Override + public UserAccount updateDb(UserAccount userAccount) { + virtualDB.put(userAccount.getUserId(), userAccount); + return userAccount; + } + + @Override + public UserAccount upsertDb(UserAccount userAccount) { + return updateDb(userAccount); + } +} \ No newline at end of file diff --git a/caching/src/test/java/com/iluwatar/caching/CachingTest.java b/caching/src/test/java/com/iluwatar/caching/CachingTest.java index 8869a66ac..8a02869bc 100644 --- a/caching/src/test/java/com/iluwatar/caching/CachingTest.java +++ b/caching/src/test/java/com/iluwatar/caching/CachingTest.java @@ -43,9 +43,7 @@ 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