Remove updated time setter from Sone, store update time in database.
[Sone.git] / src / main / java / net / pterodactylus / sone / core / Core.java
index 71dd349..c3ac305 100644 (file)
@@ -55,6 +55,7 @@ import net.pterodactylus.sone.core.event.SoneRemovedEvent;
 import net.pterodactylus.sone.core.event.SoneUnlockedEvent;
 import net.pterodactylus.sone.data.Album;
 import net.pterodactylus.sone.data.Image;
+import net.pterodactylus.sone.data.LocalSone;
 import net.pterodactylus.sone.data.Post;
 import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Reply;
@@ -142,23 +143,17 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        /** The trust updater. */
        private final WebOfTrustUpdater webOfTrustUpdater;
 
-       /** The times Sones were followed. */
-       private final Map<String, Long> soneFollowingTimes = new HashMap<String, Long>();
-
        /** Locked local Sones. */
        /* synchronize on itself. */
-       private final Set<Sone> lockedSones = new HashSet<Sone>();
+       private final Set<LocalSone> lockedSones = new HashSet<LocalSone>();
 
        /** Sone inserters. */
        /* synchronize access on this on sones. */
-       private final Map<Sone, SoneInserter> soneInserters = new HashMap<Sone, SoneInserter>();
+       private final Map<LocalSone, SoneInserter> soneInserters = new HashMap<LocalSone, SoneInserter>();
 
        /** Sone rescuers. */
        /* synchronize access on this on sones. */
-       private final Map<Sone, SoneRescuer> soneRescuers = new HashMap<Sone, SoneRescuer>();
-
-       /** All known Sones. */
-       private final Set<String> knownSones = new HashSet<String>();
+       private final Map<LocalSone, SoneRescuer> soneRescuers = new HashMap<LocalSone, SoneRescuer>();
 
        /** The post database. */
        private final Database database;
@@ -268,9 +263,8 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
         *            The local Sone to get the rescuer for
         * @return The Sone rescuer for the given Sone
         */
-       public SoneRescuer getSoneRescuer(Sone sone) {
+       public SoneRescuer getSoneRescuer(LocalSone sone) {
                checkNotNull(sone, "sone must not be null");
-               checkArgument(sone.isLocal(), "sone must be local");
                synchronized (soneRescuers) {
                        SoneRescuer soneRescuer = soneRescuers.get(sone);
                        if (soneRescuer == null) {
@@ -289,7 +283,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
         *            The sone to check
         * @return {@code true} if the Sone is locked, {@code false} if it is not
         */
-       public boolean isLocked(Sone sone) {
+       public boolean isLocked(LocalSone sone) {
                synchronized (lockedSones) {
                        return lockedSones.contains(sone);
                }
@@ -326,27 +320,13 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                return database.getSone(id);
        }
 
-       /**
-        * {@inheritDocs}
-        */
        @Override
-       public Collection<Sone> getLocalSones() {
+       public Collection<LocalSone> getLocalSones() {
                return database.getLocalSones();
        }
 
-       /**
-        * Returns the local Sone with the given ID, optionally creating a new Sone.
-        *
-        * @param id
-        *            The ID of the Sone
-        * @return The Sone with the given ID, or {@code null}
-        */
-       public Sone getLocalSone(String id) {
-               Optional<Sone> sone = database.getSone(id);
-               if (sone.isPresent() && sone.get().isLocal()) {
-                       return sone.get();
-               }
-               return null;
+       public Optional<LocalSone> getLocalSone(String id) {
+               return database.getLocalSone(id);
        }
 
        /**
@@ -377,7 +357,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
         * @return {@code true} if a modification has been detected in the Sone,
         *         {@code false} otherwise
         */
-       public boolean isModifiedSone(Sone sone) {
+       public boolean isModifiedSone(LocalSone sone) {
                return soneInserters.containsKey(sone) && soneInserters.get(sone).isModified();
        }
 
@@ -390,9 +370,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
         *         been followed, or {@link Long#MAX_VALUE}
         */
        public long getSoneFollowingTime(Sone sone) {
-               synchronized (soneFollowingTimes) {
-                       return Optional.fromNullable(soneFollowingTimes.get(sone.getId())).or(Long.MAX_VALUE);
-               }
+               return database.getSoneFollowingTime(sone.getId()).or(Long.MAX_VALUE);
        }
 
        /**
@@ -586,13 +564,13 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
 
        /**
         * Locks the given Sone. A locked Sone will not be inserted by
-        * {@link SoneInserter} until it is {@link #unlockSone(Sone) unlocked}
+        * {@link SoneInserter} until it is {@link #unlockSone(LocalSone) unlocked}
         * again.
         *
         * @param sone
         *            The sone to lock
         */
-       public void lockSone(Sone sone) {
+       public void lockSone(LocalSone sone) {
                synchronized (lockedSones) {
                        if (lockedSones.add(sone)) {
                                eventBus.post(new SoneLockedEvent(sone));
@@ -603,11 +581,11 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        /**
         * Unlocks the given Sone.
         *
-        * @see #lockSone(Sone)
+        * @see #lockSone(LocalSone)
         * @param sone
         *            The sone to unlock
         */
-       public void unlockSone(Sone sone) {
+       public void unlockSone(LocalSone sone) {
                synchronized (lockedSones) {
                        if (lockedSones.remove(sone)) {
                                eventBus.post(new SoneUnlockedEvent(sone));
@@ -622,14 +600,14 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
         *            The own identity to create a Sone from
         * @return The added (or already existing) Sone
         */
-       public Sone addLocalSone(OwnIdentity ownIdentity) {
+       public LocalSone addLocalSone(OwnIdentity ownIdentity) {
                if (ownIdentity == null) {
                        logger.log(Level.WARNING, "Given OwnIdentity is null!");
                        return null;
                }
                logger.info(String.format("Adding Sone from OwnIdentity: %s", ownIdentity));
-               Sone sone = database.registerLocalSone(ownIdentity);
-               SoneInserter soneInserter = new SoneInserter(this, eventBus, freenetInterface, ownIdentity.getId());
+               LocalSone sone = database.registerLocalSone(ownIdentity);
+               SoneInserter soneInserter = new SoneInserter(this, eventBus, freenetInterface, database, ownIdentity.getId());
                eventBus.register(soneInserter);
                synchronized (soneInserters) {
                        soneInserters.put(sone, soneInserter);
@@ -654,7 +632,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                        logger.log(Level.SEVERE, String.format("Could not add “Sone” context to own identity: %s", ownIdentity));
                        return null;
                }
-               Sone sone = addLocalSone(ownIdentity);
+               LocalSone sone = addLocalSone(ownIdentity);
 
                followSone(sone, "nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI");
                touchConfiguration();
@@ -683,13 +661,11 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                Sone sone = !newSone ? existingSone.get() : database.newSoneBuilder().from(identity).build();
                sone.setLatestEdition(latestEdition);
                if (newSone) {
-                       synchronized (knownSones) {
-                               newSone = !knownSones.contains(sone.getId());
-                       }
+                       newSone = !database.isSoneKnown(sone);
                        sone.setKnown(!newSone);
                        if (newSone) {
                                eventBus.post(new NewSoneFoundEvent(sone));
-                               for (Sone localSone : getLocalSones()) {
+                               for (LocalSone localSone : getLocalSones()) {
                                        if (localSone.getOptions().isAutoFollow()) {
                                                followSone(localSone, sone.getId());
                                        }
@@ -710,31 +686,28 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
         * @param soneId
         *            The ID of the Sone to follow
         */
-       public void followSone(Sone sone, String soneId) {
+       public void followSone(LocalSone sone, String soneId) {
                checkNotNull(sone, "sone must not be null");
                checkNotNull(soneId, "soneId must not be null");
+               boolean newFriend = !database.getSoneFollowingTime(soneId).isPresent();
                database.addFriend(sone, soneId);
-               synchronized (soneFollowingTimes) {
-                       if (!soneFollowingTimes.containsKey(soneId)) {
-                               long now = System.currentTimeMillis();
-                               soneFollowingTimes.put(soneId, now);
-                               Optional<Sone> followedSone = getSone(soneId);
-                               if (!followedSone.isPresent()) {
-                                       return;
-                               }
-                               for (Post post : followedSone.get().getPosts()) {
-                                       if (post.getTime() < now) {
-                                               markPostKnown(post);
-                                       }
+               if (newFriend) {
+                       long now = System.currentTimeMillis();
+                       Optional<Sone> followedSone = getSone(soneId);
+                       if (!followedSone.isPresent()) {
+                               return;
+                       }
+                       for (Post post : followedSone.get().getPosts()) {
+                               if (post.getTime() < now) {
+                                       markPostKnown(post);
                                }
-                               for (PostReply reply : followedSone.get().getReplies()) {
-                                       if (reply.getTime() < now) {
-                                               markReplyKnown(reply);
-                                       }
+                       }
+                       for (PostReply reply : followedSone.get().getReplies()) {
+                               if (reply.getTime() < now) {
+                                       markReplyKnown(reply);
                                }
                        }
                }
-               touchConfiguration();
        }
 
        /**
@@ -745,20 +718,10 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
         * @param soneId
         *            The ID of the Sone being unfollowed
         */
-       public void unfollowSone(Sone sone, String soneId) {
+       public void unfollowSone(LocalSone sone, String soneId) {
                checkNotNull(sone, "sone must not be null");
                checkNotNull(soneId, "soneId must not be null");
                database.removeFriend(sone, soneId);
-               boolean unfollowedSoneStillFollowed = false;
-               for (Sone localSone : getLocalSones()) {
-                       unfollowedSoneStillFollowed |= localSone.hasFriend(soneId);
-               }
-               if (!unfollowedSoneStillFollowed) {
-                       synchronized (soneFollowingTimes) {
-                               soneFollowingTimes.remove(soneId);
-                       }
-               }
-               touchConfiguration();
        }
 
        /**
@@ -953,9 +916,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        public void markSoneKnown(Sone sone) {
                if (!sone.isKnown()) {
                        sone.setKnown(true);
-                       synchronized (knownSones) {
-                               knownSones.add(sone.getId());
-                       }
+                       database.setSoneKnown(sone);
                        eventBus.post(new MarkSoneKnownEvent(sone));
                        touchConfiguration();
                }
@@ -1264,7 +1225,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        public void serviceStop() {
                localElementTicker.shutdownNow();
                synchronized (soneInserters) {
-                       for (Entry<Sone, SoneInserter> soneInserter : soneInserters.entrySet()) {
+                       for (Entry<LocalSone, SoneInserter> soneInserter : soneInserters.entrySet()) {
                                soneInserter.getValue().stop();
                        }
                }
@@ -1297,26 +1258,6 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                try {
                        preferences.saveTo(configuration);
 
-                       /* save known Sones. */
-                       int soneCounter = 0;
-                       synchronized (knownSones) {
-                               for (String knownSoneId : knownSones) {
-                                       configuration.getStringValue("KnownSone/" + soneCounter++ + "/ID").setValue(knownSoneId);
-                               }
-                               configuration.getStringValue("KnownSone/" + soneCounter + "/ID").setValue(null);
-                       }
-
-                       /* save Sone following times. */
-                       soneCounter = 0;
-                       synchronized (soneFollowingTimes) {
-                               for (Entry<String, Long> soneFollowingTime : soneFollowingTimes.entrySet()) {
-                                       configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(soneFollowingTime.getKey());
-                                       configuration.getLongValue("SoneFollowingTimes/" + soneCounter + "/Time").setValue(soneFollowingTime.getValue());
-                                       ++soneCounter;
-                               }
-                               configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(null);
-                       }
-
                        /* save known posts. */
                        database.save();
 
@@ -1339,32 +1280,6 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
         */
        private void loadConfiguration() {
                new PreferencesLoader(preferences).loadFrom(configuration);
-
-               /* load known Sones. */
-               int soneCounter = 0;
-               while (true) {
-                       String knownSoneId = configuration.getStringValue("KnownSone/" + soneCounter++ + "/ID").getValue(null);
-                       if (knownSoneId == null) {
-                               break;
-                       }
-                       synchronized (knownSones) {
-                               knownSones.add(knownSoneId);
-                       }
-               }
-
-               /* load Sone following times. */
-               soneCounter = 0;
-               while (true) {
-                       String soneId = configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").getValue(null);
-                       if (soneId == null) {
-                               break;
-                       }
-                       long time = configuration.getLongValue("SoneFollowingTimes/" + soneCounter + "/Time").getValue(Long.MAX_VALUE);
-                       synchronized (soneFollowingTimes) {
-                               soneFollowingTimes.put(soneId, time);
-                       }
-                       ++soneCounter;
-               }
        }
 
        /**