-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Task 46 : Implement RateLimiterServiceImpl and UserServiceImpl with J…
…ava Doc and Revision
- Loading branch information
1 parent
7b7a278
commit c3c67a1
Showing
2 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
src/main/java/com/springboot/ratelimiter/user/service/impl/RateLimiterServiceImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.springboot.ratelimiter.user.service.impl; | ||
|
||
import com.springboot.ratelimiter.user.service.RateLimiterService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.data.redis.core.RedisTemplate; | ||
import org.springframework.data.redis.core.ValueOperations; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
|
||
/** | ||
* Service class named {@link RateLimiterServiceImpl} implementing for rate limiting operations using Redis. | ||
* This service checks if the current request is allowed based on configured rate limiting rules. | ||
*/ | ||
@Service | ||
@RequiredArgsConstructor | ||
public class RateLimiterServiceImpl implements RateLimiterService { | ||
|
||
private final RedisTemplate<String, Object> redisTemplate; | ||
|
||
@Value("${rate.limiter.max.requests}") | ||
private int MAX_REQUESTS; | ||
|
||
@Value("${rate.limiter.time.window.seconds}") | ||
private int TIME_WINDOW_IN_SECONDS; | ||
|
||
/** | ||
* Checks if the current request is allowed based on rate limiting rules. | ||
* | ||
* @return true if the request is allowed, false otherwise | ||
*/ | ||
@Override | ||
public boolean isAllowed() { | ||
|
||
String key = "rate_limiter:" + "user_creation"; | ||
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue(); | ||
|
||
Integer currentCount = (Integer) valueOperations.get(key); | ||
if (currentCount == null) { | ||
valueOperations.set(key, 1, TIME_WINDOW_IN_SECONDS, TimeUnit.SECONDS); | ||
return true; | ||
} else if (currentCount < MAX_REQUESTS) { | ||
valueOperations.increment(key); | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
|
||
} | ||
|
||
} |
166 changes: 166 additions & 0 deletions
166
src/main/java/com/springboot/ratelimiter/user/service/impl/UserServiceImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package com.springboot.ratelimiter.user.service.impl; | ||
|
||
import com.springboot.ratelimiter.common.exception.ratelimit.RateLimitExceededException; | ||
import com.springboot.ratelimiter.common.exception.user.EmailAlreadyExistsException; | ||
import com.springboot.ratelimiter.common.exception.user.UserNotFoundException; | ||
import com.springboot.ratelimiter.common.model.page.CustomPage; | ||
import com.springboot.ratelimiter.user.User; | ||
import com.springboot.ratelimiter.user.mapper.CreateUserRequestToUserEntityMapper; | ||
import com.springboot.ratelimiter.user.mapper.ListUserEntityToListUserMapper; | ||
import com.springboot.ratelimiter.user.mapper.UpdateUserRequestToUserEntityMapper; | ||
import com.springboot.ratelimiter.user.mapper.UserEntityToUserMapper; | ||
import com.springboot.ratelimiter.user.model.UserEntity; | ||
import com.springboot.ratelimiter.user.payload.request.CreateUserRequest; | ||
import com.springboot.ratelimiter.user.payload.request.UpdateUserRequest; | ||
import com.springboot.ratelimiter.user.payload.request.UserPagingRequest; | ||
import com.springboot.ratelimiter.user.repository.UserRepository; | ||
import com.springboot.ratelimiter.user.service.RateLimiterService; | ||
import com.springboot.ratelimiter.user.service.UserService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.domain.Page; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
|
||
/** | ||
* Service class named {@link UserServiceImpl} implementing for managing user operations. | ||
*/ | ||
@Service | ||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
public class UserServiceImpl implements UserService { | ||
|
||
private final UserRepository userRepository; | ||
|
||
private final RateLimiterService rateLimiterService; | ||
|
||
private final UserEntityToUserMapper userEntityToUserMapper = UserEntityToUserMapper.initialize(); | ||
|
||
private final CreateUserRequestToUserEntityMapper createUserRequestToUserEntity = | ||
CreateUserRequestToUserEntityMapper.initialize(); | ||
|
||
private final ListUserEntityToListUserMapper listUserEntityToListUserMapper = | ||
ListUserEntityToListUserMapper.initialize(); | ||
|
||
/** | ||
* Creates a new user based on the provided CreateUserRequest. | ||
* | ||
* @param createUserRequest the CreateUserRequest containing user details | ||
* @return the created User object | ||
*/ | ||
@Override | ||
@Transactional | ||
public User createUser(CreateUserRequest createUserRequest) { | ||
|
||
if (!rateLimiterService.isAllowed()) { | ||
throw new RateLimitExceededException("Rate limit exceeded"); | ||
} | ||
|
||
if (userRepository.existsByEmail(createUserRequest.getEmail())) { | ||
throw new EmailAlreadyExistsException(createUserRequest.getEmail()); | ||
} | ||
|
||
final UserEntity userEntityToBeSaved = createUserRequestToUserEntity.map(createUserRequest); | ||
final UserEntity savedUserEntity = userRepository.save(userEntityToBeSaved); | ||
return userEntityToUserMapper.map(savedUserEntity); | ||
|
||
} | ||
|
||
/** | ||
* Retrieves a user by their unique identifier. | ||
* | ||
* @param id the identifier of the user to retrieve | ||
* @return the User object if found, otherwise null | ||
*/ | ||
@Override | ||
public User getUserById(String id) { | ||
|
||
if (!rateLimiterService.isAllowed()) { | ||
throw new RateLimitExceededException("Rate limit exceeded"); | ||
} | ||
|
||
final UserEntity userEntity = userRepository.findById(id) | ||
.orElseThrow(() -> new UserNotFoundException(id)); | ||
return userEntityToUserMapper.map(userEntity); | ||
|
||
} | ||
|
||
/** | ||
* Updates an existing user identified by their unique identifier. | ||
* | ||
* @param id the identifier of the user to update | ||
* @param updateUserRequest the UpdateUserRequest containing updated user details | ||
* @return the updated User object | ||
*/ | ||
@Override | ||
@Transactional | ||
public User updateUser(String id, UpdateUserRequest updateUserRequest) { | ||
|
||
if (!rateLimiterService.isAllowed()) { | ||
throw new RateLimitExceededException("Rate limit exceeded"); | ||
} | ||
|
||
if (userRepository.existsByEmail(updateUserRequest.getEmail())) { | ||
throw new EmailAlreadyExistsException(updateUserRequest.getEmail()); | ||
} | ||
|
||
final UserEntity userEntity = userRepository.findById(id) | ||
.orElseThrow(() -> new UserNotFoundException(id)); | ||
|
||
|
||
UserEntity userEntityToBeUpdated = UpdateUserRequestToUserEntityMapper | ||
.mapForUpdate(userEntity, updateUserRequest); | ||
|
||
final UserEntity userEntityUpdated = userRepository.save(userEntityToBeUpdated); | ||
|
||
return userEntityToUserMapper.map(userEntityUpdated); | ||
|
||
} | ||
|
||
/** | ||
* Deletes a user by their unique identifier. | ||
* | ||
* @param id the identifier of the user to delete | ||
*/ | ||
@Override | ||
@Transactional | ||
public void deleteUserById(String id) { | ||
|
||
if (!rateLimiterService.isAllowed()) { | ||
throw new RateLimitExceededException("Rate limit exceeded"); | ||
} | ||
|
||
UserEntity userEntity = userRepository.findById(id) | ||
.orElseThrow(() -> new UserNotFoundException(id)); | ||
|
||
userRepository.delete(userEntity); | ||
|
||
} | ||
|
||
/** | ||
* Retrieves a paginated list of users based on the provided UserPagingRequest. | ||
* | ||
* @param userPagingRequest the UserPagingRequest containing pagination parameters | ||
* @return a CustomPage containing the list of users | ||
*/ | ||
@Override | ||
public CustomPage<User> getUsers(UserPagingRequest userPagingRequest) { | ||
|
||
if (!rateLimiterService.isAllowed()) { | ||
throw new RateLimitExceededException("Rate limit exceeded"); | ||
} | ||
|
||
final Page<UserEntity> userEntityPage = userRepository.findAll(userPagingRequest.toPageable()); | ||
|
||
if (userEntityPage.getContent().isEmpty()) { | ||
throw new UserNotFoundException("Couldn't find any User"); | ||
} | ||
|
||
final List<User> userDomainModels = listUserEntityToListUserMapper.toUserList(userEntityPage.getContent()); | ||
|
||
return CustomPage.of(userDomainModels, userEntityPage); | ||
|
||
} | ||
|
||
} |