From 1c0a2b5e67dda41e75d2315fd0f6f1cfecf26fa6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Fri, 26 Sep 2014 21:59:30 +0200 Subject: [PATCH] =?utf8?q?Don=E2=80=99t=20store=20a=20Sone=20in=20the=20So?= =?utf8?q?ne=20inserter.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The information is readily available from the core, we just need the ID. --- .../java/net/pterodactylus/sone/core/Core.java | 3 +- .../net/pterodactylus/sone/core/SoneInserter.java | 58 +++++++++++++--------- .../sone/core/SoneModificationDetector.java | 33 ++++++++---- .../pterodactylus/sone/core/SoneInserterTest.java | 42 ++++++---------- .../sone/core/SoneModificationDetectorTest.java | 17 ++++--- 5 files changed, 82 insertions(+), 71 deletions(-) diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index d60bbda..9beeac4 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -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); diff --git a/src/main/java/net/pterodactylus/sone/core/SoneInserter.java b/src/main/java/net/pterodactylus/sone/core/SoneInserter.java index 843e9c4..9fad053 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneInserter.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneInserter.java @@ -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 = core.getSone(soneId); + if (!sone.isPresent()) { + return false; + } + return core.isLocked(sone.get()); + } + + @Override + public String getFingerprint() { + final Optional 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 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())); diff --git a/src/main/java/net/pterodactylus/sone/core/SoneModificationDetector.java b/src/main/java/net/pterodactylus/sone/core/SoneModificationDetector.java index aba329c..8b1b2ee 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneModificationDetector.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneModificationDetector.java @@ -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 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 David ‘Bombe’ Roden + */ + static interface LockableFingerprintProvider { + + boolean isLocked(); + String getFingerprint(); + } } diff --git a/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java b/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java index c5c74dc..9efd4dd 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java @@ -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.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 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() { @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() { @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() { @Override diff --git a/src/test/java/net/pterodactylus/sone/core/SoneModificationDetectorTest.java b/src/test/java/net/pterodactylus/sone/core/SoneModificationDetectorTest.java index cd0133f..e2b34f7 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneModificationDetectorTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneModificationDetectorTest.java @@ -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 -- 2.7.4