diff --git a/backend/build.gradle b/backend/build.gradle index 423d9c450..c716b1ed1 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -213,6 +213,9 @@ dependencies { //Pacj4 sub-project runtimeOnly project(':pac4j-module') + //Beacon + runtimeOnly project(':beacon:spring') + enversTestCompile sourceSets.main.output enversTestCompile sourceSets.test.output enversTestCompile configurations.compile diff --git a/beacon/core/build.gradle b/beacon/core/build.gradle index 39cef521f..f2cd35c58 100644 --- a/beacon/core/build.gradle +++ b/beacon/core/build.gradle @@ -7,8 +7,8 @@ repositories { } dependencies { - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2' - testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.5.2' + testCompile 'org.junit.jupiter:junit-jupiter-api:5.5.2' + testCompile 'org.junit.jupiter:junit-jupiter-engine:5.5.2' } jar { diff --git a/beacon/core/src/main/java/edu/internet2/tap/beacon/DefaultBeaconPublisher.java b/beacon/core/src/main/java/edu/internet2/tap/beacon/DefaultBeaconPublisher.java index 168fd01ac..610baf827 100644 --- a/beacon/core/src/main/java/edu/internet2/tap/beacon/DefaultBeaconPublisher.java +++ b/beacon/core/src/main/java/edu/internet2/tap/beacon/DefaultBeaconPublisher.java @@ -29,8 +29,6 @@ public class DefaultBeaconPublisher implements BeaconPublisher { private String jsonPayload; public DefaultBeaconPublisher(Map beaconDetails) { - - //Do data validation checks here. If any of the necessary beacon data not available here, throw a Runtime exception if (beaconDetails == null) { throw new IllegalArgumentException("beaconDetails Map must not be null"); diff --git a/beacon/spring/build.gradle b/beacon/spring/build.gradle index c527c05f1..bb895f0e6 100644 --- a/beacon/spring/build.gradle +++ b/beacon/spring/build.gradle @@ -1,13 +1,14 @@ import org.springframework.boot.gradle.plugin.SpringBootPlugin plugins { - id 'groovy' - id 'jacoco' id 'org.springframework.boot' version '2.0.0.RELEASE' apply false id 'io.spring.dependency-management' version '1.0.6.RELEASE' - id 'io.franzbecker.gradle-lombok' version '1.13' } +apply plugin: 'java' +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + repositories { jcenter() } @@ -22,8 +23,7 @@ dependencyManagement { } } -lombok { - version = "1.18.4" - //TODO: get new sha256 - sha256 = "" +dependencies { + compile project(':beacon:core') + compile "org.springframework.boot:spring-boot-starter" } \ No newline at end of file diff --git a/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/BeaconPublishingConfiguration.java b/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/BeaconPublishingConfiguration.java new file mode 100644 index 000000000..e7ea6b2ba --- /dev/null +++ b/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/BeaconPublishingConfiguration.java @@ -0,0 +1,60 @@ +package edu.internet2.tap.beacon.configuration; + +import edu.internet2.tap.beacon.BeaconPublisher; +import edu.internet2.tap.beacon.DefaultBeaconPublisher; +import edu.internet2.tap.beacon.configuration.condition.ConditionalOnBeaconEnvironmentVariablesPresent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.Scheduled; + +import java.util.HashMap; +import java.util.Map; + +import static edu.internet2.tap.beacon.Beacon.IMAGE; +import static edu.internet2.tap.beacon.Beacon.LOG_HOST; +import static edu.internet2.tap.beacon.Beacon.LOG_PORT; +import static edu.internet2.tap.beacon.Beacon.MAINTAINER; +import static edu.internet2.tap.beacon.Beacon.TIERVERSION; +import static edu.internet2.tap.beacon.Beacon.VERSION; + +@Configuration +@ConditionalOnProperty(name = "shibui.beacon-enabled", havingValue = "true") +public class BeaconPublishingConfiguration { + + private static final Logger logger = LoggerFactory.getLogger(BeaconPublishingConfiguration.class); + + @Bean + @ConditionalOnBeaconEnvironmentVariablesPresent + public BeaconPublishingTask beaconPublisher(Environment env) { + logger.debug("Creating BeaconPublishingTask..."); + Map beaconData = new HashMap<>(); + beaconData.put(LOG_HOST, env.getProperty(LOG_HOST)); + beaconData.put(LOG_PORT, env.getProperty(LOG_PORT)); + beaconData.put(IMAGE, env.getProperty(IMAGE)); + beaconData.put(VERSION, env.getProperty(VERSION)); + beaconData.put(TIERVERSION, env.getProperty(TIERVERSION)); + beaconData.put(MAINTAINER, env.getProperty(MAINTAINER)); + return new BeaconPublishingTask(new DefaultBeaconPublisher(beaconData)); + } + + public static class BeaconPublishingTask { + + private BeaconPublisher beaconPublisher; + + public BeaconPublishingTask(BeaconPublisher beaconPublisher) { + this.beaconPublisher = beaconPublisher; + } + + //Cron is based on the spec defined here: https://spaces.at.internet2.edu/display/TWGH/TIER+Instrumentation+-+The+TIER+Beacon + @Scheduled(cron = "0 ${random.int[0,59]} ${random.int[0,3]} ? * *}") + @Async + void publish() { + beaconPublisher.run(); + } + } +} diff --git a/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/condition/BeaconEnvironmentVariablesCondition.java b/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/condition/BeaconEnvironmentVariablesCondition.java new file mode 100644 index 000000000..84f8857fc --- /dev/null +++ b/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/condition/BeaconEnvironmentVariablesCondition.java @@ -0,0 +1,48 @@ +package edu.internet2.tap.beacon.configuration.condition; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; + +import static edu.internet2.tap.beacon.Beacon.IMAGE; +import static edu.internet2.tap.beacon.Beacon.LOG_HOST; +import static edu.internet2.tap.beacon.Beacon.LOG_PORT; +import static edu.internet2.tap.beacon.Beacon.MAINTAINER; +import static edu.internet2.tap.beacon.Beacon.TIERVERSION; +import static edu.internet2.tap.beacon.Beacon.VERSION; + +/** + * {@link Condition} that checks for required beacon environment variables. + * + * @author Dmitriy Kopylenko + * @see ConditionalOnBeaconEnvironmentVariablesPresent + */ +public class BeaconEnvironmentVariablesCondition extends SpringBootCondition { + + private static final String MATCHED_MSG = "Beacon properties are present. Beacon activation condition is matched."; + + private static final String NOT_MATCHED_MSG = "Beacon properties are not present. Beacon activation condition is not matched."; + + private static final Logger logger = LoggerFactory.getLogger(BeaconEnvironmentVariablesCondition.class); + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + Environment env = context.getEnvironment(); + if (env.containsProperty(LOG_HOST) + && env.containsProperty(LOG_PORT) + && env.containsProperty(IMAGE) + && env.containsProperty(VERSION) + && env.containsProperty(TIERVERSION) + && env.containsProperty(MAINTAINER)) { + logger.debug(MATCHED_MSG); + return ConditionOutcome.match(MATCHED_MSG); + } + logger.debug(NOT_MATCHED_MSG); + return ConditionOutcome.noMatch(NOT_MATCHED_MSG); + } +} diff --git a/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/condition/ConditionalOnBeaconEnvironmentVariablesPresent.java b/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/condition/ConditionalOnBeaconEnvironmentVariablesPresent.java new file mode 100644 index 000000000..66049923b --- /dev/null +++ b/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/condition/ConditionalOnBeaconEnvironmentVariablesPresent.java @@ -0,0 +1,21 @@ +package edu.internet2.tap.beacon.configuration.condition; + +import org.springframework.context.annotation.Conditional; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * {@link Conditional} that matches specific beacon environment variables are all present. + * + * @author Dmitriy Kopylenko + */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Conditional(BeaconEnvironmentVariablesCondition.class) +public @interface ConditionalOnBeaconEnvironmentVariablesPresent { +} diff --git a/beacon/spring/src/main/resources/META-INF/spring.factories b/beacon/spring/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..ae9c29c00 --- /dev/null +++ b/beacon/spring/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=edu.internet2.tap.beacon.configuration.BeaconPublishingConfiguration \ No newline at end of file