2 * Sone - WebOfTrustUpdaterImpl.java - Copyright Ā© 2013ā2019 David Roden
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.
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.
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/>.
18 package net.pterodactylus.sone.core;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static java.util.logging.Logger.getLogger;
23 import java.util.concurrent.BlockingQueue;
24 import java.util.concurrent.LinkedBlockingQueue;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
28 import net.pterodactylus.sone.freenet.plugin.PluginException;
29 import net.pterodactylus.sone.freenet.wot.OwnIdentity;
30 import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector;
31 import net.pterodactylus.util.service.AbstractService;
33 import com.google.common.annotations.VisibleForTesting;
34 import com.google.inject.Inject;
35 import com.google.inject.Singleton;
38 * Updates WebOfTrust identity data in a background thread because communicating
39 * with the WebOfTrust plugin can potentially last quite long.
42 public class WebOfTrustUpdaterImpl extends AbstractService implements WebOfTrustUpdater {
45 private static final Logger logger = getLogger(WebOfTrustUpdaterImpl.class.getName());
48 @SuppressWarnings("synthetic-access")
49 private final WebOfTrustUpdateJob stopJob = new WebOfTrustUpdateJob();
51 /** The web of trust connector. */
52 private final WebOfTrustConnector webOfTrustConnector;
54 /** The queue for jobs. */
55 private final BlockingQueue<WebOfTrustUpdateJob> updateJobs = new LinkedBlockingQueue<>();
58 * Creates a new trust updater.
60 * @param webOfTrustConnector
61 * The web of trust connector
64 public WebOfTrustUpdaterImpl(WebOfTrustConnector webOfTrustConnector) {
65 super("Trust Updater");
66 this.webOfTrustConnector = webOfTrustConnector;
74 * Adds the given context to the given own identity, waiting for completion of
78 * The own identity to add the context to
81 * @return {@code true} if the context was added successfully, {@code false}
85 public boolean addContextWait(OwnIdentity ownIdentity, String context) {
86 AddContextJob addContextJob = new AddContextJob(ownIdentity, context);
87 if (!updateJobs.contains(addContextJob)) {
88 logger.log(Level.FINER, "Adding Context Job: " + addContextJob);
90 updateJobs.put(addContextJob);
91 } catch (InterruptedException ie1) {
92 /* the queue is unbounded so it should never block. */
94 return addContextJob.waitForCompletion();
96 for (WebOfTrustUpdateJob updateJob : updateJobs) {
97 if (updateJob.equals(addContextJob)) {
98 return updateJob.waitForCompletion();
106 * Removes the given context from the given own identity.
109 * The own identity to remove the context from
111 * The context to remove
114 public void removeContext(OwnIdentity ownIdentity, String context) {
115 RemoveContextJob removeContextJob = new RemoveContextJob(ownIdentity, context);
116 if (!updateJobs.contains(removeContextJob)) {
117 logger.log(Level.FINER, "Adding Context Job: " + removeContextJob);
119 updateJobs.put(removeContextJob);
120 } catch (InterruptedException ie1) {
121 /* the queue is unbounded so it should never block. */
127 * Sets a property on the given own identity.
130 * The own identity to set the property on
131 * @param propertyName
132 * The name of the property to set
133 * @param propertyValue
134 * The value of the property to set
137 public void setProperty(OwnIdentity ownIdentity, String propertyName, String propertyValue) {
138 SetPropertyJob setPropertyJob = new SetPropertyJob(ownIdentity, propertyName, propertyValue);
139 if (updateJobs.contains(setPropertyJob)) {
140 updateJobs.remove(setPropertyJob);
142 logger.log(Level.FINER, "Adding Property Job: " + setPropertyJob);
144 updateJobs.put(setPropertyJob);
145 } catch (InterruptedException e) {
146 /* the queue is unbounded so it should never block. */
151 * Removes a property from the given own identity.
154 * The own identity to remove the property from
155 * @param propertyName
156 * The name of the property to remove
159 public void removeProperty(OwnIdentity ownIdentity, String propertyName) {
160 setProperty(ownIdentity, propertyName, null);
169 protected void serviceRun() {
170 while (!shouldStop()) {
172 WebOfTrustUpdateJob updateJob = updateJobs.take();
176 logger.log(Level.FINE, "Running Trust Update Job: " + updateJob);
177 long startTime = System.currentTimeMillis();
179 long endTime = System.currentTimeMillis();
180 logger.log(Level.FINE, "Trust Update Job finished, took " + (endTime - startTime) + " ms.");
181 } catch (InterruptedException ie1) {
182 /* happens, ignore, loop. */
189 protected void serviceStop() {
191 updateJobs.put(stopJob);
192 } catch (InterruptedException ie1) {
193 /* the queue is unbounded so it should never block. */
198 * Base class for WebOfTrust update jobs.
201 class WebOfTrustUpdateJob implements Runnable {
203 /** Object for synchronization. */
204 @SuppressWarnings("hiding")
205 private final Object syncObject = new Object();
207 /** Whether the job has finished. */
208 private boolean finished;
210 /** Whether the job was successful. */
211 private boolean success;
218 * Performs the actual update operation.
220 * The implementation of this class does nothing.
228 * Waits for completion of this job or stopping of the WebOfTrust updater.
230 * @return {@code true} if this job finished successfully, {@code false}
232 * @see WebOfTrustUpdaterImpl#stop()
234 @SuppressWarnings("synthetic-access")
235 public boolean waitForCompletion() {
236 synchronized (syncObject) {
237 while (!finished && !shouldStop()) {
240 } catch (InterruptedException ie1) {
241 /* weāre looping, ignore. */
253 * Signals that this job has finished.
256 * {@code true} if this job finished successfully, {@code false} otherwise
258 protected void finish(boolean success) {
259 synchronized (syncObject) {
261 this.success = success;
262 syncObject.notifyAll();
269 * Base class for context updates of an {@link OwnIdentity}.
272 class WebOfTrustContextUpdateJob extends WebOfTrustUpdateJob {
274 /** The own identity whose contexts to manage. */
275 protected final OwnIdentity ownIdentity;
277 /** The context to update. */
278 protected final String context;
281 * Creates a new context update job.
284 * The own identity to update
286 * The context to update
288 @SuppressWarnings("synthetic-access")
289 public WebOfTrustContextUpdateJob(OwnIdentity ownIdentity, String context) {
290 this.ownIdentity = checkNotNull(ownIdentity, "ownIdentity must not be null");
291 this.context = checkNotNull(context, "context must not be null");
300 public boolean equals(Object object) {
301 if ((object == null) || !object.getClass().equals(getClass())) {
304 WebOfTrustContextUpdateJob updateJob = (WebOfTrustContextUpdateJob) object;
305 return updateJob.ownIdentity.equals(ownIdentity) && updateJob.context.equals(context);
310 public int hashCode() {
311 return getClass().hashCode() ^ ownIdentity.hashCode() ^ context.hashCode();
316 public String toString() {
317 return String.format("%s[ownIdentity=%s,context=%s]", getClass().getSimpleName(), ownIdentity, context);
323 * Job that adds a context to an {@link OwnIdentity}.
326 class AddContextJob extends WebOfTrustContextUpdateJob {
329 * Creates a new add-context job.
332 * The own identity whose contexts to manage
336 public AddContextJob(OwnIdentity ownIdentity, String context) {
337 super(ownIdentity, context);
342 @SuppressWarnings("synthetic-access")
345 webOfTrustConnector.addContext(ownIdentity, context);
346 ownIdentity.addContext(context);
348 } catch (PluginException pe1) {
349 logger.log(Level.WARNING, String.format("Could not add Context ā%2$sā to Own Identity %1$s!", ownIdentity, context), pe1);
357 * Job that removes a context from an {@link OwnIdentity}.
360 class RemoveContextJob extends WebOfTrustContextUpdateJob {
363 * Creates a new remove-context job.
366 * The own identity whose contexts to manage
368 * The context to remove
370 public RemoveContextJob(OwnIdentity ownIdentity, String context) {
371 super(ownIdentity, context);
376 @SuppressWarnings("synthetic-access")
379 webOfTrustConnector.removeContext(ownIdentity, context);
380 ownIdentity.removeContext(context);
382 } catch (PluginException pe1) {
383 logger.log(Level.WARNING, String.format("Could not remove Context ā%2$sā to Own Identity %1$s!", ownIdentity, context), pe1);
391 * WebOfTrust update job that sets a property on an {@link OwnIdentity}.
394 class SetPropertyJob extends WebOfTrustUpdateJob {
396 /** The own identity to update properties on. */
397 private final OwnIdentity ownIdentity;
399 /** The name of the property to update. */
400 private final String propertyName;
402 /** The value of the property to set. */
403 private final String propertyValue;
406 * Creates a new set-property job.
409 * The own identity to set the property on
410 * @param propertyName
411 * The name of the property to set
412 * @param propertyValue
413 * The value of the property to set
415 public SetPropertyJob(OwnIdentity ownIdentity, String propertyName, String propertyValue) {
416 this.ownIdentity = ownIdentity;
417 this.propertyName = propertyName;
418 this.propertyValue = propertyValue;
423 @SuppressWarnings("synthetic-access")
426 if (propertyValue == null) {
427 webOfTrustConnector.removeProperty(ownIdentity, propertyName);
428 ownIdentity.removeProperty(propertyName);
430 webOfTrustConnector.setProperty(ownIdentity, propertyName, propertyValue);
431 ownIdentity.setProperty(propertyName, propertyValue);
434 } catch (PluginException pe1) {
435 logger.log(Level.WARNING, String.format("Could not set Property ā%2$sā to ā%3$sā on Own Identity %1$s!", ownIdentity, propertyName, propertyValue), pe1);
446 public boolean equals(Object object) {
447 if ((object == null) || !object.getClass().equals(getClass())) {
450 SetPropertyJob updateJob = (SetPropertyJob) object;
451 return updateJob.ownIdentity.equals(ownIdentity) && updateJob.propertyName.equals(propertyName);
456 public int hashCode() {
457 return getClass().hashCode() ^ ownIdentity.hashCode() ^ propertyName.hashCode();
462 public String toString() {
463 return String.format("%s[ownIdentity=%s,propertyName=%s]", getClass().getSimpleName(), ownIdentity, propertyName);