✨ Add page to activate debug mode
[Sone.git] / src / main / java / net / pterodactylus / sone / core / SoneModificationDetector.java
1 package net.pterodactylus.sone.core;
2
3 import static com.google.common.base.Optional.absent;
4 import static com.google.common.base.Optional.of;
5 import static com.google.common.base.Ticker.systemTicker;
6 import static java.util.concurrent.TimeUnit.NANOSECONDS;
7
8 import java.util.concurrent.atomic.AtomicInteger;
9
10 import net.pterodactylus.sone.data.Sone;
11
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.base.Objects;
14 import com.google.common.base.Optional;
15 import com.google.common.base.Ticker;
16
17 /**
18  * Class that detects {@link Sone} modifications (as per their {@link
19  * Sone#getFingerprint() fingerprints} and determines when a modified Sone may
20  * be inserted.
21  */
22 class SoneModificationDetector {
23
24         private final Ticker ticker;
25         private final LockableFingerprintProvider lockableFingerprintProvider;
26         private final AtomicInteger insertionDelay;
27         private Optional<Long> lastModificationTime;
28         private String lastInsertFingerprint;
29         private String lastCheckFingerprint;
30
31         SoneModificationDetector(LockableFingerprintProvider lockableFingerprintProvider, AtomicInteger insertionDelay) {
32                 this(systemTicker(), lockableFingerprintProvider, insertionDelay);
33         }
34
35         @VisibleForTesting
36         SoneModificationDetector(Ticker ticker, LockableFingerprintProvider lockableFingerprintProvider, AtomicInteger insertionDelay) {
37                 this.ticker = ticker;
38                 this.lockableFingerprintProvider = lockableFingerprintProvider;
39                 this.insertionDelay = insertionDelay;
40                 lastCheckFingerprint = lastInsertFingerprint;
41         }
42
43         public boolean isEligibleForInsert() {
44                 if (lockableFingerprintProvider.isLocked()) {
45                         lastModificationTime = absent();
46                         lastCheckFingerprint = "";
47                         return false;
48                 }
49                 String fingerprint = lockableFingerprintProvider.getFingerprint();
50                 if (fingerprint.equals(lastInsertFingerprint)) {
51                         lastModificationTime = absent();
52                         lastCheckFingerprint = fingerprint;
53                         return false;
54                 }
55                 if (!Objects.equal(lastCheckFingerprint, fingerprint)) {
56                         lastModificationTime = of(ticker.read());
57                         lastCheckFingerprint = fingerprint;
58                         return false;
59                 }
60                 return insertionDelayHasPassed();
61         }
62
63         public String getLastInsertFingerprint() {
64                 return lastInsertFingerprint;
65         }
66
67         public void setFingerprint(String fingerprint) {
68                 lastInsertFingerprint = fingerprint;
69                 lastCheckFingerprint = lastInsertFingerprint;
70                 lastModificationTime = absent();
71         }
72
73         private boolean insertionDelayHasPassed() {
74                 return NANOSECONDS.toSeconds(ticker.read() - lastModificationTime.get()) >= insertionDelay.get();
75         }
76
77         public boolean isModified() {
78                 return !Objects.equal(lockableFingerprintProvider.getFingerprint(), lastInsertFingerprint);
79         }
80
81         /**
82          * Provider for a fingerprint and the information if a {@link Sone} is locked. This
83          * prevents us from having to lug a Sone object around.
84          */
85         static interface LockableFingerprintProvider {
86
87                 boolean isLocked();
88                 String getFingerprint();
89
90         }
91
92 }