package de.rwth.idsg.bikeman.ixsi.service; import de.rwth.idsg.bikeman.domain.Booking; import de.rwth.idsg.bikeman.ixsi.BookingCheckTask; import de.rwth.idsg.bikeman.repository.BookingRepository; import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; import org.joda.time.Duration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; /** * We should identify reservations, that have been not used (i.e. no transaction started within the reservation * time period), and send (1) booking alert notification and (2) empty consumption to the IXSI server. * * @author Sevket Goekay <goekay@dbis.rwth-aachen.de> * @since 18.11.2015 */ @Slf4j @Service public class BookingCheckService { @Autowired private ScheduledExecutorService executorService; @Autowired private BookingRepository bookingRepository; @Autowired private ConsumptionPushService consumptionPushService; @Autowired private BookingAlertPushService bookingAlertPushService; // Key : ixsiBookingId private final ConcurrentHashMap<String, ScheduledFuture> lookupTable = new ConcurrentHashMap<>(); // Let's not check exactly at the end of the reservation, but some time later public static final int BUFFER_IN_MIN = 2; public void placedBooking(Booking booking) { log.debug("New booking is placed"); String ixsiBookingId = booking.getIxsiBookingId(); DateTime reservationEnd = booking.getReservation().getEndDateTime().toDateTime(); Duration duration = new Duration(DateTime.now(), reservationEnd.plusMinutes(BUFFER_IN_MIN)); BookingCheckTask c = new BookingCheckTask(this, ixsiBookingId, reservationEnd); ScheduledFuture ff = executorService.schedule(c, duration.getMillis(), TimeUnit.MILLISECONDS); lookupTable.put(booking.getIxsiBookingId(), ff); } public void changedBooking(Booking oldBooking, Booking newBooking) { log.debug("Booking is changed"); cancelledBooking(oldBooking); placedBooking(newBooking); } public void cancelledBooking(Booking booking) { log.debug("Booking is cancelled"); ScheduledFuture f = lookupTable.remove(booking.getIxsiBookingId()); if (f != null) { f.cancel(true); } } public void check(String ixsiBookingId, DateTime reservationEnd) { log.debug("Running the booking check"); try { boolean notUsed = bookingRepository.isNotUsedAndExpired(ixsiBookingId); if (notUsed) { log.debug("Booking '{}' is not used, reporting to IXSI server", ixsiBookingId); bookingAlertPushService.alertNotUsed(ixsiBookingId); consumptionPushService.reportNotUsed(ixsiBookingId, reservationEnd); } } finally { lookupTable.remove(ixsiBookingId); } } }