810241a9c34de54cfeff5f75eb55b55b266328b1
[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  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
23  */
24 class SoneModificationDetector {
25
26         private final Ticker ticker;
27         private final LockableFingerprintProvider lockableFingerprintProvider;
28         private final AtomicInteger insertionDelay;
29         private Optional<Long> lastModificationTime;
30         private String lastInsertFingerprint;
31         private String lastCheckFingerprint;
32
33         SoneModificationDetector(LockableFingerprintProvider lockableFingerprintProvider, AtomicInteger insertionDelay) {
34                 this(systemTicker(), lockableFingerprintProvider, insertionDelay);
35         }
36
37         @VisibleForTesting
38         SoneModificationDetector(Ticker ticker, LockableFingerprintProvider lockableFingerprintProvider, AtomicInteger insertionDelay) {
39                 this.ticker = ticker;
40                 this.lockableFingerprintProvider = lockableFingerprintProvider;
41                 this.insertionDelay = insertionDelay;
42                 lastCheckFingerprint = lastInsertFingerprint;
43         }
44
45         public boolean isEligibleForInsert() {
46                 if (lockableFingerprintProvider.isLocked()) {
47                         lastModificationTime = absent();
48                         lastCheckFingerprint = "";
49                         return false;
50                 }
51                 String fingerprint = lockableFingerprintProvider.getFingerprint();
52                 if (fingerprint.equals(lastInsertFingerprint)) {
53                         lastModificationTime = absent();
54                         lastCheckFingerprint = fingerprint;
55                         return false;
56                 }
57                 if (!Objects.equal(lastCheckFingerprint, fingerprint)) {
58                         lastModificationTime = of(ticker.read());
59                         lastCheckFingerprint = fingerprint;
60                         return false;
61                 }
62                 return insertionDelayHasPassed();
63         }
64
65         public String getLastInsertFingerprint() {
66                 return lastInsertFingerprint;
67         }
68
69         public void setFingerprint(String fingerprint) {
70                 lastInsertFingerprint = fingerprint;
71                 lastCheckFingerprint = lastInsertFingerprint;
72                 lastModificationTime = absent();
73         }
74
75         private boolean insertionDelayHasPassed() {
76                 return NANOSECONDS.toSeconds(ticker.read() - lastModificationTime.get()) >= insertionDelay.get();
77         }
78
79         public boolean isModified() {
80                 return !Objects.equal(lockableFingerprintProvider.getFingerprint(), lastInsertFingerprint);
81         }
82
83         /**
84          * Provider for a fingerprint and the information if a {@link Sone} is locked. This
85          * prevents us from having to lug a Sone object around.
86          *
87          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
88          */
89         static interface LockableFingerprintProvider {
90
91                 boolean isLocked();
92                 String getFingerprint();
93
94         }
95
96 }