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 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.fcp.FcpInterface;
import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
import net.pterodactylus.sone.freenet.wot.Identity;
/** Whether we’re currently saving the configuration. */
private boolean storingConfiguration = false;
+ /** The database. */
+ private Database database;
+
/** The identity manager. */
private final IdentityManager identityManager;
/* synchronize access on this on localSones. */
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. */
- /* synchronize access on this on itself. */
- private final Map<String, Sone> remoteSones = new HashMap<String, Sone>();
-
/** All known Sones. */
private final Set<String> knownSones = new HashSet<String>();
*
* @param configuration
* The configuration of the core
+ * @param database
+ * The database to use
* @param freenetInterface
* The freenet interface
* @param identityManager
* @param webOfTrustUpdater
* The WebOfTrust updater
*/
- public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater) {
+ public Core(Configuration configuration, Database database, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater) {
super("Sone Core");
this.configuration = configuration;
+ this.database = database;
this.freenetInterface = freenetInterface;
this.identityManager = identityManager;
this.soneDownloader = new SoneDownloader(this, freenetInterface);
* @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) {
+ Validation.begin().isNotNull("Sone", sone).check().is("Local Sone", sone.isLocal()).check();
+ synchronized (soneRescuers) {
SoneRescuer soneRescuer = soneRescuers.get(sone);
if (soneRescuer == null) {
soneRescuer = new SoneRescuer(this, soneDownloader, sone);
*
* @return All Sones
*/
- public Set<Sone> getSones() {
- Set<Sone> allSones = new HashSet<Sone>();
- allSones.addAll(getLocalSones());
- allSones.addAll(getRemoteSones());
- return allSones;
+ public Collection<Sone> getSones() {
+ return database.getSones();
}
/**
*/
@Override
public Sone getSone(String id, boolean create) {
- if (isLocalSone(id)) {
- return getLocalSone(id);
- }
- return getRemoteSone(id, create);
+ return database.getSone(id, create);
}
/**
* otherwise
*/
public boolean hasSone(String id) {
- return isLocalSone(id) || isRemoteSone(id);
- }
-
- /**
- * Returns whether the given Sone is a local Sone.
- *
- * @param sone
- * The Sone to check for its locality
- * @return {@code true} if the given Sone is local, {@code false} otherwise
- */
- public boolean isLocalSone(Sone sone) {
- synchronized (localSones) {
- return localSones.containsKey(sone.getId());
- }
- }
-
- /**
- * Returns whether the given ID is the ID of a local Sone.
- *
- * @param id
- * The Sone ID to check for its locality
- * @return {@code true} if the given ID is a local Sone, {@code false}
- * otherwise
- */
- public boolean isLocalSone(String id) {
- synchronized (localSones) {
- return localSones.containsKey(id);
- }
+ return database.getSone(id, false) != null;
}
/**
*
* @return All local Sones
*/
- public Set<Sone> getLocalSones() {
- synchronized (localSones) {
- return new HashSet<Sone>(localSones.values());
- }
+ public Collection<Sone> getLocalSones() {
+ return database.getLocalSones();
}
/**
* @return The Sone with the given ID, or {@code null}
*/
public Sone getLocalSone(String id, boolean create) {
- synchronized (localSones) {
- Sone sone = localSones.get(id);
- if ((sone == null) && create) {
- sone = new Sone(id);
- localSones.put(id, sone);
- }
- return sone;
- }
+ return database.getLocalSone(id, create);
}
/**
*
* @return All remote Sones
*/
- public Set<Sone> getRemoteSones() {
- synchronized (remoteSones) {
- return new HashSet<Sone>(remoteSones.values());
- }
+ public Collection<Sone> getRemoteSones() {
+ return database.getRemoteSones();
}
/**
* @return The Sone with the given ID
*/
public Sone getRemoteSone(String id, boolean create) {
- synchronized (remoteSones) {
- Sone sone = remoteSones.get(id);
- if ((sone == null) && create && (id != null) && (id.length() == 43)) {
- sone = new Sone(id);
- remoteSones.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);
- }
+ return database.getRemoteSone(id, create);
}
/**
}
/**
- * Returns the post with the given ID.
- *
- * @param postId
- * The ID of the post to get
- * @return The post with the given ID, or a new post with the given ID
- */
- public Post getPost(String postId) {
- return getPost(postId, true);
- }
-
- /**
* Returns the post with the given ID, optionally creating a new post.
*
* @param postId
* @return All replies for the given post
*/
public List<PostReply> getReplies(Post post) {
- Set<Sone> sones = getSones();
+ Collection<Sone> sones = getSones();
List<PostReply> replies = new ArrayList<PostReply>();
for (Sone sone : sones) {
for (PostReply reply : sone.getReplies()) {
logger.log(Level.WARNING, "Given OwnIdentity is null!");
return null;
}
- synchronized (localSones) {
- final Sone sone;
- try {
- sone = getLocalSone(ownIdentity.getId()).setIdentity(ownIdentity).setInsertUri(new FreenetURI(ownIdentity.getInsertUri())).setRequestUri(new FreenetURI(ownIdentity.getRequestUri()));
- } catch (MalformedURLException mue1) {
- logger.log(Level.SEVERE, String.format("Could not convert the Identity’s URIs to Freenet URIs: %s, %s", ownIdentity.getInsertUri(), ownIdentity.getRequestUri()), mue1);
- return null;
- }
- sone.setLatestEdition(Numbers.safeParseLong(ownIdentity.getProperty("Sone.LatestEdition"), (long) 0));
- sone.setClient(new Client("Sone", SonePlugin.VERSION.toString()));
- sone.setKnown(true);
- /* TODO - load posts ’n stuff */
- localSones.put(ownIdentity.getId(), sone);
- final SoneInserter soneInserter = new SoneInserter(this, freenetInterface, sone);
- soneInserter.addSoneInsertListener(this);
- soneInserters.put(sone, soneInserter);
- sone.setStatus(SoneStatus.idle);
- loadSone(sone);
- soneInserter.start();
- return sone;
+ Sone sone;
+ try {
+ sone = getLocalSone(ownIdentity.getId()).setIdentity(ownIdentity).setInsertUri(new FreenetURI(ownIdentity.getInsertUri())).setRequestUri(new FreenetURI(ownIdentity.getRequestUri()));
+ } catch (MalformedURLException mue1) {
+ logger.log(Level.SEVERE, String.format("Could not convert the Identity’s URIs to Freenet URIs: %s, %s", ownIdentity.getInsertUri(), ownIdentity.getRequestUri()), mue1);
+ return null;
}
+ sone.setLatestEdition(Numbers.safeParseLong(ownIdentity.getProperty("Sone.LatestEdition"), (long) 0));
+ sone.setClient(new Client("Sone", SonePlugin.VERSION.toString()));
+ sone.setKnown(true);
+ /* TODO - load posts ’n stuff */
+ final SoneInserter soneInserter = new SoneInserter(this, freenetInterface, sone);
+ soneInserter.addSoneInsertListener(this);
+ soneInserters.put(sone, soneInserter);
+ sone.setStatus(SoneStatus.idle);
+ loadSone(sone);
+ soneInserter.start();
+ database.saveSone(sone);
+ return sone;
}
/**
logger.log(Level.WARNING, "Given Identity is null!");
return null;
}
- synchronized (remoteSones) {
- final Sone sone = getRemoteSone(identity.getId(), true).setIdentity(identity);
- boolean newSone = sone.getRequestUri() == null;
- sone.setRequestUri(getSoneUri(identity.getRequestUri()));
- sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), (long) 0));
+ final Sone sone = getRemoteSone(identity.getId(), true).setIdentity(identity);
+ boolean newSone = sone.getRequestUri() == null;
+ sone.setRequestUri(getSoneUri(identity.getRequestUri()));
+ sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), (long) 0));
+ if (newSone) {
+ synchronized (knownSones) {
+ newSone = !knownSones.contains(sone.getId());
+ }
+ sone.setKnown(!newSone);
if (newSone) {
- synchronized (knownSones) {
- newSone = !knownSones.contains(sone.getId());
- }
- sone.setKnown(!newSone);
- if (newSone) {
- coreListenerManager.fireNewSoneFound(sone);
- for (Sone localSone : getLocalSones()) {
- if (localSone.getOptions().getBooleanOption("AutoFollow").get()) {
- followSone(localSone, sone);
- }
+ coreListenerManager.fireNewSoneFound(sone);
+ for (Sone localSone : getLocalSones()) {
+ if (localSone.getOptions().getBooleanOption("AutoFollow").get()) {
+ followSone(localSone, sone);
}
}
}
- soneDownloader.addSone(sone);
- soneDownloaders.execute(new Runnable() {
+ }
+ soneDownloader.addSone(sone);
+ soneDownloaders.execute(new Runnable() {
- @Override
- @SuppressWarnings("synthetic-access")
- public void run() {
- soneDownloader.fetchSone(sone, sone.getRequestUri());
- }
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ soneDownloader.fetchSone(sone, sone.getRequestUri());
+ }
- });
- return sone;
- }
+ });
+ database.saveSone(sone);
+ return sone;
}
/**
}
/**
- * Sets the trust value of the given origin Sone for the target Sone.
+ * Sets the trust value of the given origin Sone for
+ * the target Sone.
*
* @param origin
* The origin Sone
logger.log(Level.WARNING, String.format("Tried to delete Sone of non-own identity: %s", sone));
return;
}
- synchronized (localSones) {
- if (!localSones.containsKey(sone.getId())) {
- logger.log(Level.WARNING, String.format("Tried to delete non-local Sone: %s", sone));
- return;
- }
- localSones.remove(sone.getId());
- SoneInserter soneInserter = soneInserters.remove(sone);
- soneInserter.removeSoneInsertListener(this);
- soneInserter.stop();
+ if (!sone.isLocal()) {
+ logger.log(Level.WARNING, String.format("Tried to delete non-local Sone: %s", sone));
+ return;
}
+ database.removeSone(sone.getId());
+ SoneInserter soneInserter = soneInserters.remove(sone);
+ soneInserter.removeSoneInsertListener(this);
+ soneInserter.stop();
webOfTrustUpdater.removeContext((OwnIdentity) sone.getIdentity(), "Sone");
webOfTrustUpdater.removeProperty((OwnIdentity) sone.getIdentity(), "Sone.LatestEdition");
try {
* 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);
+ Post post = getPost(postId, true).setSone(sone).setTime(postTime).setText(postText);
if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
post.setRecipient(getSone(postRecipientId));
}
logger.log(Level.WARNING, "Invalid reply found, aborting load!");
return;
}
- replies.add(getReply(replyId).setSone(sone).setPost(getPost(postId)).setTime(replyTime).setText(replyText));
+ replies.add(getReply(replyId).setSone(sone).setPost(getPost(postId, true)).setTime(replyTime).setText(replyText));
}
/* load post likes. */
*
* @param sone
* The Sone that creates the post
- * @param text
- * The text of the post
- * @return The created post
- */
- public Post createPost(Sone sone, String text) {
- return createPost(sone, System.currentTimeMillis(), text);
- }
-
- /**
- * Creates a new post.
- *
- * @param sone
- * The Sone that creates the post
- * @param time
- * The time of the post
- * @param text
- * The text of the post
- * @return The created post
- */
- public Post createPost(Sone sone, long time, String text) {
- return createPost(sone, null, time, text);
- }
-
- /**
- * Creates a new post.
- *
- * @param sone
- * The Sone that creates the post
- * @param recipient
- * The recipient Sone, or {@code null} if this post does not have
- * a recipient
- * @param text
- * The text of the post
- * @return The created post
- */
- public Post createPost(Sone sone, Sone recipient, String text) {
- return createPost(sone, recipient, System.currentTimeMillis(), text);
- }
-
- /**
- * Creates a new post.
- *
- * @param sone
- * The Sone that creates the post
* @param recipient
* The recipient Sone, or {@code null} if this post does not have
* a recipient
*/
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)) {
+ if (!sone.isLocal()) {
logger.log(Level.FINE, String.format("Tried to create post for non-local Sone: %s", sone));
return null;
}
* 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;
}
*/
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)) {
+ if (!sone.isLocal()) {
logger.log(Level.FINE, String.format("Tried to create reply for non-local Sone: %s", sone));
return null;
}
*/
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;
}
* The album to remove
*/
public void deleteAlbum(Album album) {
- Validation.begin().isNotNull("Album", album).check().is("Local Sone", isLocalSone(album.getSone())).check();
+ Validation.begin().isNotNull("Album", album).check().is("Local Sone", album.getSone().isLocal()).check();
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();
+ Validation.begin().isNotNull("Sone", sone).isNotNull("Album", album).isNotNull("Temporary Image", temporaryImage).check().is("Local Sone", sone.isLocal()).check().isEqual("Owner and Album Owner", sone, album.getSone()).check();
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();
+ Validation.begin().isNotNull("Image", image).check().is("Local Sone", image.getSone().isLocal()).check();
deleteTemporaryImage(image.getId());
image.getAlbum().removeImage(image);
synchronized (images) {
*/
@Override
public void serviceStop() {
- synchronized (localSones) {
- for (Entry<Sone, SoneInserter> soneInserter : soneInserters.entrySet()) {
- soneInserter.getValue().removeSoneInsertListener(this);
- soneInserter.getValue().stop();
- saveSone(soneInserter.getKey());
- }
+ for (Entry<Sone, SoneInserter> soneInserter : soneInserters.entrySet()) {
+ soneInserter.getValue().removeSoneInsertListener(this);
+ soneInserter.getValue().stop();
+ saveSone(soneInserter.getKey());
}
saveConfiguration();
webOfTrustUpdater.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;
}
}
}
}
- synchronized (remoteSones) {
- remoteSones.remove(identity.getId());
- }
+ database.removeSone(identity.getId());
coreListenerManager.fireSoneRemoved(sone);
}
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.data.Sone.SoneStatus;
+import net.pterodactylus.sone.database.memory.MemorySone;
import net.pterodactylus.util.collection.Pair;
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.logging.Logging;
return null;
}
- Sone sone = new Sone(originalSone.getId()).setIdentity(originalSone.getIdentity());
+ Sone sone = new MemorySone(originalSone.getId(), originalSone.isLocal()).setIdentity(originalSone.getIdentity());
SimpleXML soneXml;
try {
return null;
}
try {
- Post post = core.getPost(postId).setSone(sone).setTime(Long.parseLong(postTime)).setText(postText);
+ Post post = core.getPost(postId, true).setSone(sone).setTime(Long.parseLong(postTime)).setText(postText);
if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
post.setRecipient(core.getSone(postRecipientId));
}
return null;
}
try {
- replies.add(core.getReply(replyId).setSone(sone).setPost(core.getPost(replyPostId)).setTime(Long.parseLong(replyTime)).setText(replyText));
+ replies.add(core.getReply(replyId).setSone(sone).setPost(core.getPost(replyPostId, true)).setTime(Long.parseLong(replyTime)).setText(replyText));
} 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));
package net.pterodactylus.sone.data;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CopyOnWriteArraySet;
-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.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;
/**
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
-public class Sone implements Fingerprintable, Comparable<Sone> {
+public interface Sone extends Fingerprintable, Comparable<Sone> {
/**
* Enumeration for the possible states of a {@link Sone}.
}
};
- /** Filter that matches all {@link Core#isLocalSone(Sone) local Sones}. */
+ /** Filter that matches all {@link Core#getLocalSones() local Sones}. */
public static final Filter<Sone> LOCAL_SONE_FILTER = new Filter<Sone>() {
@Override
}
};
- /** The logger. */
- private static final Logger logger = Logging.getLogger(Sone.class);
-
- /** The ID of this Sone. */
- private final String id;
-
- /** The identity of this Sone. */
- private Identity identity;
-
- /** The URI under which the Sone is stored in Freenet. */
- private volatile FreenetURI requestUri;
-
- /** The URI used to insert a new version of this Sone. */
- /* This will be null for remote Sones! */
- private volatile FreenetURI insertUri;
-
- /** The latest edition of the Sone. */
- private volatile long latestEdition;
-
- /** The time of the last inserted update. */
- private volatile long time;
-
- /** The status of this Sone. */
- private volatile SoneStatus status = SoneStatus.unknown;
-
- /** The profile of this Sone. */
- private volatile Profile profile = new Profile(this);
-
- /** The client used by the Sone. */
- private volatile Client client;
-
- /** Whether this Sone is known. */
- private volatile boolean known;
-
- /** All friend Sones. */
- private final Set<String> friendSones = new CopyOnWriteArraySet<String>();
-
- /** All posts. */
- private final Set<Post> posts = new CopyOnWriteArraySet<Post>();
-
- /** All replies. */
- private final Set<PostReply> replies = new CopyOnWriteArraySet<PostReply>();
-
- /** The IDs of all liked posts. */
- private final Set<String> likedPostIds = new CopyOnWriteArraySet<String>();
-
- /** The IDs of all liked replies. */
- private final Set<String> likedReplyIds = new CopyOnWriteArraySet<String>();
-
- /** The albums of this Sone. */
- private final List<Album> albums = new CopyOnWriteArrayList<Album>();
-
- /** Sone-specific options. */
- private final Options options = new Options();
-
- /**
- * Creates a new Sone.
- *
- * @param id
- * The ID of the Sone
- */
- public Sone(String id) {
- this.id = id;
- }
-
//
// ACCESSORS
//
*
* @return The identity of this Sone
*/
- public String getId() {
- return id;
- }
+ public String getId();
/**
* Returns the identity of this Sone.
*
* @return The identity of this Sone
*/
- public Identity getIdentity() {
- return identity;
- }
+ public Identity getIdentity();
/**
* Sets the identity of this Sone. The {@link Identity#getId() ID} of the
* @throws IllegalArgumentException
* 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)) {
- throw new IllegalArgumentException("Identity’s ID does not match Sone’s ID!");
- }
- this.identity = identity;
- return this;
- }
+ public Sone setIdentity(Identity identity) throws IllegalArgumentException;
+
+ /**
+ * Returns whether this Sone is local.
+ *
+ * @return {@code true} if this Sone is local, {@code false} otherwise
+ */
+ public boolean isLocal();
/**
* Returns the name of this Sone.
*
* @return The name of this Sone
*/
- public String getName() {
- return (identity != null) ? identity.getNickname() : null;
- }
+ public String getName();
/**
* Returns the request URI of this Sone.
*
* @return The request URI of this Sone
*/
- public FreenetURI getRequestUri() {
- return (requestUri != null) ? requestUri.setSuggestedEdition(latestEdition) : null;
- }
+ public FreenetURI getRequestUri();
/**
* Sets the request URI of this Sone.
* The request URI of this Sone
* @return This Sone (for method chaining)
*/
- public Sone setRequestUri(FreenetURI requestUri) {
- if (this.requestUri == null) {
- this.requestUri = requestUri.setKeyType("USK").setDocName("Sone").setMetaString(new String[0]);
- return this;
- }
- if (!this.requestUri.equalsKeypair(requestUri)) {
- logger.log(Level.WARNING, String.format("Request URI %s tried to overwrite %s!", requestUri, this.requestUri));
- return this;
- }
- return this;
- }
+ public Sone setRequestUri(FreenetURI requestUri);
/**
* Returns the insert URI of this Sone.
*
* @return The insert URI of this Sone
*/
- public FreenetURI getInsertUri() {
- return (insertUri != null) ? insertUri.setSuggestedEdition(latestEdition) : null;
- }
+ public FreenetURI getInsertUri();
/**
* Sets the insert URI of this Sone.
* The insert URI of this Sone
* @return This Sone (for method chaining)
*/
- public Sone setInsertUri(FreenetURI insertUri) {
- if (this.insertUri == null) {
- this.insertUri = insertUri.setKeyType("USK").setDocName("Sone").setMetaString(new String[0]);
- return this;
- }
- if (!this.insertUri.equalsKeypair(insertUri)) {
- logger.log(Level.WARNING, String.format("Request URI %s tried to overwrite %s!", insertUri, this.insertUri));
- return this;
- }
- return this;
- }
+ public Sone setInsertUri(FreenetURI insertUri);
/**
* Returns the latest edition of this Sone.
*
* @return The latest edition of this Sone
*/
- public long getLatestEdition() {
- return latestEdition;
- }
+ public long getLatestEdition();
/**
* Sets the latest edition of this Sone. If the given latest edition is not
* @param latestEdition
* The latest edition of this Sone
*/
- public void setLatestEdition(long latestEdition) {
- if (!(latestEdition > this.latestEdition)) {
- logger.log(Level.FINE, String.format("New latest edition %d is not greater than current latest edition %d!", latestEdition, this.latestEdition));
- return;
- }
- this.latestEdition = latestEdition;
- }
+ public void setLatestEdition(long latestEdition);
/**
* Return the time of the last inserted update of this Sone.
*
* @return The time of the update (in milliseconds since Jan 1, 1970 UTC)
*/
- public long getTime() {
- return time;
- }
+ public long getTime();
/**
* Sets the time of the last inserted update of this Sone.
* The time of the update (in milliseconds since Jan 1, 1970 UTC)
* @return This Sone (for method chaining)
*/
- public Sone setTime(long time) {
- this.time = time;
- return this;
- }
+ public Sone setTime(long time);
/**
* Returns the status of this Sone.
*
* @return The status of this Sone
*/
- public SoneStatus getStatus() {
- return status;
- }
+ public SoneStatus getStatus();
/**
* Sets the new status of this Sone.
* @throws IllegalArgumentException
* if {@code status} is {@code null}
*/
- public Sone setStatus(SoneStatus status) {
- Validation.begin().isNotNull("Sone Status", status).check();
- this.status = status;
- return this;
- }
+ public Sone setStatus(SoneStatus status);
/**
* Returns a copy of the profile. If you want to update values in the
*
* @return A copy of the profile
*/
- public Profile getProfile() {
- return new Profile(profile);
- }
+ public Profile getProfile();
/**
* Sets the profile of this Sone. A copy of the given profile is stored so
* @param profile
* The profile to set
*/
- public void setProfile(Profile profile) {
- this.profile = new Profile(profile);
- }
+ public void setProfile(Profile profile);
/**
* Returns the client used by this Sone.
*
* @return The client used by this Sone, or {@code null}
*/
- public Client getClient() {
- return client;
- }
+ public Client getClient();
/**
* Sets the client used by this Sone.
* The client used by this Sone, or {@code null}
* @return This Sone (for method chaining)
*/
- public Sone setClient(Client client) {
- this.client = client;
- return this;
- }
+ public Sone setClient(Client client);
/**
* Returns whether this Sone is known.
*
* @return {@code true} if this Sone is known, {@code false} otherwise
*/
- public boolean isKnown() {
- return known;
- }
+ public boolean isKnown();
/**
* Sets whether this Sone is known.
* {@code true} if this Sone is known, {@code false} otherwise
* @return This Sone
*/
- public Sone setKnown(boolean known) {
- this.known = known;
- return this;
- }
+ public Sone setKnown(boolean known);
/**
* Returns all friend Sones of this Sone.
*
* @return The friend Sones of this Sone
*/
- public List<String> getFriends() {
- List<String> friends = new ArrayList<String>(friendSones);
- return friends;
- }
+ public Collection<String> getFriends();
/**
* Returns whether this Sone has the given Sone as a friend Sone.
* @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);
- }
+ public boolean hasFriend(String friendSoneId);
/**
* Adds the given Sone as a friend Sone.
* The friend Sone to add
* @return This Sone (for method chaining)
*/
- public Sone addFriend(String friendSone) {
- if (!friendSone.equals(id)) {
- friendSones.add(friendSone);
- }
- return this;
- }
+ public Sone addFriend(String friendSone);
/**
* Removes the given Sone as a friend Sone.
* The ID of the friend Sone to remove
* @return This Sone (for method chaining)
*/
- public Sone removeFriend(String friendSoneId) {
- friendSones.remove(friendSoneId);
- return this;
- }
+ public Sone removeFriend(String friendSoneId);
/**
* Returns the list of posts of this Sone, sorted by time, newest first.
*
* @return All posts of this Sone
*/
- public List<Post> getPosts() {
- List<Post> sortedPosts;
- synchronized (this) {
- sortedPosts = new ArrayList<Post>(posts);
- }
- Collections.sort(sortedPosts, Post.TIME_COMPARATOR);
- return sortedPosts;
- }
+ public List<Post> getPosts();
/**
* Sets all posts of this Sone at once.
* The new (and only) posts of this Sone
* @return This Sone (for method chaining)
*/
- public Sone setPosts(Collection<Post> posts) {
- synchronized (this) {
- this.posts.clear();
- this.posts.addAll(posts);
- }
- return this;
- }
+ public Sone setPosts(Collection<Post> posts);
/**
* Adds the given post to this Sone. The post will not be added if its
* @param post
* The post to add
*/
- public void addPost(Post post) {
- if (post.getSone().equals(this) && posts.add(post)) {
- logger.log(Level.FINEST, String.format("Adding %s to “%s”.", post, getName()));
- }
- }
+ public void addPost(Post post);
/**
* Removes the given post from this Sone.
* @param post
* The post to remove
*/
- public void removePost(Post post) {
- if (post.getSone().equals(this)) {
- posts.remove(post);
- }
- }
+ public void removePost(Post post);
/**
* Returns all replies this Sone made.
*
* @return All replies this Sone made
*/
- public Set<PostReply> getReplies() {
- return Collections.unmodifiableSet(replies);
- }
+ public Set<PostReply> getReplies();
/**
* Sets all replies of this Sone at once.
* The new (and only) replies of this Sone
* @return This Sone (for method chaining)
*/
- public Sone setReplies(Collection<PostReply> replies) {
- this.replies.clear();
- this.replies.addAll(replies);
- return this;
- }
+ public Sone setReplies(Collection<PostReply> replies);
/**
* Adds a reply to this Sone. If the given reply was not made by this Sone,
* @param reply
* The reply to add
*/
- public void addReply(PostReply reply) {
- if (reply.getSone().equals(this)) {
- replies.add(reply);
- }
- }
+ public void addReply(PostReply reply);
/**
* Removes a reply from this Sone.
* @param reply
* The reply to remove
*/
- public void removeReply(PostReply reply) {
- if (reply.getSone().equals(this)) {
- replies.remove(reply);
- }
- }
+ public void removeReply(PostReply reply);
/**
* Returns the IDs of all liked posts.
*
* @return All liked posts’ IDs
*/
- public Set<String> getLikedPostIds() {
- return Collections.unmodifiableSet(likedPostIds);
- }
+ public Set<String> getLikedPostIds();
/**
* Sets the IDs of all liked posts.
* All liked posts’ IDs
* @return This Sone (for method chaining)
*/
- public Sone setLikePostIds(Set<String> likedPostIds) {
- this.likedPostIds.clear();
- this.likedPostIds.addAll(likedPostIds);
- return this;
- }
+ public Sone setLikePostIds(Set<String> likedPostIds);
/**
* Checks whether the given post ID is liked by this Sone.
* @return {@code true} if this Sone likes the given post, {@code false}
* otherwise
*/
- public boolean isLikedPostId(String postId) {
- return likedPostIds.contains(postId);
- }
+ public boolean isLikedPostId(String postId);
/**
* Adds the given post ID to the list of posts this Sone likes.
* The ID of the post
* @return This Sone (for method chaining)
*/
- public Sone addLikedPostId(String postId) {
- likedPostIds.add(postId);
- return this;
- }
+ public Sone addLikedPostId(String postId);
/**
* Removes the given post ID from the list of posts this Sone likes.
* The ID of the post
* @return This Sone (for method chaining)
*/
- public Sone removeLikedPostId(String postId) {
- likedPostIds.remove(postId);
- return this;
- }
+ public Sone removeLikedPostId(String postId);
/**
* Returns the IDs of all liked replies.
*
* @return All liked replies’ IDs
*/
- public Set<String> getLikedReplyIds() {
- return Collections.unmodifiableSet(likedReplyIds);
- }
+ public Set<String> getLikedReplyIds();
/**
* Sets the IDs of all liked replies.
* All liked replies’ IDs
* @return This Sone (for method chaining)
*/
- public Sone setLikeReplyIds(Set<String> likedReplyIds) {
- this.likedReplyIds.clear();
- this.likedReplyIds.addAll(likedReplyIds);
- return this;
- }
+ public Sone setLikeReplyIds(Set<String> likedReplyIds);
/**
* Checks whether the given reply ID is liked by this Sone.
* @return {@code true} if this Sone likes the given reply, {@code false}
* otherwise
*/
- public boolean isLikedReplyId(String replyId) {
- return likedReplyIds.contains(replyId);
- }
+ public boolean isLikedReplyId(String replyId);
/**
* Adds the given reply ID to the list of replies this Sone likes.
* The ID of the reply
* @return This Sone (for method chaining)
*/
- public Sone addLikedReplyId(String replyId) {
- likedReplyIds.add(replyId);
- return this;
- }
+ public Sone addLikedReplyId(String replyId);
/**
* Removes the given post ID from the list of replies this Sone likes.
* The ID of the reply
* @return This Sone (for method chaining)
*/
- public Sone removeLikedReplyId(String replyId) {
- likedReplyIds.remove(replyId);
- return this;
- }
+ public Sone removeLikedReplyId(String replyId);
/**
* Returns the albums of this Sone.
*
* @return The albums of this Sone
*/
- public List<Album> getAlbums() {
- return Collections.unmodifiableList(albums);
- }
+ public List<Album> getAlbums();
/**
* Returns a flattened list of all albums of this Sone. The resulting list
*
* @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;
- }
+ public List<Album> getAllAlbums();
/**
* Returns all images of a Sone. Images of a album are inserted into this
*
* @return The list of all images
*/
- public List<Image> getAllImages() {
- List<Image> allImages = new ArrayList<Image>();
- for (Album album : getAllAlbums()) {
- allImages.addAll(album.getImages());
- }
- return allImages;
- }
+ public List<Image> getAllImages();
/**
* Adds an album to this Sone.
* @param album
* The album to add
*/
- public void addAlbum(Album album) {
- Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
- if (!albums.contains(album)) {
- albums.add(album);
- }
- }
+ public void addAlbum(Album album);
/**
* Sets the albums of this Sone.
* @param albums
* The albums of this Sone
*/
- public void setAlbums(Collection<? extends Album> albums) {
- Validation.begin().isNotNull("Albums", albums).check();
- this.albums.clear();
- for (Album album : albums) {
- addAlbum(album);
- }
- }
+ public void setAlbums(Collection<? extends Album> albums);
/**
* Removes an album from this Sone.
* @param album
* The album to remove
*/
- public void removeAlbum(Album album) {
- Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
- albums.remove(album);
- }
+ public void removeAlbum(Album album);
/**
* Moves the given album up in this album’s albums. If the album is already
* @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();
- int oldIndex = albums.indexOf(album);
- if (oldIndex <= 0) {
- return null;
- }
- albums.remove(oldIndex);
- albums.add(oldIndex - 1, album);
- return albums.get(oldIndex);
- }
+ public Album moveAlbumUp(Album album);
/**
* Moves the given album down in this album’s albums. If the album is
* @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();
- int oldIndex = albums.indexOf(album);
- if ((oldIndex < 0) || (oldIndex >= (albums.size() - 1))) {
- return null;
- }
- albums.remove(oldIndex);
- albums.add(oldIndex + 1, album);
- return albums.get(oldIndex);
- }
+ public Album moveAlbumDown(Album album);
/**
* Returns Sone-specific options.
*
* @return The options of this Sone
*/
- public Options getOptions() {
- return options;
- }
-
- //
- // FINGERPRINTABLE METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public synchronized String getFingerprint() {
- StringBuilder fingerprint = new StringBuilder();
- fingerprint.append(profile.getFingerprint());
-
- fingerprint.append("Posts(");
- for (Post post : getPosts()) {
- fingerprint.append("Post(").append(post.getId()).append(')');
- }
- fingerprint.append(")");
-
- List<PostReply> replies = new ArrayList<PostReply>(getReplies());
- Collections.sort(replies, Reply.TIME_COMPARATOR);
- fingerprint.append("Replies(");
- for (PostReply reply : replies) {
- fingerprint.append("Reply(").append(reply.getId()).append(')');
- }
- fingerprint.append(')');
-
- List<String> likedPostIds = new ArrayList<String>(getLikedPostIds());
- Collections.sort(likedPostIds);
- fingerprint.append("LikedPosts(");
- for (String likedPostId : likedPostIds) {
- fingerprint.append("Post(").append(likedPostId).append(')');
- }
- fingerprint.append(')');
-
- List<String> likedReplyIds = new ArrayList<String>(getLikedReplyIds());
- Collections.sort(likedReplyIds);
- fingerprint.append("LikedReplies(");
- for (String likedReplyId : likedReplyIds) {
- fingerprint.append("Reply(").append(likedReplyId).append(')');
- }
- fingerprint.append(')');
-
- fingerprint.append("Albums(");
- for (Album album : albums) {
- fingerprint.append(album.getFingerprint());
- }
- fingerprint.append(')');
-
- return fingerprint.toString();
- }
-
- //
- // INTERFACE Comparable<Sone>
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int compareTo(Sone sone) {
- return NICE_NAME_COMPARATOR.compare(this, sone);
- }
-
- //
- // OBJECT METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return id.hashCode();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof Sone)) {
- return false;
- }
- return ((Sone) object).id.equals(id);
- }
-
- /**
- * {@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() + ")]";
- }
+ public Options getOptions();
}
--- /dev/null
+/*
+ * Sone - Database.java - Copyright © 2011 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;
+
+/**
+ * Interface for Sone’s database.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface Database {
+
+ /**
+ * Returns the Sone with the given ID, creating a new Sone if a Sone with
+ * the given ID does not exist and {@code create} is {@code true}. When
+ * searching for a Sone with the given IDs, local Sones are preferred.
+ *
+ * @param id
+ * The ID of the new Sone
+ * @param create
+ * {@code true} to create a new Sone if a Sone with the given ID
+ * does not exist, {@code false} to return {@code null} if a Sone
+ * with the given ID does not exist
+ * @return The created Sone
+ * @throws IllegalArgumentException
+ * if {@code id} is {@code null}
+ * @throws DatabaseException
+ * if a database error occurs
+ */
+ public Sone getSone(String id, boolean create) throws DatabaseException;
+
+ /**
+ * Returns all known Sones.
+ *
+ * @return All known Sones
+ * @throws DatabaseException
+ * if a database error occurs
+ */
+ public Collection<Sone> getSones() throws DatabaseException;
+
+ /**
+ * Returns all known local Sones.
+ *
+ * @return All known local Sones
+ * @throws DatabaseException
+ * if a database error occurs
+ */
+ public Collection<Sone> getLocalSones() throws DatabaseException;
+
+ /**
+ * Returns all known remote Sones.
+ *
+ * @return All known remote Sones
+ * @throws DatabaseException
+ * if a database error occurs
+ */
+ public Collection<Sone> getRemoteSones() throws DatabaseException;
+
+ /**
+ * Returns the local Sone with the given ID, creating it if it doesn’t exist
+ * and {@code create} is {@code true}.
+ *
+ * @param id
+ * The ID of the Sone
+ * @param create
+ * {@code true} to create a Sone if no Sone with the given ID
+ * exists yet, {@code false} to return {@code null}
+ * @return The existing Sone, the created Sone, or {@code null}
+ * @throws DatabaseException
+ * if adatabase error occurs
+ */
+ public Sone getLocalSone(String id, boolean create) throws DatabaseException;
+
+ /**
+ * Returns the remote Sone with the given ID, creating it if it doesn’t
+ * exist and {@code create} is {@code true}.
+ *
+ * @param id
+ * The ID of the Sone
+ * @param create
+ * {@code true} to create a Sone if no Sone with the given ID
+ * exists yet, {@code false} to return {@code null}
+ * @return The existing Sone, the created Sone, or {@code null}
+ * @throws DatabaseException
+ * if adatabase error occurs
+ */
+ public Sone getRemoteSone(String id, boolean create) throws DatabaseException;
+
+ /**
+ * Stores the given Sone. The given Sone has to be an object that was
+ * returned by a previous call to {@link #getSone(String, boolean)}.
+ *
+ * @param sone
+ * The Sone to store
+ * @throws IllegalArgumentException
+ * if {@code sone} is {@code null}, or the Sone was not
+ * retrieved by a call to {@link #getSone(String, boolean)}
+ * @throws DatabaseException
+ * if a database error occurs
+ */
+ public void saveSone(Sone sone) throws DatabaseException;
+
+ /**
+ * Removes the given Sone from the database.
+ *
+ * @param sone
+ * The Sone to remove
+ * @throws DatabaseException
+ * if a database error occurs
+ */
+ public void removeSone(Sone sone) throws DatabaseException;
+
+ /**
+ * Removes the Sone with the given ID from the database.
+ *
+ * @param id
+ * The ID of the Sone to remove
+ * @throws DatabaseException
+ * if a database error occurs
+ */
+ public void removeSone(String id) throws DatabaseException;
+
+}
--- /dev/null
+/*
+ * Sone - DatabaseException.java - Copyright © 2011 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 an error working with the database.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DatabaseException extends RuntimeException {
+
+ /**
+ * 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 - MemoryDatabase.java - Copyright © 2011 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.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.pterodactylus.sone.core.Core;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.Database;
+import net.pterodactylus.sone.database.DatabaseException;
+import net.pterodactylus.util.collection.SetBuilder;
+import net.pterodactylus.util.validation.Validation;
+
+/**
+ * In-memory implementation of {@link Database} that stores all its data in a
+ * {@link Map}. This is roughly equivalent to what {@link Core} does today and
+ * is mainly used while Sone is transitioning to using a real database.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class MemoryDatabase implements Database {
+
+ /** The local Sones. */
+ private final Map<String, Sone> localSones = new HashMap<String, Sone>();
+
+ /** The remote Sones. */
+ private final Map<String, Sone> remoteSones = new HashMap<String, Sone>();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone getSone(String id, boolean create) throws DatabaseException {
+ if (getLocalSone(id, false) != null) {
+ return getLocalSone(id, create);
+ }
+ return getRemoteSone(id, create);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Sone> getSones() throws DatabaseException {
+ return new SetBuilder<Sone>().addAll(getLocalSones()).addAll(getRemoteSones()).get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Sone> getLocalSones() throws DatabaseException {
+ synchronized (localSones) {
+ return Collections.unmodifiableCollection(localSones.values());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<Sone> getRemoteSones() throws DatabaseException {
+ synchronized (remoteSones) {
+ return Collections.unmodifiableCollection(remoteSones.values());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone getLocalSone(String id, boolean create) throws DatabaseException {
+ Validation.begin().isNotNull("Sone ID", id).check();
+ synchronized (localSones) {
+ if (!localSones.containsKey(id) && create) {
+ localSones.put(id, new MemorySone(id, true));
+ }
+ return localSones.get(id);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone getRemoteSone(String id, boolean create) throws DatabaseException {
+ Validation.begin().isNotNull("Sone ID", id).check();
+ synchronized (remoteSones) {
+ if (!remoteSones.containsKey(id) && create) {
+ remoteSones.put(id, new MemorySone(id, false));
+ }
+ return remoteSones.get(id);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void saveSone(Sone sone) throws DatabaseException {
+ if (sone.isLocal()) {
+ synchronized (localSones) {
+ localSones.put(sone.getId(), sone);
+ }
+ } else {
+ synchronized (remoteSones) {
+ Validation.begin().is("Sone is from this database", remoteSones.containsKey(sone.getId())).check();
+ remoteSones.put(sone.getId(), sone);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeSone(Sone sone) throws DatabaseException {
+ Map<String, Sone> sones = sone.isLocal() ? localSones : remoteSones;
+ synchronized (sones) {
+ sones.remove(sone.getId());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeSone(String id) throws DatabaseException {
+ Map<String, Sone> sones = ((getSone(id, false) != null) && getSone(id, false).isLocal()) ? localSones : remoteSones;
+ synchronized (sones) {
+ sones.remove(id);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Sone - MemorySone.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.database.memory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import net.pterodactylus.sone.core.Options;
+import net.pterodactylus.sone.data.Album;
+import net.pterodactylus.sone.data.Client;
+import net.pterodactylus.sone.data.Image;
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Profile;
+import net.pterodactylus.sone.data.Reply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.Database;
+import net.pterodactylus.sone.freenet.wot.Identity;
+import net.pterodactylus.util.logging.Logging;
+import net.pterodactylus.util.validation.Validation;
+import freenet.keys.FreenetURI;
+
+/**
+ * Implementation of a {@link Sone} that keeps all added data in memory. A
+ * self-created instance of this class should be converted to a {@link Database}
+ * -based instance of {@link Sone} as soon as possible (unless it was returned
+ * by a {@link MemoryDatabase}).
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class MemorySone implements Sone {
+
+ /** The logger. */
+ private static final Logger logger = Logging.getLogger(Sone.class);
+
+ /** The ID of this Sone. */
+ private final String id;
+
+ /** Whether this is a local Sone. */
+ private final boolean local;
+
+ /** The identity of this Sone. */
+ private Identity identity;
+
+ /** The URI under which the Sone is stored in Freenet. */
+ private volatile FreenetURI requestUri;
+
+ /** The URI used to insert a new version of this Sone. */
+ /* This will be null for remote Sones! */
+ private volatile FreenetURI insertUri;
+
+ /** The latest edition of the Sone. */
+ private volatile long latestEdition;
+
+ /** The time of the last inserted update. */
+ private volatile long time;
+
+ /** The status of this Sone. */
+ private volatile SoneStatus status = SoneStatus.unknown;
+
+ /** The profile of this Sone. */
+ private volatile Profile profile = new Profile(this);
+
+ /** The client used by the Sone. */
+ private volatile Client client;
+
+ /** Whether this Sone is known. */
+ private volatile boolean known;
+
+ /** All friend Sones. */
+ private final Set<String> friendSones = new CopyOnWriteArraySet<String>();
+
+ /** All posts. */
+ private final Set<Post> posts = new CopyOnWriteArraySet<Post>();
+
+ /** All replies. */
+ private final Set<PostReply> replies = new CopyOnWriteArraySet<PostReply>();
+
+ /** The IDs of all liked posts. */
+ private final Set<String> likedPostIds = new CopyOnWriteArraySet<String>();
+
+ /** The IDs of all liked replies. */
+ private final Set<String> likedReplyIds = new CopyOnWriteArraySet<String>();
+
+ /** The albums of this Sone. */
+ private final List<Album> albums = new CopyOnWriteArrayList<Album>();
+
+ /** Sone-specific options. */
+ private final Options options = new Options();
+
+ /**
+ * Creates a new Sone.
+ *
+ * @param id
+ * The ID of the Sone
+ * @param local
+ * {@code true} if this Sone is local, {@code false} otherwise
+ */
+ public MemorySone(String id, boolean local) {
+ this.id = id;
+ this.local = local;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Identity getIdentity() {
+ return identity;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setIdentity(Identity identity) throws IllegalArgumentException {
+ if (!identity.getId().equals(id)) {
+ throw new IllegalArgumentException("Identity’s ID does not match Sone’s ID!");
+ }
+ this.identity = identity;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isLocal() {
+ return local;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() {
+ return (identity != null) ? identity.getNickname() : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public FreenetURI getRequestUri() {
+ return (requestUri != null) ? requestUri.setSuggestedEdition(latestEdition) : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setRequestUri(FreenetURI requestUri) {
+ if (this.requestUri == null) {
+ this.requestUri = requestUri.setKeyType("USK").setDocName("Sone").setMetaString(new String[0]);
+ return this;
+ }
+ if (!this.requestUri.equalsKeypair(requestUri)) {
+ logger.log(Level.WARNING, String.format("Request URI %s tried to overwrite %s!", requestUri, this.requestUri));
+ return this;
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public FreenetURI getInsertUri() {
+ return (insertUri != null) ? insertUri.setSuggestedEdition(latestEdition) : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setInsertUri(FreenetURI insertUri) {
+ if (this.insertUri == null) {
+ this.insertUri = insertUri.setKeyType("USK").setDocName("Sone").setMetaString(new String[0]);
+ return this;
+ }
+ if (!this.insertUri.equalsKeypair(insertUri)) {
+ logger.log(Level.WARNING, String.format("Request URI %s tried to overwrite %s!", insertUri, this.insertUri));
+ return this;
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getLatestEdition() {
+ return latestEdition;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setLatestEdition(long latestEdition) {
+ if (!(latestEdition > this.latestEdition)) {
+ logger.log(Level.FINE, String.format("New latest edition %d is not greater than current latest edition %d!", latestEdition, this.latestEdition));
+ return;
+ }
+ this.latestEdition = latestEdition;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getTime() {
+ return time;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setTime(long time) {
+ this.time = time;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public SoneStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setStatus(SoneStatus status) {
+ Validation.begin().isNotNull("Sone Status", status).check();
+ this.status = status;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Profile getProfile() {
+ return new Profile(profile);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setProfile(Profile profile) {
+ this.profile = new Profile(profile);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Client getClient() {
+ return client;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setClient(Client client) {
+ this.client = client;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isKnown() {
+ return known;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setKnown(boolean known) {
+ this.known = known;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<String> getFriends() {
+ List<String> friends = new ArrayList<String>(friendSones);
+ return friends;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean hasFriend(String friendSoneId) {
+ return friendSones.contains(friendSoneId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone addFriend(String friendSone) {
+ if (!friendSone.equals(id)) {
+ friendSones.add(friendSone);
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone removeFriend(String friendSoneId) {
+ friendSones.remove(friendSoneId);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Post> getPosts() {
+ List<Post> sortedPosts;
+ synchronized (this) {
+ sortedPosts = new ArrayList<Post>(posts);
+ }
+ Collections.sort(sortedPosts, Post.TIME_COMPARATOR);
+ return sortedPosts;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setPosts(Collection<Post> posts) {
+ synchronized (this) {
+ this.posts.clear();
+ this.posts.addAll(posts);
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addPost(Post post) {
+ if (post.getSone().equals(this) && posts.add(post)) {
+ logger.log(Level.FINEST, String.format("Adding %s to “%s”.", post, getName()));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removePost(Post post) {
+ if (post.getSone().equals(this)) {
+ posts.remove(post);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<PostReply> getReplies() {
+ return Collections.unmodifiableSet(replies);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setReplies(Collection<PostReply> replies) {
+ this.replies.clear();
+ this.replies.addAll(replies);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addReply(PostReply reply) {
+ if (reply.getSone().equals(this)) {
+ replies.add(reply);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeReply(PostReply reply) {
+ if (reply.getSone().equals(this)) {
+ replies.remove(reply);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<String> getLikedPostIds() {
+ return Collections.unmodifiableSet(likedPostIds);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setLikePostIds(Set<String> likedPostIds) {
+ this.likedPostIds.clear();
+ this.likedPostIds.addAll(likedPostIds);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isLikedPostId(String postId) {
+ return likedPostIds.contains(postId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone addLikedPostId(String postId) {
+ likedPostIds.add(postId);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone removeLikedPostId(String postId) {
+ likedPostIds.remove(postId);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<String> getLikedReplyIds() {
+ return Collections.unmodifiableSet(likedReplyIds);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone setLikeReplyIds(Set<String> likedReplyIds) {
+ this.likedReplyIds.clear();
+ this.likedReplyIds.addAll(likedReplyIds);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isLikedReplyId(String replyId) {
+ return likedReplyIds.contains(replyId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone addLikedReplyId(String replyId) {
+ likedReplyIds.add(replyId);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone removeLikedReplyId(String replyId) {
+ likedReplyIds.remove(replyId);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Album> getAlbums() {
+ return Collections.unmodifiableList(albums);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ 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;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Image> getAllImages() {
+ List<Image> allImages = new ArrayList<Image>();
+ for (Album album : getAllAlbums()) {
+ allImages.addAll(album.getImages());
+ }
+ return allImages;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addAlbum(Album album) {
+ Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
+ if (!albums.contains(album)) {
+ albums.add(album);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setAlbums(Collection<? extends Album> albums) {
+ Validation.begin().isNotNull("Albums", albums).check();
+ this.albums.clear();
+ for (Album album : albums) {
+ addAlbum(album);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeAlbum(Album album) {
+ Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
+ albums.remove(album);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Album moveAlbumUp(Album album) {
+ Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).isNull("Album Parent", album.getParent()).check();
+ int oldIndex = albums.indexOf(album);
+ if (oldIndex <= 0) {
+ return null;
+ }
+ albums.remove(oldIndex);
+ albums.add(oldIndex - 1, album);
+ return albums.get(oldIndex);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Album moveAlbumDown(Album album) {
+ Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).isNull("Album Parent", album.getParent()).check();
+ int oldIndex = albums.indexOf(album);
+ if ((oldIndex < 0) || (oldIndex >= (albums.size() - 1))) {
+ return null;
+ }
+ albums.remove(oldIndex);
+ albums.add(oldIndex + 1, album);
+ return albums.get(oldIndex);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Options getOptions() {
+ return options;
+ }
+
+ //
+ // FINGERPRINTABLE METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized String getFingerprint() {
+ StringBuilder fingerprint = new StringBuilder();
+ fingerprint.append(profile.getFingerprint());
+
+ fingerprint.append("Posts(");
+ for (Post post : getPosts()) {
+ fingerprint.append("Post(").append(post.getId()).append(')');
+ }
+ fingerprint.append(")");
+
+ List<PostReply> replies = new ArrayList<PostReply>(getReplies());
+ Collections.sort(replies, Reply.TIME_COMPARATOR);
+ fingerprint.append("Replies(");
+ for (PostReply reply : replies) {
+ fingerprint.append("Reply(").append(reply.getId()).append(')');
+ }
+ fingerprint.append(')');
+
+ List<String> likedPostIds = new ArrayList<String>(getLikedPostIds());
+ Collections.sort(likedPostIds);
+ fingerprint.append("LikedPosts(");
+ for (String likedPostId : likedPostIds) {
+ fingerprint.append("Post(").append(likedPostId).append(')');
+ }
+ fingerprint.append(')');
+
+ List<String> likedReplyIds = new ArrayList<String>(getLikedReplyIds());
+ Collections.sort(likedReplyIds);
+ fingerprint.append("LikedReplies(");
+ for (String likedReplyId : likedReplyIds) {
+ fingerprint.append("Reply(").append(likedReplyId).append(')');
+ }
+ fingerprint.append(')');
+
+ fingerprint.append("Albums(");
+ for (Album album : albums) {
+ fingerprint.append(album.getFingerprint());
+ }
+ fingerprint.append(')');
+
+ return fingerprint.toString();
+ }
+
+ //
+ // INTERFACE Comparable<Sone>
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compareTo(Sone sone) {
+ return NICE_NAME_COMPARATOR.compare(this, sone);
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof Sone)) {
+ return false;
+ }
+ return ((Sone) object).getId().equals(id);
+ }
+
+ /**
+ * {@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() + ")]";
+ }
+
+}
/**
* FCP command that creates a new {@link Post}.
*
- * @see Core#createPost(Sone, Sone, String)
+ * @see Core#createPost(Sone, Sone, long, String)
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
public class CreatePostCommand extends AbstractSoneCommand {
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, recipient, System.currentTimeMillis(), text);
return new Response("PostCreated", new SimpleFieldSetBuilder().put("Post", post.getId()).get());
}
@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());
@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());
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.memory.MemoryDatabase;
import net.pterodactylus.sone.fcp.FcpInterface;
import net.pterodactylus.sone.freenet.PluginStoreConfigurationBackend;
import net.pterodactylus.sone.freenet.plugin.PluginConnector;
webOfTrustConnector = new WebOfTrustConnector(pluginConnector);
identityManager = new IdentityManager(webOfTrustConnector, "Sone");
+ /* create Sone database. */
+ Database soneDatabase = new MemoryDatabase();
+
/* create trust updater. */
WebOfTrustUpdater trustUpdater = new WebOfTrustUpdater(webOfTrustConnector);
trustUpdater.init();
/* create core. */
- core = new Core(oldConfiguration, freenetInterface, identityManager, trustUpdater);
+ core = new Core(oldConfiguration, soneDatabase, freenetInterface, identityManager, trustUpdater);
/* create the web interface. */
webInterface = new WebInterface(this);
return null;
}
Sone remoteSone = profile.getSone();
- if (core.isLocalSone(remoteSone)) {
+ if (remoteSone.isLocal()) {
/* always show your own avatars. */
return avatarId;
}
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());
import net.pterodactylus.sone.core.SoneProvider;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.memory.MemorySone;
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.logging.Logging;
import freenet.keys.FreenetURI;
* don’t use create=true above, we don’t want
* the empty shell.
*/
- sone = new Sone(soneId);
+ sone = new MemorySone(soneId, false);
}
parts.add(new SonePart(sone));
line = line.substring(50);
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);
+ Post post = webInterface.getCore().getPost(postId, false);
if (text.length() > 0) {
String senderId = request.getHttpRequest().getPartAsStringFailsafe("sender", 43);
Sone sender = webInterface.getCore().getLocalSone(senderId, false);
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")) {
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) {
if (request.getMethod() == Method.GET) {
String postId = request.getHttpRequest().getParam("post");
String returnPage = request.getHttpRequest().getParam("returnPage");
- Post post = webInterface.getCore().getPost(postId);
+ Post post = webInterface.getCore().getPost(postId, false);
templateContext.set("post", post);
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())) {
+ Post post = webInterface.getCore().getPost(postId, false);
+ if (!post.getSone().isLocal()) {
throw new RedirectException("noPermission.html");
}
if (request.getHttpRequest().isPartSet("confirmDelete")) {
PostReply reply = webInterface.getCore().getReply(replyId);
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
if (request.getMethod() == Method.POST) {
- if (!webInterface.getCore().isLocalSone(reply.getSone())) {
+ if (!reply.getSone().isLocal()) {
throw new RedirectException("noPermission.html");
}
if (request.getHttpRequest().isPartSet("confirmDelete")) {
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))) {
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))) {
redirectIfNotNull(getImageId(phrase), "imageBrowser.html?image=");
}
- Set<Sone> sones = webInterface.getCore().getSones();
+ Collection<Sone> sones = webInterface.getCore().getSones();
Set<Hit<Sone>> soneHits = getHits(sones, phrases, SoneStringGenerator.COMPLETE_GENERATOR);
Set<Hit<Post>> postHits;
super.processTemplate(request, templateContext);
String postId = request.getHttpRequest().getParam("post");
boolean raw = request.getHttpRequest().getParam("raw").equals("true");
- Post post = webInterface.getCore().getPost(postId);
+ Post post = webInterface.getCore().getPost(postId, false);
templateContext.set("post", post);
templateContext.set("raw", raw);
}
* 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();
}
}
/**
- * 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 Core#getLocalSones() local Sone}s that are referenced
+ * by {@link SonePart}s in the given text (after parsing it using
* {@link SoneTextParser}).
*
* @param text
*/
@Override
public void newPostFound(Post post) {
- boolean isLocal = getCore().isLocalSone(post.getSone());
- if (isLocal) {
+ if (post.getSone().isLocal()) {
localPostNotification.add(post);
} else {
newPostNotification.add(post);
}
if (!hasFirstStartNotification()) {
- notificationManager.addNotification(isLocal ? localPostNotification : newPostNotification);
- if (!getMentionedSones(post.getText()).isEmpty() && !isLocal) {
+ notificationManager.addNotification(post.getSone().isLocal() ? localPostNotification : newPostNotification);
+ if (!getMentionedSones(post.getText()).isEmpty() && !post.getSone().isLocal()) {
mentionNotification.add(post);
notificationManager.addNotification(mentionNotification);
}
*/
@Override
public void newReplyFound(PostReply reply) {
- boolean isLocal = getCore().isLocalSone(reply.getSone());
- if (isLocal) {
+ if (reply.getSone().isLocal()) {
localReplyNotification.add(reply);
} else {
newReplyNotification.add(reply);
}
if (!hasFirstStartNotification()) {
- notificationManager.addNotification(isLocal ? localReplyNotification : newReplyNotification);
- if (!getMentionedSones(reply.getText()).isEmpty() && !isLocal && (reply.getPost().getSone() != null) && (reply.getTime() <= System.currentTimeMillis())) {
+ notificationManager.addNotification(reply.getSone().isLocal() ? localReplyNotification : newReplyNotification);
+ if (!getMentionedSones(reply.getText()).isEmpty() && !reply.getSone().isLocal() && (reply.getPost().getSone() != null) && (reply.getTime() <= System.currentTimeMillis())) {
mentionNotification.add(reply.getPost());
notificationManager.addNotification(mentionNotification);
}
return createErrorJsonObject("text-required");
}
text = TextFilter.filter(request.getHttpRequest().getHeader("host"), text);
- Post newPost = webInterface.getCore().createPost(sender, recipient, text);
+ Post newPost = webInterface.getCore().createPost(sender, recipient, System.currentTimeMillis(), text);
return createSuccessJsonObject().put("postId", newPost.getId()).put("sone", sender.getId()).put("recipient", (newPost.getRecipient() != null) ? newPost.getRecipient().getId() : null);
}
if (sender == null) {
sender = getCurrentSone(request.getToadletContext());
}
- Post post = webInterface.getCore().getPost(postId);
+ Post post = webInterface.getCore().getPost(postId, false);
if ((post == null) || (post.getSone() == null)) {
return createErrorJsonObject("invalid-post-id");
}
if ((post == null) || (post.getSone() == null)) {
return createErrorJsonObject("invalid-post-id");
}
- if (!webInterface.getCore().isLocalSone(post.getSone())) {
+ if (!post.getSone().isLocal()) {
return createErrorJsonObject("not-authorized");
}
webInterface.getCore().deletePost(post);
if (reply == null) {
return createErrorJsonObject("invalid-reply-id");
}
- if (!webInterface.getCore().isLocalSone(reply.getSone())) {
+ if (!reply.getSone().isLocal()) {
return createErrorJsonObject("not-authorized");
}
webInterface.getCore().deleteReply(reply);
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"))) {
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"))) {
return createErrorJsonObject("invalid-" + type + "-id");
}
if ("post".equals(type)) {
- Post post = webInterface.getCore().getPost(id);
+ Post post = webInterface.getCore().getPost(id, false);
Set<Sone> sones = webInterface.getCore().getLikes(post);
return createSuccessJsonObject().put("likes", sones.size()).put("sones", getSones(sones));
} else if ("reply".equals(type)) {
import junit.framework.TestCase;
import net.pterodactylus.sone.core.SoneProvider;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.memory.MemorySone;
/**
* JUnit test case for {@link SoneTextParser}.
*/
@Override
public Sone getSone(final String soneId, boolean create) {
- return new Sone(soneId) {
+ return new MemorySone(soneId, false) {
/**
* {@inheritDoc}