+ /**
+ * Loads the Sone from the given request URI. The fetching of the data is
+ * performed in a new thread so this method returns immediately.
+ *
+ * @param requestUri
+ * The request URI to load the Sone from
+ */
+ public void loadSone(final String requestUri) {
+ loadSone(requestUri, null);
+ }
+
+ /**
+ * Loads the Sone from the given request URI. The fetching of the data is
+ * performed in a new thread so this method returns immediately. If
+ * {@code insertUri} is not {@code null} the loaded Sone is converted into a
+ * local Sone and available using as any other local Sone.
+ *
+ * @param requestUri
+ * The request URI to load the Sone from
+ * @param insertUri
+ * The insert URI of the Sone
+ */
+ public void loadSone(final String requestUri, final String insertUri) {
+ new Thread(new Runnable() {
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ try {
+ FreenetURI realRequestUri = new FreenetURI(requestUri).setMetaString(new String[] { "sone.xml" });
+ FetchResult fetchResult = freenetInterface.fetchUri(realRequestUri);
+ if (fetchResult == null) {
+ return;
+ }
+ Sone parsedSone = soneDownloader.parseSone(null, fetchResult, realRequestUri);
+ if (parsedSone != null) {
+ if (insertUri != null) {
+ parsedSone.setInsertUri(new FreenetURI(insertUri));
+ addLocalSone(parsedSone);
+ } else {
+ addSone(parsedSone);
+ }
+ }
+ } catch (MalformedURLException mue1) {
+ logger.log(Level.INFO, "Could not create URI from “" + requestUri + "”.", mue1);
+ }
+ }
+ }, "Sone Downloader").start();
+ }
+
+ /**
+ * Loads and updates the given Sone.
+ *
+ * @param sone
+ * The Sone to load
+ */
+ public void loadSone(final Sone sone) {
+ new Thread(new Runnable() {
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ FreenetURI realRequestUri = sone.getRequestUri().setMetaString(new String[] { "sone.xml" });
+ setSoneStatus(sone, SoneStatus.downloading);
+ try {
+ FetchResult fetchResult = freenetInterface.fetchUri(realRequestUri);
+ if (fetchResult == null) {
+ /* TODO - mark Sone as bad. */
+ return;
+ }
+ Sone parsedSone = soneDownloader.parseSone(sone, fetchResult, realRequestUri);
+ if (parsedSone != null) {
+ addSone(parsedSone);
+ }
+ } finally {
+ setSoneStatus(sone, (sone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle);
+ }
+ }
+ }, "Sone Downloader").start();
+ }
+
+ /**
+ * Deletes the given Sone from this plugin instance.
+ *
+ * @param sone
+ * The sone to delete
+ */
+ public void deleteSone(Sone sone) {
+ SoneInserter soneInserter = soneInserters.remove(sone);
+ soneInserter.stop();
+ localSones.remove(sone);
+ }
+
+ /**
+ * Returns the post with the given ID. If no post exists yet with the given
+ * ID, a new post is returned.
+ *
+ * @param postId
+ * The ID of the post
+ * @return The post
+ */
+ public Post getPost(String postId) {
+ if (!postCache.containsKey(postId)) {
+ postCache.put(postId, new Post(postId));
+ }
+ return postCache.get(postId);
+ }
+
+ /**
+ * Returns the reply with the given ID. If no reply exists yet with the
+ * given ID, a new reply is returned.
+ *
+ * @param replyId
+ * The ID of the reply
+ * @return The reply
+ */
+ public Reply getReply(String replyId) {
+ if (!replyCache.containsKey(replyId)) {
+ replyCache.put(replyId, new Reply(replyId));
+ }
+ return replyCache.get(replyId);
+ }
+
+ /**
+ * Gets all replies to the given post, sorted by date, oldest first.
+ *
+ * @param post
+ * The post the replies refer to
+ * @return The sorted list of replies for the post
+ */
+ public List<Reply> getReplies(Post post) {
+ List<Reply> replies = new ArrayList<Reply>();
+ for (Reply reply : replyCache.values()) {
+ if (reply.getPost().equals(post)) {
+ replies.add(reply);
+ }
+ }
+ Collections.sort(replies, new Comparator<Reply>() {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(Reply leftReply, Reply rightReply) {
+ return (int) Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, leftReply.getTime() - rightReply.getTime()));
+ }
+ });
+ return replies;
+ }
+
+ /**
+ * Gets all Sones that like the given post.
+ *
+ * @param post
+ * The post to check for
+ * @return All Sones that like the post
+ */
+ public Set<Sone> getLikes(final Post post) {
+ return Filters.filteredSet(getSones(), new Filter<Sone>() {
+
+ @Override
+ public boolean filterObject(Sone sone) {
+ return sone.isLikedPostId(post.getId());
+ }
+ });
+ }
+
+ /**
+ * Gets all Sones that like the given reply.
+ *
+ * @param reply
+ * The reply to check for
+ * @return All Sones that like the reply
+ */
+ public Set<Sone> getLikes(final Reply reply) {
+ return Filters.filteredSet(getSones(), new Filter<Sone>() {
+
+ @Override
+ public boolean filterObject(Sone sone) {
+ return sone.isLikedReplyId(reply.getId());
+ }
+ });
+ }
+
+ /**
+ * Deletes the given reply. It is removed from its Sone and from the reply
+ * cache.
+ *
+ * @param reply
+ * The reply to remove
+ */
+ public void deleteReply(Reply reply) {
+ reply.getSone().removeReply(reply);
+ replyCache.remove(reply.getId());
+ }
+