2459c069487b69be21c6b6c31ebb7642ea0103d6
[Sone.git] / src / main / java / net / pterodactylus / sone / freenet / wot / IdentityManager.java
1 /*
2  * Sone - IdentityManager.java - Copyright © 2010–2013 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.freenet.wot;
19
20 import static com.google.common.collect.HashMultimap.create;
21
22 import java.util.Collection;
23 import java.util.HashSet;
24 import java.util.Set;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27
28 import net.pterodactylus.sone.freenet.plugin.PluginException;
29 import net.pterodactylus.sone.freenet.wot.IdentityChangeDetector.IdentityProcessor;
30 import net.pterodactylus.sone.freenet.wot.event.IdentityAddedEvent;
31 import net.pterodactylus.sone.freenet.wot.event.IdentityRemovedEvent;
32 import net.pterodactylus.sone.freenet.wot.event.IdentityUpdatedEvent;
33 import net.pterodactylus.sone.freenet.wot.event.OwnIdentityAddedEvent;
34 import net.pterodactylus.sone.freenet.wot.event.OwnIdentityRemovedEvent;
35 import net.pterodactylus.util.logging.Logging;
36 import net.pterodactylus.util.service.AbstractService;
37
38 import com.google.common.collect.Multimap;
39 import com.google.common.collect.Sets;
40 import com.google.common.eventbus.EventBus;
41 import com.google.inject.Inject;
42 import com.google.inject.name.Named;
43
44 /**
45  * The identity manager takes care of loading and storing identities, their
46  * contexts, and properties. It does so in a way that does not expose errors via
47  * exceptions but it only logs them and tries to return sensible defaults.
48  * <p/>
49  * It is also responsible for polling identities from the Web of Trust plugin
50  * and sending events to the {@link EventBus} when {@link Identity}s and {@link
51  * OwnIdentity}s are discovered or disappearing.
52  *
53  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
54  */
55 public class IdentityManager extends AbstractService {
56
57         /** The logger. */
58         private static final Logger logger = Logging.getLogger(IdentityManager.class);
59
60         /** The event bus. */
61         private final EventBus eventBus;
62
63         /** The Web of Trust connector. */
64         private final WebOfTrustConnector webOfTrustConnector;
65
66         /** The context to filter for. */
67         private final String context;
68
69         /** The currently known own identities. */
70         /* synchronize access on syncObject. */
71         private final Set<OwnIdentity> currentOwnIdentities = Sets.newHashSet();
72
73         /**
74          * Creates a new identity manager.
75          *
76          * @param eventBus
77          *              The event bus
78          * @param webOfTrustConnector
79          *              The Web of Trust connector
80          * @param context
81          *              The context to focus on (may be {@code null} to ignore contexts)
82          */
83         @Inject
84         public IdentityManager(EventBus eventBus, WebOfTrustConnector webOfTrustConnector, @Named("WebOfTrustContext") String context) {
85                 super("Sone Identity Manager", false);
86                 this.eventBus = eventBus;
87                 this.webOfTrustConnector = webOfTrustConnector;
88                 this.context = context;
89         }
90
91         //
92         // ACCESSORS
93         //
94
95         /**
96          * Returns whether the Web of Trust plugin could be reached during the last
97          * try.
98          *
99          * @return {@code true} if the Web of Trust plugin is connected, {@code false}
100          *         otherwise
101          */
102         public boolean isConnected() {
103                 try {
104                         webOfTrustConnector.ping();
105                         return true;
106                 } catch (PluginException pe1) {
107                         /* not connected, ignore. */
108                         return false;
109                 }
110         }
111
112         /**
113          * Returns all own identities.
114          *
115          * @return All own identities
116          */
117         public Set<OwnIdentity> getAllOwnIdentities() {
118                 synchronized (currentOwnIdentities) {
119                         return new HashSet<OwnIdentity>(currentOwnIdentities);
120                 }
121         }
122
123         //
124         // SERVICE METHODS
125         //
126
127         @Override
128         protected void serviceRun() {
129                 Multimap<OwnIdentity, Identity> oldIdentities = create();
130
131                 while (!shouldStop()) {
132                         try {
133                                 Collection<OwnIdentity> currentOwnIdentities = webOfTrustConnector.loadAllOwnIdentities();
134                                 Multimap<OwnIdentity, Identity> currentIdentities = loadTrustedIdentitiesForOwnIdentities(currentOwnIdentities);
135
136                                 detectChangesInIdentities(currentOwnIdentities, currentIdentities, oldIdentities);
137                                 oldIdentities = currentIdentities;
138
139                                 synchronized (currentOwnIdentities) {
140                                         this.currentOwnIdentities.clear();
141                                         this.currentOwnIdentities.addAll(currentOwnIdentities);
142                                 }
143                         } catch (WebOfTrustException wote1) {
144                                 logger.log(Level.WARNING, "WoT has disappeared!", wote1);
145                         }
146
147                         /* wait a minute before checking again. */
148                         sleep(60 * 1000);
149                 }
150         }
151
152         private void detectChangesInIdentities(Collection<OwnIdentity> currentOwnIdentities, Multimap<OwnIdentity, Identity> newIdentities, Multimap<OwnIdentity, Identity> oldIdentities) {
153                 IdentityChangeDetector identityChangeDetector = new IdentityChangeDetector(getAllOwnIdentities());
154                 identityChangeDetector.onNewIdentity(addNewOwnIdentityAndItsTrustedIdentities(newIdentities));
155                 identityChangeDetector.onRemovedIdentity(removeOwnIdentityAndItsTrustedIdentities(oldIdentities));
156                 identityChangeDetector.onUnchangedIdentity(detectChangesInTrustedIdentities(newIdentities, oldIdentities));
157                 identityChangeDetector.detectChanges(currentOwnIdentities);
158         }
159
160         private IdentityProcessor detectChangesInTrustedIdentities(Multimap<OwnIdentity, Identity> newIdentities, Multimap<OwnIdentity, Identity> oldIdentities) {
161                 return new DefaultIdentityProcessor(oldIdentities, newIdentities);
162         }
163
164         private IdentityProcessor removeOwnIdentityAndItsTrustedIdentities(final Multimap<OwnIdentity, Identity> oldIdentities) {
165                 return new IdentityProcessor() {
166                         @Override
167                         public void processIdentity(Identity identity) {
168                                 eventBus.post(new OwnIdentityRemovedEvent((OwnIdentity) identity));
169                                 for (Identity removedIdentity : oldIdentities.get((OwnIdentity) identity)) {
170                                         eventBus.post(new IdentityRemovedEvent((OwnIdentity) identity, removedIdentity));
171                                 }
172                         }
173                 };
174         }
175
176         private IdentityProcessor addNewOwnIdentityAndItsTrustedIdentities(final Multimap<OwnIdentity, Identity> newIdentities) {
177                 return new IdentityProcessor() {
178                         @Override
179                         public void processIdentity(Identity identity) {
180                                 eventBus.post(new OwnIdentityAddedEvent((OwnIdentity) identity));
181                                 for (Identity newIdentity : newIdentities.get((OwnIdentity) identity)) {
182                                         eventBus.post(new IdentityAddedEvent((OwnIdentity) identity, newIdentity));
183                                 }
184                         }
185                 };
186         }
187
188         private Multimap<OwnIdentity, Identity> loadTrustedIdentitiesForOwnIdentities(Collection<OwnIdentity> ownIdentities) throws PluginException {
189                 Multimap<OwnIdentity, Identity> currentIdentities = create();
190
191                 for (OwnIdentity ownIdentity : ownIdentities) {
192                         if ((context != null) && !ownIdentity.hasContext(context)) {
193                                 continue;
194                         }
195
196                         logger.finer(String.format("Getting trusted identities for %s...", ownIdentity.getId()));
197                         Set<Identity> trustedIdentities = webOfTrustConnector.loadTrustedIdentities(ownIdentity, context);
198                         logger.finest(String.format("Got %d trusted identities.", trustedIdentities.size()));
199                         currentIdentities.putAll(ownIdentity, trustedIdentities);
200                 }
201
202                 return currentIdentities;
203         }
204
205         private class DefaultIdentityProcessor implements IdentityProcessor {
206
207                 private final Multimap<OwnIdentity, Identity> oldIdentities;
208                 private final Multimap<OwnIdentity, Identity> newIdentities;
209
210                 public DefaultIdentityProcessor(Multimap<OwnIdentity, Identity> oldIdentities, Multimap<OwnIdentity, Identity> newIdentities) {
211                         this.oldIdentities = oldIdentities;
212                         this.newIdentities = newIdentities;
213                 }
214
215                 @Override
216                 public void processIdentity(Identity ownIdentity) {
217                         IdentityChangeDetector identityChangeDetector = new IdentityChangeDetector(oldIdentities.get((OwnIdentity) ownIdentity));
218                         identityChangeDetector.onNewIdentity(notifyForAddedIdentities((OwnIdentity) ownIdentity));
219                         identityChangeDetector.onRemovedIdentity(notifyForRemovedIdentities((OwnIdentity) ownIdentity));
220                         identityChangeDetector.onChangedIdentity(notifyForChangedIdentities((OwnIdentity) ownIdentity));
221                         identityChangeDetector.detectChanges(newIdentities.get((OwnIdentity) ownIdentity));
222                 }
223
224                 private IdentityProcessor notifyForChangedIdentities(final OwnIdentity ownIdentity) {
225                         return new IdentityProcessor() {
226                                 @Override
227                                 public void processIdentity(Identity identity) {
228                                         eventBus.post(new IdentityUpdatedEvent(ownIdentity, identity));
229                                 }
230                         };
231                 }
232
233                 private IdentityProcessor notifyForRemovedIdentities(final OwnIdentity ownIdentity) {
234                         return new IdentityProcessor() {
235                                 @Override
236                                 public void processIdentity(Identity identity) {
237                                         eventBus.post(new IdentityRemovedEvent(ownIdentity, identity));
238                                 }
239                         };
240                 }
241
242                 private IdentityProcessor notifyForAddedIdentities(final OwnIdentity ownIdentity) {
243                         return new IdentityProcessor() {
244                                 @Override
245                                 public void processIdentity(Identity identity) {
246                                         eventBus.post(new IdentityAddedEvent(ownIdentity, identity));
247                                 }
248                         };
249                 }
250
251         }
252
253 }