Merge branch 'next' into new-database-38
[Sone.git] / src / main / java / net / pterodactylus / sone / core / Core.java
index 9e1e6c6..0b1379a 100644 (file)
@@ -19,6 +19,7 @@ package net.pterodactylus.sone.core;
 
 import java.net.MalformedURLException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -47,6 +48,7 @@ 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.fcp.FcpInterface;
 import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
 import net.pterodactylus.sone.freenet.wot.Identity;
@@ -92,6 +94,9 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        /** Whether we’re currently saving the configuration. */
        private boolean storingConfiguration = false;
 
+       /** The database. */
+       private Database database;
+
        /** The identity manager. */
        private final IdentityManager identityManager;
 
@@ -131,14 +136,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        /* 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>();
 
@@ -181,6 +178,8 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *
         * @param configuration
         *            The configuration of the core
+        * @param database
+        *            The database to use
         * @param freenetInterface
         *            The freenet interface
         * @param identityManager
@@ -188,9 +187,10 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         * @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);
@@ -284,8 +284,8 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         * @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);
@@ -314,11 +314,8 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *
         * @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();
        }
 
        /**
@@ -349,10 +346,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         */
        @Override
        public Sone getSone(String id, boolean create) {
-               if (isLocalSone(id)) {
-                       return getLocalSone(id);
-               }
-               return getRemoteSone(id, create);
+               return database.getSone(id, create);
        }
 
        /**
@@ -364,34 +358,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *         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;
        }
 
        /**
@@ -399,10 +366,8 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *
         * @return All local Sones
         */
-       public Set<Sone> getLocalSones() {
-               synchronized (localSones) {
-                       return new HashSet<Sone>(localSones.values());
-               }
+       public Collection<Sone> getLocalSones() {
+               return database.getLocalSones();
        }
 
        /**
@@ -427,14 +392,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         * @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);
        }
 
        /**
@@ -442,10 +400,8 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *
         * @return All remote Sones
         */
-       public Set<Sone> getRemoteSones() {
-               synchronized (remoteSones) {
-                       return new HashSet<Sone>(remoteSones.values());
-               }
+       public Collection<Sone> getRemoteSones() {
+               return database.getRemoteSones();
        }
 
        /**
@@ -459,42 +415,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         * @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);
        }
 
        /**
@@ -541,17 +462,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        }
 
        /**
-        * 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
@@ -637,7 +547,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         * @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()) {
@@ -858,27 +768,25 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        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;
        }
 
        /**
@@ -918,37 +826,36 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        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;
        }
 
        /**
@@ -1041,7 +948,8 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        }
 
        /**
-        * 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
@@ -1245,16 +1153,14 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        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 {
@@ -1290,7 +1196,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *            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;
                }
@@ -1347,7 +1253,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                                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));
                        }
@@ -1369,7 +1275,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                                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. */
@@ -1513,50 +1419,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *
         * @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
@@ -1567,7 +1429,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         * @return The created post
         */
        public Post createPost(Sone sone, Sone recipient, long time, String text) {
-               if (!isLocalSone(sone)) {
+               if (!sone.isLocal()) {
                        logger.log(Level.FINE, String.format("Tried to create post for non-local Sone: %s", sone));
                        return null;
                }
@@ -1601,7 +1463,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *            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;
                }
@@ -1707,7 +1569,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         * @return The created reply
         */
        public PostReply createReply(Sone sone, Post post, long time, String text) {
-               if (!isLocalSone(sone)) {
+               if (!sone.isLocal()) {
                        logger.log(Level.FINE, String.format("Tried to create reply for non-local Sone: %s", sone));
                        return null;
                }
@@ -1741,7 +1603,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         */
        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;
                }
@@ -1816,7 +1678,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *            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;
                }
@@ -1843,7 +1705,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         * @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) {
@@ -1862,7 +1724,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *            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) {
@@ -1965,12 +1827,10 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         */
        @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();
@@ -1991,7 +1851,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
         *            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;
                }
@@ -2454,9 +2314,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                                }
                        }
                }
-               synchronized (remoteSones) {
-                       remoteSones.remove(identity.getId());
-               }
+               database.removeSone(identity.getId());
                coreListenerManager.fireSoneRemoved(sone);
        }