Commits

Kevin Poalses committed 7fd2086

NEW: Adding entity snapshots and repository support

Comments (0)

Files changed (5)

src/main/java/net/poalsoft/common/persistence/internal/EntitySnapshotBuilderImpl.java

     @Override
     public EntitySnapshot<ValueType> build() {
 
-        // Sanity checks
-        if (this.version.get() == null) {
-            throw new IllegalArgumentException("Entity snapshot version has not been set");
-        } else if (this.version.get() < 0L) {
-            throw new IllegalArgumentException("Entity snapshot version must be a positive integer");
-        } else if (this.value.get() == null) {
-            throw new IllegalArgumentException("Entity value has not been set");
-        } else if (this.timestamp.get() == null) {
-            throw new IllegalArgumentException("Entity snapshot timestamp has not been set");
-        }
+        validate();
 
         // Build entity snapshot
         return new EntitySnapshotImpl<>(this.entityId.get(),
         return this;
     }
 
+    private void validate() {
+        // Validate builder state
+        if (this.version.get() == null) {
+            throw new IllegalStateException("Entity snapshot version has not been set");
+        } else if (this.version.get() < 0L) {
+            throw new IllegalStateException("Entity snapshot version must be a positive integer");
+        } else if (this.value.get() == null) {
+            throw new IllegalStateException("Entity value has not been set");
+        } else if (this.timestamp.get() == null) {
+            throw new IllegalStateException("Entity snapshot timestamp has not been set");
+        }
+    }
+
     private final ThreadLocal<UUID> entityId = new ThreadLocal<>();
 
     private final ThreadLocal<ValueType> value = new ThreadLocal<>();

src/main/java/net/poalsoft/common/util/AbstractVisitor.java

             throw new IllegalArgumentException("Visitable object may not be null");
         }
 
-        // Perform visitation
-        try {
-            // Determine most specific visit method
-            Method visitMethod = determineVisitMethod(visitable.getClass());
-
-            // Invoke the visit method
-            visitMethod.invoke(this, visitable);
-
-        } catch (IllegalAccessException e) {
-            logger.warn("Visiting object of unexpected type [{}]: {}",
-                        visitable.getClass()
-                                 .getName(),
-                        visitable);
-            innerVisit(visitable);
-        } catch (InvocationTargetException e) {
-            logger.error("Encountered a problem while visiting [{}]",
-                         visitable,
-                         e);
-            throw new RuntimeException("Encountered a problem while visiting [" + visitable + "]",
-                                       e);
-        }
+        // Perform inner visitation
+        innerVisit(visitable);
 
         // Return self
         return this;
             throw new IllegalArgumentException("Visitable entity may not be null");
         }
 
-        // Perform visitations
         for (VisitableType visitable : visitables) {
-            visit(visitable);
+            innerVisit(visitable);
         }
 
         // Return self
         return this;
     }
 
+    private void innerVisit(@Nonnull VisitableType visitable) {
+        // Perform visitation
+        Class<? extends Visitable> visitableClass = visitable.getClass();
+        try {
+            // Determine most specific visit method
+            Method visitMethod = determineVisitMethod(visitableClass);
+
+            // Invoke the visit method
+            visitMethod.invoke(this, visitable);
+
+        } catch (IllegalAccessException e) {
+            logger.warn("Visiting object of unexpected type [{}]: {}",
+                        visitableClass
+                                 .getName(),
+                        visitable);
+            fallbackVisit(visitable);
+        } catch (InvocationTargetException e) {
+            logger.error("Encountered a problem while visiting [{}]",
+                         visitable,
+                         e);
+            throw new RuntimeException("Encountered a problem while visiting [" + visitable + "]",
+                                       e);
+        }
+    }
+
     /**
      * Determines the closest matching visit method to use for the given visitable type.
      *
         }
     }
 
-    protected abstract void innerVisit(@Nonnull Object visitableEntity);
+    /**
+     * Handle visitation of unsupported visitable.
+     *
+     * @param visitable Visitable object
+     */
+    protected void fallbackVisit(@Nonnull Object visitable) {
+        throw new UnsupportedOperationException("Attempt to visit unsupported visitable [" + visitable + "]");
+    }
 
     private final ReadWriteLock visitorMethodMapLock;
 

src/test/java/net/poalsoft/common/persistence/internal/EntitySnapshotBuilderImplTest.java

 @RunWith(SpringJUnit4ClassRunner.class)
 public class EntitySnapshotBuilderImplTest {
 
-    @Test(expected = IllegalArgumentException.class)
+    @Test(expected = IllegalStateException.class)
     public void testIllegalBuild() throws Exception {
         new EntitySnapshotBuilderImpl<>().build();
     }
         assertNotEquals(entitySnapshot, entitySnapshotNewValue);
     }
 
-    @Test(expected = IllegalArgumentException.class)
+    @Test(expected = IllegalStateException.class)
     public void testReset() throws Exception {
 
         EntitySnapshotBuilder<String> builder = new EntitySnapshotBuilderImpl<>();

src/test/java/net/poalsoft/common/persistence/internal/InMemoryEntitySnapshotRepositoryImplTest.java

 import net.poalsoft.common.persistence.EntitySnapshot;
 import net.poalsoft.common.persistence.EntitySnapshotBuilder;
 import net.poalsoft.common.persistence.EntitySnapshotRepository;
-import net.poalsoft.common.util.Visitor;
+import net.poalsoft.common.util.AbstractVisitor;
 import org.joda.time.DateTime;
 import org.junit.After;
 import org.junit.Before;
         storeRandomTestSnapshots(1000, 20);
 
         final CountDownLatch countDownLatch = new CountDownLatch(1000);
-        this.entitySnapshotRepository.visitAll(new Visitor<EntitySnapshot<String>>() {
+        this.entitySnapshotRepository.visitAll(new AbstractVisitor<EntitySnapshot<String>>() {
             @Nonnull
             @Override
-            public Visitor visit(@Nonnull EntitySnapshot<String> visitable) {
+            public AbstractVisitor visit(@Nonnull EntitySnapshot<String> visitable) {
                 countDownLatch.countDown();
                 return this;
             }
-
-            @Nonnull
-            @Override
-            public Visitor visit(@Nonnull Iterable<? extends EntitySnapshot<String>> visitables) {
-                throw new RuntimeException("We shouldn't reach this");
-            }
         });
 
         assertEquals("Failed to visit all entity snapshots", 0, countDownLatch.getCount());

src/test/java/net/poalsoft/common/util/AbstractVisitorTest.java

 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
 
 /**
  * Abstract visitor test fixture.
         assertEquals("Wrong visit method used", 1, this.testVisitor.getVisitsToAbstractTestVisitable());
         assertEquals("Wrong visit method used", 1, this.testVisitor.getVisitsToTestVisitableDerivedTwo());
 
-        this.testVisitor.visit(new TestVisitable() {
+        this.testVisitor.visit(new Visitable() {
             @Override
             public void accept(@Nonnull Visitor visitor) {
             }
     @Test
     public void testVisitIterable() throws Exception {
 
-        final List<TestVisitable> testVisitables = Arrays.asList(new TestVisitableDerivedOne(),
+        final List<? extends Visitable> testVisitables = Arrays.asList(new TestVisitableDerivedOne(),
                                                                  new TestVisitableDerivedTwo(),
                                                                  new TestVisitableThree());
         this.testVisitor.visit(testVisitables);
     }
 
 
-    private static class TestVisitor extends AbstractVisitor<TestVisitable> {
+    private static class TestVisitor extends AbstractVisitor<Visitable> {
 
         @Nonnull
-        public TestVisitor visit(@Nonnull TestVisitable visitable) {
+        public TestVisitor visit(@Nonnull Visitable visitable) {
             this.visitsToTestVisitable++;
             return this;
         }
             return this;
         }
 
-        @Override
-        protected void innerVisit(@Nonnull Object visitableEntity) {
-            fail("We reached inner visit");
-        }
-
         public int getVisitsToTestVisitable() {
             return visitsToTestVisitable;
         }