diff --git a/src/main/java/swiss/fihlon/apus/service/ConferenceService.java b/src/main/java/swiss/fihlon/apus/service/ConferenceService.java index 5eba1e1..cac4b48 100644 --- a/src/main/java/swiss/fihlon/apus/service/ConferenceService.java +++ b/src/main/java/swiss/fihlon/apus/service/ConferenceService.java @@ -17,10 +17,13 @@ */ package swiss.fihlon.apus.service; -import org.springframework.scheduling.annotation.Scheduled; +import jakarta.annotation.PreDestroy; +import org.jetbrains.annotations.NotNull; +import org.springframework.scheduling.TaskScheduler; import org.springframework.stereotype.Service; import swiss.fihlon.apus.conference.Session; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; @@ -28,21 +31,26 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ScheduledFuture; import static java.util.stream.Collectors.groupingBy; @Service public final class ConferenceService { + private static final Duration UPDATE_FREQUENCY = Duration.ofMinutes(5); + + private final ScheduledFuture updateScheduler; private List sessions; - public ConferenceService() { + public ConferenceService(@NotNull final TaskScheduler taskScheduler) { updateSessions(); + updateScheduler = taskScheduler.scheduleAtFixedRate(this::updateSessions, UPDATE_FREQUENCY); } - @Scheduled(fixedRate = 300_000) // every five minutes - private void scheduler() { - updateSessions(); + @PreDestroy + public void stopUpdateScheduler() { + updateScheduler.cancel(true); } private void updateSessions() { diff --git a/src/main/java/swiss/fihlon/apus/service/SocialService.java b/src/main/java/swiss/fihlon/apus/service/SocialService.java index fa68be6..a4f1ed2 100644 --- a/src/main/java/swiss/fihlon/apus/service/SocialService.java +++ b/src/main/java/swiss/fihlon/apus/service/SocialService.java @@ -17,32 +17,40 @@ */ package swiss.fihlon.apus.service; -import org.springframework.scheduling.annotation.Scheduled; +import jakarta.annotation.PreDestroy; +import org.jetbrains.annotations.NotNull; +import org.springframework.scheduling.TaskScheduler; import org.springframework.stereotype.Service; import swiss.fihlon.apus.social.Message; import swiss.fihlon.apus.social.mastodon.MastodonAPI; +import java.time.Duration; import java.util.Collections; import java.util.List; +import java.util.concurrent.ScheduledFuture; @Service public final class SocialService { + private static final Duration UPDATE_FREQUENCY = Duration.ofMinutes(1); + + private final ScheduledFuture updateScheduler; private final MastodonAPI mastodonAPI; - private List messages; + private List messages = List.of(); - public SocialService() { + public SocialService(@NotNull final TaskScheduler taskScheduler) { mastodonAPI = new MastodonAPI("ijug.social"); updateMessages(); + updateScheduler = taskScheduler.scheduleAtFixedRate(this::updateMessages, UPDATE_FREQUENCY); } - @Scheduled(fixedRate = 60_000) - private void scheduler() { - updateMessages(); + @PreDestroy + public void stopUpdateScheduler() { + updateScheduler.cancel(true); } private void updateMessages() { - final var newMessages = mastodonAPI.getMessages("hackergarten"); + final var newMessages = mastodonAPI.getMessages("duke"); synchronized (this) { messages = newMessages; } @@ -50,8 +58,11 @@ private void updateMessages() { public List getMessages(final int limit) { synchronized (this) { - final int toIndex = limit > 0 && limit < messages.size() ? limit : messages.size() - 1; - return Collections.unmodifiableList(limit == 0 ? messages : messages.subList(0, toIndex)); + if (limit <= 0 || messages.isEmpty()) { + return Collections.unmodifiableList(messages); + } + final int toIndex = limit < messages.size() ? limit : messages.size() - 1; + return Collections.unmodifiableList(messages.subList(0, toIndex)); } } diff --git a/src/main/java/swiss/fihlon/apus/ui/view/ConferenceView.java b/src/main/java/swiss/fihlon/apus/ui/view/ConferenceView.java index 3c8d67c..d9e535a 100644 --- a/src/main/java/swiss/fihlon/apus/ui/view/ConferenceView.java +++ b/src/main/java/swiss/fihlon/apus/ui/view/ConferenceView.java @@ -21,11 +21,13 @@ import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.H2; import org.jetbrains.annotations.NotNull; -import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.scheduling.TaskScheduler; import org.springframework.stereotype.Component; import swiss.fihlon.apus.conference.Session; import swiss.fihlon.apus.service.ConferenceService; +import java.time.Duration; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicInteger; @Component @@ -33,27 +35,34 @@ public final class ConferenceView extends Div { private static final int MAX_SESSIONS_IN_VIEW = 15; + private static final Duration UPDATE_FREQUENCY = Duration.ofMinutes(1); private final transient ConferenceService conferenceService; private final Div sessionContainer = new Div(); - public ConferenceView(@NotNull final ConferenceService conferenceService) { + public ConferenceView(@NotNull final ConferenceService conferenceService, + @NotNull final TaskScheduler taskScheduler) { this.conferenceService = conferenceService; setId("conference-view"); add(new H2("Agenda")); add(sessionContainer); updateConferenceSessions(); + final ScheduledFuture updateScheduler = taskScheduler.scheduleAtFixedRate(this::updateScheduler, UPDATE_FREQUENCY); + addDetachListener(event -> updateScheduler.cancel(true)); } - @Scheduled(fixedRate = 60_000) - private void scheduler() { + private void updateScheduler() { getUI().ifPresent(ui -> ui.access(this::updateConferenceSessions)); } private void updateConferenceSessions() { sessionContainer.removeAll(); var sessionCounter = new AtomicInteger(0); + addRunningSessions(sessionCounter); + addNextSessions(sessionCounter); + } + private void addRunningSessions(@NotNull final AtomicInteger sessionCounter) { final var runningSessions = conferenceService.getRunningSessions(); for (final Session session : runningSessions) { final var sessionView = new SessionView(session); @@ -63,7 +72,9 @@ private void updateConferenceSessions() { break; } } + } + private void addNextSessions(@NotNull final AtomicInteger sessionCounter) { // There is space for 15 sessions on the screen, 5 rows with 3 sessions each. // Fill up free space with next sessions. if (sessionCounter.get() < MAX_SESSIONS_IN_VIEW) { diff --git a/src/main/java/swiss/fihlon/apus/ui/view/SocialView.java b/src/main/java/swiss/fihlon/apus/ui/view/SocialView.java index f7cb636..5a5899b 100644 --- a/src/main/java/swiss/fihlon/apus/ui/view/SocialView.java +++ b/src/main/java/swiss/fihlon/apus/ui/view/SocialView.java @@ -21,28 +21,35 @@ import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.H2; import org.jetbrains.annotations.NotNull; -import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.scheduling.TaskScheduler; import org.springframework.stereotype.Component; import swiss.fihlon.apus.service.SocialService; import swiss.fihlon.apus.social.Message; +import java.time.Duration; +import java.util.concurrent.ScheduledFuture; + @Component @CssImport(value = "./themes/apus/views/social-view.css") public final class SocialView extends Div { + private static final Duration UPDATE_FREQUENCY = Duration.ofMinutes(1); + private final transient SocialService socialService; private final Div messageContainer = new Div(); - public SocialView(@NotNull final SocialService socialService) { + public SocialView(@NotNull final SocialService socialService, + @NotNull final TaskScheduler taskScheduler) { this.socialService = socialService; setId("social-view"); add(new H2("#JavaLand on Mastodon")); add(messageContainer); updateMessages(); + final ScheduledFuture updateScheduler = taskScheduler.scheduleAtFixedRate(this::updateScheduler, UPDATE_FREQUENCY); + addDetachListener(event -> updateScheduler.cancel(true)); } - @Scheduled(fixedRate = 60_000) - private void scheduler() { + private void updateScheduler() { getUI().ifPresent(ui -> ui.access(this::updateMessages)); } diff --git a/src/main/java/swiss/fihlon/apus/ui/view/SocialWallView.java b/src/main/java/swiss/fihlon/apus/ui/view/SocialWallView.java index 23f97ab..84a1940 100644 --- a/src/main/java/swiss/fihlon/apus/ui/view/SocialWallView.java +++ b/src/main/java/swiss/fihlon/apus/ui/view/SocialWallView.java @@ -21,15 +21,20 @@ import com.vaadin.flow.component.html.Div; import com.vaadin.flow.router.Route; import org.jetbrains.annotations.NotNull; +import org.springframework.scheduling.TaskScheduler; +import swiss.fihlon.apus.service.ConferenceService; +import swiss.fihlon.apus.service.SocialService; @Route("") @CssImport(value = "./themes/apus/views/social-wall-view.css") public final class SocialWallView extends Div { - public SocialWallView(@NotNull final ConferenceView conferenceview, - @NotNull final SocialView socialView) { + public SocialWallView(@NotNull final ConferenceService conferenceService, + @NotNull final SocialService socialService, + @NotNull final TaskScheduler taskScheduler) { setId("social-wall-view"); - add(conferenceview, socialView); + add(new ConferenceView(conferenceService, taskScheduler), + new SocialView(socialService, taskScheduler)); } } diff --git a/src/test/java/swiss/fihlon/apus/service/ConferenceServiceTest.java b/src/test/java/swiss/fihlon/apus/service/ConferenceServiceTest.java index 4c7f50a..1df0905 100644 --- a/src/test/java/swiss/fihlon/apus/service/ConferenceServiceTest.java +++ b/src/test/java/swiss/fihlon/apus/service/ConferenceServiceTest.java @@ -18,6 +18,7 @@ package swiss.fihlon.apus.service; import org.junit.jupiter.api.Test; +import org.springframework.scheduling.support.NoOpTaskScheduler; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -25,7 +26,7 @@ class ConferenceServiceTest { @Test void displaySampleData() { - final ConferenceService conferenceService = new ConferenceService(); + final ConferenceService conferenceService = new ConferenceService(new NoOpTaskScheduler()); final var runningSessions = conferenceService.getRunningSessions(); assertEquals(15, runningSessions.size()); final var nextSessions = conferenceService.getNextSessions();