CarpoolingServiceImpl.java
package net.andresbustamante.yafoot.core.services.impl;
import net.andresbustamante.yafoot.commons.exceptions.ApplicationException;
import net.andresbustamante.yafoot.commons.exceptions.DatabaseException;
import net.andresbustamante.yafoot.commons.model.UserContext;
import net.andresbustamante.yafoot.core.dao.CarDao;
import net.andresbustamante.yafoot.core.dao.MatchDao;
import net.andresbustamante.yafoot.core.events.CarpoolingRequestEvent;
import net.andresbustamante.yafoot.core.events.CarpoolingUpdateEvent;
import net.andresbustamante.yafoot.core.exceptions.UnauthorisedUserException;
import net.andresbustamante.yafoot.core.model.Car;
import net.andresbustamante.yafoot.core.model.Match;
import net.andresbustamante.yafoot.core.model.Player;
import net.andresbustamante.yafoot.core.model.Registration;
import net.andresbustamante.yafoot.core.services.CarpoolingService;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.List;
@Service
public class CarpoolingServiceImpl implements CarpoolingService {
private final CarDao carDAO;
private final MatchDao matchDAO;
private final RabbitTemplate rabbitTemplate;
@Value("${app.messaging.queues.carpooling.requests.name}")
private String carpoolingRequestsQueue;
@Value("${app.messaging.queues.carpooling.updates.name}")
private String carpoolingUpdatesQueue;
private final Logger log = LoggerFactory.getLogger(CarpoolingServiceImpl.class);
public CarpoolingServiceImpl(final CarDao carDAO, final MatchDao matchDAO, final RabbitTemplate rabbitTemplate) {
this.carDAO = carDAO;
this.matchDAO = matchDAO;
this.rabbitTemplate = rabbitTemplate;
}
@Transactional(readOnly = true)
@Override
public List<Car> findAvailableCarsByMatch(final Match match) throws DatabaseException {
if (match.isCarpoolingEnabled()) {
return carDAO.findCarsByMatch(match);
} else {
return Collections.emptyList();
}
}
@Transactional
@Override
public void updateCarpoolingInformation(final Match match, final Player player, final Car car,
final boolean isCarConfirmed, final UserContext ctx)
throws ApplicationException {
if (car.getId() != null) {
Car storedCar = carDAO.findCarById(car.getId());
if (storedCar != null && storedCar.getDriver().getEmail().equals(ctx.getUsername())) {
// The user is the owner of the car
Registration actualPlayerRegistration = null;
if (!player.equals(car.getDriver())) {
actualPlayerRegistration = matchDAO.loadRegistration(match, player);
}
matchDAO.updateCarForRegistration(match, player, car, isCarConfirmed);
if (actualPlayerRegistration != null && actualPlayerRegistration.isCarConfirmed() != isCarConfirmed) {
// Send notification for this update
processCarSeatUpdate(match, player, storedCar, isCarConfirmed);
}
log.info("Carpool update for match #{}: Player #{} confirmation modified for car #{}", match.getId(),
player.getId(), car.getId());
} else if (storedCar == null) {
throw new ApplicationException("car.not.found.error", "No car found for the given ID");
} else {
throw new UnauthorisedUserException("User not allowed to update carpooling details for registration");
}
} else {
throw new ApplicationException("car.not.found.error", "No car found as no valid ID was used");
}
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void processCarSeatRequest(final Match match, final Player player, final Car car, final UserContext ctx) {
CarpoolingRequestEvent event = new CarpoolingRequestEvent();
event.setPlayerId(player.getId());
event.setPlayerFirstName(player.getFirstName());
event.setMatchId(match.getId());
event.setMatchCode(match.getCode());
event.setCarId(car.getId());
event.setCarName(car.getName());
rabbitTemplate.convertAndSend(carpoolingRequestsQueue, event);
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void processTransportationChange(final Match match, final Car oldCar, final Car newCar,
final UserContext ctx)
throws ApplicationException {
List<Registration> registrations = matchDAO.findPassengerRegistrationsByCar(match, oldCar);
Car storedNewCar = (newCar != null && newCar.getId() != null) ? carDAO.findCarById(newCar.getId()) : null;
if (CollectionUtils.isNotEmpty(registrations)) {
if (storedNewCar != null && storedNewCar.getDriver().getEmail().equals(ctx.getUsername())) {
// Changing between two owned cars
if (storedNewCar.getNumSeats() >= registrations.size()) {
// Transfer the passengers to the new car
registrations.forEach(registration -> matchDAO.updateCarForRegistration(match,
registration.getPlayer(), storedNewCar, registration.isCarConfirmed()));
} else {
throw new ApplicationException("carpooling.passengers.transfer.failed",
"There are not enough seats for all your passengers");
}
} else if (storedNewCar == null && newCar != null) {
// Changing to an unregistered car
throw new ApplicationException("carpooling.passengers.transfer.failed",
"The new car must have been registered before this operation");
} else {
// Changing to a car belonging to somebody else or not using a car at all
registrations.forEach(registration -> matchDAO.resetCarDetails(match, registration.getPlayer()));
}
}
}
/**
* Sends a notification concerning an update on the carpooling request made by a player for a given car to go to a
* given match.
*
* @param match Match to go to
* @param player Player asking for a seat in carpooling
* @param car Selected car
* @param isCarSeatConfirmed Confirmation / refusal from the driver of the given car
*/
private void processCarSeatUpdate(final Match match, final Player player, final Car car,
final boolean isCarSeatConfirmed) {
CarpoolingUpdateEvent event = new CarpoolingUpdateEvent();
event.setCarId(car.getId());
event.setCarName(car.getName());
event.setMatchId(match.getId());
event.setMatchCode(match.getCode());
event.setPlayerId(player.getId());
event.setPlayerFirstName(player.getFirstName());
event.setCarSeatConfirmed(isCarSeatConfirmed ? 1 : 0);
rabbitTemplate.convertAndSend(carpoolingUpdatesQueue, event);
}
}