2 * Sone - WebOfTrustUpdater.java - Copyright © 2012 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 java.util.concurrent.BlockingQueue;
21 import java.util.concurrent.LinkedBlockingQueue;
22 import java.util.logging.Level;
23 import java.util.logging.Logger;
25 import net.pterodactylus.sone.freenet.plugin.PluginException;
26 import net.pterodactylus.sone.freenet.wot.DefaultIdentity;
27 import net.pterodactylus.sone.freenet.wot.Identity;
28 import net.pterodactylus.sone.freenet.wot.OwnIdentity;
29 import net.pterodactylus.sone.freenet.wot.Trust;
30 import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector;
31 import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
32 import net.pterodactylus.util.logging.Logging;
33 import net.pterodactylus.util.service.AbstractService;
34 import net.pterodactylus.util.validation.Validation;
37 * Updates WebOfTrust identity data in a background thread because communicating
38 * with the WebOfTrust plugin can potentially last quite long.
40 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
42 public class WebOfTrustUpdater extends AbstractService {
45 private static final Logger logger = Logging.getLogger(WebOfTrustUpdater.class);
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<WebOfTrustUpdateJob>();
58 * Creates a new trust updater.
60 * @param webOfTrustConnector
61 * The web of trust connector
63 public WebOfTrustUpdater(WebOfTrustConnector webOfTrustConnector) {
64 super("Trust Updater");
65 this.webOfTrustConnector = webOfTrustConnector;
73 * Retrieves the trust relation between the truster and the trustee. This
74 * method will return immediately and perform a trust update in the
78 * The identity giving the trust
80 * The identity receiving the trust
82 public void getTrust(OwnIdentity truster, Identity trustee) {
83 GetTrustJob getTrustJob = new GetTrustJob(truster, trustee);
84 if (!updateJobs.contains(getTrustJob)) {
85 logger.log(Level.FINER, "Adding Trust Update Job: " + getTrustJob);
87 updateJobs.put(getTrustJob);
88 } catch (InterruptedException ie1) {
89 /* the queue is unbounded so it should never block. */
95 * Updates the trust relation between the truster and the trustee. This
96 * method will return immediately and perform a trust update in the
100 * The identity giving the trust
102 * The identity receiving the trust
104 * The new level of trust (from -100 to 100, may be {@code null}
105 * to remove the trust completely)
107 * The comment of the trust relation
109 public void setTrust(OwnIdentity truster, Identity trustee, Integer score, String comment) {
110 SetTrustJob setTrustJob = new SetTrustJob(truster, trustee, score, comment);
111 if (updateJobs.contains(setTrustJob)) {
112 updateJobs.remove(setTrustJob);
114 logger.log(Level.FINER, "Adding Trust Update Job: " + setTrustJob);
116 updateJobs.put(setTrustJob);
117 } catch (InterruptedException e) {
118 /* the queue is unbounded so it should never block. */
123 * Adds the given context to the given own identity.
126 * The own identity to add the context to
130 public void addContext(OwnIdentity ownIdentity, String context) {
131 addContextWait(ownIdentity, context, false);
135 * Adds the given context to the given own identity, waiting for completion
139 * The own identity to add the context to
142 * @return {@code true} if the context was added successfully, {@code false}
145 public boolean addContextWait(OwnIdentity ownIdentity, String context) {
146 return addContextWait(ownIdentity, context, true);
150 * Adds the given context to the given own identity, waiting for completion
154 * The own identity to add the context to
158 * {@code true} to wait for the end of the operation,
159 * {@code false} to return immediately
160 * @return {@code true} if the context was added successfully, {@code false}
161 * if the context was not added successfully, or if the job should
162 * not wait for completion
164 private boolean addContextWait(OwnIdentity ownIdentity, String context, boolean wait) {
165 AddContextJob addContextJob = new AddContextJob(ownIdentity, context);
166 if (!updateJobs.contains(addContextJob)) {
167 logger.log(Level.FINER, "Adding Context Job: " + addContextJob);
169 updateJobs.put(addContextJob);
170 } catch (InterruptedException ie1) {
171 /* the queue is unbounded so it should never block. */
174 return addContextJob.waitForCompletion();
177 for (WebOfTrustUpdateJob updateJob : updateJobs) {
178 if (updateJob.equals(addContextJob)) {
179 return updateJob.waitForCompletion();
187 * Removes the given context from the given own identity.
190 * The own identity to remove the context from
192 * The context to remove
194 public void removeContext(OwnIdentity ownIdentity, String context) {
195 RemoveContextJob removeContextJob = new RemoveContextJob(ownIdentity, context);
196 if (!updateJobs.contains(removeContextJob)) {
197 logger.log(Level.FINER, "Adding Context Job: " + removeContextJob);
199 updateJobs.put(removeContextJob);
200 } catch (InterruptedException ie1) {
201 /* the queue is unbounded so it should never block. */
214 protected void serviceRun() {
215 while (!shouldStop()) {
217 WebOfTrustUpdateJob updateJob = updateJobs.take();
218 if (shouldStop() || (updateJob == stopJob)) {
221 logger.log(Level.FINE, "Running Trust Update Job: " + updateJob);
222 long startTime = System.currentTimeMillis();
224 long endTime = System.currentTimeMillis();
225 logger.log(Level.FINE, "Trust Update Job finished, took " + (endTime - startTime) + " ms.");
226 } catch (InterruptedException ie1) {
227 /* happens, ignore, loop. */
236 protected void serviceStop() {
238 updateJobs.put(stopJob);
239 } catch (InterruptedException ie1) {
240 /* the queue is unbounded so it should never block. */
245 * Base class for WebOfTrust update jobs.
247 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
249 private class WebOfTrustUpdateJob {
251 /** Object for synchronization. */
252 @SuppressWarnings("hiding")
253 private final Object syncObject = new Object();
255 /** Whether the job has finished. */
256 private boolean finished;
258 /** Whether the job was successful. */
259 private boolean success;
266 * Performs the actual update operation.
268 * The implementation of this class does nothing.
275 * Waits for completion of this job or stopping of the WebOfTrust
278 * @return {@code true} if this job finished successfully, {@code false}
281 * @see WebOfTrustUpdater#stop()
283 @SuppressWarnings("synthetic-access")
284 public boolean waitForCompletion() {
285 synchronized (syncObject) {
286 while (!finished && !shouldStop()) {
289 } catch (InterruptedException ie1) {
290 /* we’re looping, ignore. */
302 * Signals that this job has finished.
305 * {@code true} if this job finished successfully,
306 * {@code false} otherwise
308 protected void finish(boolean success) {
309 synchronized (syncObject) {
311 this.success = success;
312 syncObject.notifyAll();
319 * Base class for WebOfTrust trust update jobs.
321 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
323 private class WebOfTrustTrustUpdateJob extends WebOfTrustUpdateJob {
325 /** The identity giving the trust. */
326 protected final OwnIdentity truster;
328 /** The identity receiving the trust. */
329 protected final Identity trustee;
332 * Creates a new trust update job.
335 * The identity giving the trust
337 * The identity receiving the trust
339 @SuppressWarnings("synthetic-access")
340 public WebOfTrustTrustUpdateJob(OwnIdentity truster, Identity trustee) {
341 this.truster = truster;
342 this.trustee = trustee;
353 public boolean equals(Object object) {
354 if ((object == null) || !object.getClass().equals(getClass())) {
357 WebOfTrustTrustUpdateJob updateJob = (WebOfTrustTrustUpdateJob) object;
358 return ((truster == null) ? (updateJob.truster == null) : updateJob.truster.equals(truster)) && ((trustee == null) ? (updateJob.trustee == null) : updateJob.trustee.equals(trustee));
365 public int hashCode() {
366 return getClass().hashCode() ^ ((truster == null) ? 0 : truster.hashCode()) ^ ((trustee == null) ? 0 : trustee.hashCode());
373 public String toString() {
374 return String.format("%s[truster=%s,trustee=%s]", getClass().getSimpleName(), (truster == null) ? null : truster.getId(), (trustee == null) ? null : trustee.getId());
380 * Update job that sets the trust relation between two identities.
382 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
384 private class SetTrustJob extends WebOfTrustTrustUpdateJob {
386 /** The score of the relation. */
387 private final Integer score;
389 /** The comment of the relation. */
390 private final String comment;
393 * Creates a new set trust job.
396 * The identity giving the trust
398 * The identity receiving the trust
400 * The score of the trust (from -100 to 100, may be
401 * {@code null} to remote the trust relation completely)
403 * The comment of the trust relation
405 public SetTrustJob(OwnIdentity truster, Identity trustee, Integer score, String comment) {
406 super(truster, trustee);
408 this.comment = comment;
415 @SuppressWarnings("synthetic-access")
419 if (trustee instanceof DefaultIdentity) {
420 ((DefaultIdentity) trustee).setTrust(truster, new Trust(score, null, 0));
422 webOfTrustConnector.setTrust(truster, trustee, score, comment);
424 if (trustee instanceof DefaultIdentity) {
425 ((DefaultIdentity) trustee).setTrust(truster, null);
427 webOfTrustConnector.removeTrust(truster, trustee);
430 } catch (WebOfTrustException wote1) {
431 logger.log(Level.WARNING, "Could not set Trust value for " + truster + " -> " + trustee + " to " + score + " (" + comment + ")!", wote1);
439 * Update job that retrieves the trust relation between two identities.
441 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
443 private class GetTrustJob extends WebOfTrustTrustUpdateJob {
446 * Creates a new trust update job.
449 * The identity giving the trust
451 * The identity receiving the trust
453 public GetTrustJob(OwnIdentity truster, Identity trustee) {
454 super(truster, trustee);
461 @SuppressWarnings("synthetic-access")
464 Trust trust = webOfTrustConnector.getTrust(truster, trustee);
465 if (trustee instanceof DefaultIdentity) {
466 ((DefaultIdentity) trustee).setTrust(truster, trust);
469 } catch (PluginException pe1) {
470 logger.log(Level.WARNING, "Could not get Trust value for " + truster + " -> " + trustee + "!", pe1);
478 * Base class for context updates of an {@link OwnIdentity}.
480 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
482 private class WebOfTrustContextUpdateJob extends WebOfTrustUpdateJob {
484 /** The own identity whose contexts to manage. */
485 protected final OwnIdentity ownIdentity;
487 /** The context to update. */
488 protected final String context;
491 * Creates a new context update job.
494 * The own identity to update
496 * The context to update
498 @SuppressWarnings("synthetic-access")
499 public WebOfTrustContextUpdateJob(OwnIdentity ownIdentity, String context) {
500 Validation.begin().isNotNull("OwnIdentity", ownIdentity).isNotNull("Context", context).check();
501 this.ownIdentity = ownIdentity;
502 this.context = context;
513 public boolean equals(Object object) {
514 if ((object == null) || !object.getClass().equals(getClass())) {
517 WebOfTrustContextUpdateJob updateJob = (WebOfTrustContextUpdateJob) object;
518 return updateJob.ownIdentity.equals(ownIdentity) && updateJob.context.equals(context);
525 public int hashCode() {
526 return getClass().hashCode() ^ ownIdentity.hashCode() ^ context.hashCode();
533 public String toString() {
534 return String.format("%s[ownIdentity=%s,context=%s]", getClass().getSimpleName(), ownIdentity, context);
540 * Job that adds a context to an {@link OwnIdentity}.
542 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
544 private class AddContextJob extends WebOfTrustContextUpdateJob {
547 * Creates a new add-context job.
550 * The own identity whose contexts to manage
554 public AddContextJob(OwnIdentity ownIdentity, String context) {
555 super(ownIdentity, context);
562 @SuppressWarnings("synthetic-access")
565 webOfTrustConnector.addContext(ownIdentity, context);
566 ownIdentity.addContext(context);
568 } catch (PluginException pe1) {
569 logger.log(Level.WARNING, String.format("Could not add Context “%2$s” to Own Identity %1$s!", ownIdentity, context), pe1);
577 * Job that removes a context from an {@link OwnIdentity}.
579 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
581 private class RemoveContextJob extends WebOfTrustContextUpdateJob {
584 * Creates a new remove-context job.
587 * The own identity whose contexts to manage
589 * The context to remove
591 public RemoveContextJob(OwnIdentity ownIdentity, String context) {
592 super(ownIdentity, context);
599 @SuppressWarnings("synthetic-access")
602 webOfTrustConnector.removeContext(ownIdentity, context);
603 ownIdentity.removeContext(context);
605 } catch (PluginException pe1) {
606 logger.log(Level.WARNING, String.format("Could not remove Context “%2$s” to Own Identity %1$s!", ownIdentity, context), pe1);