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. */
207 * Sets a property on the given own identity.
210 * The own identity to set the property on
211 * @param propertyName
212 * The name of the property to set
213 * @param propertyValue
214 * The value of the property to set
216 public void setProperty(OwnIdentity ownIdentity, String propertyName, String propertyValue) {
217 SetPropertyJob setPropertyJob = new SetPropertyJob(ownIdentity, propertyName, propertyValue);
218 if (updateJobs.contains(setPropertyJob)) {
219 updateJobs.remove(setPropertyJob);
221 logger.log(Level.FINER, "Adding Property Job: " + setPropertyJob);
223 updateJobs.put(setPropertyJob);
224 } catch (InterruptedException e) {
225 /* the queue is unbounded so it should never block. */
230 * Removes a property from the given own identity.
233 * The own identity to remove the property from
234 * @param propertyName
235 * The name of the property to remove
237 public void removeProperty(OwnIdentity ownIdentity, String propertyName) {
238 setProperty(ownIdentity, propertyName, null);
249 protected void serviceRun() {
250 while (!shouldStop()) {
252 WebOfTrustUpdateJob updateJob = updateJobs.take();
253 if (shouldStop() || (updateJob == stopJob)) {
256 logger.log(Level.FINE, "Running Trust Update Job: " + updateJob);
257 long startTime = System.currentTimeMillis();
259 long endTime = System.currentTimeMillis();
260 logger.log(Level.FINE, "Trust Update Job finished, took " + (endTime - startTime) + " ms.");
261 } catch (InterruptedException ie1) {
262 /* happens, ignore, loop. */
271 protected void serviceStop() {
273 updateJobs.put(stopJob);
274 } catch (InterruptedException ie1) {
275 /* the queue is unbounded so it should never block. */
280 * Base class for WebOfTrust update jobs.
282 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
284 private class WebOfTrustUpdateJob {
286 /** Object for synchronization. */
287 @SuppressWarnings("hiding")
288 private final Object syncObject = new Object();
290 /** Whether the job has finished. */
291 private boolean finished;
293 /** Whether the job was successful. */
294 private boolean success;
301 * Performs the actual update operation.
303 * The implementation of this class does nothing.
310 * Waits for completion of this job or stopping of the WebOfTrust
313 * @return {@code true} if this job finished successfully, {@code false}
316 * @see WebOfTrustUpdater#stop()
318 @SuppressWarnings("synthetic-access")
319 public boolean waitForCompletion() {
320 synchronized (syncObject) {
321 while (!finished && !shouldStop()) {
324 } catch (InterruptedException ie1) {
325 /* we’re looping, ignore. */
337 * Signals that this job has finished.
340 * {@code true} if this job finished successfully,
341 * {@code false} otherwise
343 protected void finish(boolean success) {
344 synchronized (syncObject) {
346 this.success = success;
347 syncObject.notifyAll();
354 * Base class for WebOfTrust trust update jobs.
356 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
358 private class WebOfTrustTrustUpdateJob extends WebOfTrustUpdateJob {
360 /** The identity giving the trust. */
361 protected final OwnIdentity truster;
363 /** The identity receiving the trust. */
364 protected final Identity trustee;
367 * Creates a new trust update job.
370 * The identity giving the trust
372 * The identity receiving the trust
374 @SuppressWarnings("synthetic-access")
375 public WebOfTrustTrustUpdateJob(OwnIdentity truster, Identity trustee) {
376 this.truster = truster;
377 this.trustee = trustee;
388 public boolean equals(Object object) {
389 if ((object == null) || !object.getClass().equals(getClass())) {
392 WebOfTrustTrustUpdateJob updateJob = (WebOfTrustTrustUpdateJob) object;
393 return ((truster == null) ? (updateJob.truster == null) : updateJob.truster.equals(truster)) && ((trustee == null) ? (updateJob.trustee == null) : updateJob.trustee.equals(trustee));
400 public int hashCode() {
401 return getClass().hashCode() ^ ((truster == null) ? 0 : truster.hashCode()) ^ ((trustee == null) ? 0 : trustee.hashCode());
408 public String toString() {
409 return String.format("%s[truster=%s,trustee=%s]", getClass().getSimpleName(), (truster == null) ? null : truster.getId(), (trustee == null) ? null : trustee.getId());
415 * Update job that sets the trust relation between two identities.
417 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
419 private class SetTrustJob extends WebOfTrustTrustUpdateJob {
421 /** The score of the relation. */
422 private final Integer score;
424 /** The comment of the relation. */
425 private final String comment;
428 * Creates a new set trust job.
431 * The identity giving the trust
433 * The identity receiving the trust
435 * The score of the trust (from -100 to 100, may be
436 * {@code null} to remote the trust relation completely)
438 * The comment of the trust relation
440 public SetTrustJob(OwnIdentity truster, Identity trustee, Integer score, String comment) {
441 super(truster, trustee);
443 this.comment = comment;
450 @SuppressWarnings("synthetic-access")
454 if (trustee instanceof DefaultIdentity) {
455 ((DefaultIdentity) trustee).setTrust(truster, new Trust(score, null, 0));
457 webOfTrustConnector.setTrust(truster, trustee, score, comment);
459 if (trustee instanceof DefaultIdentity) {
460 ((DefaultIdentity) trustee).setTrust(truster, null);
462 webOfTrustConnector.removeTrust(truster, trustee);
465 } catch (WebOfTrustException wote1) {
466 logger.log(Level.WARNING, "Could not set Trust value for " + truster + " -> " + trustee + " to " + score + " (" + comment + ")!", wote1);
474 * Update job that retrieves the trust relation between two identities.
476 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
478 private class GetTrustJob extends WebOfTrustTrustUpdateJob {
481 * Creates a new trust update job.
484 * The identity giving the trust
486 * The identity receiving the trust
488 public GetTrustJob(OwnIdentity truster, Identity trustee) {
489 super(truster, trustee);
496 @SuppressWarnings("synthetic-access")
499 Trust trust = webOfTrustConnector.getTrust(truster, trustee);
500 if (trustee instanceof DefaultIdentity) {
501 ((DefaultIdentity) trustee).setTrust(truster, trust);
504 } catch (PluginException pe1) {
505 logger.log(Level.WARNING, "Could not get Trust value for " + truster + " -> " + trustee + "!", pe1);
513 * Base class for context updates of an {@link OwnIdentity}.
515 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
517 private class WebOfTrustContextUpdateJob extends WebOfTrustUpdateJob {
519 /** The own identity whose contexts to manage. */
520 protected final OwnIdentity ownIdentity;
522 /** The context to update. */
523 protected final String context;
526 * Creates a new context update job.
529 * The own identity to update
531 * The context to update
533 @SuppressWarnings("synthetic-access")
534 public WebOfTrustContextUpdateJob(OwnIdentity ownIdentity, String context) {
535 Validation.begin().isNotNull("OwnIdentity", ownIdentity).isNotNull("Context", context).check();
536 this.ownIdentity = ownIdentity;
537 this.context = context;
548 public boolean equals(Object object) {
549 if ((object == null) || !object.getClass().equals(getClass())) {
552 WebOfTrustContextUpdateJob updateJob = (WebOfTrustContextUpdateJob) object;
553 return updateJob.ownIdentity.equals(ownIdentity) && updateJob.context.equals(context);
560 public int hashCode() {
561 return getClass().hashCode() ^ ownIdentity.hashCode() ^ context.hashCode();
568 public String toString() {
569 return String.format("%s[ownIdentity=%s,context=%s]", getClass().getSimpleName(), ownIdentity, context);
575 * Job that adds a context to an {@link OwnIdentity}.
577 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
579 private class AddContextJob extends WebOfTrustContextUpdateJob {
582 * Creates a new add-context job.
585 * The own identity whose contexts to manage
589 public AddContextJob(OwnIdentity ownIdentity, String context) {
590 super(ownIdentity, context);
597 @SuppressWarnings("synthetic-access")
600 webOfTrustConnector.addContext(ownIdentity, context);
601 ownIdentity.addContext(context);
603 } catch (PluginException pe1) {
604 logger.log(Level.WARNING, String.format("Could not add Context “%2$s” to Own Identity %1$s!", ownIdentity, context), pe1);
612 * Job that removes a context from an {@link OwnIdentity}.
614 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
616 private class RemoveContextJob extends WebOfTrustContextUpdateJob {
619 * Creates a new remove-context job.
622 * The own identity whose contexts to manage
624 * The context to remove
626 public RemoveContextJob(OwnIdentity ownIdentity, String context) {
627 super(ownIdentity, context);
634 @SuppressWarnings("synthetic-access")
637 webOfTrustConnector.removeContext(ownIdentity, context);
638 ownIdentity.removeContext(context);
640 } catch (PluginException pe1) {
641 logger.log(Level.WARNING, String.format("Could not remove Context “%2$s” to Own Identity %1$s!", ownIdentity, context), pe1);
649 * Base class for update jobs that deal with properties.
651 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
653 private class WebOfTrustPropertyUpdateJob extends WebOfTrustUpdateJob {
655 /** The own identity to update properties on. */
656 protected final OwnIdentity ownIdentity;
658 /** The name of the property to update. */
659 protected final String propertyName;
662 * Creates a new property update job.
665 * The own identity to update the property on
666 * @param propertyName
667 * The name of the property to update
669 @SuppressWarnings("synthetic-access")
670 public WebOfTrustPropertyUpdateJob(OwnIdentity ownIdentity, String propertyName) {
671 this.ownIdentity = ownIdentity;
672 this.propertyName = propertyName;
683 public boolean equals(Object object) {
684 if ((object == null) || !object.getClass().equals(getClass())) {
687 WebOfTrustContextUpdateJob updateJob = (WebOfTrustContextUpdateJob) object;
688 return updateJob.ownIdentity.equals(ownIdentity) && updateJob.context.equals(propertyName);
695 public int hashCode() {
696 return getClass().hashCode() ^ ownIdentity.hashCode() ^ propertyName.hashCode();
703 public String toString() {
704 return String.format("%s[ownIdentity=%s,propertyName=%s]", getClass().getSimpleName(), ownIdentity, propertyName);
710 * WebOfTrust update job that sets a property on an {@link OwnIdentity}.
712 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
714 private class SetPropertyJob extends WebOfTrustPropertyUpdateJob {
716 /** The value of the property to set. */
717 private final String propertyValue;
720 * Creates a new set-property job.
723 * The own identity to set the property on
724 * @param propertyName
725 * The name of the property to set
726 * @param propertyValue
727 * The value of the property to set
729 public SetPropertyJob(OwnIdentity ownIdentity, String propertyName, String propertyValue) {
730 super(ownIdentity, propertyName);
731 this.propertyValue = propertyValue;
738 @SuppressWarnings("synthetic-access")
741 if (propertyValue == null) {
742 webOfTrustConnector.removeProperty(ownIdentity, propertyName);
743 ownIdentity.removeProperty(propertyName);
745 webOfTrustConnector.setProperty(ownIdentity, propertyName, propertyValue);
746 ownIdentity.setProperty(propertyName, propertyValue);
749 } catch (PluginException pe1) {
750 logger.log(Level.WARNING, String.format("Could not set Property “%2$s” to “%3$s” on Own Identity %1$s!", ownIdentity, propertyName, propertyValue), pe1);