TedeeCallbackRegistration.java

1
package org.sanmibuh.tedee.lock.infrastructure.secondary;
2
3
import static org.sanmibuh.tedee.lock.infrastructure.TedeeInfrastructureConfiguration.*;
4
5
import com.tedee.bridge.client.api.CallbackApi;
6
import com.tedee.bridge.client.model.CallbackDetails;
7
import com.tedee.bridge.client.model.CallbackDetailsNoId;
8
import com.tedee.bridge.client.model.CallbackHeader;
9
import java.time.Clock;
10
import java.time.Duration;
11
import java.util.List;
12
import java.util.Objects;
13
import java.util.Optional;
14
import lombok.extern.slf4j.Slf4j;
15
import org.jspecify.annotations.Nullable;
16
import org.sanmibuh.tedee.ServerProperties;
17
import org.sanmibuh.tedee.lock.infrastructure.TedeeProperties;
18
import org.springframework.context.SmartLifecycle;
19
import org.springframework.http.HttpMethod;
20
import org.springframework.scheduling.TaskScheduler;
21
import org.springframework.stereotype.Component;
22
import org.springframework.web.client.RestClientException;
23
import org.springframework.web.util.UriComponentsBuilder;
24
25
@Slf4j
26
@Component
27
final class TedeeCallbackRegistration implements SmartLifecycle {
28
29
  private final CallbackApi callbackApi;
30
  private final String callbackUrl;
31
  private final String callbackSecret;
32
  private final Clock clock;
33
  private final TaskScheduler taskScheduler;
34
  private final Duration registrationRetryInterval;
35
  private boolean running;
36
  private @Nullable Long registeredId;
37
38
  TedeeCallbackRegistration(
39
      final CallbackApi callbackApi,
40
      final ServerProperties serverProperties,
41
      final TedeeProperties tedeeProperties,
42
      final Clock clock,
43
      final TaskScheduler taskScheduler) {
44
    this.callbackApi = callbackApi;
45
    callbackSecret = tedeeProperties.callbackSecret();
46
    this.clock = clock;
47
    this.taskScheduler = taskScheduler;
48
    registrationRetryInterval = tedeeProperties.callbackRegistrationInterval();
49
    callbackUrl =
50
        UriComponentsBuilder.fromUriString(serverProperties.publicUrl())
51
            .path(EVENTS_PATH)
52
            .toUriString();
53
  }
54
55
  @Override
56
  public synchronized void start() {
57
    running = true;
58 1 1. start : removed call to org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::registerCallback → KILLED
    registerCallback();
59
  }
60
61
  private void registerCallback() {
62
    try {
63
      registeredId =
64
          keepSingleExistingCallback()
65 1 1. lambda$registerCallback$0 : replaced Long return value with 0L for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::lambda$registerCallback$0 → KILLED
              .map(callback -> Objects.requireNonNull(callback.getId()))
66
              .orElseGet(this::register);
67
    } catch (final RestClientException exception) {
68
      log.warn("Could not register callback {} on the Tedee Bridge", callbackUrl, exception);
69 1 1. registerCallback : removed call to org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::scheduleRetry → KILLED
      scheduleRetry();
70
    }
71
  }
72
73
  @SuppressWarnings("FutureReturnValueIgnored")
74
  private void scheduleRetry() {
75
    taskScheduler.schedule(this::reregister, clock.instant().plus(registrationRetryInterval));
76
  }
77
78
  synchronized void reregister() {
79 1 1. reregister : negated conditional → KILLED
    if (running) {
80 1 1. reregister : removed call to org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::registerCallback → KILLED
      registerCallback();
81
    }
82
  }
83
84
  private Optional<CallbackDetails> keepSingleExistingCallback() {
85
    final var ourCallbacks = ourCallbacks();
86
    ourCallbacks.stream()
87
        .skip(1)
88 2 1. keepSingleExistingCallback : removed call to java/util/stream/Stream::forEach → KILLED
2. lambda$keepSingleExistingCallback$0 : removed call to org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::delete → KILLED
        .forEach(duplicate -> delete(Objects.requireNonNull(duplicate.getId())));
89 1 1. keepSingleExistingCallback : replaced return value with Optional.empty for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::keepSingleExistingCallback → KILLED
    return ourCallbacks.stream().findFirst();
90
  }
91
92
  private List<CallbackDetails> ourCallbacks() {
93 1 1. ourCallbacks : replaced return value with Collections.emptyList for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::ourCallbacks → KILLED
    return callbackApi.getCallback().stream()
94 2 1. lambda$ourCallbacks$0 : replaced boolean return with false for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::lambda$ourCallbacks$0 → KILLED
2. lambda$ourCallbacks$0 : replaced boolean return with true for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::lambda$ourCallbacks$0 → KILLED
        .filter(callback -> callbackUrl.equals(callback.getUrl()))
95
        .toList();
96
  }
97
98
  private long register() {
99
    final var registered =
100
        callbackApi.postSingleCallback(
101
            new CallbackDetailsNoId()
102
                .url(callbackUrl)
103
                .method(HttpMethod.POST.name())
104
                .addHeadersItem(
105
                    new CallbackHeader()
106
                        .headerName(CALLBACK_SECRET_HEADER + ": " + callbackSecret)));
107 1 1. register : replaced long return with 0 for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::register → KILLED
    return Objects.requireNonNull(registered.getId());
108
  }
109
110
  private void delete(final long callbackId) {
111 1 1. delete : removed call to com/tedee/bridge/client/api/CallbackApi::deleteCallback → KILLED
    callbackApi.deleteCallback(Math.toIntExact(callbackId));
112
  }
113
114
  @Override
115
  public synchronized void stop() {
116
    running = false;
117 1 1. stop : negated conditional → KILLED
    if (registeredId != null) {
118
      try {
119 1 1. stop : removed call to org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::delete → KILLED
        delete(registeredId);
120
      } catch (final RestClientException exception) {
121
        log.warn("Could not unregister callback {} from the Tedee Bridge", callbackUrl, exception);
122
      } finally {
123
        registeredId = null;
124
      }
125
    }
126
  }
127
128
  @Override
129
  public synchronized boolean isRunning() {
130 2 1. isRunning : replaced boolean return with true for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::isRunning → KILLED
2. isRunning : replaced boolean return with false for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::isRunning → KILLED
    return running;
131
  }
132
}

Mutations

58

1.1
Location : start
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_notPostCallback_whenCallbackAlreadyMatchesOurUrl()]
removed call to org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::registerCallback → KILLED

65

1.1
Location : lambda$registerCallback$0
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_reportNotRunning_whenStopped()]
replaced Long return value with 0L for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::lambda$registerCallback$0 → KILLED

69

1.1
Location : registerCallback
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_scheduleRetryAtConfiguredInterval_whenBridgeFails()]
removed call to org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::scheduleRetry → KILLED

79

1.1
Location : reregister
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_notRegisterCallback_whenReregisteringAfterStopped()]
negated conditional → KILLED

80

1.1
Location : reregister
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_registerCallback_whenBridgeRecoversAfterStartupFailure()]
removed call to org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::registerCallback → KILLED

88

1.1
Location : keepSingleExistingCallback
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_deleteDuplicateCallbacks_whenSeveralMatchOurUrl()]
removed call to java/util/stream/Stream::forEach → KILLED

2.2
Location : lambda$keepSingleExistingCallback$0
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_deleteDuplicateCallbacks_whenSeveralMatchOurUrl()]
removed call to org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::delete → KILLED

89

1.1
Location : keepSingleExistingCallback
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_notPostCallback_whenCallbackAlreadyMatchesOurUrl()]
replaced return value with Optional.empty for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::keepSingleExistingCallback → KILLED

93

1.1
Location : ourCallbacks
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_notPostCallback_whenCallbackAlreadyMatchesOurUrl()]
replaced return value with Collections.emptyList for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::ourCallbacks → KILLED

94

1.1
Location : lambda$ourCallbacks$0
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_notPostCallback_whenCallbackAlreadyMatchesOurUrl()]
replaced boolean return with false for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::lambda$ourCallbacks$0 → KILLED

2.2
Location : lambda$ourCallbacks$0
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_notPostCallback_whenCallbackAlreadyMatchesOurUrl()]
replaced boolean return with true for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::lambda$ourCallbacks$0 → KILLED

107

1.1
Location : register
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_deleteRegisteredCallback_whenStoppedAfterRegistering()]
replaced long return with 0 for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::register → KILLED

111

1.1
Location : delete
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_deleteDuplicateCallbacks_whenSeveralMatchOurUrl()]
removed call to com/tedee/bridge/client/api/CallbackApi::deleteCallback → KILLED

117

1.1
Location : stop
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_notCallBridge_whenStoppedWhileNotRunning()]
negated conditional → KILLED

119

1.1
Location : stop
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_deleteRegisteredCallback_whenStoppedAfterRegistering()]
removed call to org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::delete → KILLED

130

1.1
Location : isRunning
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_notRegisterCallback_whenReregisteringAfterStopped()]
replaced boolean return with true for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::isRunning → KILLED

2.2
Location : isRunning
Killed by : org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest.[engine:junit-jupiter]/[class:org.sanmibuh.tedee.lock.infrastructure.secondary.TedeeCallbackRegistrationTest]/[method:should_remainRunningWithoutCallback_whenBridgeFails()]
replaced boolean return with false for org/sanmibuh/tedee/lock/infrastructure/secondary/TedeeCallbackRegistration::isRunning → KILLED

Active mutators

Tests examined


Report generated by PIT 1.30.0 support