diff --git a/src/main/java/com/arangodb/springframework/boot/actuate/ArangoHealthIndicator.java b/src/main/java/com/arangodb/springframework/boot/actuate/ArangoHealthIndicator.java index c0121b8..a32c6c3 100644 --- a/src/main/java/com/arangodb/springframework/boot/actuate/ArangoHealthIndicator.java +++ b/src/main/java/com/arangodb/springframework/boot/actuate/ArangoHealthIndicator.java @@ -28,7 +28,7 @@ import com.arangodb.springframework.core.ArangoOperations; /** - * Simple {@link HealthIndicator} returning status information of ArangoDB + * Simple {@link HealthIndicator} returning status information of ArangoDB. * * @author Mark Vollmary * @@ -44,7 +44,7 @@ public ArangoHealthIndicator(final ArangoOperations operations) { } @Override - protected void doHealthCheck(final Health.Builder builder) throws Exception { + protected void doHealthCheck(final Health.Builder builder) { final ArangoDBVersion version = operations.driver().getVersion(); builder.up() .withDetail("server", version.getServer()) diff --git a/src/main/java/com/arangodb/springframework/boot/autoconfigure/ArangoAutoConfiguration.java b/src/main/java/com/arangodb/springframework/boot/autoconfigure/ArangoAutoConfiguration.java index a0d6616..0e21b2f 100644 --- a/src/main/java/com/arangodb/springframework/boot/autoconfigure/ArangoAutoConfiguration.java +++ b/src/main/java/com/arangodb/springframework/boot/autoconfigure/ArangoAutoConfiguration.java @@ -28,49 +28,54 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** * {@link EnableAutoConfiguration} class for ArangoDB * * @author Mark Vollmary + * @author Arne Burmeister */ @AutoConfiguration @ConditionalOnClass(ArangoDB.class) @ConditionalOnMissingBean(ArangoOperations.class) @EnableConfigurationProperties(ArangoProperties.class) -@Import(ArangoRepositoriesAutoConfigureRegistrar.class) -public class ArangoAutoConfiguration implements ArangoConfiguration { +@Import({ArangoRepositoriesAutoConfigureRegistrar.class, ArangoAutoConfiguration.ArangoBootConfiguration.class}) +public class ArangoAutoConfiguration { - private final ArangoProperties properties; + @Configuration + static class ArangoBootConfiguration implements ArangoConfiguration { - public ArangoAutoConfiguration(final ArangoProperties properties) { - super(); - this.properties = properties; - } + private final ArangoProperties properties; - @Override - public ArangoDB.Builder arango() { - final ArangoDB.Builder builder = new ArangoDB.Builder() - .user(properties.getUser()) - .password(properties.getPassword()) - .jwt(properties.getJwt()) - .timeout(properties.getTimeout()) - .useSsl(properties.getUseSsl()) - .maxConnections(properties.getMaxConnections()) - .connectionTtl(properties.getConnectionTtl()) - .acquireHostList(properties.getAcquireHostList()) - .acquireHostListInterval(properties.getAcquireHostListInterval()) - .loadBalancingStrategy(properties.getLoadBalancingStrategy()) - .protocol(properties.getProtocol()); - properties.getHosts().stream().map(HostDescription::parse) - .forEach(host -> builder.host(host.getHost(), host.getPort())); - return builder; - } + ArangoBootConfiguration(final ArangoProperties properties) { + super(); + this.properties = properties; + } + + @Override + public ArangoDB.Builder arango() { + final ArangoDB.Builder builder = new ArangoDB.Builder() + .user(properties.getUser()) + .password(properties.getPassword()) + .jwt(properties.getJwt()) + .timeout(properties.getTimeout()) + .useSsl(properties.getUseSsl()) + .maxConnections(properties.getMaxConnections()) + .connectionTtl(properties.getConnectionTtl()) + .acquireHostList(properties.getAcquireHostList()) + .acquireHostListInterval(properties.getAcquireHostListInterval()) + .loadBalancingStrategy(properties.getLoadBalancingStrategy()) + .protocol(properties.getProtocol()); + properties.getHosts().stream().map(HostDescription::parse) + .forEach(host -> builder.host(host.getHost(), host.getPort())); + return builder; + } - @Override - public String database() { + @Override + public String database() { return properties.getDatabase(); } - + } } diff --git a/src/main/java/com/arangodb/springframework/boot/autoconfigure/ArangoProperties.java b/src/main/java/com/arangodb/springframework/boot/autoconfigure/ArangoProperties.java index 92bfec5..a3b4f21 100644 --- a/src/main/java/com/arangodb/springframework/boot/autoconfigure/ArangoProperties.java +++ b/src/main/java/com/arangodb/springframework/boot/autoconfigure/ArangoProperties.java @@ -42,7 +42,7 @@ public class ArangoProperties { /** * Hosts to connect to. Multiple hosts can be added to provide fallbacks in a - * single server with active failover or load balancing in an cluster setup. + * single server with active failover or load balancing in a cluster setup. */ private Collection hosts = new ArrayList<>(); @@ -73,7 +73,7 @@ public class ArangoProperties { private Boolean useSsl = ArangoDefaults.DEFAULT_USE_SSL; /** - * Maximum number of connections the built in connection pool will open per host. + * Maximum number of connections the built-in connection pool will open per host. */ private Integer maxConnections; @@ -83,7 +83,7 @@ public class ArangoProperties { private Long connectionTtl; /** - * Whether or not the driver should acquire a list of available coordinators in + * Whether the driver should acquire a list of available coordinators in * an ArangoDB cluster or a single server with active failover. */ private Boolean acquireHostList = ArangoDefaults.DEFAULT_ACQUIRE_HOST_LIST; diff --git a/src/test/java/com/arangodb/springframework/boot/SpringTest.java b/src/test/java/com/arangodb/springframework/boot/SpringTest.java index f6cfb93..f7bb123 100644 --- a/src/test/java/com/arangodb/springframework/boot/SpringTest.java +++ b/src/test/java/com/arangodb/springframework/boot/SpringTest.java @@ -21,21 +21,35 @@ package com.arangodb.springframework.boot; import com.arangodb.springframework.annotation.Document; +import com.arangodb.springframework.annotation.Ref; import com.arangodb.springframework.boot.actuate.ArangoHealthIndicator; import com.arangodb.springframework.core.ArangoOperations; +import com.arangodb.springframework.core.mapping.event.AfterLoadEvent; +import com.arangodb.springframework.core.mapping.event.AfterSaveEvent; +import com.arangodb.springframework.core.mapping.event.ArangoMappingEvent; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.actuate.health.Status; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Bean; import org.springframework.data.annotation.Id; import org.springframework.data.repository.CrudRepository; +import org.springframework.lang.NonNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; import static org.assertj.core.api.Assertions.assertThat; /** * @author Michele Rastelli + * @author Arne Burmeister */ @SpringBootTest @EnableAutoConfiguration @@ -51,6 +65,17 @@ public class SpringTest { @Autowired private CatRepo repo; + @Autowired + private MouseRepo referencingRepo; + + @Autowired + private Listener listener; + + @BeforeEach + void clearEvents() { + listener.events.clear(); + } + @Test public void operationsShouldBeNotNull() { assertThat(operations).isNotNull(); @@ -75,15 +100,94 @@ void repo() { assertThat(read.id).isNotNull(); assertThat(read.name).isEqualTo(cat.name); } + + @Test + void event() { + Cat cat = new Cat(); + cat.name = "Tom"; + Cat saved = repo.save(cat); + assertThat(listener.events).hasSize(3) + .describedAs("event after save of cat") + .anyMatch(event -> matches(event, AfterSaveEvent.class, saved)); + Mouse mouse = new Mouse(); + mouse.huntBy = cat; + referencingRepo.save(mouse); + listener.events.clear(); + + Cat hunter = referencingRepo.findById(mouse.id).orElseThrow().huntBy; + assertThat(hunter).isEqualTo(saved); + assertThat(listener.events).describedAs("event after resolving cat") + .anyMatch(event -> matches(event, AfterLoadEvent.class, hunter)); + } + + @TestConfiguration + static class EventConfig { + @Bean + ApplicationListener> listener() { + return new Listener(); + } + } + + @SuppressWarnings("rawtypes") + private static boolean matches(ArangoMappingEvent event, Class type, Object source) { + return type.isInstance(event) && event.getSource().equals(source); + } } interface CatRepo extends CrudRepository { } +interface MouseRepo extends CrudRepository { +} @Document class Cat { @Id String id; String name; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Cat cat = (Cat) o; + return Objects.equals(id, cat.id) && Objects.equals(name, cat.name); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} + +@Document +class Mouse { + @Id + String id; + + @Ref + Cat huntBy; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Mouse mouse = (Mouse) o; + return Objects.equals(id, mouse.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} + +class Listener implements ApplicationListener> { + + final List> events = new ArrayList<>(); + + @Override + public void onApplicationEvent(@NonNull ArangoMappingEvent event) { + events.add(event); + } }