Don’t store a Sone in the Sone inserter.
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 26 Sep 2014 19:59:30 +0000 (21:59 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 26 Sep 2014 20:00:00 +0000 (22:00 +0200)
The information is readily available from the core, we just need the ID.

src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/core/SoneInserter.java
src/main/java/net/pterodactylus/sone/core/SoneModificationDetector.java
src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java
src/test/java/net/pterodactylus/sone/core/SoneModificationDetectorTest.java

index d60bbda..9beeac4 100644 (file)
@@ -720,7 +720,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                        sone.setKnown(true);
                        /* TODO - load posts ’n stuff */
                        sones.put(ownIdentity.getId(), sone);
-                       final SoneInserter soneInserter = new SoneInserter(this, eventBus, freenetInterface, sone);
+                       SoneInserter soneInserter = new SoneInserter(this, eventBus, freenetInterface, ownIdentity.getId());
                        soneInserters.put(sone, soneInserter);
                        sone.setStatus(SoneStatus.idle);
                        loadSone(sone);
@@ -988,7 +988,6 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                                sone.setKnown(storedSone.get().isKnown());
                                sone.setStatus((sone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle);
                                if (sone.isLocal()) {
-                                       soneInserters.get(storedSone.get()).setSone(sone);
                                        touchConfiguration();
                                }
                                sones.put(sone.getId(), sone);
index 843e9c4..9fad053 100644 (file)
@@ -18,6 +18,7 @@
 package net.pterodactylus.sone.core;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.String.format;
 import static java.lang.System.currentTimeMillis;
 import static net.pterodactylus.sone.data.Album.NOT_EMPTY;
 
@@ -34,6 +35,7 @@ import java.util.logging.Logger;
 
 import net.pterodactylus.sone.core.Options.Option;
 import net.pterodactylus.sone.core.Options.OptionWatcher;
+import net.pterodactylus.sone.core.SoneModificationDetector.LockableFingerprintProvider;
 import net.pterodactylus.sone.core.event.SoneInsertAbortedEvent;
 import net.pterodactylus.sone.core.event.SoneInsertedEvent;
 import net.pterodactylus.sone.core.event.SoneInsertingEvent;
@@ -57,6 +59,7 @@ import net.pterodactylus.util.template.TemplateParser;
 import net.pterodactylus.util.template.XmlFilter;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Ordering;
 import com.google.common.eventbus.EventBus;
@@ -100,9 +103,7 @@ public class SoneInserter extends AbstractService {
 
        private final SoneModificationDetector soneModificationDetector;
        private final long delay;
-
-       /** The Sone to insert. */
-       private volatile Sone sone;
+       private final String soneId;
 
        /**
         * Creates a new Sone inserter.
@@ -113,20 +114,38 @@ public class SoneInserter extends AbstractService {
         *            The event bus
         * @param freenetInterface
         *            The freenet interface
-        * @param sone
-        *            The Sone to insert
+        * @param soneId
+        *            The ID of the Sone to insert
         */
-       public SoneInserter(Core core, EventBus eventBus, FreenetInterface freenetInterface, Sone sone) {
-               this(core, eventBus, freenetInterface, sone, new SoneModificationDetector(core, sone, insertionDelay), 1000);
+       public SoneInserter(final Core core, EventBus eventBus, FreenetInterface freenetInterface, final String soneId) {
+               this(core, eventBus, freenetInterface, soneId, new SoneModificationDetector(new LockableFingerprintProvider() {
+                       @Override
+                       public boolean isLocked() {
+                               final Optional<Sone> sone = core.getSone(soneId);
+                               if (!sone.isPresent()) {
+                                       return false;
+                               }
+                               return core.isLocked(sone.get());
+                       }
+
+                       @Override
+                       public String getFingerprint() {
+                               final Optional<Sone> sone = core.getSone(soneId);
+                               if (!sone.isPresent()) {
+                                       return null;
+                               }
+                               return sone.get().getFingerprint();
+                       }
+               }, insertionDelay), 1000);
        }
 
        @VisibleForTesting
-       SoneInserter(Core core, EventBus eventBus, FreenetInterface freenetInterface, Sone sone, SoneModificationDetector soneModificationDetector, long delay) {
-               super("Sone Inserter for “" + sone.getName() + "”", false);
+       SoneInserter(Core core, EventBus eventBus, FreenetInterface freenetInterface, String soneId, SoneModificationDetector soneModificationDetector, long delay) {
+               super("Sone Inserter for “" + soneId + "”", false);
                this.core = core;
                this.eventBus = eventBus;
                this.freenetInterface = freenetInterface;
-               this.sone = sone;
+               this.soneId = soneId;
                this.soneModificationDetector = soneModificationDetector;
                this.delay = delay;
        }
@@ -135,19 +154,6 @@ public class SoneInserter extends AbstractService {
        // ACCESSORS
        //
 
-       /**
-        * Sets the Sone to insert.
-        *
-        * @param sone
-        *              The Sone to insert
-        * @return This Sone inserter
-        */
-       public SoneInserter setSone(Sone sone) {
-               checkArgument(sone.equals(this.sone), "Sone to insert can not be set to a different Sone");
-               this.sone = sone;
-               return this;
-       }
-
        @VisibleForTesting
        static AtomicInteger getInsertionDelay() {
                return insertionDelay;
@@ -209,6 +215,12 @@ public class SoneInserter extends AbstractService {
                                sleep(delay);
 
                                if (soneModificationDetector.isEligibleForInsert()) {
+                                       Optional<Sone> soneOptional = core.getSone(soneId);
+                                       if (!soneOptional.isPresent()) {
+                                               logger.log(Level.WARNING, format("Sone %s has disappeared, exiting inserter.", soneId));
+                                               return;
+                                       }
+                                       Sone sone = soneOptional.get();
                                        InsertInformation insertInformation = new InsertInformation(sone);
                                        logger.log(Level.INFO, String.format("Inserting Sone “%s”…", sone.getName()));
 
index aba329c..8b1b2ee 100644 (file)
@@ -23,34 +23,32 @@ import com.google.common.base.Ticker;
 class SoneModificationDetector {
 
        private final Ticker ticker;
-       private final Core core;
-       private final Sone sone;
+       private final LockableFingerprintProvider lockableFingerprintProvider;
        private final AtomicInteger insertionDelay;
        private Optional<Long> lastModificationTime;
        private String originalFingerprint;
        private String lastFingerprint;
 
-       SoneModificationDetector(Core core, Sone sone, AtomicInteger insertionDelay) {
-               this(systemTicker(), core, sone, insertionDelay);
+       SoneModificationDetector(LockableFingerprintProvider lockableFingerprintProvider, AtomicInteger insertionDelay) {
+               this(systemTicker(), lockableFingerprintProvider, insertionDelay);
        }
 
        @VisibleForTesting
-       SoneModificationDetector(Ticker ticker, Core core, Sone sone, AtomicInteger insertionDelay) {
+       SoneModificationDetector(Ticker ticker, LockableFingerprintProvider lockableFingerprintProvider, AtomicInteger insertionDelay) {
                this.ticker = ticker;
-               this.core = core;
-               this.sone = sone;
+               this.lockableFingerprintProvider = lockableFingerprintProvider;
                this.insertionDelay = insertionDelay;
-               originalFingerprint = sone.getFingerprint();
+               originalFingerprint = lockableFingerprintProvider.getFingerprint();
                lastFingerprint = originalFingerprint;
        }
 
        public boolean isEligibleForInsert() {
-               if (core.isLocked(sone)) {
+               if (lockableFingerprintProvider.isLocked()) {
                        lastModificationTime = absent();
                        lastFingerprint = "";
                        return false;
                }
-               String fingerprint = sone.getFingerprint();
+               String fingerprint = lockableFingerprintProvider.getFingerprint();
                if (originalFingerprint.equals(fingerprint)) {
                        lastModificationTime = absent();
                        lastFingerprint = fingerprint;
@@ -79,7 +77,20 @@ class SoneModificationDetector {
        }
 
        public boolean isModified() {
-               return !sone.getFingerprint().equals(originalFingerprint);
+               return !lockableFingerprintProvider.getFingerprint().equals(originalFingerprint);
+       }
+
+       /**
+        * Provider for a fingerprint and the information if a {@link Sone} is locked. This
+        * prevents us from having to lug a Sone object around.
+        *
+        * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+        */
+       static interface LockableFingerprintProvider {
+
+               boolean isLocked();
+               String getFingerprint();
+
        }
 
 }
index c5c74dc..9efd4dd 100644 (file)
@@ -1,10 +1,13 @@
 package net.pterodactylus.sone.core;
 
+import static com.google.common.base.Optional.absent;
+import static com.google.common.base.Optional.of;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.argThat;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
@@ -27,6 +30,7 @@ import net.pterodactylus.sone.data.Sone;
 
 import freenet.keys.FreenetURI;
 
+import com.google.common.base.Optional;
 import com.google.common.eventbus.EventBus;
 import org.junit.Before;
 import org.junit.Test;
@@ -49,6 +53,7 @@ public class SoneInserterTest {
        public void setupCore() {
                UpdateChecker updateChecker = mock(UpdateChecker.class);
                when(core.getUpdateChecker()).thenReturn(updateChecker);
+               when(core.getSone(anyString())).thenReturn(Optional.<Sone>absent());
        }
 
        @Test
@@ -64,7 +69,7 @@ public class SoneInserterTest {
                FreenetURI insertUri = mock(FreenetURI.class);
                String fingerprint = "fingerprint";
                Sone sone = createSone(insertUri, fingerprint);
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone);
+               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId");
                InsertInformation insertInformation = soneInserter.new InsertInformation(sone);
                HashMap<String, Object> manifestEntries = insertInformation.generateManifestEntries();
                assertThat(manifestEntries.keySet(), containsInAnyOrder("index.html", "sone.xml"));
@@ -77,52 +82,35 @@ public class SoneInserterTest {
                when(sone.getInsertUri()).thenReturn(insertUri);
                when(sone.getFingerprint()).thenReturn(fingerprint);
                when(sone.getRootAlbum()).thenReturn(mock(Album.class));
+               when(core.getSone(anyString())).thenReturn(of(sone));
                return sone;
        }
 
-       @Test(expected = IllegalArgumentException.class)
-       public void soneOfSoneInserterCanNotBeSetToADifferentSone() {
-               Sone sone = mock(Sone.class);
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone);
-               soneInserter.setSone(mock(Sone.class));
-       }
-
-       @Test
-       public void soneCanBeSetToEqualSone() {
-               Sone sone = mock(Sone.class);
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone);
-               soneInserter.setSone(sone);
-       }
-
        @Test
        public void isModifiedIsTrueIfModificationDetectorSaysSo() {
-               Sone sone = mock(Sone.class);
                SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
                when(soneModificationDetector.isModified()).thenReturn(true);
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone, soneModificationDetector, 1);
+               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
                assertThat(soneInserter.isModified(), is(true));
        }
 
        @Test
        public void isModifiedIsFalseIfModificationDetectorSaysSo() {
-               Sone sone = mock(Sone.class);
                SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone, soneModificationDetector, 1);
+               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
                assertThat(soneInserter.isModified(), is(false));
        }
 
        @Test
        public void lastFingerprintIsStoredCorrectly() {
-               Sone sone = mock(Sone.class);
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone);
+               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId");
                soneInserter.setLastInsertFingerprint("last-fingerprint");
                assertThat(soneInserter.getLastInsertFingerprint(), is("last-fingerprint"));
        }
 
        @Test
        public void soneInserterStopsWhenItShould() {
-               Sone sone = mock(Sone.class);
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone);
+               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId");
                soneInserter.stop();
                soneInserter.serviceRun();
        }
@@ -136,7 +124,7 @@ public class SoneInserterTest {
                SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
                when(soneModificationDetector.isEligibleForInsert()).thenReturn(true);
                when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenReturn(finalUri);
-               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone, soneModificationDetector, 1);
+               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
                doAnswer(new Answer<Void>() {
                        @Override
                        public Void answer(InvocationOnMock invocation) throws Throwable {
@@ -162,7 +150,7 @@ public class SoneInserterTest {
                Sone sone = createSone(insertUri, fingerprint);
                SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
                when(soneModificationDetector.isEligibleForInsert()).thenReturn(true);
-               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone, soneModificationDetector, 1);
+               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
                when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenAnswer(new Answer<FreenetURI>() {
                        @Override
                        public FreenetURI answer(InvocationOnMock invocation) throws Throwable {
@@ -187,7 +175,7 @@ public class SoneInserterTest {
                String fingerprint = "fingerprint";
                Sone sone = createSone(insertUri, fingerprint);
                SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
-               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone, soneModificationDetector, 1);
+               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
                new Thread(new Runnable() {
                        @Override
                        public void run() {
@@ -211,7 +199,7 @@ public class SoneInserterTest {
                Sone sone = createSone(insertUri, fingerprint);
                SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
                when(soneModificationDetector.isEligibleForInsert()).thenReturn(true);
-               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, sone, soneModificationDetector, 1);
+               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
                final SoneException soneException = new SoneException(new Exception());
                when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenAnswer(new Answer<FreenetURI>() {
                        @Override
index cd0133f..e2b34f7 100644 (file)
@@ -8,6 +8,7 @@ import static org.mockito.Mockito.when;
 
 import java.util.concurrent.atomic.AtomicInteger;
 
+import net.pterodactylus.sone.core.SoneModificationDetector.LockableFingerprintProvider;
 import net.pterodactylus.sone.data.Sone;
 
 import com.google.common.base.Ticker;
@@ -21,14 +22,14 @@ import org.junit.Test;
 public class SoneModificationDetectorTest {
 
        private final Ticker ticker = mock(Ticker.class);
-       private final Sone sone = mock(Sone.class);
-       private final Core core = mock(Core.class);
        private final AtomicInteger insertionDelay = new AtomicInteger(60);
        private final SoneModificationDetector soneModificationDetector;
+       private final LockableFingerprintProvider lockableFingerprintProvider = mock(LockableFingerprintProvider.class);
 
        public SoneModificationDetectorTest() {
-               when(sone.getFingerprint()).thenReturn("original");
-               soneModificationDetector = new SoneModificationDetector(ticker, core, sone, insertionDelay);
+               when(lockableFingerprintProvider.getFingerprint()).thenReturn("original");
+               when(lockableFingerprintProvider.isLocked()).thenReturn(false);
+               soneModificationDetector = new SoneModificationDetector(ticker, lockableFingerprintProvider, insertionDelay);
        }
 
        private void modifySone() {
@@ -36,7 +37,7 @@ public class SoneModificationDetectorTest {
        }
 
        private void modifySone(String uniqueValue) {
-               when(sone.getFingerprint()).thenReturn("modified" + uniqueValue);
+               when(lockableFingerprintProvider.getFingerprint()).thenReturn("modified" + uniqueValue);
        }
 
        private void passTime(int seconds) {
@@ -44,16 +45,16 @@ public class SoneModificationDetectorTest {
        }
 
        private void lockSone() {
-               when(core.isLocked(sone)).thenReturn(true);
+               when(lockableFingerprintProvider.isLocked()).thenReturn(true);
        }
 
        private void unlockSone() {
-               when(core.isLocked(sone)).thenReturn(false);
+               when(lockableFingerprintProvider.isLocked()).thenReturn(false);
        }
 
        @Test
        public void normalConstructorCanBeCalled() {
-               new SoneModificationDetector(core, sone, insertionDelay);
+               new SoneModificationDetector(lockableFingerprintProvider, insertionDelay);
        }
 
        @Test