package org.openstack.atlas.service.domain.services.impl; import org.openstack.atlas.service.domain.entities.*; import org.openstack.atlas.service.domain.exceptions.*; import org.openstack.atlas.service.domain.services.LoadBalancerStatusHistoryService; import org.openstack.atlas.service.domain.services.RateLimitingService; import org.openstack.atlas.service.domain.services.helpers.StringHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Calendar; import java.util.List; @Service public class RateLimitingServiceImpl extends BaseService implements RateLimitingService { private final Log LOG = LogFactory.getLog(RateLimitingServiceImpl.class); @Autowired private LoadBalancerStatusHistoryService loadBalancerStatusHistoryService; @Override public RateLimit get(Integer id) throws EntityNotFoundException, DeletedStatusException { return loadBalancerRepository.getRateLimitByLoadBalancerId(id); } @Override public List<RateLimit> retrieveLoadBalancerRateLimits() { return loadBalancerRepository.getRateLimitByExpiration(); } @Override @Transactional public void create(LoadBalancer dblb) throws UnprocessableEntityException, EntityNotFoundException, BadRequestException, ImmutableEntityException { LOG.debug("Entering " + getClass()); LoadBalancer dbLoadBalancer = loadBalancerRepository.getById(dblb.getId()); dblb.setAccountId(dbLoadBalancer.getAccountId()); if (isRateLimitValid(dblb)) { LOG.debug(String.format("Rate limit is invalid, expirationTime cannot be set prior to the current time.")); throw new BadRequestException("Must provide valid expiration time. cannot be set prior to the current time."); } if(dbLoadBalancer.getRateLimit() != null) { LOG.debug(String.format("Rate limit already exists for loadbalancer %d.", dblb.getId())); throw new BadRequestException("A rate limit already exists."); } LOG.debug("Updating the lb status to pending_update"); if(!loadBalancerRepository.testAndSetStatus(dbLoadBalancer.getAccountId(), dbLoadBalancer.getId(), LoadBalancerStatus.PENDING_UPDATE, false)) { String message = StringHelper.immutableLoadBalancer(dbLoadBalancer); LOG.warn(message); throw new ImmutableEntityException(message); } else { //Set status record loadBalancerStatusHistoryService.save(dbLoadBalancer.getAccountId(), dbLoadBalancer.getId(), LoadBalancerStatus.PENDING_UPDATE); } loadBalancerRepository.update(dbLoadBalancer); LOG.debug("Adding the rate limit to the database..."); loadBalancerRepository.createRateLimit(dbLoadBalancer, dblb.getRateLimit()); LOG.debug("Leaving " + getClass()); } @Override @Transactional(rollbackFor = {EntityNotFoundException.class, ImmutableEntityException.class, UnprocessableEntityException.class, BadRequestException.class}) public void update(LoadBalancer dbLb) throws EntityNotFoundException, UnprocessableEntityException, BadRequestException, ImmutableEntityException { LOG.debug("Entering " + getClass()); LoadBalancer dbLoadBalancer = loadBalancerRepository.getById(dbLb.getId()); if (dbLoadBalancer.getRateLimit() == null) { LOG.debug(String.format("Rate limit does not exist for loadbalancer %d.", dbLb.getId())); throw new EntityNotFoundException("No rate limit to update."); } if (isRateLimitValid(dbLb)) { LOG.debug(String.format("Rate limit is invalid, expirationTime cannot be set prior to the current time.")); throw new BadRequestException("Must provide valid expiration time. cannot be set prior to the current time."); } RateLimit queueRateLimit = dbLb.getRateLimit(); RateLimit dbRateLimit = dbLoadBalancer.getRateLimit(); RateLimit newRateLimit = new RateLimit(); if(queueRateLimit.getExpirationTime() != null) newRateLimit.setExpirationTime(queueRateLimit.getExpirationTime()); else newRateLimit.setExpirationTime(dbRateLimit.getExpirationTime()); if(queueRateLimit.getMaxRequestsPerSecond() != null) newRateLimit.setMaxRequestsPerSecond(queueRateLimit.getMaxRequestsPerSecond()); else newRateLimit.setMaxRequestsPerSecond(dbRateLimit.getMaxRequestsPerSecond()); LOG.debug("Updating the lb status to pending_update"); if(!loadBalancerRepository.testAndSetStatus(dbLoadBalancer.getAccountId(), dbLoadBalancer.getId(), LoadBalancerStatus.PENDING_UPDATE, false)) { String message = StringHelper.immutableLoadBalancer(dbLoadBalancer); LOG.warn(message); throw new ImmutableEntityException(message); } else { //Set status record loadBalancerStatusHistoryService.save(dbLoadBalancer.getAccountId(), dbLoadBalancer.getId(), LoadBalancerStatus.PENDING_UPDATE); } dbLb.setRateLimit(newRateLimit); loadBalancerRepository.update(dbLoadBalancer); LOG.debug("Updating the loadbalancer and rate limit in the database..."); loadBalancerRepository.updateRateLimit(dbLoadBalancer, dbLb.getRateLimit()); LOG.debug("Leaving " + getClass()); } @Override @Transactional(rollbackFor = {EntityNotFoundException.class, ImmutableEntityException.class, UnprocessableEntityException.class}) public void delete(LoadBalancer dbLb) throws EntityNotFoundException, UnprocessableEntityException, ImmutableEntityException { LOG.debug("Entering " + getClass()); LoadBalancer dbLoadBalancer = loadBalancerRepository.getById(dbLb.getId()); if (dbLoadBalancer.getRateLimit() == null) { LOG.debug(String.format("Rate limit does not exist for loadbalancer %d.", dbLb.getId())); throw new EntityNotFoundException("No rate limit to delete."); } LOG.debug("Updating the lb status to pending_update"); if(!loadBalancerRepository.testAndSetStatus(dbLoadBalancer.getAccountId(), dbLoadBalancer.getId(), LoadBalancerStatus.PENDING_UPDATE, false)) { String message = StringHelper.immutableLoadBalancer(dbLoadBalancer); LOG.warn(message); throw new ImmutableEntityException(message); } else { //Set status record loadBalancerStatusHistoryService.save(dbLoadBalancer.getAccountId(), dbLoadBalancer.getId(), LoadBalancerStatus.PENDING_UPDATE); } LOG.debug("Leaving " + getClass()); } @Override @Transactional public void pseudoDelete(LoadBalancer requestLb) throws EntityNotFoundException { LoadBalancer dbLb = loadBalancerRepository.getByIdAndAccountId(requestLb.getId(), requestLb.getAccountId()); loadBalancerRepository.removeRateLimit(dbLb); } @Override @Transactional public void removeLimitByExpiration(int id) { loadBalancerRepository.removeRateLimitByExpiration(id); } protected boolean isRateLimitValid(LoadBalancer lb) throws UnauthorizedException, EntityNotFoundException { RateLimit rl = lb.getRateLimit(); Calendar cal = Calendar.getInstance(); cal.add(Calendar.HOUR, -6); return rl.getExpirationTime().before(cal); } }