X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;ds=inline;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fcore%2FCore.java;h=c3ac305dc39f3ec513409abbc92125f1feff40ce;hb=f5c7590a5a340597f8127440a20058f65ed0abd1;hp=8a6236a1713a39f3d767a26387e6c4600bb43f1e;hpb=41ad88e59a3249031c6b546c8189204d99596e26;p=Sone.git
diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java
index 8a6236a..c3ac305 100644
--- a/src/main/java/net/pterodactylus/sone/core/Core.java
+++ b/src/main/java/net/pterodactylus/sone/core/Core.java
@@ -1,5 +1,5 @@
/*
- * Sone - Core.java - Copyright © 2010 David Roden
+ * Sone - Core.java - Copyright © 2010â2013 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
@@ -17,85 +17,107 @@
package net.pterodactylus.sone.core;
-import java.net.MalformedURLException;
+import static com.google.common.base.Optional.fromNullable;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.primitives.Longs.tryParse;
+import static java.util.logging.Logger.getLogger;
+
import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
-import net.pterodactylus.sone.core.Options.DefaultOption;
-import net.pterodactylus.sone.core.Options.Option;
-import net.pterodactylus.sone.core.Options.OptionWatcher;
+import net.pterodactylus.sone.core.SoneChangeDetector.PostProcessor;
+import net.pterodactylus.sone.core.SoneChangeDetector.PostReplyProcessor;
+import net.pterodactylus.sone.core.event.ImageInsertFinishedEvent;
+import net.pterodactylus.sone.core.event.MarkPostKnownEvent;
+import net.pterodactylus.sone.core.event.MarkPostReplyKnownEvent;
+import net.pterodactylus.sone.core.event.MarkSoneKnownEvent;
+import net.pterodactylus.sone.core.event.NewPostFoundEvent;
+import net.pterodactylus.sone.core.event.NewPostReplyFoundEvent;
+import net.pterodactylus.sone.core.event.NewSoneFoundEvent;
+import net.pterodactylus.sone.core.event.PostRemovedEvent;
+import net.pterodactylus.sone.core.event.PostReplyRemovedEvent;
+import net.pterodactylus.sone.core.event.SoneInsertedEvent;
+import net.pterodactylus.sone.core.event.SoneLockedEvent;
+import net.pterodactylus.sone.core.event.SoneRemovedEvent;
+import net.pterodactylus.sone.core.event.SoneUnlockedEvent;
import net.pterodactylus.sone.data.Album;
-import net.pterodactylus.sone.data.Client;
import net.pterodactylus.sone.data.Image;
+import net.pterodactylus.sone.data.LocalSone;
import net.pterodactylus.sone.data.Post;
-import net.pterodactylus.sone.data.Profile;
-import net.pterodactylus.sone.data.Profile.Field;
+import net.pterodactylus.sone.data.PostReply;
import net.pterodactylus.sone.data.Reply;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.data.Sone.SoneStatus;
import net.pterodactylus.sone.data.TemporaryImage;
+import net.pterodactylus.sone.database.AlbumBuilder;
+import net.pterodactylus.sone.database.Database;
+import net.pterodactylus.sone.database.DatabaseException;
+import net.pterodactylus.sone.database.ImageBuilder;
+import net.pterodactylus.sone.database.PostBuilder;
+import net.pterodactylus.sone.database.PostProvider;
+import net.pterodactylus.sone.database.PostReplyBuilder;
+import net.pterodactylus.sone.database.PostReplyProvider;
+import net.pterodactylus.sone.database.SoneBuilder;
+import net.pterodactylus.sone.database.SoneProvider;
import net.pterodactylus.sone.freenet.wot.Identity;
-import net.pterodactylus.sone.freenet.wot.IdentityListener;
import net.pterodactylus.sone.freenet.wot.IdentityManager;
import net.pterodactylus.sone.freenet.wot.OwnIdentity;
-import net.pterodactylus.sone.freenet.wot.Trust;
-import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
-import net.pterodactylus.sone.main.SonePlugin;
+import net.pterodactylus.sone.freenet.wot.event.IdentityAddedEvent;
+import net.pterodactylus.sone.freenet.wot.event.IdentityRemovedEvent;
+import net.pterodactylus.sone.freenet.wot.event.IdentityUpdatedEvent;
+import net.pterodactylus.sone.freenet.wot.event.OwnIdentityAddedEvent;
+import net.pterodactylus.sone.freenet.wot.event.OwnIdentityRemovedEvent;
import net.pterodactylus.util.config.Configuration;
import net.pterodactylus.util.config.ConfigurationException;
-import net.pterodactylus.util.logging.Logging;
-import net.pterodactylus.util.number.Numbers;
-import net.pterodactylus.util.validation.Validation;
-import net.pterodactylus.util.version.Version;
-import freenet.keys.FreenetURI;
+import net.pterodactylus.util.service.AbstractService;
+import net.pterodactylus.util.thread.NamedThreadFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
/**
* The Sone core.
*
* @author David âBombeâ Roden
*/
-public class Core implements IdentityListener, UpdateListener {
-
- /**
- * Enumeration for the possible states of a {@link Sone}.
- *
- * @author David âBombeâ Roden
- */
- public enum SoneStatus {
-
- /** The Sone is unknown, i.e. not yet downloaded. */
- unknown,
-
- /** The Sone is idle, i.e. not being downloaded or inserted. */
- idle,
-
- /** The Sone is currently being inserted. */
- inserting,
-
- /** The Sone is currently being downloaded. */
- downloading,
- }
+@Singleton
+public class Core extends AbstractService implements SoneProvider, PostProvider, PostReplyProvider {
/** The logger. */
- private static final Logger logger = Logging.getLogger(Core.class);
+ private static final Logger logger = getLogger("Sone.Core");
- /** The options. */
- private final Options options = new Options();
+ /** The start time. */
+ private final long startupTime = System.currentTimeMillis();
/** The preferences. */
- private final Preferences preferences = new Preferences(options);
+ private final Preferences preferences;
- /** The core listener manager. */
- private final CoreListenerManager coreListenerManager = new CoreListenerManager(this);
+ /** The event bus. */
+ private final EventBus eventBus;
/** The configuration. */
- private Configuration configuration;
+ private final Configuration configuration;
/** Whether weâre currently saving the configuration. */
private boolean storingConfiguration = false;
@@ -109,73 +131,44 @@ public class Core implements IdentityListener, UpdateListener {
/** The Sone downloader. */
private final SoneDownloader soneDownloader;
+ /** The image inserter. */
+ private final ImageInserter imageInserter;
+
+ /** Sone downloader thread-pool. */
+ private final ExecutorService soneDownloaders = Executors.newFixedThreadPool(10, new NamedThreadFactory("Sone Downloader %2$d"));
+
/** The update checker. */
private final UpdateChecker updateChecker;
- /** Whether the core has been stopped. */
- private volatile boolean stopped;
-
- /** The Sonesâ statuses. */
- /* synchronize access on itself. */
- private final Map soneStatuses = new HashMap();
+ /** The trust updater. */
+ private final WebOfTrustUpdater webOfTrustUpdater;
/** Locked local Sones. */
/* synchronize on itself. */
- private final Set lockedSones = new HashSet();
+ private final Set lockedSones = new HashSet();
/** Sone inserters. */
- /* synchronize access on this on localSones. */
- private final Map soneInserters = new HashMap();
-
- /** All local Sones. */
- /* synchronize access on this on itself. */
- private Map localSones = new HashMap();
-
- /** All remote Sones. */
- /* synchronize access on this on itself. */
- private Map remoteSones = new HashMap();
-
- /** All new Sones. */
- private Set newSones = new HashSet();
+ /* synchronize access on this on sones. */
+ private final Map soneInserters = new HashMap();
- /** All known Sones. */
- /* synchronize access on {@link #newSones}. */
- private Set knownSones = new HashSet();
+ /** Sone rescuers. */
+ /* synchronize access on this on sones. */
+ private final Map soneRescuers = new HashMap();
- /** All posts. */
- private Map posts = new HashMap();
-
- /** All new posts. */
- private Set newPosts = new HashSet();
-
- /** All known posts. */
- /* synchronize access on {@link #newPosts}. */
- private Set knownPosts = new HashSet();
-
- /** All replies. */
- private Map replies = new HashMap();
-
- /** All new replies. */
- private Set newReplies = new HashSet();
-
- /** All known replies. */
- private Set knownReplies = new HashSet();
-
- /** All bookmarked posts. */
- /* synchronize access on itself. */
- private Set bookmarkedPosts = new HashSet();
+ /** The post database. */
+ private final Database database;
/** Trusted identities, sorted by own identities. */
- private Map> trustedIdentities = Collections.synchronizedMap(new HashMap>());
+ private final Multimap trustedIdentities = Multimaps.synchronizedSetMultimap(HashMultimap.create());
- /** All known albums. */
- private Map albums = new HashMap();
+ /** All temporary images. */
+ private final Map temporaryImages = new HashMap();
- /** All known images. */
- private Map images = new HashMap();
+ /** Ticker for threads that mark own elements as known. */
+ private final ScheduledExecutorService localElementTicker = Executors.newScheduledThreadPool(1);
- /** All temporary images. */
- private Map temporaryImages = new HashMap();
+ /** The time the configuration was last touched. */
+ private volatile long lastConfigurationUpdate;
/**
* Creates a new core.
@@ -186,37 +179,41 @@ public class Core implements IdentityListener, UpdateListener {
* The freenet interface
* @param identityManager
* The identity manager
- */
- public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager) {
+ * @param webOfTrustUpdater
+ * The WebOfTrust updater
+ * @param eventBus
+ * The event bus
+ * @param database
+ * The database
+ */
+ @Inject
+ public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, Database database) {
+ super("Sone Core");
this.configuration = configuration;
this.freenetInterface = freenetInterface;
this.identityManager = identityManager;
- this.soneDownloader = new SoneDownloader(this, freenetInterface);
- this.updateChecker = new UpdateChecker(freenetInterface);
- }
-
- //
- // LISTENER MANAGEMENT
- //
-
- /**
- * Adds a new core listener.
- *
- * @param coreListener
- * The listener to add
- */
- public void addCoreListener(CoreListener coreListener) {
- coreListenerManager.addListener(coreListener);
- }
-
- /**
- * Removes a core listener.
- *
- * @param coreListener
- * The listener to remove
- */
- public void removeCoreListener(CoreListener coreListener) {
- coreListenerManager.removeListener(coreListener);
+ this.soneDownloader = new SoneDownloaderImpl(this, freenetInterface);
+ this.imageInserter = new ImageInserter(freenetInterface, freenetInterface.new InsertTokenSupplier());
+ this.updateChecker = new UpdateChecker(eventBus, freenetInterface);
+ this.webOfTrustUpdater = webOfTrustUpdater;
+ this.eventBus = eventBus;
+ this.database = database;
+ preferences = new Preferences(eventBus);
+ }
+
+ @VisibleForTesting
+ protected Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, SoneDownloader soneDownloader, ImageInserter imageInserter, UpdateChecker updateChecker, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, Database database) {
+ super("Sone Core");
+ this.configuration = configuration;
+ this.freenetInterface = freenetInterface;
+ this.identityManager = identityManager;
+ this.soneDownloader = soneDownloader;
+ this.imageInserter = imageInserter;
+ this.updateChecker = updateChecker;
+ this.webOfTrustUpdater = webOfTrustUpdater;
+ this.eventBus = eventBus;
+ this.database = database;
+ preferences = new Preferences(eventBus);
}
//
@@ -224,15 +221,12 @@ public class Core implements IdentityListener, UpdateListener {
//
/**
- * Sets the configuration to use. This will automatically save the current
- * configuration to the given configuration.
+ * Returns the time Sone was started.
*
- * @param configuration
- * The new configuration to use
+ * @return The startup time (in milliseconds since Jan 1, 1970 UTC)
*/
- public void setConfiguration(Configuration configuration) {
- this.configuration = configuration;
- saveConfiguration();
+ public long getStartupTime() {
+ return startupTime;
}
/**
@@ -263,29 +257,22 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
- * Returns the status of the given Sone.
- *
- * @param sone
- * The Sone to get the status for
- * @return The status of the Sone
- */
- public SoneStatus getSoneStatus(Sone sone) {
- synchronized (soneStatuses) {
- return soneStatuses.get(sone);
- }
- }
-
- /**
- * Sets the status of the given Sone.
+ * Returns the Sone rescuer for the given local Sone.
*
* @param sone
- * The Sone to set the status of
- * @param soneStatus
- * The status to set
+ * The local Sone to get the rescuer for
+ * @return The Sone rescuer for the given Sone
*/
- public void setSoneStatus(Sone sone, SoneStatus soneStatus) {
- synchronized (soneStatuses) {
- soneStatuses.put(sone, soneStatus);
+ public SoneRescuer getSoneRescuer(LocalSone sone) {
+ checkNotNull(sone, "sone must not be null");
+ synchronized (soneRescuers) {
+ SoneRescuer soneRescuer = soneRescuers.get(sone);
+ if (soneRescuer == null) {
+ soneRescuer = new SoneRescuer(this, soneDownloader, sone);
+ soneRescuers.put(sone, soneRescuer);
+ soneRescuer.start();
+ }
+ return soneRescuer;
}
}
@@ -296,35 +283,27 @@ public class Core implements IdentityListener, UpdateListener {
* The sone to check
* @return {@code true} if the Sone is locked, {@code false} if it is not
*/
- public boolean isLocked(Sone sone) {
+ public boolean isLocked(LocalSone sone) {
synchronized (lockedSones) {
return lockedSones.contains(sone);
}
}
- /**
- * Returns all Sones, remote and local.
- *
- * @return All Sones
- */
- public Set getSones() {
- Set allSones = new HashSet();
- allSones.addAll(getLocalSones());
- allSones.addAll(getRemoteSones());
- return allSones;
+ public SoneBuilder soneBuilder() {
+ return database.newSoneBuilder();
}
/**
- * Returns the Sone with the given ID, regardless whether itâs local or
- * remote.
- *
- * @param id
- * The ID of the Sone to get
- * @return The Sone with the given ID, or {@code null} if there is no such
- * Sone
+ * {@inheritDocs}
*/
- public Sone getSone(String id) {
- return getSone(id, true);
+ @Override
+ public Collection getSones() {
+ return database.getSones();
+ }
+
+ @Override
+ public Function> soneLoader() {
+ return database.soneLoader();
}
/**
@@ -333,186 +312,41 @@ public class Core implements IdentityListener, UpdateListener {
*
* @param id
* The ID of the Sone to get
- * @param create
- * {@code true} to create a new Sone if none exists,
- * {@code false} to return {@code null} if a Sone with the given
- * ID does not exist
* @return The Sone with the given ID, or {@code null} if there is no such
* Sone
*/
- public Sone getSone(String id, boolean create) {
- if (isLocalSone(id)) {
- return getLocalSone(id);
- }
- return getRemoteSone(id, create);
- }
-
- /**
- * Checks whether the core knows a Sone with the given ID.
- *
- * @param id
- * The ID of the Sone
- * @return {@code true} if there is a Sone with the given ID, {@code false}
- * otherwise
- */
- public boolean hasSone(String id) {
- return isLocalSone(id) || isRemoteSone(id);
- }
-
- /**
- * Returns whether the given Sone is a local Sone.
- *
- * @param sone
- * The Sone to check for its locality
- * @return {@code true} if the given Sone is local, {@code false} otherwise
- */
- public boolean isLocalSone(Sone sone) {
- synchronized (localSones) {
- return localSones.containsKey(sone.getId());
- }
- }
-
- /**
- * Returns whether the given ID is the ID of a local Sone.
- *
- * @param id
- * The Sone ID to check for its locality
- * @return {@code true} if the given ID is a local Sone, {@code false}
- * otherwise
- */
- public boolean isLocalSone(String id) {
- synchronized (localSones) {
- return localSones.containsKey(id);
- }
- }
-
- /**
- * Returns all local Sones.
- *
- * @return All local Sones
- */
- public Set getLocalSones() {
- synchronized (localSones) {
- return new HashSet(localSones.values());
- }
+ @Override
+ public Optional getSone(String id) {
+ return database.getSone(id);
}
- /**
- * Returns the local Sone with the given ID.
- *
- * @param id
- * The ID of the Sone to get
- * @return The Sone with the given ID
- */
- public Sone getLocalSone(String id) {
- return getLocalSone(id, true);
+ @Override
+ public Collection getLocalSones() {
+ return database.getLocalSones();
}
- /**
- * Returns the local Sone with the given ID, optionally creating a new Sone.
- *
- * @param id
- * The ID of the Sone
- * @param create
- * {@code true} to create a new Sone if none exists,
- * {@code false} to return null if none exists
- * @return The Sone with the given ID, or {@code null}
- */
- public Sone getLocalSone(String id, boolean create) {
- synchronized (localSones) {
- Sone sone = localSones.get(id);
- if ((sone == null) && create) {
- sone = new Sone(id);
- localSones.put(id, sone);
- setSoneStatus(sone, SoneStatus.unknown);
- }
- return sone;
- }
+ public Optional getLocalSone(String id) {
+ return database.getLocalSone(id);
}
/**
- * Returns all remote Sones.
- *
- * @return All remote Sones
+ * {@inheritDocs}
*/
- public Set getRemoteSones() {
- synchronized (remoteSones) {
- return new HashSet(remoteSones.values());
- }
+ @Override
+ public Collection getRemoteSones() {
+ return database.getRemoteSones();
}
/**
* Returns the remote Sone with the given ID.
*
- * @param id
- * The ID of the remote Sone to get
- * @return The Sone with the given ID
- */
- public Sone getRemoteSone(String id) {
- return getRemoteSone(id, true);
- }
-
- /**
- * Returns the remote Sone with the given ID.
*
* @param id
* The ID of the remote Sone to get
- * @param create
- * {@code true} to always create a Sone, {@code false} to return
- * {@code null} if no Sone with the given ID exists
* @return The Sone with the given ID
*/
- public Sone getRemoteSone(String id, boolean create) {
- synchronized (remoteSones) {
- Sone sone = remoteSones.get(id);
- if ((sone == null) && create) {
- sone = new Sone(id);
- remoteSones.put(id, sone);
- setSoneStatus(sone, SoneStatus.unknown);
- }
- return sone;
- }
- }
-
- /**
- * Returns whether the given Sone is a remote Sone.
- *
- * @param sone
- * The Sone to check
- * @return {@code true} if the given Sone is a remote Sone, {@code false}
- * otherwise
- */
- public boolean isRemoteSone(Sone sone) {
- synchronized (remoteSones) {
- return remoteSones.containsKey(sone.getId());
- }
- }
-
- /**
- * Returns whether the Sone with the given ID is a remote Sone.
- *
- * @param id
- * The ID of the Sone to check
- * @return {@code true} if the Sone with the given ID is a remote Sone,
- * {@code false} otherwise
- */
- public boolean isRemoteSone(String id) {
- synchronized (remoteSones) {
- return remoteSones.containsKey(id);
- }
- }
-
- /**
- * Returns whether the Sone with the given ID is a new Sone.
- *
- * @param soneId
- * The ID of the sone to check for
- * @return {@code true} if the given Sone is new, false otherwise
- */
- public boolean isNewSone(String soneId) {
- synchronized (newSones) {
- return !knownSones.contains(soneId) && newSones.contains(soneId);
- }
+ public Sone getRemoteSone(String id) {
+ return database.getSone(id).orNull();
}
/**
@@ -523,137 +357,79 @@ public class Core implements IdentityListener, UpdateListener {
* @return {@code true} if a modification has been detected in the Sone,
* {@code false} otherwise
*/
- public boolean isModifiedSone(Sone sone) {
- return (soneInserters.containsKey(sone)) ? soneInserters.get(sone).isModified() : false;
+ public boolean isModifiedSone(LocalSone sone) {
+ return soneInserters.containsKey(sone) && soneInserters.get(sone).isModified();
}
/**
- * Returns whether the target Sone is trusted by the origin Sone.
+ * Returns the time when the given was first followed by any local Sone.
*
- * @param origin
- * The origin Sone
- * @param target
- * The target Sone
- * @return {@code true} if the target Sone is trusted by the origin Sone
+ * @param sone
+ * The Sone to get the time for
+ * @return The time (in milliseconds since Jan 1, 1970) the Sone has first
+ * been followed, or {@link Long#MAX_VALUE}
*/
- public boolean isSoneTrusted(Sone origin, Sone target) {
- return trustedIdentities.containsKey(origin) && trustedIdentities.get(origin.getIdentity()).contains(target);
+ public long getSoneFollowingTime(Sone sone) {
+ return database.getSoneFollowingTime(sone.getId()).or(Long.MAX_VALUE);
}
/**
- * Returns the post with the given ID.
+ * Returns a post builder.
*
- * @param postId
- * The ID of the post to get
- * @return The post, or {@code null} if there is no such post
+ * @return A new post builder
*/
- public Post getPost(String postId) {
- return getPost(postId, true);
+ public PostBuilder postBuilder() {
+ return database.newPostBuilder();
}
/**
- * Returns the post with the given ID, optionally creating a new post.
- *
- * @param postId
- * The ID of the post to get
- * @param create
- * {@code true} it create a new post if no post with the given ID
- * exists, {@code false} to return {@code null}
- * @return The post, or {@code null} if there is no such post
- */
- public Post getPost(String postId, boolean create) {
- synchronized (posts) {
- Post post = posts.get(postId);
- if ((post == null) && create) {
- post = new Post(postId);
- posts.put(postId, post);
- }
- return post;
- }
+ * {@inheritDoc}
+ */
+ @Override
+ public Optional getPost(String postId) {
+ return database.getPost(postId);
}
/**
- * Returns whether the given post ID is new.
- *
- * @param postId
- * The post ID
- * @return {@code true} if the post is considered to be new, {@code false}
- * otherwise
+ * {@inheritDocs}
*/
- public boolean isNewPost(String postId) {
- synchronized (newPosts) {
- return !knownPosts.contains(postId) && newPosts.contains(postId);
- }
+ @Override
+ public Collection getPosts(String soneId) {
+ return database.getPosts(soneId);
}
/**
- * Returns the reply with the given ID. If there is no reply with the given
- * ID yet, a new one is created.
- *
- * @param replyId
- * The ID of the reply to get
- * @return The reply
+ * {@inheritDoc}
*/
- public Reply getReply(String replyId) {
- return getReply(replyId, true);
+ @Override
+ public Collection getDirectedPosts(final String recipientId) {
+ checkNotNull(recipientId, "recipient must not be null");
+ return database.getDirectedPosts(recipientId);
}
/**
- * Returns the reply with the given ID. If there is no reply with the given
- * ID yet, a new one is created, unless {@code create} is false in which
- * case {@code null} is returned.
+ * Returns a post reply builder.
*
- * @param replyId
- * The ID of the reply to get
- * @param create
- * {@code true} to always return a {@link Reply}, {@code false}
- * to return {@code null} if no reply can be found
- * @return The reply, or {@code null} if there is no such reply
- */
- public Reply getReply(String replyId, boolean create) {
- synchronized (replies) {
- Reply reply = replies.get(replyId);
- if (create && (reply == null)) {
- reply = new Reply(replyId);
- replies.put(replyId, reply);
- }
- return reply;
- }
+ * @return A new post reply builder
+ */
+ public PostReplyBuilder postReplyBuilder() {
+ return database.newPostReplyBuilder();
}
/**
- * Returns all replies for the given post, order ascending by time.
- *
- * @param post
- * The post to get all replies for
- * @return All replies for the given post
- */
- public List getReplies(Post post) {
- Set sones = getSones();
- List replies = new ArrayList();
- for (Sone sone : sones) {
- for (Reply reply : sone.getReplies()) {
- if (reply.getPost().equals(post)) {
- replies.add(reply);
- }
- }
- }
- Collections.sort(replies, Reply.TIME_COMPARATOR);
- return replies;
+ * {@inheritDoc}
+ */
+ @Override
+ public Optional getPostReply(String replyId) {
+ return database.getPostReply(replyId);
}
/**
- * Returns whether the reply with the given ID is new.
- *
- * @param replyId
- * The ID of the reply to check
- * @return {@code true} if the reply is considered to be new, {@code false}
- * otherwise
+ * {@inheritDoc}
*/
- public boolean isNewReply(String replyId) {
- synchronized (newReplies) {
- return !knownReplies.contains(replyId) && newReplies.contains(replyId);
- }
+ @Override
+ public List getReplies(final String postId) {
+ return database.getReplies(postId);
}
/**
@@ -680,7 +456,7 @@ public class Core implements IdentityListener, UpdateListener {
* The reply to get the liking Sones for
* @return The Sones that like the given reply
*/
- public Set getLikes(Reply reply) {
+ public Set getLikes(PostReply reply) {
Set sones = new HashSet();
for (Sone sone : getSones()) {
if (sone.getLikedReplyIds().contains(reply.getId())) {
@@ -699,21 +475,7 @@ public class Core implements IdentityListener, UpdateListener {
* otherwise
*/
public boolean isBookmarked(Post post) {
- return isPostBookmarked(post.getId());
- }
-
- /**
- * Returns whether the post with the given ID is bookmarked.
- *
- * @param id
- * The ID of the post to check
- * @return {@code true} if the post with the given ID is bookmarked,
- * {@code false} otherwise
- */
- public boolean isPostBookmarked(String id) {
- synchronized (bookmarkedPosts) {
- return bookmarkedPosts.contains(id);
- }
+ return database.isPostBookmarked(post);
}
/**
@@ -722,28 +484,11 @@ public class Core implements IdentityListener, UpdateListener {
* @return All bookmarked posts
*/
public Set getBookmarkedPosts() {
- Set posts = new HashSet();
- synchronized (bookmarkedPosts) {
- for (String bookmarkedPostId : bookmarkedPosts) {
- Post post = getPost(bookmarkedPostId, false);
- if (post != null) {
- posts.add(post);
- }
- }
- }
- return posts;
+ return database.getBookmarkedPosts();
}
- /**
- * Returns the album with the given ID, creating a new album if no album
- * with the given ID can be found.
- *
- * @param albumId
- * The ID of the album
- * @return The album with the given ID
- */
- public Album getAlbum(String albumId) {
- return getAlbum(albumId, true);
+ public AlbumBuilder albumBuilder() {
+ return database.newAlbumBuilder();
}
/**
@@ -752,21 +497,15 @@ public class Core implements IdentityListener, UpdateListener {
*
* @param albumId
* The ID of the album
- * @param create
- * {@code true} to create a new album if none exists for the
- * given ID
* @return The album with the given ID, or {@code null} if no album with the
- * given ID exists and {@code create} is {@code false}
- */
- public Album getAlbum(String albumId, boolean create) {
- synchronized (albums) {
- Album album = albums.get(albumId);
- if (create && (album == null)) {
- album = new Album(albumId);
- albums.put(albumId, album);
- }
- return album;
- }
+ * given ID exists
+ */
+ public Album getAlbum(String albumId) {
+ return database.getAlbum(albumId).orNull();
+ }
+
+ public ImageBuilder imageBuilder() {
+ return database.newImageBuilder();
}
/**
@@ -793,14 +532,16 @@ public class Core implements IdentityListener, UpdateListener {
* none was created
*/
public Image getImage(String imageId, boolean create) {
- synchronized (images) {
- Image image = images.get(imageId);
- if (create && (image == null)) {
- image = new Image(imageId);
- images.put(imageId, image);
- }
- return image;
+ Optional image = database.getImage(imageId);
+ if (image.isPresent()) {
+ return image.get();
+ }
+ if (!create) {
+ return null;
}
+ Image newImage = database.newImageBuilder().withId(imageId).build();
+ database.storeImage(newImage);
+ return newImage;
}
/**
@@ -823,16 +564,16 @@ public class Core implements IdentityListener, UpdateListener {
/**
* Locks the given Sone. A locked Sone will not be inserted by
- * {@link SoneInserter} until it is {@link #unlockSone(Sone) unlocked}
+ * {@link SoneInserter} until it is {@link #unlockSone(LocalSone) unlocked}
* again.
*
* @param sone
* The sone to lock
*/
- public void lockSone(Sone sone) {
+ public void lockSone(LocalSone sone) {
synchronized (lockedSones) {
if (lockedSones.add(sone)) {
- coreListenerManager.fireSoneLocked(sone);
+ eventBus.post(new SoneLockedEvent(sone));
}
}
}
@@ -840,38 +581,15 @@ public class Core implements IdentityListener, UpdateListener {
/**
* Unlocks the given Sone.
*
- * @see #lockSone(Sone)
+ * @see #lockSone(LocalSone)
* @param sone
* The sone to unlock
*/
- public void unlockSone(Sone sone) {
+ public void unlockSone(LocalSone sone) {
synchronized (lockedSones) {
if (lockedSones.remove(sone)) {
- coreListenerManager.fireSoneUnlocked(sone);
- }
- }
- }
-
- /**
- * Adds a local Sone from the given ID which has to be the ID of an own
- * identity.
- *
- * @param id
- * The ID of an own identity to add a Sone for
- * @return The added (or already existing) Sone
- */
- public Sone addLocalSone(String id) {
- synchronized (localSones) {
- if (localSones.containsKey(id)) {
- logger.log(Level.FINE, "Tried to add known local Sone: %s", id);
- return localSones.get(id);
- }
- OwnIdentity ownIdentity = identityManager.getOwnIdentity(id);
- if (ownIdentity == null) {
- logger.log(Level.INFO, "Invalid Sone ID: %s", id);
- return null;
+ eventBus.post(new SoneUnlockedEvent(sone));
}
- return addLocalSone(ownIdentity);
}
}
@@ -882,57 +600,24 @@ public class Core implements IdentityListener, UpdateListener {
* The own identity to create a Sone from
* @return The added (or already existing) Sone
*/
- public Sone addLocalSone(OwnIdentity ownIdentity) {
+ public LocalSone addLocalSone(OwnIdentity ownIdentity) {
if (ownIdentity == null) {
logger.log(Level.WARNING, "Given OwnIdentity is null!");
return null;
}
- synchronized (localSones) {
- final Sone sone;
- try {
- sone = getLocalSone(ownIdentity.getId()).setIdentity(ownIdentity).setInsertUri(new FreenetURI(ownIdentity.getInsertUri())).setRequestUri(new FreenetURI(ownIdentity.getRequestUri()));
- } catch (MalformedURLException mue1) {
- logger.log(Level.SEVERE, "Could not convert the Identityâs URIs to Freenet URIs: " + ownIdentity.getInsertUri() + ", " + ownIdentity.getRequestUri(), mue1);
- return null;
- }
- sone.setLatestEdition(Numbers.safeParseLong(ownIdentity.getProperty("Sone.LatestEdition"), (long) 0));
- sone.setClient(new Client("Sone", SonePlugin.VERSION.toString()));
- /* TODO - load posts ân stuff */
- localSones.put(ownIdentity.getId(), sone);
- final SoneInserter soneInserter = new SoneInserter(this, freenetInterface, sone);
+ logger.info(String.format("Adding Sone from OwnIdentity: %s", ownIdentity));
+ LocalSone sone = database.registerLocalSone(ownIdentity);
+ SoneInserter soneInserter = new SoneInserter(this, eventBus, freenetInterface, database, ownIdentity.getId());
+ eventBus.register(soneInserter);
+ synchronized (soneInserters) {
soneInserters.put(sone, soneInserter);
- setSoneStatus(sone, SoneStatus.idle);
- loadSone(sone);
- if (!preferences.isSoneRescueMode()) {
- soneInserter.start();
- }
- new Thread(new Runnable() {
-
- @Override
- @SuppressWarnings("synthetic-access")
- public void run() {
- if (!preferences.isSoneRescueMode()) {
- soneDownloader.fetchSone(sone);
- return;
- }
- logger.log(Level.INFO, "Trying to restore Sone from Freenetâ¦");
- coreListenerManager.fireRescuingSone(sone);
- lockSone(sone);
- long edition = sone.getLatestEdition();
- while (!stopped && (edition >= 0) && preferences.isSoneRescueMode()) {
- logger.log(Level.FINE, "Downloading edition " + edition + "â¦");
- soneDownloader.fetchSone(sone, sone.getRequestUri().setKeyType("SSK").setDocName("Sone-" + edition));
- --edition;
- }
- logger.log(Level.INFO, "Finished restoring Sone from Freenet, starting Inserterâ¦");
- saveSone(sone);
- coreListenerManager.fireRescuedSone(sone);
- soneInserter.start();
- }
-
- }, "Sone Downloader").start();
- return sone;
}
+ synchronized (soneInserters) {
+ soneInserters.get(sone).setLastInsertFingerprint(database.getLastInsertFingerprint(sone));
+ }
+ sone.setStatus(SoneStatus.idle);
+ soneInserter.start();
+ return sone;
}
/**
@@ -943,13 +628,14 @@ public class Core implements IdentityListener, UpdateListener {
* @return The created Sone
*/
public Sone createSone(OwnIdentity ownIdentity) {
- try {
- ownIdentity.addContext("Sone");
- } catch (WebOfTrustException wote1) {
- logger.log(Level.SEVERE, "Could not add âSoneâ context to own identity: " + ownIdentity, wote1);
+ if (!webOfTrustUpdater.addContextWait(ownIdentity, "Sone")) {
+ logger.log(Level.SEVERE, String.format("Could not add âSoneâ context to own identity: %s", ownIdentity));
return null;
}
- Sone sone = addLocalSone(ownIdentity);
+ LocalSone sone = addLocalSone(ownIdentity);
+
+ followSone(sone, "nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI");
+ touchConfiguration();
return sone;
}
@@ -965,55 +651,77 @@ public class Core implements IdentityListener, UpdateListener {
logger.log(Level.WARNING, "Given Identity is null!");
return null;
}
- synchronized (remoteSones) {
- final Sone sone = getRemoteSone(identity.getId()).setIdentity(identity);
- boolean newSone = sone.getRequestUri() == null;
- sone.setRequestUri(getSoneUri(identity.getRequestUri()));
- sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), (long) 0));
+ final Long latestEdition = tryParse(fromNullable(
+ identity.getProperty("Sone.LatestEdition")).or("0"));
+ Optional existingSone = getSone(identity.getId());
+ if (existingSone.isPresent() && existingSone.get().isLocal()) {
+ return existingSone.get();
+ }
+ boolean newSone = !existingSone.isPresent();
+ Sone sone = !newSone ? existingSone.get() : database.newSoneBuilder().from(identity).build();
+ sone.setLatestEdition(latestEdition);
+ if (newSone) {
+ newSone = !database.isSoneKnown(sone);
+ sone.setKnown(!newSone);
if (newSone) {
- synchronized (newSones) {
- newSone = !knownSones.contains(sone.getId());
- if (newSone) {
- newSones.add(sone.getId());
+ eventBus.post(new NewSoneFoundEvent(sone));
+ for (LocalSone localSone : getLocalSones()) {
+ if (localSone.getOptions().isAutoFollow()) {
+ followSone(localSone, sone.getId());
}
}
- if (newSone) {
- coreListenerManager.fireNewSoneFound(sone);
+ }
+ }
+ database.storeSone(sone);
+ soneDownloader.addSone(sone);
+ soneDownloaders.execute(soneDownloader.fetchSoneWithUriAction(sone));
+ return sone;
+ }
+
+ /**
+ * Lets the given local Sone follow the Sone with the given ID.
+ *
+ * @param sone
+ * The local Sone that should follow another Sone
+ * @param soneId
+ * The ID of the Sone to follow
+ */
+ public void followSone(LocalSone sone, String soneId) {
+ checkNotNull(sone, "sone must not be null");
+ checkNotNull(soneId, "soneId must not be null");
+ boolean newFriend = !database.getSoneFollowingTime(soneId).isPresent();
+ database.addFriend(sone, soneId);
+ if (newFriend) {
+ long now = System.currentTimeMillis();
+ Optional followedSone = getSone(soneId);
+ if (!followedSone.isPresent()) {
+ return;
+ }
+ for (Post post : followedSone.get().getPosts()) {
+ if (post.getTime() < now) {
+ markPostKnown(post);
}
}
- remoteSones.put(identity.getId(), sone);
- soneDownloader.addSone(sone);
- setSoneStatus(sone, SoneStatus.unknown);
- new Thread(new Runnable() {
-
- @Override
- @SuppressWarnings("synthetic-access")
- public void run() {
- soneDownloader.fetchSone(sone);
+ for (PostReply reply : followedSone.get().getReplies()) {
+ if (reply.getTime() < now) {
+ markReplyKnown(reply);
}
-
- }, "Sone Downloader").start();
- return sone;
+ }
}
}
/**
- * Retrieves the trust relationship from the origin to the target. If the
- * trust relationship can not be retrieved, {@code null} is returned.
+ * Lets the given local Sone unfollow the Sone with the given ID.
*
- * @see Identity#getTrust(OwnIdentity)
- * @param origin
- * The origin of the trust tree
- * @param target
- * The target of the trust
- * @return The trust relationship
+ * @param sone
+ * The local Sone that should unfollow another Sone
+ * @param soneId
+ * The ID of the Sone being unfollowed
*/
- public Trust getTrust(Sone origin, Sone target) {
- if (!isLocalSone(origin)) {
- logger.log(Level.WARNING, "Tried to get trust from remote Sone: %s", origin);
- return null;
- }
- return target.getIdentity().getTrust((OwnIdentity) origin.getIdentity());
+ public void unfollowSone(LocalSone sone, String soneId) {
+ checkNotNull(sone, "sone must not be null");
+ checkNotNull(soneId, "soneId must not be null");
+ database.removeFriend(sone, soneId);
}
/**
@@ -1027,12 +735,11 @@ public class Core implements IdentityListener, UpdateListener {
* The trust value (from {@code -100} to {@code 100})
*/
public void setTrust(Sone origin, Sone target, int trustValue) {
- Validation.begin().isNotNull("Trust Origin", origin).check().isInstanceOf("Trust Origin", origin.getIdentity(), OwnIdentity.class).isNotNull("Trust Target", target).isLessOrEqual("Trust Value", trustValue, 100).isGreaterOrEqual("Trust Value", trustValue, -100).check();
- try {
- ((OwnIdentity) origin.getIdentity()).setTrust(target.getIdentity(), trustValue, preferences.getTrustComment());
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, "Could not set trust for Sone: " + target, wote1);
- }
+ checkNotNull(origin, "origin must not be null");
+ checkArgument(origin.getIdentity() instanceof OwnIdentity, "origin must be a local Sone");
+ checkNotNull(target, "target must not be null");
+ checkArgument((trustValue >= -100) && (trustValue <= 100), "trustValue must be within [-100, 100]");
+ webOfTrustUpdater.setTrust((OwnIdentity) origin.getIdentity(), target.getIdentity(), trustValue, preferences.getTrustComment());
}
/**
@@ -1044,12 +751,10 @@ public class Core implements IdentityListener, UpdateListener {
* The trust target
*/
public void removeTrust(Sone origin, Sone target) {
- Validation.begin().isNotNull("Trust Origin", origin).isNotNull("Trust Target", target).check().isInstanceOf("Trust Origin Identity", origin.getIdentity(), OwnIdentity.class).check();
- try {
- ((OwnIdentity) origin.getIdentity()).removeTrust(target.getIdentity());
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, "Could not remove trust for Sone: " + target, wote1);
- }
+ checkNotNull(origin, "origin must not be null");
+ checkNotNull(target, "target must not be null");
+ checkArgument(origin.getIdentity() instanceof OwnIdentity, "origin must be a local Sone");
+ webOfTrustUpdater.setTrust((OwnIdentity) origin.getIdentity(), target.getIdentity(), null, null);
}
/**
@@ -1089,527 +794,132 @@ public class Core implements IdentityListener, UpdateListener {
}
/**
- * Updates the stores Sone with the given Sone.
+ * Updates the stored Sone with the given Sone.
*
* @param sone
* The updated Sone
*/
public void updateSone(Sone sone) {
- if (hasSone(sone.getId())) {
- boolean soneRescueMode = isLocalSone(sone) && preferences.isSoneRescueMode();
- Sone storedSone = getSone(sone.getId());
- if (!soneRescueMode && !(sone.getTime() > storedSone.getTime())) {
- logger.log(Level.FINE, "Downloaded Sone %s is not newer than stored Sone %s.", new Object[] { sone, storedSone });
- return;
- }
- synchronized (posts) {
- if (!soneRescueMode) {
- for (Post post : storedSone.getPosts()) {
- posts.remove(post.getId());
- if (!sone.getPosts().contains(post)) {
- coreListenerManager.firePostRemoved(post);
- }
- }
- }
- List storedPosts = storedSone.getPosts();
- synchronized (newPosts) {
- for (Post post : sone.getPosts()) {
- post.setSone(storedSone);
- if (!storedPosts.contains(post) && !knownPosts.contains(post.getId())) {
- newPosts.add(post.getId());
- coreListenerManager.fireNewPostFound(post);
- }
- posts.put(post.getId(), post);
- }
- }
- }
- synchronized (replies) {
- if (!soneRescueMode) {
- for (Reply reply : storedSone.getReplies()) {
- replies.remove(reply.getId());
- if (!sone.getReplies().contains(reply)) {
- coreListenerManager.fireReplyRemoved(reply);
- }
- }
- }
- Set storedReplies = storedSone.getReplies();
- synchronized (newReplies) {
- for (Reply reply : sone.getReplies()) {
- reply.setSone(storedSone);
- if (!storedReplies.contains(reply) && !knownReplies.contains(reply.getId())) {
- newReplies.add(reply.getId());
- coreListenerManager.fireNewReplyFound(reply);
- }
- replies.put(reply.getId(), reply);
- }
- }
- }
- synchronized (storedSone) {
- if (!soneRescueMode || (sone.getTime() > storedSone.getTime())) {
- storedSone.setTime(sone.getTime());
- }
- storedSone.setClient(sone.getClient());
- storedSone.setProfile(sone.getProfile());
- if (soneRescueMode) {
- for (Post post : sone.getPosts()) {
- storedSone.addPost(post);
- }
- for (Reply reply : sone.getReplies()) {
- storedSone.addReply(reply);
- }
- for (String likedPostId : sone.getLikedPostIds()) {
- storedSone.addLikedPostId(likedPostId);
- }
- for (String likedReplyId : sone.getLikedReplyIds()) {
- storedSone.addLikedReplyId(likedReplyId);
- }
- } else {
- storedSone.setPosts(sone.getPosts());
- storedSone.setReplies(sone.getReplies());
- storedSone.setLikePostIds(sone.getLikedPostIds());
- storedSone.setLikeReplyIds(sone.getLikedReplyIds());
- }
- storedSone.setLatestEdition(sone.getLatestEdition());
- }
- }
- }
-
- /**
- * Deletes the given Sone. This will remove the Sone from the
- * {@link #getLocalSone(String) local Sones}, stops its {@link SoneInserter}
- * and remove the context from its identity.
- *
- * @param sone
- * The Sone to delete
- */
- public void deleteSone(Sone sone) {
- if (!(sone.getIdentity() instanceof OwnIdentity)) {
- logger.log(Level.WARNING, "Tried to delete Sone of non-own identity: %s", sone);
- return;
- }
- synchronized (localSones) {
- if (!localSones.containsKey(sone.getId())) {
- logger.log(Level.WARNING, "Tried to delete non-local Sone: %s", sone);
- return;
- }
- localSones.remove(sone.getId());
- soneInserters.remove(sone).stop();
- }
- try {
- ((OwnIdentity) sone.getIdentity()).removeContext("Sone");
- ((OwnIdentity) sone.getIdentity()).removeProperty("Sone.LatestEdition");
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, "Could not remove context and properties from Sone: " + sone, wote1);
- }
- try {
- configuration.getLongValue("Sone/" + sone.getId() + "/Time").setValue(null);
- } catch (ConfigurationException ce1) {
- logger.log(Level.WARNING, "Could not remove Sone from configuration!", ce1);
- }
- }
-
- /**
- * Marks the given Sone as known. If the Sone was {@link #isNewPost(String)
- * new} before, a {@link CoreListener#markSoneKnown(Sone)} event is fired.
- *
- * @param sone
- * The Sone to mark as known
- */
- public void markSoneKnown(Sone sone) {
- synchronized (newSones) {
- if (newSones.remove(sone.getId())) {
- knownSones.add(sone.getId());
- coreListenerManager.fireMarkSoneKnown(sone);
- saveConfiguration();
- }
- }
+ updateSone(sone, false);
}
/**
- * Loads and updates the given Sone from the configuration. If any error is
- * encountered, loading is aborted and the given Sone is not changed.
+ * Updates the stored Sone with the given Sone. If {@code soneRescueMode} is
+ * {@code true}, an older Sone than the current Sone can be given to restore
+ * an old state.
*
* @param sone
- * The Sone to load and update
- */
- public void loadSone(Sone sone) {
- if (!isLocalSone(sone)) {
- logger.log(Level.FINE, "Tried to load non-local Sone: %s", sone);
- return;
- }
-
- /* load Sone. */
- String sonePrefix = "Sone/" + sone.getId();
- Long soneTime = configuration.getLongValue(sonePrefix + "/Time").getValue(null);
- if (soneTime == null) {
- logger.log(Level.INFO, "Could not load Sone because no Sone has been saved.");
- return;
- }
- String lastInsertFingerprint = configuration.getStringValue(sonePrefix + "/LastInsertFingerprint").getValue("");
-
- /* load profile. */
- Profile profile = new Profile();
- profile.setFirstName(configuration.getStringValue(sonePrefix + "/Profile/FirstName").getValue(null));
- profile.setMiddleName(configuration.getStringValue(sonePrefix + "/Profile/MiddleName").getValue(null));
- profile.setLastName(configuration.getStringValue(sonePrefix + "/Profile/LastName").getValue(null));
- profile.setBirthDay(configuration.getIntValue(sonePrefix + "/Profile/BirthDay").getValue(null));
- profile.setBirthMonth(configuration.getIntValue(sonePrefix + "/Profile/BirthMonth").getValue(null));
- profile.setBirthYear(configuration.getIntValue(sonePrefix + "/Profile/BirthYear").getValue(null));
-
- /* load profile fields. */
- while (true) {
- String fieldPrefix = sonePrefix + "/Profile/Fields/" + profile.getFields().size();
- String fieldName = configuration.getStringValue(fieldPrefix + "/Name").getValue(null);
- if (fieldName == null) {
- break;
- }
- String fieldValue = configuration.getStringValue(fieldPrefix + "/Value").getValue("");
- profile.addField(fieldName).setValue(fieldValue);
- }
-
- /* load posts. */
- Set posts = new HashSet();
- while (true) {
- String postPrefix = sonePrefix + "/Posts/" + posts.size();
- String postId = configuration.getStringValue(postPrefix + "/ID").getValue(null);
- if (postId == null) {
- break;
- }
- String postRecipientId = configuration.getStringValue(postPrefix + "/Recipient").getValue(null);
- long postTime = configuration.getLongValue(postPrefix + "/Time").getValue((long) 0);
- String postText = configuration.getStringValue(postPrefix + "/Text").getValue(null);
- if ((postTime == 0) || (postText == null)) {
- logger.log(Level.WARNING, "Invalid post found, aborting load!");
- return;
- }
- Post post = getPost(postId).setSone(sone).setTime(postTime).setText(postText);
- if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
- post.setRecipient(getSone(postRecipientId));
- }
- posts.add(post);
- }
-
- /* load replies. */
- Set replies = new HashSet();
- while (true) {
- String replyPrefix = sonePrefix + "/Replies/" + replies.size();
- String replyId = configuration.getStringValue(replyPrefix + "/ID").getValue(null);
- if (replyId == null) {
- break;
- }
- String postId = configuration.getStringValue(replyPrefix + "/Post/ID").getValue(null);
- long replyTime = configuration.getLongValue(replyPrefix + "/Time").getValue((long) 0);
- String replyText = configuration.getStringValue(replyPrefix + "/Text").getValue(null);
- if ((postId == null) || (replyTime == 0) || (replyText == null)) {
- logger.log(Level.WARNING, "Invalid reply found, aborting load!");
+ * The Sone to update
+ * @param soneRescueMode
+ * {@code true} if the stored Sone should be updated regardless
+ * of the age of the given Sone
+ */
+ public void updateSone(final Sone sone, boolean soneRescueMode) {
+ Optional storedSone = getSone(sone.getId());
+ if (storedSone.isPresent()) {
+ if (!soneRescueMode && !(sone.getTime() > storedSone.get().getTime())) {
+ logger.log(Level.FINE, String.format("Downloaded Sone %s is not newer than stored Sone %s.", sone, storedSone));
return;
}
- replies.add(getReply(replyId).setSone(sone).setPost(getPost(postId)).setTime(replyTime).setText(replyText));
- }
-
- /* load post likes. */
- Set likedPostIds = new HashSet();
- while (true) {
- String likedPostId = configuration.getStringValue(sonePrefix + "/Likes/Post/" + likedPostIds.size() + "/ID").getValue(null);
- if (likedPostId == null) {
- break;
+ List