Fix 40 errors from checkstyle plugin run. 139 left))
This commit is contained in:
parent
a437f5b2eb
commit
3c213fcd69
@ -1,26 +1,3 @@
|
||||
/*
|
||||
* 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.database.DbManager;
|
||||
@ -28,33 +5,42 @@ import com.iluwatar.caching.database.DbManagerFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* The Caching pattern describes how to avoid expensive re-acquisition of resources by not releasing
|
||||
* the resources immediately after their use. The resources retain their identity, are kept in some
|
||||
* fast-access storage, and are re-used to avoid having to acquire them again. There are four main
|
||||
* caching strategies/techniques in this pattern; each with their own pros and cons. They are;
|
||||
* <code>write-through</code> which writes data to the cache and DB in a single transaction,
|
||||
* <code>write-around</code> which writes data immediately into the DB instead of the cache,
|
||||
* <code>write-behind</code> which writes data into the cache initially whilst the data is only
|
||||
* written into the DB when the cache is full, and <code>cache-aside</code> which pushes the
|
||||
* responsibility of keeping the data synchronized in both data sources to the application itself.
|
||||
* The <code>read-through</code> strategy is also included in the mentioned four strategies --
|
||||
* returns data from the cache to the caller <b>if</b> it exists <b>else</b> queries from DB and
|
||||
* stores it into the cache for future use. These strategies determine when the data in the cache
|
||||
* should be written back to the backing store (i.e. Database) and help keep both data sources
|
||||
* synchronized/up-to-date. This pattern can improve performance and also helps to maintain
|
||||
* consistency between data held in the cache and the data in the underlying data store.
|
||||
* The Caching pattern describes how to avoid expensive re-acquisition of
|
||||
* resources by not releasing the resources immediately after their use.
|
||||
* The resources retain their identity, are kept in some fast-access storage,
|
||||
* and are re-used to avoid having to acquire them again. There are four main
|
||||
* caching strategies/techniques in this pattern; each with their own pros and
|
||||
* cons. They are <code>write-through</code> which writes data to the cache and
|
||||
* DB in a single transaction, <code>write-around</code> which writes data
|
||||
* immediately into the DB instead of the cache, <code>write-behind</code>
|
||||
* which writes data into the cache initially whilst the data is only
|
||||
* written into the DB when the cache is full, and <code>cache-aside</code>
|
||||
* which pushes the responsibility of keeping the data synchronized in both
|
||||
* data sources to the application itself. The <code>read-through</code>
|
||||
* strategy is also included in the mentioned four strategies --
|
||||
* returns data from the cache to the caller <b>if</b> it exists <b>else</b>
|
||||
* queries from DB and stores it into the cache for future use. These strategies
|
||||
* determine when the data in the cache should be written back to the backing
|
||||
* store (i.e. Database) and help keep both data sources
|
||||
* synchronized/up-to-date. This pattern can improve performance and also helps
|
||||
* to maintainconsistency between data held in the cache and the data in
|
||||
* the underlying data store.
|
||||
*
|
||||
* <p>In this example, the user account ({@link UserAccount}) entity is used as the underlying
|
||||
* application data. The cache itself is implemented as an internal (Java) data structure. It adopts
|
||||
* a Least-Recently-Used (LRU) strategy for evicting data from itself when its full. The four
|
||||
* strategies are individually tested. The testing of the cache is restricted towards saving and
|
||||
* querying of user accounts from the underlying data store ( {@link DbManager}). The main class (
|
||||
* {@link App} is not aware of the underlying mechanics of the application (i.e. save and query) and
|
||||
* whether the data is coming from the cache or the DB (i.e. separation of concern). The AppManager
|
||||
* ({@link AppManager}) handles the transaction of data to-and-from the underlying data store
|
||||
* (depending on the preferred caching policy/strategy).
|
||||
* <p>In this example, the user account ({@link UserAccount}) entity is used
|
||||
* as the underlying application data. The cache itself is implemented as an
|
||||
* internal (Java) data structure. It adopts a Least-Recently-Used (LRU)
|
||||
* strategy for evicting data from itself when its full. The four
|
||||
* strategies are individually tested. The testing of the cache is restricted
|
||||
* towards saving and querying of user accounts from the
|
||||
* underlying data store( {@link DbManager}). The main class ( {@link App}
|
||||
* is not aware of the underlying mechanics of the application
|
||||
* (i.e. save and query) and whether the data is coming from the cache or the
|
||||
* DB (i.e. separation of concern). The AppManager ({@link AppManager}) handles
|
||||
* the transaction of data to-and-from the underlying data store (depending on
|
||||
* the preferred caching policy/strategy).
|
||||
* <p>
|
||||
* <i>{@literal App --> AppManager --> CacheStore/LRUCache/CachingPolicy --> DBManager} </i>
|
||||
* <i>{@literal App --> AppManager --> CacheStore/LRUCache/CachingPolicy -->
|
||||
* DBManager} </i>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
@ -68,10 +54,20 @@ import lombok.extern.slf4j.Slf4j;
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
/**
|
||||
* Constant parameter name to use mongoDB.
|
||||
*/
|
||||
private static final String USE_MONGO_DB = "--mongo";
|
||||
private AppManager appManager;
|
||||
/**
|
||||
* Application manager.
|
||||
*/
|
||||
private final AppManager appManager;
|
||||
|
||||
public App(boolean isMongo) {
|
||||
/**
|
||||
* Constructor of current App.
|
||||
* @param isMongo boolean
|
||||
*/
|
||||
public App(final boolean isMongo) {
|
||||
DbManager dbManager = DbManagerFactory.initDb(isMongo);
|
||||
appManager = new AppManager(dbManager);
|
||||
appManager.initDb();
|
||||
@ -82,20 +78,20 @@ public class App {
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] 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();
|
||||
System.out.println("=====================================================");
|
||||
System.out.println("==============================================");
|
||||
app.useReadThroughAndWriteAroundStrategy();
|
||||
System.out.println("=====================================================");
|
||||
System.out.println("==============================================");
|
||||
app.useReadThroughAndWriteBehindStrategy();
|
||||
System.out.println("=====================================================");
|
||||
System.out.println("==============================================");
|
||||
app.useCacheAsideStategy();
|
||||
System.out.println("=====================================================");
|
||||
System.out.println("==============================================");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,7 +99,7 @@ public class App {
|
||||
* @param args input params
|
||||
* @return true if there is "--mongo" parameter in arguments
|
||||
*/
|
||||
private static boolean isDbMongo(String[] args) {
|
||||
private static boolean isDbMongo(final String[] args) {
|
||||
for (String arg : args) {
|
||||
if (arg.equals(USE_MONGO_DB)) {
|
||||
return true;
|
||||
@ -156,9 +152,15 @@ public class App {
|
||||
LOGGER.info("# 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);
|
||||
@ -166,7 +168,9 @@ public class App {
|
||||
LOGGER.info(appManager.printCacheContent());
|
||||
appManager.find("003");
|
||||
LOGGER.info(appManager.printCacheContent());
|
||||
UserAccount userAccount6 = new UserAccount("006", "Yasha", "She is an only child.");
|
||||
UserAccount userAccount6 = new UserAccount("006",
|
||||
"Yasha",
|
||||
"She is an only child.");
|
||||
appManager.save(userAccount6);
|
||||
LOGGER.info(appManager.printCacheContent());
|
||||
appManager.find("004");
|
||||
@ -181,9 +185,15 @@ public class App {
|
||||
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);
|
||||
|
@ -29,28 +29,41 @@ import com.iluwatar.caching.database.DbManager;
|
||||
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 class AppManager {
|
||||
|
||||
/**
|
||||
* Caching Policy.
|
||||
*/
|
||||
private static CachingPolicy cachingPolicy;
|
||||
/**
|
||||
* Database Manager.
|
||||
*/
|
||||
private final DbManager dbManager;
|
||||
/**
|
||||
* Cache Store.
|
||||
*/
|
||||
private final CacheStore cacheStore;
|
||||
|
||||
public AppManager(DbManager dbManager) {
|
||||
this.dbManager = dbManager;
|
||||
this.cacheStore = new CacheStore(dbManager);
|
||||
/**
|
||||
* 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 void initDb() {
|
||||
dbManager.connect();
|
||||
@ -58,8 +71,9 @@ public class AppManager {
|
||||
|
||||
/**
|
||||
* Initialize caching policy.
|
||||
* @param policy is a {@link CachingPolicy}
|
||||
*/
|
||||
public void initCachingPolicy(CachingPolicy policy) {
|
||||
public void initCachingPolicy(final CachingPolicy policy) {
|
||||
cachingPolicy = policy;
|
||||
if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(cacheStore::flushCache));
|
||||
@ -69,10 +83,13 @@ public class AppManager {
|
||||
|
||||
/**
|
||||
* Find user account.
|
||||
* @param userId String
|
||||
* @return {@link UserAccount}
|
||||
*/
|
||||
public UserAccount find(String userId) {
|
||||
public UserAccount find(final String userId) {
|
||||
LOGGER.info("Trying to find {} in cache", userId);
|
||||
if (cachingPolicy == CachingPolicy.THROUGH || cachingPolicy == CachingPolicy.AROUND) {
|
||||
if (cachingPolicy == CachingPolicy.THROUGH
|
||||
|| cachingPolicy == CachingPolicy.AROUND) {
|
||||
return cacheStore.readThrough(userId);
|
||||
} else if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||
return cacheStore.readThroughWithWriteBackPolicy(userId);
|
||||
@ -84,8 +101,9 @@ public class AppManager {
|
||||
|
||||
/**
|
||||
* Save user account.
|
||||
* @param userAccount {@link UserAccount}
|
||||
*/
|
||||
public void save(UserAccount userAccount) {
|
||||
public void save(final UserAccount userAccount) {
|
||||
LOGGER.info("Save record!");
|
||||
if (cachingPolicy == CachingPolicy.THROUGH) {
|
||||
cacheStore.writeThrough(userAccount);
|
||||
@ -98,25 +116,33 @@ public class AppManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns String.
|
||||
* @return String
|
||||
*/
|
||||
public String printCacheContent() {
|
||||
return cacheStore.print();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache-Aside save user account helper.
|
||||
* @param userAccount {@link UserAccount}
|
||||
*/
|
||||
private void saveAside(UserAccount userAccount) {
|
||||
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 UserAccount findAside(String userId) {
|
||||
private UserAccount findAside(final String userId) {
|
||||
return Optional.ofNullable(cacheStore.get(userId))
|
||||
.or(() -> {
|
||||
Optional<UserAccount> userAccount = Optional.ofNullable(dbManager.readFromDb(userId));
|
||||
Optional<UserAccount> userAccount =
|
||||
Optional.ofNullable(dbManager.readFromDb(userId));
|
||||
userAccount.ifPresent(account -> cacheStore.set(userId, account));
|
||||
return userAccount;
|
||||
})
|
||||
|
@ -3,14 +3,38 @@ package com.iluwatar.caching.database;
|
||||
import com.iluwatar.caching.UserAccount;
|
||||
|
||||
/**
|
||||
* <p>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.</p>
|
||||
* <p>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.</p>
|
||||
*/
|
||||
public interface DbManager {
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Database classes
|
||||
*/
|
||||
package com.iluwatar.caching.database;
|
24
caching/src/main/java/com/iluwatar/caching/package-info.java
Normal file
24
caching/src/main/java/com/iluwatar/caching/package-info.java
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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;
|
Loading…
x
Reference in New Issue
Block a user