diff --git a/E-Stores-API/pom.xml b/E-Stores-API/pom.xml index ce38a4a..4cb163e 100644 --- a/E-Stores-API/pom.xml +++ b/E-Stores-API/pom.xml @@ -93,9 +93,16 @@ - com.google.guava - guava - 32.1.2-jre + org.springframework.boot + spring-boot-starter-cache + + + org.ehcache + ehcache + + + javax.cache + cache-api diff --git a/E-Stores-API/src/main/java/com/devb/estores/cache/CacheBeanConfig.java b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheBeanConfig.java new file mode 100644 index 0000000..c0cc594 --- /dev/null +++ b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheBeanConfig.java @@ -0,0 +1,32 @@ +package com.devb.estores.cache; + +import com.devb.estores.model.User; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.Duration; + +@Configuration +public class CacheBeanConfig { + + private CacheConfigurer configure(String cacheName, Class keyType, Class valueType, int heap, int offHeap, Duration ttl) { + return CacheConfigurer.builder() + .cacheName(cacheName) + .keyType(keyType) + .valueType(valueType) + .heap(heap) + .offHeap(offHeap) + .ttl(ttl) + .build(); + } + + @Bean + CacheConfigurer OtpCache() { + return this.configure(CacheName.OTP_CACHE, String.class, Integer.class, 10000, 1, Duration.ofMinutes(5)); + } + + @Bean + CacheConfigurer userCache() { + return this.configure(CacheName.USER_CACHE, String.class, User.class, 20000, 10, Duration.ofDays(1)); + } +} diff --git a/E-Stores-API/src/main/java/com/devb/estores/cache/CacheBeansConfig.java b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheBeansConfig.java deleted file mode 100644 index e29787d..0000000 --- a/E-Stores-API/src/main/java/com/devb/estores/cache/CacheBeansConfig.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.devb.estores.cache; - -import com.devb.estores.dto.Attempt; -import com.devb.estores.dto.OtpModel; -import com.devb.estores.model.User; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.time.Duration; - -@Configuration -public class CacheBeansConfig { - - @Bean - CacheStore otpCache(){ - return new CacheStore<>(Duration.ofMinutes(5)); - } - - @Bean - CacheStore userCacheStore(){ - return new CacheStore<>(Duration.ofMinutes(10)); - } - - @Bean - CacheStore attemptCacheStore(){ - return new CacheStore<>(Duration.ofMinutes(1)); - } -} diff --git a/E-Stores-API/src/main/java/com/devb/estores/cache/CacheConfigurer.java b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheConfigurer.java new file mode 100644 index 0000000..94a0402 --- /dev/null +++ b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheConfigurer.java @@ -0,0 +1,43 @@ +package com.devb.estores.cache; + +import lombok.Builder; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.ehcache.config.CacheConfiguration; +import org.ehcache.config.builders.CacheConfigurationBuilder; +import org.ehcache.config.builders.ExpiryPolicyBuilder; +import org.ehcache.config.builders.ResourcePoolsBuilder; +import org.ehcache.config.units.EntryUnit; +import org.ehcache.config.units.MemoryUnit; +import org.ehcache.jsr107.Eh107Configuration; + +import javax.cache.configuration.Configuration; +import java.time.Duration; + +@Getter +@Builder +@Slf4j +public class CacheConfigurer { + private String cacheName; + private Class keyType; + private Class valueType; + private int heap; + private int offHeap; + private Duration ttl; + + public Configuration getEhCacheConfiguration() { + log.info("Configuring Cache with name: {}, heap: {}, offHeap: {}, TTL: {}", this.cacheName, this.heap, this.offHeap, this.ttl.toMinutes() + " Minutes"); + ResourcePoolsBuilder resourcePoolsBuilder = ResourcePoolsBuilder.newResourcePoolsBuilder() + .heap(this.heap, EntryUnit.ENTRIES).offheap(this.offHeap > 0 ? this.offHeap : 10, MemoryUnit.MB); + + CacheConfiguration cacheConfiguration = CacheConfigurationBuilder + .newCacheConfigurationBuilder( + this.keyType, + this.valueType, + resourcePoolsBuilder) + .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(this.ttl)) + .build(); + + return Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfiguration); + } +} diff --git a/E-Stores-API/src/main/java/com/devb/estores/cache/CacheInitializer.java b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheInitializer.java new file mode 100644 index 0000000..82c4262 --- /dev/null +++ b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheInitializer.java @@ -0,0 +1,31 @@ +package com.devb.estores.cache; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.jcache.JCacheCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.cache.CacheManager; +import javax.cache.Caching; +import javax.cache.spi.CachingProvider; +import java.util.List; + +@Configuration +@EnableCaching +@Slf4j +public class CacheInitializer { + + @Bean + JCacheCacheManager cacheManager(List> cacheConfigurers) { + log.info("Configuring CacheManger, {} cache configurations found", cacheConfigurers.size()); + CachingProvider provider = Caching.getCachingProvider(); + CacheManager manager = provider.getCacheManager(); + + cacheConfigurers.forEach(cacheConfigurer -> { + manager.createCache(cacheConfigurer.getCacheName(), cacheConfigurer.getEhCacheConfiguration()); + }); + + return new JCacheCacheManager(manager); + } +} diff --git a/E-Stores-API/src/main/java/com/devb/estores/cache/CacheName.java b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheName.java new file mode 100644 index 0000000..8a0cd55 --- /dev/null +++ b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheName.java @@ -0,0 +1,6 @@ +package com.devb.estores.cache; + +public class CacheName { + public static final String OTP_CACHE = "otp-cache"; + public static final String USER_CACHE = "user-cache"; +} diff --git a/E-Stores-API/src/main/java/com/devb/estores/cache/CacheService.java b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheService.java new file mode 100644 index 0000000..cc02d23 --- /dev/null +++ b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheService.java @@ -0,0 +1,45 @@ +package com.devb.estores.cache; + +import lombok.AllArgsConstructor; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Service; + +@Service +@AllArgsConstructor +public class CacheService { + + private final CacheManager cacheManager; + + public boolean doEntry(String cacheName, K key, V value) { + Cache cache = cacheManager.getCache(cacheName); + if(cache != null) { + cache.put(key, value); + return true; + } else return false; + } + + public V getEntry(String cacheName, K key, Class type) { + Cache cache = cacheManager.getCache(cacheName); + if(cache != null) + return cache.get(key, type); + else return null; + } + + public boolean evictEntry(String cacheName, K key) { + Cache cache = cacheManager.getCache(cacheName); + if(cache != null) { + cache.evict(key); + return true; + } else return false; + } + + public boolean clearCache(String cacheName) { + Cache cache = cacheManager.getCache(cacheName); + if (cache != null) { + cache.clear(); + return true; + } + return false; + } +} diff --git a/E-Stores-API/src/main/java/com/devb/estores/cache/CacheStore.java b/E-Stores-API/src/main/java/com/devb/estores/cache/CacheStore.java deleted file mode 100644 index 27a823c..0000000 --- a/E-Stores-API/src/main/java/com/devb/estores/cache/CacheStore.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.devb.estores.cache; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import lombok.extern.slf4j.Slf4j; - -import java.time.Duration; - -@Slf4j -public class CacheStore { - - private final Cache cache; - - public CacheStore(Duration expiry) { - this.cache = CacheBuilder.newBuilder() - .expireAfterWrite(expiry) - .concurrencyLevel(Runtime.getRuntime().availableProcessors()).build(); - } - - public T get(String key){ - return cache.getIfPresent(key); - } - - public void add(String key, T value){ - cache.put(key, value); - } - - public void remove(String key){ - cache.invalidate(key); - } -} diff --git a/E-Stores-API/src/main/java/com/devb/estores/model/User.java b/E-Stores-API/src/main/java/com/devb/estores/model/User.java index 70b9ce2..3494ab0 100644 --- a/E-Stores-API/src/main/java/com/devb/estores/model/User.java +++ b/E-Stores-API/src/main/java/com/devb/estores/model/User.java @@ -6,6 +6,7 @@ import lombok.*; import org.hibernate.annotations.GenericGenerator; +import java.io.Serializable; import java.util.List; @Entity @@ -17,7 +18,7 @@ @AllArgsConstructor @NoArgsConstructor @ToString -public class User { +public class User implements Serializable { @Id @GeneratedValue(generator = "custom") @GenericGenerator(name = "custom", type = IdGenerator.class) diff --git a/E-Stores-API/src/main/java/com/devb/estores/serviceimpl/AuthServiceImpl.java b/E-Stores-API/src/main/java/com/devb/estores/serviceimpl/AuthServiceImpl.java index e52dc09..0e725b1 100644 --- a/E-Stores-API/src/main/java/com/devb/estores/serviceimpl/AuthServiceImpl.java +++ b/E-Stores-API/src/main/java/com/devb/estores/serviceimpl/AuthServiceImpl.java @@ -1,6 +1,7 @@ package com.devb.estores.serviceimpl; -import com.devb.estores.cache.CacheStore; +import com.devb.estores.cache.CacheName; +import com.devb.estores.cache.CacheService; import com.devb.estores.config.AppEnv; import com.devb.estores.dto.MessageData; import com.devb.estores.dto.OtpModel; @@ -41,13 +42,12 @@ public class AuthServiceImpl implements AuthService { private final UserRepo userRepo; private final PasswordEncoder passwordEncoder; private final MailService mailService; - private final CacheStore otpCache; - private final CacheStore userCacheStore; private final JwtService jwtService; private final AuthenticationManager authenticationManager; private final CookieManager cookieManager; private final Random random; private final AppEnv appEnv; + private final CacheService cacheService; public static final String FAILED_REFRESH = "Failed to refresh login"; public static final String FAILED_OTP_VERIFICATION = "Failed to verify OTP"; @@ -61,16 +61,14 @@ public String registerUser(UserRequest userRequest, UserRole role) { User user = mapToUserEntity(userRequest, role); // caching user data - userCacheStore.add(user.getEmail(), user); + cacheService.doEntry(CacheName.USER_CACHE, user.getEmail(), user); - // Generate the OTP and provide the ID of the OTP as a path variable to the confirmation link. - OtpModel otp = OtpModel.builder() - .otp(random.nextInt(100000, 999999)) - .email(user.getEmail()).build(); - otpCache.add(otp.getEmail(), otp); + // Generating OTP and caching to otp-cache + int otp = random.nextInt(100000, 999999); + cacheService.doEntry(CacheName.OTP_CACHE, user.getEmail(), otp); try { - sendOTPToMailId(user, otp.getOtp()); + sendOTPToMailId(user, otp); return "Verify Email using the OTP sent to " + user.getEmail(); } catch (MessagingException e) { throw new EmailNotFoundException("Failed to verify the email ID"); @@ -79,17 +77,19 @@ public String registerUser(UserRequest userRequest, UserRole role) { @Override public UserResponse verifyUserEmail(OtpModel otpModel) { - OtpModel otp = otpCache.get(otpModel.getEmail()); - User user = userCacheStore.get(otpModel.getEmail()); + Integer otp = cacheService.getEntry(CacheName.OTP_CACHE, otpModel.getEmail(), Integer.class); + User user = cacheService.getEntry(CacheName.USER_CACHE, otpModel.getEmail(), User.class); if (otp == null) throw new OtpExpiredException(FAILED_OTP_VERIFICATION); if (user == null) throw new RegistrationSessionExpiredException(FAILED_OTP_VERIFICATION); - if (otp.getOtp() != otpModel.getOtp()) throw new IncorrectOTPException(FAILED_OTP_VERIFICATION); + if (otp != otpModel.getOtp()) throw new IncorrectOTPException(FAILED_OTP_VERIFICATION); user.setEmailVerified(true); user = userRepo.save(user); - otpCache.remove(otpModel.getEmail()); + cacheService.evictEntry(CacheName.USER_CACHE, user.getEmail()); + cacheService.evictEntry(CacheName.OTP_CACHE, user.getEmail()); + try { sendConfirmationMail(user); return mapToUserResponse(user);