Fix issues in VALIDATE phase

This commit is contained in:
Victor Zalevskii 2021-08-27 15:29:58 +03:00
parent dabe4d2022
commit 49039843e5
9 changed files with 368 additions and 352 deletions

View File

@ -54,155 +54,155 @@ 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;
/**
* 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();
/**
* 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(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).
App app = new App(isDbMongo(args));
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;
}
/**
* Program entry point.
*
* @param args command line args
*/
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).
App app = new App(isDbMongo(args));
app.useReadAndWriteThroughStrategy();
String splitLine = "==============================================";
LOGGER.info(splitLine);
app.useReadThroughAndWriteAroundStrategy();
LOGGER.info(splitLine);
app.useReadThroughAndWriteBehindStrategy();
LOGGER.info(splitLine);
app.useCacheAsideStategy();
LOGGER.info(splitLine);
}
/**
* Read-through and write-through.
*/
public void useReadAndWriteThroughStrategy() {
LOGGER.info("# CachingPolicy.THROUGH");
appManager.initCachingPolicy(CachingPolicy.THROUGH);
/**
* 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;
}
var userAccount1 = new UserAccount("001", "John", "He is a boy.");
/**
* Read-through and write-through.
*/
public void useReadAndWriteThroughStrategy() {
LOGGER.info("# CachingPolicy.THROUGH");
appManager.initCachingPolicy(CachingPolicy.THROUGH);
appManager.save(userAccount1);
LOGGER.info(appManager.printCacheContent());
appManager.find("001");
appManager.find("001");
}
var userAccount1 = new UserAccount("001", "John", "He is a boy.");
/**
* Read-through and write-around.
*/
public void useReadThroughAndWriteAroundStrategy() {
LOGGER.info("# CachingPolicy.AROUND");
appManager.initCachingPolicy(CachingPolicy.AROUND);
appManager.save(userAccount1);
LOGGER.info(appManager.printCacheContent());
appManager.find("001");
appManager.find("001");
}
var userAccount2 = new UserAccount("002", "Jane", "She is a girl.");
/**
* Read-through and write-around.
*/
public void useReadThroughAndWriteAroundStrategy() {
LOGGER.info("# CachingPolicy.AROUND");
appManager.initCachingPolicy(CachingPolicy.AROUND);
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");
}
var userAccount2 = new UserAccount("002", "Jane", "She is a girl.");
/**
* Read-through and write-behind.
*/
public void useReadThroughAndWriteBehindStrategy() {
LOGGER.info("# CachingPolicy.BEHIND");
appManager.initCachingPolicy(CachingPolicy.BEHIND);
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");
}
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.");
/**
* Read-through and write-behind.
*/
public void useReadThroughAndWriteBehindStrategy() {
LOGGER.info("# CachingPolicy.BEHIND");
appManager.initCachingPolicy(CachingPolicy.BEHIND);
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());
}
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.");
/**
* Cache-Aside.
*/
public void useCacheAsideStategy() {
LOGGER.info("# CachingPolicy.ASIDE");
appManager.initCachingPolicy(CachingPolicy.ASIDE);
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());
}
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);
/**
* 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());
}
LOGGER.info(appManager.printCacheContent());
appManager.find("003");
LOGGER.info(appManager.printCacheContent());
appManager.find("004");
LOGGER.info(appManager.printCacheContent());
}
}

View File

@ -23,9 +23,9 @@
package com.iluwatar.caching;
import com.iluwatar.caching.database.DbManager;
import java.util.Optional;
import com.iluwatar.caching.database.DbManager;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@ -68,7 +68,7 @@ public class AppManager {
* to (temporarily) store the data/objects during runtime.
*/
public void initDb() {
dbManager.connect();
dbManager.connect();
}
/**

View File

@ -23,11 +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 com.iluwatar.caching.database.DbManager;
import lombok.extern.slf4j.Slf4j;
/**

View File

@ -29,6 +29,7 @@ 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
@ -62,7 +63,8 @@ public class LruCache {
/**
* Node definition.
* @param id String
*
* @param id String
* @param account {@link UserAccount}
*/
Node(final String id, final UserAccount account) {
@ -90,6 +92,7 @@ public class LruCache {
/**
* Constructor.
*
* @param cap Integer.
*/
public LruCache(final int cap) {
@ -98,6 +101,7 @@ public class LruCache {
/**
* Get user account.
*
* @param userId String
* @return {@link UserAccount}
*/
@ -113,6 +117,7 @@ public class LruCache {
/**
* Remove node from linked list.
*
* @param node {@link Node}
*/
public void remove(final Node node) {
@ -130,6 +135,7 @@ public class LruCache {
/**
* Move node to the front of the list.
*
* @param node {@link Node}
*/
public void setHead(final Node node) {
@ -146,8 +152,9 @@ public class LruCache {
/**
* Set user account.
*
* @param userAccount {@link UserAccount}
* @param userId {@link String}
* @param userId {@link String}
*/
public void set(final String userId, final UserAccount userAccount) {
if (cache.containsKey(userId)) {
@ -169,19 +176,21 @@ public class LruCache {
}
}
/**
* Che if Cache cintains the userId.
* @param userId {@link String}
* @return boolean
*/
/**
* Che if Cache cintains 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}
*/
/**
* Invalidate cache for user.
*
* @param userId {@link String}
*/
public void invalidate(final String userId) {
var toBeRemoved = cache.remove(userId);
if (toBeRemoved != null) {
@ -191,18 +200,19 @@ public class LruCache {
}
}
/**
* Is cache full?
* @return boolean
*/
/**
* Check if the cache is full.
* @return boolean
*/
public boolean isFull() {
return cache.size() >= capacity;
}
/**
* Get LRU data.
* @return {@link UserAccount}
*/
/**
* Get LRU data.
*
* @return {@link UserAccount}
*/
public UserAccount getLruData() {
return end.userAccount;
}
@ -218,6 +228,7 @@ public class LruCache {
/**
* Returns cache data in list form.
*
* @return {@link List}
*/
public List<UserAccount> getCacheDataInListForm() {
@ -232,6 +243,7 @@ public class LruCache {
/**
* Set cache capacity.
*
* @param newCapacity int
*/
public void setCapacity(final int newCapacity) {

View File

@ -8,33 +8,36 @@ import com.iluwatar.caching.UserAccount;
* and updating data. MongoDB was used as the database for the application.</p>
*/
public interface DbManager {
/**
* Connect to DB.
*/
void connect();
/**
* Connect to DB.
*/
void connect();
/**
* 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);
/**
* 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);
}

View File

@ -4,22 +4,22 @@ package com.iluwatar.caching.database;
* Creates the database connection accroding the input parameter.
*/
public final class DbManagerFactory {
/**
* Private constructor.
*/
private 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();
/**
* Init database.
*
* @param isMongo boolean
* @return {@link DbManager}
*/
public static DbManager initDb(final boolean isMongo) {
if (isMongo) {
return new MongoDb();
}
return new VirtualDb();
}
}

View File

@ -1,5 +1,10 @@
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;
@ -7,114 +12,109 @@ import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.UpdateOptions;
import org.bson.Document;
import static com.iluwatar.caching.constants.CachingConstants.USER_NAME;
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_ACCOUNT;
/**
* Implementation of DatabaseManager.
* implements base methods to work with MongoDb.
*/
public class MongoDb implements DbManager {
/**
* Mongo db.
*/
private MongoDatabase db;
/**
* Mongo db.
*/
private MongoDatabase db;
/**
* Connect to Db.
*/
@Override
public void connect() {
MongoClient mongoClient = new MongoClient();
db = mongoClient.getDatabase("test");
}
/**
* Connect to Db.
*/
@Override
public void connect() {
MongoClient mongoClient = new MongoClient();
db = mongoClient.getDatabase("test");
}
/**
* Read data from DB.
*
* @param userId {@link String}
* @return {@link UserAccount}
*/
@Override
public UserAccount readFromDb(final String userId) {
if (db == null) {
connect();
}
var iterable = db
.getCollection(CachingConstants.USER_ACCOUNT)
.find(new Document(USER_ID, userId));
if (iterable.first()==null) {
return null;
}
Document doc = iterable.first();
String userName = doc.getString(USER_NAME);
String appInfo = doc.getString(ADD_INFO);
return new UserAccount(userId, userName, appInfo);
/**
* Read data from DB.
*
* @param userId {@link String}
* @return {@link UserAccount}
*/
@Override
public UserAccount readFromDb(final String userId) {
if (db == null) {
connect();
}
var iterable = db
.getCollection(CachingConstants.USER_ACCOUNT)
.find(new Document(USER_ID, userId));
if (iterable.first() == null) {
return null;
}
Document doc = iterable.first();
String userName = doc.getString(USER_NAME);
String appInfo = doc.getString(ADD_INFO);
return new UserAccount(userId, userName, appInfo);
}
/**
* Write data to DB.
*
* @param userAccount {@link UserAccount}
* @return {@link UserAccount}
*/
@Override
public UserAccount writeToDb(final UserAccount userAccount) {
if (db == null) {
connect();
}
db.getCollection(USER_ACCOUNT).insertOne(
new Document(USER_ID, userAccount.getUserId())
.append(USER_NAME, userAccount.getUserName())
.append(ADD_INFO, userAccount.getAdditionalInfo())
);
return userAccount;
/**
* Write data to DB.
*
* @param userAccount {@link UserAccount}
* @return {@link UserAccount}
*/
@Override
public UserAccount writeToDb(final UserAccount userAccount) {
if (db == null) {
connect();
}
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) {
if (db == null) {
connect();
}
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 DB.
*
* @param userAccount {@link UserAccount}
* @return {@link UserAccount}
*/
@Override
public UserAccount updateDb(final UserAccount userAccount) {
if (db == null) {
connect();
}
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) {
if (db == null) {
connect();
}
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;
/**
* Update data if exists.
*
* @param userAccount {@link UserAccount}
* @return {@link UserAccount}
*/
@Override
public UserAccount upsertDb(final UserAccount userAccount) {
if (db == null) {
connect();
}
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;
}
}

View File

@ -10,60 +10,64 @@ import java.util.Map;
* implements base methods to work with hashMap as database.
*/
public class VirtualDb implements DbManager {
/**
* Virtual DataBase.
*/
private Map<String, UserAccount> db;
/**
* Virtual DataBase.
*/
private Map<String, UserAccount> db;
/**
* Creates new HashMap.
*/
@Override
public void connect() {
db = new HashMap<>();
}
/**
* Creates new HashMap.
*/
@Override
public void connect() {
db = new HashMap<>();
}
/**
* 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;
/**
* 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;
}
/**
* 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 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);
}
/**
* Update.
*
* @param userAccount {@link UserAccount}
* @return {@link UserAccount}
*/
@Override
public UserAccount upsertDb(final UserAccount userAccount) {
return updateDb(userAccount);
}
}

View File

@ -1,17 +1,14 @@
/**
* 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