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