X-Git-Url: https://git.pterodactylus.net/?p=WoTNS.git;a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fwotns%2Ffreenet%2Fwot%2FIdentityManager.java;fp=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fwotns%2Ffreenet%2Fwot%2FIdentityManager.java;h=e9107fefa196d1a67d72ff6cc5dc35a9e044aa06;hp=0000000000000000000000000000000000000000;hb=622c4a4d3ebed447d5708a41cf3e1e82e18fa29b;hpb=77869390c46e8e5eff63bf00c7ef44a37ba8f317 diff --git a/src/main/java/net/pterodactylus/wotns/freenet/wot/IdentityManager.java b/src/main/java/net/pterodactylus/wotns/freenet/wot/IdentityManager.java new file mode 100644 index 0000000..e9107fe --- /dev/null +++ b/src/main/java/net/pterodactylus/wotns/freenet/wot/IdentityManager.java @@ -0,0 +1,342 @@ +/* + * Sone - IdentityManager.java - Copyright © 2010 David Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.wotns.freenet.wot; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.pterodactylus.util.collection.SetBuilder; +import net.pterodactylus.util.logging.Logging; +import net.pterodactylus.util.service.AbstractService; +import net.pterodactylus.wotns.freenet.plugin.PluginException; + +/** + * The identity manager takes care of loading and storing identities, their + * contexts, and properties. It does so in a way that does not expose errors via + * exceptions but it only logs them and tries to return sensible defaults. + *

+ * It is also responsible for polling identities from the Web of Trust plugin + * and notifying registered {@link IdentityListener}s when {@link Identity}s and + * {@link OwnIdentity}s are discovered or disappearing. + * + * @author David ‘Bombe’ Roden + */ +public class IdentityManager extends AbstractService { + + /** Object used for synchronization. */ + private final Object syncObject = new Object() { + /* inner class for better lock names. */ + }; + + /** The logger. */ + private static final Logger logger = Logging.getLogger(IdentityManager.class); + + /** The event manager. */ + private final IdentityListenerManager identityListenerManager = new IdentityListenerManager(); + + /** The Web of Trust connector. */ + private final WebOfTrustConnector webOfTrustConnector; + + /** The context to filter for. */ + private volatile String context; + + /** The currently known own identities. */ + /* synchronize access on syncObject. */ + private Map currentOwnIdentities = new HashMap(); + + /** The currently trusted identities. */ + private Map> currentTrustedIdentities = new HashMap>(); + + /** + * Creates a new identity manager. + * + * @param webOfTrustConnector + * The Web of Trust connector + */ + public IdentityManager(WebOfTrustConnector webOfTrustConnector) { + super("Sone Identity Manager", false); + this.webOfTrustConnector = webOfTrustConnector; + } + + // + // LISTENER MANAGEMENT + // + + /** + * Adds a listener for identity events. + * + * @param identityListener + * The listener to add + */ + public void addIdentityListener(IdentityListener identityListener) { + identityListenerManager.addListener(identityListener); + } + + /** + * Removes a listener for identity events. + * + * @param identityListener + * The listener to remove + */ + public void removeIdentityListener(IdentityListener identityListener) { + identityListenerManager.removeListener(identityListener); + } + + // + // ACCESSORS + // + + /** + * Sets the context to filter own identities and trusted identities for. + * + * @param context + * The context to filter for, or {@code null} to not filter + */ + public void setContext(String context) { + this.context = context; + } + + /** + * Returns whether the Web of Trust plugin could be reached during the last + * try. + * + * @return {@code true} if the Web of Trust plugin is connected, {@code + * false} otherwise + */ + public boolean isConnected() { + try { + webOfTrustConnector.ping(); + return true; + } catch (PluginException pe1) { + /* not connected, ignore. */ + return false; + } + } + + /** + * Returns the own identity with the given ID. + * + * @param id + * The ID of the own identity + * @return The own identity, or {@code null} if there is no such identity + */ + public OwnIdentity getOwnIdentity(String id) { + Set allOwnIdentities = getAllOwnIdentities(); + for (OwnIdentity ownIdentity : allOwnIdentities) { + if (ownIdentity.getId().equals(id)) { + return ownIdentity; + } + } + return null; + } + + /** + * Returns all own identities. + * + * @return All own identities + */ + public Set getAllOwnIdentities() { + try { + Set ownIdentities = webOfTrustConnector.loadAllOwnIdentities(); + Map newOwnIdentities = new HashMap(); + for (OwnIdentity ownIdentity : ownIdentities) { + newOwnIdentities.put(ownIdentity.getId(), ownIdentity); + } + checkOwnIdentities(newOwnIdentities); + return ownIdentities; + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "Could not load all own identities!", wote1); + return Collections.emptySet(); + } + } + + public Set getTrustedIdentities(OwnIdentity ownIdentity) { + SetBuilder identities = new SetBuilder(); + if ((context == null) || ownIdentity.getContexts().contains(context)) { + identities.add(ownIdentity); + } + synchronized (syncObject) { + identities.addAll(currentTrustedIdentities.get(ownIdentity)); + } + return identities.get(); + } + + // + // SERVICE METHODS + // + + /** + * {@inheritDoc} + */ + @Override + protected void serviceRun() { + Map> oldIdentities = Collections.emptyMap(); + while (!shouldStop()) { + Map> currentIdentities = new HashMap>(); + @SuppressWarnings("hiding") + Map currentOwnIdentities = new HashMap(); + + Set ownIdentities = null; + boolean identitiesLoaded = false; + try { + /* get all identities with the wanted context from WoT. */ + ownIdentities = webOfTrustConnector.loadAllOwnIdentities(); + + /* load trusted identities. */ + for (OwnIdentity ownIdentity : ownIdentities) { + if ((context != null) && !ownIdentity.hasContext(context)) { + continue; + } + currentOwnIdentities.put(ownIdentity.getId(), ownIdentity); + + Set trustedIdentities = webOfTrustConnector.loadTrustedIdentities(ownIdentity, context); + Map identities = new HashMap(); + currentIdentities.put(ownIdentity, identities); + for (Identity identity : trustedIdentities) { + identities.put(identity.getId(), identity); + } + } + identitiesLoaded = true; + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "WoT has disappeared!", wote1); + } + + if (identitiesLoaded) { + + /* check for changes. */ + checkOwnIdentities(currentOwnIdentities); + + /* now check for changes in remote identities. */ + for (OwnIdentity ownIdentity : currentOwnIdentities.values()) { + + /* find new identities. */ + for (Identity currentIdentity : currentIdentities.get(ownIdentity).values()) { + if (!oldIdentities.containsKey(ownIdentity) || !oldIdentities.get(ownIdentity).containsKey(currentIdentity.getId())) { + identityListenerManager.fireIdentityAdded(ownIdentity, currentIdentity); + } + } + + /* find removed identities. */ + if (oldIdentities.containsKey(ownIdentity)) { + for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) { + if (!currentIdentities.get(ownIdentity).containsKey(oldIdentity.getId())) { + identityListenerManager.fireIdentityRemoved(ownIdentity, oldIdentity); + } + } + + /* check for changes in the contexts. */ + for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) { + if (!currentIdentities.get(ownIdentity).containsKey(oldIdentity.getId())) { + continue; + } + Identity newIdentity = currentIdentities.get(ownIdentity).get(oldIdentity.getId()); + Set oldContexts = oldIdentity.getContexts(); + Set newContexts = newIdentity.getContexts(); + if (oldContexts.size() != newContexts.size()) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + continue; + } + for (String oldContext : oldContexts) { + if (!newContexts.contains(oldContext)) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + break; + } + } + } + + /* check for changes in the properties. */ + for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) { + if (!currentIdentities.get(ownIdentity).containsKey(oldIdentity.getId())) { + continue; + } + Identity newIdentity = currentIdentities.get(ownIdentity).get(oldIdentity.getId()); + Map oldProperties = oldIdentity.getProperties(); + Map newProperties = newIdentity.getProperties(); + if (oldProperties.size() != newProperties.size()) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + continue; + } + for (Entry oldProperty : oldProperties.entrySet()) { + if (!newProperties.containsKey(oldProperty.getKey()) || !newProperties.get(oldProperty.getKey()).equals(oldProperty.getValue())) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + break; + } + } + } + } + } + + /* remember the current set of identities. */ + oldIdentities = currentIdentities; + synchronized (syncObject) { + currentTrustedIdentities.clear(); + for (Entry> entry : currentIdentities.entrySet()) { + Set identities = new HashSet(); + currentTrustedIdentities.put(entry.getKey(), identities); + for (Identity identity : entry.getValue().values()) { + identities.add(identity); + } + } + } + } + + /* wait a minute before checking again. */ + sleep(60 * 1000); + } + } + + // + // PRIVATE METHODS + // + + /** + * Checks the given new list of own identities for added or removed own + * identities, as compared to {@link #currentOwnIdentities}. + * + * @param newOwnIdentities + * The new own identities + */ + private void checkOwnIdentities(Map newOwnIdentities) { + synchronized (syncObject) { + + /* find removed own identities: */ + for (OwnIdentity oldOwnIdentity : currentOwnIdentities.values()) { + if (!newOwnIdentities.containsKey(oldOwnIdentity.getId())) { + identityListenerManager.fireOwnIdentityRemoved(oldOwnIdentity); + } + } + + /* find added own identities. */ + for (OwnIdentity currentOwnIdentity : newOwnIdentities.values()) { + if (!currentOwnIdentities.containsKey(currentOwnIdentity.getId())) { + identityListenerManager.fireOwnIdentityAdded(currentOwnIdentity); + } + } + + currentOwnIdentities.clear(); + currentOwnIdentities.putAll(newOwnIdentities); + } + } + +}