Move management of Sone following times to database.
[Sone.git] / src / main / java / net / pterodactylus / sone / database / memory / MemoryFriendDatabase.java
1 package net.pterodactylus.sone.database.memory;
2
3 import java.util.Collection;
4 import java.util.HashMap;
5 import java.util.Map;
6 import java.util.concurrent.locks.ReadWriteLock;
7 import java.util.concurrent.locks.ReentrantReadWriteLock;
8
9 import com.google.common.base.Optional;
10 import com.google.common.collect.HashMultimap;
11 import com.google.common.collect.Multimap;
12
13 /**
14  * In-memory implementation of friend-related functionality.
15  *
16  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
17  */
18 class MemoryFriendDatabase {
19
20         private final ReadWriteLock lock = new ReentrantReadWriteLock();
21         private final ConfigurationLoader configurationLoader;
22         private final Multimap<String, String> soneFriends = HashMultimap.create();
23         private final Map<String, Long> soneFollowingTimes = new HashMap<String, Long>();
24
25         MemoryFriendDatabase(ConfigurationLoader configurationLoader) {
26                 this.configurationLoader = configurationLoader;
27         }
28
29         void start() {
30                 loadSoneFollowingTimes();
31         }
32
33         private void loadSoneFollowingTimes() {
34                 Map<String, Long> soneFollowingTimes = configurationLoader.loadSoneFollowingTimes();
35                 lock.writeLock().lock();
36                 try {
37                         this.soneFollowingTimes.clear();
38                         this.soneFollowingTimes.putAll(soneFollowingTimes);
39                 } finally {
40                         lock.writeLock().unlock();
41                 }
42         }
43
44         void stop() {
45                 saveSoneFollowingTimes();
46         }
47
48         private void saveSoneFollowingTimes() {
49                 lock.readLock().lock();
50                 try {
51                         configurationLoader.saveSoneFollowingTimes(soneFollowingTimes);
52                 } finally {
53                         lock.readLock().unlock();
54                 }
55         }
56
57         Collection<String> getFriends(String localSoneId) {
58                 loadFriends(localSoneId);
59                 lock.readLock().lock();
60                 try {
61                         return soneFriends.get(localSoneId);
62                 } finally {
63                         lock.readLock().unlock();
64                 }
65         }
66
67         Optional<Long> getSoneFollowingTime(String soneId) {
68                 lock.readLock().lock();
69                 try {
70                         return Optional.fromNullable(soneFollowingTimes.get(soneId));
71                 } finally {
72                         lock.readLock().unlock();
73                 }
74         }
75
76         boolean isFriend(String localSoneId, String friendSoneId) {
77                 loadFriends(localSoneId);
78                 lock.readLock().lock();
79                 try {
80                         return soneFriends.containsEntry(localSoneId, friendSoneId);
81                 } finally {
82                         lock.readLock().unlock();
83                 }
84         }
85
86         void addFriend(String localSoneId, String friendSoneId) {
87                 loadFriends(localSoneId);
88                 lock.writeLock().lock();
89                 try {
90                         if (!soneFollowingTimes.containsKey(friendSoneId)) {
91                                 soneFollowingTimes.put(friendSoneId, System.currentTimeMillis());
92                                 saveSoneFollowingTimes();
93                         }
94                         if (soneFriends.put(localSoneId, friendSoneId)) {
95                                 configurationLoader.saveFriends(localSoneId, soneFriends.get(localSoneId));
96                         }
97                 } finally {
98                         lock.writeLock().unlock();
99                 }
100         }
101
102         void removeFriend(String localSoneId, String friendSoneId) {
103                 loadFriends(localSoneId);
104                 lock.writeLock().lock();
105                 try {
106                         if (soneFriends.remove(localSoneId, friendSoneId)) {
107                                 if (!soneFriends.containsValue(friendSoneId)) {
108                                         soneFollowingTimes.remove(friendSoneId);
109                                         saveSoneFollowingTimes();
110                                 }
111                                 configurationLoader.saveFriends(localSoneId, soneFriends.get(localSoneId));
112                         }
113                 } finally {
114                         lock.writeLock().unlock();
115                 }
116         }
117
118         private void loadFriends(String localSoneId) {
119                 lock.writeLock().lock();
120                 try {
121                         if (soneFriends.containsKey(localSoneId)) {
122                                 return;
123                         }
124                         soneFriends.putAll(localSoneId, configurationLoader.loadFriends(localSoneId));
125                 } finally {
126                         lock.writeLock().unlock();
127                 }
128         }
129
130 }