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;
|
package com.iluwatar.caching;
|
||||||
|
|
||||||
import com.iluwatar.caching.database.DbManager;
|
import com.iluwatar.caching.database.DbManager;
|
||||||
@ -28,33 +5,42 @@ import com.iluwatar.caching.database.DbManagerFactory;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Caching pattern describes how to avoid expensive re-acquisition of resources by not releasing
|
* The Caching pattern describes how to avoid expensive re-acquisition of
|
||||||
* the resources immediately after their use. The resources retain their identity, are kept in some
|
* resources by not releasing the resources immediately after their use.
|
||||||
* fast-access storage, and are re-used to avoid having to acquire them again. There are four main
|
* The resources retain their identity, are kept in some fast-access storage,
|
||||||
* caching strategies/techniques in this pattern; each with their own pros and cons. They are;
|
* and are re-used to avoid having to acquire them again. There are four main
|
||||||
* <code>write-through</code> which writes data to the cache and DB in a single transaction,
|
* caching strategies/techniques in this pattern; each with their own pros and
|
||||||
* <code>write-around</code> which writes data immediately into the DB instead of the cache,
|
* cons. They are <code>write-through</code> which writes data to the cache and
|
||||||
* <code>write-behind</code> which writes data into the cache initially whilst the data is only
|
* DB in a single transaction, <code>write-around</code> which writes data
|
||||||
* written into the DB when the cache is full, and <code>cache-aside</code> which pushes the
|
* immediately into the DB instead of the cache, <code>write-behind</code>
|
||||||
* responsibility of keeping the data synchronized in both data sources to the application itself.
|
* which writes data into the cache initially whilst the data is only
|
||||||
* The <code>read-through</code> strategy is also included in the mentioned four strategies --
|
* written into the DB when the cache is full, and <code>cache-aside</code>
|
||||||
* returns data from the cache to the caller <b>if</b> it exists <b>else</b> queries from DB and
|
* which pushes the responsibility of keeping the data synchronized in both
|
||||||
* stores it into the cache for future use. These strategies determine when the data in the cache
|
* data sources to the application itself. The <code>read-through</code>
|
||||||
* should be written back to the backing store (i.e. Database) and help keep both data sources
|
* strategy is also included in the mentioned four strategies --
|
||||||
* synchronized/up-to-date. This pattern can improve performance and also helps to maintain
|
* returns data from the cache to the caller <b>if</b> it exists <b>else</b>
|
||||||
* consistency between data held in the cache and the data in the underlying data store.
|
* 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
|
* <p>In this example, the user account ({@link UserAccount}) entity is used
|
||||||
* application data. The cache itself is implemented as an internal (Java) data structure. It adopts
|
* as the underlying application data. The cache itself is implemented as an
|
||||||
* a Least-Recently-Used (LRU) strategy for evicting data from itself when its full. The four
|
* internal (Java) data structure. It adopts a Least-Recently-Used (LRU)
|
||||||
* strategies are individually tested. The testing of the cache is restricted towards saving and
|
* strategy for evicting data from itself when its full. The four
|
||||||
* querying of user accounts from the underlying data store ( {@link DbManager}). The main class (
|
* strategies are individually tested. The testing of the cache is restricted
|
||||||
* {@link App} is not aware of the underlying mechanics of the application (i.e. save and query) and
|
* towards saving and querying of user accounts from the
|
||||||
* whether the data is coming from the cache or the DB (i.e. separation of concern). The AppManager
|
* underlying data store( {@link DbManager}). The main class ( {@link App}
|
||||||
* ({@link AppManager}) handles the transaction of data to-and-from the underlying data store
|
* is not aware of the underlying mechanics of the application
|
||||||
* (depending on the preferred caching policy/strategy).
|
* (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>
|
* <p>
|
||||||
* <i>{@literal App --> AppManager --> CacheStore/LRUCache/CachingPolicy --> DBManager} </i>
|
* <i>{@literal App --> AppManager --> CacheStore/LRUCache/CachingPolicy -->
|
||||||
|
* DBManager} </i>
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
@ -68,10 +54,20 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class App {
|
public class App {
|
||||||
|
/**
|
||||||
|
* Constant parameter name to use mongoDB.
|
||||||
|
*/
|
||||||
private static final String USE_MONGO_DB = "--mongo";
|
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);
|
DbManager dbManager = DbManagerFactory.initDb(isMongo);
|
||||||
appManager = new AppManager(dbManager);
|
appManager = new AppManager(dbManager);
|
||||||
appManager.initDb();
|
appManager.initDb();
|
||||||
@ -82,20 +78,20 @@ public class App {
|
|||||||
*
|
*
|
||||||
* @param args command line args
|
* @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
|
// VirtualDB (instead of MongoDB) was used in running the JUnit tests
|
||||||
// and the App class to avoid Maven compilation errors. Set flag to
|
// and the App class to avoid Maven compilation errors. Set flag to
|
||||||
// true to run the tests with MongoDB (provided that MongoDB is
|
// true to run the tests with MongoDB (provided that MongoDB is
|
||||||
// installed and socket connection is open).
|
// installed and socket connection is open).
|
||||||
App app = new App(isDbMongo(args));
|
App app = new App(isDbMongo(args));
|
||||||
app.useReadAndWriteThroughStrategy();
|
app.useReadAndWriteThroughStrategy();
|
||||||
System.out.println("=====================================================");
|
System.out.println("==============================================");
|
||||||
app.useReadThroughAndWriteAroundStrategy();
|
app.useReadThroughAndWriteAroundStrategy();
|
||||||
System.out.println("=====================================================");
|
System.out.println("==============================================");
|
||||||
app.useReadThroughAndWriteBehindStrategy();
|
app.useReadThroughAndWriteBehindStrategy();
|
||||||
System.out.println("=====================================================");
|
System.out.println("==============================================");
|
||||||
app.useCacheAsideStategy();
|
app.useCacheAsideStategy();
|
||||||
System.out.println("=====================================================");
|
System.out.println("==============================================");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,7 +99,7 @@ public class App {
|
|||||||
* @param args input params
|
* @param args input params
|
||||||
* @return true if there is "--mongo" parameter in arguments
|
* @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) {
|
for (String arg : args) {
|
||||||
if (arg.equals(USE_MONGO_DB)) {
|
if (arg.equals(USE_MONGO_DB)) {
|
||||||
return true;
|
return true;
|
||||||
@ -156,9 +152,15 @@ public class App {
|
|||||||
LOGGER.info("# CachingPolicy.BEHIND");
|
LOGGER.info("# CachingPolicy.BEHIND");
|
||||||
appManager.initCachingPolicy(CachingPolicy.BEHIND);
|
appManager.initCachingPolicy(CachingPolicy.BEHIND);
|
||||||
|
|
||||||
var userAccount3 = new UserAccount("003", "Adam", "He likes food.");
|
var userAccount3 = new UserAccount("003",
|
||||||
var userAccount4 = new UserAccount("004", "Rita", "She hates cats.");
|
"Adam",
|
||||||
var userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard.");
|
"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(userAccount3);
|
||||||
appManager.save(userAccount4);
|
appManager.save(userAccount4);
|
||||||
@ -166,7 +168,9 @@ public class App {
|
|||||||
LOGGER.info(appManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
appManager.find("003");
|
appManager.find("003");
|
||||||
LOGGER.info(appManager.printCacheContent());
|
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);
|
appManager.save(userAccount6);
|
||||||
LOGGER.info(appManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
appManager.find("004");
|
appManager.find("004");
|
||||||
@ -181,9 +185,15 @@ public class App {
|
|||||||
appManager.initCachingPolicy(CachingPolicy.ASIDE);
|
appManager.initCachingPolicy(CachingPolicy.ASIDE);
|
||||||
LOGGER.info(appManager.printCacheContent());
|
LOGGER.info(appManager.printCacheContent());
|
||||||
|
|
||||||
var userAccount3 = new UserAccount("003", "Adam", "He likes food.");
|
var userAccount3 = new UserAccount("003",
|
||||||
var userAccount4 = new UserAccount("004", "Rita", "She hates cats.");
|
"Adam",
|
||||||
var userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard.");
|
"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(userAccount3);
|
||||||
appManager.save(userAccount4);
|
appManager.save(userAccount4);
|
||||||
appManager.save(userAccount5);
|
appManager.save(userAccount5);
|
||||||
|
@ -29,28 +29,41 @@ import com.iluwatar.caching.database.DbManager;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AppManager helps to bridge the gap in communication between the main class and the application's
|
* AppManager helps to bridge the gap in communication between the main class
|
||||||
* back-end. DB connection is initialized through this class. The chosen caching strategy/policy is
|
* and the application's back-end. DB connection is initialized through this
|
||||||
* also initialized here. Before the cache can be used, the size of the cache has to be set.
|
* class. The chosen caching strategy/policy is also initialized here.
|
||||||
* Depending on the chosen caching policy, AppManager will call the appropriate function in the
|
* Before the cache can be used, the size of the cache has to be set.
|
||||||
* CacheStore class.
|
* Depending on the chosen caching policy, AppManager will call the
|
||||||
|
* appropriate function in the CacheStore class.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AppManager {
|
public class AppManager {
|
||||||
|
/**
|
||||||
|
* Caching Policy.
|
||||||
|
*/
|
||||||
private static CachingPolicy cachingPolicy;
|
private static CachingPolicy cachingPolicy;
|
||||||
|
/**
|
||||||
|
* Database Manager.
|
||||||
|
*/
|
||||||
private final DbManager dbManager;
|
private final DbManager dbManager;
|
||||||
|
/**
|
||||||
|
* Cache Store.
|
||||||
|
*/
|
||||||
private final CacheStore cacheStore;
|
private final CacheStore cacheStore;
|
||||||
|
|
||||||
public AppManager(DbManager dbManager) {
|
/**
|
||||||
this.dbManager = dbManager;
|
* Constructor.
|
||||||
this.cacheStore = new CacheStore(dbManager);
|
* @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
|
* Developer/Tester is able to choose whether the application should use
|
||||||
* data storage or a simple Java data structure to (temporarily) store the data/objects during
|
* MongoDB as its underlying data storage or a simple Java data structure
|
||||||
* runtime.
|
* to (temporarily) store the data/objects during runtime.
|
||||||
*/
|
*/
|
||||||
public void initDb() {
|
public void initDb() {
|
||||||
dbManager.connect();
|
dbManager.connect();
|
||||||
@ -58,8 +71,9 @@ public class AppManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize caching policy.
|
* Initialize caching policy.
|
||||||
|
* @param policy is a {@link CachingPolicy}
|
||||||
*/
|
*/
|
||||||
public void initCachingPolicy(CachingPolicy policy) {
|
public void initCachingPolicy(final CachingPolicy policy) {
|
||||||
cachingPolicy = policy;
|
cachingPolicy = policy;
|
||||||
if (cachingPolicy == CachingPolicy.BEHIND) {
|
if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(cacheStore::flushCache));
|
Runtime.getRuntime().addShutdownHook(new Thread(cacheStore::flushCache));
|
||||||
@ -69,10 +83,13 @@ public class AppManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Find user account.
|
* 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);
|
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);
|
return cacheStore.readThrough(userId);
|
||||||
} else if (cachingPolicy == CachingPolicy.BEHIND) {
|
} else if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||||
return cacheStore.readThroughWithWriteBackPolicy(userId);
|
return cacheStore.readThroughWithWriteBackPolicy(userId);
|
||||||
@ -84,8 +101,9 @@ public class AppManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Save user account.
|
* Save user account.
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
public void save(UserAccount userAccount) {
|
public void save(final UserAccount userAccount) {
|
||||||
LOGGER.info("Save record!");
|
LOGGER.info("Save record!");
|
||||||
if (cachingPolicy == CachingPolicy.THROUGH) {
|
if (cachingPolicy == CachingPolicy.THROUGH) {
|
||||||
cacheStore.writeThrough(userAccount);
|
cacheStore.writeThrough(userAccount);
|
||||||
@ -98,25 +116,33 @@ public class AppManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns String.
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
public String printCacheContent() {
|
public String printCacheContent() {
|
||||||
return cacheStore.print();
|
return cacheStore.print();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache-Aside save user account helper.
|
* Cache-Aside save user account helper.
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
*/
|
*/
|
||||||
private void saveAside(UserAccount userAccount) {
|
private void saveAside(final UserAccount userAccount) {
|
||||||
dbManager.updateDb(userAccount);
|
dbManager.updateDb(userAccount);
|
||||||
cacheStore.invalidate(userAccount.getUserId());
|
cacheStore.invalidate(userAccount.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache-Aside find user account helper.
|
* 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))
|
return Optional.ofNullable(cacheStore.get(userId))
|
||||||
.or(() -> {
|
.or(() -> {
|
||||||
Optional<UserAccount> userAccount = Optional.ofNullable(dbManager.readFromDb(userId));
|
Optional<UserAccount> userAccount =
|
||||||
|
Optional.ofNullable(dbManager.readFromDb(userId));
|
||||||
userAccount.ifPresent(account -> cacheStore.set(userId, account));
|
userAccount.ifPresent(account -> cacheStore.set(userId, account));
|
||||||
return userAccount;
|
return userAccount;
|
||||||
})
|
})
|
||||||
|
@ -3,14 +3,38 @@ package com.iluwatar.caching.database;
|
|||||||
import com.iluwatar.caching.UserAccount;
|
import com.iluwatar.caching.UserAccount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>DBManager handles the communication with the underlying data store i.e. Database. It contains
|
* <p>DBManager handles the communication with the underlying data store i.e.
|
||||||
* the implemented methods for querying, inserting, and updating data. MongoDB was used as the
|
* Database. It contains the implemented methods for querying, inserting,
|
||||||
* database for the application.</p>
|
* and updating data. MongoDB was used as the database for the application.</p>
|
||||||
*/
|
*/
|
||||||
public interface DbManager {
|
public interface DbManager {
|
||||||
|
/**
|
||||||
|
* Connect to DB.
|
||||||
|
*/
|
||||||
void connect();
|
void connect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from DB.
|
||||||
|
* @param userId {@link String}
|
||||||
|
* @return {@link UserAccount}
|
||||||
|
*/
|
||||||
UserAccount readFromDb(String userId);
|
UserAccount readFromDb(String userId);
|
||||||
|
/**
|
||||||
|
* Write to DB.
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
|
* @return {@link UserAccount}
|
||||||
|
*/
|
||||||
UserAccount writeToDb(UserAccount userAccount);
|
UserAccount writeToDb(UserAccount userAccount);
|
||||||
|
/**
|
||||||
|
* Update record.
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
|
* @return {@link UserAccount}
|
||||||
|
*/
|
||||||
UserAccount updateDb(UserAccount userAccount);
|
UserAccount updateDb(UserAccount userAccount);
|
||||||
|
/**
|
||||||
|
* Update record or Insert if not exists.
|
||||||
|
* @param userAccount {@link UserAccount}
|
||||||
|
* @return {@link UserAccount}
|
||||||
|
*/
|
||||||
UserAccount upsertDb(UserAccount 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