<artifactId>utils.json</artifactId>
<version>0.1</version>
</dependency>
+ <dependency>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ <version>3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>14.0-rc1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.6</version>
+ </dependency>
</dependencies>
<repositories>
<repository>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
+ <version>2.2</version>
<configuration>
<archive>
<manifestEntries>
</execution>
</executions>
</plugin>
- </plugins>
- </build>
- <reporting>
- <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.7</version>
<configuration>
- <links>
- <link>http://download.oracle.com/javase/6/docs/api/</link>
- <link>http://java.pterodactylus.net/utils/apidocs/</link>
- <link>http://java.pterodactylus.net/utils.json/apidocs/</link>
- </links>
+ <detectLinks>true</detectLinks>
+ <detectJavaApiLink>true</detectJavaApiLink>
+ <show>private</show>
+ <footer>© 2010–2013 David ‘Bombe’ Roden</footer>
</configuration>
</plugin>
</plugins>
- </reporting>
+ </build>
</project>
/*
- * Sone - Core.java - Copyright © 2010–2012 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
package net.pterodactylus.sone.core;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.net.MalformedURLException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
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.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.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.Sone.ShowCustomAvatars;
import net.pterodactylus.sone.data.Sone.SoneStatus;
import net.pterodactylus.sone.data.TemporaryImage;
-import net.pterodactylus.sone.data.impl.PostImpl;
+import net.pterodactylus.sone.database.Database;
+import net.pterodactylus.sone.database.DatabaseException;
+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.SoneProvider;
import net.pterodactylus.sone.fcp.FcpInterface;
import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
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.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.sone.main.SonePlugin;
+import net.pterodactylus.sone.utils.IntegerRangePredicate;
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.service.AbstractService;
import net.pterodactylus.util.thread.NamedThreadFactory;
-import net.pterodactylus.util.thread.Ticker;
-import net.pterodactylus.util.validation.EqualityValidator;
-import net.pterodactylus.util.validation.IntegerRangeValidator;
-import net.pterodactylus.util.validation.OrValidator;
-import net.pterodactylus.util.validation.Validation;
-import net.pterodactylus.util.version.Version;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.FluentIterable;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+
import freenet.keys.FreenetURI;
/**
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
-public class Core extends AbstractService implements IdentityListener, UpdateListener, SoneProvider, PostProvider, SoneInsertListener, ImageInsertListener {
+public class Core extends AbstractService implements SoneProvider, PostProvider, PostReplyProvider {
/** The logger. */
private static final Logger logger = Logging.getLogger(Core.class);
/** The preferences. */
private final Preferences preferences = new Preferences(options);
- /** The core listener manager. */
- private final CoreListenerManager coreListenerManager = new CoreListenerManager(this);
+ /** The event bus. */
+ private final EventBus eventBus;
/** The configuration. */
private Configuration configuration;
private volatile FcpInterface fcpInterface;
/** The times Sones were followed. */
- private final Map<Sone, Long> soneFollowingTimes = new HashMap<Sone, Long>();
+ private final Map<String, Long> soneFollowingTimes = new HashMap<String, Long>();
/** Locked local Sones. */
/* synchronize on itself. */
private final Set<Sone> lockedSones = new HashSet<Sone>();
/** Sone inserters. */
- /* synchronize access on this on localSones. */
+ /* synchronize access on this on sones. */
private final Map<Sone, SoneInserter> soneInserters = new HashMap<Sone, SoneInserter>();
/** Sone rescuers. */
- /* synchronize access on this on localSones. */
+ /* synchronize access on this on sones. */
private final Map<Sone, SoneRescuer> soneRescuers = new HashMap<Sone, SoneRescuer>();
- /** All local Sones. */
- /* synchronize access on this on itself. */
- private final Map<String, Sone> localSones = new HashMap<String, Sone>();
-
- /** All remote Sones. */
+ /** All Sones. */
/* synchronize access on this on itself. */
- private final Map<String, Sone> remoteSones = new HashMap<String, Sone>();
+ private final Map<String, Sone> sones = new HashMap<String, Sone>();
/** All known Sones. */
private final Set<String> knownSones = new HashSet<String>();
- /** All posts. */
- private final Map<String, Post> posts = new HashMap<String, Post>();
-
- /** All known posts. */
- private final Set<String> knownPosts = new HashSet<String>();
-
- /** All replies. */
- private final Map<String, PostReply> replies = new HashMap<String, PostReply>();
-
- /** All known replies. */
- private final Set<String> knownReplies = new HashSet<String>();
+ /** The post database. */
+ private final Database database;
/** All bookmarked posts. */
/* synchronize access on itself. */
private final Map<String, TemporaryImage> temporaryImages = new HashMap<String, TemporaryImage>();
/** Ticker for threads that mark own elements as known. */
- private final Ticker localElementTicker = new Ticker();
+ private final ScheduledExecutorService localElementTicker = Executors.newScheduledThreadPool(1);
/** The time the configuration was last touched. */
private volatile long lastConfigurationUpdate;
* The identity manager
* @param webOfTrustUpdater
* The WebOfTrust updater
+ * @param eventBus
+ * The event bus
+ * @param database
+ * The database
*/
- public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater) {
+ @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.imageInserter = new ImageInserter(this, freenetInterface);
- this.updateChecker = new UpdateChecker(freenetInterface);
+ this.imageInserter = new ImageInserter(freenetInterface);
+ this.updateChecker = new UpdateChecker(eventBus, freenetInterface);
this.webOfTrustUpdater = webOfTrustUpdater;
- }
-
- //
- // 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.eventBus = eventBus;
+ this.database = database;
}
//
* @return The Sone rescuer for the given Sone
*/
public SoneRescuer getSoneRescuer(Sone sone) {
- Validation.begin().isNotNull("Sone", sone).check().is("Local Sone", isLocalSone(sone)).check();
- synchronized (localSones) {
+ checkNotNull(sone, "sone must not be null");
+ checkArgument(sone.isLocal(), "sone must be local");
+ synchronized (sones) {
SoneRescuer soneRescuer = soneRescuers.get(sone);
if (soneRescuer == null) {
soneRescuer = new SoneRescuer(this, soneDownloader, sone);
}
/**
- * Returns all Sones, remote and local.
- *
- * @return All Sones
+ * {@inheritDocs}
*/
- public Set<Sone> getSones() {
- Set<Sone> allSones = new HashSet<Sone>();
- allSones.addAll(getLocalSones());
- allSones.addAll(getRemoteSones());
- return allSones;
- }
-
- /**
- * 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
- */
- public Sone getSone(String id) {
- return getSone(id, true);
+ @Override
+ public Collection<Sone> getSones() {
+ synchronized (sones) {
+ return Collections.unmodifiableCollection(sones.values());
+ }
}
/**
*
* @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
*/
@Override
- 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());
+ public Optional<Sone> getSone(String id) {
+ synchronized (sones) {
+ return Optional.fromNullable(sones.get(id));
}
}
/**
- * 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
+ * {@inheritDocs}
*/
- public boolean isLocalSone(String id) {
- synchronized (localSones) {
- return localSones.containsKey(id);
- }
- }
+ @Override
+ public Collection<Sone> getLocalSones() {
+ synchronized (sones) {
+ return Collections2.filter(sones.values(), new Predicate<Sone>() {
- /**
- * Returns all local Sones.
- *
- * @return All local Sones
- */
- public Set<Sone> getLocalSones() {
- synchronized (localSones) {
- return new HashSet<Sone>(localSones.values());
+ @Override
+ public boolean apply(Sone sone) {
+ return sone.isLocal();
+ }
+ });
}
}
/**
- * 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);
- }
-
- /**
* Returns the local Sone with the given ID, optionally creating a new Sone.
*
* @param id
* @return The Sone with the given ID, or {@code null}
*/
public Sone getLocalSone(String id, boolean create) {
- synchronized (localSones) {
- Sone sone = localSones.get(id);
+ synchronized (sones) {
+ Sone sone = sones.get(id);
if ((sone == null) && create) {
- sone = new Sone(id);
- localSones.put(id, sone);
+ sone = new Sone(id, true);
+ sones.put(id, sone);
+ }
+ if ((sone != null) && !sone.isLocal()) {
+ sone = new Sone(id, true);
+ sones.put(id, sone);
}
return sone;
}
}
/**
- * Returns all remote Sones.
- *
- * @return All remote Sones
+ * {@inheritDocs}
*/
- public Set<Sone> getRemoteSones() {
- synchronized (remoteSones) {
- return new HashSet<Sone>(remoteSones.values());
+ @Override
+ public Collection<Sone> getRemoteSones() {
+ synchronized (sones) {
+ return Collections2.filter(sones.values(), new Predicate<Sone>() {
+
+ @Override
+ public boolean apply(Sone sone) {
+ return !sone.isLocal();
+ }
+ });
}
}
* @return The Sone with the given ID
*/
public Sone getRemoteSone(String id, boolean create) {
- synchronized (remoteSones) {
- Sone sone = remoteSones.get(id);
+ synchronized (sones) {
+ Sone sone = sones.get(id);
if ((sone == null) && create && (id != null) && (id.length() == 43)) {
- sone = new Sone(id);
- remoteSones.put(id, sone);
+ sone = new Sone(id, false);
+ sones.put(id, sone);
}
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 given Sone has been modified.
*
* @param sone
*/
public long getSoneFollowingTime(Sone sone) {
synchronized (soneFollowingTimes) {
- if (soneFollowingTimes.containsKey(sone)) {
- return soneFollowingTimes.get(sone);
- }
- return Long.MAX_VALUE;
+ return Optional.fromNullable(soneFollowingTimes.get(sone.getId())).or(Long.MAX_VALUE);
}
}
* @return {@code true} if the target Sone is trusted by the origin Sone
*/
public boolean isSoneTrusted(Sone origin, Sone target) {
- Validation.begin().isNotNull("Origin", origin).isNotNull("Target", target).check().isInstanceOf("Origin’s OwnIdentity", origin.getIdentity(), OwnIdentity.class).check();
+ checkNotNull(origin, "origin must not be null");
+ checkNotNull(target, "target must not be null");
+ checkArgument(origin.getIdentity() instanceof OwnIdentity, "origin’s identity must be an OwnIdentity");
return trustedIdentities.containsKey(origin.getIdentity()) && trustedIdentities.get(origin.getIdentity()).contains(target.getIdentity());
}
/**
- * Returns the post with the given ID.
+ * Returns a post builder.
*
- * @param postId
- * The ID of the post to get
- * @return The post with the given ID, or a new post with the given ID
+ * @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
+ * {@inheritDoc}
*/
@Override
- public Post getPost(String postId, boolean create) {
- synchronized (posts) {
- Post post = posts.get(postId);
- if ((post == null) && create) {
- post = new PostImpl(postId);
- posts.put(postId, post);
- }
- return post;
- }
+ public Optional<Post> getPost(String postId) {
+ return database.getPost(postId);
}
/**
- * Returns all posts that have the given Sone as recipient.
- *
- * @see Post#getRecipient()
- * @param recipient
- * The recipient of the posts
- * @return All posts that have the given Sone as recipient
- */
- public Set<Post> getDirectedPosts(Sone recipient) {
- Validation.begin().isNotNull("Recipient", recipient).check();
- Set<Post> directedPosts = new HashSet<Post>();
- synchronized (posts) {
- for (Post post : posts.values()) {
- if (recipient.equals(post.getRecipient())) {
- directedPosts.add(post);
- }
- }
- }
- return directedPosts;
+ * {@inheritDocs}
+ */
+ @Override
+ public Collection<Post> 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 PostReply getReply(String replyId) {
- return getReply(replyId, true);
+ @Override
+ public Collection<Post> 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
+ * @return A new post reply builder
*/
- public PostReply getReply(String replyId, boolean create) {
- synchronized (replies) {
- PostReply reply = replies.get(replyId);
- if (create && (reply == null)) {
- reply = new PostReply(replyId);
- replies.put(replyId, reply);
- }
- return reply;
- }
+ 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
+ * {@inheritDoc}
*/
- public List<PostReply> getReplies(Post post) {
- Set<Sone> sones = getSones();
- List<PostReply> replies = new ArrayList<PostReply>();
- for (Sone sone : sones) {
- for (PostReply reply : sone.getReplies()) {
- if (reply.getPost().equals(post)) {
- replies.add(reply);
- }
- }
- }
- Collections.sort(replies, Reply.TIME_COMPARATOR);
- return replies;
+ @Override
+ public Optional<PostReply> getPostReply(String replyId) {
+ return database.getPostReply(replyId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<PostReply> getReplies(final String postId) {
+ return database.getReplies(postId);
}
/**
Set<Post> posts = new HashSet<Post>();
synchronized (bookmarkedPosts) {
for (String bookmarkedPostId : bookmarkedPosts) {
- Post post = getPost(bookmarkedPostId, false);
- if (post != null) {
- posts.add(post);
+ Optional<Post> post = getPost(bookmarkedPostId);
+ if (!post.isPresent()) {
+ posts.add(post.get());
}
}
}
public void lockSone(Sone sone) {
synchronized (lockedSones) {
if (lockedSones.add(sone)) {
- coreListenerManager.fireSoneLocked(sone);
+ eventBus.post(new SoneLockedEvent(sone));
}
}
}
public void unlockSone(Sone sone) {
synchronized (lockedSones) {
if (lockedSones.remove(sone)) {
- coreListenerManager.fireSoneUnlocked(sone);
+ eventBus.post(new SoneUnlockedEvent(sone));
}
}
}
logger.log(Level.WARNING, "Given OwnIdentity is null!");
return null;
}
- synchronized (localSones) {
+ synchronized (sones) {
final Sone sone;
try {
- sone = getLocalSone(ownIdentity.getId()).setIdentity(ownIdentity).setInsertUri(new FreenetURI(ownIdentity.getInsertUri())).setRequestUri(new FreenetURI(ownIdentity.getRequestUri()));
+ sone = getLocalSone(ownIdentity.getId(), true).setIdentity(ownIdentity).setInsertUri(new FreenetURI(ownIdentity.getInsertUri())).setRequestUri(new FreenetURI(ownIdentity.getRequestUri()));
} catch (MalformedURLException mue1) {
logger.log(Level.SEVERE, String.format("Could not convert the Identity’s URIs to Freenet URIs: %s, %s", ownIdentity.getInsertUri(), ownIdentity.getRequestUri()), mue1);
return null;
sone.setClient(new Client("Sone", SonePlugin.VERSION.toString()));
sone.setKnown(true);
/* TODO - load posts ’n stuff */
- localSones.put(ownIdentity.getId(), sone);
- final SoneInserter soneInserter = new SoneInserter(this, freenetInterface, sone);
- soneInserter.addSoneInsertListener(this);
+ trustedIdentities.put(ownIdentity, Collections.synchronizedSet(new HashSet<Identity>()));
+ sones.put(ownIdentity.getId(), sone);
+ final SoneInserter soneInserter = new SoneInserter(this, eventBus, freenetInterface, sone);
soneInserters.put(sone, soneInserter);
sone.setStatus(SoneStatus.idle);
loadSone(sone);
sone.getOptions().addBooleanOption("ShowNotification/NewReplies", new DefaultOption<Boolean>(true));
sone.getOptions().addEnumOption("ShowCustomAvatars", new DefaultOption<ShowCustomAvatars>(ShowCustomAvatars.NEVER));
- followSone(sone, getSone("nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI"));
+ followSone(sone, "nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI");
touchConfiguration();
return sone;
}
logger.log(Level.WARNING, "Given Identity is null!");
return null;
}
- synchronized (remoteSones) {
+ synchronized (sones) {
final Sone sone = getRemoteSone(identity.getId(), true).setIdentity(identity);
boolean newSone = sone.getRequestUri() == null;
- sone.setRequestUri(getSoneUri(identity.getRequestUri()));
+ sone.setRequestUri(SoneUri.create(identity.getRequestUri()));
sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), (long) 0));
if (newSone) {
synchronized (knownSones) {
}
sone.setKnown(!newSone);
if (newSone) {
- coreListenerManager.fireNewSoneFound(sone);
+ eventBus.post(new NewSoneFoundEvent(sone));
for (Sone localSone : getLocalSones()) {
if (localSone.getOptions().getBooleanOption("AutoFollow").get()) {
- followSone(localSone, sone);
+ followSone(localSone, sone.getId());
}
}
}
* The ID of the Sone to follow
*/
public void followSone(Sone sone, String soneId) {
- Validation.begin().isNotNull("Sone", sone).isNotNull("Sone ID", soneId).check();
- Sone followedSone = getSone(soneId, true);
- if (followedSone == null) {
- logger.log(Level.INFO, String.format("Ignored Sone with invalid ID: %s", soneId));
- return;
- }
- followSone(sone, getSone(soneId));
- }
-
- /**
- * Lets the given local Sone follow the other given Sone. If the given Sone
- * was not followed by any local Sone before, this will mark all elements of
- * the followed Sone as read that have been created before the current
- * moment.
- *
- * @param sone
- * The local Sone that should follow the other Sone
- * @param followedSone
- * The Sone that should be followed
- */
- public void followSone(Sone sone, Sone followedSone) {
- Validation.begin().isNotNull("Sone", sone).isNotNull("Followed Sone", followedSone).check();
- sone.addFriend(followedSone.getId());
+ checkNotNull(sone, "sone must not be null");
+ checkNotNull(soneId, "soneId must not be null");
+ sone.addFriend(soneId);
synchronized (soneFollowingTimes) {
- if (!soneFollowingTimes.containsKey(followedSone)) {
+ if (!soneFollowingTimes.containsKey(soneId)) {
long now = System.currentTimeMillis();
- soneFollowingTimes.put(followedSone, now);
- for (Post post : followedSone.getPosts()) {
+ soneFollowingTimes.put(soneId, now);
+ Optional<Sone> followedSone = getSone(soneId);
+ if (!followedSone.isPresent()) {
+ return;
+ }
+ for (Post post : followedSone.get().getPosts()) {
if (post.getTime() < now) {
markPostKnown(post);
}
}
- for (PostReply reply : followedSone.getReplies()) {
+ for (PostReply reply : followedSone.get().getReplies()) {
if (reply.getTime() < now) {
markReplyKnown(reply);
}
* The ID of the Sone being unfollowed
*/
public void unfollowSone(Sone sone, String soneId) {
- Validation.begin().isNotNull("Sone", sone).isNotNull("Sone ID", soneId).check();
- unfollowSone(sone, getSone(soneId, false));
- }
-
- /**
- * Lets the given local Sone unfollow the other given Sone. If the given
- * local Sone is the last local Sone that followed the given Sone, its
- * following time will be removed.
- *
- * @param sone
- * The local Sone that should unfollow another Sone
- * @param unfollowedSone
- * The Sone being unfollowed
- */
- public void unfollowSone(Sone sone, Sone unfollowedSone) {
- Validation.begin().isNotNull("Sone", sone).isNotNull("Unfollowed Sone", unfollowedSone).check();
- sone.removeFriend(unfollowedSone.getId());
+ checkNotNull(sone, "sone must not be null");
+ checkNotNull(soneId, "soneId must not be null");
+ sone.removeFriend(soneId);
boolean unfollowedSoneStillFollowed = false;
for (Sone localSone : getLocalSones()) {
- unfollowedSoneStillFollowed |= localSone.hasFriend(unfollowedSone.getId());
+ unfollowedSoneStillFollowed |= localSone.hasFriend(soneId);
}
if (!unfollowedSoneStillFollowed) {
synchronized (soneFollowingTimes) {
- soneFollowingTimes.remove(unfollowedSone);
+ soneFollowingTimes.remove(soneId);
}
}
touchConfiguration();
* 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();
+ 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());
}
* 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();
+ 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);
}
* of the age of the given Sone
*/
public void updateSone(Sone sone, boolean soneRescueMode) {
- if (hasSone(sone.getId())) {
- Sone storedSone = getSone(sone.getId());
- if (!soneRescueMode && !(sone.getTime() > storedSone.getTime())) {
+ Optional<Sone> 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;
}
- synchronized (posts) {
- if (!soneRescueMode) {
- for (Post post : storedSone.getPosts()) {
- posts.remove(post.getId());
- if (!sone.getPosts().contains(post)) {
- coreListenerManager.firePostRemoved(post);
- }
- }
+ /* find removed posts. */
+ Collection<Post> existingPosts = database.getPosts(sone.getId());
+ for (Post oldPost : existingPosts) {
+ if (!sone.getPosts().contains(oldPost)) {
+ eventBus.post(new PostRemovedEvent(oldPost));
}
- List<Post> storedPosts = storedSone.getPosts();
- synchronized (knownPosts) {
- for (Post post : sone.getPosts()) {
- post.setSone(storedSone).setKnown(knownPosts.contains(post.getId()));
- if (!storedPosts.contains(post)) {
- if (post.getTime() < getSoneFollowingTime(sone)) {
- knownPosts.add(post.getId());
- post.setKnown(true);
- } else if (!knownPosts.contains(post.getId())) {
- coreListenerManager.fireNewPostFound(post);
- }
- }
- posts.put(post.getId(), post);
- }
+ }
+ /* find new posts. */
+ for (Post newPost : sone.getPosts()) {
+ if (existingPosts.contains(newPost)) {
+ continue;
+ }
+ if (newPost.getTime() < getSoneFollowingTime(sone)) {
+ newPost.setKnown(true);
+ } else if (!newPost.isKnown()) {
+ eventBus.post(new NewPostFoundEvent(newPost));
}
}
- synchronized (replies) {
- if (!soneRescueMode) {
- for (PostReply reply : storedSone.getReplies()) {
- replies.remove(reply.getId());
- if (!sone.getReplies().contains(reply)) {
- coreListenerManager.fireReplyRemoved(reply);
- }
+ /* store posts. */
+ database.storePosts(sone, sone.getPosts());
+ if (!soneRescueMode) {
+ for (PostReply reply : storedSone.get().getReplies()) {
+ if (!sone.getReplies().contains(reply)) {
+ eventBus.post(new PostReplyRemovedEvent(reply));
}
}
- Set<PostReply> storedReplies = storedSone.getReplies();
- synchronized (knownReplies) {
- for (PostReply reply : sone.getReplies()) {
- reply.setSone(storedSone).setKnown(knownReplies.contains(reply.getId()));
- if (!storedReplies.contains(reply)) {
- if (reply.getTime() < getSoneFollowingTime(sone)) {
- knownReplies.add(reply.getId());
- reply.setKnown(true);
- } else if (!knownReplies.contains(reply.getId())) {
- coreListenerManager.fireNewReplyFound(reply);
- }
- }
- replies.put(reply.getId(), reply);
- }
+ }
+ Set<PostReply> storedReplies = storedSone.get().getReplies();
+ for (PostReply reply : sone.getReplies()) {
+ if (storedReplies.contains(reply)) {
+ continue;
+ }
+ if (reply.getTime() < getSoneFollowingTime(sone)) {
+ reply.setKnown(true);
+ } else if (!reply.isKnown()) {
+ eventBus.post(new NewPostReplyFoundEvent(reply));
}
}
+ database.storePostReplies(sone, sone.getReplies());
synchronized (albums) {
synchronized (images) {
- for (Album album : storedSone.getAlbums()) {
+ for (Album album : storedSone.get().getAlbums()) {
albums.remove(album.getId());
for (Image image : album.getImages()) {
images.remove(image.getId());
}
}
}
- 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 (PostReply reply : sone.getReplies()) {
- storedSone.addReply(reply);
- }
- for (String likedPostId : sone.getLikedPostIds()) {
- storedSone.addLikedPostId(likedPostId);
- }
- for (String likedReplyId : sone.getLikedReplyIds()) {
- storedSone.addLikedReplyId(likedReplyId);
- }
- for (Album album : sone.getAlbums()) {
- storedSone.addAlbum(album);
- }
- } else {
- storedSone.setPosts(sone.getPosts());
- storedSone.setReplies(sone.getReplies());
- storedSone.setLikePostIds(sone.getLikedPostIds());
- storedSone.setLikeReplyIds(sone.getLikedReplyIds());
- storedSone.setAlbums(sone.getAlbums());
- }
- storedSone.setLatestEdition(sone.getLatestEdition());
+ synchronized (sones) {
+ sone.setOptions(storedSone.get().getOptions());
+ sones.put(sone.getId(), sone);
}
}
}
/**
* 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.
+ * {@link #getLocalSones() local Sones}, stop its {@link SoneInserter} and
+ * remove the context from its identity.
*
* @param sone
* The Sone to delete
logger.log(Level.WARNING, String.format("Tried to delete Sone of non-own identity: %s", sone));
return;
}
- synchronized (localSones) {
- if (!localSones.containsKey(sone.getId())) {
+ synchronized (sones) {
+ if (!getLocalSones().contains(sone)) {
logger.log(Level.WARNING, String.format("Tried to delete non-local Sone: %s", sone));
return;
}
- localSones.remove(sone.getId());
+ sones.remove(sone.getId());
SoneInserter soneInserter = soneInserters.remove(sone);
- soneInserter.removeSoneInsertListener(this);
soneInserter.stop();
}
webOfTrustUpdater.removeContext((OwnIdentity) sone.getIdentity(), "Sone");
/**
* Marks the given Sone as known. If the Sone was not {@link Post#isKnown()
- * known} before, a {@link CoreListener#markSoneKnown(Sone)} event is fired.
+ * known} before, a {@link MarkSoneKnownEvent} is fired.
*
* @param sone
* The Sone to mark as known
synchronized (knownSones) {
knownSones.add(sone.getId());
}
- coreListenerManager.fireMarkSoneKnown(sone);
+ eventBus.post(new MarkSoneKnownEvent(sone));
touchConfiguration();
}
}
* The Sone to load and update
*/
public void loadSone(Sone sone) {
- if (!isLocalSone(sone)) {
+ if (!sone.isLocal()) {
logger.log(Level.FINE, String.format("Tried to load non-local Sone: %s", sone));
return;
}
logger.log(Level.WARNING, "Invalid post found, aborting load!");
return;
}
- Post post = getPost(postId).setSone(sone).setTime(postTime).setText(postText);
+ PostBuilder postBuilder = postBuilder().withId(postId).from(sone.getId()).withTime(postTime).withText(postText);
if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
- post.setRecipient(getSone(postRecipientId));
+ postBuilder.to(postRecipientId);
}
- posts.add(post);
+ posts.add(postBuilder.build());
}
/* load replies. */
logger.log(Level.WARNING, "Invalid reply found, aborting load!");
return;
}
- replies.add(getReply(replyId).setSone(sone).setPost(getPost(postId)).setTime(replyTime).setText(replyText));
+ PostReplyBuilder postReplyBuilder = postReplyBuilder().withId(replyId).from(sone.getId()).to(postId).withTime(replyTime).withText(replyText);
+ replies.add(postReplyBuilder.build());
}
/* load post likes. */
knownSones.add(friend);
}
}
- synchronized (knownPosts) {
- for (Post post : posts) {
- knownPosts.add(post.getId());
- }
+ database.storePosts(sone, posts);
+ for (Post post : posts) {
+ post.setKnown(true);
}
- synchronized (knownReplies) {
- for (PostReply reply : replies) {
- knownReplies.add(reply.getId());
- }
+ database.storePostReplies(sone, replies);
+ for (PostReply reply : replies) {
+ reply.setKnown(true);
}
}
* The text of the post
* @return The created post
*/
- public Post createPost(Sone sone, Sone recipient, String text) {
+ public Post createPost(Sone sone, Optional<Sone> recipient, String text) {
return createPost(sone, recipient, System.currentTimeMillis(), text);
}
* The text of the post
* @return The created post
*/
- public Post createPost(Sone sone, Sone recipient, long time, String text) {
- Validation.begin().isNotNull("Text", text).check().isGreater("Text Length", text.length(), 0).check();
- if (!isLocalSone(sone)) {
+ public Post createPost(Sone sone, Optional<Sone> recipient, long time, String text) {
+ checkNotNull(text, "text must not be null");
+ checkArgument(text.trim().length() > 0, "text must not be empty");
+ if (!sone.isLocal()) {
logger.log(Level.FINE, String.format("Tried to create post for non-local Sone: %s", sone));
return null;
}
- final Post post = new PostImpl(sone, time, text);
- if (recipient != null) {
- post.setRecipient(recipient);
+ PostBuilder postBuilder = database.newPostBuilder();
+ postBuilder.from(sone.getId()).randomId().withTime(time).withText(text.trim());
+ if (recipient.isPresent()) {
+ postBuilder.to(recipient.get().getId());
}
- synchronized (posts) {
- posts.put(post.getId(), post);
- }
- coreListenerManager.fireNewPostFound(post);
+ final Post post = postBuilder.build();
+ database.storePost(post);
+ eventBus.post(new NewPostFoundEvent(post));
sone.addPost(post);
touchConfiguration();
- localElementTicker.registerEvent(System.currentTimeMillis() + 10 * 1000, new Runnable() {
+ localElementTicker.schedule(new Runnable() {
/**
* {@inheritDoc}
public void run() {
markPostKnown(post);
}
- }, "Mark " + post + " read.");
+ }, 10, TimeUnit.SECONDS);
return post;
}
* The post to delete
*/
public void deletePost(Post post) {
- if (!isLocalSone(post.getSone())) {
+ if (!post.getSone().isLocal()) {
logger.log(Level.WARNING, String.format("Tried to delete post of non-local Sone: %s", post.getSone()));
return;
}
- post.getSone().removePost(post);
- synchronized (posts) {
- posts.remove(post.getId());
- }
- coreListenerManager.firePostRemoved(post);
+ database.removePost(post);
+ eventBus.post(new PostRemovedEvent(post));
markPostKnown(post);
touchConfiguration();
}
*/
public void markPostKnown(Post post) {
post.setKnown(true);
- synchronized (knownPosts) {
- coreListenerManager.fireMarkPostKnown(post);
- if (knownPosts.add(post.getId())) {
- touchConfiguration();
- }
- }
- for (PostReply reply : getReplies(post)) {
+ eventBus.post(new MarkPostKnownEvent(post));
+ touchConfiguration();
+ for (PostReply reply : getReplies(post.getId())) {
markReplyKnown(reply);
}
}
* @return The created reply
*/
public PostReply createReply(Sone sone, Post post, String text) {
- return createReply(sone, post, System.currentTimeMillis(), text);
- }
-
- /**
- * Creates a new reply.
- *
- * @param sone
- * The Sone that creates the reply
- * @param post
- * The post that this reply refers to
- * @param time
- * The time of the reply
- * @param text
- * The text of the reply
- * @return The created reply
- */
- public PostReply createReply(Sone sone, Post post, long time, String text) {
- Validation.begin().isNotNull("Text", text).check().isGreater("Text Length", text.trim().length(), 0).check();
- if (!isLocalSone(sone)) {
+ checkNotNull(text, "text must not be null");
+ checkArgument(text.trim().length() > 0, "text must not be empty");
+ if (!sone.isLocal()) {
logger.log(Level.FINE, String.format("Tried to create reply for non-local Sone: %s", sone));
return null;
}
- final PostReply reply = new PostReply(sone, post, System.currentTimeMillis(), text);
- synchronized (replies) {
- replies.put(reply.getId(), reply);
- }
- synchronized (knownReplies) {
- coreListenerManager.fireNewReplyFound(reply);
- }
+ PostReplyBuilder postReplyBuilder = postReplyBuilder();
+ postReplyBuilder.randomId().from(sone.getId()).to(post.getId()).currentTime().withText(text.trim());
+ final PostReply reply = postReplyBuilder.build();
+ database.storePostReply(reply);
+ eventBus.post(new NewPostReplyFoundEvent(reply));
sone.addReply(reply);
touchConfiguration();
- localElementTicker.registerEvent(System.currentTimeMillis() + 10 * 1000, new Runnable() {
+ localElementTicker.schedule(new Runnable() {
/**
* {@inheritDoc}
public void run() {
markReplyKnown(reply);
}
- }, "Mark " + reply + " read.");
+ }, 10, TimeUnit.SECONDS);
return reply;
}
*/
public void deleteReply(PostReply reply) {
Sone sone = reply.getSone();
- if (!isLocalSone(sone)) {
+ if (!sone.isLocal()) {
logger.log(Level.FINE, String.format("Tried to delete non-local reply: %s", reply));
return;
}
- synchronized (replies) {
- replies.remove(reply.getId());
- }
- synchronized (knownReplies) {
- markReplyKnown(reply);
- knownReplies.remove(reply.getId());
- }
+ database.removePostReply(reply);
+ markReplyKnown(reply);
sone.removeReply(reply);
touchConfiguration();
}
* The reply to mark as known
*/
public void markReplyKnown(PostReply reply) {
+ boolean previouslyKnown = reply.isKnown();
reply.setKnown(true);
- synchronized (knownReplies) {
- coreListenerManager.fireMarkReplyKnown(reply);
- if (knownReplies.add(reply.getId())) {
- touchConfiguration();
- }
+ eventBus.post(new MarkPostReplyKnownEvent(reply));
+ if (!previouslyKnown) {
+ touchConfiguration();
}
}
* The album to remove
*/
public void deleteAlbum(Album album) {
- Validation.begin().isNotNull("Album", album).check().is("Local Sone", isLocalSone(album.getSone())).check();
+ checkNotNull(album, "album must not be null");
+ checkArgument(album.getSone().isLocal(), "album’s Sone must be a local Sone");
if (!album.isEmpty()) {
return;
}
* @return The newly created image
*/
public Image createImage(Sone sone, Album album, TemporaryImage temporaryImage) {
- Validation.begin().isNotNull("Sone", sone).isNotNull("Album", album).isNotNull("Temporary Image", temporaryImage).check().is("Local Sone", isLocalSone(sone)).check().isEqual("Owner and Album Owner", sone, album.getSone()).check();
+ checkNotNull(sone, "sone must not be null");
+ checkNotNull(album, "album must not be null");
+ checkNotNull(temporaryImage, "temporaryImage must not be null");
+ checkArgument(sone.isLocal(), "sone must be a local Sone");
+ checkArgument(sone.equals(album.getSone()), "album must belong to the given Sone");
Image image = new Image(temporaryImage.getId()).setSone(sone).setCreationTime(System.currentTimeMillis());
album.addImage(image);
synchronized (images) {
* The image to delete
*/
public void deleteImage(Image image) {
- Validation.begin().isNotNull("Image", image).check().is("Local Sone", isLocalSone(image.getSone())).check();
+ checkNotNull(image, "image must not be null");
+ checkArgument(image.getSone().isLocal(), "image must belong to a local Sone");
deleteTemporaryImage(image.getId());
image.getAlbum().removeImage(image);
synchronized (images) {
* The temporary image to delete
*/
public void deleteTemporaryImage(TemporaryImage temporaryImage) {
- Validation.begin().isNotNull("Temporary Image", temporaryImage).check();
+ checkNotNull(temporaryImage, "temporaryImage must not be null");
deleteTemporaryImage(temporaryImage.getId());
}
* The ID of the temporary image to delete
*/
public void deleteTemporaryImage(String imageId) {
- Validation.begin().isNotNull("Temporary Image ID", imageId).check();
+ checkNotNull(imageId, "imageId must not be null");
synchronized (temporaryImages) {
temporaryImages.remove(imageId);
}
@Override
public void serviceStart() {
loadConfiguration();
- updateChecker.addUpdateListener(this);
updateChecker.start();
+ identityManager.start();
+ webOfTrustUpdater.init();
webOfTrustUpdater.start();
+ database.start();
}
/**
*/
@Override
public void serviceStop() {
- synchronized (localSones) {
+ localElementTicker.shutdownNow();
+ synchronized (sones) {
for (Entry<Sone, SoneInserter> soneInserter : soneInserters.entrySet()) {
- soneInserter.getValue().removeSoneInsertListener(this);
soneInserter.getValue().stop();
saveSone(soneInserter.getKey());
}
}
saveConfiguration();
+ database.stop();
webOfTrustUpdater.stop();
updateChecker.stop();
- updateChecker.removeUpdateListener(this);
soneDownloader.stop();
+ soneDownloaders.shutdown();
+ identityManager.stop();
}
//
* The Sone to save
*/
private synchronized void saveSone(Sone sone) {
- if (!isLocalSone(sone)) {
+ if (!sone.isLocal()) {
logger.log(Level.FINE, String.format("Tried to save non-local Sone: %s", sone));
return;
}
for (Post post : sone.getPosts()) {
String postPrefix = sonePrefix + "/Posts/" + postCounter++;
configuration.getStringValue(postPrefix + "/ID").setValue(post.getId());
- configuration.getStringValue(postPrefix + "/Recipient").setValue((post.getRecipient() != null) ? post.getRecipient().getId() : null);
+ configuration.getStringValue(postPrefix + "/Recipient").setValue(post.getRecipientId().orNull());
configuration.getLongValue(postPrefix + "/Time").setValue(post.getTime());
configuration.getStringValue(postPrefix + "/Text").setValue(post.getText());
}
for (PostReply reply : sone.getReplies()) {
String replyPrefix = sonePrefix + "/Replies/" + replyCounter++;
configuration.getStringValue(replyPrefix + "/ID").setValue(reply.getId());
- configuration.getStringValue(replyPrefix + "/Post/ID").setValue(reply.getPost().getId());
+ configuration.getStringValue(replyPrefix + "/Post/ID").setValue(reply.getPostId());
configuration.getLongValue(replyPrefix + "/Time").setValue(reply.getTime());
configuration.getStringValue(replyPrefix + "/Text").setValue(reply.getText());
}
configuration.getStringValue(sonePrefix + "/Friends/" + friendCounter + "/ID").setValue(null);
/* save albums. first, collect in a flat structure, top-level first. */
- List<Album> albums = sone.getAllAlbums();
+ List<Album> albums = FluentIterable.from(sone.getAlbums()).transformAndConcat(Album.FLATTENER).toList();
int albumCounter = 0;
for (Album album : albums) {
/* save Sone following times. */
soneCounter = 0;
synchronized (soneFollowingTimes) {
- for (Entry<Sone, Long> soneFollowingTime : soneFollowingTimes.entrySet()) {
- configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(soneFollowingTime.getKey().getId());
+ for (Entry<String, Long> soneFollowingTime : soneFollowingTimes.entrySet()) {
+ configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(soneFollowingTime.getKey());
configuration.getLongValue("SoneFollowingTimes/" + soneCounter + "/Time").setValue(soneFollowingTime.getValue());
++soneCounter;
}
}
/* save known posts. */
- int postCounter = 0;
- synchronized (knownPosts) {
- for (String knownPostId : knownPosts) {
- configuration.getStringValue("KnownPosts/" + postCounter++ + "/ID").setValue(knownPostId);
- }
- configuration.getStringValue("KnownPosts/" + postCounter + "/ID").setValue(null);
- }
-
- /* save known replies. */
- int replyCounter = 0;
- synchronized (knownReplies) {
- for (String knownReplyId : knownReplies) {
- configuration.getStringValue("KnownReplies/" + replyCounter++ + "/ID").setValue(knownReplyId);
- }
- configuration.getStringValue("KnownReplies/" + replyCounter + "/ID").setValue(null);
- }
+ database.save();
/* save bookmarked posts. */
int bookmarkedPostCounter = 0;
} catch (ConfigurationException ce1) {
logger.log(Level.SEVERE, "Could not store configuration!", ce1);
+ } catch (DatabaseException de1) {
+ logger.log(Level.SEVERE, "Could not save database!", de1);
} finally {
synchronized (configuration) {
storingConfiguration = false;
/**
* Loads the configuration.
*/
- @SuppressWarnings("unchecked")
private void loadConfiguration() {
/* create options. */
- options.addIntegerOption("InsertionDelay", new DefaultOption<Integer>(60, new IntegerRangeValidator(0, Integer.MAX_VALUE), new OptionWatcher<Integer>() {
+ options.addIntegerOption("InsertionDelay", new DefaultOption<Integer>(60, new IntegerRangePredicate(0, Integer.MAX_VALUE), new OptionWatcher<Integer>() {
@Override
public void optionChanged(Option<Integer> option, Integer oldValue, Integer newValue) {
}
}));
- options.addIntegerOption("PostsPerPage", new DefaultOption<Integer>(10, new IntegerRangeValidator(1, Integer.MAX_VALUE)));
- options.addIntegerOption("ImagesPerPage", new DefaultOption<Integer>(9, new IntegerRangeValidator(1, Integer.MAX_VALUE)));
- options.addIntegerOption("CharactersPerPost", new DefaultOption<Integer>(400, new OrValidator<Integer>(new IntegerRangeValidator(50, Integer.MAX_VALUE), new EqualityValidator<Integer>(-1))));
- options.addIntegerOption("PostCutOffLength", new DefaultOption<Integer>(200, new OrValidator<Integer>(new IntegerRangeValidator(50, Integer.MAX_VALUE), new EqualityValidator<Integer>(-1))));
+ options.addIntegerOption("PostsPerPage", new DefaultOption<Integer>(10, new IntegerRangePredicate(1, Integer.MAX_VALUE)));
+ options.addIntegerOption("ImagesPerPage", new DefaultOption<Integer>(9, new IntegerRangePredicate(1, Integer.MAX_VALUE)));
+ options.addIntegerOption("CharactersPerPost", new DefaultOption<Integer>(400, Predicates.<Integer> or(new IntegerRangePredicate(50, Integer.MAX_VALUE), Predicates.equalTo(-1))));
+ options.addIntegerOption("PostCutOffLength", new DefaultOption<Integer>(200, Predicates.<Integer> or(new IntegerRangePredicate(50, Integer.MAX_VALUE), Predicates.equalTo(-1))));
options.addBooleanOption("RequireFullAccess", new DefaultOption<Boolean>(false));
- options.addIntegerOption("PositiveTrust", new DefaultOption<Integer>(75, new IntegerRangeValidator(0, 100)));
- options.addIntegerOption("NegativeTrust", new DefaultOption<Integer>(-25, new IntegerRangeValidator(-100, 100)));
+ options.addIntegerOption("PositiveTrust", new DefaultOption<Integer>(75, new IntegerRangePredicate(0, 100)));
+ options.addIntegerOption("NegativeTrust", new DefaultOption<Integer>(-25, new IntegerRangePredicate(-100, 100)));
options.addStringOption("TrustComment", new DefaultOption<String>("Set from Sone Web Interface"));
options.addBooleanOption("ActivateFcpInterface", new DefaultOption<Boolean>(false, new OptionWatcher<Boolean>() {
break;
}
long time = configuration.getLongValue("SoneFollowingTimes/" + soneCounter + "/Time").getValue(Long.MAX_VALUE);
- Sone followedSone = getSone(soneId);
- if (followedSone == null) {
- logger.log(Level.WARNING, String.format("Ignoring Sone with invalid ID: %s", soneId));
- } else {
- synchronized (soneFollowingTimes) {
- soneFollowingTimes.put(getSone(soneId), time);
- }
+ synchronized (soneFollowingTimes) {
+ soneFollowingTimes.put(soneId, time);
}
++soneCounter;
}
- /* load known posts. */
- int postCounter = 0;
- while (true) {
- String knownPostId = configuration.getStringValue("KnownPosts/" + postCounter++ + "/ID").getValue(null);
- if (knownPostId == null) {
- break;
- }
- synchronized (knownPosts) {
- knownPosts.add(knownPostId);
- }
- }
-
- /* load known replies. */
- int replyCounter = 0;
- while (true) {
- String knownReplyId = configuration.getStringValue("KnownReplies/" + replyCounter++ + "/ID").getValue(null);
- if (knownReplyId == null) {
- break;
- }
- synchronized (knownReplies) {
- knownReplies.add(knownReplyId);
- }
- }
-
/* load bookmarked posts. */
int bookmarkedPostCounter = 0;
while (true) {
}
/**
- * Generate a Sone URI from the given URI and latest edition.
+ * Notifies the core that a new {@link OwnIdentity} was added.
*
- * @param uriString
- * The URI to derive the Sone URI from
- * @return The derived URI
- */
- private static FreenetURI getSoneUri(String uriString) {
- try {
- FreenetURI uri = new FreenetURI(uriString).setDocName("Sone").setMetaString(new String[0]);
- return uri;
- } catch (MalformedURLException mue1) {
- logger.log(Level.WARNING, String.format("Could not create Sone URI from URI: %s", uriString), mue1);
- return null;
- }
- }
-
- //
- // INTERFACE IdentityListener
- //
-
- /**
- * {@inheritDoc}
+ * @param ownIdentityAddedEvent
+ * The event
*/
- @Override
- public void ownIdentityAdded(OwnIdentity ownIdentity) {
+ @Subscribe
+ public void ownIdentityAdded(OwnIdentityAddedEvent ownIdentityAddedEvent) {
+ OwnIdentity ownIdentity = ownIdentityAddedEvent.ownIdentity();
logger.log(Level.FINEST, String.format("Adding OwnIdentity: %s", ownIdentity));
if (ownIdentity.hasContext("Sone")) {
- trustedIdentities.put(ownIdentity, Collections.synchronizedSet(new HashSet<Identity>()));
addLocalSone(ownIdentity);
}
}
/**
- * {@inheritDoc}
+ * Notifies the core that an {@link OwnIdentity} was removed.
+ *
+ * @param ownIdentityRemovedEvent
+ * The event
*/
- @Override
- public void ownIdentityRemoved(OwnIdentity ownIdentity) {
+ @Subscribe
+ public void ownIdentityRemoved(OwnIdentityRemovedEvent ownIdentityRemovedEvent) {
+ OwnIdentity ownIdentity = ownIdentityRemovedEvent.ownIdentity();
logger.log(Level.FINEST, String.format("Removing OwnIdentity: %s", ownIdentity));
trustedIdentities.remove(ownIdentity);
}
/**
- * {@inheritDoc}
+ * Notifies the core that a new {@link Identity} was added.
+ *
+ * @param identityAddedEvent
+ * The event
*/
- @Override
- public void identityAdded(OwnIdentity ownIdentity, Identity identity) {
+ @Subscribe
+ public void identityAdded(IdentityAddedEvent identityAddedEvent) {
+ Identity identity = identityAddedEvent.identity();
logger.log(Level.FINEST, String.format("Adding Identity: %s", identity));
- trustedIdentities.get(ownIdentity).add(identity);
+ trustedIdentities.get(identityAddedEvent.ownIdentity()).add(identity);
addRemoteSone(identity);
}
/**
- * {@inheritDoc}
+ * Notifies the core that an {@link Identity} was updated.
+ *
+ * @param identityUpdatedEvent
+ * The event
*/
- @Override
- public void identityUpdated(OwnIdentity ownIdentity, final Identity identity) {
+ @Subscribe
+ public void identityUpdated(IdentityUpdatedEvent identityUpdatedEvent) {
+ final Identity identity = identityUpdatedEvent.identity();
soneDownloaders.execute(new Runnable() {
@Override
}
/**
- * {@inheritDoc}
+ * Notifies the core that an {@link Identity} was removed.
+ *
+ * @param identityRemovedEvent
+ * The event
*/
- @Override
- public void identityRemoved(OwnIdentity ownIdentity, Identity identity) {
+ @Subscribe
+ public void identityRemoved(IdentityRemovedEvent identityRemovedEvent) {
+ OwnIdentity ownIdentity = identityRemovedEvent.ownIdentity();
+ Identity identity = identityRemovedEvent.identity();
trustedIdentities.get(ownIdentity).remove(identity);
boolean foundIdentity = false;
for (Entry<OwnIdentity, Set<Identity>> trustedIdentity : trustedIdentities.entrySet()) {
/* some local identity still trusts this identity, don’t remove. */
return;
}
- Sone sone = getSone(identity.getId(), false);
- if (sone == null) {
+ Optional<Sone> sone = getSone(identity.getId());
+ if (!sone.isPresent()) {
/* TODO - we don’t have the Sone anymore. should this happen? */
return;
}
- synchronized (posts) {
- synchronized (knownPosts) {
- for (Post post : sone.getPosts()) {
- posts.remove(post.getId());
- coreListenerManager.firePostRemoved(post);
- }
- }
+ database.removePosts(sone.get());
+ for (Post post : sone.get().getPosts()) {
+ eventBus.post(new PostRemovedEvent(post));
}
- synchronized (replies) {
- synchronized (knownReplies) {
- for (PostReply reply : sone.getReplies()) {
- replies.remove(reply.getId());
- coreListenerManager.fireReplyRemoved(reply);
- }
- }
+ database.removePostReplies(sone.get());
+ for (PostReply reply : sone.get().getReplies()) {
+ eventBus.post(new PostReplyRemovedEvent(reply));
}
- synchronized (remoteSones) {
- remoteSones.remove(identity.getId());
+ synchronized (sones) {
+ sones.remove(identity.getId());
}
- coreListenerManager.fireSoneRemoved(sone);
- }
-
- //
- // INTERFACE UpdateListener
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void updateFound(Version version, long releaseTime, long latestEdition) {
- coreListenerManager.fireUpdateFound(version, releaseTime, latestEdition);
+ eventBus.post(new SoneRemovedEvent(sone.get()));
}
- //
- // INTERFACE ImageInsertListener
- //
-
/**
- * {@inheritDoc}
- */
- @Override
- public void insertStarted(Sone sone) {
- coreListenerManager.fireSoneInserting(sone);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void insertFinished(Sone sone, long insertDuration) {
- coreListenerManager.fireSoneInserted(sone, insertDuration);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void insertAborted(Sone sone, Throwable cause) {
- coreListenerManager.fireSoneInsertAborted(sone, cause);
- }
-
- //
- // SONEINSERTLISTENER METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void imageInsertStarted(Image image) {
- logger.log(Level.WARNING, String.format("Image insert started for %s...", image));
- coreListenerManager.fireImageInsertStarted(image);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void imageInsertAborted(Image image) {
- logger.log(Level.WARNING, String.format("Image insert aborted for %s.", image));
- coreListenerManager.fireImageInsertAborted(image);
- }
-
- /**
- * {@inheritDoc}
+ * Deletes the temporary image.
+ *
+ * @param imageInsertFinishedEvent
+ * The event
*/
- @Override
- public void imageInsertFinished(Image image, FreenetURI key) {
- logger.log(Level.WARNING, String.format("Image insert finished for %s: %s", image, key));
- image.setKey(key.toString());
- deleteTemporaryImage(image.getId());
+ @Subscribe
+ public void imageInsertFinished(ImageInsertFinishedEvent imageInsertFinishedEvent) {
+ logger.log(Level.WARNING, String.format("Image insert finished for %s: %s", imageInsertFinishedEvent.image(), imageInsertFinishedEvent.resultingUri()));
+ imageInsertFinishedEvent.image().setKey(imageInsertFinishedEvent.resultingUri().toString());
+ deleteTemporaryImage(imageInsertFinishedEvent.image().getId());
touchConfiguration();
- coreListenerManager.fireImageInsertFinished(image);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void imageInsertFailed(Image image, Throwable cause) {
- logger.log(Level.WARNING, String.format("Image insert failed for %s." + image), cause);
- coreListenerManager.fireImageInsertFailed(image, cause);
- }
-
- /**
- * Convenience interface for external classes that want to access the core’s
- * configuration.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
- public static class Preferences {
-
- /** The wrapped options. */
- private final Options options;
-
- /**
- * Creates a new preferences object wrapped around the given options.
- *
- * @param options
- * The options to wrap
- */
- public Preferences(Options options) {
- this.options = options;
- }
-
- /**
- * Returns the insertion delay.
- *
- * @return The insertion delay
- */
- public int getInsertionDelay() {
- return options.getIntegerOption("InsertionDelay").get();
- }
-
- /**
- * Validates the given insertion delay.
- *
- * @param insertionDelay
- * The insertion delay to validate
- * @return {@code true} if the given insertion delay was valid,
- * {@code false} otherwise
- */
- public boolean validateInsertionDelay(Integer insertionDelay) {
- return options.getIntegerOption("InsertionDelay").validate(insertionDelay);
- }
-
- /**
- * Sets the insertion delay
- *
- * @param insertionDelay
- * The new insertion delay, or {@code null} to restore it to
- * the default value
- * @return This preferences
- */
- public Preferences setInsertionDelay(Integer insertionDelay) {
- options.getIntegerOption("InsertionDelay").set(insertionDelay);
- return this;
- }
-
- /**
- * Returns the number of posts to show per page.
- *
- * @return The number of posts to show per page
- */
- public int getPostsPerPage() {
- return options.getIntegerOption("PostsPerPage").get();
- }
-
- /**
- * Validates the number of posts per page.
- *
- * @param postsPerPage
- * The number of posts per page
- * @return {@code true} if the number of posts per page was valid,
- * {@code false} otherwise
- */
- public boolean validatePostsPerPage(Integer postsPerPage) {
- return options.getIntegerOption("PostsPerPage").validate(postsPerPage);
- }
-
- /**
- * Sets the number of posts to show per page.
- *
- * @param postsPerPage
- * The number of posts to show per page
- * @return This preferences object
- */
- public Preferences setPostsPerPage(Integer postsPerPage) {
- options.getIntegerOption("PostsPerPage").set(postsPerPage);
- return this;
- }
-
- /**
- * Returns the number of images to show per page.
- *
- * @return The number of images to show per page
- */
- public int getImagesPerPage() {
- return options.getIntegerOption("ImagesPerPage").get();
- }
-
- /**
- * Validates the number of images per page.
- *
- * @param imagesPerPage
- * The number of images per page
- * @return {@code true} if the number of images per page was valid,
- * {@code false} otherwise
- */
- public boolean validateImagesPerPage(Integer imagesPerPage) {
- return options.getIntegerOption("ImagesPerPage").validate(imagesPerPage);
- }
-
- /**
- * Sets the number of images per page.
- *
- * @param imagesPerPage
- * The number of images per page
- * @return This preferences object
- */
- public Preferences setImagesPerPage(Integer imagesPerPage) {
- options.getIntegerOption("ImagesPerPage").set(imagesPerPage);
- return this;
- }
-
- /**
- * Returns the number of characters per post, or <code>-1</code> if the
- * posts should not be cut off.
- *
- * @return The numbers of characters per post
- */
- public int getCharactersPerPost() {
- return options.getIntegerOption("CharactersPerPost").get();
- }
-
- /**
- * Validates the number of characters per post.
- *
- * @param charactersPerPost
- * The number of characters per post
- * @return {@code true} if the number of characters per post was valid,
- * {@code false} otherwise
- */
- public boolean validateCharactersPerPost(Integer charactersPerPost) {
- return options.getIntegerOption("CharactersPerPost").validate(charactersPerPost);
- }
-
- /**
- * Sets the number of characters per post.
- *
- * @param charactersPerPost
- * The number of characters per post, or <code>-1</code> to
- * not cut off the posts
- * @return This preferences objects
- */
- public Preferences setCharactersPerPost(Integer charactersPerPost) {
- options.getIntegerOption("CharactersPerPost").set(charactersPerPost);
- return this;
- }
-
- /**
- * Returns the number of characters the shortened post should have.
- *
- * @return The number of characters of the snippet
- */
- public int getPostCutOffLength() {
- return options.getIntegerOption("PostCutOffLength").get();
- }
-
- /**
- * Validates the number of characters after which to cut off the post.
- *
- * @param postCutOffLength
- * The number of characters of the snippet
- * @return {@code true} if the number of characters of the snippet is
- * valid, {@code false} otherwise
- */
- public boolean validatePostCutOffLength(Integer postCutOffLength) {
- return options.getIntegerOption("PostCutOffLength").validate(postCutOffLength);
- }
-
- /**
- * Sets the number of characters the shortened post should have.
- *
- * @param postCutOffLength
- * The number of characters of the snippet
- * @return This preferences
- */
- public Preferences setPostCutOffLength(Integer postCutOffLength) {
- options.getIntegerOption("PostCutOffLength").set(postCutOffLength);
- return this;
- }
-
- /**
- * Returns whether Sone requires full access to be even visible.
- *
- * @return {@code true} if Sone requires full access, {@code false}
- * otherwise
- */
- public boolean isRequireFullAccess() {
- return options.getBooleanOption("RequireFullAccess").get();
- }
-
- /**
- * Sets whether Sone requires full access to be even visible.
- *
- * @param requireFullAccess
- * {@code true} if Sone requires full access, {@code false}
- * otherwise
- */
- public void setRequireFullAccess(Boolean requireFullAccess) {
- options.getBooleanOption("RequireFullAccess").set(requireFullAccess);
- }
-
- /**
- * Returns the positive trust.
- *
- * @return The positive trust
- */
- public int getPositiveTrust() {
- return options.getIntegerOption("PositiveTrust").get();
- }
-
- /**
- * Validates the positive trust.
- *
- * @param positiveTrust
- * The positive trust to validate
- * @return {@code true} if the positive trust was valid, {@code false}
- * otherwise
- */
- public boolean validatePositiveTrust(Integer positiveTrust) {
- return options.getIntegerOption("PositiveTrust").validate(positiveTrust);
- }
-
- /**
- * Sets the positive trust.
- *
- * @param positiveTrust
- * The new positive trust, or {@code null} to restore it to
- * the default vlaue
- * @return This preferences
- */
- public Preferences setPositiveTrust(Integer positiveTrust) {
- options.getIntegerOption("PositiveTrust").set(positiveTrust);
- return this;
- }
-
- /**
- * Returns the negative trust.
- *
- * @return The negative trust
- */
- public int getNegativeTrust() {
- return options.getIntegerOption("NegativeTrust").get();
- }
-
- /**
- * Validates the negative trust.
- *
- * @param negativeTrust
- * The negative trust to validate
- * @return {@code true} if the negative trust was valid, {@code false}
- * otherwise
- */
- public boolean validateNegativeTrust(Integer negativeTrust) {
- return options.getIntegerOption("NegativeTrust").validate(negativeTrust);
- }
-
- /**
- * Sets the negative trust.
- *
- * @param negativeTrust
- * The negative trust, or {@code null} to restore it to the
- * default value
- * @return The preferences
- */
- public Preferences setNegativeTrust(Integer negativeTrust) {
- options.getIntegerOption("NegativeTrust").set(negativeTrust);
- return this;
- }
-
- /**
- * Returns the trust comment. This is the comment that is set in the web
- * of trust when a trust value is assigned to an identity.
- *
- * @return The trust comment
- */
- public String getTrustComment() {
- return options.getStringOption("TrustComment").get();
- }
-
- /**
- * Sets the trust comment.
- *
- * @param trustComment
- * The trust comment, or {@code null} to restore it to the
- * default value
- * @return This preferences
- */
- public Preferences setTrustComment(String trustComment) {
- options.getStringOption("TrustComment").set(trustComment);
- return this;
- }
-
- /**
- * Returns whether the {@link FcpInterface FCP interface} is currently
- * active.
- *
- * @see FcpInterface#setActive(boolean)
- * @return {@code true} if the FCP interface is currently active,
- * {@code false} otherwise
- */
- public boolean isFcpInterfaceActive() {
- return options.getBooleanOption("ActivateFcpInterface").get();
- }
-
- /**
- * Sets whether the {@link FcpInterface FCP interface} is currently
- * active.
- *
- * @see FcpInterface#setActive(boolean)
- * @param fcpInterfaceActive
- * {@code true} to activate the FCP interface, {@code false}
- * to deactivate the FCP interface
- * @return This preferences object
- */
- public Preferences setFcpInterfaceActive(boolean fcpInterfaceActive) {
- options.getBooleanOption("ActivateFcpInterface").set(fcpInterfaceActive);
- return this;
- }
-
- /**
- * Returns the action level for which full access to the FCP interface
- * is required.
- *
- * @return The action level for which full access to the FCP interface
- * is required
- */
- public FullAccessRequired getFcpFullAccessRequired() {
- return FullAccessRequired.values()[options.getIntegerOption("FcpFullAccessRequired").get()];
- }
-
- /**
- * Sets the action level for which full access to the FCP interface is
- * required
- *
- * @param fcpFullAccessRequired
- * The action level
- * @return This preferences
- */
- public Preferences setFcpFullAccessRequired(FullAccessRequired fcpFullAccessRequired) {
- options.getIntegerOption("FcpFullAccessRequired").set((fcpFullAccessRequired != null) ? fcpFullAccessRequired.ordinal() : null);
- return this;
- }
-
}
}
+++ /dev/null
-/*
- * Sone - CoreListener.java - Copyright © 2010–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.core;
-
-import java.util.EventListener;
-
-import net.pterodactylus.sone.data.Image;
-import net.pterodactylus.sone.data.Post;
-import net.pterodactylus.sone.data.PostReply;
-import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.util.version.Version;
-
-/**
- * Listener interface for objects that want to be notified on certain
- * {@link Core} events, such es discovery of new data.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface CoreListener extends EventListener {
-
- /**
- * Notifies a listener that a new Sone has been discovered.
- *
- * @param sone
- * The new Sone
- */
- public void newSoneFound(Sone sone);
-
- /**
- * Notifies a listener that a new post has been found.
- *
- * @param post
- * The new post
- */
- public void newPostFound(Post post);
-
- /**
- * Notifies a listener that a new reply has been found.
- *
- * @param reply
- * The new reply
- */
- public void newReplyFound(PostReply reply);
-
- /**
- * Notifies a listener that the given Sone is now marked as known.
- *
- * @param sone
- * The known Sone
- */
- public void markSoneKnown(Sone sone);
-
- /**
- * Notifies a listener that the given post is now marked as known.
- *
- * @param post
- * The known post
- */
- public void markPostKnown(Post post);
-
- /**
- * Notifies a listener that the given reply is now marked as known.
- *
- * @param reply
- * The known reply
- */
- public void markReplyKnown(PostReply reply);
-
- /**
- * Notifies a listener that the given Sone was removed.
- *
- * @param sone
- * The removed Sone
- */
- public void soneRemoved(Sone sone);
-
- /**
- * Notifies a listener that the given post was removed.
- *
- * @param post
- * The removed post
- */
- public void postRemoved(Post post);
-
- /**
- * Notifies a listener that the given reply was removed.
- *
- * @param reply
- * The removed reply
- */
- public void replyRemoved(PostReply reply);
-
- /**
- * Notifies a listener when a Sone was locked.
- *
- * @param sone
- * The Sone that was locked
- */
- public void soneLocked(Sone sone);
-
- /**
- * Notifies a listener that a Sone was unlocked.
- *
- * @param sone
- * The Sone that was unlocked
- */
- public void soneUnlocked(Sone sone);
-
- /**
- * Notifies a listener that the insert of the given Sone has started.
- *
- * @see SoneInsertListener#insertStarted(Sone)
- * @param sone
- * The Sone that is being inserted
- */
- public void soneInserting(Sone sone);
-
- /**
- * Notifies a listener that the insert of the given Sone has finished
- * successfully.
- *
- * @see SoneInsertListener#insertFinished(Sone, long)
- * @param sone
- * The Sone that has been inserted
- * @param insertDuration
- * The insert duration (in milliseconds)
- */
- public void soneInserted(Sone sone, long insertDuration);
-
- /**
- * Notifies a listener that the insert of the given Sone was aborted.
- *
- * @see SoneInsertListener#insertAborted(Sone, Throwable)
- * @param sone
- * The Sone that was inserted
- * @param cause
- * The cause for the abortion (may be {@code null})
- */
- public void soneInsertAborted(Sone sone, Throwable cause);
-
- /**
- * Notifies a listener that a new version has been found.
- *
- * @param version
- * The version that was found
- * @param releaseTime
- * The release time of the new version
- * @param latestEdition
- * The latest edition of the Sone homepage
- */
- public void updateFound(Version version, long releaseTime, long latestEdition);
-
- /**
- * Notifies a listener that an image has started being inserted.
- *
- * @param image
- * The image that is now inserted
- */
- public void imageInsertStarted(Image image);
-
- /**
- * Notifies a listener that an image insert was aborted by the user.
- *
- * @param image
- * The image that is not inserted anymore
- */
- public void imageInsertAborted(Image image);
-
- /**
- * Notifies a listener that an image was successfully inserted.
- *
- * @param image
- * The image that was inserted
- */
- public void imageInsertFinished(Image image);
-
- /**
- * Notifies a listener that an image failed to be inserted.
- *
- * @param image
- * The image that could not be inserted
- * @param cause
- * The reason for the failed insert
- */
- public void imageInsertFailed(Image image, Throwable cause);
-
-}
+++ /dev/null
-/*
- * Sone - CoreListenerManager.java - Copyright © 2010–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.core;
-
-import net.pterodactylus.sone.data.Image;
-import net.pterodactylus.sone.data.Post;
-import net.pterodactylus.sone.data.PostReply;
-import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.util.event.AbstractListenerManager;
-import net.pterodactylus.util.version.Version;
-
-/**
- * Manager for {@link CoreListener}s.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class CoreListenerManager extends AbstractListenerManager<Core, CoreListener> {
-
- /**
- * Creates a new core listener manager.
- *
- * @param source
- * The Core
- */
- public CoreListenerManager(Core source) {
- super(source);
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Notifies all listeners that a new Sone has been discovered.
- *
- * @see CoreListener#newSoneFound(Sone)
- * @param sone
- * The discovered sone
- */
- void fireNewSoneFound(Sone sone) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.newSoneFound(sone);
- }
- }
-
- /**
- * Notifies all listeners that a new post has been found.
- *
- * @see CoreListener#newPostFound(Post)
- * @param post
- * The new post
- */
- void fireNewPostFound(Post post) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.newPostFound(post);
- }
- }
-
- /**
- * Notifies all listeners that a new reply has been found.
- *
- * @see CoreListener#newReplyFound(PostReply)
- * @param reply
- * The new reply
- */
- void fireNewReplyFound(PostReply reply) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.newReplyFound(reply);
- }
- }
-
- /**
- * Notifies all listeners that the given Sone is now marked as known.
- *
- * @see CoreListener#markSoneKnown(Sone)
- * @param sone
- * The known Sone
- */
- void fireMarkSoneKnown(Sone sone) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.markSoneKnown(sone);
- }
- }
-
- /**
- * Notifies all listeners that the given post is now marked as known.
- *
- * @param post
- * The known post
- */
- void fireMarkPostKnown(Post post) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.markPostKnown(post);
- }
- }
-
- /**
- * Notifies all listeners that the given reply is now marked as known.
- *
- * @param reply
- * The known reply
- */
- void fireMarkReplyKnown(PostReply reply) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.markReplyKnown(reply);
- }
- }
-
- /**
- * Notifies all listener that the given Sone was removed.
- *
- * @see CoreListener#soneRemoved(Sone)
- * @param sone
- * The removed Sone
- */
- void fireSoneRemoved(Sone sone) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.soneRemoved(sone);
- }
- }
-
- /**
- * Notifies all listener that the given post was removed.
- *
- * @see CoreListener#postRemoved(Post)
- * @param post
- * The removed post
- */
- void firePostRemoved(Post post) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.postRemoved(post);
- }
- }
-
- /**
- * Notifies all listener that the given reply was removed.
- *
- * @see CoreListener#replyRemoved(PostReply)
- * @param reply
- * The removed reply
- */
- void fireReplyRemoved(PostReply reply) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.replyRemoved(reply);
- }
- }
-
- /**
- * Notifies all listeners that the given Sone was locked.
- *
- * @see CoreListener#soneLocked(Sone)
- * @param sone
- * The Sone that was locked
- */
- void fireSoneLocked(Sone sone) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.soneLocked(sone);
- }
- }
-
- /**
- * Notifies all listeners that the given Sone was unlocked.
- *
- * @see CoreListener#soneUnlocked(Sone)
- * @param sone
- * The Sone that was unlocked
- */
- void fireSoneUnlocked(Sone sone) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.soneUnlocked(sone);
- }
- }
-
- /**
- * Notifies all listeners that the insert of the given Sone has started.
- *
- * @see SoneInsertListener#insertStarted(Sone)
- * @param sone
- * The Sone being inserted
- */
- void fireSoneInserting(Sone sone) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.soneInserting(sone);
- }
- }
-
- /**
- * Notifies all listeners that the insert of the given Sone has finished
- * successfully.
- *
- * @see SoneInsertListener#insertFinished(Sone, long)
- * @param sone
- * The Sone that was inserted
- * @param insertDuration
- * The insert duration (in milliseconds)
- */
- void fireSoneInserted(Sone sone, long insertDuration) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.soneInserted(sone, insertDuration);
- }
- }
-
- /**
- * Notifies all listeners that the insert of the given Sone was aborted.
- *
- * @see SoneInsertListener#insertStarted(Sone)
- * @param sone
- * The Sone being inserted
- * @param cause
- * The cause for the abortion (may be {@code null}
- */
- void fireSoneInsertAborted(Sone sone, Throwable cause) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.soneInsertAborted(sone, cause);
- }
- }
-
- /**
- * Notifies all listeners that a new version was found.
- *
- * @see CoreListener#updateFound(Version, long, long)
- * @param version
- * The new version
- * @param releaseTime
- * The release time of the new version
- * @param latestEdition
- * The latest edition of the Sone homepage
- */
- void fireUpdateFound(Version version, long releaseTime, long latestEdition) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.updateFound(version, releaseTime, latestEdition);
- }
- }
-
- /**
- * Notifies all listeners that an image has started being inserted.
- *
- * @see CoreListener#imageInsertStarted(Image)
- * @param image
- * The image that is now inserted
- */
- void fireImageInsertStarted(Image image) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.imageInsertStarted(image);
- }
- }
-
- /**
- * Notifies all listeners that an image insert was aborted by the user.
- *
- * @see CoreListener#imageInsertAborted(Image)
- * @param image
- * The image that is not inserted anymore
- */
- void fireImageInsertAborted(Image image) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.imageInsertAborted(image);
- }
- }
-
- /**
- * Notifies all listeners that an image was successfully inserted.
- *
- * @see CoreListener#imageInsertFinished(Image)
- * @param image
- * The image that was inserted
- */
- void fireImageInsertFinished(Image image) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.imageInsertFinished(image);
- }
- }
-
- /**
- * Notifies all listeners that an image failed to be inserted.
- *
- * @see CoreListener#imageInsertFailed(Image, Throwable)
- * @param image
- * The image that could not be inserted
- * @param cause
- * The cause of the failure
- */
- void fireImageInsertFailed(Image image, Throwable cause) {
- for (CoreListener coreListener : getListeners()) {
- coreListener.imageInsertFailed(image, cause);
- }
- }
-
-}
/*
- * Sone - FreenetInterface.java - Copyright © 2010–2012 David Roden
+ * Sone - FreenetInterface.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
package net.pterodactylus.sone.core;
import java.net.MalformedURLException;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
+import net.pterodactylus.sone.core.event.ImageInsertAbortedEvent;
+import net.pterodactylus.sone.core.event.ImageInsertFailedEvent;
+import net.pterodactylus.sone.core.event.ImageInsertFinishedEvent;
+import net.pterodactylus.sone.core.event.ImageInsertStartedEvent;
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.data.TemporaryImage;
-import net.pterodactylus.util.collection.Pair;
import net.pterodactylus.util.logging.Logging;
import com.db4o.ObjectContainer;
+import com.google.common.eventbus.EventBus;
+import com.google.inject.Inject;
import freenet.client.ClientMetadata;
import freenet.client.FetchException;
/** The logger. */
private static final Logger logger = Logging.getLogger(FreenetInterface.class);
+ /** The event bus. */
+ private final EventBus eventBus;
+
/** The node to interact with. */
private final Node node;
/**
* Creates a new Freenet interface.
*
+ * @param eventBus
+ * The event bus
* @param node
* The node to interact with
*/
- public FreenetInterface(Node node) {
+ @Inject
+ public FreenetInterface(EventBus eventBus, Node node) {
+ this.eventBus = eventBus;
this.node = node;
this.client = node.clientCore.makeClient(RequestStarter.INTERACTIVE_PRIORITY_CLASS, false, true);
}
* The URI to fetch
* @return The result of the fetch, or {@code null} if an error occured
*/
- public Pair<FreenetURI, FetchResult> fetchUri(FreenetURI uri) {
+ public Fetched fetchUri(FreenetURI uri) {
FetchResult fetchResult = null;
FreenetURI currentUri = new FreenetURI(uri);
while (true) {
try {
fetchResult = client.fetch(currentUri);
- return new Pair<FreenetURI, FetchResult>(currentUri, fetchResult);
+ return new Fetched(currentUri, fetchResult);
} catch (FetchException fe1) {
if (fe1.getMode() == FetchException.PERMANENT_REDIRECT) {
currentUri = fe1.newURI;
}
};
soneUskCallbacks.put(sone.getId(), uskCallback);
- node.clientCore.uskManager.subscribe(USK.create(sone.getRequestUri()), uskCallback, (System.currentTimeMillis() - sone.getTime()) < 7 * 24 * 60 * 60 * 1000, (HighLevelSimpleClientImpl) client);
+ boolean runBackgroundFetch = (System.currentTimeMillis() - sone.getTime()) < TimeUnit.DAYS.toMillis(7);
+ node.clientCore.uskManager.subscribe(USK.create(sone.getRequestUri()), uskCallback, runBackgroundFetch, (HighLevelSimpleClientImpl) client);
} catch (MalformedURLException mue1) {
logger.log(Level.WARNING, String.format("Could not subscribe USK “%s”!", sone.getRequestUri()), mue1);
}
}
/**
+ * Container for a fetched URI and the {@link FetchResult}.
+ *
+ * @author <a href="mailto:d.roden@xplosion.de">David Roden</a>
+ */
+ public static class Fetched {
+
+ /** The fetched URI. */
+ private final FreenetURI freenetUri;
+
+ /** The fetch result. */
+ private final FetchResult fetchResult;
+
+ /**
+ * Creates a new fetched URI.
+ *
+ * @param freenetUri
+ * The URI that was fetched
+ * @param fetchResult
+ * The fetch result
+ */
+ public Fetched(FreenetURI freenetUri, FetchResult fetchResult) {
+ this.freenetUri = freenetUri;
+ this.fetchResult = fetchResult;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the fetched URI.
+ *
+ * @return The fetched URI
+ */
+ public FreenetURI getFreenetUri() {
+ return freenetUri;
+ }
+
+ /**
+ * Returns the fetch result.
+ *
+ * @return The fetch result
+ */
+ public FetchResult getFetchResult() {
+ return fetchResult;
+ }
+
+ }
+
+ /**
* Callback for USK watcher events.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
}
/**
- * Insert token that can be used to add {@link ImageInsertListener}s and
- * cancel a running insert.
+ * Insert token that can cancel a running insert and sends events.
*
+ * @see ImageInsertAbortedEvent
+ * @see ImageInsertStartedEvent
+ * @see ImageInsertFailedEvent
+ * @see ImageInsertFinishedEvent
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
public class InsertToken implements ClientPutCallback {
/** The image being inserted. */
private final Image image;
- /** The list of registered image insert listeners. */
- private final List<ImageInsertListener> imageInsertListeners = Collections.synchronizedList(new ArrayList<ImageInsertListener>());
-
/** The client putter. */
private ClientPutter clientPutter;
}
//
- // LISTENER MANAGEMENT
- //
-
- /**
- * Adds the given listener to the list of registered listener.
- *
- * @param imageInsertListener
- * The listener to add
- */
- public void addImageInsertListener(ImageInsertListener imageInsertListener) {
- imageInsertListeners.add(imageInsertListener);
- }
-
- /**
- * Removes the given listener from the list of registered listener.
- *
- * @param imageInsertListener
- * The listener to remove
- */
- public void removeImageInsertListener(ImageInsertListener imageInsertListener) {
- imageInsertListeners.remove(imageInsertListener);
- }
-
- //
// ACCESSORS
//
* Sets the client putter that is inserting the image. This will also
* signal all registered listeners that the image has started.
*
- * @see ImageInsertListener#imageInsertStarted(Image)
* @param clientPutter
* The client putter
*/
+ @SuppressWarnings("synthetic-access")
public void setClientPutter(ClientPutter clientPutter) {
this.clientPutter = clientPutter;
- for (ImageInsertListener imageInsertListener : imageInsertListeners) {
- imageInsertListener.imageInsertStarted(image);
- }
+ eventBus.post(new ImageInsertStartedEvent(image));
}
//
/**
* Cancels the running insert.
- *
- * @see ImageInsertListener#imageInsertAborted(Image)
*/
@SuppressWarnings("synthetic-access")
public void cancel() {
clientPutter.cancel(null, node.clientCore.clientContext);
- for (ImageInsertListener imageInsertListener : imageInsertListeners) {
- imageInsertListener.imageInsertAborted(image);
- }
+ eventBus.post(new ImageInsertAbortedEvent(image));
}
//
* {@inheritDoc}
*/
@Override
+ @SuppressWarnings("synthetic-access")
public void onFailure(InsertException insertException, BaseClientPutter clientPutter, ObjectContainer objectContainer) {
- for (ImageInsertListener imageInsertListener : imageInsertListeners) {
- if ((insertException != null) && ("Cancelled by user".equals(insertException.getMessage()))) {
- imageInsertListener.imageInsertAborted(image);
- } else {
- imageInsertListener.imageInsertFailed(image, insertException);
- }
+ if ((insertException != null) && ("Cancelled by user".equals(insertException.getMessage()))) {
+ eventBus.post(new ImageInsertAbortedEvent(image));
+ } else {
+ eventBus.post(new ImageInsertFailedEvent(image, insertException));
}
}
* {@inheritDoc}
*/
@Override
+ @SuppressWarnings("synthetic-access")
public void onSuccess(BaseClientPutter clientPutter, ObjectContainer objectContainer) {
- for (ImageInsertListener imageInsertListener : imageInsertListeners) {
- imageInsertListener.imageInsertFinished(image, resultingUri);
- }
+ eventBus.post(new ImageInsertFinishedEvent(image, resultingUri));
}
}
+++ /dev/null
-/*
- * Sone - ImageInsertListener.java - Copyright © 2011–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.core;
-
-import java.util.EventListener;
-
-import net.pterodactylus.sone.core.FreenetInterface.InsertToken;
-import net.pterodactylus.sone.data.Image;
-import freenet.keys.FreenetURI;
-
-/**
- * Listener interface for objects that want to be notified about the status of
- * an image insert.
- *
- * @see ImageInserter#insertImage(net.pterodactylus.sone.data.TemporaryImage,
- * Image)
- * @see FreenetInterface#insertImage(net.pterodactylus.sone.data.TemporaryImage,
- * Image, net.pterodactylus.sone.core.FreenetInterface.InsertToken)
- * @see InsertToken
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface ImageInsertListener extends EventListener {
-
- /**
- * Notifies a listener that the insert of the given image started.
- *
- * @param image
- * The image that is being inserted
- */
- public void imageInsertStarted(Image image);
-
- /**
- * Notifies a listener that the insert of the given image was aborted by the
- * user.
- *
- * @param image
- * The image that is no longer being inserted
- */
- public void imageInsertAborted(Image image);
-
- /**
- * Notifies a listener that the given image was inserted successfully.
- *
- * @param image
- * The image that was inserted
- * @param key
- * The final key of the image
- */
- public void imageInsertFinished(Image image, FreenetURI key);
-
- /**
- * Notifies a listener that the given image could not be inserted.
- *
- * @param image
- * The image that could not be inserted
- * @param cause
- * The cause of the insertion failure
- */
- public void imageInsertFailed(Image image, Throwable cause);
-
-}
/*
- * Sone - ImageInserter.java - Copyright © 2011–2012 David Roden
+ * Sone - ImageInserter.java - Copyright © 2011–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
package net.pterodactylus.sone.core;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.data.TemporaryImage;
import net.pterodactylus.util.logging.Logging;
-import net.pterodactylus.util.validation.Validation;
/**
* The image inserter is responsible for inserting images using
/** The logger. */
private static final Logger logger = Logging.getLogger(ImageInserter.class);
- /** The core. */
- private final Core core;
-
/** The freenet interface. */
private final FreenetInterface freenetInterface;
/**
* Creates a new image inserter.
*
- * @param core
- * The Sone core
* @param freenetInterface
* The freenet interface
*/
- public ImageInserter(Core core, FreenetInterface freenetInterface) {
- this.core = core;
+ public ImageInserter(FreenetInterface freenetInterface) {
this.freenetInterface = freenetInterface;
}
/**
- * Inserts the given image. The {@link #core} will automatically added as
- * {@link ImageInsertListener} to the created {@link InsertToken}.
+ * Inserts the given image.
*
* @param temporaryImage
* The temporary image data
* The image
*/
public void insertImage(TemporaryImage temporaryImage, Image image) {
- Validation.begin().isNotNull("Temporary Image", temporaryImage).isNotNull("Image", image).check().isEqual("Image IDs", image.getId(), temporaryImage.getId()).check();
+ checkNotNull(temporaryImage, "temporaryImage must not be null");
+ checkNotNull(image, "image must not be null");
+ checkArgument(image.getId().equals(temporaryImage.getId()), "image IDs must match");
try {
InsertToken insertToken = freenetInterface.new InsertToken(image);
insertTokens.put(image.getId(), insertToken);
- insertToken.addImageInsertListener(core);
freenetInterface.insertImage(temporaryImage, image, insertToken);
} catch (SoneException se1) {
logger.log(Level.WARNING, "Could not insert image!", se1);
return;
}
insertToken.cancel();
- insertToken.removeImageInsertListener(core);
}
}
/*
- * Sone - Options.java - Copyright © 2010–2012 David Roden
+ * Sone - Options.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
import java.util.HashMap;
import java.util.Map;
-import net.pterodactylus.util.validation.Validator;
+import com.google.common.base.Predicate;
/**
* Stores various options that influence Sone’s behaviour.
*
* @param value
* The value to validate
- * @return {@code true} if this option does not have a {@link Validator}
- * , or the {@link Validator} validates this object, {@code
- * false} otherwise
+ * @return {@code true} if this option does not have a validator, or the
+ * validator validates this object, {@code false} otherwise
*/
public boolean validate(T value);
private volatile T value;
/** The validator. */
- private Validator<T> validator;
+ private Predicate<T> validator;
/** The option watcher. */
private final OptionWatcher<T> optionWatcher;
* @param validator
* The validator for value validation (may be {@code null})
*/
- public DefaultOption(T defaultValue, Validator<T> validator) {
+ public DefaultOption(T defaultValue, Predicate<T> validator) {
this(defaultValue, validator, null);
}
* @param optionWatcher
* The option watcher (may be {@code null})
*/
- public DefaultOption(T defaultValue, Validator<T> validator, OptionWatcher<T> optionWatcher) {
+ public DefaultOption(T defaultValue, Predicate<T> validator, OptionWatcher<T> optionWatcher) {
this.defaultValue = defaultValue;
this.validator = validator;
this.optionWatcher = optionWatcher;
*/
@Override
public boolean validate(T value) {
- return (validator == null) || (value == null) || validator.validate(value);
+ return (validator == null) || (value == null) || validator.apply(value);
}
/**
*/
@Override
public void set(T value) {
- if ((value != null) && (validator != null) && (!validator.validate(value))) {
+ if ((value != null) && (validator != null) && (!validator.apply(value))) {
throw new IllegalArgumentException("New Value (" + value + ") could not be validated.");
}
T oldValue = this.value;
+++ /dev/null
-/*
- * Sone - PostProvider.java - Copyright © 2011–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.core;
-
-import net.pterodactylus.sone.data.Post;
-
-/**
- * Interface for objects that can provide {@link Post}s by their ID.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface PostProvider {
-
- /**
- * Returns the post with the given ID, if it exists. If it does not exist
- * and {@code create} is {@code false}, {@code null} is returned; otherwise,
- * a new post with the given ID is created and returned.
- *
- * @param postId
- * The ID of the post to return
- * @param create
- * {@code true} to create a new post if no post with the given ID
- * exists, {@code false} to return {@code null} instead
- * @return The post with the given ID, or {@code null}
- */
- public Post getPost(String postId, boolean create);
-
-}
--- /dev/null
+/*
+ * Sone - Preferences.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core;
+
+import net.pterodactylus.sone.fcp.FcpInterface;
+import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
+
+/**
+ * Convenience interface for external classes that want to access the core’s
+ * configuration.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class Preferences {
+
+ /** The wrapped options. */
+ private final Options options;
+
+ /**
+ * Creates a new preferences object wrapped around the given options.
+ *
+ * @param options
+ * The options to wrap
+ */
+ public Preferences(Options options) {
+ this.options = options;
+ }
+
+ /**
+ * Returns the insertion delay.
+ *
+ * @return The insertion delay
+ */
+ public int getInsertionDelay() {
+ return options.getIntegerOption("InsertionDelay").get();
+ }
+
+ /**
+ * Validates the given insertion delay.
+ *
+ * @param insertionDelay
+ * The insertion delay to validate
+ * @return {@code true} if the given insertion delay was valid,
+ * {@code false} otherwise
+ */
+ public boolean validateInsertionDelay(Integer insertionDelay) {
+ return options.getIntegerOption("InsertionDelay").validate(insertionDelay);
+ }
+
+ /**
+ * Sets the insertion delay
+ *
+ * @param insertionDelay
+ * The new insertion delay, or {@code null} to restore it to
+ * the default value
+ * @return This preferences
+ */
+ public Preferences setInsertionDelay(Integer insertionDelay) {
+ options.getIntegerOption("InsertionDelay").set(insertionDelay);
+ return this;
+ }
+
+ /**
+ * Returns the number of posts to show per page.
+ *
+ * @return The number of posts to show per page
+ */
+ public int getPostsPerPage() {
+ return options.getIntegerOption("PostsPerPage").get();
+ }
+
+ /**
+ * Validates the number of posts per page.
+ *
+ * @param postsPerPage
+ * The number of posts per page
+ * @return {@code true} if the number of posts per page was valid,
+ * {@code false} otherwise
+ */
+ public boolean validatePostsPerPage(Integer postsPerPage) {
+ return options.getIntegerOption("PostsPerPage").validate(postsPerPage);
+ }
+
+ /**
+ * Sets the number of posts to show per page.
+ *
+ * @param postsPerPage
+ * The number of posts to show per page
+ * @return This preferences object
+ */
+ public Preferences setPostsPerPage(Integer postsPerPage) {
+ options.getIntegerOption("PostsPerPage").set(postsPerPage);
+ return this;
+ }
+
+ /**
+ * Returns the number of images to show per page.
+ *
+ * @return The number of images to show per page
+ */
+ public int getImagesPerPage() {
+ return options.getIntegerOption("ImagesPerPage").get();
+ }
+
+ /**
+ * Validates the number of images per page.
+ *
+ * @param imagesPerPage
+ * The number of images per page
+ * @return {@code true} if the number of images per page was valid,
+ * {@code false} otherwise
+ */
+ public boolean validateImagesPerPage(Integer imagesPerPage) {
+ return options.getIntegerOption("ImagesPerPage").validate(imagesPerPage);
+ }
+
+ /**
+ * Sets the number of images per page.
+ *
+ * @param imagesPerPage
+ * The number of images per page
+ * @return This preferences object
+ */
+ public Preferences setImagesPerPage(Integer imagesPerPage) {
+ options.getIntegerOption("ImagesPerPage").set(imagesPerPage);
+ return this;
+ }
+
+ /**
+ * Returns the number of characters per post, or <code>-1</code> if the
+ * posts should not be cut off.
+ *
+ * @return The numbers of characters per post
+ */
+ public int getCharactersPerPost() {
+ return options.getIntegerOption("CharactersPerPost").get();
+ }
+
+ /**
+ * Validates the number of characters per post.
+ *
+ * @param charactersPerPost
+ * The number of characters per post
+ * @return {@code true} if the number of characters per post was valid,
+ * {@code false} otherwise
+ */
+ public boolean validateCharactersPerPost(Integer charactersPerPost) {
+ return options.getIntegerOption("CharactersPerPost").validate(charactersPerPost);
+ }
+
+ /**
+ * Sets the number of characters per post.
+ *
+ * @param charactersPerPost
+ * The number of characters per post, or <code>-1</code> to
+ * not cut off the posts
+ * @return This preferences objects
+ */
+ public Preferences setCharactersPerPost(Integer charactersPerPost) {
+ options.getIntegerOption("CharactersPerPost").set(charactersPerPost);
+ return this;
+ }
+
+ /**
+ * Returns the number of characters the shortened post should have.
+ *
+ * @return The number of characters of the snippet
+ */
+ public int getPostCutOffLength() {
+ return options.getIntegerOption("PostCutOffLength").get();
+ }
+
+ /**
+ * Validates the number of characters after which to cut off the post.
+ *
+ * @param postCutOffLength
+ * The number of characters of the snippet
+ * @return {@code true} if the number of characters of the snippet is
+ * valid, {@code false} otherwise
+ */
+ public boolean validatePostCutOffLength(Integer postCutOffLength) {
+ return options.getIntegerOption("PostCutOffLength").validate(postCutOffLength);
+ }
+
+ /**
+ * Sets the number of characters the shortened post should have.
+ *
+ * @param postCutOffLength
+ * The number of characters of the snippet
+ * @return This preferences
+ */
+ public Preferences setPostCutOffLength(Integer postCutOffLength) {
+ options.getIntegerOption("PostCutOffLength").set(postCutOffLength);
+ return this;
+ }
+
+ /**
+ * Returns whether Sone requires full access to be even visible.
+ *
+ * @return {@code true} if Sone requires full access, {@code false}
+ * otherwise
+ */
+ public boolean isRequireFullAccess() {
+ return options.getBooleanOption("RequireFullAccess").get();
+ }
+
+ /**
+ * Sets whether Sone requires full access to be even visible.
+ *
+ * @param requireFullAccess
+ * {@code true} if Sone requires full access, {@code false}
+ * otherwise
+ */
+ public void setRequireFullAccess(Boolean requireFullAccess) {
+ options.getBooleanOption("RequireFullAccess").set(requireFullAccess);
+ }
+
+ /**
+ * Returns the positive trust.
+ *
+ * @return The positive trust
+ */
+ public int getPositiveTrust() {
+ return options.getIntegerOption("PositiveTrust").get();
+ }
+
+ /**
+ * Validates the positive trust.
+ *
+ * @param positiveTrust
+ * The positive trust to validate
+ * @return {@code true} if the positive trust was valid, {@code false}
+ * otherwise
+ */
+ public boolean validatePositiveTrust(Integer positiveTrust) {
+ return options.getIntegerOption("PositiveTrust").validate(positiveTrust);
+ }
+
+ /**
+ * Sets the positive trust.
+ *
+ * @param positiveTrust
+ * The new positive trust, or {@code null} to restore it to
+ * the default vlaue
+ * @return This preferences
+ */
+ public Preferences setPositiveTrust(Integer positiveTrust) {
+ options.getIntegerOption("PositiveTrust").set(positiveTrust);
+ return this;
+ }
+
+ /**
+ * Returns the negative trust.
+ *
+ * @return The negative trust
+ */
+ public int getNegativeTrust() {
+ return options.getIntegerOption("NegativeTrust").get();
+ }
+
+ /**
+ * Validates the negative trust.
+ *
+ * @param negativeTrust
+ * The negative trust to validate
+ * @return {@code true} if the negative trust was valid, {@code false}
+ * otherwise
+ */
+ public boolean validateNegativeTrust(Integer negativeTrust) {
+ return options.getIntegerOption("NegativeTrust").validate(negativeTrust);
+ }
+
+ /**
+ * Sets the negative trust.
+ *
+ * @param negativeTrust
+ * The negative trust, or {@code null} to restore it to the
+ * default value
+ * @return The preferences
+ */
+ public Preferences setNegativeTrust(Integer negativeTrust) {
+ options.getIntegerOption("NegativeTrust").set(negativeTrust);
+ return this;
+ }
+
+ /**
+ * Returns the trust comment. This is the comment that is set in the web
+ * of trust when a trust value is assigned to an identity.
+ *
+ * @return The trust comment
+ */
+ public String getTrustComment() {
+ return options.getStringOption("TrustComment").get();
+ }
+
+ /**
+ * Sets the trust comment.
+ *
+ * @param trustComment
+ * The trust comment, or {@code null} to restore it to the
+ * default value
+ * @return This preferences
+ */
+ public Preferences setTrustComment(String trustComment) {
+ options.getStringOption("TrustComment").set(trustComment);
+ return this;
+ }
+
+ /**
+ * Returns whether the {@link FcpInterface FCP interface} is currently
+ * active.
+ *
+ * @see FcpInterface#setActive(boolean)
+ * @return {@code true} if the FCP interface is currently active,
+ * {@code false} otherwise
+ */
+ public boolean isFcpInterfaceActive() {
+ return options.getBooleanOption("ActivateFcpInterface").get();
+ }
+
+ /**
+ * Sets whether the {@link FcpInterface FCP interface} is currently
+ * active.
+ *
+ * @see FcpInterface#setActive(boolean)
+ * @param fcpInterfaceActive
+ * {@code true} to activate the FCP interface, {@code false}
+ * to deactivate the FCP interface
+ * @return This preferences object
+ */
+ public Preferences setFcpInterfaceActive(boolean fcpInterfaceActive) {
+ options.getBooleanOption("ActivateFcpInterface").set(fcpInterfaceActive);
+ return this;
+ }
+
+ /**
+ * Returns the action level for which full access to the FCP interface
+ * is required.
+ *
+ * @return The action level for which full access to the FCP interface
+ * is required
+ */
+ public FullAccessRequired getFcpFullAccessRequired() {
+ return FullAccessRequired.values()[options.getIntegerOption("FcpFullAccessRequired").get()];
+ }
+
+ /**
+ * Sets the action level for which full access to the FCP interface is
+ * required
+ *
+ * @param fcpFullAccessRequired
+ * The action level
+ * @return This preferences
+ */
+ public Preferences setFcpFullAccessRequired(FullAccessRequired fcpFullAccessRequired) {
+ options.getIntegerOption("FcpFullAccessRequired").set((fcpFullAccessRequired != null) ? fcpFullAccessRequired.ordinal() : null);
+ return this;
+ }
+
+}
/*
- * Sone - SoneDownloader.java - Copyright © 2010–2012 David Roden
+ * Sone - SoneDownloader.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
import java.util.logging.Level;
import java.util.logging.Logger;
+import net.pterodactylus.sone.core.FreenetInterface.Fetched;
import net.pterodactylus.sone.data.Album;
import net.pterodactylus.sone.data.Client;
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.data.Sone.SoneStatus;
-import net.pterodactylus.util.collection.Pair;
+import net.pterodactylus.sone.database.PostBuilder;
+import net.pterodactylus.sone.database.PostReplyBuilder;
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.number.Numbers;
* The Sone to add
*/
public void addSone(Sone sone) {
- if (!sones.add(sone)) {
- freenetInterface.unregisterUsk(sone);
+ if (sones.add(sone)) {
+ freenetInterface.registerUsk(sone, this);
}
- freenetInterface.registerUsk(sone, this);
}
/**
FreenetURI requestUri = soneUri.setMetaString(new String[] { "sone.xml" });
sone.setStatus(SoneStatus.downloading);
try {
- Pair<FreenetURI, FetchResult> fetchResults = freenetInterface.fetchUri(requestUri);
+ Fetched fetchResults = freenetInterface.fetchUri(requestUri);
if (fetchResults == null) {
/* TODO - mark Sone as bad. */
return null;
}
- logger.log(Level.FINEST, String.format("Got %d bytes back.", fetchResults.getRight().size()));
- Sone parsedSone = parseSone(sone, fetchResults.getRight(), fetchResults.getLeft());
+ logger.log(Level.FINEST, String.format("Got %d bytes back.", fetchResults.getFetchResult().size()));
+ Sone parsedSone = parseSone(sone, fetchResults.getFetchResult(), fetchResults.getFreenetUri());
if (parsedSone != null) {
if (!fetchOnly) {
+ parsedSone.setStatus((parsedSone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle);
core.updateSone(parsedSone);
addSone(parsedSone);
}
return null;
}
- Sone sone = new Sone(originalSone.getId()).setIdentity(originalSone.getIdentity());
+ Sone sone = new Sone(originalSone.getId(), false).setIdentity(originalSone.getIdentity());
SimpleXML soneXml;
try {
return null;
}
try {
- Post post = core.getPost(postId).setSone(sone).setTime(Long.parseLong(postTime)).setText(postText);
+ PostBuilder postBuilder = core.postBuilder();
+ /* TODO - parse time correctly. */
+ postBuilder.withId(postId).from(sone.getId()).withTime(Long.parseLong(postTime)).withText(postText);
if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
- post.setRecipient(core.getSone(postRecipientId));
+ postBuilder.to(postRecipientId);
}
- posts.add(post);
+ posts.add(postBuilder.build());
} catch (NumberFormatException nfe1) {
/* TODO - mark Sone as bad. */
logger.log(Level.WARNING, String.format("Downloaded post for Sone %s with invalid time: %s", sone, postTime));
return null;
}
try {
- replies.add(core.getReply(replyId).setSone(sone).setPost(core.getPost(replyPostId)).setTime(Long.parseLong(replyTime)).setText(replyText));
+ PostReplyBuilder postReplyBuilder = core.postReplyBuilder();
+ /* TODO - parse time correctly. */
+ postReplyBuilder.withId(replyId).from(sone.getId()).to(replyPostId).withTime(Long.parseLong(replyTime)).withText(replyText);
+ replies.add(postReplyBuilder.build());
} catch (NumberFormatException nfe1) {
/* TODO - mark Sone as bad. */
logger.log(Level.WARNING, String.format("Downloaded reply for Sone %s with invalid time: %s", sone, replyTime));
/*
- * Sone - SoneException.java - Copyright © 2010–2012 David Roden
+ * Sone - SoneException.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
/*
- * Sone - SoneInsertException.java - Copyright © 2011–2012 David Roden
+ * Sone - SoneInsertException.java - Copyright © 2011–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
+++ /dev/null
-/*
- * Sone - SoneInsertListener.java - Copyright © 2011–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.core;
-
-import java.util.EventListener;
-
-import net.pterodactylus.sone.data.Sone;
-
-/**
- * Listener for Sone insert events.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface SoneInsertListener extends EventListener {
-
- /**
- * Notifies a listener that a Sone is now being inserted.
- *
- * @param sone
- * The Sone being inserted
- */
- public void insertStarted(Sone sone);
-
- /**
- * Notifies a listener that a Sone has been successfully inserted.
- *
- * @param sone
- * The Sone that was inserted
- * @param insertDuration
- * The duration of the insert (in milliseconds)
- */
- public void insertFinished(Sone sone, long insertDuration);
-
- /**
- * Notifies a listener that the insert of the given Sone was aborted.
- *
- * @param sone
- * The Sone that was being inserted
- * @param cause
- * The cause of the abortion (may be {@code null})
- */
- public void insertAborted(Sone sone, Throwable cause);
-
-}
+++ /dev/null
-/*
- * Sone - SoneInsertListenerManager.java - Copyright © 2011–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.core;
-
-import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.util.event.AbstractListenerManager;
-
-/**
- * Manager for {@link SoneInsertListener}s.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class SoneInsertListenerManager extends AbstractListenerManager<Sone, SoneInsertListener> {
-
- /**
- * Creates a new Sone insert listener manager.
- *
- * @param sone
- * The sone being inserted
- */
- public SoneInsertListenerManager(Sone sone) {
- super(sone);
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Notifies all listeners that the insert of the Sone has started.
- *
- * @see SoneInsertListener#insertStarted(Sone)
- */
- void fireInsertStarted() {
- for (SoneInsertListener soneInsertListener : getListeners()) {
- soneInsertListener.insertStarted(getSource());
- }
- }
-
- /**
- * Notifies all listeners that the insert of the Sone has finished
- * successfully.
- *
- * @see SoneInsertListener#insertFinished(Sone, long)
- * @param insertDuration
- * The insert duration (in milliseconds)
- */
- void fireInsertFinished(long insertDuration) {
- for (SoneInsertListener soneInsertListener : getListeners()) {
- soneInsertListener.insertFinished(getSource(), insertDuration);
- }
- }
-
- /**
- * Notifies all listeners that the insert of the Sone was aborted.
- *
- * @see SoneInsertListener#insertAborted(Sone, Throwable)
- * @param cause
- * The cause of the abortion (may be {@code null}
- */
- void fireInsertAborted(Throwable cause) {
- for (SoneInsertListener soneInsertListener : getListeners()) {
- soneInsertListener.insertAborted(getSource(), cause);
- }
- }
-
-}
/*
- * Sone - SoneInserter.java - Copyright © 2010–2012 David Roden
+ * Sone - SoneInserter.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
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.nio.charset.Charset;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
+import net.pterodactylus.sone.core.event.SoneInsertAbortedEvent;
+import net.pterodactylus.sone.core.event.SoneInsertedEvent;
+import net.pterodactylus.sone.core.event.SoneInsertingEvent;
+import net.pterodactylus.sone.data.Album;
import net.pterodactylus.sone.data.Post;
-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.freenet.StringBucket;
import net.pterodactylus.sone.main.SonePlugin;
-import net.pterodactylus.util.collection.ListBuilder;
-import net.pterodactylus.util.collection.ReverseComparator;
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.service.AbstractService;
import net.pterodactylus.util.template.TemplateException;
import net.pterodactylus.util.template.TemplateParser;
import net.pterodactylus.util.template.XmlFilter;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Ordering;
+import com.google.common.eventbus.EventBus;
+
import freenet.client.async.ManifestElement;
import freenet.keys.FreenetURI;
/** The core. */
private final Core core;
+ /** The event bus. */
+ private final EventBus eventBus;
+
/** The Freenet interface. */
private final FreenetInterface freenetInterface;
/** The Sone to insert. */
private final Sone sone;
- /** The insert listener manager. */
- private SoneInsertListenerManager soneInsertListenerManager;
-
/** Whether a modification has been detected. */
private volatile boolean modified = false;
*
* @param core
* The core
+ * @param eventBus
+ * The event bus
* @param freenetInterface
* The freenet interface
* @param sone
* The Sone to insert
*/
- public SoneInserter(Core core, FreenetInterface freenetInterface, Sone sone) {
+ public SoneInserter(Core core, EventBus eventBus, FreenetInterface freenetInterface, Sone sone) {
super("Sone Inserter for “" + sone.getName() + "”", false);
this.core = core;
+ this.eventBus = eventBus;
this.freenetInterface = freenetInterface;
this.sone = sone;
- this.soneInsertListenerManager = new SoneInsertListenerManager(sone);
- }
-
- //
- // LISTENER MANAGEMENT
- //
-
- /**
- * Adds a listener for Sone insert events.
- *
- * @param soneInsertListener
- * The Sone insert listener
- */
- public void addSoneInsertListener(SoneInsertListener soneInsertListener) {
- soneInsertListenerManager.addListener(soneInsertListener);
- }
-
- /**
- * Removes a listener for Sone insert events.
- *
- * @param soneInsertListener
- * The Sone insert listener
- */
- public void removeSoneInsertListener(SoneInsertListener soneInsertListener) {
- soneInsertListenerManager.removeListener(soneInsertListener);
}
//
long lastModificationTime = 0;
String lastInsertedFingerprint = lastInsertFingerprint;
String lastFingerprint = "";
- while (!shouldStop()) { try {
- /* check every seconds. */
- sleep(1000);
+ while (!shouldStop()) {
+ try {
+ /* check every seconds. */
+ sleep(1000);
- /* don’t insert locked Sones. */
- if (core.isLocked(sone)) {
- /* trigger redetection when the Sone is unlocked. */
- synchronized (sone) {
- modified = !sone.getFingerprint().equals(lastInsertedFingerprint);
+ /* don’t insert locked Sones. */
+ if (core.isLocked(sone)) {
+ /* trigger redetection when the Sone is unlocked. */
+ synchronized (sone) {
+ modified = !sone.getFingerprint().equals(lastInsertedFingerprint);
+ }
+ lastFingerprint = "";
+ lastModificationTime = 0;
+ continue;
}
- lastFingerprint = "";
- lastModificationTime = 0;
- continue;
- }
- InsertInformation insertInformation = null;
- synchronized (sone) {
- String fingerprint = sone.getFingerprint();
- if (!fingerprint.equals(lastFingerprint)) {
- if (fingerprint.equals(lastInsertedFingerprint)) {
- modified = false;
- lastModificationTime = 0;
- logger.log(Level.FINE, String.format("Sone %s has been reverted to last insert state.", sone));
- } else {
- lastModificationTime = System.currentTimeMillis();
- modified = true;
- logger.log(Level.FINE, String.format("Sone %s has been modified, waiting %d seconds before inserting.", sone.getName(), insertionDelay));
+ InsertInformation insertInformation = null;
+ synchronized (sone) {
+ String fingerprint = sone.getFingerprint();
+ if (!fingerprint.equals(lastFingerprint)) {
+ if (fingerprint.equals(lastInsertedFingerprint)) {
+ modified = false;
+ lastModificationTime = 0;
+ logger.log(Level.FINE, String.format("Sone %s has been reverted to last insert state.", sone));
+ } else {
+ lastModificationTime = System.currentTimeMillis();
+ modified = true;
+ logger.log(Level.FINE, String.format("Sone %s has been modified, waiting %d seconds before inserting.", sone.getName(), insertionDelay));
+ }
+ lastFingerprint = fingerprint;
+ }
+ if (modified && (lastModificationTime > 0) && ((System.currentTimeMillis() - lastModificationTime) > (insertionDelay * 1000))) {
+ lastInsertedFingerprint = fingerprint;
+ insertInformation = new InsertInformation(sone);
}
- lastFingerprint = fingerprint;
- }
- if (modified && (lastModificationTime > 0) && ((System.currentTimeMillis() - lastModificationTime) > (insertionDelay * 1000))) {
- lastInsertedFingerprint = fingerprint;
- insertInformation = new InsertInformation(sone);
}
- }
- if (insertInformation != null) {
- logger.log(Level.INFO, String.format("Inserting Sone “%s”…", sone.getName()));
-
- boolean success = false;
- try {
- sone.setStatus(SoneStatus.inserting);
- long insertTime = System.currentTimeMillis();
- insertInformation.setTime(insertTime);
- soneInsertListenerManager.fireInsertStarted();
- FreenetURI finalUri = freenetInterface.insertDirectory(insertInformation.getInsertUri(), insertInformation.generateManifestEntries(), "index.html");
- soneInsertListenerManager.fireInsertFinished(System.currentTimeMillis() - insertTime);
- /* at this point we might already be stopped. */
- if (shouldStop()) {
- /* if so, bail out, don’t change anything. */
- break;
+ if (insertInformation != null) {
+ logger.log(Level.INFO, String.format("Inserting Sone “%s”…", sone.getName()));
+
+ boolean success = false;
+ try {
+ sone.setStatus(SoneStatus.inserting);
+ long insertTime = System.currentTimeMillis();
+ insertInformation.setTime(insertTime);
+ eventBus.post(new SoneInsertingEvent(sone));
+ FreenetURI finalUri = freenetInterface.insertDirectory(insertInformation.getInsertUri(), insertInformation.generateManifestEntries(), "index.html");
+ eventBus.post(new SoneInsertedEvent(sone, System.currentTimeMillis() - insertTime));
+ /* at this point we might already be stopped. */
+ if (shouldStop()) {
+ /* if so, bail out, don’t change anything. */
+ break;
+ }
+ sone.setTime(insertTime);
+ sone.setLatestEdition(finalUri.getEdition());
+ core.touchConfiguration();
+ success = true;
+ logger.log(Level.INFO, String.format("Inserted Sone “%s” at %s.", sone.getName(), finalUri));
+ } catch (SoneException se1) {
+ eventBus.post(new SoneInsertAbortedEvent(sone, se1));
+ logger.log(Level.WARNING, String.format("Could not insert Sone “%s”!", sone.getName()), se1);
+ } finally {
+ sone.setStatus(SoneStatus.idle);
}
- sone.setTime(insertTime);
- sone.setLatestEdition(finalUri.getEdition());
- core.touchConfiguration();
- success = true;
- logger.log(Level.INFO, String.format("Inserted Sone “%s” at %s.", sone.getName(), finalUri));
- } catch (SoneException se1) {
- soneInsertListenerManager.fireInsertAborted(se1);
- logger.log(Level.WARNING, String.format("Could not insert Sone “%s”!", sone.getName()), se1);
- } finally {
- sone.setStatus(SoneStatus.idle);
- }
- /*
- * reset modification counter if Sone has not been modified
- * while it was inserted.
- */
- if (success) {
- synchronized (sone) {
- if (lastInsertedFingerprint.equals(sone.getFingerprint())) {
- logger.log(Level.FINE, String.format("Sone “%s” was not modified further, resetting counter…", sone));
- lastModificationTime = 0;
- lastInsertFingerprint = lastInsertedFingerprint;
- core.touchConfiguration();
- modified = false;
+ /*
+ * reset modification counter if Sone has not been modified
+ * while it was inserted.
+ */
+ if (success) {
+ synchronized (sone) {
+ if (lastInsertedFingerprint.equals(sone.getFingerprint())) {
+ logger.log(Level.FINE, String.format("Sone “%s” was not modified further, resetting counter…", sone));
+ lastModificationTime = 0;
+ lastInsertFingerprint = lastInsertedFingerprint;
+ core.touchConfiguration();
+ modified = false;
+ }
}
}
}
+ } catch (Throwable t1) {
+ logger.log(Level.SEVERE, "SoneInserter threw an Exception!", t1);
}
- } catch (Throwable t1) {
- logger.log(Level.SEVERE, "SoneInserter threw an Exception!", t1);
- }}
+ }
}
/**
soneProperties.put("requestUri", sone.getRequestUri());
soneProperties.put("insertUri", sone.getInsertUri());
soneProperties.put("profile", sone.getProfile());
- soneProperties.put("posts", new ListBuilder<Post>(new ArrayList<Post>(sone.getPosts())).sort(Post.TIME_COMPARATOR).get());
- soneProperties.put("replies", new ListBuilder<PostReply>(new ArrayList<PostReply>(sone.getReplies())).sort(new ReverseComparator<Reply<?>>(Reply.TIME_COMPARATOR)).get());
+ soneProperties.put("posts", Ordering.from(Post.TIME_COMPARATOR).sortedCopy(sone.getPosts()));
+ soneProperties.put("replies", Ordering.from(Reply.TIME_COMPARATOR).reverse().sortedCopy(sone.getReplies()));
soneProperties.put("likedPostIds", new HashSet<String>(sone.getLikedPostIds()));
soneProperties.put("likedReplyIds", new HashSet<String>(sone.getLikedReplyIds()));
- soneProperties.put("albums", sone.getAllAlbums());
+ soneProperties.put("albums", FluentIterable.from(sone.getAlbums()).transformAndConcat(Album.FLATTENER).toList());
}
//
+++ /dev/null
-/*
- * Sone - SoneProvider.java - Copyright © 2011–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.core;
-
-import net.pterodactylus.sone.data.Sone;
-
-/**
- * Interface for objects that can provide {@link Sone}s by their ID.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface SoneProvider {
-
- /**
- * Returns the Sone with the given ID, if it exists. If it does not exist
- * and {@code create} is {@code false}, {@code null} is returned; otherwise,
- * a new Sone with the given ID is created and returned.
- *
- * @param soneId
- * The ID of the Sone to return
- * @param create
- * {@code true} to create a new Sone if no Sone with the given ID
- * exists, {@code false} to return {@code null} instead
- * @return The Sone with the given ID, or {@code null}
- */
- public Sone getSone(String soneId, boolean create);
-
-}
/*
- * Sone - SoneRescuer.java - Copyright © 2011–2012 David Roden
+ * Sone - SoneRescuer.java - Copyright © 2011–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
--- /dev/null
+/*
+ * Sone - SoneUri.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core;
+
+import java.net.MalformedURLException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import net.pterodactylus.util.logging.Logging;
+import freenet.keys.FreenetURI;
+
+/**
+ * Helper class that creates {@link FreenetURI}s for Sone to insert to and
+ * request from.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class SoneUri {
+
+ /** The logger. */
+ private static final Logger logger = Logging.getLogger(SoneUri.class);
+
+ /**
+ * Generate a Sone URI from the given URI.
+ *
+ * @param uri
+ * The URI to derive the Sone URI from
+ * @return The derived URI
+ */
+ public static FreenetURI create(String uri) {
+ try {
+ return new FreenetURI(uri).setDocName("Sone").setMetaString(new String[0]);
+ } catch (MalformedURLException mue1) {
+ /* this should never happen. */
+ logger.log(Level.WARNING, String.format("Could not create Sone URI from URI: %s", uri), mue1);
+ return null;
+ }
+ }
+
+}
/*
- * Sone - UpdateChecker.java - Copyright © 2011–2012 David Roden
+ * Sone - UpdateChecker.java - Copyright © 2011–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
import java.util.logging.Level;
import java.util.logging.Logger;
+import net.pterodactylus.sone.core.FreenetInterface.Fetched;
+import net.pterodactylus.sone.core.event.UpdateFoundEvent;
import net.pterodactylus.sone.main.SonePlugin;
-import net.pterodactylus.util.collection.Pair;
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.version.Version;
-import freenet.client.FetchResult;
+
+import com.google.common.eventbus.EventBus;
+import com.google.inject.Inject;
+
import freenet.keys.FreenetURI;
import freenet.support.api.Bucket;
/** The current latest known edition. */
private static final int LATEST_EDITION = 55;
+ /** The event bus. */
+ private final EventBus eventBus;
+
/** The Freenet interface. */
private final FreenetInterface freenetInterface;
- /** The update listener manager. */
- private final UpdateListenerManager updateListenerManager = new UpdateListenerManager();
-
/** The current URI of the homepage. */
private FreenetURI currentUri;
/**
* Creates a new update checker.
*
+ * @param eventBus
+ * The event bus
* @param freenetInterface
* The freenet interface to use
*/
- public UpdateChecker(FreenetInterface freenetInterface) {
+ @Inject
+ public UpdateChecker(EventBus eventBus, FreenetInterface freenetInterface) {
+ this.eventBus = eventBus;
this.freenetInterface = freenetInterface;
}
//
- // EVENT LISTENER MANAGEMENT
- //
-
- /**
- * Adds the given listener to the list of registered listeners.
- *
- * @param updateListener
- * The listener to add
- */
- public void addUpdateListener(UpdateListener updateListener) {
- updateListenerManager.addListener(updateListener);
- }
-
- /**
- * Removes the given listener from the list of registered listeners.
- *
- * @param updateListener
- * The listener to remove
- */
- public void removeUpdateListener(UpdateListener updateListener) {
- updateListenerManager.removeListener(updateListener);
- }
-
- //
// ACCESSORS
//
public void editionFound(FreenetURI uri, long edition, boolean newKnownGood, boolean newSlot) {
logger.log(Level.FINEST, String.format("Found update for %s: %d, %s, %s", uri, edition, newKnownGood, newSlot));
if (newKnownGood || newSlot) {
- Pair<FreenetURI, FetchResult> uriResult = freenetInterface.fetchUri(uri.setMetaString(new String[] { "sone.properties" }));
+ Fetched uriResult = freenetInterface.fetchUri(uri.setMetaString(new String[] { "sone.properties" }));
if (uriResult == null) {
logger.log(Level.WARNING, String.format("Could not fetch properties of latest homepage: %s", uri));
return;
}
- Bucket resultBucket = uriResult.getRight().asBucket();
+ Bucket resultBucket = uriResult.getFetchResult().asBucket();
try {
parseProperties(resultBucket.getInputStream(), edition);
latestEdition = edition;
* Parses the properties of the latest version and fires events, if
* necessary.
*
- * @see UpdateListener#updateFound(Version, long, long)
- * @see UpdateListenerManager#fireUpdateFound(Version, long, long)
+ * @see UpdateFoundEvent
* @param propertiesInputStream
* The input stream to parse
* @param edition
currentLatestVersion = version;
latestVersionDate = releaseTime;
logger.log(Level.INFO, String.format("Found new version: %s (%tc)", version, new Date(releaseTime)));
- updateListenerManager.fireUpdateFound(version, releaseTime, edition);
+ eventBus.post(new UpdateFoundEvent(version, releaseTime, edition));
}
}
+++ /dev/null
-/*
- * Sone - UpdateListener.java - Copyright © 2011–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.core;
-
-import java.util.EventListener;
-
-import net.pterodactylus.util.version.Version;
-
-/**
- * Listener interface for {@link UpdateChecker} events.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface UpdateListener extends EventListener {
-
- /**
- * Notifies a listener that a newer version than the current version was
- * found.
- *
- * @param version
- * The version that was found
- * @param releaseTime
- * The release time of the version
- * @param latestEdition
- * The latest edition of the Sone homepage
- */
- public void updateFound(Version version, long releaseTime, long latestEdition);
-
-}
+++ /dev/null
-/*
- * Sone - UpdateListenerManager.java - Copyright © 2011–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.core;
-
-import net.pterodactylus.util.event.AbstractListenerManager;
-import net.pterodactylus.util.version.Version;
-
-/**
- * Listener manager for {@link UpdateListener} events.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class UpdateListenerManager extends AbstractListenerManager<Void, UpdateListener> {
-
- /**
- * Creates a new update listener manager.
- */
- public UpdateListenerManager() {
- super(null);
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Notifies all listeners that a new version has been found.
- *
- * @param version
- * The new version
- * @param releaseTime
- * The release time of the new version
- * @param latestEdition
- * The latest edition of the Sone homepage
- */
- void fireUpdateFound(Version version, long releaseTime, long latestEdition) {
- for (UpdateListener updateListener : getListeners()) {
- updateListener.updateFound(version, releaseTime, latestEdition);
- }
- }
-
-}
/*
- * Sone - WebOfTrustUpdater.java - Copyright © 2012 David Roden
+ * Sone - WebOfTrustUpdater.java - Copyright © 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
package net.pterodactylus.sone.core;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.service.AbstractService;
-import net.pterodactylus.util.validation.Validation;
+
+import com.google.inject.Inject;
/**
* Updates WebOfTrust identity data in a background thread because communicating
* @param webOfTrustConnector
* The web of trust connector
*/
+ @Inject
public WebOfTrustUpdater(WebOfTrustConnector webOfTrustConnector) {
super("Trust Updater");
this.webOfTrustConnector = webOfTrustConnector;
*
* @return {@code true} if this job finished successfully, {@code false}
* otherwise
- *
* @see WebOfTrustUpdater#stop()
*/
@SuppressWarnings("synthetic-access")
*/
@SuppressWarnings("synthetic-access")
public WebOfTrustContextUpdateJob(OwnIdentity ownIdentity, String context) {
- Validation.begin().isNotNull("OwnIdentity", ownIdentity).isNotNull("Context", context).check();
- this.ownIdentity = ownIdentity;
- this.context = context;
+ this.ownIdentity = checkNotNull(ownIdentity, "ownIdentity must not be null");
+ this.context = checkNotNull(context, "context must not be null");
}
//
--- /dev/null
+/*
+ * Sone - ImageEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Image;
+
+/**
+ * Base class for {@link Image} events.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public abstract class ImageEvent {
+
+ /** The image this event is about. */
+ private final Image image;
+
+ /**
+ * Creates a new image event.
+ *
+ * @param image
+ * The image this event is about
+ */
+ protected ImageEvent(Image image) {
+ this.image = image;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the image this event is about.
+ *
+ * @return The image this event is about
+ */
+ public Image image() {
+ return image;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - ImageInsertAbortedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Image;
+
+/**
+ * Event that signals that an {@link Image} insert is aborted.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class ImageInsertAbortedEvent extends ImageEvent {
+
+ /**
+ * Creates a new “image insert aborted” event.
+ *
+ * @param image
+ * The image whose insert aborted
+ */
+ public ImageInsertAbortedEvent(Image image) {
+ super(image);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - ImageInsertFailedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Image;
+
+/**
+ * Event that signals that an {@link Image} insert has failed.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class ImageInsertFailedEvent extends ImageEvent {
+
+ /** The cause of the insert failure. */
+ private final Throwable cause;
+
+ /**
+ * Creates a new “image insert failed” event.
+ *
+ * @param image
+ * The image whose insert failed
+ * @param cause
+ * The cause of the insert failure
+ */
+ public ImageInsertFailedEvent(Image image, Throwable cause) {
+ super(image);
+ this.cause = cause;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the cause of the insert failure.
+ *
+ * @return The cause of the insert failure
+ */
+ public Throwable cause() {
+ return cause;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - ImageInsertFinishedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Image;
+import freenet.keys.FreenetURI;
+
+/**
+ * Event that signals that an {@link Image} insert is finished.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class ImageInsertFinishedEvent extends ImageEvent {
+
+ /** The URI of the image. */
+ private final FreenetURI resultingUri;
+
+ /**
+ * Creates a new “image insert finished” event.
+ *
+ * @param image
+ * The image whose insert finished
+ * @param resultingUri
+ * The resulting URI of the image
+ */
+ public ImageInsertFinishedEvent(Image image, FreenetURI resultingUri) {
+ super(image);
+ this.resultingUri = resultingUri;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the URI of the image.
+ *
+ * @return The URI of the image
+ */
+ public FreenetURI resultingUri() {
+ return resultingUri;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - ImageInsertStartedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Image;
+
+/**
+ * Event that signals that an {@link Image} is not being inserted.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class ImageInsertStartedEvent extends ImageEvent {
+
+ /**
+ * Creates a new “image is inserted” event.
+ *
+ * @param image
+ * The image that is being inserted
+ */
+ public ImageInsertStartedEvent(Image image) {
+ super(image);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - MarkPostKnownEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Post;
+
+/**
+ * Event that signals that a {@link Post} has been marked as
+ * {@link Post#isKnown() known}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class MarkPostKnownEvent extends PostEvent {
+
+ /**
+ * Creates a new “post marked known” event.
+ *
+ * @param post
+ * The post that was marked as known
+ */
+ public MarkPostKnownEvent(Post post) {
+ super(post);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - MarkPostReplyKnownEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.PostReply;
+
+/**
+ * Event that signals that a {@link PostReply} has been marked as
+ * {@link PostReply#isKnown() known}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class MarkPostReplyKnownEvent extends PostReplyEvent {
+
+ /**
+ * Creates a new “post reply marked known” event.
+ *
+ * @param postReply
+ * The post reply that was marked as known
+ */
+ public MarkPostReplyKnownEvent(PostReply postReply) {
+ super(postReply);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - MarkSoneKnownEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Event that signals that a {@link Sone} has been marked as
+ * {@link Sone#isKnown() known}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class MarkSoneKnownEvent extends SoneEvent {
+
+ /**
+ * Creates a new “Sone marked known” event.
+ *
+ * @param sone
+ * The Sone that was marked as known
+ */
+ public MarkSoneKnownEvent(Sone sone) {
+ super(sone);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - NewPostFoundEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Post;
+
+/**
+ * Event that signals that a new post was found.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class NewPostFoundEvent extends PostEvent {
+
+ /**
+ * Creates a new “new post found” event.
+ *
+ * @param post
+ * The post that was found
+ */
+ public NewPostFoundEvent(Post post) {
+ super(post);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - NewPostReplyFoundEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.PostReply;
+
+/**
+ * Event that signals that a new {@link PostReply} was found.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class NewPostReplyFoundEvent extends PostReplyEvent {
+
+ /**
+ * Creates a new “new post found” event.
+ *
+ * @param postReply
+ * The post reply that was found
+ */
+ public NewPostReplyFoundEvent(PostReply postReply) {
+ super(postReply);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - NewSoneFoundEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Event that signals that a new remote Sone was found.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class NewSoneFoundEvent extends SoneEvent {
+
+ /**
+ * Creates a new “new Sone found” event.
+ *
+ * @param sone
+ * The Sone that was found
+ */
+ public NewSoneFoundEvent(Sone sone) {
+ super(sone);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - PostEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Post;
+
+/**
+ * Base class for post events.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostEvent {
+
+ /** The post the event is about. */
+ private final Post post;
+
+ /**
+ * Creates a new post event.
+ *
+ * @param post
+ * The post the event is about
+ */
+ protected PostEvent(Post post) {
+ this.post = post;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the post the event is about.
+ *
+ * @return The post the event is about
+ */
+ public Post post() {
+ return post;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - PostRemovedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Post;
+
+/**
+ * Event that signals that a {@link Post} was removed.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostRemovedEvent extends PostEvent {
+
+ /**
+ * Creates a new “post removed” event.
+ *
+ * @param post
+ * The post that was removed
+ */
+ public PostRemovedEvent(Post post) {
+ super(post);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - PostReplyEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.PostReply;
+
+/**
+ * Base class for {@link PostReply} events.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostReplyEvent {
+
+ /** The post reply the event is about. */
+ private final PostReply postReply;
+
+ /**
+ * Creates a new post reply event.
+ *
+ * @param postReply
+ * The post reply the event is about
+ */
+ protected PostReplyEvent(PostReply postReply) {
+ this.postReply = postReply;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the post reply the event is about.
+ *
+ * @return The post reply the event is about
+ */
+ public PostReply postReply() {
+ return postReply;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - PostReplyRemovedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.PostReply;
+
+/**
+ * Event that signals that a {@link PostReply} was removed.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostReplyRemovedEvent extends PostReplyEvent {
+
+ /**
+ * Creates a new “post reply removed” event.
+ *
+ * @param postReply
+ * The post reply that was removed
+ */
+ public PostReplyRemovedEvent(PostReply postReply) {
+ super(postReply);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - SoneEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Base class for Sone events.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public abstract class SoneEvent {
+
+ /** The Sone this event is about. */
+ private final Sone sone;
+
+ /**
+ * Creates a new Sone event.
+ *
+ * @param sone
+ * The Sone this event is about
+ */
+ protected SoneEvent(Sone sone) {
+ this.sone = sone;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the Sone this event is about.
+ *
+ * @return The Sone this event is about
+ */
+ public Sone sone() {
+ return sone;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - SoneInsertAbortedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Event that signals that a {@link Sone} insert was aborted.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class SoneInsertAbortedEvent extends SoneEvent {
+
+ /** The cause of the abortion. */
+ private final Throwable cause;
+
+ /**
+ * Creates a new “Sone was inserted” event.
+ *
+ * @param sone
+ * The Sone that was inserted
+ * @param cause
+ * The cause of the abortion
+ */
+ public SoneInsertAbortedEvent(Sone sone, Throwable cause) {
+ super(sone);
+ this.cause = cause;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the cause of the abortion.
+ *
+ * @return The cause of the abortion (may be {@code null})
+ */
+ public Throwable cause() {
+ return cause;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - SoneInsertedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Event that signals that a {@link Sone} was inserted.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class SoneInsertedEvent extends SoneEvent {
+
+ /** The duration of the insert. */
+ private final long insertDuration;
+
+ /**
+ * Creates a new “Sone was inserted” event.
+ *
+ * @param sone
+ * The Sone that was inserted
+ * @param insertDuration
+ * The duration of the insert (in milliseconds)
+ */
+ public SoneInsertedEvent(Sone sone, long insertDuration) {
+ super(sone);
+ this.insertDuration = insertDuration;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the duration of the insert.
+ *
+ * @return The duration of the insert (in milliseconds)
+ */
+ public long insertDuration() {
+ return insertDuration;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - SoneInsertingEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Event that signals that a {@link Sone} is now being inserted.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class SoneInsertingEvent extends SoneEvent {
+
+ /**
+ * Creates a new “Sone is being inserted” event.
+ *
+ * @param sone
+ * The Sone that is being inserted
+ */
+ public SoneInsertingEvent(Sone sone) {
+ super(sone);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - SoneLockedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Event that signals that a {@link Sone} was locked. Only
+ * {@link Sone#isLocal() local Sones} can be locked.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class SoneLockedEvent extends SoneEvent {
+
+ /**
+ * Creates a new “Sone locked” event.
+ *
+ * @param sone
+ * The Sone that was locked
+ */
+ public SoneLockedEvent(Sone sone) {
+ super(sone);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - SoneRemovedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Event that signals that a {@link Sone} was removed.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class SoneRemovedEvent extends SoneEvent {
+
+ /**
+ * Creates a new “Sone removed” event.
+ *
+ * @param sone
+ * The Sone that was removed
+ */
+ public SoneRemovedEvent(Sone sone) {
+ super(sone);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - SoneUnlockedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Event that signals that a {@link Sone} was unlocked. Only
+ * {@link Sone#isLocal() local Sones} can be locked.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class SoneUnlockedEvent extends SoneEvent {
+
+ /**
+ * Creates a new “Sone unlocked” event.
+ *
+ * @param sone
+ * The Sone that was unlocked
+ */
+ public SoneUnlockedEvent(Sone sone) {
+ super(sone);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - UpdateFoundEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core.event;
+
+import net.pterodactylus.util.version.Version;
+
+/**
+ * Event that signals that an update for Sone was found.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class UpdateFoundEvent {
+
+ /** The version that was found. */
+ private final Version version;
+
+ /** The time the update was released. */
+ private final long releaseTime;
+
+ /** The latest edition of the update page. */
+ private final long latestEdition;
+
+ /**
+ * Creates a new “update found” event.
+ *
+ * @param version
+ * The version of the update
+ * @param releaseTime
+ * The release time of the update
+ * @param latestEdition
+ * The latest edition of the update page
+ */
+ public UpdateFoundEvent(Version version, long releaseTime, long latestEdition) {
+ this.version = version;
+ this.releaseTime = releaseTime;
+ this.latestEdition = latestEdition;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the version of the update.
+ *
+ * @return The version of the update
+ */
+ public Version version() {
+ return version;
+ }
+
+ /**
+ * Returns the release time of the update.
+ *
+ * @return The releae time of the update (in milliseconds since Jan 1, 1970
+ * UTC)
+ */
+ public long releaseTime() {
+ return releaseTime;
+ }
+
+ /**
+ * Returns the latest edition of the update page.
+ *
+ * @return The latest edition of the update page
+ */
+ public long latestEdition() {
+ return latestEdition;
+ }
+
+}
/*
- * Sone - Album.java - Copyright © 2011–2012 David Roden
+ * Sone - Album.java - Copyright © 2011–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
package net.pterodactylus.sone.data;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
-import net.pterodactylus.util.collection.IterableWrapper;
-import net.pterodactylus.util.collection.filter.NotNullFilter;
-import net.pterodactylus.util.collection.mapper.Mapper;
-import net.pterodactylus.util.object.Default;
-import net.pterodactylus.util.validation.Validation;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
/**
* Container for images that can also contain nested {@link Album}s.
}
};
+ /** Function that flattens the given album and all albums beneath it. */
+ public static final Function<Album, List<Album>> FLATTENER = new Function<Album, List<Album>>() {
+
+ @Override
+ public List<Album> apply(Album album) {
+ List<Album> albums = new ArrayList<Album>();
+ albums.add(album);
+ for (Album subAlbum : album.getAlbums()) {
+ albums.addAll(FluentIterable.from(ImmutableList.of(subAlbum)).transformAndConcat(FLATTENER).toList());
+ }
+ return albums;
+ }
+ };
+
/** The ID of this album. */
private final String id;
* The ID of the album
*/
public Album(String id) {
- Validation.begin().isNotNull("Album ID", id).check();
- this.id = id;
+ this.id = checkNotNull(id, "id must not be null");
}
//
* @return This album
*/
public Album setSone(Sone sone) {
- Validation.begin().isNotNull("New Album Owner", sone).isEither("Old Album Owner", this.sone, null, sone).check();
+ checkNotNull(sone, "sone must not be null");
+ checkState((this.sone == null) || (this.sone.equals(sone)), "album owner must not already be set to some other Sone");
this.sone = sone;
return this;
}
* The album to add
*/
public void addAlbum(Album album) {
- Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.sone, sone).isEither("Old Album Parent", this.parent, null, album.parent).check();
+ checkNotNull(album, "album must not be null");
+ checkArgument(album.getSone().equals(sone), "album must belong to the same Sone as this album");
+ checkState((this.parent == null) || (this.parent.equals(album.parent)), "album must not already be set to some other Sone");
album.setParent(this);
if (!albums.contains(album)) {
albums.add(album);
* The album to remove
*/
public void removeAlbum(Album album) {
- Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.sone, sone).isEqual("Album Parent", album.parent, this).check();
+ checkNotNull(album, "album must not be null");
+ checkArgument(album.sone.equals(sone), "album must belong this album’s Sone");
+ checkArgument(equals(album.parent), "album must belong to this album");
albums.remove(album);
album.removeParent();
}
* <code>null</code> if the album did not change its place
*/
public Album moveAlbumUp(Album album) {
- Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.sone, sone).isEqual("Album Parent", album.parent, this).check();
+ checkNotNull(album, "album must not be null");
+ checkArgument(album.sone.equals(sone), "album must belong to the same Sone as this album");
+ checkArgument(equals(album.parent), "album must belong to this album");
int oldIndex = albums.indexOf(album);
if (oldIndex <= 0) {
return null;
* <code>null</code> if the album did not change its place
*/
public Album moveAlbumDown(Album album) {
- Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.sone, sone).isEqual("Album Parent", album.parent, this).check();
+ checkNotNull(album, "album must not be null");
+ checkArgument(album.sone.equals(sone), "album must belong to the same Sone as this album");
+ checkArgument(equals(album.parent), "album must belong to this album");
int oldIndex = albums.indexOf(album);
if ((oldIndex < 0) || (oldIndex >= (albums.size() - 1))) {
return null;
* @return The images in this album
*/
public List<Image> getImages() {
- return IterableWrapper.wrap(imageIds).map(new Mapper<String, Image>() {
+ return new ArrayList<Image>(Collections2.filter(Collections2.transform(imageIds, new Function<String, Image>() {
@Override
@SuppressWarnings("synthetic-access")
- public Image map(String imageId) {
+ public Image apply(String imageId) {
return images.get(imageId);
}
-
- }).filter(new NotNullFilter()).list();
+ }), Predicates.notNull()));
}
/**
* The image to add
*/
public void addImage(Image image) {
- Validation.begin().isNotNull("Image", image).check().isNotNull("Image Owner", image.getSone()).check().isEqual("Image Owner", image.getSone(), sone).check();
+ checkNotNull(image, "image must not be null");
+ checkNotNull(image.getSone(), "image must have an owner");
+ checkArgument(image.getSone().equals(sone), "image must belong to the same Sone as this album");
if (image.getAlbum() != null) {
image.getAlbum().removeImage(image);
}
* The image to remove
*/
public void removeImage(Image image) {
- Validation.begin().isNotNull("Image", image).check().isEqual("Image Owner", image.getSone(), sone).check();
+ checkNotNull(image, "image must not be null");
+ checkNotNull(image.getSone(), "image must have an owner");
+ checkArgument(image.getSone().equals(sone), "image must belong to the same Sone as this album");
imageIds.remove(image.getId());
images.remove(image.getId());
if (image.getId().equals(albumImage)) {
* <code>null</code> if the image did not change its place
*/
public Image moveImageUp(Image image) {
- Validation.begin().isNotNull("Image", image).check().isEqual("Image Album", image.getAlbum(), this).isEqual("Album Owner", image.getAlbum().getSone(), sone).check();
+ checkNotNull(image, "image must not be null");
+ checkNotNull(image.getSone(), "image must have an owner");
+ checkArgument(image.getSone().equals(sone), "image must belong to the same Sone as this album");
+ checkArgument(image.getAlbum().equals(this), "image must belong to this album");
int oldIndex = imageIds.indexOf(image.getId());
if (oldIndex <= 0) {
return null;
* <code>null</code> if the image did not change its place
*/
public Image moveImageDown(Image image) {
- Validation.begin().isNotNull("Image", image).check().isEqual("Image Album", image.getAlbum(), this).isEqual("Album Owner", image.getAlbum().getSone(), sone).check();
+ checkNotNull(image, "image must not be null");
+ checkNotNull(image.getSone(), "image must have an owner");
+ checkArgument(image.getSone().equals(sone), "image must belong to the same Sone as this album");
+ checkArgument(image.getAlbum().equals(this), "image must belong to this album");
int oldIndex = imageIds.indexOf(image.getId());
if ((oldIndex == -1) || (oldIndex >= (imageIds.size() - 1))) {
return null;
if (albumImage == null) {
return null;
}
- return Default.forNull(images.get(albumImage), images.values().iterator().next());
+ return Optional.fromNullable(images.get(albumImage)).or(images.values().iterator().next());
}
/**
* @return This album
*/
protected Album setParent(Album parent) {
- Validation.begin().isNotNull("Album Parent", parent).check();
- this.parent = parent;
+ this.parent = checkNotNull(parent, "parent must not be null");
return this;
}
* @return This album
*/
public Album setTitle(String title) {
- Validation.begin().isNotNull("Album Title", title).check();
- this.title = title;
+ this.title = checkNotNull(title, "title must not be null");
return this;
}
* @return This album
*/
public Album setDescription(String description) {
- Validation.begin().isNotNull("Album Description", description).check();
- this.description = description;
+ this.description = checkNotNull(description, "description must not be null");
return this;
}
*/
@Override
public String getFingerprint() {
- StringBuilder fingerprint = new StringBuilder();
- fingerprint.append("Album(");
- fingerprint.append("ID(").append(id).append(')');
- fingerprint.append("Title(").append(title).append(')');
- fingerprint.append("Description(").append(description).append(')');
+ Hasher hash = Hashing.sha256().newHasher();
+ hash.putString("Album(");
+ hash.putString("ID(").putString(id).putString(")");
+ hash.putString("Title(").putString(title).putString(")");
+ hash.putString("Description(").putString(description).putString(")");
if (albumImage != null) {
- fingerprint.append("AlbumImage(").append(albumImage).append(')');
+ hash.putString("AlbumImage(").putString(albumImage).putString(")");
}
/* add nested albums. */
- fingerprint.append("Albums(");
+ hash.putString("Albums(");
for (Album album : albums) {
- fingerprint.append(album.getFingerprint());
+ hash.putString(album.getFingerprint());
}
- fingerprint.append(')');
+ hash.putString(")");
/* add images. */
- fingerprint.append("Images(");
+ hash.putString("Images(");
for (Image image : getImages()) {
if (image.isInserted()) {
- fingerprint.append(image.getFingerprint());
+ hash.putString(image.getFingerprint());
}
}
- fingerprint.append(')');
+ hash.putString(")");
- fingerprint.append(')');
- return fingerprint.toString();
+ hash.putString(")");
+ return hash.hash().toString();
}
//
/*
- * Sone - Client.java - Copyright © 2010–2012 David Roden
+ * Sone - Client.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
/*
- * Sone - Fingerprintable.java - Copyright © 2011–2012 David Roden
+ * Sone - Fingerprintable.java - Copyright © 2011–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
/*
- * Sone - Image.java - Copyright © 2011–2012 David Roden
+ * Sone - Image.java - Copyright © 2011–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
package net.pterodactylus.sone.data;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
import java.util.UUID;
-import net.pterodactylus.util.validation.Validation;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
/**
* Container for image metadata.
* The ID of the image
*/
public Image(String id) {
- Validation.begin().isNotNull("Image ID", id).check();
- this.id = id;
+ this.id = checkNotNull(id, "id must not be null");
}
//
* @return This image
*/
public Image setSone(Sone sone) {
- Validation.begin().isNotNull("New Image Owner", sone).isEither("Old Image Owner", this.sone, null, sone).check();
+ checkNotNull(sone, "sone must not be null");
+ checkArgument((this.sone == null) || this.sone.equals(sone), "sone must not already be set to another sone");
this.sone = sone;
return this;
}
* @return This image
*/
public Image setAlbum(Album album) {
- Validation.begin().isNotNull("New Album", album).check().isEqual("Album Owner and Image Owner", album.getSone(), getSone()).check();
+ checkNotNull(album, "album must not be null");
+ checkNotNull(album.getSone().equals(getSone()), "album must belong to the same Sone as this image");
this.album = album;
return this;
}
* @return This image
*/
public Image setKey(String key) {
- Validation.begin().isNotNull("New Image Key", key).isEither("Old Image Key", this.key, null, key).check();
+ checkNotNull(key, "key must not be null");
+ checkState((this.key == null) || this.key.equals(key), "key must not be already set to another key");
this.key = key;
return this;
}
* @return This image
*/
public Image setCreationTime(long creationTime) {
- Validation.begin().isGreater("New Image Creation Time", creationTime, 0).isEither("Old Image Creation Time", this.creationTime, 0L, creationTime).check();
+ checkArgument(creationTime > 0, "creationTime must be > 0");
+ checkState((this.creationTime == 0) || (this.creationTime == creationTime), "creationTime must not already be set");
this.creationTime = creationTime;
return this;
}
* @return This image
*/
public Image setWidth(int width) {
- Validation.begin().isGreater("New Image Width", width, 0).isEither("Old Image Width", this.width, 0, width).check();
+ checkArgument(width > 0, "width must be > 0");
+ checkState((this.width == 0) || (this.width == width), "width must not already be set to another width");
this.width = width;
return this;
}
* @return This image
*/
public Image setHeight(int height) {
- Validation.begin().isGreater("New Image Height", height, 0).isEither("Old Image Height", this.height, 0, height).check();
+ checkArgument(height > 0, "height must be > 0");
+ checkState((this.height == 0) || (this.height == height), "height must not already be set to another height");
this.height = height;
return this;
}
* @return This image
*/
public Image setTitle(String title) {
- Validation.begin().isNotNull("Image Title", title).check();
- this.title = title;
+ this.title = checkNotNull(title, "title must not be null");
return this;
}
* @return This image
*/
public Image setDescription(String description) {
- Validation.begin().isNotNull("Image Description", description).check();
- this.description = description;
+ this.description = checkNotNull(description, "description must not be null");
return this;
}
*/
@Override
public String getFingerprint() {
- StringBuilder fingerprint = new StringBuilder();
- fingerprint.append("Image(");
- fingerprint.append("ID(").append(id).append(')');
- fingerprint.append("Title(").append(title).append(')');
- fingerprint.append("Description(").append(description).append(')');
- fingerprint.append(')');
- return fingerprint.toString();
+ Hasher hash = Hashing.sha256().newHasher();
+ hash.putString("Image(");
+ hash.putString("ID(").putString(id).putString(")");
+ hash.putString("Title(").putString(title).putString(")");
+ hash.putString("Description(").putString(description).putString(")");
+ hash.putString(")");
+ return hash.hash().toString();
}
//
/*
- * Sone - Post.java - Copyright © 2010–2012 David Roden
+ * Sone - Post.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
import java.util.Comparator;
-import net.pterodactylus.util.collection.filter.Filter;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
/**
* A post is a short message that a user writes in his Sone to let other users
};
/** Filter for posts with timestamps from the future. */
- public static final Filter<Post> FUTURE_POSTS_FILTER = new Filter<Post>() {
+ public static final Predicate<Post> FUTURE_POSTS_FILTER = new Predicate<Post>() {
@Override
- public boolean filterObject(Post post) {
+ public boolean apply(Post post) {
return post.getTime() <= System.currentTimeMillis();
}
public Sone getSone();
/**
- * Sets the Sone of this post.
+ * Returns the ID of the recipient {@link Sone}, or
+ * {@link Optional#absent()} if this post does not have a recipient.
*
- * @param sone
- * The Sone of this post
- * @return This post (for method chaining)
+ * @return The ID of the recipient, or {@link Optional#absent()}
*/
- public Post setSone(Sone sone);
+ public Optional<String> getRecipientId();
/**
- * Returns the recipient of this post, if any.
+ * Returns the recipient of this post, if any. As this method can return
+ * {@link Optional#absent()} if the post has a recipient which has not yet
+ * been loaded, it is recommended to use {@link #hasRecipient()} to check
+ * for the presence of a recipient.
*
- * @return The recipient of this post, or {@code null}
+ * @return The recipient of this post, or {@link Optional#absent()} if there
+ * is no recipient
*/
- public Sone getRecipient();
-
- /**
- * Sets the recipient of this post.
- *
- * @param recipient
- * The recipient of this post, or {@code null}
- * @return This post (for method chaining)
- */
- public Post setRecipient(Sone recipient);
+ public Optional<Sone> getRecipient();
/**
* Returns the time of the post.
public long getTime();
/**
- * Sets the time of this post.
- *
- * @param time
- * The time of this post (in milliseconds since Jan 1, 1970 UTC)
- * @return This post (for method chaining)
- */
- public Post setTime(long time);
-
- /**
* Returns the text of the post.
*
* @return The text of the post
public String getText();
/**
- * Sets the text of this post.
- *
- * @param text
- * The text of this post
- * @return This post (for method chaining)
- */
- public Post setText(String text);
-
- /**
* Returns whether this post is known.
*
* @return {@code true} if this post is known, {@code false} otherwise
/*
- * Sone - PostReply.java - Copyright © 2010–2012 David Roden
+ * Sone - PostReply.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
package net.pterodactylus.sone.data;
-import java.util.UUID;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
/**
* A reply is like a {@link Post} but can never be posted on its own, it always
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
-public class PostReply extends Reply<PostReply> {
-
- /** The Post this reply refers to. */
- private volatile Post post;
+public interface PostReply extends Reply<PostReply> {
/**
- * Creates a new reply.
- *
- * @param id
- * The ID of the reply
+ * Filter that selects {@link PostReply}s that have a
+ * {@link Optional#isPresent() present} {@link #getPost() post}.
*/
- public PostReply(String id) {
- this(id, null, null, 0, null);
- }
+ public static final Predicate<PostReply> HAS_POST_FILTER = new Predicate<PostReply>() {
- /**
- * Creates a new reply.
- *
- * @param sone
- * The sone that posted the reply
- * @param post
- * The post to reply to
- * @param text
- * The text of the reply
- */
- public PostReply(Sone sone, Post post, String text) {
- this(sone, post, System.currentTimeMillis(), text);
- }
-
- /**
- * Creates a new reply-
- *
- * @param sone
- * The sone that posted the reply
- * @param post
- * The post to reply to
- * @param time
- * The time of the reply
- * @param text
- * The text of the reply
- */
- public PostReply(Sone sone, Post post, long time, String text) {
- this(UUID.randomUUID().toString(), sone, post, time, text);
- }
+ @Override
+ public boolean apply(PostReply postReply) {
+ return postReply.getPost().isPresent();
+ }
+ };
/**
- * Creates a new reply-
+ * Returns the ID of the post this reply refers to.
*
- * @param sone
- * The sone that posted the reply
- * @param id
- * The ID of the reply
- * @param post
- * The post to reply to
- * @param time
- * The time of the reply
- * @param text
- * The text of the reply
+ * @return The ID of the post this reply refers to
*/
- public PostReply(String id, Sone sone, Post post, long time, String text) {
- super(id, sone, time, text);
- this.post = post;
- }
-
- //
- // ACCESSORS
- //
+ public String getPostId();
/**
* Returns the post this reply refers to.
*
* @return The post this reply refers to
*/
- public Post getPost() {
- return post;
- }
-
- /**
- * Sets the post this reply refers to.
- *
- * @param post
- * The post this reply refers to
- * @return This reply (for method chaining)
- */
- public PostReply setPost(Post post) {
- this.post = post;
- return this;
- }
+ public Optional<Post> getPost();
}
/*
- * Sone - Profile.java - Copyright © 2010–2012 David Roden
+ * Sone - Profile.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
package net.pterodactylus.sone.data;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
-import net.pterodactylus.util.validation.Validation;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
/**
* A profile stores personal information about a {@link Sone}. All information
this.avatar = null;
return this;
}
- Validation.begin().isEqual("Image Owner", avatar.getSone(), sone).check();
+ checkArgument(avatar.getSone().equals(sone), "avatar must belong to Sone");
this.avatar = avatar.getId();
return this;
}
* field with the given ID
*/
public Field getFieldById(String fieldId) {
- Validation.begin().isNotNull("Field ID", fieldId).check();
+ checkNotNull(fieldId, "fieldId must not be null");
for (Field field : fields) {
if (field.getId().equals(fieldId)) {
return field;
* if the name is not valid
*/
public Field addField(String fieldName) throws IllegalArgumentException {
- Validation.begin().isNotNull("Field Name", fieldName).check().isGreater("Field Name Length", fieldName.length(), 0).isNull("Field Name Unique", getFieldByName(fieldName)).check();
+ checkNotNull(fieldName, "fieldName must not be null");
+ checkArgument(fieldName.length() > 0, "fieldName must not be empty");
+ checkState(getFieldByName(fieldName) == null, "fieldName must be unique");
@SuppressWarnings("synthetic-access")
Field field = new Field().setName(fieldName);
fields.add(field);
* The field to move up
*/
public void moveFieldUp(Field field) {
- Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).isGreater("Field Index", getFieldIndex(field), 0).check();
+ checkNotNull(field, "field must not be null");
+ checkArgument(hasField(field), "field must belong to this profile");
+ checkArgument(getFieldIndex(field) > 0, "field index must be > 0");
int fieldIndex = getFieldIndex(field);
fields.remove(field);
fields.add(fieldIndex - 1, field);
* The field to move down
*/
public void moveFieldDown(Field field) {
- Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).isLess("Field Index", getFieldIndex(field), fields.size() - 1).check();
+ checkNotNull(field, "field must not be null");
+ checkArgument(hasField(field), "field must belong to this profile");
+ checkArgument(getFieldIndex(field) < fields.size() - 1, "field index must be < " + (fields.size() - 1));
int fieldIndex = getFieldIndex(field);
fields.remove(field);
fields.add(fieldIndex + 1, field);
* The field to remove
*/
public void removeField(Field field) {
- Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).check();
+ checkNotNull(field, "field must not be null");
+ checkArgument(hasField(field), "field must belong to this profile");
fields.remove(field);
}
*/
@Override
public String getFingerprint() {
- StringBuilder fingerprint = new StringBuilder();
- fingerprint.append("Profile(");
+ Hasher hash = Hashing.sha256().newHasher();
+ hash.putString("Profile(");
if (firstName != null) {
- fingerprint.append("FirstName(").append(firstName).append(')');
+ hash.putString("FirstName(").putString(firstName).putString(")");
}
if (middleName != null) {
- fingerprint.append("MiddleName(").append(middleName).append(')');
+ hash.putString("MiddleName(").putString(middleName).putString(")");
}
if (lastName != null) {
- fingerprint.append("LastName(").append(lastName).append(')');
+ hash.putString("LastName(").putString(lastName).putString(")");
}
if (birthDay != null) {
- fingerprint.append("BirthDay(").append(birthDay).append(')');
+ hash.putString("BirthDay(").putInt(birthDay).putString(")");
}
if (birthMonth != null) {
- fingerprint.append("BirthMonth(").append(birthMonth).append(')');
+ hash.putString("BirthMonth(").putInt(birthMonth).putString(")");
}
if (birthYear != null) {
- fingerprint.append("BirthYear(").append(birthYear).append(')');
+ hash.putString("BirthYear(").putInt(birthYear).putString(")");
}
if (avatar != null) {
- fingerprint.append("Avatar(").append(avatar).append(')');
+ hash.putString("Avatar(").putString(avatar).putString(")");
}
- fingerprint.append("ContactInformation(");
+ hash.putString("ContactInformation(");
for (Field field : fields) {
- fingerprint.append(field.getName()).append('(').append(field.getValue()).append(')');
+ hash.putString(field.getName()).putString("(").putString(field.getValue()).putString(")");
}
- fingerprint.append(")");
- fingerprint.append(")");
+ hash.putString(")");
+ hash.putString(")");
- return fingerprint.toString();
+ return hash.hash().toString();
}
/**
* The ID of the field
*/
private Field(String id) {
- Validation.begin().isNotNull("Field ID", id).check();
- this.id = id;
+ this.id = checkNotNull(id, "id must not be null");
}
/**
* @return This field
*/
public Field setName(String name) {
- Validation.begin().isNotNull("Field Name", name).check().is("Field Unique", (getFieldByName(name) == null) || equals(getFieldByName(name))).check();
+ checkNotNull(name, "name must not be null");
+ checkArgument(getFieldByName(name) == null, "name must be unique");
this.name = name;
return this;
}
/*
- * Sone - Reply.java - Copyright © 2011–2012 David Roden
+ * Sone - Reply.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
package net.pterodactylus.sone.data;
import java.util.Comparator;
-import java.util.UUID;
-import net.pterodactylus.util.collection.filter.Filter;
+import com.google.common.base.Predicate;
/**
- * Abstract base class for all replies.
+ * Defines methods common for all replies.
*
* @param <T>
* The type of the reply
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
-public abstract class Reply<T extends Reply<T>> {
+public interface Reply<T extends Reply<T>> {
/** Comparator that sorts replies ascending by time. */
- public static final Comparator<Reply<?>> TIME_COMPARATOR = new Comparator<Reply<?>>() {
+ public static final Comparator<? super Reply<?>> TIME_COMPARATOR = new Comparator<Reply<?>>() {
/**
* {@inheritDoc}
};
/** Filter for replies with timestamps from the future. */
- public static final Filter<Reply<?>> FUTURE_REPLY_FILTER = new Filter<Reply<?>>() {
+ public static final Predicate<Reply<?>> FUTURE_REPLY_FILTER = new Predicate<Reply<?>>() {
/**
* {@inheritDoc}
*/
@Override
- public boolean filterObject(Reply<?> reply) {
+ public boolean apply(Reply<?> reply) {
return reply.getTime() <= System.currentTimeMillis();
}
};
- /** The ID of the reply. */
- private final String id;
-
- /** The Sone that created this reply. */
- private volatile Sone sone;
-
- /** The time of the reply. */
- private volatile long time;
-
- /** The text of the reply. */
- private volatile String text;
-
- /** Whether the reply is known. */
- private volatile boolean known;
-
- /**
- * Creates a new reply with the given ID.
- *
- * @param id
- * The ID of the reply
- */
- protected Reply(String id) {
- this(id, null, 0, null);
- }
-
- /**
- * Creates a new reply with a new random ID.
- *
- * @param sone
- * The Sone of the reply
- * @param time
- * The time of the reply
- * @param text
- * The text of the reply
- */
- protected Reply(Sone sone, long time, String text) {
- this(UUID.randomUUID().toString(), sone, time, text);
- }
-
- /**
- * Creates a new reply.
- *
- * @param id
- * The ID of the reply
- * @param sone
- * The Sone of the reply
- * @param time
- * The time of the reply
- * @param text
- * The text of the reply
- */
- protected Reply(String id, Sone sone, long time, String text) {
- this.id = id;
- this.sone = sone;
- this.time = time;
- this.text = text;
- }
-
/**
* Returns the ID of the reply.
*
* @return The ID of the reply
*/
- public String getId() {
- return id;
- }
+ public String getId();
/**
* Returns the Sone that posted this reply.
*
* @return The Sone that posted this reply
*/
- public Sone getSone() {
- return sone;
- }
-
- /**
- * Sets the Sone that posted this reply.
- *
- * @param sone
- * The Sone that posted this reply
- * @return This reply (for method chaining)
- */
- @SuppressWarnings("unchecked")
- public T setSone(Sone sone) {
- this.sone = sone;
- return (T) this;
- }
+ public Sone getSone();
/**
* Returns the time of the reply.
*
* @return The time of the reply (in milliseconds since Jan 1, 1970 UTC)
*/
- public long getTime() {
- return time;
- }
-
- /**
- * Sets the time of this reply.
- *
- * @param time
- * The time of this reply (in milliseconds since Jan 1, 1970 UTC)
- * @return This reply (for method chaining)
- */
- @SuppressWarnings("unchecked")
- public T setTime(long time) {
- this.time = time;
- return (T) this;
- }
+ public long getTime();
/**
* Returns the text of the reply.
*
* @return The text of the reply
*/
- public String getText() {
- return text;
- }
-
- /**
- * Sets the text of this reply.
- *
- * @param text
- * The text of this reply
- * @return This reply (for method chaining)
- */
- @SuppressWarnings("unchecked")
- public T setText(String text) {
- this.text = text;
- return (T) this;
- }
+ public String getText();
/**
* Returns whether this reply is known.
*
* @return {@code true} if this reply is known, {@code false} otherwise
*/
- public boolean isKnown() {
- return known;
- }
+ public boolean isKnown();
/**
* Sets whether this reply is known.
* {@code true} if this reply is known, {@code false} otherwise
* @return This reply
*/
- @SuppressWarnings("unchecked")
- public T setKnown(boolean known) {
- this.known = known;
- return (T) this;
- }
-
- //
- // OBJECT METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return id.hashCode();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof Reply<?>)) {
- return false;
- }
- Reply<?> reply = (Reply<?>) object;
- return reply.id.equals(id);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return getClass().getName() + "[id=" + id + ",sone=" + sone + ",time=" + time + ",text=" + text + "]";
- }
+ public T setKnown(boolean known);
}
/*
- * Sone - Sone.java - Copyright © 2010–2012 David Roden
+ * Sone - Sone.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
package net.pterodactylus.sone.data;
+import static com.google.common.base.Preconditions.*;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
-import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.core.Options;
import net.pterodactylus.sone.freenet.wot.Identity;
import net.pterodactylus.sone.freenet.wot.OwnIdentity;
import net.pterodactylus.sone.template.SoneAccessor;
-import net.pterodactylus.util.collection.filter.Filter;
import net.pterodactylus.util.logging.Logging;
-import net.pterodactylus.util.validation.Validation;
+
import freenet.keys.FreenetURI;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+
/**
* A Sone defines everything about a user: her profile, her status updates, her
* replies, her likes and dislikes, etc.
- * <p>
+ * <p/>
* Operations that modify the Sone need to synchronize on the Sone in question.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
};
- /**
- * Comparator that sorts Sones by last activity (least recent active first).
- */
+ /** Comparator that sorts Sones by last activity (least recent active first). */
public static final Comparator<Sone> LAST_ACTIVITY_COMPARATOR = new Comparator<Sone>() {
@Override
};
/** Filter to remove Sones that have not been downloaded. */
- public static final Filter<Sone> EMPTY_SONE_FILTER = new Filter<Sone>() {
+ public static final Predicate<Sone> EMPTY_SONE_FILTER = new Predicate<Sone>() {
@Override
- public boolean filterObject(Sone sone) {
+ public boolean apply(Sone sone) {
return sone.getTime() != 0;
}
};
- /** Filter that matches all {@link Core#isLocalSone(Sone) local Sones}. */
- public static final Filter<Sone> LOCAL_SONE_FILTER = new Filter<Sone>() {
+ /** Filter that matches all {@link Sone#isLocal() local Sones}. */
+ public static final Predicate<Sone> LOCAL_SONE_FILTER = new Predicate<Sone>() {
@Override
- public boolean filterObject(Sone sone) {
+ public boolean apply(Sone sone) {
return sone.getIdentity() instanceof OwnIdentity;
}
};
/** Filter that matches Sones that have at least one album. */
- public static final Filter<Sone> HAS_ALBUM_FILTER = new Filter<Sone>() {
+ public static final Predicate<Sone> HAS_ALBUM_FILTER = new Predicate<Sone>() {
@Override
- public boolean filterObject(Sone sone) {
+ public boolean apply(Sone sone) {
return !sone.getAlbums().isEmpty();
}
};
/** The ID of this Sone. */
private final String id;
+ /** Whether the Sone is local. */
+ private final boolean local;
+
/** The identity of this Sone. */
private Identity identity;
private final List<Album> albums = new CopyOnWriteArrayList<Album>();
/** Sone-specific options. */
- private final Options options = new Options();
+ private Options options = new Options();
/**
* Creates a new Sone.
*
* @param id
- * The ID of the Sone
+ * The ID of the Sone
+ * @param local
+ * {@code true} if the Sone is a local Sone, {@code false} otherwise
*/
- public Sone(String id) {
+ public Sone(String id, boolean local) {
this.id = id;
+ this.local = local;
}
//
* identity has to match this Sone’s {@link #getId()}.
*
* @param identity
- * The identity of this Sone
+ * The identity of this Sone
* @return This Sone (for method chaining)
* @throws IllegalArgumentException
- * if the ID of the identity does not match this Sone’s ID
+ * if the ID of the identity does not match this Sone’s ID
*/
public Sone setIdentity(Identity identity) throws IllegalArgumentException {
if (!identity.getId().equals(id)) {
}
/**
+ * Returns whether this Sone is a local Sone.
+ *
+ * @return {@code true} if this Sone is a local Sone, {@code false} otherwise
+ */
+ public boolean isLocal() {
+ return local;
+ }
+
+ /**
* Returns the request URI of this Sone.
*
* @return The request URI of this Sone
* Sets the request URI of this Sone.
*
* @param requestUri
- * The request URI of this Sone
+ * The request URI of this Sone
* @return This Sone (for method chaining)
*/
public Sone setRequestUri(FreenetURI requestUri) {
* Sets the insert URI of this Sone.
*
* @param insertUri
- * The insert URI of this Sone
+ * The insert URI of this Sone
* @return This Sone (for method chaining)
*/
public Sone setInsertUri(FreenetURI insertUri) {
/**
* Sets the latest edition of this Sone. If the given latest edition is not
- * greater than the current latest edition, the latest edition of this Sone
- * is not changed.
+ * greater than the current latest edition, the latest edition of this Sone is
+ * not changed.
*
* @param latestEdition
- * The latest edition of this Sone
+ * The latest edition of this Sone
*/
public void setLatestEdition(long latestEdition) {
if (!(latestEdition > this.latestEdition)) {
* Sets the time of the last inserted update of this Sone.
*
* @param time
- * The time of the update (in milliseconds since Jan 1, 1970 UTC)
+ * The time of the update (in milliseconds since Jan 1, 1970 UTC)
* @return This Sone (for method chaining)
*/
public Sone setTime(long time) {
* Sets the new status of this Sone.
*
* @param status
- * The new status of this Sone
+ * The new status of this Sone
* @return This Sone
* @throws IllegalArgumentException
- * if {@code status} is {@code null}
+ * if {@code status} is {@code null}
*/
public Sone setStatus(SoneStatus status) {
- Validation.begin().isNotNull("Sone Status", status).check();
- this.status = status;
+ this.status = checkNotNull(status, "status must not be null");
return this;
}
/**
- * Returns a copy of the profile. If you want to update values in the
- * profile of this Sone, update the values in the returned {@link Profile}
- * and use {@link #setProfile(Profile)} to change the profile in this Sone.
+ * Returns a copy of the profile. If you want to update values in the profile
+ * of this Sone, update the values in the returned {@link Profile} and use
+ * {@link #setProfile(Profile)} to change the profile in this Sone.
*
* @return A copy of the profile
*/
}
/**
- * Sets the profile of this Sone. A copy of the given profile is stored so
- * that subsequent modifications of the given profile are not reflected in
- * this Sone!
+ * Sets the profile of this Sone. A copy of the given profile is stored so that
+ * subsequent modifications of the given profile are not reflected in this
+ * Sone!
*
* @param profile
- * The profile to set
+ * The profile to set
*/
public void setProfile(Profile profile) {
this.profile = new Profile(profile);
* Sets the client used by this Sone.
*
* @param client
- * The client used by this Sone, or {@code null}
+ * The client used by this Sone, or {@code null}
* @return This Sone (for method chaining)
*/
public Sone setClient(Client client) {
* Sets whether this Sone is known.
*
* @param known
- * {@code true} if this Sone is known, {@code false} otherwise
+ * {@code true} if this Sone is known, {@code false} otherwise
* @return This Sone
*/
public Sone setKnown(boolean known) {
* Returns whether this Sone has the given Sone as a friend Sone.
*
* @param friendSoneId
- * The ID of the Sone to check for
- * @return {@code true} if this Sone has the given Sone as a friend,
- * {@code false} otherwise
+ * The ID of the Sone to check for
+ * @return {@code true} if this Sone has the given Sone as a friend, {@code
+ * false} otherwise
*/
public boolean hasFriend(String friendSoneId) {
return friendSones.contains(friendSoneId);
* Adds the given Sone as a friend Sone.
*
* @param friendSone
- * The friend Sone to add
+ * The friend Sone to add
* @return This Sone (for method chaining)
*/
public Sone addFriend(String friendSone) {
* Removes the given Sone as a friend Sone.
*
* @param friendSoneId
- * The ID of the friend Sone to remove
+ * The ID of the friend Sone to remove
* @return This Sone (for method chaining)
*/
public Sone removeFriend(String friendSoneId) {
* Sets all posts of this Sone at once.
*
* @param posts
- * The new (and only) posts of this Sone
+ * The new (and only) posts of this Sone
* @return This Sone (for method chaining)
*/
public Sone setPosts(Collection<Post> posts) {
}
/**
- * Adds the given post to this Sone. The post will not be added if its
- * {@link Post#getSone() Sone} is not this Sone.
+ * Adds the given post to this Sone. The post will not be added if its {@link
+ * Post#getSone() Sone} is not this Sone.
*
* @param post
- * The post to add
+ * The post to add
*/
public void addPost(Post post) {
if (post.getSone().equals(this) && posts.add(post)) {
* Removes the given post from this Sone.
*
* @param post
- * The post to remove
+ * The post to remove
*/
public void removePost(Post post) {
if (post.getSone().equals(this)) {
* Sets all replies of this Sone at once.
*
* @param replies
- * The new (and only) replies of this Sone
+ * The new (and only) replies of this Sone
* @return This Sone (for method chaining)
*/
public Sone setReplies(Collection<PostReply> replies) {
* nothing is added to this Sone.
*
* @param reply
- * The reply to add
+ * The reply to add
*/
public void addReply(PostReply reply) {
if (reply.getSone().equals(this)) {
* Removes a reply from this Sone.
*
* @param reply
- * The reply to remove
+ * The reply to remove
*/
public void removeReply(PostReply reply) {
if (reply.getSone().equals(this)) {
* Sets the IDs of all liked posts.
*
* @param likedPostIds
- * All liked posts’ IDs
+ * All liked posts’ IDs
* @return This Sone (for method chaining)
*/
public Sone setLikePostIds(Set<String> likedPostIds) {
* Checks whether the given post ID is liked by this Sone.
*
* @param postId
- * The ID of the post
+ * The ID of the post
* @return {@code true} if this Sone likes the given post, {@code false}
* otherwise
*/
* Adds the given post ID to the list of posts this Sone likes.
*
* @param postId
- * The ID of the post
+ * The ID of the post
* @return This Sone (for method chaining)
*/
public Sone addLikedPostId(String postId) {
* Removes the given post ID from the list of posts this Sone likes.
*
* @param postId
- * The ID of the post
+ * The ID of the post
* @return This Sone (for method chaining)
*/
public Sone removeLikedPostId(String postId) {
* Sets the IDs of all liked replies.
*
* @param likedReplyIds
- * All liked replies’ IDs
+ * All liked replies’ IDs
* @return This Sone (for method chaining)
*/
public Sone setLikeReplyIds(Set<String> likedReplyIds) {
* Checks whether the given reply ID is liked by this Sone.
*
* @param replyId
- * The ID of the reply
+ * The ID of the reply
* @return {@code true} if this Sone likes the given reply, {@code false}
* otherwise
*/
* Adds the given reply ID to the list of replies this Sone likes.
*
* @param replyId
- * The ID of the reply
+ * The ID of the reply
* @return This Sone (for method chaining)
*/
public Sone addLikedReplyId(String replyId) {
* Removes the given post ID from the list of replies this Sone likes.
*
* @param replyId
- * The ID of the reply
+ * The ID of the reply
* @return This Sone (for method chaining)
*/
public Sone removeLikedReplyId(String replyId) {
}
/**
- * Returns a flattened list of all albums of this Sone. The resulting list
- * contains parent albums before child albums so that the resulting list can
- * be parsed in a single pass.
- *
- * @return The flattened albums
- */
- public List<Album> getAllAlbums() {
- List<Album> flatAlbums = new ArrayList<Album>();
- flatAlbums.addAll(albums);
- int lastAlbumIndex = 0;
- while (lastAlbumIndex < flatAlbums.size()) {
- int previousAlbumCount = flatAlbums.size();
- for (Album album : new ArrayList<Album>(flatAlbums.subList(lastAlbumIndex, flatAlbums.size()))) {
- flatAlbums.addAll(album.getAlbums());
- }
- lastAlbumIndex = previousAlbumCount;
- }
- return flatAlbums;
- }
-
- /**
- * Returns all images of a Sone. Images of a album are inserted into this
- * list before images of all child albums.
+ * Returns all images of a Sone. Images of a album are inserted into this list
+ * before images of all child albums.
*
* @return The list of all images
*/
public List<Image> getAllImages() {
List<Image> allImages = new ArrayList<Image>();
- for (Album album : getAllAlbums()) {
+ for (Album album : FluentIterable.from(getAlbums()).transformAndConcat(Album.FLATTENER).toList()) {
allImages.addAll(album.getImages());
}
return allImages;
* Adds an album to this Sone.
*
* @param album
- * The album to add
+ * The album to add
*/
public void addAlbum(Album album) {
- Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
+ checkNotNull(album, "album must not be null");
+ checkArgument(album.getSone().equals(this), "album must belong to this Sone");
if (!albums.contains(album)) {
albums.add(album);
}
* Sets the albums of this Sone.
*
* @param albums
- * The albums of this Sone
+ * The albums of this Sone
*/
public void setAlbums(Collection<? extends Album> albums) {
- Validation.begin().isNotNull("Albums", albums).check();
+ checkNotNull(albums, "albums must not be null");
this.albums.clear();
for (Album album : albums) {
addAlbum(album);
* Removes an album from this Sone.
*
* @param album
- * The album to remove
+ * The album to remove
*/
public void removeAlbum(Album album) {
- Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
+ checkNotNull(album, "album must not be null");
+ checkArgument(album.getSone().equals(this), "album must belong to this Sone");
albums.remove(album);
}
/**
- * Moves the given album up in this album’s albums. If the album is already
- * the first album, nothing happens.
+ * Moves the given album up in this album’s albums. If the album is already the
+ * first album, nothing happens.
*
* @param album
- * The album to move up
+ * The album to move up
* @return The album that the given album swapped the place with, or
* <code>null</code> if the album did not change its place
*/
public Album moveAlbumUp(Album album) {
- Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).isNull("Album Parent", album.getParent()).check();
+ checkNotNull(album, "album must not be null");
+ checkArgument(album.getSone().equals(this), "album must belong to this Sone");
+ checkArgument(album.getParent() == null, "album must not have a parent");
int oldIndex = albums.indexOf(album);
if (oldIndex <= 0) {
return null;
}
/**
- * Moves the given album down in this album’s albums. If the album is
- * already the last album, nothing happens.
+ * Moves the given album down in this album’s albums. If the album is already
+ * the last album, nothing happens.
*
* @param album
- * The album to move down
+ * The album to move down
* @return The album that the given album swapped the place with, or
* <code>null</code> if the album did not change its place
*/
public Album moveAlbumDown(Album album) {
- Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).isNull("Album Parent", album.getParent()).check();
+ checkNotNull(album, "album must not be null");
+ checkArgument(album.getSone().equals(this), "album must belong to this Sone");
+ checkArgument(album.getParent() == null, "album must not have a parent");
int oldIndex = albums.indexOf(album);
if ((oldIndex < 0) || (oldIndex >= (albums.size() - 1))) {
return null;
return options;
}
+ /**
+ * Sets the options of this Sone.
+ *
+ * @param options
+ * The options of this Sone
+ */
+ /* TODO - remove this method again, maybe add an option provider */
+ public void setOptions(Options options) {
+ this.options = options;
+ }
+
//
// FINGERPRINTABLE METHODS
//
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public synchronized String getFingerprint() {
- StringBuilder fingerprint = new StringBuilder();
- fingerprint.append(profile.getFingerprint());
+ Hasher hash = Hashing.sha256().newHasher();
+ hash.putString(profile.getFingerprint());
- fingerprint.append("Posts(");
+ hash.putString("Posts(");
for (Post post : getPosts()) {
- fingerprint.append("Post(").append(post.getId()).append(')');
+ hash.putString("Post(").putString(post.getId()).putString(")");
}
- fingerprint.append(")");
+ hash.putString(")");
List<PostReply> replies = new ArrayList<PostReply>(getReplies());
Collections.sort(replies, Reply.TIME_COMPARATOR);
- fingerprint.append("Replies(");
+ hash.putString("Replies(");
for (PostReply reply : replies) {
- fingerprint.append("Reply(").append(reply.getId()).append(')');
+ hash.putString("Reply(").putString(reply.getId()).putString(")");
}
- fingerprint.append(')');
+ hash.putString(")");
List<String> likedPostIds = new ArrayList<String>(getLikedPostIds());
Collections.sort(likedPostIds);
- fingerprint.append("LikedPosts(");
+ hash.putString("LikedPosts(");
for (String likedPostId : likedPostIds) {
- fingerprint.append("Post(").append(likedPostId).append(')');
+ hash.putString("Post(").putString(likedPostId).putString(")");
}
- fingerprint.append(')');
+ hash.putString(")");
List<String> likedReplyIds = new ArrayList<String>(getLikedReplyIds());
Collections.sort(likedReplyIds);
- fingerprint.append("LikedReplies(");
+ hash.putString("LikedReplies(");
for (String likedReplyId : likedReplyIds) {
- fingerprint.append("Reply(").append(likedReplyId).append(')');
+ hash.putString("Reply(").putString(likedReplyId).putString(")");
}
- fingerprint.append(')');
+ hash.putString(")");
- fingerprint.append("Albums(");
+ hash.putString("Albums(");
for (Album album : albums) {
- fingerprint.append(album.getFingerprint());
+ hash.putString(album.getFingerprint());
}
- fingerprint.append(')');
+ hash.putString(")");
- return fingerprint.toString();
+ return hash.hash().toString();
}
//
// INTERFACE Comparable<Sone>
//
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public int compareTo(Sone sone) {
return NICE_NAME_COMPARATOR.compare(this, sone);
// OBJECT METHODS
//
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public int hashCode() {
return id.hashCode();
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public boolean equals(Object object) {
if (!(object instanceof Sone)) {
return ((Sone) object).id.equals(id);
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public String toString() {
return getClass().getName() + "[identity=" + identity + ",requestUri=" + requestUri + ",insertUri(" + String.valueOf(insertUri).length() + "),friends(" + friendSones.size() + "),posts(" + posts.size() + "),replies(" + replies.size() + ")]";
/*
- * Sone - TemporaryImage.java - Copyright © 2011–2012 David Roden
+ * Sone - TemporaryImage.java - Copyright © 2011–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
package net.pterodactylus.sone.data;
-import java.util.UUID;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
-import net.pterodactylus.util.validation.Validation;
+import java.util.UUID;
/**
* A temporary image stores an uploaded image in memory until it has been
* @return This temporary image
*/
public TemporaryImage setMimeType(String mimeType) {
- Validation.begin().isNotNull("MIME Type", mimeType).isNull("Previous MIME Type", this.mimeType).check();
+ checkNotNull(mimeType, "mimeType must not be null");
+ checkState(this.mimeType == null, "mime type must not already be set");
this.mimeType = mimeType;
return this;
}
* @return This temporary image
*/
public TemporaryImage setImageData(byte[] imageData) {
- Validation.begin().isNotNull("Image Data", imageData).isNull("Previous Image Data", this.imageData).check();
+ checkNotNull(imageData, "imageData must not be null");
+ checkState(this.imageData == null, "image data must not already be set");
this.imageData = imageData;
return this;
}
--- /dev/null
+/*
+ * Sone - AbstractPostBuilder.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data.impl;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import org.apache.commons.lang.StringUtils;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.database.PostBuilder;
+import net.pterodactylus.sone.database.SoneProvider;
+
+/**
+ * Abstract {@link PostBuilder} implementation. It stores the state of the new
+ * post and performs validation, you only need to implement {@link #build()}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public abstract class AbstractPostBuilder implements PostBuilder {
+
+ /** The Sone provider for the created posts. */
+ protected final SoneProvider soneProvider;
+
+ /** Wether to create a post with a random ID. */
+ protected boolean randomId;
+
+ /** The ID of the post. */
+ protected String id;
+
+ /** The sender of the post. */
+ protected String senderId;
+
+ /** Whether to use the current time when creating the post. */
+ protected boolean currentTime;
+
+ /** The time of the post. */
+ protected long time;
+
+ /** The text of the post. */
+ protected String text;
+
+ /** The (optional) recipient of the post. */
+ protected String recipientId;
+
+ /**
+ * Creates a new abstract post builder.
+ *
+ * @param soneProvider
+ * The Sone provider
+ */
+ public AbstractPostBuilder(SoneProvider soneProvider) {
+ this.soneProvider = soneProvider;
+ }
+
+ //
+ // POSTBUILDER METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostBuilder copyPost(Post post) {
+ this.randomId = false;
+ this.id = post.getId();
+ this.senderId = post.getSone().getId();
+ this.currentTime = false;
+ this.time = post.getTime();
+ this.text = post.getText();
+ this.recipientId = post.getRecipientId().orNull();
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostBuilder randomId() {
+ randomId = true;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostBuilder withId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostBuilder from(String senderId) {
+ this.senderId = senderId;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostBuilder currentTime() {
+ currentTime = true;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostBuilder withTime(long time) {
+ this.time = time;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostBuilder withText(String text) {
+ this.text = text;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostBuilder to(String recipientId) {
+ this.recipientId = recipientId;
+ return this;
+ }
+
+ //
+ // PROTECTED METHODS
+ //
+
+ /**
+ * Validates the state of this post builder.
+ *
+ * @throws IllegalStateException
+ * if the state is not valid for building a new post
+ */
+ protected void validate() throws IllegalStateException {
+ checkState((randomId && (id == null)) || (!randomId && (id != null)), "exactly one of random ID or custom ID must be set");
+ checkState(senderId != null, "sender must not be null");
+ checkState((currentTime && (time == 0)) || (!currentTime && (time > 0)), "one of current time or custom time must be set");
+ checkState(!StringUtils.isBlank(text), "text must not be empty");
+ checkState((recipientId == null) || !recipientId.equals(senderId), "sender and recipient must not be the same");
+ }
+
+}
--- /dev/null
+/*
+ * Sone - AbstractPostReplyBuilder.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data.impl;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import org.apache.commons.lang.StringUtils;
+
+import net.pterodactylus.sone.database.PostReplyBuilder;
+
+/**
+ * Abstract {@link PostReplyBuilder} implementation. It stores the state of the
+ * new post and performs validation, implementations only need to implement
+ * {@link #build()}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public abstract class AbstractPostReplyBuilder extends AbstractReplyBuilder<PostReplyBuilder> implements PostReplyBuilder {
+
+ /** The ID of the post the created reply refers to. */
+ protected String postId;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostReplyBuilder to(String postId) {
+ this.postId = postId;
+ return this;
+ }
+
+ //
+ // PROTECTED METHODS
+ //
+
+ /**
+ * Validates the state of this post reply builder.
+ *
+ * @throws IllegalStateException
+ * if the state is not valid for building a new post reply
+ */
+ protected void validate() throws IllegalStateException {
+ checkState((randomId && (id == null)) || (!randomId && (id != null)), "either random ID nor custom ID must be set");
+ checkState(senderId != null, "sender must not be null");
+ checkState((currentTime && (time == 0)) || (!currentTime && (time >= 0)), "either current time or custom time must be set");
+ checkState(!StringUtils.isBlank(text), "text must not be empty");
+ checkState(postId != null, "post must not be null");
+ }
+
+}
--- /dev/null
+/*
+ * Sone - ReplyBuilder.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data.impl;
+
+import net.pterodactylus.sone.database.ReplyBuilder;
+
+/**
+ * Abstract implementation of a {@link ReplyBuilder}.
+ *
+ * @param <B>
+ * The interface implemented and exposed by the builder
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class AbstractReplyBuilder<B extends ReplyBuilder<B>> implements ReplyBuilder<B> {
+
+ /** Whether to use a random ID for the reply. */
+ protected boolean randomId;
+
+ /** The ID of the reply. */
+ protected String id;
+
+ /** The sender of the reply. */
+ protected String senderId;
+
+ /** Whether to use the current time when creating the reply. */
+ protected boolean currentTime;
+
+ /** The time of the reply. */
+ protected long time;
+
+ /** The text of the reply. */
+ protected String text;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public B randomId() {
+ this.randomId = true;
+ return (B) this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public B withId(String id) {
+ this.id = id;
+ return (B) this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public B from(String senderId) {
+ this.senderId = senderId;
+ return (B) this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public B currentTime() {
+ this.currentTime = true;
+ return (B) this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public B withTime(long time) {
+ this.time = time;
+ return (B) this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public B withText(String text) {
+ this.text = text;
+ return (B) this;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - DefaultPostBuilderFactory.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data.impl;
+
+import net.pterodactylus.sone.database.PostBuilder;
+import net.pterodactylus.sone.database.PostBuilderFactory;
+import net.pterodactylus.sone.database.SoneProvider;
+
+import com.google.inject.Inject;
+
+/**
+ * {@link PostBuilderFactory} implementation that creates
+ * {@link PostBuilderImpl}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DefaultPostBuilderFactory implements PostBuilderFactory {
+
+ /** The Sone provider. */
+ private final SoneProvider soneProvider;
+
+ /**
+ * Creates a new default post builder factory.
+ *
+ * @param soneProvider
+ * The Sone provider
+ */
+ @Inject
+ public DefaultPostBuilderFactory(SoneProvider soneProvider) {
+ this.soneProvider = soneProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostBuilder newPostBuilder() {
+ return new PostBuilderImpl(soneProvider);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - DefaultPostReplyBuilderFactory.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data.impl;
+
+import net.pterodactylus.sone.database.PostProvider;
+import net.pterodactylus.sone.database.PostReplyBuilder;
+import net.pterodactylus.sone.database.PostReplyBuilderFactory;
+import net.pterodactylus.sone.database.SoneProvider;
+
+import com.google.inject.Inject;
+
+/**
+ * {@link PostReplyBuilderFactory} that creates {@link PostReplyBuilderImpl}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DefaultPostReplyBuilderFactory implements PostReplyBuilderFactory {
+
+ /** The Sone provider. */
+ private final SoneProvider soneProvider;
+
+ /** The post provider. */
+ private final PostProvider postProvider;
+
+ /**
+ * Creates a new default post reply builder factory.
+ *
+ * @param soneProvider
+ * The Sone provider
+ * @param postProvider
+ * The post provider
+ */
+ @Inject
+ public DefaultPostReplyBuilderFactory(SoneProvider soneProvider, PostProvider postProvider) {
+ this.soneProvider = soneProvider;
+ this.postProvider = postProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostReplyBuilder newPostReplyBuilder() {
+ return new PostReplyBuilderImpl(soneProvider, postProvider);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - PostBuilderImpl.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data.impl;
+
+import java.util.UUID;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.database.PostBuilder;
+import net.pterodactylus.sone.database.SoneProvider;
+
+/**
+ * {@link PostBuilder} implementation that creates {@link PostImpl} objects.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostBuilderImpl extends AbstractPostBuilder {
+
+ /**
+ * Creates a new post builder.
+ *
+ * @param soneProvider
+ * The Sone provider
+ */
+ public PostBuilderImpl(SoneProvider soneProvider) {
+ super(soneProvider);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Post build() {
+ validate();
+ return new PostImpl(soneProvider, randomId ? UUID.randomUUID().toString() : id, senderId, recipientId, currentTime ? System.currentTimeMillis() : time, text);
+ }
+
+}
/*
- * Sone - PostImpl.java - Copyright © 2010–2012 David Roden
+ * Sone - PostImpl.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
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.SoneProvider;
+
+import com.google.common.base.Optional;
/**
* A post is a short message that a user writes in his Sone to let other users
*/
public class PostImpl implements Post {
+ /** The Sone provider. */
+ private final SoneProvider soneProvider;
+
/** The GUID of the post. */
private final UUID id;
- /** The Sone this post belongs to. */
- private volatile Sone sone;
+ /** The ID of the owning Sone. */
+ private final String soneId;
- /** The Sone of the recipient. */
- private volatile Sone recipient;
+ /** The ID of the recipient Sone. */
+ private final String recipientId;
/** The time of the post (in milliseconds since Jan 1, 1970 UTC). */
- private volatile long time;
+ private final long time;
/** The text of the post. */
- private volatile String text;
+ private final String text;
/** Whether the post is known. */
private volatile boolean known;
/**
* Creates a new post.
*
+ * @param soneProvider
+ * The Sone provider
* @param id
* The ID of the post
- */
- public PostImpl(String id) {
- this(id, null, 0, null);
- }
-
- /**
- * Creates a new post.
- *
- * @param sone
- * The Sone this post belongs to
- * @param text
- * The text of the post
- */
- public PostImpl(Sone sone, String text) {
- this(sone, System.currentTimeMillis(), text);
- }
-
- /**
- * Creates a new post.
- *
- * @param sone
- * The Sone this post belongs to
- * @param time
- * The time of the post (in milliseconds since Jan 1, 1970 UTC)
- * @param text
- * The text of the post
- */
- public PostImpl(Sone sone, long time, String text) {
- this(UUID.randomUUID().toString(), sone, time, text);
- }
-
- /**
- * Creates a new post.
- *
- * @param id
- * The ID of the post
- * @param sone
- * The Sone this post belongs to
+ * @param soneId
+ * The ID of the Sone this post belongs to
+ * @param recipientId
+ * The ID of the recipient of the post
* @param time
* The time of the post (in milliseconds since Jan 1, 1970 UTC)
* @param text
* The text of the post
*/
- public PostImpl(String id, Sone sone, long time, String text) {
+ public PostImpl(SoneProvider soneProvider, String id, String soneId, String recipientId, long time, String text) {
+ this.soneProvider = soneProvider;
this.id = UUID.fromString(id);
- this.sone = sone;
+ this.soneId = soneId;
+ this.recipientId = recipientId;
this.time = time;
this.text = text;
}
*/
@Override
public Sone getSone() {
- return sone;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public PostImpl setSone(Sone sone) {
- this.sone = sone;
- return this;
+ return soneProvider.getSone(soneId).get();
}
/**
- * {@inheritDoc}
+ * {@inheritDocs}
*/
@Override
- public Sone getRecipient() {
- return recipient;
+ public Optional<String> getRecipientId() {
+ return Optional.fromNullable(recipientId);
}
/**
* {@inheritDoc}
*/
@Override
- public PostImpl setRecipient(Sone recipient) {
- if (!sone.equals(recipient)) {
- this.recipient = recipient;
- }
- return this;
+ public Optional<Sone> getRecipient() {
+ return soneProvider.getSone(recipientId);
}
/**
* {@inheritDoc}
*/
@Override
- public PostImpl setTime(long time) {
- this.time = time;
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public String getText() {
return text;
}
* {@inheritDoc}
*/
@Override
- public PostImpl setText(String text) {
- this.text = text;
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public boolean isKnown() {
return known;
}
*/
@Override
public String toString() {
- return getClass().getName() + "[id=" + id + ",sone=" + sone + ",time=" + time + ",text=" + text + "]";
+ return String.format("%s[id=%s,sone=%s,recipient=%s,time=%d,text=%s]", getClass().getName(), id, soneId, recipientId, time, text);
}
}
--- /dev/null
+/*
+ * Sone - PostReplyBuilderImpl.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data.impl;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.UUID;
+
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.database.PostProvider;
+import net.pterodactylus.sone.database.PostReplyBuilder;
+import net.pterodactylus.sone.database.SoneProvider;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * {@link PostReplyBuilder} implementation that creates {@link PostReplyImpl}
+ * objects.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostReplyBuilderImpl extends AbstractPostReplyBuilder {
+
+ /** The Sone provider. */
+ private final SoneProvider soneProvider;
+
+ /** The post provider. */
+ private final PostProvider postProvider;
+
+ /**
+ * Creates a new post reply builder.
+ *
+ * @param soneProvider
+ * The Sone provider
+ * @param postProvider
+ * The post provider
+ */
+ public PostReplyBuilderImpl(SoneProvider soneProvider, PostProvider postProvider) {
+ this.soneProvider = soneProvider;
+ this.postProvider = postProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostReply build() {
+ checkState((randomId && (id == null)) || (!randomId && (id != null)), "either random ID nor custom ID must be set");
+ checkState(senderId != null, "sender must not be null");
+ checkState((currentTime && (time == 0)) || (!currentTime && (time >= 0)), "either current time or custom time must be set");
+ checkState(!StringUtils.isBlank(text), "text must not be empty");
+ checkState(postId != null, "post must not be null");
+
+ /* create new post reply. */
+ return new PostReplyImpl(soneProvider, postProvider, randomId ? UUID.randomUUID().toString() : id, senderId, currentTime ? System.currentTimeMillis() : time, text, postId);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - PostReplyImpl.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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data.impl;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.database.PostProvider;
+import net.pterodactylus.sone.database.SoneProvider;
+
+import com.google.common.base.Optional;
+
+/**
+ * Simple {@link PostReply} implementation.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostReplyImpl extends ReplyImpl<PostReply> implements PostReply {
+
+ /** The post provider. */
+ private final PostProvider postProvider;
+
+ /** The Post this reply refers to. */
+ private final String postId;
+
+ /**
+ * Creates a new reply.
+ *
+ * @param soneProvider
+ * The Sone provider
+ * @param postProvider
+ * The post provider
+ * @param id
+ * The ID of the reply
+ * @param soneId
+ * The ID of the Sone of the reply
+ * @param time
+ * The time of the reply
+ * @param text
+ * The text of the reply
+ * @param postId
+ * The ID of the post this reply refers to
+ */
+ public PostReplyImpl(SoneProvider soneProvider, PostProvider postProvider, String id, String soneId, long time, String text, String postId) {
+ super(soneProvider, id, soneId, time, text);
+ this.postProvider = postProvider;
+ this.postId = postId;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public String getPostId() {
+ return postId;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Optional<Post> getPost() {
+ return postProvider.getPost(postId);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - ReplyImpl.java - Copyright © 2011–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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data.impl;
+
+import net.pterodactylus.sone.data.Reply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.SoneProvider;
+
+/**
+ * Abstract base class for all replies.
+ *
+ * @param <T>
+ * The type of the reply
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public abstract class ReplyImpl<T extends Reply<T>> implements Reply<T> {
+
+ /** The Sone provider. */
+ private final SoneProvider soneProvider;
+
+ /** The ID of the reply. */
+ private final String id;
+
+ /** The Sone that created this reply. */
+ private final String soneId;
+
+ /** The time of the reply. */
+ private final long time;
+
+ /** The text of the reply. */
+ private final String text;
+
+ /** Whether the reply is known. */
+ private volatile boolean known;
+
+ /**
+ * Creates a new reply.
+ *
+ * @param soneProvider
+ * The Sone provider
+ * @param id
+ * The ID of the reply
+ * @param soneId
+ * The ID of the Sone of the reply
+ * @param time
+ * The time of the reply
+ * @param text
+ * The text of the reply
+ */
+ protected ReplyImpl(SoneProvider soneProvider, String id, String soneId, long time, String text) {
+ this.soneProvider = soneProvider;
+ this.id = id;
+ this.soneId = soneId;
+ this.time = time;
+ this.text = text;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone getSone() {
+ return soneProvider.getSone(soneId).get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getTime() {
+ return time;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isKnown() {
+ return known;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public T setKnown(boolean known) {
+ this.known = known;
+ return (T) this;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof Reply<?>)) {
+ return false;
+ }
+ Reply<?> reply = (Reply<?>) object;
+ return reply.getId().equals(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return String.format("%s[id=%s,sone=%s,time=%d,text=%s]", getClass().getName(), id, soneId, time, text);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - Database.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+import com.google.common.util.concurrent.Service;
+
+/**
+ * Database for Sone data. This interface combines the various provider, store,
+ * and builder factory interfaces into a single interface and adds some methods
+ * necessary for lifecycle management.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface Database extends Service, PostDatabase, PostReplyDatabase {
+
+ /**
+ * Saves the database.
+ *
+ * @throws DatabaseException
+ * if an error occurs while saving
+ */
+ public void save() throws DatabaseException;
+
+}
--- /dev/null
+/*
+ * Sone - DatabaseException.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+/**
+ * Exception that signals a database error.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DatabaseException extends Exception {
+
+ /**
+ * Creates a new database exception.
+ */
+ public DatabaseException() {
+ super();
+ }
+
+ /**
+ * Creates a new database exception.
+ *
+ * @param message
+ * The message of the exception
+ */
+ public DatabaseException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new database exception.
+ *
+ * @param cause
+ * The cause of the exception
+ */
+ public DatabaseException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates a new database exception.
+ *
+ * @param message
+ * The message of the exception
+ * @param cause
+ * The cause of the exception
+ */
+ public DatabaseException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - PostBuilder.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Builder for {@link Post} objects.
+ * <p>
+ * A {@link Post} consists of the following elements:
+ * <ul>
+ * <li>an ID,</li>
+ * <li>a {@link Sone sender},</li>
+ * <li>an optional {@link Sone recipient},</li>
+ * <li>a time,</li>
+ * <li>and a text.</li>
+ * </ul>
+ * Except for the recipient, all this elements have to be configured on this
+ * builder. For the ID you have the possibility to configure either a random ID
+ * (which should be used for new posts) or a custom ID you specify (for creating
+ * an existing post). For the time you can use the current time (again, for
+ * creating new posts) or the given time (for loading posts). It is an error to
+ * specify both ways for either the ID or the time.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostBuilder {
+
+ /**
+ * Copies all attributes of the given post to this post builder.
+ *
+ * @param post
+ * The post whose attributes to copy into this builder
+ * @return This builder
+ * @throws NullPointerException
+ * if {@code post} is {@code null}
+ */
+ public PostBuilder copyPost(Post post) throws NullPointerException;
+
+ /**
+ * Configures this builder to use the given Sone as sender of the new post.
+ *
+ * @param senderId
+ * The ID of the sender of the post
+ * @return This post builder
+ */
+ public PostBuilder from(String senderId);
+
+ /**
+ * Configures this builder to use a random ID for the new post. If this
+ * method is used, {@link #withId(String)} must not be used.
+ *
+ * @return This post builder
+ */
+ public PostBuilder randomId();
+
+ /**
+ * Configures this builder to use the given ID as ID for the new post. If
+ * this method is used, {@link #randomId()} must not be used.
+ *
+ * @param id
+ * The ID to use for the post
+ * @return This post builder
+ */
+ public PostBuilder withId(String id);
+
+ /**
+ * Configures this builder to use the current time when creating the post.
+ * If this method is used, {@link #withTime(long)} must not be used.
+ *
+ * @return This post builder
+ */
+ public PostBuilder currentTime();
+
+ /**
+ * Configures the builder to use the given time as time for the new post. If
+ * this method is used, {@link #currentTime()} must not be used.
+ *
+ * @param time
+ * The time to use for the post
+ * @return This post builder
+ */
+ public PostBuilder withTime(long time);
+
+ /**
+ * Configures the builder to use the given text for the new post.
+ *
+ * @param text
+ * The text to use for the post
+ * @return This post builder
+ */
+ public PostBuilder withText(String text);
+
+ /**
+ * Configures the builder to use the given {@link Sone} as recipient for the
+ * post.
+ *
+ * @param recipientId
+ * The ID of the recipient of the post
+ * @return This post builder
+ */
+ public PostBuilder to(String recipientId);
+
+ /**
+ * Verifies this builder’s configuration and creates a new post.
+ * <p>
+ * The following conditions must be met in order for this builder to be
+ * configured correctly:
+ * <ul>
+ * <li>Exactly one of {@link #randomId()} or {@link #withId(String)} must
+ * have been called.</li>
+ * <li>The {@link #from(String) sender} must not be {@code null}.</li>
+ * <li>Exactly one of {@link #currentTime()} or {@link #withTime(long)} must
+ * have been called.</li>
+ * <li>The {@link #withText(String) text} must not be {@code null} and must
+ * contain something other than whitespace.</li>
+ * <li>The {@link #to(String) recipient} must either not have been set, or
+ * it must have been set to a {@link Sone} other than {@link #from(String)
+ * the sender}.</li>
+ * </ul>
+ *
+ * @return A new post
+ * @throws IllegalStateException
+ * if this builder’s configuration is not valid
+ */
+ public Post build() throws IllegalStateException;
+
+}
--- /dev/null
+/*
+ * Sone - PostBuilderFactory.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+/**
+ * Factory for {@link PostBuilder}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostBuilderFactory {
+
+ /**
+ * Creates a new post builder.
+ *
+ * @return A new post builder
+ */
+ public PostBuilder newPostBuilder();
+
+}
--- /dev/null
+/*
+ * Sone - PostDatabase.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+/**
+ * Combines a {@link PostProvider}, a {@link PostBuilderFactory}, and a
+ * {@link PostStore} into a complete post database.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostDatabase extends PostProvider, PostBuilderFactory, PostStore {
+
+ /* nothing here. */
+
+}
--- /dev/null
+/*
+ * Sone - PostProvider.java - Copyright © 2011–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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+import java.util.Collection;
+
+import net.pterodactylus.sone.data.Post;
+
+import com.google.common.base.Optional;
+
+/**
+ * Interface for objects that can provide {@link Post}s by their ID.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostProvider {
+
+ /**
+ * Returns the post with the given ID.
+ *
+ * @param postId
+ * The ID of the post to return
+ * @return The post with the given ID, or {@code null}
+ */
+ public Optional<Post> getPost(String postId);
+
+ /**
+ * Returns all posts from the given Sone.
+ *
+ * @param soneId
+ * The ID of the Sone
+ * @return All posts from the given Sone
+ */
+ public Collection<Post> getPosts(String soneId);
+
+ /**
+ * Returns all posts that have the given Sone as recipient.
+ *
+ * @see Post#getRecipient()
+ * @param recipientId
+ * The ID of the recipient of the posts
+ * @return All posts that have the given Sone as recipient
+ */
+ public Collection<Post> getDirectedPosts(String recipientId);
+
+}
--- /dev/null
+/*
+ * Sone - PostReplyBuilder.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+import net.pterodactylus.sone.data.PostReply;
+
+/**
+ * Builder for a {@link PostReply} object.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostReplyBuilder extends ReplyBuilder<PostReplyBuilder> {
+
+ /**
+ * Configures this builder to set the given post as post the created reply
+ * refers to.
+ *
+ * @param postId
+ * The ID of the post the reply refers to
+ * @return This builder
+ */
+ public PostReplyBuilder to(String postId);
+
+ /**
+ * Verifies the configuration of this builder and creates a new post reply.
+ * <p>
+ * The following conditions must be met in order for the configuration to be
+ * considered valid:
+ * <ul>
+ * <li>Exactly one of {@link #randomId()} or {@link #withId(String)} must
+ * have been called.</li>
+ * <li>The {@link #from(String) sender} must not be {@code null}.</li>
+ * <li>Exactly one of {@link #currentTime()} or {@link #withTime(long)} must
+ * have been called.</li>
+ * <li>The {@link #withText(String) text} must not be {@code null} and must
+ * contain something other than whitespace.</li>
+ * <li>The {@link #to(String) post} have been set.</li>
+ * </ul>
+ *
+ * @return The created post reply
+ * @throws IllegalStateException
+ * if this builder’s configuration is not valid
+ */
+ public PostReply build() throws IllegalStateException;
+
+}
--- /dev/null
+/*
+ * Sone - PostReplyBuilderFactory.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+/**
+ * Factory for {@link PostReplyBuilder}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostReplyBuilderFactory {
+
+ /**
+ * Creates a new post reply builder.
+ *
+ * @return A new post reply builder
+ */
+ public PostReplyBuilder newPostReplyBuilder();
+
+}
--- /dev/null
+/*
+ * Sone - PostReplyDatabase.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+/**
+ * Combines a {@link PostReplyProvider}, a {@link PostReplyBuilderFactory}, and
+ * a {@link PostReplyStore} into a complete post reply database.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostReplyDatabase extends PostReplyProvider, PostReplyBuilderFactory, PostReplyStore {
+
+ /* nothing here. */
+
+}
--- /dev/null
+/*
+ * Sone - PostReplyProvider.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+import java.util.List;
+
+import net.pterodactylus.sone.data.PostReply;
+
+import com.google.common.base.Optional;
+
+/**
+ * Interface for objects that can provide {@link PostReply}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostReplyProvider {
+
+ /**
+ * Returns the reply with the given ID.
+ *
+ * @param id
+ * The ID of the reply to get
+ * @return The reply, or {@code null} if there is no such reply
+ */
+ public Optional<PostReply> getPostReply(String id);
+
+ /**
+ * Returns all replies for the given post, order ascending by time.
+ *
+ * @param postId
+ * The ID of the post to get all replies for
+ * @return All replies for the given post
+ */
+ public List<PostReply> getReplies(String postId);
+
+}
--- /dev/null
+/*
+ * Sone - PostReplyStore.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+import java.util.Collection;
+
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Defines a store for {@link PostReply post replies}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostReplyStore {
+
+ /**
+ * Stores the given post reply.
+ *
+ * @param postReply
+ * The post reply
+ */
+ public void storePostReply(PostReply postReply);
+
+ /**
+ * Stores the given post replies as exclusive collection of post replies for
+ * the given Sone. This will remove all other post replies from this Sone!
+ *
+ * @param sone
+ * The Sone to store all post replies for
+ * @param postReplies
+ * The post replies of the Sone
+ * @throws IllegalArgumentException
+ * if one of the replies does not belong to the given Sone
+ */
+ public void storePostReplies(Sone sone, Collection<PostReply> postReplies) throws IllegalArgumentException;
+
+ /**
+ * Removes the given post reply from this store.
+ *
+ * @param postReply
+ * The post reply to remove
+ */
+ public void removePostReply(PostReply postReply);
+
+ /**
+ * Removes all post replies of the given Sone.
+ *
+ * @param sone
+ * The Sone to remove all post replies for
+ */
+ public void removePostReplies(Sone sone);
+
+}
--- /dev/null
+/*
+ * Sone - PostStore.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+import java.util.Collection;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Interface for a store for posts.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostStore {
+
+ /**
+ * Adds the given post to the store.
+ *
+ * @param post
+ * The post to store
+ */
+ public void storePost(Post post);
+
+ /**
+ * Removes the given post.
+ *
+ * @param post
+ * The post to remove
+ */
+ public void removePost(Post post);
+
+ /**
+ * Stores the given posts as all posts of a single {@link Sone}. This method
+ * will removed all other posts from the Sone!
+ *
+ * @param sone
+ * The Sone to store the posts for
+ * @param posts
+ * The posts to store
+ * @throws IllegalArgumentException
+ * if posts do not all belong to the same Sone
+ */
+ public void storePosts(Sone sone, Collection<Post> posts) throws IllegalArgumentException;
+
+ /**
+ * Removes all posts of the given {@link Sone}
+ *
+ * @param sone
+ * The Sone to remove all posts for
+ */
+ public void removePosts(Sone sone);
+
+}
--- /dev/null
+/*
+ * Sone - ReplyBuilder.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+import net.pterodactylus.sone.data.Reply;
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Methods that all reply builders need to implement in order to be able to
+ * create any kind of {@link Reply}.
+ *
+ * @param <B>
+ * The type of the builder
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface ReplyBuilder<B extends ReplyBuilder<B>> {
+
+ /**
+ * Configures this builder to use a random ID when creating the reply. If
+ * this method is used, {@link #withId(String)} must not be used.
+ *
+ * @return This builder
+ */
+ public B randomId();
+
+ /**
+ * Configures this builder to use the given ID when creating the reply. If
+ * this method is used, {@link #randomId()} must not be used.
+ *
+ * @param id
+ * The ID of the reply
+ * @return This builder
+ */
+ public B withId(String id);
+
+ /**
+ * Configures this builder to use the ID of the given {@link Sone} as sender
+ * of the reply.
+ *
+ * @param senderId
+ * The ID of the sender of the reply
+ * @return This builder
+ */
+ public B from(String senderId);
+
+ /**
+ * Configures this builder to use the current time when creating the reply.
+ * If this method is used, {@link #withTime(long)} must not be used.
+ *
+ * @return This builder
+ */
+ public B currentTime();
+
+ /**
+ * Configures this builder to use the given time when creating the reply. If
+ * this method is used, {@link #currentTime()} must not be used.
+ *
+ * @param time
+ * The time of the reply
+ * @return This builder
+ */
+ public B withTime(long time);
+
+ /**
+ * Configures this builder to use the given text when creating the reply.
+ *
+ * @param text
+ * The text of the reply
+ * @return This builder
+ */
+ public B withText(String text);
+
+}
--- /dev/null
+/*
+ * Sone - SoneProvider.java - Copyright © 2011–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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database;
+
+import java.util.Collection;
+
+import net.pterodactylus.sone.data.Sone;
+
+import com.google.common.base.Optional;
+
+/**
+ * Interface for objects that can provide {@link Sone}s by their ID.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface SoneProvider {
+
+ /**
+ * Returns the Sone with the given ID, or {@link Optional#absent()} if it
+ * does not exist.
+ *
+ * @param soneId
+ * The ID of the Sone to return
+ * @return The Sone with the given ID, or {@link Optional#absent()}
+ */
+ public Optional<Sone> getSone(String soneId);
+
+ /**
+ * Returns all Sones.
+ *
+ * @return All Sones
+ */
+ public Collection<Sone> getSones();
+
+ /**
+ * Returns all local Sones.
+ *
+ * @return All local Sones
+ */
+ public Collection<Sone> getLocalSones();
+
+ /**
+ * Returns all remote Sones.
+ *
+ * @return All remote Sones
+ */
+ public Collection<Sone> getRemoteSones();
+
+}
--- /dev/null
+/*
+ * Sone - MemoryDatabase.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database.memory;
+
+import static com.google.common.base.Preconditions.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Reply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.Database;
+import net.pterodactylus.sone.database.DatabaseException;
+import net.pterodactylus.sone.database.PostBuilder;
+import net.pterodactylus.sone.database.PostDatabase;
+import net.pterodactylus.sone.database.PostReplyBuilder;
+import net.pterodactylus.sone.database.SoneProvider;
+import net.pterodactylus.util.config.Configuration;
+import net.pterodactylus.util.config.ConfigurationException;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.SortedSetMultimap;
+import com.google.common.collect.TreeMultimap;
+import com.google.common.util.concurrent.AbstractService;
+import com.google.inject.Inject;
+
+/**
+ * Memory-based {@link PostDatabase} implementation.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class MemoryDatabase extends AbstractService implements Database {
+
+ /** The lock. */
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+ /** The Sone provider. */
+ private final SoneProvider soneProvider;
+
+ /** The configuration. */
+ private final Configuration configuration;
+
+ /** All posts by their ID. */
+ private final Map<String, Post> allPosts = new HashMap<String, Post>();
+
+ /** All posts by their Sones. */
+ private final Map<String, Collection<Post>> sonePosts = new HashMap<String, Collection<Post>>();
+
+ /** All posts by their recipient. */
+ private final Map<String, Collection<Post>> recipientPosts = new HashMap<String, Collection<Post>>();
+
+ /** Whether posts are known. */
+ private final Set<String> knownPosts = new HashSet<String>();
+
+ /** All post replies by their ID. */
+ private final Map<String, PostReply> allPostReplies = new HashMap<String, PostReply>();
+
+ /** Replies sorted by Sone. */
+ private final SortedSetMultimap<String, PostReply> sonePostReplies = TreeMultimap.create(new Comparator<String>() {
+
+ @Override
+ public int compare(String leftString, String rightString) {
+ return leftString.compareTo(rightString);
+ }
+ }, PostReply.TIME_COMPARATOR);
+
+ /** Replies by post. */
+ private final Map<String, SortedSet<PostReply>> postReplies = new HashMap<String, SortedSet<PostReply>>();
+
+ /** Whether post replies are known. */
+ private final Set<String> knownPostReplies = new HashSet<String>();
+
+ /**
+ * Creates a new memory database.
+ *
+ * @param soneProvider
+ * The Sone provider
+ * @param configuration
+ * The configuration for loading and saving elements
+ */
+ @Inject
+ public MemoryDatabase(SoneProvider soneProvider, Configuration configuration) {
+ this.soneProvider = soneProvider;
+ this.configuration = configuration;
+ }
+
+ //
+ // DATABASE METHODS
+ //
+
+ /**
+ * Saves the database.
+ *
+ * @throws DatabaseException
+ * if an error occurs while saving
+ */
+ @Override
+ public void save() throws DatabaseException {
+ saveKnownPosts();
+ saveKnownPostReplies();
+ }
+
+ //
+ // SERVICE METHODS
+ //
+
+ /** {@inheritDocs} */
+ @Override
+ protected void doStart() {
+ loadKnownPosts();
+ loadKnownPostReplies();
+ notifyStarted();
+ }
+
+ /** {@inheritDocs} */
+ @Override
+ protected void doStop() {
+ try {
+ save();
+ notifyStopped();
+ } catch (DatabaseException de1) {
+ notifyFailed(de1);
+ }
+ }
+
+ //
+ // POSTPROVIDER METHODS
+ //
+
+ /** {@inheritDocs} */
+ @Override
+ public Optional<Post> getPost(String postId) {
+ lock.readLock().lock();
+ try {
+ return Optional.fromNullable(allPosts.get(postId));
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /** {@inheritDocs} */
+ @Override
+ public Collection<Post> getPosts(String soneId) {
+ return new HashSet<Post>(getPostsFrom(soneId));
+ }
+
+ /** {@inheritDocs} */
+ @Override
+ public Collection<Post> getDirectedPosts(String recipientId) {
+ lock.readLock().lock();
+ try {
+ Collection<Post> posts = recipientPosts.get(recipientId);
+ return (posts == null) ? Collections.<Post>emptySet() : new HashSet<Post>(posts);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ //
+ // POSTBUILDERFACTORY METHODS
+ //
+
+ /** {@inheritDocs} */
+ @Override
+ public PostBuilder newPostBuilder() {
+ return new MemoryPostBuilder(this, soneProvider);
+ }
+
+ //
+ // POSTSTORE METHODS
+ //
+
+ /** {@inheritDocs} */
+ @Override
+ public void storePost(Post post) {
+ checkNotNull(post, "post must not be null");
+ lock.writeLock().lock();
+ try {
+ allPosts.put(post.getId(), post);
+ getPostsFrom(post.getSone().getId()).add(post);
+ if (post.getRecipientId().isPresent()) {
+ getPostsTo(post.getRecipientId().get()).add(post);
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /** {@inheritDocs} */
+ @Override
+ public void removePost(Post post) {
+ checkNotNull(post, "post must not be null");
+ lock.writeLock().lock();
+ try {
+ allPosts.remove(post.getId());
+ getPostsFrom(post.getSone().getId()).remove(post);
+ if (post.getRecipientId().isPresent()) {
+ getPostsTo(post.getRecipientId().get()).remove(post);
+ }
+ post.getSone().removePost(post);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /** {@inheritDocs} */
+ @Override
+ public void storePosts(Sone sone, Collection<Post> posts) throws IllegalArgumentException {
+ checkNotNull(sone, "sone must not be null");
+ /* verify that all posts are from the same Sone. */
+ for (Post post : posts) {
+ if (!sone.equals(post.getSone())) {
+ throw new IllegalArgumentException(String.format("Post from different Sone found: %s", post));
+ }
+ }
+
+ lock.writeLock().lock();
+ try {
+ /* remove all posts by the Sone. */
+ getPostsFrom(sone.getId()).clear();
+ for (Post post : posts) {
+ allPosts.remove(post.getId());
+ if (post.getRecipientId().isPresent()) {
+ getPostsTo(post.getRecipientId().get()).remove(post);
+ }
+ }
+
+ /* add new posts. */
+ getPostsFrom(sone.getId()).addAll(posts);
+ for (Post post : posts) {
+ allPosts.put(post.getId(), post);
+ if (post.getRecipientId().isPresent()) {
+ getPostsTo(post.getRecipientId().get()).add(post);
+ }
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /** {@inheritDocs} */
+ @Override
+ public void removePosts(Sone sone) {
+ checkNotNull(sone, "sone must not be null");
+ lock.writeLock().lock();
+ try {
+ /* remove all posts by the Sone. */
+ getPostsFrom(sone.getId()).clear();
+ for (Post post : sone.getPosts()) {
+ allPosts.remove(post.getId());
+ if (post.getRecipientId().isPresent()) {
+ getPostsTo(post.getRecipientId().get()).remove(post);
+ }
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ //
+ // POSTREPLYPROVIDER METHODS
+ //
+
+ /** {@inheritDocs} */
+ @Override
+ public Optional<PostReply> getPostReply(String id) {
+ lock.readLock().lock();
+ try {
+ return Optional.fromNullable(allPostReplies.get(id));
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /** {@inheritDocs} */
+ @Override
+ public List<PostReply> getReplies(String postId) {
+ lock.readLock().lock();
+ try {
+ if (!postReplies.containsKey(postId)) {
+ return Collections.emptyList();
+ }
+ return new ArrayList<PostReply>(postReplies.get(postId));
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ //
+ // POSTREPLYBUILDERFACTORY METHODS
+ //
+
+ /** {@inheritDocs} */
+ @Override
+ public PostReplyBuilder newPostReplyBuilder() {
+ return new MemoryPostReplyBuilder(this, soneProvider);
+ }
+
+ //
+ // POSTREPLYSTORE METHODS
+ //
+
+ /** {@inheritDocs} */
+ @Override
+ public void storePostReply(PostReply postReply) {
+ lock.writeLock().lock();
+ try {
+ allPostReplies.put(postReply.getId(), postReply);
+ if (postReplies.containsKey(postReply.getPostId())) {
+ postReplies.get(postReply.getPostId()).add(postReply);
+ } else {
+ TreeSet<PostReply> replies = new TreeSet<PostReply>(Reply.TIME_COMPARATOR);
+ replies.add(postReply);
+ postReplies.put(postReply.getPostId(), replies);
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /** {@inheritDocs} */
+ @Override
+ public void storePostReplies(Sone sone, Collection<PostReply> postReplies) {
+ checkNotNull(sone, "sone must not be null");
+ /* verify that all posts are from the same Sone. */
+ for (PostReply postReply : postReplies) {
+ if (!sone.equals(postReply.getSone())) {
+ throw new IllegalArgumentException(String.format("PostReply from different Sone found: %s", postReply));
+ }
+ }
+
+ lock.writeLock().lock();
+ try {
+ /* remove all post replies of the Sone. */
+ for (PostReply postReply : getRepliesFrom(sone.getId())) {
+ removePostReply(postReply);
+ }
+ for (PostReply postReply : postReplies) {
+ allPostReplies.put(postReply.getId(), postReply);
+ sonePostReplies.put(postReply.getSone().getId(), postReply);
+ if (this.postReplies.containsKey(postReply.getPostId())) {
+ this.postReplies.get(postReply.getPostId()).add(postReply);
+ } else {
+ TreeSet<PostReply> replies = new TreeSet<PostReply>(Reply.TIME_COMPARATOR);
+ replies.add(postReply);
+ this.postReplies.put(postReply.getPostId(), replies);
+ }
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /** {@inheritDocs} */
+ @Override
+ public void removePostReply(PostReply postReply) {
+ lock.writeLock().lock();
+ try {
+ allPostReplies.remove(postReply.getId());
+ if (postReplies.containsKey(postReply.getPostId())) {
+ postReplies.get(postReply.getPostId()).remove(postReply);
+ if (postReplies.get(postReply.getPostId()).isEmpty()) {
+ postReplies.remove(postReply.getPostId());
+ }
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /** {@inheritDocs} */
+ @Override
+ public void removePostReplies(Sone sone) {
+ checkNotNull(sone, "sone must not be null");
+
+ lock.writeLock().lock();
+ try {
+ for (PostReply postReply : sone.getReplies()) {
+ removePostReply(postReply);
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ //
+ // PACKAGE-PRIVATE METHODS
+ //
+
+ /**
+ * Returns whether the given post is known.
+ *
+ * @param post
+ * The post
+ * @return {@code true} if the post is known, {@code false} otherwise
+ */
+ boolean isPostKnown(Post post) {
+ lock.readLock().lock();
+ try {
+ return knownPosts.contains(post.getId());
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Sets whether the given post is known.
+ *
+ * @param post
+ * The post
+ * @param known
+ * {@code true} if the post is known, {@code false} otherwise
+ */
+ void setPostKnown(Post post, boolean known) {
+ lock.writeLock().lock();
+ try {
+ if (known) {
+ knownPosts.add(post.getId());
+ } else {
+ knownPosts.remove(post.getId());
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Returns whether the given post reply is known.
+ *
+ * @param postReply
+ * The post reply
+ * @return {@code true} if the given post reply is known, {@code false}
+ * otherwise
+ */
+ boolean isPostReplyKnown(PostReply postReply) {
+ lock.readLock().lock();
+ try {
+ return knownPostReplies.contains(postReply.getId());
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Sets whether the given post reply is known.
+ *
+ * @param postReply
+ * The post reply
+ * @param known
+ * {@code true} if the post reply is known, {@code false} otherwise
+ */
+ void setPostReplyKnown(PostReply postReply, boolean known) {
+ lock.writeLock().lock();
+ try {
+ if (known) {
+ knownPostReplies.add(postReply.getId());
+ } else {
+ knownPostReplies.remove(postReply.getId());
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ //
+ // PRIVATE METHODS
+ //
+
+ /**
+ * Gets all posts for the given Sone, creating a new collection if there is
+ * none yet.
+ *
+ * @param soneId
+ * The ID of the Sone to get the posts for
+ * @return All posts
+ */
+ private Collection<Post> getPostsFrom(String soneId) {
+ Collection<Post> posts = null;
+ lock.readLock().lock();
+ try {
+ posts = sonePosts.get(soneId);
+ } finally {
+ lock.readLock().unlock();
+ }
+ if (posts != null) {
+ return posts;
+ }
+
+ posts = new HashSet<Post>();
+ lock.writeLock().lock();
+ try {
+ sonePosts.put(soneId, posts);
+ } finally {
+ lock.writeLock().unlock();
+ }
+
+ return posts;
+ }
+
+ /**
+ * Gets all posts that are directed the given Sone, creating a new collection
+ * if there is none yet.
+ *
+ * @param recipientId
+ * The ID of the Sone to get the posts for
+ * @return All posts
+ */
+ private Collection<Post> getPostsTo(String recipientId) {
+ Collection<Post> posts = null;
+ lock.readLock().lock();
+ try {
+ posts = recipientPosts.get(recipientId);
+ } finally {
+ lock.readLock().unlock();
+ }
+ if (posts != null) {
+ return posts;
+ }
+
+ posts = new HashSet<Post>();
+ lock.writeLock().lock();
+ try {
+ recipientPosts.put(recipientId, posts);
+ } finally {
+ lock.writeLock().unlock();
+ }
+
+ return posts;
+ }
+
+ /** Loads the known posts. */
+ private void loadKnownPosts() {
+ lock.writeLock().lock();
+ try {
+ int postCounter = 0;
+ while (true) {
+ String knownPostId = configuration.getStringValue("KnownPosts/" + postCounter++ + "/ID").getValue(null);
+ if (knownPostId == null) {
+ break;
+ }
+ knownPosts.add(knownPostId);
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Saves the known posts to the configuration.
+ *
+ * @throws DatabaseException
+ * if a configuration error occurs
+ */
+ private void saveKnownPosts() throws DatabaseException {
+ lock.readLock().lock();
+ try {
+ int postCounter = 0;
+ for (String knownPostId : knownPosts) {
+ configuration.getStringValue("KnownPosts/" + postCounter++ + "/ID").setValue(knownPostId);
+ }
+ configuration.getStringValue("KnownPosts/" + postCounter + "/ID").setValue(null);
+ } catch (ConfigurationException ce1) {
+ throw new DatabaseException("Could not save database.", ce1);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Returns all replies by the given Sone.
+ *
+ * @param id
+ * The ID of the Sone
+ * @return The post replies of the Sone, sorted by time (newest first)
+ */
+ private Collection<PostReply> getRepliesFrom(String id) {
+ lock.readLock().lock();
+ try {
+ if (sonePostReplies.containsKey(id)) {
+ return Collections.unmodifiableCollection(sonePostReplies.get(id));
+ }
+ return Collections.emptySet();
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /** Loads the known post replies. */
+ private void loadKnownPostReplies() {
+ lock.writeLock().lock();
+ try {
+ int replyCounter = 0;
+ while (true) {
+ String knownReplyId = configuration.getStringValue("KnownReplies/" + replyCounter++ + "/ID").getValue(null);
+ if (knownReplyId == null) {
+ break;
+ }
+ knownPostReplies.add(knownReplyId);
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Saves the known post replies to the configuration.
+ *
+ * @throws DatabaseException
+ * if a configuration error occurs
+ */
+ private void saveKnownPostReplies() throws DatabaseException {
+ lock.readLock().lock();
+ try {
+ int replyCounter = 0;
+ for (String knownReplyId : knownPostReplies) {
+ configuration.getStringValue("KnownReplies/" + replyCounter++ + "/ID").setValue(knownReplyId);
+ }
+ configuration.getStringValue("KnownReplies/" + replyCounter + "/ID").setValue(null);
+ } catch (ConfigurationException ce1) {
+ throw new DatabaseException("Could not save database.", ce1);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Sone - PostImpl.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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database.memory;
+
+import java.util.UUID;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.SoneProvider;
+
+import com.google.common.base.Optional;
+
+/**
+ * A post is a short message that a user writes in his Sone to let other users
+ * know what is going on.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+class MemoryPost implements Post {
+
+ /** The post database. */
+ private final MemoryDatabase postDatabase;
+
+ /** The Sone provider. */
+ private final SoneProvider soneProvider;
+
+ /** The GUID of the post. */
+ private final UUID id;
+
+ /** The ID of the owning Sone. */
+ private final String soneId;
+
+ /** The ID of the recipient Sone. */
+ private final String recipientId;
+
+ /** The time of the post (in milliseconds since Jan 1, 1970 UTC). */
+ private final long time;
+
+ /** The text of the post. */
+ private final String text;
+
+ /**
+ * Creates a new post.
+ *
+ * @param postDatabase
+ * The post database
+ * @param soneProvider
+ * The Sone provider
+ * @param id
+ * The ID of the post
+ * @param soneId
+ * The ID of the Sone this post belongs to
+ * @param recipientId
+ * The ID of the recipient of the post
+ * @param time
+ * The time of the post (in milliseconds since Jan 1, 1970 UTC)
+ * @param text
+ * The text of the post
+ */
+ public MemoryPost(MemoryDatabase postDatabase, SoneProvider soneProvider, String id, String soneId, String recipientId, long time, String text) {
+ this.postDatabase = postDatabase;
+ this.soneProvider = soneProvider;
+ this.id = UUID.fromString(id);
+ this.soneId = soneId;
+ this.recipientId = recipientId;
+ this.time = time;
+ this.text = text;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getId() {
+ return id.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone getSone() {
+ return soneProvider.getSone(soneId).get();
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public Optional<String> getRecipientId() {
+ return Optional.fromNullable(recipientId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Optional<Sone> getRecipient() {
+ return soneProvider.getSone(recipientId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getTime() {
+ return time;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isKnown() {
+ return postDatabase.isPostKnown(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public MemoryPost setKnown(boolean known) {
+ postDatabase.setPostKnown(this, known);
+ return this;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof MemoryPost)) {
+ return false;
+ }
+ MemoryPost post = (MemoryPost) object;
+ return post.id.equals(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return String.format("%s[id=%s,sone=%s,recipient=%s,time=%d,text=%s]", getClass().getName(), id, soneId, recipientId, time, text);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - MemoryPostBuilder.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database.memory;
+
+import java.util.UUID;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.impl.AbstractPostBuilder;
+import net.pterodactylus.sone.database.PostBuilder;
+import net.pterodactylus.sone.database.SoneProvider;
+
+/**
+ * {@link PostBuilder} implementation that creates a {@link MemoryPost}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+class MemoryPostBuilder extends AbstractPostBuilder {
+
+ /** The database. */
+ private final MemoryDatabase database;
+
+ /**
+ * Creates a new memory post builder.
+ *
+ * @param memoryDatabase
+ * The database
+ * @param soneProvider
+ * The Sone provider
+ */
+ public MemoryPostBuilder(MemoryDatabase memoryDatabase, SoneProvider soneProvider) {
+ super(soneProvider);
+ database = memoryDatabase;
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public Post build() throws IllegalStateException {
+ validate();
+ Post post = new MemoryPost(database, soneProvider, randomId ? UUID.randomUUID().toString() : id, senderId, recipientId, currentTime ? System.currentTimeMillis() : time, text);
+ post.setKnown(database.isPostKnown(post));
+ return post;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - MemoryPostReply.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database.memory;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.SoneProvider;
+
+import com.google.common.base.Optional;
+
+/**
+ * Memory-based {@link PostReply} implementation.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+class MemoryPostReply implements PostReply {
+
+ /** The database. */
+ private final MemoryDatabase database;
+
+ /** The Sone provider. */
+ private final SoneProvider soneProvider;
+
+ /** The ID of the post reply. */
+ private final String id;
+
+ /** The ID of the owning Sone. */
+ private final String soneId;
+
+ /** The time of the post reply. */
+ private final long time;
+
+ /** The text of the post reply. */
+ private final String text;
+
+ /** The ID of the post this post reply refers to. */
+ private final String postId;
+
+ /**
+ * Creates a new memory-based {@link PostReply} implementation.
+ *
+ * @param database
+ * The database
+ * @param soneProvider
+ * The Sone provider
+ * @param id
+ * The ID of the post reply
+ * @param soneId
+ * The ID of the owning Sone
+ * @param time
+ * The time of the post reply
+ * @param text
+ * The text of the post reply
+ * @param postId
+ * The ID of the post this post reply refers to
+ */
+ public MemoryPostReply(MemoryDatabase database, SoneProvider soneProvider, String id, String soneId, long time, String text, String postId) {
+ this.database = database;
+ this.soneProvider = soneProvider;
+ this.id = id;
+ this.soneId = soneId;
+ this.time = time;
+ this.text = text;
+ this.postId = postId;
+ }
+
+ //
+ // REPLY METHODS
+ //
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public Sone getSone() {
+ return soneProvider.getSone(soneId).get();
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public long getTime() {
+ return time;
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public boolean isKnown() {
+ return database.isPostReplyKnown(this);
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public PostReply setKnown(boolean known) {
+ database.setPostReplyKnown(this, known);
+ return this;
+ }
+
+ //
+ // POSTREPLY METHODS
+ //
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public String getPostId() {
+ return postId;
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public Optional<Post> getPost() {
+ return database.getPost(postId);
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof MemoryPostReply)) {
+ return false;
+ }
+ MemoryPostReply memoryPostReply = (MemoryPostReply) object;
+ return memoryPostReply.id.equals(id);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - MemoryPostReplyBuilder.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.database.memory;
+
+import java.util.UUID;
+
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.impl.AbstractPostReplyBuilder;
+import net.pterodactylus.sone.database.PostReplyBuilder;
+import net.pterodactylus.sone.database.SoneProvider;
+
+/**
+ * {@link PostReplyBuilder} implementation that creates {@link MemoryPostReply}
+ * objects.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+class MemoryPostReplyBuilder extends AbstractPostReplyBuilder {
+
+ /** The database. */
+ private final MemoryDatabase database;
+
+ /** The Sone provider. */
+ private final SoneProvider soneProvider;
+
+ /**
+ * Creates a new {@link MemoryPostReply} builder.
+ *
+ * @param database
+ * The database
+ * @param soneProvider
+ * The Sone provider
+ */
+ public MemoryPostReplyBuilder(MemoryDatabase database, SoneProvider soneProvider) {
+ this.database = database;
+ this.soneProvider = soneProvider;
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public PostReply build() throws IllegalStateException {
+ validate();
+
+ PostReply postReply = new MemoryPostReply(database, soneProvider, randomId ? UUID.randomUUID().toString() : id, senderId, currentTime ? System.currentTimeMillis() : time, text, postId);
+ postReply.setKnown(database.isPostReplyKnown(postReply));
+ return postReply;
+ }
+
+}
/*
- * Sone - FcpInterface.java - Copyright © 2011–2012 David Roden
+ * Sone - AbstractSoneCommand.java - Copyright © 2011–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
import net.pterodactylus.sone.freenet.fcp.Command;
import net.pterodactylus.sone.freenet.fcp.FcpException;
import net.pterodactylus.sone.template.SoneAccessor;
-import net.pterodactylus.util.collection.filter.Filters;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Collections2;
+
import freenet.node.FSParseException;
import freenet.support.SimpleFieldSet;
* or if the Sone ID is invalid
*/
protected Sone getSone(SimpleFieldSet simpleFieldSet, String parameterName, boolean localOnly) throws FcpException {
- return getSone(simpleFieldSet, parameterName, localOnly, true);
+ return getSone(simpleFieldSet, parameterName, localOnly, true).get();
}
/**
* or if {@code mandatory} is {@code true} and the Sone ID is
* invalid
*/
- protected Sone getSone(SimpleFieldSet simpleFieldSet, String parameterName, boolean localOnly, boolean mandatory) throws FcpException {
+ protected Optional<Sone> getSone(SimpleFieldSet simpleFieldSet, String parameterName, boolean localOnly, boolean mandatory) throws FcpException {
String soneId = simpleFieldSet.get(parameterName);
if (mandatory && (soneId == null)) {
throw new FcpException("Could not load Sone ID from “" + parameterName + "”.");
}
- Sone sone = localOnly ? core.getLocalSone(soneId, false) : core.getSone(soneId, false);
- if (mandatory && (sone == null)) {
+ Optional<Sone> sone = core.getSone(soneId);
+ if ((mandatory && !sone.isPresent()) || (mandatory && sone.isPresent() && (localOnly && !sone.get().isLocal()))) {
throw new FcpException("Could not load Sone from “" + soneId + "”.");
}
return sone;
protected Post getPost(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException {
try {
String postId = simpleFieldSet.getString(parameterName);
- Post post = core.getPost(postId, false);
- if (post == null) {
+ Optional<Post> post = core.getPost(postId);
+ if (!post.isPresent()) {
throw new FcpException("Could not load post from “" + postId + "”.");
}
- return post;
+ return post.get();
} catch (FSParseException fspe1) {
throw new FcpException("Could not post ID from “" + parameterName + "”.", fspe1);
}
protected PostReply getReply(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException {
try {
String replyId = simpleFieldSet.getString(parameterName);
- PostReply reply = core.getReply(replyId, false);
- if (reply == null) {
+ Optional<PostReply> reply = core.getPostReply(replyId);
+ if (!reply.isPresent()) {
throw new FcpException("Could not load reply from “" + replyId + "”.");
}
- return reply;
+ return reply.get();
} catch (FSParseException fspe1) {
throw new FcpException("Could not reply ID from “" + parameterName + "”.", fspe1);
}
* such as if the Sone is followed by the local Sone
* @return The simple field set containing the given Sone
*/
- protected static SimpleFieldSet encodeSone(Sone sone, String prefix, Sone localSone) {
+ protected static SimpleFieldSet encodeSone(Sone sone, String prefix, Optional<Sone> localSone) {
SimpleFieldSetBuilder soneBuilder = new SimpleFieldSetBuilder();
soneBuilder.put(prefix + "Name", sone.getName());
soneBuilder.put(prefix + "NiceName", SoneAccessor.getNiceName(sone));
soneBuilder.put(prefix + "LastUpdated", sone.getTime());
- if (localSone != null) {
- soneBuilder.put(prefix + "Followed", String.valueOf(localSone.hasFriend(sone.getId())));
+ if (localSone.isPresent()) {
+ soneBuilder.put(prefix + "Followed", String.valueOf(localSone.get().hasFriend(sone.getId())));
}
Profile profile = sone.getProfile();
soneBuilder.put(prefix + "Field.Count", profile.getFields().size());
postBuilder.put(prefix + "ID", post.getId());
postBuilder.put(prefix + "Sone", post.getSone().getId());
- if (post.getRecipient() != null) {
- postBuilder.put(prefix + "Recipient", post.getRecipient().getId());
+ if (post.getRecipientId().isPresent()) {
+ postBuilder.put(prefix + "Recipient", post.getRecipientId().get());
}
postBuilder.put(prefix + "Time", post.getTime());
postBuilder.put(prefix + "Text", encodeString(post.getText()));
postBuilder.put(encodeLikes(core.getLikes(post), prefix + "Likes."));
if (includeReplies) {
- List<PostReply> replies = core.getReplies(post);
+ List<PostReply> replies = core.getReplies(post.getId());
postBuilder.put(encodeReplies(replies, prefix));
}
String postPrefix = prefix + postIndex++;
postBuilder.put(encodePost(post, postPrefix + ".", includeReplies));
if (includeReplies) {
- postBuilder.put(encodeReplies(Filters.filteredList(core.getReplies(post), Reply.FUTURE_REPLY_FILTER), postPrefix + "."));
+ postBuilder.put(encodeReplies(Collections2.filter(core.getReplies(post.getId()), Reply.FUTURE_REPLY_FILTER), postPrefix + "."));
}
}
/*
- * Sone - CreatePostCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - CreatePostCommand.java - Copyright © 2011–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
package net.pterodactylus.sone.fcp;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
if (sone.equals(recipient)) {
return new ErrorResponse("Sone and Recipient must not be the same.");
}
- Post post = getCore().createPost(sone, recipient, text);
+ Post post = getCore().createPost(sone, Optional.fromNullable(recipient), text);
return new Response("PostCreated", new SimpleFieldSetBuilder().put("Post", post.getId()).get());
}
/*
- * Sone - CreateReplyCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - CreateReplyCommand.java - Copyright © 2011–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
/*
- * Sone - DeletePostCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - DeletePostCommand.java - Copyright © 2011–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
@Override
public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
Post post = getPost(parameters, "Post");
- if (!getCore().isLocalSone(post.getSone())) {
+ if (!post.getSone().isLocal()) {
return new ErrorResponse(401, "Not allowed.");
}
return new Response("PostDeleted", new SimpleFieldSetBuilder().get());
/*
- * Sone - DeleteReplyCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - DeleteReplyCommand.java - Copyright © 2011–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
@Override
public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
PostReply reply = getReply(parameters, "Reply");
- if (!getCore().isLocalSone(reply.getSone())) {
+ if (!reply.getSone().isLocal()) {
return new ErrorResponse(401, "Not allowed.");
}
return new Response("ReplyDeleted", new SimpleFieldSetBuilder().get());
/*
- * Sone - FcpInterface.java - Copyright © 2011–2012 David Roden
+ * Sone - FcpInterface.java - Copyright © 2011–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
package net.pterodactylus.sone.fcp;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import net.pterodactylus.sone.freenet.fcp.Command.ErrorResponse;
import net.pterodactylus.sone.freenet.fcp.Command.Response;
import net.pterodactylus.util.logging.Logging;
-import net.pterodactylus.util.validation.Validation;
+
+import com.google.inject.Inject;
+
import freenet.pluginmanager.FredPluginFCP;
import freenet.pluginmanager.PluginNotFoundException;
import freenet.pluginmanager.PluginReplySender;
* @param core
* The core
*/
+ @Inject
public FcpInterface(Core core) {
commands.put("Version", new VersionCommand(core));
commands.put("GetLocalSones", new GetLocalSonesCommand(core));
* The action level for which full FCP access is required
*/
public void setFullAccessRequired(FullAccessRequired fullAccessRequired) {
- Validation.begin().isNotNull("FullAccessRequired", fullAccessRequired).check();
- this.fullAccessRequired = fullAccessRequired;
+ this.fullAccessRequired = checkNotNull(fullAccessRequired, "fullAccessRequired must not be null");
}
//
/*
- * Sone - GetLocalSonesCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - GetLocalSonesCommand.java - Copyright © 2011–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
package net.pterodactylus.sone.fcp;
import net.pterodactylus.sone.core.Core;
-import net.pterodactylus.sone.freenet.fcp.FcpException;
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
* {@inheritDoc}
*/
@Override
- public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
+ public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) {
return new Response("ListLocalSones", encodeSones(getCore().getLocalSones(), "LocalSones."));
}
/*
- * Sone - GetPostCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - GetPostCommand.java - Copyright © 2011–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
/*
- * Sone - GetPostFeedCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - GetPostFeedCommand.java - Copyright © 2011–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
package net.pterodactylus.sone.fcp;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.freenet.fcp.FcpException;
-import net.pterodactylus.util.collection.filter.Filters;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Collections2;
+
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
int startPost = getInt(parameters, "StartPost", 0);
int maxPosts = getInt(parameters, "MaxPosts", -1);
- Set<Post> allPosts = new HashSet<Post>();
+ Collection<Post> allPosts = new HashSet<Post>();
allPosts.addAll(sone.getPosts());
for (String friendSoneId : sone.getFriends()) {
- if (!getCore().hasSone(friendSoneId)) {
+ Optional<Sone> friendSone = getCore().getSone(friendSoneId);
+ if (!friendSone.isPresent()) {
continue;
}
- allPosts.addAll(getCore().getSone(friendSoneId, false).getPosts());
+ allPosts.addAll(friendSone.get().getPosts());
}
- allPosts.addAll(getCore().getDirectedPosts(sone));
- allPosts = Filters.filteredSet(allPosts, Post.FUTURE_POSTS_FILTER);
+ allPosts.addAll(getCore().getDirectedPosts(sone.getId()));
+ allPosts = Collections2.filter(allPosts, Post.FUTURE_POSTS_FILTER);
List<Post> sortedPosts = new ArrayList<Post>(allPosts);
Collections.sort(sortedPosts, Post.TIME_COMPARATOR);
/*
- * Sone - GetPostsCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - GetPostsCommand.java - Copyright © 2011–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
/*
- * Sone - GetSoneCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - GetSoneCommand.java - Copyright © 2011–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
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.freenet.fcp.FcpException;
+
+import com.google.common.base.Optional;
+
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
@Override
public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
Sone sone = getSone(parameters, "Sone", false);
- Sone localSone = getSone(parameters, "LocalSone", false, false);
+ Optional<Sone> localSone = getSone(parameters, "LocalSone", false, false);
return new Response("Sone", encodeSone(sone, "", localSone));
}
/*
- * Sone - GetSonesCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - GetSonesCommand.java - Copyright © 2011–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
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.freenet.fcp.FcpException;
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
* {@inheritDoc}
*/
@Override
- public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
+ public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) {
int startSone = getInt(parameters, "StartSone", 0);
int maxSones = getInt(parameters, "MaxSones", -1);
List<Sone> sones = new ArrayList<Sone>(getCore().getSones());
/*
- * Sone - LikePostCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - LikePostCommand.java - Copyright © 2011–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
/*
- * Sone - LikeReplyCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - LikeReplyCommand.java - Copyright © 2011–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
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
+import com.google.common.base.Optional;
+
/**
* Implements the “LockSone” FCP command. If a valid local Sone was given as
* parameter “Sone,” this command will always lock the Sone and reply with
@Override
public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
- Sone sone = getSone(parameters, "Sone", true, true);
- getCore().lockSone(sone);
- return new Response("SoneLocked", new SimpleFieldSetBuilder().put("Sone", sone.getId()).get());
+ Optional<Sone> sone = getSone(parameters, "Sone", true, true);
+ getCore().lockSone(sone.get());
+ return new Response("SoneLocked", new SimpleFieldSetBuilder().put("Sone", sone.get().getId()).get());
}
}
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
+import com.google.common.base.Optional;
+
/**
* Implements the “UnlockSone” FCP command. If a valid local Sone was given as
* parameter “Sone,” this command will always unlock the Sone and reply with
@Override
public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
- Sone sone = getSone(parameters, "Sone", true, true);
- getCore().unlockSone(sone);
- return new Response("SoneUnlocked", new SimpleFieldSetBuilder().put("Sone", sone.getId()).get());
+ Optional<Sone> sone = getSone(parameters, "Sone", true, true);
+ getCore().unlockSone(sone.get());
+ return new Response("SoneUnlocked", new SimpleFieldSetBuilder().put("Sone", sone.get().getId()).get());
}
}
/*
- * Sone - VersionCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - VersionCommand.java - Copyright © 2011–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
/*
- * Sone - L10nFilter.java - Copyright © 2010–2012 David Roden
+ * Sone - L10nFilter.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
/*
- * Sone - PluginStoreConfigurationBackend.java - Copyright © 2010–2012 David Roden
+ * Sone - PluginStoreConfigurationBackend.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
/*
- * Sone - SimpleFieldSetBuilder.java - Copyright © 2011–2012 David Roden
+ * Sone - SimpleFieldSetBuilder.java - Copyright © 2011–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
package net.pterodactylus.sone.freenet;
-import net.pterodactylus.util.validation.Validation;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import freenet.support.SimpleFieldSet;
/**
* The simple field set to build
*/
public SimpleFieldSetBuilder(SimpleFieldSet simpleFieldSet) {
- Validation.begin().isNotNull("Simple Field Set", simpleFieldSet).check();
- this.simpleFieldSet = simpleFieldSet;
+ this.simpleFieldSet = checkNotNull(simpleFieldSet, "simpleFieldSet must not be null");
}
/**
/*
- * Sone - StringBucket.java - Copyright © 2010–2012 David Roden
+ * Sone - StringBucket.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
package net.pterodactylus.sone.freenet;
import java.io.ByteArrayInputStream;
-import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
* {@inheritDoc}
*/
@Override
- public InputStream getInputStream() throws IOException {
+ public InputStream getInputStream() {
return new ByteArrayInputStream(string.getBytes(encoding));
}
* {@inheritDoc}
*/
@Override
- public OutputStream getOutputStream() throws IOException {
+ public OutputStream getOutputStream() {
return null;
}
/*
- * Sone - AbstractCommand.java - Copyright © 2011–2012 David Roden
+ * Sone - AbstractCommand.java - Copyright © 2011–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
/*
- * Sone - Command.java - Copyright © 2011–2012 David Roden
+ * Sone - Command.java - Copyright © 2011–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
/*
- * Sone - FcpException.java - Copyright © 2011–2012 David Roden
+ * Sone - FcpException.java - Copyright © 2011–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
+++ /dev/null
-/*
- * Sone - ConnectorListener.java - Copyright © 2010–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.freenet.plugin;
-
-import java.util.EventListener;
-
-import freenet.support.SimpleFieldSet;
-import freenet.support.api.Bucket;
-
-/**
- * Interface for objects that want to be notified if a {@link PluginConnector}
- * receives a reply from a plugin. As a connection listener is always
- * {@link PluginConnector#addConnectorListener(String, String, ConnectorListener)
- * added} for a specific plugin, it will always be notified for replies from the
- * correct plugin (unless you register the same listener for multiple
- * plugins—which you subsequently should not do).
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface ConnectorListener extends EventListener {
-
- /**
- * A reply was received from the plugin this connection listener was added
- * for.
- *
- * @param pluginConnector
- * The plugin connector that received the reply
- * @param fields
- * The fields of the reply
- * @param data
- * The data of the reply (may be null)
- */
- public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data);
-
-}
+++ /dev/null
-/*
- * Sone - ConnectorListenerManager.java - Copyright © 2010–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.freenet.plugin;
-
-import net.pterodactylus.util.event.AbstractListenerManager;
-import freenet.support.SimpleFieldSet;
-import freenet.support.api.Bucket;
-
-/**
- * Manages {@link ConnectorListener}s and fire events.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class ConnectorListenerManager extends AbstractListenerManager<PluginConnector, ConnectorListener> {
-
- /**
- * Creates a new manager for {@link ConnectorListener}s.
- *
- * @param pluginConnector
- * The plugin connector that is the source for all events
- */
- public ConnectorListenerManager(PluginConnector pluginConnector) {
- super(pluginConnector);
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Notifies all registered listeners that a reply from the plugin was
- * received.
- *
- * @param fields
- * The fields of the reply
- * @param data
- * The data of the reply (may be null)
- */
- public void fireReceivedReply(SimpleFieldSet fields, Bucket data) {
- for (ConnectorListener connectorListener : getListeners()) {
- connectorListener.receivedReply(getSource(), fields, data);
- }
- }
-
-}
/*
- * Sone - PluginConnector.java - Copyright © 2010–2012 David Roden
+ * Sone - PluginConnector.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
package net.pterodactylus.sone.freenet.plugin;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import net.pterodactylus.sone.freenet.plugin.event.ReceivedReplyEvent;
+
+import com.google.common.eventbus.EventBus;
+import com.google.inject.Inject;
-import net.pterodactylus.util.collection.Pair;
import freenet.pluginmanager.FredPluginTalker;
import freenet.pluginmanager.PluginNotFoundException;
import freenet.pluginmanager.PluginRespirator;
*/
public class PluginConnector implements FredPluginTalker {
+ /** The event bus. */
+ private final EventBus eventBus;
+
/** The plugin respirator. */
private final PluginRespirator pluginRespirator;
- /** Connector listener managers for all plugin connections. */
- private final Map<Pair<String, String>, ConnectorListenerManager> connectorListenerManagers = Collections.synchronizedMap(new HashMap<Pair<String, String>, ConnectorListenerManager>());
-
/**
* Creates a new plugin connector.
*
+ * @param eventBus
+ * The event bus
* @param pluginRespirator
* The plugin respirator
*/
- public PluginConnector(PluginRespirator pluginRespirator) {
+ @Inject
+ public PluginConnector(EventBus eventBus, PluginRespirator pluginRespirator) {
+ this.eventBus = eventBus;
this.pluginRespirator = pluginRespirator;
}
//
- // LISTENER MANAGEMENT
- //
-
- /**
- * Adds a connection listener for the given plugin connection.
- *
- * @param pluginName
- * The name of the plugin
- * @param identifier
- * The identifier of the connection
- * @param connectorListener
- * The listener to add
- */
- public void addConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) {
- getConnectorListenerManager(pluginName, identifier).addListener(connectorListener);
- }
-
- /**
- * Removes a connection listener for the given plugin connection.
- *
- * @param pluginName
- * The name of the plugin
- * @param identifier
- * The identifier of the connection
- * @param connectorListener
- * The listener to remove
- */
- public void removeConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) {
- getConnectorListenerManager(pluginName, identifier).removeListener(connectorListener);
- }
-
- //
// ACTIONS
//
//
/**
- * Returns the connection listener manager for the given plugin connection,
- * creating a new one if none does exist yet.
- *
- * @param pluginName
- * The name of the plugin
- * @param identifier
- * The identifier of the connection
- * @return The connection listener manager
- */
- private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier) {
- return getConnectorListenerManager(pluginName, identifier, true);
- }
-
- /**
- * Returns the connection listener manager for the given plugin connection,
- * optionally creating a new one if none does exist yet.
- *
- * @param pluginName
- * The name of the plugin
- * @param identifier
- * The identifier of the connection
- * @param create
- * {@code true} to create a new manager if there is none,
- * {@code false} to return {@code null} in that case
- * @return The connection listener manager, or {@code null} if none existed
- * and {@code create} is {@code false}
- */
- private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier, boolean create) {
- ConnectorListenerManager connectorListenerManager = connectorListenerManagers.get(new Pair<String, String>(pluginName, identifier));
- if (create && (connectorListenerManager == null)) {
- connectorListenerManager = new ConnectorListenerManager(this);
- connectorListenerManagers.put(new Pair<String, String>(pluginName, identifier), connectorListenerManager);
- }
- return connectorListenerManager;
- }
-
- /**
* Returns the plugin talker for the given plugin connection.
*
* @param pluginName
*/
@Override
public void onReply(String pluginName, String identifier, SimpleFieldSet params, Bucket data) {
- ConnectorListenerManager connectorListenerManager = getConnectorListenerManager(pluginName, identifier, false);
- if (connectorListenerManager == null) {
- /* we don’t care about events for this plugin. */
- return;
- }
- connectorListenerManager.fireReceivedReply(params, data);
+ eventBus.post(new ReceivedReplyEvent(this, pluginName, identifier, params, data));
}
}
/*
- * Sone - PluginException.java - Copyright © 2010–2012 David Roden
+ * Sone - PluginException.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
--- /dev/null
+/*
+ * Sone - ReceivedReplyEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.freenet.plugin.event;
+
+import net.pterodactylus.sone.freenet.plugin.PluginConnector;
+import freenet.support.SimpleFieldSet;
+import freenet.support.api.Bucket;
+
+/**
+ * Event that signals that a plugin reply was received.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class ReceivedReplyEvent {
+
+ /** The connector that received the reply. */
+ private final PluginConnector pluginConnector;
+
+ /** The name of the plugin that sent the reply. */
+ private final String pluginName;
+
+ /** The identifier of the initial request. */
+ private final String identifier;
+
+ /** The fields containing the reply. */
+ private final SimpleFieldSet fieldSet;
+
+ /** The optional reply data. */
+ private final Bucket data;
+
+ /**
+ * Creates a new “reply received” event.
+ *
+ * @param pluginConnector
+ * The connector that received the event
+ * @param pluginName
+ * The name of the plugin that sent the reply
+ * @param identifier
+ * The identifier of the initial request
+ * @param fieldSet
+ * The fields containing the reply
+ * @param data
+ * The optional data of the reply
+ */
+ public ReceivedReplyEvent(PluginConnector pluginConnector, String pluginName, String identifier, SimpleFieldSet fieldSet, Bucket data) {
+ this.pluginConnector = pluginConnector;
+ this.pluginName = pluginName;
+ this.identifier = identifier;
+ this.fieldSet = fieldSet;
+ this.data = data;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the plugin connector that received the reply.
+ *
+ * @return The plugin connector that received the reply
+ */
+ public PluginConnector pluginConnector() {
+ return pluginConnector;
+ }
+
+ /**
+ * Returns the name of the plugin that sent the reply.
+ *
+ * @return The name of the plugin that sent the reply
+ */
+ public String pluginName() {
+ return pluginName;
+ }
+
+ /**
+ * Returns the identifier of the initial request.
+ *
+ * @return The identifier of the initial request
+ */
+ public String identifier() {
+ return identifier;
+ }
+
+ /**
+ * Returns the fields containing the reply.
+ *
+ * @return The fields containing the reply
+ */
+ public SimpleFieldSet fieldSet() {
+ return fieldSet;
+ }
+
+ /**
+ * Returns the optional data of the reply.
+ *
+ * @return The optional data of the reply (may be {@code null})
+ */
+ public Bucket data() {
+ return data;
+ }
+
+}
/*
- * Sone - DefaultIdentity.java - Copyright © 2010–2012 David Roden
+ * Sone - DefaultIdentity.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
*/
@Override
public int hashCode() {
- return id.hashCode();
+ return getId().hashCode();
}
/**
*/
@Override
public boolean equals(Object object) {
- if (!(object instanceof DefaultIdentity)) {
+ if (!(object instanceof Identity)) {
return false;
}
- DefaultIdentity identity = (DefaultIdentity) object;
- return identity.id.equals(id);
+ Identity identity = (Identity) object;
+ return identity.getId().equals(getId());
}
/**
/*
- * Sone - DefaultOwnIdentity.java - Copyright © 2010–2012 David Roden
+ * Sone - DefaultOwnIdentity.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
/*
- * Sone - Identity.java - Copyright © 2010–2012 David Roden
+ * Sone - Identity.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
+++ /dev/null
-/*
- * Sone - IdentityListener.java - Copyright © 2010–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.freenet.wot;
-
-import java.util.EventListener;
-
-/**
- * Listener interface for {@link IdentityManager} events.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public interface IdentityListener extends EventListener {
-
- /**
- * Notifies a listener that an {@link OwnIdentity} that was not known on the
- * previous check is available.
- *
- * @param ownIdentity
- * The new own identity
- */
- public void ownIdentityAdded(OwnIdentity ownIdentity);
-
- /**
- * Notifies a listener that an {@link OwnIdentity} that was available during
- * the last check has gone away.
- *
- * @param ownIdentity
- * The disappeared own identity
- */
- public void ownIdentityRemoved(OwnIdentity ownIdentity);
-
- /**
- * Notifies a listener that a new identity was discovered.
- *
- * @param ownIdentity
- * The own identity at the root of the trust tree
- * @param identity
- * The new identity
- */
- public void identityAdded(OwnIdentity ownIdentity, Identity identity);
-
- /**
- * Notifies a listener that some properties of the identity have changed.
- *
- * @param ownIdentity
- * The own identity at the root of the trust tree
- * @param identity
- * The updated identity
- */
- public void identityUpdated(OwnIdentity ownIdentity, Identity identity);
-
- /**
- * Notifies a listener that an identity has gone away.
- *
- * @param ownIdentity
- * The own identity at the root of the trust tree
- * @param identity
- * The disappeared identity
- */
- public void identityRemoved(OwnIdentity ownIdentity, Identity identity);
-
-}
+++ /dev/null
-/*
- * Sone - IdentityListenerManager.java - Copyright © 2010–2012 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.freenet.wot;
-
-import net.pterodactylus.util.event.AbstractListenerManager;
-
-/**
- * Manager for {@link IdentityListener}s.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class IdentityListenerManager extends AbstractListenerManager<IdentityManager, IdentityListener> {
-
- /**
- * Creates a new identity listener manager.
- */
- public IdentityListenerManager() {
- super(null);
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Notifies all listeners that an {@link OwnIdentity} that was not known on
- * the previous check is available.
- *
- * @see IdentityListener#ownIdentityAdded(OwnIdentity)
- * @param ownIdentity
- * The new own identity
- */
- public void fireOwnIdentityAdded(OwnIdentity ownIdentity) {
- for (IdentityListener identityListener : getListeners()) {
- identityListener.ownIdentityAdded(ownIdentity);
- }
- }
-
- /**
- * Notifies all listeners that an {@link OwnIdentity} that was available
- * during the last check has gone away.
- *
- * @see IdentityListener#ownIdentityRemoved(OwnIdentity)
- * @param ownIdentity
- * The disappeared own identity
- */
- public void fireOwnIdentityRemoved(OwnIdentity ownIdentity) {
- for (IdentityListener identityListener : getListeners()) {
- identityListener.ownIdentityRemoved(ownIdentity);
- }
- }
-
- /**
- * Notifies all listeners that a new identity was discovered.
- *
- * @see IdentityListener#identityAdded(OwnIdentity, Identity)
- * @param ownIdentity
- * The own identity at the root of the trust tree
- * @param identity
- * The new identity
- */
- public void fireIdentityAdded(OwnIdentity ownIdentity, Identity identity) {
- for (IdentityListener identityListener : getListeners()) {
- identityListener.identityAdded(ownIdentity, identity);
- }
- }
-
- /**
- * Notifies all listeners that some properties of the identity have changed.
- *
- * @see IdentityListener#identityUpdated(OwnIdentity, Identity)
- * @param ownIdentity
- * The own identity at the root of the trust tree
- * @param identity
- * The updated identity
- */
- public void fireIdentityUpdated(OwnIdentity ownIdentity, Identity identity) {
- for (IdentityListener identityListener : getListeners()) {
- identityListener.identityUpdated(ownIdentity, identity);
- }
- }
-
- /**
- * Notifies all listeners that an identity has gone away.
- *
- * @see IdentityListener#identityRemoved(OwnIdentity, Identity)
- * @param ownIdentity
- * The own identity at the root of the trust tree
- * @param identity
- * The disappeared identity
- */
- public void fireIdentityRemoved(OwnIdentity ownIdentity, Identity identity) {
- for (IdentityListener identityListener : getListeners()) {
- identityListener.identityRemoved(ownIdentity, identity);
- }
- }
-
-}
/*
- * Sone - IdentityManager.java - Copyright © 2010–2012 David Roden
+ * Sone - IdentityManager.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
import java.util.logging.Logger;
import net.pterodactylus.sone.freenet.plugin.PluginException;
+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.logging.Logging;
import net.pterodactylus.util.service.AbstractService;
+import com.google.common.eventbus.EventBus;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
/**
* The identity manager takes care of loading and storing identities, their
* contexts, and properties. It does so in a way that does not expose errors via
* exceptions but it only logs them and tries to return sensible defaults.
* <p>
* It is also responsible for polling identities from the Web of Trust plugin
- * and notifying registered {@link IdentityListener}s when {@link Identity}s and
+ * and sending events to the {@link EventBus} when {@link Identity}s and
* {@link OwnIdentity}s are discovered or disappearing.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
/** The logger. */
private static final Logger logger = Logging.getLogger(IdentityManager.class);
- /** The event manager. */
- private final IdentityListenerManager identityListenerManager = new IdentityListenerManager();
+ /** The event bus. */
+ private final EventBus eventBus;
/** The Web of Trust connector. */
private final WebOfTrustConnector webOfTrustConnector;
/**
* Creates a new identity manager.
*
+ * @param eventBus
+ * The event bus
* @param webOfTrustConnector
* The Web of Trust connector
* @param context
* The context to focus on (may be {@code null} to ignore
* contexts)
*/
- public IdentityManager(WebOfTrustConnector webOfTrustConnector, String context) {
+ @Inject
+ public IdentityManager(EventBus eventBus, WebOfTrustConnector webOfTrustConnector, @Named("WebOfTrustContext") String context) {
super("Sone Identity Manager", false);
+ this.eventBus = eventBus;
this.webOfTrustConnector = webOfTrustConnector;
this.context = context;
}
//
- // LISTENER MANAGEMENT
- //
-
- /**
- * Adds a listener for identity events.
- *
- * @param identityListener
- * The listener to add
- */
- public void addIdentityListener(IdentityListener identityListener) {
- identityListenerManager.addListener(identityListener);
- }
-
- /**
- * Removes a listener for identity events.
- *
- * @param identityListener
- * The listener to remove
- */
- public void removeIdentityListener(IdentityListener identityListener) {
- identityListenerManager.removeListener(identityListener);
- }
-
- //
// ACCESSORS
//
Map<String, Identity> identities = new HashMap<String, Identity>();
currentIdentities.put(ownIdentity, identities);
- /* if the context doesn’t match, skip getting trusted identities. */
+ /*
+ * if the context doesn’t match, skip getting trusted
+ * identities.
+ */
if ((context != null) && !ownIdentity.hasContext(context)) {
continue;
}
/* find new identities. */
for (Identity currentIdentity : currentIdentities.get(ownIdentity).values()) {
if (!oldIdentities.containsKey(ownIdentity) || !oldIdentities.get(ownIdentity).containsKey(currentIdentity.getId())) {
- identityListenerManager.fireIdentityAdded(ownIdentity, currentIdentity);
+ eventBus.post(new IdentityAddedEvent(ownIdentity, currentIdentity));
}
}
if (oldIdentities.containsKey(ownIdentity)) {
for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) {
if (!currentIdentities.get(ownIdentity).containsKey(oldIdentity.getId())) {
- identityListenerManager.fireIdentityRemoved(ownIdentity, oldIdentity);
+ eventBus.post(new IdentityRemovedEvent(ownIdentity, oldIdentity));
}
}
Set<String> oldContexts = oldIdentity.getContexts();
Set<String> newContexts = newIdentity.getContexts();
if (oldContexts.size() != newContexts.size()) {
- identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity);
+ eventBus.post(new IdentityUpdatedEvent(ownIdentity, newIdentity));
continue;
}
for (String oldContext : oldContexts) {
if (!newContexts.contains(oldContext)) {
- identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity);
+ eventBus.post(new IdentityUpdatedEvent(ownIdentity, newIdentity));
break;
}
}
Map<String, String> oldProperties = oldIdentity.getProperties();
Map<String, String> newProperties = newIdentity.getProperties();
if (oldProperties.size() != newProperties.size()) {
- identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity);
+ eventBus.post(new IdentityUpdatedEvent(ownIdentity, newIdentity));
continue;
}
for (Entry<String, String> oldProperty : oldProperties.entrySet()) {
if (!newProperties.containsKey(oldProperty.getKey()) || !newProperties.get(oldProperty.getKey()).equals(oldProperty.getValue())) {
- identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity);
+ eventBus.post(new IdentityUpdatedEvent(ownIdentity, newIdentity));
break;
}
}
for (OwnIdentity oldOwnIdentity : currentOwnIdentities.values()) {
OwnIdentity newOwnIdentity = newOwnIdentities.get(oldOwnIdentity.getId());
if ((newOwnIdentity == null) || ((context != null) && oldOwnIdentity.hasContext(context) && !newOwnIdentity.hasContext(context))) {
- identityListenerManager.fireOwnIdentityRemoved(new DefaultOwnIdentity(oldOwnIdentity));
+ eventBus.post(new OwnIdentityRemovedEvent(new DefaultOwnIdentity(oldOwnIdentity)));
}
}
for (OwnIdentity currentOwnIdentity : newOwnIdentities.values()) {
OwnIdentity oldOwnIdentity = currentOwnIdentities.get(currentOwnIdentity.getId());
if (((oldOwnIdentity == null) && ((context == null) || currentOwnIdentity.hasContext(context))) || ((oldOwnIdentity != null) && (context != null) && (!oldOwnIdentity.hasContext(context) && currentOwnIdentity.hasContext(context)))) {
- identityListenerManager.fireOwnIdentityAdded(new DefaultOwnIdentity(currentOwnIdentity));
+ eventBus.post(new OwnIdentityAddedEvent(new DefaultOwnIdentity(currentOwnIdentity)));
}
}
/*
- * Sone - OwnIdentity.java - Copyright © 2010–2012 David Roden
+ * Sone - OwnIdentity.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
/*
- * Sone - Trust.java - Copyright © 2010–2012 David Roden
+ * Sone - Trust.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
/*
- * Sone - WebOfTrustConnector.java - Copyright © 2010–2012 David Roden
+ * Sone - WebOfTrustConnector.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
import java.util.logging.Level;
import java.util.logging.Logger;
-import net.pterodactylus.sone.freenet.plugin.ConnectorListener;
import net.pterodactylus.sone.freenet.plugin.PluginConnector;
import net.pterodactylus.sone.freenet.plugin.PluginException;
+import net.pterodactylus.sone.freenet.plugin.event.ReceivedReplyEvent;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.number.Numbers;
+
+import com.google.common.collect.MapMaker;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
/** The plugin connector. */
private final PluginConnector pluginConnector;
+ /** Map for replies. */
+ private final Map<PluginIdentifier, Reply> replies = new MapMaker().makeMap();
+
/**
* Creates a new Web of Trust connector that uses the given plugin
* connector.
* @param pluginConnector
* The plugin connector
*/
+ @Inject
public WebOfTrustConnector(PluginConnector pluginConnector) {
this.pluginConnector = pluginConnector;
}
* if the request could not be sent
*/
private Reply performRequest(SimpleFieldSet fields, Bucket data) throws PluginException {
- final String identifier = "FCP-Command-" + System.currentTimeMillis() + "-" + counter.getAndIncrement();
- final Reply reply = new Reply();
+ String identifier = "FCP-Command-" + System.currentTimeMillis() + "-" + counter.getAndIncrement();
+ Reply reply = new Reply();
+ PluginIdentifier pluginIdentifier = new PluginIdentifier(WOT_PLUGIN_NAME, identifier);
+ replies.put(pluginIdentifier, reply);
+
logger.log(Level.FINE, String.format("Sending FCP Request: %s", fields.get("Message")));
- ConnectorListener connectorListener = new ConnectorListener() {
-
- @Override
- @SuppressWarnings("synthetic-access")
- public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data) {
- String messageName = fields.get("Message");
- logger.log(Level.FINEST, String.format("Received Reply from Plugin: %s", messageName));
- synchronized (reply) {
- reply.setFields(fields);
- reply.setData(data);
- reply.notify();
- }
- }
- };
- pluginConnector.addConnectorListener(WOT_PLUGIN_NAME, identifier, connectorListener);
synchronized (reply) {
try {
pluginConnector.sendRequest(WOT_PLUGIN_NAME, identifier, fields, data);
}
}
} finally {
- pluginConnector.removeConnectorListener(WOT_PLUGIN_NAME, identifier, connectorListener);
+ replies.remove(pluginIdentifier);
}
}
logger.log(Level.FINEST, String.format("Received FCP Response for %s: %s", fields.get("Message"), (reply.getFields() != null) ? reply.getFields().get("Message") : null));
}
/**
+ * Notifies the connector that a plugin reply was received.
+ *
+ * @param receivedReplyEvent
+ * The event
+ */
+ @Subscribe
+ public void receivedReply(ReceivedReplyEvent receivedReplyEvent) {
+ PluginIdentifier pluginIdentifier = new PluginIdentifier(receivedReplyEvent.pluginName(), receivedReplyEvent.identifier());
+ Reply reply = replies.remove(pluginIdentifier);
+ if (reply == null) {
+ return;
+ }
+ logger.log(Level.FINEST, String.format("Received Reply from Plugin: %s", receivedReplyEvent.fieldSet().get("Message")));
+ synchronized (reply) {
+ reply.setFields(receivedReplyEvent.fieldSet());
+ reply.setData(receivedReplyEvent.data());
+ reply.notify();
+ }
+ }
+
+ /**
* Container for the data of the reply from a plugin.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
}
+ /**
+ * Container for identifying plugins. Plugins are identified by their plugin
+ * name and their unique identifier.
+ *
+ * @author <a href="mailto:d.roden@xplosion.de">David Roden</a>
+ */
+ private static class PluginIdentifier {
+
+ /** The plugin name. */
+ private final String pluginName;
+
+ /** The plugin identifier. */
+ private final String identifier;
+
+ /**
+ * Creates a new plugin identifier.
+ *
+ * @param pluginName
+ * The name of the plugin
+ * @param identifier
+ * The identifier of the plugin
+ */
+ public PluginIdentifier(String pluginName, String identifier) {
+ this.pluginName = pluginName;
+ this.identifier = identifier;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return pluginName.hashCode() ^ identifier.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof PluginIdentifier)) {
+ return false;
+ }
+ PluginIdentifier pluginIdentifier = (PluginIdentifier) object;
+ return pluginName.equals(pluginIdentifier.pluginName) && identifier.equals(pluginIdentifier.identifier);
+ }
+
+ }
+
}
/*
- * Sone - WebOfTrustException.java - Copyright © 2010–2012 David Roden
+ * Sone - WebOfTrustException.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
--- /dev/null
+/*
+ * Sone - IdentityAddedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.freenet.wot.event;
+
+import net.pterodactylus.sone.freenet.wot.Identity;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+
+/**
+ * Event that signals that an {@link Identity} was added.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class IdentityAddedEvent extends IdentityEvent {
+
+ /**
+ * Creates a new “identity added” event.
+ *
+ * @param ownIdentity
+ * The own identity that added the identity
+ * @param identity
+ * The identity that was added
+ */
+ public IdentityAddedEvent(OwnIdentity ownIdentity, Identity identity) {
+ super(ownIdentity, identity);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - IdentityEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.freenet.wot.event;
+
+import net.pterodactylus.sone.freenet.wot.Identity;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+
+/**
+ * Base class for {@link Identity} events.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public abstract class IdentityEvent {
+
+ /** The own identity this event relates to. */
+ private final OwnIdentity ownIdentity;
+
+ /** The identity this event is about. */
+ private final Identity identity;
+
+ /**
+ * Creates a new identity-based event.
+ *
+ * @param ownIdentity
+ * The own identity that relates to the identity
+ * @param identity
+ * The identity this event is about
+ */
+ protected IdentityEvent(OwnIdentity ownIdentity, Identity identity) {
+ this.ownIdentity = ownIdentity;
+ this.identity = identity;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the own identity this event relates to.
+ *
+ * @return The own identity this event relates to
+ */
+ public OwnIdentity ownIdentity() {
+ return ownIdentity;
+ }
+
+ /**
+ * Returns the identity this event is about.
+ *
+ * @return The identity this event is about
+ */
+ public Identity identity() {
+ return identity;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - IdentityRemovedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.freenet.wot.event;
+
+import net.pterodactylus.sone.freenet.wot.Identity;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+
+/**
+ * Event that signals that an {@link Identity} was removed.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class IdentityRemovedEvent extends IdentityEvent {
+
+ /**
+ * Creates a new “identity removed” event.
+ *
+ * @param ownIdentity
+ * The own identity that removed the identity
+ * @param identity
+ * The identity that was removed
+ */
+ public IdentityRemovedEvent(OwnIdentity ownIdentity, Identity identity) {
+ super(ownIdentity, identity);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - IdentityUpdatedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.freenet.wot.event;
+
+import net.pterodactylus.sone.freenet.wot.Identity;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+
+/**
+ * Event that signals that an {@link Identity} was updated.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class IdentityUpdatedEvent extends IdentityEvent {
+
+ /**
+ * Creates a new “identity updated” event.
+ *
+ * @param ownIdentity
+ * The own identity that tracks the identity
+ * @param identity
+ * The identity that was updated
+ */
+ public IdentityUpdatedEvent(OwnIdentity ownIdentity, Identity identity) {
+ super(ownIdentity, identity);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - OwnIdentityAddedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.freenet.wot.event;
+
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+
+/**
+ * Event that signals that an {@link OwnIdentity} was added.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class OwnIdentityAddedEvent extends OwnIdentityEvent {
+
+ /**
+ * Creates new “own identity added” event.
+ *
+ * @param ownIdentity
+ * The own identity that was added
+ */
+ public OwnIdentityAddedEvent(OwnIdentity ownIdentity) {
+ super(ownIdentity);
+ }
+
+}
--- /dev/null
+/*
+ * Sone - OwnIdentityEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.freenet.wot.event;
+
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+
+/**
+ * Base class for {@link OwnIdentity} events.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public abstract class OwnIdentityEvent {
+
+ /** The own identity this event is about. */
+ private final OwnIdentity ownIdentity;
+
+ /**
+ * Creates a new own identity-based event.
+ *
+ * @param ownIdentity
+ * The own identity this event is about
+ */
+ protected OwnIdentityEvent(OwnIdentity ownIdentity) {
+ this.ownIdentity = ownIdentity;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the own identity this event is about.
+ *
+ * @return The own identity this event is about
+ */
+ public OwnIdentity ownIdentity() {
+ return ownIdentity;
+ }
+
+}
--- /dev/null
+/*
+ * Sone - OwnIdentityRemovedEvent.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.freenet.wot.event;
+
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+
+/**
+ * Event that signals that an {@link OwnIdentity} was removed.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class OwnIdentityRemovedEvent extends OwnIdentityEvent {
+
+ /**
+ * Creates a new “own identity removed” event.
+ *
+ * @param ownIdentity
+ * The own identity that was removed
+ */
+ public OwnIdentityRemovedEvent(OwnIdentity ownIdentity) {
+ super(ownIdentity);
+ }
+
+}
/*
- * Sone - SonePlugin.java - Copyright © 2010–2012 David Roden
+ * Sone - SonePlugin.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
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.core.FreenetInterface;
import net.pterodactylus.sone.core.WebOfTrustUpdater;
+import net.pterodactylus.sone.database.Database;
+import net.pterodactylus.sone.database.PostBuilderFactory;
+import net.pterodactylus.sone.database.PostProvider;
+import net.pterodactylus.sone.database.PostReplyBuilderFactory;
+import net.pterodactylus.sone.database.SoneProvider;
+import net.pterodactylus.sone.database.memory.MemoryDatabase;
import net.pterodactylus.sone.fcp.FcpInterface;
import net.pterodactylus.sone.freenet.PluginStoreConfigurationBackend;
import net.pterodactylus.sone.freenet.plugin.PluginConnector;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.logging.LoggingListener;
import net.pterodactylus.util.version.Version;
+
+import com.google.common.eventbus.EventBus;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+import com.google.inject.TypeLiteral;
+import com.google.inject.matcher.Matchers;
+import com.google.inject.name.Names;
+import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.TypeEncounter;
+import com.google.inject.spi.TypeListener;
+
import freenet.client.async.DatabaseDisabledException;
import freenet.l10n.BaseL10n.LANGUAGE;
import freenet.l10n.PluginL10n;
+import freenet.node.Node;
import freenet.pluginmanager.FredPlugin;
import freenet.pluginmanager.FredPluginBaseL10n;
import freenet.pluginmanager.FredPluginFCP;
/** The web of trust connector. */
private WebOfTrustConnector webOfTrustConnector;
- /** The identity manager. */
- private IdentityManager identityManager;
-
//
// ACCESSORS
//
}
}
- boolean startupFailed = true;
- try {
- /* create freenet interface. */
- FreenetInterface freenetInterface = new FreenetInterface(pluginRespirator.getNode());
+ final Configuration startConfiguration = oldConfiguration;
+ final EventBus eventBus = new EventBus();
+
+ /* Freenet injector configuration. */
+ AbstractModule freenetModule = new AbstractModule() {
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ protected void configure() {
+ bind(PluginRespirator.class).toInstance(SonePlugin.this.pluginRespirator);
+ bind(Node.class).toInstance(SonePlugin.this.pluginRespirator.getNode());
+ }
+ };
+ /* Sone injector configuration. */
+ AbstractModule soneModule = new AbstractModule() {
- /* create web of trust connector. */
- PluginConnector pluginConnector = new PluginConnector(pluginRespirator);
- webOfTrustConnector = new WebOfTrustConnector(pluginConnector);
- identityManager = new IdentityManager(webOfTrustConnector, "Sone");
+ @Override
+ protected void configure() {
+ bind(Core.class).in(Singleton.class);
+ bind(MemoryDatabase.class).in(Singleton.class);
+ bind(EventBus.class).toInstance(eventBus);
+ bind(Configuration.class).toInstance(startConfiguration);
+ bind(FreenetInterface.class).in(Singleton.class);
+ bind(PluginConnector.class).in(Singleton.class);
+ bind(WebOfTrustConnector.class).in(Singleton.class);
+ bind(WebOfTrustUpdater.class).in(Singleton.class);
+ bind(IdentityManager.class).in(Singleton.class);
+ bind(String.class).annotatedWith(Names.named("WebOfTrustContext")).toInstance("Sone");
+ bind(SonePlugin.class).toInstance(SonePlugin.this);
+ bind(FcpInterface.class).in(Singleton.class);
+ bind(Database.class).to(MemoryDatabase.class);
+ bind(PostBuilderFactory.class).to(MemoryDatabase.class);
+ bind(PostReplyBuilderFactory.class).to(MemoryDatabase.class);
+ bind(SoneProvider.class).to(Core.class).in(Singleton.class);
+ bind(PostProvider.class).to(MemoryDatabase.class);
+ bindListener(Matchers.any(), new TypeListener() {
+
+ @Override
+ public <I> void hear(TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {
+ typeEncounter.register(new InjectionListener<I>() {
+
+ @Override
+ public void afterInjection(I injectee) {
+ eventBus.register(injectee);
+ }
+ });
+ }
+ });
+ }
- /* create trust updater. */
- WebOfTrustUpdater trustUpdater = new WebOfTrustUpdater(webOfTrustConnector);
- trustUpdater.init();
+ };
+ Injector injector = Guice.createInjector(freenetModule, soneModule);
+ core = injector.getInstance(Core.class);
- /* create core. */
- core = new Core(oldConfiguration, freenetInterface, identityManager, trustUpdater);
+ /* create web of trust connector. */
+ webOfTrustConnector = injector.getInstance(WebOfTrustConnector.class);
- /* create the web interface. */
- webInterface = new WebInterface(this);
- core.addCoreListener(webInterface);
+ /* create FCP interface. */
+ fcpInterface = injector.getInstance(FcpInterface.class);
+ core.setFcpInterface(fcpInterface);
- /* create FCP interface. */
- fcpInterface = new FcpInterface(core);
- core.setFcpInterface(fcpInterface);
+ /* create the web interface. */
+ webInterface = injector.getInstance(WebInterface.class);
- /* create the identity manager. */
- identityManager.addIdentityListener(core);
+ boolean startupFailed = true;
+ try {
/* start core! */
core.start();
webInterface.start();
webInterface.setFirstStart(firstStart);
webInterface.setNewConfig(newConfig);
- identityManager.start();
startupFailed = false;
} finally {
if (startupFailed) {
/* stop the core. */
core.stop();
- /* stop the identity manager. */
- identityManager.stop();
-
/* stop the web of trust connector. */
webOfTrustConnector.stop();
} catch (Throwable t1) {
/*
- * Sone - ListNotification.java - Copyright © 2010–2012 David Roden
+ * Sone - ListNotification.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
* The element to remove
*/
public void remove(T element) {
- elements.remove(element);
+ while (elements.remove(element)) {
+ /* do nothing, just remove all instances of the element. */
+ }
if (elements.isEmpty()) {
dismiss();
}
/*
- * Sone - ListNotificationFilters.java - Copyright © 2010–2012 David Roden
+ * Sone - ListNotificationFilters.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
package net.pterodactylus.sone.notify;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import net.pterodactylus.sone.freenet.wot.OwnIdentity;
import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.util.notify.Notification;
-import net.pterodactylus.util.validation.Validation;
+
+import com.google.common.base.Optional;
/**
* Filter for {@link ListNotification}s.
* otherwise
*/
public static boolean isPostVisible(Sone sone, Post post) {
- Validation.begin().isNotNull("Post", post).check();
+ checkNotNull(post, "post must not be null");
Sone postSone = post.getSone();
if (postSone == null) {
return false;
* received trust values. to prevent this we simply assume that
* posts are visible if there is no trust.
*/
- return true;
}
- if ((!postSone.equals(sone)) && !sone.hasFriend(postSone.getId()) && !sone.equals(post.getRecipient())) {
+ if ((!postSone.equals(sone)) && !sone.hasFriend(postSone.getId()) && !sone.getId().equals(post.getRecipientId().orNull())) {
return false;
}
}
* otherwise
*/
public static boolean isReplyVisible(Sone sone, PostReply reply) {
- Validation.begin().isNotNull("Reply", reply).check();
- Post post = reply.getPost();
- if (post == null) {
+ checkNotNull(reply, "reply must not be null");
+ Optional<Post> post = reply.getPost();
+ if (!post.isPresent()) {
return false;
}
- if (!isPostVisible(sone, post)) {
+ if (!isPostVisible(sone, post.get())) {
return false;
}
if (reply.getTime() > System.currentTimeMillis()) {
/*
- * Sone - AlbumAccessor.java - Copyright © 2011–2012 David Roden
+ * Sone - AlbumAccessor.java - Copyright © 2011–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
/*
- * Sone - CollectionAccessor.java - Copyright © 2010–2012 David Roden
+ * Sone - CollectionAccessor.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
/*
- * Sone - CssClassNameFilter.java - Copyright © 2010–2012 David Roden
+ * Sone - CssClassNameFilter.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
/*
- * Sone - GetPagePlugin.java - Copyright © 2010–2012 David Roden
+ * Sone - GetPagePlugin.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
/*
- * Sone - HttpRequestAccessor.java - Copyright © 2011–2012 David Roden
+ * Sone - HttpRequestAccessor.java - Copyright © 2011–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
/*
- * Sone - IdentityAccessor.java - Copyright © 2010–2012 David Roden
+ * Sone - IdentityAccessor.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
/*
- * Sone - ImageAccessor.java - Copyright © 2011–2012 David Roden
+ * Sone - ImageAccessor.java - Copyright © 2011–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
/*
- * Sone - ImageLinkFilter.java - Copyright © 2011–2012 David Roden
+ * Sone - ImageLinkFilter.java - Copyright © 2011–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
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.util.number.Numbers;
-import net.pterodactylus.util.object.Default;
import net.pterodactylus.util.template.Filter;
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
import net.pterodactylus.util.template.TemplateContextFactory;
import net.pterodactylus.util.template.TemplateParser;
+import com.google.common.base.Optional;
+
/**
* Template filter that turns an {@link Image} into an HTML <img> tag,
* using some parameters to influence parameters of the image.
linkTemplateContext.set("width", (int) (imageWidth * scale + 0.5));
linkTemplateContext.set("height", (int) (imageHeight * scale + 0.5));
}
- linkTemplateContext.set("alt", Default.forNull(title, image.getDescription()));
- linkTemplateContext.set("title", Default.forNull(title, image.getTitle()));
+ linkTemplateContext.set("alt", Optional.fromNullable(title).or(image.getDescription()));
+ linkTemplateContext.set("title", Optional.fromNullable(title).or(image.getTitle()));
StringWriter stringWriter = new StringWriter();
linkTemplate.render(linkTemplateContext, stringWriter);
/*
- * Sone - JavascriptFilter.java - Copyright © 2011–2012 David Roden
+ * Sone - JavascriptFilter.java - Copyright © 2011–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
import java.util.Map;
-import net.pterodactylus.util.number.Hex;
import net.pterodactylus.util.template.Filter;
import net.pterodactylus.util.template.TemplateContext;
+import com.google.common.io.BaseEncoding;
+
/**
* Escapes double quotes, backslashes, carriage returns and line feeds, and
* additionally encloses a given string with double quotes to make it possible
javascriptString.append('\\');
javascriptString.append(c);
} else if (c < 32) {
- javascriptString.append("\\x").append(Hex.toHex((byte) c));
+ javascriptString.append("\\x").append(BaseEncoding.base16().lowerCase().encode(new byte[] { (byte) c }));
} else {
javascriptString.append(c);
}
/*
- * Sone - ParserFilter.java - Copyright © 2011–2012 David Roden
+ * Sone - ParserFilter.java - Copyright © 2011–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
int cutOffLength = Numbers.safeParseInteger(parameters.get("cut-off-length"), Numbers.safeParseInteger(templateContext.get(String.valueOf(parameters.get("cut-off-length"))), length));
Object sone = parameters.get("sone");
if (sone instanceof String) {
- sone = core.getSone((String) sone, false);
+ sone = core.getSone((String) sone);
}
FreenetRequest request = (FreenetRequest) templateContext.get("request");
SoneTextParserContext context = new SoneTextParserContext(request, (Sone) sone);
/*
- * Sone - PostAccessor.java - Copyright © 2010–2012 David Roden
+ * Sone - PostAccessor.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
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Reply;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.util.collection.filter.Filters;
import net.pterodactylus.util.template.ReflectionAccessor;
import net.pterodactylus.util.template.TemplateContext;
+import com.google.common.collect.Collections2;
+
/**
* Accessor for {@link Post} objects that adds additional properties:
* <dl>
public Object get(TemplateContext templateContext, Object object, String member) {
Post post = (Post) object;
if ("replies".equals(member)) {
- return Filters.filteredList(core.getReplies(post), Reply.FUTURE_REPLY_FILTER);
+ return Collections2.filter(core.getReplies(post.getId()), Reply.FUTURE_REPLY_FILTER);
} else if (member.equals("likes")) {
return core.getLikes(post);
} else if (member.equals("liked")) {
/*
- * Sone - ProfileAccessor.java - Copyright © 2011–2012 David Roden
+ * Sone - ProfileAccessor.java - Copyright © 2011–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
return null;
}
Sone remoteSone = profile.getSone();
- if (core.isLocalSone(remoteSone)) {
+ if (remoteSone.isLocal()) {
/* always show your own avatars. */
return avatarId;
}
/*
- * Sone - ReplyAccessor.java - Copyright © 2010–2012 David Roden
+ * Sone - ReplyAccessor.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
/*
- * Sone - ReplyGroupFilter.java - Copyright © 2010–2012 David Roden
+ * Sone - ReplyGroupFilter.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
import net.pterodactylus.util.template.Filter;
import net.pterodactylus.util.template.TemplateContext;
+import com.google.common.base.Optional;
+
/**
* {@link Filter} implementation that groups replies by the post the are in
* reply to, returning a map with the post as key and the list of replies as
Map<Post, Set<Sone>> postSones = new HashMap<Post, Set<Sone>>();
Map<Post, Set<PostReply>> postReplies = new HashMap<Post, Set<PostReply>>();
for (PostReply reply : allReplies) {
- Post post = reply.getPost();
- Set<Sone> sones = postSones.get(post);
+ /*
+ * All replies from a new-reply notification have posts,
+ * ListNotificationFilters takes care of that.
+ */
+ Optional<Post> post = reply.getPost();
+ Set<Sone> sones = postSones.get(post.get());
if (sones == null) {
sones = new HashSet<Sone>();
- postSones.put(post, sones);
+ postSones.put(post.get(), sones);
}
sones.add(reply.getSone());
- Set<PostReply> replies = postReplies.get(post);
+ Set<PostReply> replies = postReplies.get(post.get());
if (replies == null) {
replies = new HashSet<PostReply>();
- postReplies.put(post, replies);
+ postReplies.put(post.get(), replies);
}
replies.add(reply);
}
/*
- * Sone - RequestChangeFilter.java - Copyright © 2010–2012 David Roden
+ * Sone - RequestChangeFilter.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
/*
- * Sone - SoneAccessor.java - Copyright © 2010–2012 David Roden
+ * Sone - SoneAccessor.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
Sone sone = (Sone) object;
if (member.equals("niceName")) {
return getNiceName(sone);
- } else if (member.equals("local")) {
- return core.isLocalSone(sone);
} else if (member.equals("friend")) {
Sone currentSone = (Sone) templateContext.get("currentSone");
return (currentSone != null) && currentSone.hasFriend(sone.getId());
/*
- * Sone - SubstringFilter.java - Copyright © 2010–2012 David Roden
+ * Sone - SubstringFilter.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
/*
- * Sone - TrustAccessor.java - Copyright © 2010–2012 David Roden
+ * Sone - TrustAccessor.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
/*
- * Sone - UniqueElementFilter.java - Copyright © 2011–2012 David Roden
+ * Sone - UniqueElementFilter.java - Copyright © 2011–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
/*
- * Sone - UnknownDateFilter.java - Copyright © 2011–2012 David Roden
+ * Sone - UnknownDateFilter.java - Copyright © 2011–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
/*
- * Sone - FreenetLinkPart.java - Copyright © 2011–2012 David Roden
+ * Sone - FreenetLinkPart.java - Copyright © 2011–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
/*
- * Sone - LinkPart.java - Copyright © 2011–2012 David Roden
+ * Sone - LinkPart.java - Copyright © 2011–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
/*
- * Sone - Parser.java - Copyright © 2010–2012 David Roden
+ * Sone - Parser.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
/*
- * Sone - ParserContext.java - Copyright © 2010–2012 David Roden
+ * Sone - ParserContext.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
/*
- * Sone - Part.java - Copyright © 2010–2012 David Roden
+ * Sone - Part.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
/*
- * Sone - PartContainer.java - Copyright © 2010–2012 David Roden
+ * Sone - PartContainer.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
/*
- * Sone - PlainTextPart.java - Copyright © 2011–2012 David Roden
+ * Sone - PlainTextPart.java - Copyright © 2011–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
/*
- * Sone - PostLinkPart.java - Copyright © 2011–2012 David Roden
+ * Sone - PostPart.java - Copyright © 2011–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
/*
- * Sone - SoneLinkPart.java - Copyright © 2011–2012 David Roden
+ * Sone - SonePart.java - Copyright © 2011–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
/*
- * Sone - FreenetLinkParser.java - Copyright © 2010–2012 David Roden
+ * Sone - SoneTextParser.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
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import net.pterodactylus.sone.core.PostProvider;
-import net.pterodactylus.sone.core.SoneProvider;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.PostProvider;
+import net.pterodactylus.sone.database.SoneProvider;
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.logging.Logging;
+
+import com.google.common.base.Optional;
+
import freenet.keys.FreenetURI;
/**
if (linkType == LinkType.SONE) {
if (line.length() >= (7 + 43)) {
String soneId = line.substring(7, 50);
- Sone sone = soneProvider.getSone(soneId, false);
- if (sone == null) {
+ Optional<Sone> sone = soneProvider.getSone(soneId);
+ if (!sone.isPresent()) {
/*
* don’t use create=true above, we don’t want
* the empty shell.
*/
- sone = new Sone(soneId);
+ sone = Optional.fromNullable(new Sone(soneId, false));
}
- parts.add(new SonePart(sone));
+ parts.add(new SonePart(sone.get()));
line = line.substring(50);
} else {
parts.add(new PlainTextPart(line));
if (linkType == LinkType.POST) {
if (line.length() >= (7 + 36)) {
String postId = line.substring(7, 43);
- Post post = postProvider.getPost(postId, false);
- if ((post != null) && (post.getSone() != null)) {
- parts.add(new PostPart(post));
+ Optional<Post> post = postProvider.getPost(postId);
+ if (post.isPresent()) {
+ parts.add(new PostPart(post.get()));
} else {
parts.add(new PlainTextPart(line.substring(0, 43)));
}
/*
- * Sone - SoneTextParserContext.java - Copyright © 2011–2012 David Roden
+ * Sone - SoneTextParserContext.java - Copyright © 2011–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
/*
- * Sone - TextFilter.java - Copyright © 2011–2012 David Roden
+ * Sone - TextFilter.java - Copyright © 2011–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
--- /dev/null
+/*
+ * Sone - IntegerRangePredicate.java - Copyright © 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.utils;
+
+import com.google.common.base.Predicate;
+
+/**
+ * {@link Predicate} that verifies that an {@link Integer} value is not
+ * {@code null} and is between a lower and an upper bound. Both bounds are
+ * inclusive.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class IntegerRangePredicate implements Predicate<Integer> {
+
+ /** The lower bound. */
+ private final int lowerBound;
+
+ /** The upper bound. */
+ private final int upperBound;
+
+ /**
+ * Creates a new integer range predicate.
+ *
+ * @param lowerBound
+ * The lower bound
+ * @param upperBound
+ * The upper bound
+ */
+ public IntegerRangePredicate(int lowerBound, int upperBound) {
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ }
+
+ //
+ // PREDICATE METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean apply(Integer value) {
+ return (value != null) && (value >= lowerBound) && (value <= upperBound);
+ }
+
+}
/*
- * Sone - AboutPage.java - Copyright © 2010–2012 David Roden
+ * Sone - AboutPage.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
/*
- * Sone - BookmarkPage.java - Copyright © 2011–2012 David Roden
+ * Sone - BookmarkPage.java - Copyright © 2011–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
/*
- * Sone - BookmarksPage.java - Copyright © 2011–2012 David Roden
+ * Sone - BookmarksPage.java - Copyright © 2011–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
package net.pterodactylus.sone.web;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.collection.Pagination;
-import net.pterodactylus.util.collection.filter.Filter;
-import net.pterodactylus.util.collection.filter.Filters;
import net.pterodactylus.util.number.Numbers;
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+
/**
* Page that lets the user browse all his bookmarked posts.
*
protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
Set<Post> allPosts = webInterface.getCore().getBookmarkedPosts();
- Set<Post> loadedPosts = Filters.filteredSet(allPosts, new Filter<Post>() {
+ Collection<Post> loadedPosts = Collections2.filter(allPosts, new Predicate<Post>() {
@Override
- public boolean filterObject(Post post) {
+ public boolean apply(Post post) {
return post.getSone() != null;
}
});
/*
- * Sone - CreateAlbumPage.java - Copyright © 2011–2012 David Roden
+ * Sone - CreateAlbumPage.java - Copyright © 2011–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
/*
- * Sone - CreatePostPage.java - Copyright © 2010–2012 David Roden
+ * Sone - CreatePostPage.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
package net.pterodactylus.sone.web;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.text.TextFilter;
if (sender == null) {
sender = currentSone;
}
- Sone recipient = webInterface.getCore().getSone(recipientId, false);
+ Optional<Sone> recipient = webInterface.getCore().getSone(recipientId);
text = TextFilter.filter(request.getHttpRequest().getHeader("host"), text);
webInterface.getCore().createPost(sender, recipient, System.currentTimeMillis(), text);
throw new RedirectException(returnPage);
/*
- * Sone - CreateReplyPage.java - Copyright © 2010–2012 David Roden
+ * Sone - CreateReplyPage.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
package net.pterodactylus.sone.web;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.text.TextFilter;
String text = request.getHttpRequest().getPartAsStringFailsafe("text", 65536).trim();
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
if (request.getMethod() == Method.POST) {
- Post post = webInterface.getCore().getPost(postId);
+ Optional<Post> post = webInterface.getCore().getPost(postId);
+ if (!post.isPresent()) {
+ throw new RedirectException("noPermission.html");
+ }
if (text.length() > 0) {
String senderId = request.getHttpRequest().getPartAsStringFailsafe("sender", 43);
Sone sender = webInterface.getCore().getLocalSone(senderId, false);
sender = getCurrentSone(request.getToadletContext());
}
text = TextFilter.filter(request.getHttpRequest().getHeader("host"), text);
- webInterface.getCore().createReply(sender, post, text);
+ webInterface.getCore().createReply(sender, post.get(), text);
throw new RedirectException(returnPage);
}
templateContext.set("errorTextEmpty", true);
/*
- * Sone - CreateSonePage.java - Copyright © 2010–2012 David Roden
+ * Sone - CreateSonePage.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
/*
- * Sone - DeleteAlbumPage.java - Copyright © 2011–2012 David Roden
+ * Sone - DeleteAlbumPage.java - Copyright © 2011–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
if (album == null) {
throw new RedirectException("invalid.html");
}
- if (!webInterface.getCore().isLocalSone(album.getSone())) {
+ if (!album.getSone().isLocal()) {
throw new RedirectException("noPermission.html");
}
if (request.getHttpRequest().isPartSet("abortDelete")) {
/*
- * Sone - DeleteImagePage.java - Copyright © 2011–2012 David Roden
+ * Sone - DeleteImagePage.java - Copyright © 2011–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
if (image == null) {
throw new RedirectException("invalid.html");
}
- if (!webInterface.getCore().isLocalSone(image.getSone())) {
+ if (!image.getSone().isLocal()) {
throw new RedirectException("noPermission.html");
}
if (request.getMethod() == Method.POST) {
/*
- * Sone - DeletePostPage.java - Copyright © 2010–2012 David Roden
+ * Sone - DeletePostPage.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
package net.pterodactylus.sone.web;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.template.Template;
if (request.getMethod() == Method.GET) {
String postId = request.getHttpRequest().getParam("post");
String returnPage = request.getHttpRequest().getParam("returnPage");
- Post post = webInterface.getCore().getPost(postId);
- templateContext.set("post", post);
+ Optional<Post> post = webInterface.getCore().getPost(postId);
+ if (!post.isPresent()) {
+ throw new RedirectException("noPermission.html");
+ }
+ templateContext.set("post", post.get());
templateContext.set("returnPage", returnPage);
return;
} else if (request.getMethod() == Method.POST) {
String postId = request.getHttpRequest().getPartAsStringFailsafe("post", 36);
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
- Post post = webInterface.getCore().getPost(postId);
- if (!webInterface.getCore().isLocalSone(post.getSone())) {
+ Optional<Post> post = webInterface.getCore().getPost(postId);
+ if (!post.isPresent() || !post.get().getSone().isLocal()) {
throw new RedirectException("noPermission.html");
}
if (request.getHttpRequest().isPartSet("confirmDelete")) {
- webInterface.getCore().deletePost(post);
+ webInterface.getCore().deletePost(post.get());
throw new RedirectException(returnPage);
} else if (request.getHttpRequest().isPartSet("abortDelete")) {
throw new RedirectException(returnPage);
/*
- * Sone - DeleteProfileFieldPage.java - Copyright © 2011–2012 David Roden
+ * Sone - DeleteProfileFieldPage.java - Copyright © 2011–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
/*
- * Sone - DeleteReplyPage.java - Copyright © 2010–2012 David Roden
+ * Sone - DeleteReplyPage.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
import net.pterodactylus.util.template.TemplateContext;
import net.pterodactylus.util.web.Method;
+import com.google.common.base.Optional;
+
/**
* This page lets the user delete a reply.
*
protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
String replyId = request.getHttpRequest().getPartAsStringFailsafe("reply", 36);
- PostReply reply = webInterface.getCore().getReply(replyId);
+ Optional<PostReply> reply = webInterface.getCore().getPostReply(replyId);
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
if (request.getMethod() == Method.POST) {
- if (!webInterface.getCore().isLocalSone(reply.getSone())) {
+ if (!reply.get().getSone().isLocal()) {
throw new RedirectException("noPermission.html");
}
if (request.getHttpRequest().isPartSet("confirmDelete")) {
- webInterface.getCore().deleteReply(reply);
+ webInterface.getCore().deleteReply(reply.get());
throw new RedirectException(returnPage);
} else if (request.getHttpRequest().isPartSet("abortDelete")) {
throw new RedirectException(returnPage);
/*
- * Sone - DeleteSonePage.java - Copyright © 2010–2012 David Roden
+ * Sone - DeleteSonePage.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
/*
- * Sone - DismissNotificationPage.java - Copyright © 2010–2012 David Roden
+ * Sone - DismissNotificationPage.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
/*
- * Sone - DistrustPage.java - Copyright © 2011–2012 David Roden
+ * Sone - DistrustPage.java - Copyright © 2011–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
package net.pterodactylus.sone.web;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.FreenetRequest;
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
String identity = request.getHttpRequest().getPartAsStringFailsafe("sone", 44);
Sone currentSone = getCurrentSone(request.getToadletContext());
- Sone sone = webInterface.getCore().getSone(identity, false);
- if (sone != null) {
- webInterface.getCore().distrustSone(currentSone, sone);
+ Optional<Sone> sone = webInterface.getCore().getSone(identity);
+ if (sone.isPresent()) {
+ webInterface.getCore().distrustSone(currentSone, sone.get());
}
throw new RedirectException(returnPage);
}
/*
- * Sone - EditAlbumPage.java - Copyright © 2011–2012 David Roden
+ * Sone - EditAlbumPage.java - Copyright © 2011–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
if (album == null) {
throw new RedirectException("invalid.html");
}
- if (!webInterface.getCore().isLocalSone(album.getSone())) {
+ if (!album.getSone().isLocal()) {
throw new RedirectException("noPermission.html");
}
if ("true".equals(request.getHttpRequest().getPartAsStringFailsafe("moveLeft", 4))) {
/*
- * FreenetSone - WebInterface.java - Copyright © 2010–2012 David Roden
+ * Sone - EditImagePage.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
if (image == null) {
throw new RedirectException("invalid.html");
}
- if (!webInterface.getCore().isLocalSone(image.getSone())) {
+ if (!image.getSone().isLocal()) {
throw new RedirectException("noPermission.html");
}
if ("true".equals(request.getHttpRequest().getPartAsStringFailsafe("moveLeft", 4))) {
image.getAlbum().moveImageUp(image);
- } else if ("true".equals(request.getHttpRequest().getPartAsStringFailsafe("moveRight", 4))) {
+ } else if ("true".equals(request.getHttpRequest().getPartAsStringFailsafe("moveRight", 4))) {
image.getAlbum().moveImageDown(image);
} else {
String title = request.getHttpRequest().getPartAsStringFailsafe("title", 100).trim();
/*
- * Sone - EditProfileFieldPage.java - Copyright © 2011–2012 David Roden
+ * Sone - EditProfileFieldPage.java - Copyright © 2011–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
/*
- * Sone - EditProfilePage.java - Copyright © 2010–2012 David Roden
+ * Sone - EditProfilePage.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
/*
- * Sone - FollowSonePage.java - Copyright © 2010–2012 David Roden
+ * Sone - FollowSonePage.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
package net.pterodactylus.sone.web;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.template.Template;
Sone currentSone = getCurrentSone(request.getToadletContext());
String soneIds = request.getHttpRequest().getPartAsStringFailsafe("sone", 1200);
for (String soneId : soneIds.split("[ ,]+")) {
- if (webInterface.getCore().hasSone(soneId)) {
+ Optional<Sone> sone = webInterface.getCore().getSone(soneId);
+ if (sone.isPresent()) {
webInterface.getCore().followSone(currentSone, soneId);
- webInterface.getCore().markSoneKnown(webInterface.getCore().getSone(soneId));
+ webInterface.getCore().markSoneKnown(sone.get());
}
}
throw new RedirectException(returnPage);
/*
- * Sone - GetImagePage.java - Copyright © 2011–2012 David Roden
+ * Sone - GetImagePage.java - Copyright © 2011–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
/*
- * Sone - ImageBrowserPage.java - Copyright © 2011–2012 David Roden
+ * Sone - ImageBrowserPage.java - Copyright © 2011–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
import java.util.Collections;
import java.util.List;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+
import net.pterodactylus.sone.data.Album;
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.data.Sone;
}
String soneId = request.getHttpRequest().getParam("sone", null);
if (soneId != null) {
- Sone sone = webInterface.getCore().getSone(soneId, false);
+ Optional<Sone> sone = webInterface.getCore().getSone(soneId);
templateContext.set("soneRequested", true);
- templateContext.set("sone", sone);
+ templateContext.set("sone", sone.orNull());
return;
}
String mode = request.getHttpRequest().getParam("mode", null);
templateContext.set("galleryRequested", true);
List<Album> albums = new ArrayList<Album>();
for (Sone sone : webInterface.getCore().getSones()) {
- albums.addAll(sone.getAllAlbums());
+ albums.addAll(FluentIterable.from(sone.getAlbums()).transformAndConcat(Album.FLATTENER).toList());
}
Collections.sort(albums, Album.TITLE_COMPARATOR);
Pagination<Album> albumPagination = new Pagination<Album>(albums, 12).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0));
/*
- * Sone - IndexPage.java - Copyright © 2010–2012 David Roden
+ * Sone - IndexPage.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
package net.pterodactylus.sone.web;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import net.pterodactylus.sone.notify.ListNotificationFilters;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.collection.Pagination;
-import net.pterodactylus.util.collection.filter.Filter;
-import net.pterodactylus.util.collection.filter.Filters;
import net.pterodactylus.util.number.Numbers;
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+
/**
* The index page shows the main page of Sone. This page will contain the posts
* of all friends of the current user.
protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
final Sone currentSone = getCurrentSone(request.getToadletContext());
- List<Post> allPosts = new ArrayList<Post>();
+ Collection<Post> allPosts = new ArrayList<Post>();
allPosts.addAll(currentSone.getPosts());
for (String friendSoneId : currentSone.getFriends()) {
- if (!webInterface.getCore().hasSone(friendSoneId)) {
+ Optional<Sone> friendSone = webInterface.getCore().getSone(friendSoneId);
+ if (!friendSone.isPresent()) {
continue;
}
- allPosts.addAll(webInterface.getCore().getSone(friendSoneId).getPosts());
+ allPosts.addAll(friendSone.get().getPosts());
}
for (Sone sone : webInterface.getCore().getSones()) {
for (Post post : sone.getPosts()) {
- if (currentSone.equals(post.getRecipient()) && !allPosts.contains(post)) {
+ if (currentSone.equals(post.getRecipient().orNull()) && !allPosts.contains(post)) {
allPosts.add(post);
}
}
}
- allPosts = Filters.filteredList(allPosts, new Filter<Post>() {
+ allPosts = Collections2.filter(allPosts, new Predicate<Post>() {
@Override
- public boolean filterObject(Post post) {
+ public boolean apply(Post post) {
return ListNotificationFilters.isPostVisible(currentSone, post);
}
});
- allPosts = Filters.filteredList(allPosts, Post.FUTURE_POSTS_FILTER);
- Collections.sort(allPosts, Post.TIME_COMPARATOR);
- Pagination<Post> pagination = new Pagination<Post>(allPosts, webInterface.getCore().getPreferences().getPostsPerPage()).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0));
+ allPosts = Collections2.filter(allPosts, Post.FUTURE_POSTS_FILTER);
+ List<Post> sortedPosts = new ArrayList<Post>(allPosts);
+ Collections.sort(sortedPosts, Post.TIME_COMPARATOR);
+ Pagination<Post> pagination = new Pagination<Post>(sortedPosts, webInterface.getCore().getPreferences().getPostsPerPage()).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0));
templateContext.set("pagination", pagination);
templateContext.set("posts", pagination.getItems());
}
/*
- * Sone - KnownSonesPage.java - Copyright © 2010–2012 David Roden
+ * Sone - KnownSonesPage.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
package net.pterodactylus.sone.web;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.collection.Pagination;
-import net.pterodactylus.util.collection.ReverseComparator;
-import net.pterodactylus.util.collection.filter.Filter;
-import net.pterodactylus.util.collection.filter.Filters;
import net.pterodactylus.util.number.Numbers;
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Ordering;
+
/**
* This page shows all known Sones.
*
templateContext.set("order", (sortOrder != null) ? sortOrder : "asc");
templateContext.set("filter", filter);
final Sone currentSone = getCurrentSone(request.getToadletContext(), false);
- List<Sone> knownSones = Filters.filteredList(new ArrayList<Sone>(webInterface.getCore().getSones()), Sone.EMPTY_SONE_FILTER);
+ Collection<Sone> knownSones = Collections2.filter(webInterface.getCore().getSones(), Sone.EMPTY_SONE_FILTER);
if ((currentSone != null) && "followed".equals(filter)) {
- knownSones = Filters.filteredList(knownSones, new Filter<Sone>() {
+ knownSones = Collections2.filter(knownSones, new Predicate<Sone>() {
@Override
- public boolean filterObject(Sone sone) {
+ public boolean apply(Sone sone) {
return currentSone.hasFriend(sone.getId());
}
});
} else if ((currentSone != null) && "not-followed".equals(filter)) {
- knownSones = Filters.filteredList(knownSones, new Filter<Sone>() {
+ knownSones = Collections2.filter(knownSones, new Predicate<Sone>() {
@Override
- public boolean filterObject(Sone sone) {
+ public boolean apply(Sone sone) {
return !currentSone.hasFriend(sone.getId());
}
});
} else if ("new".equals(filter)) {
- knownSones = Filters.filteredList(knownSones, new Filter<Sone>() {
+ knownSones = Collections2.filter(knownSones, new Predicate<Sone>() {
+
/**
* {@inheritDoc}
*/
@Override
- public boolean filterObject(Sone sone) {
+ public boolean apply(Sone sone) {
return !sone.isKnown();
}
});
} else if ("not-new".equals(filter)) {
- knownSones = Filters.filteredList(knownSones, new Filter<Sone>() {
+ knownSones = Collections2.filter(knownSones, new Predicate<Sone>() {
+
/**
* {@inheritDoc}
*/
@Override
- public boolean filterObject(Sone sone) {
+ public boolean apply(Sone sone) {
return sone.isKnown();
}
});
+ } else if ("own".equals(filter)) {
+ knownSones = Collections2.filter(knownSones, Sone.LOCAL_SONE_FILTER);
+ } else if ("not-own".equals(filter)) {
+ knownSones = Collections2.filter(knownSones, Predicates.not(Sone.LOCAL_SONE_FILTER));
}
+ List<Sone> sortedSones = new ArrayList<Sone>(knownSones);
if ("activity".equals(sortField)) {
if ("asc".equals(sortOrder)) {
- Collections.sort(knownSones, new ReverseComparator<Sone>(Sone.LAST_ACTIVITY_COMPARATOR));
+ Collections.sort(sortedSones, Ordering.from(Sone.LAST_ACTIVITY_COMPARATOR).reverse());
} else {
- Collections.sort(knownSones, Sone.LAST_ACTIVITY_COMPARATOR);
+ Collections.sort(sortedSones, Sone.LAST_ACTIVITY_COMPARATOR);
}
} else if ("posts".equals(sortField)) {
if ("asc".equals(sortOrder)) {
- Collections.sort(knownSones, new ReverseComparator<Sone>(Sone.POST_COUNT_COMPARATOR));
+ Collections.sort(sortedSones, Ordering.from(Sone.POST_COUNT_COMPARATOR).reverse());
} else {
- Collections.sort(knownSones, Sone.POST_COUNT_COMPARATOR);
+ Collections.sort(sortedSones, Sone.POST_COUNT_COMPARATOR);
}
} else if ("images".equals(sortField)) {
if ("asc".equals(sortOrder)) {
- Collections.sort(knownSones, new ReverseComparator<Sone>(Sone.IMAGE_COUNT_COMPARATOR));
+ Collections.sort(sortedSones, Ordering.from(Sone.IMAGE_COUNT_COMPARATOR).reverse());
} else {
- Collections.sort(knownSones, Sone.IMAGE_COUNT_COMPARATOR);
+ Collections.sort(sortedSones, Sone.IMAGE_COUNT_COMPARATOR);
}
} else {
if ("desc".equals(sortOrder)) {
- Collections.sort(knownSones, new ReverseComparator<Sone>(Sone.NICE_NAME_COMPARATOR));
+ Collections.sort(sortedSones, Ordering.from(Sone.NICE_NAME_COMPARATOR).reverse());
} else {
- Collections.sort(knownSones, Sone.NICE_NAME_COMPARATOR);
+ Collections.sort(sortedSones, Sone.NICE_NAME_COMPARATOR);
}
}
- Pagination<Sone> sonePagination = new Pagination<Sone>(knownSones, 25).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0));
+ Pagination<Sone> sonePagination = new Pagination<Sone>(sortedSones, 25).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0));
templateContext.set("pagination", sonePagination);
templateContext.set("knownSones", sonePagination.getItems());
}
/*
- * Sone - LikePage.java - Copyright © 2010–2012 David Roden
+ * Sone - LikePage.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
/*
- * Sone - LockSonePage.java - Copyright © 2010–2012 David Roden
+ * Sone - LockSonePage.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
/*
- * Sone - LoginPage.java - Copyright © 2010–2012 David Roden
+ * Sone - LoginPage.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
/*
- * Sone - LogoutPage.java - Copyright © 2010–2012 David Roden
+ * Sone - LogoutPage.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
/*
- * Sone - MarkAsKnownPage.java - Copyright © 2011–2012 David Roden
+ * Sone - MarkAsKnownPage.java - Copyright © 2011–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
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
+import com.google.common.base.Optional;
+
/**
* Page that lets the user mark a number of {@link Sone}s, {@link Post}s, or
* {@link Reply Replie}s as known.
for (StringTokenizer idTokenizer = new StringTokenizer(ids); idTokenizer.hasMoreTokens();) {
String id = idTokenizer.nextToken();
if (type.equals("post")) {
- Post post = webInterface.getCore().getPost(id, false);
- if (post == null) {
+ Optional<Post> post = webInterface.getCore().getPost(id);
+ if (!post.isPresent()) {
continue;
}
- webInterface.getCore().markPostKnown(post);
+ webInterface.getCore().markPostKnown(post.get());
} else if (type.equals("reply")) {
- PostReply reply = webInterface.getCore().getReply(id, false);
- if (reply == null) {
+ Optional<PostReply> reply = webInterface.getCore().getPostReply(id);
+ if (!reply.isPresent()) {
continue;
}
- webInterface.getCore().markReplyKnown(reply);
+ webInterface.getCore().markReplyKnown(reply.get());
} else if (type.equals("sone")) {
- Sone sone = webInterface.getCore().getSone(id, false);
- if (sone == null) {
+ Optional<Sone> sone = webInterface.getCore().getSone(id);
+ if (!sone.isPresent()) {
continue;
}
- webInterface.getCore().markSoneKnown(sone);
+ webInterface.getCore().markSoneKnown(sone.get());
}
}
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
/*
- * Sone - NewPage.java - Copyright © 2012 David Roden
+ * Sone - NewPage.java - Copyright © 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
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import com.google.common.collect.Collections2;
+
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.PostReply;
import net.pterodactylus.sone.notify.ListNotificationFilters;
//
/**
- * {@inherit}
+ * {@inheritDoc}
*/
@Override
protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
/* collect new elements from notifications. */
- Set<Post> posts = webInterface.getNewPosts();
- for (PostReply reply : webInterface.getNewReplies()) {
- posts.add(reply.getPost());
+ Set<Post> posts = new HashSet<Post>(webInterface.getNewPosts());
+ for (PostReply reply : Collections2.filter(webInterface.getNewReplies(), PostReply.HAS_POST_FILTER)) {
+ posts.add(reply.getPost().get());
}
/* filter and sort them. */
/*
- * Sone - OptionsPage.java - Copyright © 2010–2012 David Roden
+ * Sone - OptionsPage.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
import java.util.ArrayList;
import java.util.List;
-import net.pterodactylus.sone.core.Core.Preferences;
+import net.pterodactylus.sone.core.Preferences;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.data.Sone.ShowCustomAvatars;
import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
/*
- * Sone - RescuePage.java - Copyright © 2011–2012 David Roden
+ * Sone - RescuePage.java - Copyright © 2011–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
/*
- * Sone - SearchPage.java - Copyright © 2010–2012 David Roden
+ * Sone - SearchPage.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
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.pterodactylus.sone.data.Reply;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.FreenetRequest;
-import net.pterodactylus.util.cache.Cache;
-import net.pterodactylus.util.cache.CacheException;
-import net.pterodactylus.util.cache.CacheItem;
-import net.pterodactylus.util.cache.DefaultCacheItem;
-import net.pterodactylus.util.cache.MemoryCache;
-import net.pterodactylus.util.cache.ValueRetriever;
import net.pterodactylus.util.collection.Pagination;
-import net.pterodactylus.util.collection.TimedMap;
-import net.pterodactylus.util.collection.filter.Filter;
-import net.pterodactylus.util.collection.filter.Filters;
-import net.pterodactylus.util.collection.mapper.Mapper;
-import net.pterodactylus.util.collection.mapper.Mappers;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.number.Numbers;
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.text.StringEscaper;
import net.pterodactylus.util.text.TextException;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Ordering;
+
/**
* This page lets the user search for posts and replies that contain certain
* words.
private static final Logger logger = Logging.getLogger(SearchPage.class);
/** Short-term cache. */
- private final Cache<List<Phrase>, Set<Hit<Post>>> hitCache = new MemoryCache<List<Phrase>, Set<Hit<Post>>>(new ValueRetriever<List<Phrase>, Set<Hit<Post>>>() {
+ private final LoadingCache<List<Phrase>, Set<Hit<Post>>> hitCache = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build(new CacheLoader<List<Phrase>, Set<Hit<Post>>>() {
@Override
@SuppressWarnings("synthetic-access")
- public CacheItem<Set<Hit<Post>>> retrieve(List<Phrase> phrases) throws CacheException {
+ public Set<Hit<Post>> load(List<Phrase> phrases) {
Set<Post> posts = new HashSet<Post>();
for (Sone sone : webInterface.getCore().getSones()) {
posts.addAll(sone.getPosts());
}
- return new DefaultCacheItem<Set<Hit<Post>>>(getHits(Filters.filteredSet(posts, Post.FUTURE_POSTS_FILTER), phrases, new PostStringGenerator()));
+ return getHits(Collections2.filter(posts, Post.FUTURE_POSTS_FILTER), phrases, new PostStringGenerator());
}
-
- }, new TimedMap<List<Phrase>, CacheItem<Set<Hit<Post>>>>(300000));
+ });
/**
* Creates a new search page.
* {@inheritDoc}
*/
@Override
+ @SuppressWarnings("synthetic-access")
protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
String query = request.getHttpRequest().getParam("query").trim();
redirectIfNotNull(getImageId(phrase), "imageBrowser.html?image=");
}
- Set<Sone> sones = webInterface.getCore().getSones();
- Set<Hit<Sone>> soneHits = getHits(sones, phrases, SoneStringGenerator.COMPLETE_GENERATOR);
+ Collection<Sone> sones = webInterface.getCore().getSones();
+ Collection<Hit<Sone>> soneHits = getHits(sones, phrases, SoneStringGenerator.COMPLETE_GENERATOR);
- Set<Hit<Post>> postHits;
- try {
- postHits = hitCache.get(phrases);
- } catch (CacheException ce1) {
- /* should never happen. */
- logger.log(Level.SEVERE, "Could not get search results from cache!", ce1);
- postHits = Collections.emptySet();
- }
+ Collection<Hit<Post>> postHits = hitCache.getUnchecked(phrases);
/* now filter. */
- soneHits = Filters.filteredSet(soneHits, Hit.POSITIVE_FILTER);
- postHits = Filters.filteredSet(postHits, Hit.POSITIVE_FILTER);
+ soneHits = Collections2.filter(soneHits, Hit.POSITIVE_FILTER);
+ postHits = Collections2.filter(postHits, Hit.POSITIVE_FILTER);
/* now sort. */
- List<Hit<Sone>> sortedSoneHits = new ArrayList<Hit<Sone>>(soneHits);
- Collections.sort(sortedSoneHits, Hit.DESCENDING_COMPARATOR);
- List<Hit<Post>> sortedPostHits = new ArrayList<Hit<Post>>(postHits);
- Collections.sort(sortedPostHits, Hit.DESCENDING_COMPARATOR);
+ List<Hit<Sone>> sortedSoneHits = Ordering.from(Hit.DESCENDING_COMPARATOR).sortedCopy(soneHits);
+ List<Hit<Post>> sortedPostHits = Ordering.from(Hit.DESCENDING_COMPARATOR).sortedCopy(postHits);
/* extract Sones and posts. */
- List<Sone> resultSones = Mappers.mappedList(sortedSoneHits, new HitMapper<Sone>());
- List<Post> resultPosts = Mappers.mappedList(sortedPostHits, new HitMapper<Post>());
+ List<Sone> resultSones = FluentIterable.from(sortedSoneHits).transform(new HitMapper<Sone>()).toList();
+ List<Post> resultPosts = FluentIterable.from(sortedPostHits).transform(new HitMapper<Post>()).toList();
/* pagination. */
Pagination<Sone> sonePagination = new Pagination<Sone>(resultSones, webInterface.getCore().getPreferences().getPostsPerPage()).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("sonePage"), 0));
*/
private String getSoneId(String phrase) {
String soneId = phrase.startsWith("sone://") ? phrase.substring(7) : phrase;
- return (webInterface.getCore().getSone(soneId, false) != null) ? soneId : null;
+ return (webInterface.getCore().getSone(soneId).isPresent()) ? soneId : null;
}
/**
*/
private String getPostId(String phrase) {
String postId = phrase.startsWith("post://") ? phrase.substring(7) : phrase;
- return (webInterface.getCore().getPost(postId, false) != null) ? postId : null;
+ return (webInterface.getCore().getPost(postId).isPresent()) ? postId : null;
}
/**
*/
private String getReplyPostId(String phrase) {
String replyId = phrase.startsWith("reply://") ? phrase.substring(8) : phrase;
- return (webInterface.getCore().getReply(replyId, false) != null) ? webInterface.getCore().getReply(replyId, false).getPost().getId() : null;
+ Optional<PostReply> postReply = webInterface.getCore().getPostReply(replyId);
+ if (!postReply.isPresent()) {
+ return null;
+ }
+ return postReply.get().getPostId();
}
/**
public String generateString(Post post) {
StringBuilder postString = new StringBuilder();
postString.append(post.getText());
- if (post.getRecipient() != null) {
- postString.append(' ').append(SoneStringGenerator.NAME_GENERATOR.generateString(post.getRecipient()));
+ if (post.getRecipient().isPresent()) {
+ postString.append(' ').append(SoneStringGenerator.NAME_GENERATOR.generateString(post.getRecipient().get()));
}
- for (PostReply reply : Filters.filteredList(webInterface.getCore().getReplies(post), Reply.FUTURE_REPLY_FILTER)) {
+ for (PostReply reply : Collections2.filter(webInterface.getCore().getReplies(post.getId()), Reply.FUTURE_REPLY_FILTER)) {
postString.append(' ').append(SoneStringGenerator.NAME_GENERATOR.generateString(reply.getSone()));
postString.append(' ').append(reply.getText());
}
private static class Hit<T> {
/** Filter for {@link Hit}s with a score of more than 0. */
- public static final Filter<Hit<?>> POSITIVE_FILTER = new Filter<Hit<?>>() {
+ public static final Predicate<Hit<?>> POSITIVE_FILTER = new Predicate<Hit<?>>() {
@Override
- public boolean filterObject(Hit<?> hit) {
+ public boolean apply(Hit<?> hit) {
return hit.getScore() > 0;
}
* The type of the object to extract
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
- public static class HitMapper<T> implements Mapper<Hit<T>, T> {
+ private static class HitMapper<T> implements Function<Hit<T>, T> {
/**
* {@inheritDoc}
*/
@Override
- public T map(Hit<T> input) {
+ public T apply(Hit<T> input) {
return input.getObject();
}
/*
- * Sone - SoneTemplatePage.java - Copyright © 2010–2012 David Roden
+ * Sone - SoneTemplatePage.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
import net.pterodactylus.sone.notify.ListNotificationFilters;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.sone.web.page.FreenetTemplatePage;
-import net.pterodactylus.util.collection.ListBuilder;
-import net.pterodactylus.util.collection.MapBuilder;
import net.pterodactylus.util.notify.Notification;
-import net.pterodactylus.util.object.HashCode;
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
import freenet.clients.http.SessionManager.Session;
import freenet.clients.http.ToadletContext;
import freenet.support.api.HTTPRequest;
*/
@Override
protected List<Map<String, String>> getAdditionalLinkNodes(FreenetRequest request) {
- return new ListBuilder<Map<String, String>>().add(new MapBuilder<String, String>().put("rel", "search").put("type", "application/opensearchdescription+xml").put("title", "Sone").put("href", "http://" + request.getHttpRequest().getHeader("host") + "/Sone/OpenSearch.xml").get()).get();
+ return ImmutableList.<Map<String, String>> builder().add(ImmutableMap.<String, String> builder().put("rel", "search").put("type", "application/opensearchdescription+xml").put("title", "Sone").put("href", "http://" + request.getHttpRequest().getHeader("host") + "/Sone/OpenSearch.xml").build()).build();
}
/**
List<Notification> notifications = ListNotificationFilters.filterNotifications(webInterface.getNotifications().getNotifications(), currentSone);
Collections.sort(notifications, Notification.CREATED_TIME_SORTER);
templateContext.set("notifications", notifications);
- templateContext.set("notificationHash", HashCode.hashCode(notifications));
+ templateContext.set("notificationHash", notifications.hashCode());
}
/**
/*
- * Sone - TrustPage.java - Copyright © 2011–2012 David Roden
+ * Sone - TrustPage.java - Copyright © 2011–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
package net.pterodactylus.sone.web;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.FreenetRequest;
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
String identity = request.getHttpRequest().getPartAsStringFailsafe("sone", 44);
Sone currentSone = getCurrentSone(request.getToadletContext());
- Sone sone = webInterface.getCore().getSone(identity, false);
- if (sone != null) {
- webInterface.getCore().trustSone(currentSone, sone);
+ Optional<Sone> sone = webInterface.getCore().getSone(identity);
+ if (sone.isPresent()) {
+ webInterface.getCore().trustSone(currentSone, sone.get());
}
throw new RedirectException(returnPage);
}
/*
- * Sone - UnbookmarkPage.java - Copyright © 2011–2012 David Roden
+ * Sone - UnbookmarkPage.java - Copyright © 2011–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
/*
- * Sone - UnfollowSonePage.java - Copyright © 2010–2012 David Roden
+ * Sone - UnfollowSonePage.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
/*
- * Sone - UnlikePage.java - Copyright © 2010–2012 David Roden
+ * Sone - UnlikePage.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
/*
- * Sone - UnlockSonePage.java - Copyright © 2010–2012 David Roden
+ * Sone - UnlockSonePage.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
/*
- * Sone - UntrustPage.java - Copyright © 2011–2012 David Roden
+ * Sone - UntrustPage.java - Copyright © 2011–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
package net.pterodactylus.sone.web;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.FreenetRequest;
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
String identity = request.getHttpRequest().getPartAsStringFailsafe("sone", 44);
Sone currentSone = getCurrentSone(request.getToadletContext());
- Sone sone = webInterface.getCore().getSone(identity, false);
- if (sone != null) {
- webInterface.getCore().untrustSone(currentSone, sone);
+ Optional<Sone> sone = webInterface.getCore().getSone(identity);
+ if (sone.isPresent()) {
+ webInterface.getCore().untrustSone(currentSone, sone.get());
}
throw new RedirectException(returnPage);
}
/*
- * Sone - UploadImagePage.java - Copyright © 2011–2012 David Roden
+ * Sone - UploadImagePage.java - Copyright © 2011–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
import net.pterodactylus.sone.text.TextFilter;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.io.Closer;
-import net.pterodactylus.util.io.StreamCopier;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
import net.pterodactylus.util.web.Method;
+
+import com.google.common.io.ByteStreams;
+
import freenet.support.api.Bucket;
import freenet.support.api.HTTPUploadedFile;
imageInputStream = fileBucket.getInputStream();
/* TODO - check length */
imageDataOutputStream = new ByteArrayOutputStream((int) fileBucket.size());
- StreamCopier.copy(imageInputStream, imageDataOutputStream);
+ ByteStreams.copy(imageInputStream, imageDataOutputStream);
} catch (IOException ioe1) {
logger.log(Level.WARNING, "Could not read uploaded image!", ioe1);
return;
/*
- * Sone - ViewPostPage.java - Copyright © 2010–2012 David Roden
+ * Sone - ViewPostPage.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
import java.net.URI;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.template.SoneAccessor;
import net.pterodactylus.sone.web.page.FreenetRequest;
@Override
protected String getPageTitle(FreenetRequest request) {
String postId = request.getHttpRequest().getParam("post");
- Post post = webInterface.getCore().getPost(postId, false);
+ Optional<Post> post = webInterface.getCore().getPost(postId);
String title = "";
- if ((post != null) && (post.getSone() != null)) {
- title = post.getText().substring(0, Math.min(20, post.getText().length())) + "…";
- title += " - " + SoneAccessor.getNiceName(post.getSone()) + " - ";
+ if (post.isPresent()) {
+ title = post.get().getText().substring(0, Math.min(20, post.get().getText().length())) + "…";
+ title += " - " + SoneAccessor.getNiceName(post.get().getSone()) + " - ";
}
title += webInterface.getL10n().getString("Page.ViewPost.Title");
return title;
super.processTemplate(request, templateContext);
String postId = request.getHttpRequest().getParam("post");
boolean raw = request.getHttpRequest().getParam("raw").equals("true");
- Post post = webInterface.getCore().getPost(postId);
- templateContext.set("post", post);
+ Optional<Post> post = webInterface.getCore().getPost(postId);
+ templateContext.set("post", post.orNull());
templateContext.set("raw", raw);
}
/*
- * Sone - ViewSonePage.java - Copyright © 2010–2012 David Roden
+ * Sone - ViewSonePage.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
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
+import com.google.common.base.Optional;
+
/**
* Lets the user browser another Sone.
*
@Override
protected String getPageTitle(FreenetRequest request) {
String soneId = request.getHttpRequest().getParam("sone");
- Sone sone = webInterface.getCore().getSone(soneId, false);
- if ((sone != null) && (sone.getTime() > 0)) {
- String soneName = SoneAccessor.getNiceName(sone);
+ Optional<Sone> sone = webInterface.getCore().getSone(soneId);
+ if (sone.isPresent()) {
+ String soneName = SoneAccessor.getNiceName(sone.get());
return soneName + " - " + webInterface.getL10n().getString("Page.ViewSone.Title");
}
return webInterface.getL10n().getString("Page.ViewSone.Page.TitleWithoutSone");
protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
String soneId = request.getHttpRequest().getParam("sone");
- Sone sone = webInterface.getCore().getSone(soneId, false);
- templateContext.set("sone", sone);
+ Optional<Sone> sone = webInterface.getCore().getSone(soneId);
+ templateContext.set("sone", sone.orNull());
templateContext.set("soneId", soneId);
- if (sone == null) {
+ if (!sone.isPresent()) {
return;
}
- List<Post> sonePosts = sone.getPosts();
- sonePosts.addAll(webInterface.getCore().getDirectedPosts(sone));
+ List<Post> sonePosts = sone.get().getPosts();
+ sonePosts.addAll(webInterface.getCore().getDirectedPosts(sone.get().getId()));
Collections.sort(sonePosts, Post.TIME_COMPARATOR);
Pagination<Post> postPagination = new Pagination<Post>(sonePosts, webInterface.getCore().getPreferences().getPostsPerPage()).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("postPage"), 0));
templateContext.set("postPagination", postPagination);
templateContext.set("posts", postPagination.getItems());
- Set<PostReply> replies = sone.getReplies();
+ Set<PostReply> replies = sone.get().getReplies();
final Map<Post, List<PostReply>> repliedPosts = new HashMap<Post, List<PostReply>>();
for (PostReply reply : replies) {
- Post post = reply.getPost();
- if (repliedPosts.containsKey(post) || sone.equals(post.getSone()) || (sone.equals(post.getRecipient()))) {
+ Optional<Post> post = reply.getPost();
+ if (!post.isPresent() || repliedPosts.containsKey(post.get()) || sone.get().equals(post.get().getSone()) || (sone.get().getId().equals(post.get().getRecipientId().orNull()))) {
continue;
}
- repliedPosts.put(post, webInterface.getCore().getReplies(post));
+ repliedPosts.put(post.get(), webInterface.getCore().getReplies(post.get().getId()));
}
List<Post> posts = new ArrayList<Post>(repliedPosts.keySet());
Collections.sort(posts, new Comparator<Post>() {
/*
- * Sone - WebInterface.java - Copyright © 2010–2012 David Roden
+ * Sone - WebInterface.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
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.pterodactylus.sone.core.Core;
-import net.pterodactylus.sone.core.CoreListener;
+import net.pterodactylus.sone.core.event.ImageInsertAbortedEvent;
+import net.pterodactylus.sone.core.event.ImageInsertFailedEvent;
+import net.pterodactylus.sone.core.event.ImageInsertFinishedEvent;
+import net.pterodactylus.sone.core.event.ImageInsertStartedEvent;
+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.SoneInsertAbortedEvent;
+import net.pterodactylus.sone.core.event.SoneInsertedEvent;
+import net.pterodactylus.sone.core.event.SoneInsertingEvent;
+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.core.event.UpdateFoundEvent;
import net.pterodactylus.sone.data.Album;
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.sone.web.page.PageToadlet;
import net.pterodactylus.sone.web.page.PageToadletFactory;
-import net.pterodactylus.util.collection.SetBuilder;
-import net.pterodactylus.util.collection.filter.Filters;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.notify.Notification;
import net.pterodactylus.util.notify.NotificationManager;
import net.pterodactylus.util.template.TemplateParser;
import net.pterodactylus.util.template.TemplateProvider;
import net.pterodactylus.util.template.XmlFilter;
-import net.pterodactylus.util.thread.Ticker;
-import net.pterodactylus.util.version.Version;
import net.pterodactylus.util.web.RedirectPage;
import net.pterodactylus.util.web.StaticPage;
import net.pterodactylus.util.web.TemplatePage;
+
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+
import freenet.clients.http.SessionManager;
import freenet.clients.http.SessionManager.Session;
import freenet.clients.http.ToadletContainer;
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
-public class WebInterface implements CoreListener {
+public class WebInterface {
/** The logger. */
private static final Logger logger = Logging.getLogger(WebInterface.class);
private final Map<Sone, TemplateNotification> soneInsertNotifications = new HashMap<Sone, TemplateNotification>();
/** Sone locked notification ticker objects. */
- private final Map<Sone, Object> lockedSonesTickerObjects = Collections.synchronizedMap(new HashMap<Sone, Object>());
+ private final Map<Sone, ScheduledFuture<?>> lockedSonesTickerObjects = Collections.synchronizedMap(new HashMap<Sone, ScheduledFuture<?>>());
/** The “Sone locked” notification. */
private final ListNotification<Sone> lockedSonesNotification;
/** The “image insert failed” notification. */
private final ListNotification<Image> imageInsertFailedNotification;
+ /** Scheduled executor for time-based notifications. */
+ private final ScheduledExecutorService ticker = Executors.newScheduledThreadPool(1);
+
/**
* Creates a new web interface.
*
* @param sonePlugin
* The Sone plugin
*/
+ @Inject
public WebInterface(SonePlugin sonePlugin) {
this.sonePlugin = sonePlugin;
formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword();
* currently logged in
*/
public Sone getCurrentSone(ToadletContext toadletContext, boolean create) {
- Set<Sone> localSones = getCore().getLocalSones();
+ Collection<Sone> localSones = getCore().getLocalSones();
if (localSones.size() == 1) {
return localSones.iterator().next();
}
* @return The new posts
*/
public Set<Post> getNewPosts() {
- return new SetBuilder<Post>().addAll(newPostNotification.getElements()).addAll(localPostNotification.getElements()).get();
+ return ImmutableSet.<Post> builder().addAll(newPostNotification.getElements()).addAll(localPostNotification.getElements()).build();
}
/**
* @return The new replies
*/
public Set<PostReply> getNewReplies() {
- return new SetBuilder<PostReply>().addAll(newReplyNotification.getElements()).addAll(localReplyNotification.getElements()).get();
+ return ImmutableSet.<PostReply> builder().addAll(newReplyNotification.getElements()).addAll(localReplyNotification.getElements()).build();
}
/**
final TemplateNotification startupNotification = new TemplateNotification("startup-notification", startupNotificationTemplate);
notificationManager.addNotification(startupNotification);
- Ticker.getInstance().registerEvent(System.currentTimeMillis() + (120 * 1000), new Runnable() {
+ ticker.schedule(new Runnable() {
@Override
public void run() {
startupNotification.dismiss();
}
- }, "Sone Startup Notification Remover");
+ }, 2, TimeUnit.MINUTES);
Template wotMissingNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/wotMissingNotification.html"));
final TemplateNotification wotMissingNotification = new TemplateNotification("wot-missing-notification", wotMissingNotificationTemplate);
- Ticker.getInstance().registerEvent(System.currentTimeMillis() + (15 * 1000), new Runnable() {
+ ticker.scheduleAtFixedRate(new Runnable() {
@Override
@SuppressWarnings("synthetic-access")
} else {
notificationManager.addNotification(wotMissingNotification);
}
- Ticker.getInstance().registerEvent(System.currentTimeMillis() + (15 * 1000), this, "Sone WoT Connector Checker");
}
- }, "Sone WoT Connector Checker");
+ }, 15, 15, TimeUnit.SECONDS);
}
/**
*/
public void stop() {
unregisterToadlets();
- Ticker.getInstance().stop();
+ ticker.shutdownNow();
}
//
}
/**
- * Returns all {@link Core#isLocalSone(Sone) local Sone}s that are
- * referenced by {@link SonePart}s in the given text (after parsing it using
+ * Returns all {@link Sone#isLocal() local Sone}s that are referenced by
+ * {@link SonePart}s in the given text (after parsing it using
* {@link SoneTextParser}).
*
* @param text
* The text to parse
* @return All mentioned local Sones
*/
- private Set<Sone> getMentionedSones(String text) {
+ private Collection<Sone> getMentionedSones(String text) {
/* we need no context to find mentioned Sones. */
Set<Sone> mentionedSones = new HashSet<Sone>();
try {
} catch (IOException ioe1) {
logger.log(Level.WARNING, String.format("Could not parse post text: %s", text), ioe1);
}
- return Filters.filteredSet(mentionedSones, Sone.LOCAL_SONE_FILTER);
+ return Collections2.filter(mentionedSones, Sone.LOCAL_SONE_FILTER);
}
/**
}
//
- // CORELISTENER METHODS
+ // EVENT HANDLERS
//
/**
- * {@inheritDoc}
+ * Notifies the web interface that a new {@link Sone} was found.
+ *
+ * @param newSoneFoundEvent
+ * The event
*/
- @Override
- public void newSoneFound(Sone sone) {
- newSoneNotification.add(sone);
+ @Subscribe
+ public void newSoneFound(NewSoneFoundEvent newSoneFoundEvent) {
+ newSoneNotification.add(newSoneFoundEvent.sone());
if (!hasFirstStartNotification()) {
notificationManager.addNotification(newSoneNotification);
}
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a new {@link Post} was found.
+ *
+ * @param newPostFoundEvent
+ * The event
*/
- @Override
- public void newPostFound(Post post) {
- boolean isLocal = getCore().isLocalSone(post.getSone());
+ @Subscribe
+ public void newPostFound(NewPostFoundEvent newPostFoundEvent) {
+ Post post = newPostFoundEvent.post();
+ boolean isLocal = post.getSone().isLocal();
if (isLocal) {
localPostNotification.add(post);
} else {
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a new {@link PostReply} was found.
+ *
+ * @param newPostReplyFoundEvent
+ * The event
*/
- @Override
- public void newReplyFound(PostReply reply) {
- boolean isLocal = getCore().isLocalSone(reply.getSone());
+ @Subscribe
+ public void newReplyFound(NewPostReplyFoundEvent newPostReplyFoundEvent) {
+ PostReply reply = newPostReplyFoundEvent.postReply();
+ boolean isLocal = reply.getSone().isLocal();
if (isLocal) {
localReplyNotification.add(reply);
} else {
}
if (!hasFirstStartNotification()) {
notificationManager.addNotification(isLocal ? localReplyNotification : newReplyNotification);
- if (!getMentionedSones(reply.getText()).isEmpty() && !isLocal && (reply.getPost().getSone() != null) && (reply.getTime() <= System.currentTimeMillis())) {
- mentionNotification.add(reply.getPost());
+ if (!getMentionedSones(reply.getText()).isEmpty() && !isLocal && reply.getPost().isPresent() && (reply.getTime() <= System.currentTimeMillis())) {
+ mentionNotification.add(reply.getPost().get());
notificationManager.addNotification(mentionNotification);
}
} else {
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a {@link Sone} was marked as known.
+ *
+ * @param markSoneKnownEvent
+ * The event
*/
- @Override
- public void markSoneKnown(Sone sone) {
- newSoneNotification.remove(sone);
+ @Subscribe
+ public void markSoneKnown(MarkSoneKnownEvent markSoneKnownEvent) {
+ newSoneNotification.remove(markSoneKnownEvent.sone());
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a {@link Post} was marked as known.
+ *
+ * @param markPostKnownEvent
+ * The event
*/
- @Override
- public void markPostKnown(Post post) {
- newPostNotification.remove(post);
- localPostNotification.remove(post);
- mentionNotification.remove(post);
+ @Subscribe
+ public void markPostKnown(MarkPostKnownEvent markPostKnownEvent) {
+ newPostNotification.remove(markPostKnownEvent.post());
+ localPostNotification.remove(markPostKnownEvent.post());
+ mentionNotification.remove(markPostKnownEvent.post());
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a {@link PostReply} was marked as known.
+ *
+ * @param markPostReplyKnownEvent
+ * The event
*/
- @Override
- public void markReplyKnown(PostReply reply) {
- newReplyNotification.remove(reply);
- localReplyNotification.remove(reply);
- mentionNotification.remove(reply.getPost());
+ @Subscribe
+ public void markReplyKnown(MarkPostReplyKnownEvent markPostReplyKnownEvent) {
+ newReplyNotification.remove(markPostReplyKnownEvent.postReply());
+ localReplyNotification.remove(markPostReplyKnownEvent.postReply());
+ mentionNotification.remove(markPostReplyKnownEvent.postReply().getPost().get());
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a {@link Sone} was removed.
+ *
+ * @param soneRemovedEvent
+ * The event
*/
- @Override
- public void soneRemoved(Sone sone) {
- newSoneNotification.remove(sone);
+ @Subscribe
+ public void soneRemoved(SoneRemovedEvent soneRemovedEvent) {
+ newSoneNotification.remove(soneRemovedEvent.sone());
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a {@link Post} was removed.
+ *
+ * @param postRemovedEvent
+ * The event
*/
- @Override
- public void postRemoved(Post post) {
- newPostNotification.remove(post);
- localPostNotification.remove(post);
- mentionNotification.remove(post);
+ @Subscribe
+ public void postRemoved(PostRemovedEvent postRemovedEvent) {
+ newPostNotification.remove(postRemovedEvent.post());
+ localPostNotification.remove(postRemovedEvent.post());
+ mentionNotification.remove(postRemovedEvent.post());
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a {@link PostReply} was removed.
+ *
+ * @param postReplyRemovedEvent
+ * The event
*/
- @Override
- public void replyRemoved(PostReply reply) {
+ @Subscribe
+ public void replyRemoved(PostReplyRemovedEvent postReplyRemovedEvent) {
+ PostReply reply = postReplyRemovedEvent.postReply();
newReplyNotification.remove(reply);
localReplyNotification.remove(reply);
- if (!getMentionedSones(reply.getText()).isEmpty()) {
+ if (!getMentionedSones(reply.getText()).isEmpty() && reply.getPost().isPresent()) {
boolean isMentioned = false;
- for (PostReply existingReply : getCore().getReplies(reply.getPost())) {
+ for (PostReply existingReply : getCore().getReplies(reply.getPostId())) {
isMentioned |= !reply.isKnown() && !getMentionedSones(existingReply.getText()).isEmpty();
}
if (!isMentioned) {
- mentionNotification.remove(reply.getPost());
+ mentionNotification.remove(reply.getPost().get());
}
}
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a Sone was locked.
+ *
+ * @param soneLockedEvent
+ * The event
*/
- @Override
- public void soneLocked(final Sone sone) {
- Object tickerObject = Ticker.getInstance().registerEvent(System.currentTimeMillis() + (5 * 60) * 1000, new Runnable() {
+ @Subscribe
+ public void soneLocked(SoneLockedEvent soneLockedEvent) {
+ final Sone sone = soneLockedEvent.sone();
+ ScheduledFuture<?> tickerObject = ticker.schedule(new Runnable() {
@Override
@SuppressWarnings("synthetic-access")
public void run() {
lockedSonesNotification.add(sone);
- lockedSonesTickerObjects.remove(sone);
notificationManager.addNotification(lockedSonesNotification);
}
- }, "Sone Locked Notification");
+ }, 5, TimeUnit.MINUTES);
lockedSonesTickerObjects.put(sone, tickerObject);
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a Sone was unlocked.
+ *
+ * @param soneUnlockedEvent
+ * The event
*/
- @Override
- public void soneUnlocked(Sone sone) {
- lockedSonesNotification.remove(sone);
- Ticker.getInstance().deregisterEvent(lockedSonesTickerObjects.remove(sone));
+ @Subscribe
+ public void soneUnlocked(SoneUnlockedEvent soneUnlockedEvent) {
+ lockedSonesNotification.remove(soneUnlockedEvent.sone());
+ lockedSonesTickerObjects.remove(soneUnlockedEvent.sone()).cancel(false);
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a {@link Sone} is being inserted.
+ *
+ * @param soneInsertingEvent
+ * The event
*/
- @Override
- public void soneInserting(Sone sone) {
- TemplateNotification soneInsertNotification = getSoneInsertNotification(sone);
+ @Subscribe
+ public void soneInserting(SoneInsertingEvent soneInsertingEvent) {
+ TemplateNotification soneInsertNotification = getSoneInsertNotification(soneInsertingEvent.sone());
soneInsertNotification.set("soneStatus", "inserting");
- if (sone.getOptions().getBooleanOption("EnableSoneInsertNotifications").get()) {
+ if (soneInsertingEvent.sone().getOptions().getBooleanOption("EnableSoneInsertNotifications").get()) {
notificationManager.addNotification(soneInsertNotification);
}
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a {@link Sone} was inserted.
+ *
+ * @param soneInsertedEvent
+ * The event
*/
- @Override
- public void soneInserted(Sone sone, long insertDuration) {
- TemplateNotification soneInsertNotification = getSoneInsertNotification(sone);
+ @Subscribe
+ public void soneInserted(SoneInsertedEvent soneInsertedEvent) {
+ TemplateNotification soneInsertNotification = getSoneInsertNotification(soneInsertedEvent.sone());
soneInsertNotification.set("soneStatus", "inserted");
- soneInsertNotification.set("insertDuration", insertDuration / 1000);
- if (sone.getOptions().getBooleanOption("EnableSoneInsertNotifications").get()) {
+ soneInsertNotification.set("insertDuration", soneInsertedEvent.insertDuration() / 1000);
+ if (soneInsertedEvent.sone().getOptions().getBooleanOption("EnableSoneInsertNotifications").get()) {
notificationManager.addNotification(soneInsertNotification);
}
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a {@link Sone} insert was aborted.
+ *
+ * @param soneInsertAbortedEvent
+ * The event
*/
- @Override
- public void soneInsertAborted(Sone sone, Throwable cause) {
- TemplateNotification soneInsertNotification = getSoneInsertNotification(sone);
+ @Subscribe
+ public void soneInsertAborted(SoneInsertAbortedEvent soneInsertAbortedEvent) {
+ TemplateNotification soneInsertNotification = getSoneInsertNotification(soneInsertAbortedEvent.sone());
soneInsertNotification.set("soneStatus", "insert-aborted");
- soneInsertNotification.set("insert-error", cause);
- if (sone.getOptions().getBooleanOption("EnableSoneInsertNotifications").get()) {
+ soneInsertNotification.set("insert-error", soneInsertAbortedEvent.cause());
+ if (soneInsertAbortedEvent.sone().getOptions().getBooleanOption("EnableSoneInsertNotifications").get()) {
notificationManager.addNotification(soneInsertNotification);
}
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that a new Sone version was found.
+ *
+ * @param updateFoundEvent
+ * The event
*/
- @Override
- public void updateFound(Version version, long releaseTime, long latestEdition) {
- newVersionNotification.getTemplateContext().set("latestVersion", version);
- newVersionNotification.getTemplateContext().set("latestEdition", latestEdition);
- newVersionNotification.getTemplateContext().set("releaseTime", releaseTime);
+ @Subscribe
+ public void updateFound(UpdateFoundEvent updateFoundEvent) {
+ newVersionNotification.getTemplateContext().set("latestVersion", updateFoundEvent.version());
+ newVersionNotification.getTemplateContext().set("latestEdition", updateFoundEvent.latestEdition());
+ newVersionNotification.getTemplateContext().set("releaseTime", updateFoundEvent.releaseTime());
notificationManager.addNotification(newVersionNotification);
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that an image insert was started
+ *
+ * @param imageInsertStartedEvent
+ * The event
*/
- @Override
- public void imageInsertStarted(Image image) {
- insertingImagesNotification.add(image);
+ @Subscribe
+ public void imageInsertStarted(ImageInsertStartedEvent imageInsertStartedEvent) {
+ insertingImagesNotification.add(imageInsertStartedEvent.image());
notificationManager.addNotification(insertingImagesNotification);
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that an {@link Image} insert was aborted.
+ *
+ * @param imageInsertAbortedEvent
+ * The event
*/
- @Override
- public void imageInsertAborted(Image image) {
- insertingImagesNotification.remove(image);
+ @Subscribe
+ public void imageInsertAborted(ImageInsertAbortedEvent imageInsertAbortedEvent) {
+ insertingImagesNotification.remove(imageInsertAbortedEvent.image());
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that an {@link Image} insert is finished.
+ *
+ * @param imageInsertFinishedEvent
+ * The event
*/
- @Override
- public void imageInsertFinished(Image image) {
- insertingImagesNotification.remove(image);
- insertedImagesNotification.add(image);
+ @Subscribe
+ public void imageInsertFinished(ImageInsertFinishedEvent imageInsertFinishedEvent) {
+ insertingImagesNotification.remove(imageInsertFinishedEvent.image());
+ insertedImagesNotification.add(imageInsertFinishedEvent.image());
notificationManager.addNotification(insertedImagesNotification);
}
/**
- * {@inheritDoc}
+ * Notifies the web interface that an {@link Image} insert has failed.
+ *
+ * @param imageInsertFailedEvent
+ * The event
*/
- @Override
- public void imageInsertFailed(Image image, Throwable cause) {
- insertingImagesNotification.remove(image);
- imageInsertFailedNotification.add(image);
+ @Subscribe
+ public void imageInsertFailed(ImageInsertFailedEvent imageInsertFailedEvent) {
+ insertingImagesNotification.remove(imageInsertFailedEvent.image());
+ imageInsertFailedNotification.add(imageInsertFailedEvent.image());
notificationManager.addNotification(imageInsertFailedNotification);
}
/*
- * Sone - BookmarkAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - BookmarkAjaxPage.java - Copyright © 2011–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
/*
- * Sone - CreatePostAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - CreatePostAjaxPage.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
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.json.JsonObject;
+import com.google.common.base.Optional;
+
/**
* AJAX handler that creates a new post.
*
return createErrorJsonObject("auth-required");
}
String recipientId = request.getHttpRequest().getParam("recipient");
- Sone recipient = webInterface.getCore().getSone(recipientId, false);
+ Optional<Sone> recipient = webInterface.getCore().getSone(recipientId);
String senderId = request.getHttpRequest().getParam("sender");
Sone sender = webInterface.getCore().getLocalSone(senderId, false);
if (sender == null) {
}
text = TextFilter.filter(request.getHttpRequest().getHeader("host"), text);
Post newPost = webInterface.getCore().createPost(sender, recipient, text);
- return createSuccessJsonObject().put("postId", newPost.getId()).put("sone", sender.getId()).put("recipient", (newPost.getRecipient() != null) ? newPost.getRecipient().getId() : null);
+ return createSuccessJsonObject().put("postId", newPost.getId()).put("sone", sender.getId()).put("recipient", newPost.getRecipientId().orNull());
}
}
/*
- * Sone - CreateReplyAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - CreateReplyAjaxPage.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
package net.pterodactylus.sone.web.ajax;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.PostReply;
import net.pterodactylus.sone.data.Sone;
if (sender == null) {
sender = getCurrentSone(request.getToadletContext());
}
- Post post = webInterface.getCore().getPost(postId);
- if ((post == null) || (post.getSone() == null)) {
+ Optional<Post> post = webInterface.getCore().getPost(postId);
+ if (!post.isPresent()) {
return createErrorJsonObject("invalid-post-id");
}
text = TextFilter.filter(request.getHttpRequest().getHeader("host"), text);
- PostReply reply = webInterface.getCore().createReply(sender, post, text);
+ PostReply reply = webInterface.getCore().createReply(sender, post.get(), text);
return createSuccessJsonObject().put("reply", reply.getId()).put("sone", sender.getId());
}
/*
- * Sone - DeletePostAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - DeletePostAjaxPage.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
package net.pterodactylus.sone.web.ajax;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
@Override
protected JsonObject createJsonObject(FreenetRequest request) {
String postId = request.getHttpRequest().getParam("post");
- Post post = webInterface.getCore().getPost(postId, false);
- if ((post == null) || (post.getSone() == null)) {
+ Optional<Post> post = webInterface.getCore().getPost(postId);
+ if (!post.isPresent()) {
return createErrorJsonObject("invalid-post-id");
}
- if (!webInterface.getCore().isLocalSone(post.getSone())) {
+ if (!post.get().getSone().isLocal()) {
return createErrorJsonObject("not-authorized");
}
- webInterface.getCore().deletePost(post);
+ webInterface.getCore().deletePost(post.get());
return createSuccessJsonObject();
}
/*
- * Sone - DeleteProfileFieldAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - DeleteProfileFieldAjaxPage.java - Copyright © 2011–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
/*
- * Sone - DeleteReplyAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - DeleteReplyAjaxPage.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
package net.pterodactylus.sone.web.ajax;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.PostReply;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
@Override
protected JsonObject createJsonObject(FreenetRequest request) {
String replyId = request.getHttpRequest().getParam("reply");
- PostReply reply = webInterface.getCore().getReply(replyId);
- if (reply == null) {
+ Optional<PostReply> reply = webInterface.getCore().getPostReply(replyId);
+ if (!reply.isPresent()) {
return createErrorJsonObject("invalid-reply-id");
}
- if (!webInterface.getCore().isLocalSone(reply.getSone())) {
+ if (!reply.get().getSone().isLocal()) {
return createErrorJsonObject("not-authorized");
}
- webInterface.getCore().deleteReply(reply);
+ webInterface.getCore().deleteReply(reply.get());
return createSuccessJsonObject();
}
/*
- * Sone - DismissNotificationAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - DismissNotificationAjaxPage.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
/*
- * Sone - DistrustAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - DistrustAjaxPage.java - Copyright © 2011–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
package net.pterodactylus.sone.web.ajax;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.WebInterface;
return createErrorJsonObject("auth-required");
}
String soneId = request.getHttpRequest().getParam("sone");
- Sone sone = webInterface.getCore().getSone(soneId, false);
- if (sone == null) {
+ Optional<Sone> sone = webInterface.getCore().getSone(soneId);
+ if (!sone.isPresent()) {
return createErrorJsonObject("invalid-sone-id");
}
- webInterface.getCore().distrustSone(currentSone, sone);
+ webInterface.getCore().distrustSone(currentSone, sone.get());
return createSuccessJsonObject().put("trustValue", webInterface.getCore().getPreferences().getNegativeTrust());
}
/*
- * Sone - EditAlbumAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - EditAlbumAjaxPage.java - Copyright © 2011–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
if (album == null) {
return createErrorJsonObject("invalid-album-id");
}
- if (!webInterface.getCore().isLocalSone(album.getSone())) {
+ if (!album.getSone().isLocal()) {
return createErrorJsonObject("not-authorized");
}
if ("true".equals(request.getHttpRequest().getParam("moveLeft"))) {
/*
- * Sone - EditImageAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - EditImageAjaxPage.java - Copyright © 2011–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
import net.pterodactylus.sone.text.TextFilter;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
-import net.pterodactylus.util.collection.MapBuilder;
import net.pterodactylus.util.json.JsonObject;
import net.pterodactylus.util.template.TemplateContext;
+import com.google.common.collect.ImmutableMap;
+
/**
* Page that stores a user’s image modifications.
*
if (image == null) {
return createErrorJsonObject("invalid-image-id");
}
- if (!webInterface.getCore().isLocalSone(image.getSone())) {
+ if (!image.getSone().isLocal()) {
return createErrorJsonObject("not-authorized");
}
if ("true".equals(request.getHttpRequest().getParam("moveLeft"))) {
String description = request.getHttpRequest().getParam("description").trim();
image.setTitle(title).setDescription(TextFilter.filter(request.getHttpRequest().getHeader("host"), description));
webInterface.getCore().touchConfiguration();
- return createSuccessJsonObject().put("imageId", image.getId()).put("title", image.getTitle()).put("description", image.getDescription()).put("parsedDescription", (String) parserFilter.format(new TemplateContext(), image.getDescription(), new MapBuilder<String, Object>().put("sone", image.getSone()).get()));
+ return createSuccessJsonObject().put("imageId", image.getId()).put("title", image.getTitle()).put("description", image.getDescription()).put("parsedDescription", (String) parserFilter.format(new TemplateContext(), image.getDescription(), ImmutableMap.<String, Object> builder().put("sone", image.getSone()).build()));
}
}
/*
- * Sone - EditProfileFieldAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - EditProfileFieldAjaxPage.java - Copyright © 2011–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
/*
- * Sone - FollowSoneAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - FollowSoneAjaxPage.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
package net.pterodactylus.sone.web.ajax;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
@Override
protected JsonObject createJsonObject(FreenetRequest request) {
String soneId = request.getHttpRequest().getParam("sone");
- if (!webInterface.getCore().hasSone(soneId)) {
+ Optional<Sone> sone = webInterface.getCore().getSone(soneId);
+ if (!sone.isPresent()) {
return createErrorJsonObject("invalid-sone-id");
}
Sone currentSone = getCurrentSone(request.getToadletContext());
return createErrorJsonObject("auth-required");
}
webInterface.getCore().followSone(currentSone, soneId);
- webInterface.getCore().markSoneKnown(webInterface.getCore().getSone(soneId));
+ webInterface.getCore().markSoneKnown(sone.get());
return createSuccessJsonObject();
}
/*
- * Sone - GetLikesAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - GetLikesAjaxPage.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
import net.pterodactylus.util.json.JsonArray;
import net.pterodactylus.util.json.JsonObject;
+import com.google.common.base.Optional;
+
/**
* AJAX page that retrieves the number of “likes” a {@link Post} has.
*
return createErrorJsonObject("invalid-" + type + "-id");
}
if ("post".equals(type)) {
- Post post = webInterface.getCore().getPost(id);
- Set<Sone> sones = webInterface.getCore().getLikes(post);
+ Optional<Post> post = webInterface.getCore().getPost(id);
+ if (!post.isPresent()) {
+ return createErrorJsonObject("invalid-post-id");
+ }
+ Set<Sone> sones = webInterface.getCore().getLikes(post.get());
return createSuccessJsonObject().put("likes", sones.size()).put("sones", getSones(sones));
} else if ("reply".equals(type)) {
- PostReply reply = webInterface.getCore().getReply(id);
- Set<Sone> sones = webInterface.getCore().getLikes(reply);
+ Optional<PostReply> reply = webInterface.getCore().getPostReply(id);
+ if (!reply.isPresent()) {
+ return createErrorJsonObject("invalid-reply-id");
+ }
+ Set<Sone> sones = webInterface.getCore().getLikes(reply.get());
return createSuccessJsonObject().put("likes", sones.size()).put("sones", getSones(sones));
}
return createErrorJsonObject("invalid-type");
/*
- * Sone - GetNotificationsAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - GetNotificationsAjaxPage.java - Copyright © 2011–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
import net.pterodactylus.util.json.JsonObject;
import net.pterodactylus.util.notify.Notification;
import net.pterodactylus.util.notify.TemplateNotification;
-import net.pterodactylus.util.object.HashCode;
import net.pterodactylus.util.template.TemplateContext;
/**
Collection<Notification> notifications = webInterface.getNotifications().getNotifications();
List<Notification> filteredNotifications = ListNotificationFilters.filterNotifications(notifications, currentSone);
Collections.sort(filteredNotifications, Notification.CREATED_TIME_SORTER);
- int notificationHash = HashCode.hashCode(filteredNotifications);
JsonArray jsonNotifications = new JsonArray();
for (Notification notification : filteredNotifications) {
jsonNotifications.add(createJsonNotification(request, notification));
}
- return createSuccessJsonObject().put("notificationHash", notificationHash).put("notifications", jsonNotifications).put("options", createJsonOptions(currentSone));
+ return createSuccessJsonObject().put("notificationHash", filteredNotifications.hashCode()).put("notifications", jsonNotifications).put("options", createJsonOptions(currentSone));
}
//
/*
- * Sone - GetPostAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - GetPostAjaxPage.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
import java.io.StringWriter;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.WebInterface;
@Override
protected JsonObject createJsonObject(FreenetRequest request) {
String postId = request.getHttpRequest().getParam("post");
- Post post = webInterface.getCore().getPost(postId, false);
- if (post == null) {
+ Optional<Post> post = webInterface.getCore().getPost(postId);
+ if (!post.isPresent()) {
return createErrorJsonObject("invalid-post-id");
}
- return createSuccessJsonObject().put("post", createJsonPost(request, post, getCurrentSone(request.getToadletContext())));
+ return createSuccessJsonObject().put("post", createJsonPost(request, post.get(), getCurrentSone(request.getToadletContext())));
}
/**
JsonObject jsonPost = new JsonObject();
jsonPost.put("id", post.getId());
jsonPost.put("sone", post.getSone().getId());
- jsonPost.put("recipient", (post.getRecipient() == null) ? null : post.getRecipient().getId());
+ jsonPost.put("recipient", post.getRecipientId().orNull());
jsonPost.put("time", post.getTime());
StringWriter stringWriter = new StringWriter();
TemplateContext templateContext = webInterface.getTemplateContextFactory().createTemplateContext();
/*
- * Sone - GetReplyAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - GetReplyAjaxPage.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
import java.io.StringWriter;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.data.PostReply;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.WebInterface;
@Override
protected JsonObject createJsonObject(FreenetRequest request) {
String replyId = request.getHttpRequest().getParam("reply");
- PostReply reply = webInterface.getCore().getReply(replyId);
- if ((reply == null) || (reply.getSone() == null)) {
+ Optional<PostReply> reply = webInterface.getCore().getPostReply(replyId);
+ if (!reply.isPresent()) {
return createErrorJsonObject("invalid-reply-id");
}
- return createSuccessJsonObject().put("reply", createJsonReply(request, reply, getCurrentSone(request.getToadletContext())));
+ return createSuccessJsonObject().put("reply", createJsonReply(request, reply.get(), getCurrentSone(request.getToadletContext())));
}
/**
private JsonObject createJsonReply(FreenetRequest request, PostReply reply, Sone currentSone) {
JsonObject jsonReply = new JsonObject();
jsonReply.put("id", reply.getId());
- jsonReply.put("postId", reply.getPost().getId());
+ jsonReply.put("postId", reply.getPostId());
jsonReply.put("soneId", reply.getSone().getId());
jsonReply.put("time", reply.getTime());
StringWriter stringWriter = new StringWriter();
/*
- * Sone - GetStatusAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - GetStatusAjaxPage.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
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import net.pterodactylus.sone.template.SoneAccessor;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
-import net.pterodactylus.util.collection.filter.Filter;
-import net.pterodactylus.util.collection.filter.Filters;
import net.pterodactylus.util.json.JsonArray;
import net.pterodactylus.util.json.JsonObject;
import net.pterodactylus.util.notify.Notification;
-import net.pterodactylus.util.object.HashCode;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
/**
* The “get status” AJAX handler returns all information that is necessary to
String[] soneIds = loadSoneIds.split(",");
for (String soneId : soneIds) {
/* just add it, we skip null further down. */
- sones.add(webInterface.getCore().getSone(soneId, false));
+ sones.add(webInterface.getCore().getSone(soneId).orNull());
}
}
JsonArray jsonSones = new JsonArray();
/* load notifications. */
List<Notification> notifications = ListNotificationFilters.filterNotifications(webInterface.getNotifications().getNotifications(), currentSone);
Collections.sort(notifications, Notification.CREATED_TIME_SORTER);
- int notificationHash = HashCode.hashCode(notifications);
/* load new posts. */
- Set<Post> newPosts = webInterface.getNewPosts();
+ Collection<Post> newPosts = webInterface.getNewPosts();
if (currentSone != null) {
- newPosts = Filters.filteredSet(newPosts, new Filter<Post>() {
+ newPosts = Collections2.filter(newPosts, new Predicate<Post>() {
@Override
- public boolean filterObject(Post post) {
+ public boolean apply(Post post) {
return ListNotificationFilters.isPostVisible(currentSone, post);
}
JsonObject jsonPost = new JsonObject();
jsonPost.put("id", post.getId());
jsonPost.put("sone", post.getSone().getId());
- jsonPost.put("recipient", (post.getRecipient() != null) ? post.getRecipient().getId() : null);
+ jsonPost.put("recipient", post.getRecipientId().orNull());
jsonPost.put("time", post.getTime());
jsonPosts.add(jsonPost);
}
/* load new replies. */
- Set<PostReply> newReplies = webInterface.getNewReplies();
+ Collection<PostReply> newReplies = webInterface.getNewReplies();
if (currentSone != null) {
- newReplies = Filters.filteredSet(newReplies, new Filter<PostReply>() {
+ newReplies = Collections2.filter(newReplies, new Predicate<PostReply>() {
@Override
- public boolean filterObject(PostReply reply) {
+ public boolean apply(PostReply reply) {
return ListNotificationFilters.isReplyVisible(currentSone, reply);
}
});
}
/* remove replies to unknown posts. */
- newReplies = Filters.filteredSet(newReplies, new Filter<PostReply>() {
-
- @Override
- public boolean filterObject(PostReply reply) {
- return (reply.getPost() != null) && (reply.getPost().getSone() != null);
- }
- });
+ newReplies = Collections2.filter(newReplies, PostReply.HAS_POST_FILTER);
JsonArray jsonReplies = new JsonArray();
for (PostReply reply : newReplies) {
JsonObject jsonReply = new JsonObject();
jsonReply.put("id", reply.getId());
jsonReply.put("sone", reply.getSone().getId());
- jsonReply.put("post", reply.getPost().getId());
- jsonReply.put("postSone", reply.getPost().getSone().getId());
+ jsonReply.put("post", reply.getPostId());
+ jsonReply.put("postSone", reply.getPost().get().getSone().getId());
jsonReplies.add(jsonReply);
}
- return createSuccessJsonObject().put("loggedIn", currentSone != null).put("options", createJsonOptions(currentSone)).put("sones", jsonSones).put("notificationHash", notificationHash).put("newPosts", jsonPosts).put("newReplies", jsonReplies);
+ return createSuccessJsonObject().put("loggedIn", currentSone != null).put("options", createJsonOptions(currentSone)).put("sones", jsonSones).put("notificationHash", notifications.hashCode()).put("newPosts", jsonPosts).put("newReplies", jsonReplies);
}
/**
/*
- * Sone - GetTimesAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - GetTimesAjaxPage.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 the Free Software
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.concurrent.TimeUnit;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.PostReply;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.json.JsonObject;
-import net.pterodactylus.util.number.Digits;
+
+import com.google.common.base.Optional;
/**
* Ajax page that returns a formatted, relative timestamp for replies or posts.
if (allIds.length() > 0) {
String[] ids = allIds.split(",");
for (String id : ids) {
- Post post = webInterface.getCore().getPost(id, false);
- if (post == null) {
+ Optional<Post> post = webInterface.getCore().getPost(id);
+ if (!post.isPresent()) {
continue;
}
JsonObject postTime = new JsonObject();
- Time time = getTime(post.getTime());
+ Time time = getTime(post.get().getTime());
postTime.put("timeText", time.getText());
- postTime.put("refreshTime", time.getRefresh() / Time.SECOND);
+ postTime.put("refreshTime", TimeUnit.MILLISECONDS.toSeconds(time.getRefresh()));
synchronized (dateFormat) {
- postTime.put("tooltip", dateFormat.format(new Date(post.getTime())));
+ postTime.put("tooltip", dateFormat.format(new Date(post.get().getTime())));
}
postTimes.put(id, postTime);
}
if (allIds.length() > 0) {
String[] ids = allIds.split(",");
for (String id : ids) {
- PostReply reply = webInterface.getCore().getReply(id, false);
- if (reply == null) {
+ Optional<PostReply> reply = webInterface.getCore().getPostReply(id);
+ if (!reply.isPresent()) {
continue;
}
JsonObject replyTime = new JsonObject();
- Time time = getTime(reply.getTime());
+ Time time = getTime(reply.get().getTime());
replyTime.put("timeText", time.getText());
- replyTime.put("refreshTime", time.getRefresh() / Time.SECOND);
+ replyTime.put("refreshTime", TimeUnit.MILLISECONDS.toSeconds(time.getRefresh()));
synchronized (dateFormat) {
- replyTime.put("tooltip", dateFormat.format(new Date(reply.getTime())));
+ replyTime.put("tooltip", dateFormat.format(new Date(reply.get().getTime())));
}
replyTimes.put(id, replyTime);
}
*/
public static Time getTime(WebInterface webInterface, long time) {
if (time == 0) {
- return new Time(webInterface.getL10n().getString("View.Sone.Text.UnknownDate"), 12 * Time.HOUR);
+ return new Time(webInterface.getL10n().getString("View.Sone.Text.UnknownDate"), TimeUnit.HOURS.toMillis(12));
}
long age = System.currentTimeMillis() - time;
String text;
long refresh;
if (age < 0) {
text = webInterface.getL10n().getDefaultString("View.Time.InTheFuture");
- refresh = 5 * Time.MINUTE;
- } else if (age < 20 * Time.SECOND) {
+ refresh = TimeUnit.MINUTES.toMillis(5);
+ } else if (age < TimeUnit.SECONDS.toMillis(20)) {
text = webInterface.getL10n().getDefaultString("View.Time.AFewSecondsAgo");
- refresh = 10 * Time.SECOND;
- } else if (age < 45 * Time.SECOND) {
+ refresh = TimeUnit.SECONDS.toMillis(10);
+ } else if (age < TimeUnit.SECONDS.toMillis(45)) {
text = webInterface.getL10n().getString("View.Time.HalfAMinuteAgo");
- refresh = 20 * Time.SECOND;
- } else if (age < 90 * Time.SECOND) {
+ refresh = TimeUnit.SECONDS.toMillis(20);
+ } else if (age < TimeUnit.SECONDS.toMillis(90)) {
text = webInterface.getL10n().getString("View.Time.AMinuteAgo");
- refresh = Time.MINUTE;
- } else if (age < 30 * Time.MINUTE) {
- text = webInterface.getL10n().getString("View.Time.XMinutesAgo", "min", String.valueOf((int) (Digits.round(age, Time.MINUTE) / Time.MINUTE)));
- refresh = 1 * Time.MINUTE;
- } else if (age < 45 * Time.MINUTE) {
+ refresh = TimeUnit.MINUTES.toMillis(1);
+ } else if (age < TimeUnit.MINUTES.toMillis(30)) {
+ text = webInterface.getL10n().getString("View.Time.XMinutesAgo", "min", String.valueOf(TimeUnit.MILLISECONDS.toMinutes(age + TimeUnit.SECONDS.toMillis(30))));
+ refresh = TimeUnit.MINUTES.toMillis(1);
+ } else if (age < TimeUnit.MINUTES.toMillis(45)) {
text = webInterface.getL10n().getString("View.Time.HalfAnHourAgo");
- refresh = 10 * Time.MINUTE;
- } else if (age < 90 * Time.MINUTE) {
+ refresh = TimeUnit.MINUTES.toMillis(10);
+ } else if (age < TimeUnit.MINUTES.toMillis(90)) {
text = webInterface.getL10n().getString("View.Time.AnHourAgo");
- refresh = Time.HOUR;
- } else if (age < 21 * Time.HOUR) {
- text = webInterface.getL10n().getString("View.Time.XHoursAgo", "hour", String.valueOf((int) (Digits.round(age, Time.HOUR) / Time.HOUR)));
- refresh = Time.HOUR;
- } else if (age < 42 * Time.HOUR) {
+ refresh = TimeUnit.HOURS.toMillis(1);
+ } else if (age < TimeUnit.HOURS.toMillis(21)) {
+ text = webInterface.getL10n().getString("View.Time.XHoursAgo", "hour", String.valueOf(TimeUnit.MILLISECONDS.toHours(age + TimeUnit.MINUTES.toMillis(30))));
+ refresh = TimeUnit.HOURS.toMillis(1);
+ } else if (age < TimeUnit.HOURS.toMillis(42)) {
text = webInterface.getL10n().getString("View.Time.ADayAgo");
- refresh = Time.DAY;
- } else if (age < 6 * Time.DAY) {
- text = webInterface.getL10n().getString("View.Time.XDaysAgo", "day", String.valueOf((int) (Digits.round(age, Time.DAY) / Time.DAY)));
- refresh = Time.DAY;
- } else if (age < 11 * Time.DAY) {
+ refresh = TimeUnit.DAYS.toMillis(1);
+ } else if (age < TimeUnit.DAYS.toMillis(6)) {
+ text = webInterface.getL10n().getString("View.Time.XDaysAgo", "day", String.valueOf(TimeUnit.MILLISECONDS.toDays(age + TimeUnit.HOURS.toMillis(12))));
+ refresh = TimeUnit.DAYS.toMillis(1);
+ } else if (age < TimeUnit.DAYS.toMillis(11)) {
text = webInterface.getL10n().getString("View.Time.AWeekAgo");
- refresh = Time.DAY;
- } else if (age < 4 * Time.WEEK) {
- text = webInterface.getL10n().getString("View.Time.XWeeksAgo", "week", String.valueOf((int) (Digits.round(age, Time.WEEK) / Time.WEEK)));
- refresh = Time.DAY;
- } else if (age < 6 * Time.WEEK) {
+ refresh = TimeUnit.DAYS.toMillis(1);
+ } else if (age < TimeUnit.DAYS.toMillis(28)) {
+ text = webInterface.getL10n().getString("View.Time.XWeeksAgo", "week", String.valueOf((TimeUnit.MILLISECONDS.toHours(age) + 84) / (7 * 24)));
+ refresh = TimeUnit.DAYS.toMillis(1);
+ } else if (age < TimeUnit.DAYS.toMillis(42)) {
text = webInterface.getL10n().getString("View.Time.AMonthAgo");
- refresh = Time.DAY;
- } else if (age < 11 * Time.MONTH) {
- text = webInterface.getL10n().getString("View.Time.XMonthsAgo", "month", String.valueOf((int) (Digits.round(age, Time.MONTH) / Time.MONTH)));
- refresh = Time.DAY;
- } else if (age < 18 * Time.MONTH) {
+ refresh = TimeUnit.DAYS.toMillis(1);
+ } else if (age < TimeUnit.DAYS.toMillis(330)) {
+ text = webInterface.getL10n().getString("View.Time.XMonthsAgo", "month", String.valueOf((TimeUnit.MILLISECONDS.toDays(age) + 15) / 30));
+ refresh = TimeUnit.DAYS.toMillis(1);
+ } else if (age < TimeUnit.DAYS.toMillis(540)) {
text = webInterface.getL10n().getString("View.Time.AYearAgo");
- refresh = Time.WEEK;
+ refresh = TimeUnit.DAYS.toMillis(7);
} else {
- text = webInterface.getL10n().getString("View.Time.XYearsAgo", "year", String.valueOf((int) (Digits.round(age, Time.YEAR) / Time.YEAR)));
- refresh = Time.WEEK;
+ text = webInterface.getL10n().getString("View.Time.XYearsAgo", "year", String.valueOf((long) ((TimeUnit.MILLISECONDS.toDays(age) + 182.64) / 365.28)));
+ refresh = TimeUnit.DAYS.toMillis(7);
}
return new Time(text, refresh);
}
*/
public static class Time {
- /** Number of milliseconds in a second. */
- private static final long SECOND = 1000;
-
- /** Number of milliseconds in a minute. */
- private static final long MINUTE = 60 * SECOND;
-
- /** Number of milliseconds in an hour. */
- private static final long HOUR = 60 * MINUTE;
-
- /** Number of milliseconds in a day. */
- private static final long DAY = 24 * HOUR;
-
- /** Number of milliseconds in a week. */
- private static final long WEEK = 7 * DAY;
-
- /** Number of milliseconds in a 30-day month. */
- private static final long MONTH = 30 * DAY;
-
- /** Number of milliseconds in a year. */
- private static final long YEAR = 365 * DAY;
-
/** The formatted time. */
private final String text;
/*
- * Sone - GetTranslationPage.java - Copyright © 2010–2012 David Roden
+ * Sone - GetTranslationPage.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
/*
- * Sone - JsonPage.java - Copyright © 2010–2012 David Roden
+ * Sone - JsonPage.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
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URI;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.json.JsonObject;
import net.pterodactylus.util.json.JsonUtils;
+import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.web.Page;
import net.pterodactylus.util.web.Response;
import freenet.clients.http.SessionManager.Session;
*/
public abstract class JsonPage implements FreenetPage {
+ /** The logger. */
+ private static final Logger logger = Logging.getLogger(JsonPage.class);
+
/** The path of the page. */
private final String path;
JsonObject jsonObject = createJsonObject(request);
return response.setStatusCode(200).setStatusText("OK").setContentType("application/json").write(JsonUtils.format(jsonObject));
} catch (Exception e1) {
+ logger.log(Level.WARNING, "Error executing JSON page!", e1);
return response.setStatusCode(500).setStatusText(e1.getMessage()).setContentType("text/plain").write(dumpStackTrace(e1));
}
}
/*
- * Sone - LikeAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - LikeAjaxPage.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
/*
- * Sone - LockSoneAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - LockSoneAjaxPage.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
/*
- * Sone - MarkAsKnownAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - MarkAsKnownAjaxPage.java - Copyright © 2011–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
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.json.JsonObject;
+import com.google.common.base.Optional;
+
/**
* AJAX page that lets the user mark a number of {@link Sone}s, {@link Post}s,
* or {@link Reply}s as known.
Core core = webInterface.getCore();
for (String id : ids) {
if (type.equals("post")) {
- Post post = core.getPost(id, false);
- if (post == null) {
+ Optional<Post> post = core.getPost(id);
+ if (!post.isPresent()) {
continue;
}
- core.markPostKnown(post);
+ core.markPostKnown(post.get());
} else if (type.equals("reply")) {
- PostReply reply = core.getReply(id, false);
- if (reply == null) {
+ Optional<PostReply> reply = core.getPostReply(id);
+ if (!reply.isPresent()) {
continue;
}
- core.markReplyKnown(reply);
+ core.markReplyKnown(reply.get());
} else if (type.equals("sone")) {
- Sone sone = core.getSone(id, false);
- if (sone == null) {
+ Optional<Sone> sone = core.getSone(id);
+ if (!sone.isPresent()) {
continue;
}
- core.markSoneKnown(sone);
+ core.markSoneKnown(sone.get());
}
}
return createSuccessJsonObject();
/*
- * Sone - MoveProfileFieldAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - MoveProfileFieldAjaxPage.java - Copyright © 2011–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
/*
- * Sone - TrustAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - TrustAjaxPage.java - Copyright © 2011–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
package net.pterodactylus.sone.web.ajax;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.WebInterface;
return createErrorJsonObject("auth-required");
}
String soneId = request.getHttpRequest().getParam("sone");
- Sone sone = webInterface.getCore().getSone(soneId, false);
- if (sone == null) {
+ Optional<Sone> sone = webInterface.getCore().getSone(soneId);
+ if (!sone.isPresent()) {
return createErrorJsonObject("invalid-sone-id");
}
- webInterface.getCore().trustSone(currentSone, sone);
+ webInterface.getCore().trustSone(currentSone, sone.get());
return createSuccessJsonObject().put("trustValue", webInterface.getCore().getPreferences().getPositiveTrust());
}
/*
- * Sone - UnbookmarkAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - UnbookmarkAjaxPage.java - Copyright © 2011–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
/*
- * Sone - UnfollowSoneAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - UnfollowSoneAjaxPage.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
@Override
protected JsonObject createJsonObject(FreenetRequest request) {
String soneId = request.getHttpRequest().getParam("sone");
- if (!webInterface.getCore().hasSone(soneId)) {
+ if (!webInterface.getCore().getSone(soneId).isPresent()) {
return createErrorJsonObject("invalid-sone-id");
}
Sone currentSone = getCurrentSone(request.getToadletContext());
/*
- * Sone - UnlikeAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - UnlikeAjaxPage.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
/*
- * Sone - UnlockSoneAjaxPage.java - Copyright © 2010–2012 David Roden
+ * Sone - UnlockSoneAjaxPage.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
/*
- * Sone - UntrustAjaxPage.java - Copyright © 2011–2012 David Roden
+ * Sone - UntrustAjaxPage.java - Copyright © 2011–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
package net.pterodactylus.sone.web.ajax;
+import com.google.common.base.Optional;
+
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.WebInterface;
return createErrorJsonObject("auth-required");
}
String soneId = request.getHttpRequest().getParam("sone");
- Sone sone = webInterface.getCore().getSone(soneId, false);
- if (sone == null) {
+ Optional<Sone> sone = webInterface.getCore().getSone(soneId);
+ if (!sone.isPresent()) {
return createErrorJsonObject("invalid-sone-id");
}
- webInterface.getCore().untrustSone(currentSone, sone);
+ webInterface.getCore().untrustSone(currentSone, sone.get());
return createSuccessJsonObject().put("trustValue", (String) null);
}
/*
- * Sone - FreenetPage.java - Copyright © 2011–2012 David Roden
+ * Sone - FreenetPage.java - Copyright © 2011–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
/*
- * Sone - FreenetRequest.java - Copyright © 2011–2012 David Roden
+ * Sone - FreenetRequest.java - Copyright © 2011–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
/*
- * Sone - FreenetTemplatePage.java - Copyright © 2010–2012 David Roden
+ * Sone - FreenetTemplatePage.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
/*
- * Sone - PageToadlet.java - Copyright © 2010–2012 David Roden
+ * Sone - PageToadlet.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
/*
- * Sone - PageToadletFactory.java - Copyright © 2010–2012 David Roden
+ * Sone - PageToadletFactory.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
--- /dev/null
+<body>
+ <h1>Sone API Documentation</h1>
+ <p>This is the API documentation of Sone.</p>
+ <p>I recognize that this has probably little value for the average
+ user; however, should you ever plan to fiddle around with Sone, extend
+ it, change some functionality, fix bugs, or do whatever else you have
+ in mind, this documentation might come in handy.</p>
+</body>
\ No newline at end of file
Page.KnownSones.Filter.NotFollowed=Gefolgte Sones nicht anzeigen
Page.KnownSones.Filter.New=Nur neue Sones anzeigen
Page.KnownSones.Filter.NotNew=Neue Sones nicht anzeigen
+Page.KnownSones.Filter.Own=Nur eigene Sones anzeigen
+Page.KnownSones.Filter.NotOwn=Nur fremde Sones anzeigen
Page.KnownSones.Button.Apply=Anwenden
Page.KnownSones.Button.FollowAllSones=Allen Sones auf dieser Seite folgen
Page.KnownSones.Button.UnfollowAllSones=Alle Sones auf dieser Seite entfolgen
Page.KnownSones.Filter.NotFollowed=Hide followed Sones
Page.KnownSones.Filter.New=Show only new Sones
Page.KnownSones.Filter.NotNew=Hide new Sones
+Page.KnownSones.Filter.Own=Show only local Sones
+Page.KnownSones.Filter.NotOwn=Show only remote Sones
Page.KnownSones.Button.Apply=Apply
Page.KnownSones.Button.FollowAllSones=Follow all Sones on this page
Page.KnownSones.Button.UnfollowAllSones=Unfollow all Sones on this page
Page.KnownSones.Filter.NotFollowed=Cacher les Sones suivis
Page.KnownSones.Filter.New=Montrer seulement les nouveaux Sones
Page.KnownSones.Filter.NotNew=Cacher les nouveaux Sones
+Page.KnownSones.Filter.Own=Show only local Sones
+Page.KnownSones.Filter.NotOwn=Show only remote Sones
Page.KnownSones.Button.Apply=Appliquer
Page.KnownSones.Button.FollowAllSones=Suivre tous les Sones de cette page
Page.KnownSones.Button.UnfollowAllSones=Ne plus suivre tous les Sones de cette page
Notification.Mention.ShortText=Vous avez été mentionné.
Notification.Mention.Text=Vous avez été mentionné dans les messages suivants:
Notification.SoneInsert.Duration={0,number} {0,choice,0#seconds|1#second|1<seconds}
+# 120-121
Page.KnownSones.Filter.NotFollowed=フォローしているSoneを隠す
Page.KnownSones.Filter.New=新しいSoneのみ表示
Page.KnownSones.Filter.NotNew=新しいSoneを隠す
+Page.KnownSones.Filter.Own=Show only local Sones
+Page.KnownSones.Filter.NotOwn=Show only remote Sones
Page.KnownSones.Button.Apply=実行
Page.KnownSones.Button.FollowAllSones=このページ内の全てのSoneをフォロー
Page.KnownSones.Button.UnfollowAllSones=このページ内の全てのフォローを解除
Notification.Mention.ShortText=誰かにメンションされました。
Notification.Mention.Text=次の投稿でメンションされています:
Notification.SoneInsert.Duration={0,number} {0,choice,0#秒|1#秒|1<秒}
+# 120-121
Page.KnownSones.Filter.NotFollowed=Gjem Soner som følges
Page.KnownSones.Filter.New=Vis bare nye Soner
Page.KnownSones.Filter.NotNew=Gjem nye Soner
+Page.KnownSones.Filter.Own=Show only local Sones
+Page.KnownSones.Filter.NotOwn=Show only remote Sones
Page.KnownSones.Button.Apply=Tilføy
Page.KnownSones.Button.FollowAllSones=Følg alle Soner på denne siden
Page.KnownSones.Button.UnfollowAllSones=Slutt å følge alle Soner på denne siden
Notification.Mention.ShortText=Du har blitt nevnt:
Notification.Mention.Text=Du har blitt nevnt i følgende innlegg:
Notification.SoneInsert.Duration={0,number} {0,choice,0#sekund|1#sekund|1<sekunder}
+# 120-121
Page.KnownSones.Filter.NotFollowed=Ukryj śledzone Sone
Page.KnownSones.Filter.New=Pokazuj tylko nowe Sone
Page.KnownSones.Filter.NotNew=Ukryj nowe Sone
+Page.KnownSones.Filter.Own=Show only local Sones
+Page.KnownSones.Filter.NotOwn=Show only remote Sones
Page.KnownSones.Button.Apply=Zastosuj
Page.KnownSones.Button.FollowAllSones=Śledź wszystkie Sone na tej stronie
Page.KnownSones.Button.UnfollowAllSones=Przestań śledzić wszystkie Sone na tej stronie
Notification.Mention.ShortText=Zostałeś oznaczony.
Notification.Mention.Text=Zostałeś oznaczony w następujących postach:
Notification.SoneInsert.Duration={0,number} {0,choice,0#seconds|1#second|1<seconds}
+# 120-121
Page.KnownSones.Filter.NotFollowed=Скрыть Sone, на которые вы подписаны
Page.KnownSones.Filter.New=Показывать только новые Sone
Page.KnownSones.Filter.NotNew=Скрыть новые Sone
+Page.KnownSones.Filter.Own=Show only local Sones
+Page.KnownSones.Filter.NotOwn=Show only remote Sones
Page.KnownSones.Button.Apply=Применить
Page.KnownSones.Button.FollowAllSones=Подписаться на все Sone на этой странице
Page.KnownSones.Button.UnfollowAllSones=Снять подписку со всех Sone на этой странице
Notification.Mention.ShortText=Вас упомянули.
Notification.Mention.Text=Вас упомянули в следующих сообщениях:
Notification.SoneInsert.Duration={0,number} {0,choice,0#секунд|1#секунда|2#секунды|4<секунд}
+# 120-121
* request
*/
function markSoneAsKnown(soneElement, skipRequest) {
- if ($(soneElement).is(".new")) {
+ if ($(soneElement).hasClass("new")) {
$(soneElement).removeClass("new");
if ((typeof skipRequest == "undefined") || !skipRequest) {
ajaxGet("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": "sone", "id": getSoneId(soneElement)});
<div class="inner-part">
<div<%if !post.loaded> class="hidden"<%/if>>
<div class="author profile-link"><a href="viewSone.html?sone=<% post.sone.id|html>"><% post.sone.niceName|html></a></div>
- <%ifnull !post.recipient>
+ <%if post.recipientId.present>
<span class="recipient-to">→</span>
- <%ifnull post.recipient.identity>
- <div class="recipient profile-link"><a href="viewSone.html?sone=<% post.recipient.id|html>"><%= View.Post.UnknownAuthor|l10n|html></a></div>
+ <%if !post.recipient.present>
+ <div class="recipient profile-link"><a href="viewSone.html?sone=<% post.recipientId.get|html>"><%= View.Post.UnknownAuthor|l10n|html></a></div>
<%else>
- <div class="recipient profile-link"><a href="viewSone.html?sone=<% post.recipient.id|html>"><% post.recipient.niceName|html></a></div>
+ <div class="recipient profile-link"><a href="viewSone.html?sone=<% post.recipientId.get|html>"><% post.recipient.get.niceName|html></a></div>
<%/if>
<%/if>
<% post.text|html|store key==originalText text==true>
<%foreach currentSone.posts post>
<post>
<id><% post.id|xml></id>
- <recipient><%ifnull !post.recipient><% post.recipient.id|xml><%/if></recipient>
+ <recipient><%if post.recipientId.present><% post.recipientId.get|xml><%/if></recipient>
<time><% post.time></time>
<text><% post.text|xml></text>
</post>
<%foreach currentSone.replies reply>
<reply>
<id><% reply.id></id>
- <post-id><% reply.post.id|xml></post-id>
+ <post-id><% reply.postId|xml></post-id>
<time><% reply.time></time>
<text><% reply.text|xml></text>
</reply>
<%/if>
<option value="new"<%if filter|match value=="new"> selected="selected"<%/if>><%= Page.KnownSones.Filter.New|l10n|html></option>
<option value="not-new"<%if filter|match value=="not-new"> selected="selected"<%/if>><%= Page.KnownSones.Filter.NotNew|l10n|html></option>
+ <option value="own"<%if filter|match value=="own"> selected="selected"<%/if>><%= Page.KnownSones.Filter.Own|l10n|html></option>
+ <option value="not-own"<%if filter|match value=="not-own"> selected="selected"<%/if>><%= Page.KnownSones.Filter.NotOwn|l10n|html></option>
</select>
</div>
<%/if>
import freenet.support.SimpleFieldSet;
+import com.google.common.base.Optional;
import org.junit.Test;
/**
public void testLockingALocalSone() throws FcpException {
Sone localSone = mock(Sone.class);
when(localSone.getId()).thenReturn("LocalSone");
+ when(localSone.isLocal()).thenReturn(true);
Core core = mock(Core.class);
- when(core.getSone(eq("LocalSone"), anyBoolean())).thenReturn(localSone);
+ when(core.getSone(eq("LocalSone"))).thenReturn(Optional.of(localSone));
when(core.getLocalSone(eq("LocalSone"), anyBoolean())).thenReturn(localSone);
SimpleFieldSet fields = new SimpleFieldSetBuilder().put("Sone", "LocalSone").get();
public void testLockingARemoteSone() throws FcpException {
Sone removeSone = mock(Sone.class);
Core core = mock(Core.class);
- when(core.getSone(eq("RemoteSone"), anyBoolean())).thenReturn(removeSone);
+ when(core.getSone(eq("RemoteSone"))).thenReturn(Optional.of(removeSone));
SimpleFieldSet fields = new SimpleFieldSetBuilder().put("Sone", "RemoteSone").get();
LockSoneCommand lockSoneCommand = new LockSoneCommand(core);
import freenet.support.SimpleFieldSet;
+import com.google.common.base.Optional;
import org.junit.Test;
/**
public void testUnlockingALocalSone() throws FcpException {
Sone localSone = mock(Sone.class);
when(localSone.getId()).thenReturn("LocalSone");
+ when(localSone.isLocal()).thenReturn(true);
Core core = mock(Core.class);
- when(core.getSone(eq("LocalSone"), anyBoolean())).thenReturn(localSone);
+ when(core.getSone(eq("LocalSone"))).thenReturn(Optional.of(localSone));
when(core.getLocalSone(eq("LocalSone"), anyBoolean())).thenReturn(localSone);
SimpleFieldSet fields = new SimpleFieldSetBuilder().put("Sone", "LocalSone").get();
public void testUnlockingARemoteSone() throws FcpException {
Sone removeSone = mock(Sone.class);
Core core = mock(Core.class);
- when(core.getSone(eq("RemoteSone"), anyBoolean())).thenReturn(removeSone);
+ when(core.getSone(eq("RemoteSone"))).thenReturn(Optional.of(removeSone));
SimpleFieldSet fields = new SimpleFieldSetBuilder().put("Sone", "RemoteSone").get();
UnlockSoneCommand unlockSoneCommand = new UnlockSoneCommand(core);
/*
- * Sone - SoneTextParserTest.java - Copyright © 2011–2012 David Roden
+ * Sone - SoneTextParserTest.java - Copyright © 2011–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
import java.io.IOException;
import java.io.StringReader;
import java.util.Arrays;
+import java.util.Collection;
+
+import com.google.common.base.Optional;
import junit.framework.TestCase;
-import net.pterodactylus.sone.core.SoneProvider;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.SoneProvider;
/**
* JUnit test case for {@link SoneTextParser}.
* {@inheritDoc}
*/
@Override
- public Sone getSone(final String soneId, boolean create) {
- return new Sone(soneId) {
+ public Optional<Sone> getSone(final String soneId) {
+ return Optional.<Sone> fromNullable(new Sone(soneId, false) {
/**
* {@inheritDoc}
public String getName() {
return soneId;
}
- };
+ });
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public Collection<Sone> getSones() {
+ return null;
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public Collection<Sone> getLocalSones() {
+ return null;
+ }
+
+ /**
+ * {@inheritDocs}
+ */
+ @Override
+ public Collection<Sone> getRemoteSones() {
+ return null;
}
}