diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 40e55a9..b761045 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -15,27 +15,26 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 16
- uses: actions/setup-java@v1
- with:
- java-version: 16
- - name: Cache SonarCloud packages
- uses: actions/cache@v1
+ - uses: actions/checkout@v4
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
with:
- path: ~/.sonar/cache
- key: ${{ runner.os }}-sonar
- restore-keys: ${{ runner.os }}-sonar
+ distribution: "oracle"
+ java-version: 17
+
- name: Cache Gradle packages
- uses: actions/cache@v1
+ uses: actions/cache@v4
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle
+
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- - name: Build and analyze
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
- SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- run: ./gradlew build sonarqube --info
+
+ - name: Build
+ run: ./gradlew compileJava compileTestJava
+
+ - name: Test
+ run: ./gradlew test
diff --git a/.gitignore b/.gitignore
index b55c818..95ddd25 100644
--- a/.gitignore
+++ b/.gitignore
@@ -192,4 +192,6 @@ flycheck_*.el
!gradle-wrapper.jar
-node_modules/
\ No newline at end of file
+node_modules/
+
+.idea
\ No newline at end of file
diff --git a/.idea/$PRODUCT_WORKSPACE_FILE$ b/.idea/$PRODUCT_WORKSPACE_FILE$
deleted file mode 100644
index 96ce66b..0000000
--- a/.idea/$PRODUCT_WORKSPACE_FILE$
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 5c98b42..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# Default ignored files
-/workspace.xml
\ No newline at end of file
diff --git a/.idea/.name b/.idea/.name
deleted file mode 100644
index 780c8da..0000000
--- a/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-telraam
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 659bf43..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
deleted file mode 100644
index f37c315..0000000
--- a/.idea/dataSources.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
- postgresql
- true
- org.postgresql.Driver
- jdbc:postgresql://localhost:5432/telraam_dev
-
-
- sqlite.xerial
- true
- org.sqlite.JDBC
- jdbc:sqlite::memory:
-
-
- postgresql
- true
- org.postgresql.Driver
- jdbc:postgresql://localhost:5432/telraam_dev
-
-
-
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
deleted file mode 100644
index b3e9cbd..0000000
--- a/.idea/jarRepositories.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/jpa-buddy.xml b/.idea/jpa-buddy.xml
deleted file mode 100644
index d08f400..0000000
--- a/.idea/jpa-buddy.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 240ddf3..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Telraam__build_.xml b/.idea/runConfigurations/Telraam__build_.xml
deleted file mode 100644
index 0d73339..0000000
--- a/.idea/runConfigurations/Telraam__build_.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
- true
- false
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Telraam__migrateDevelopmentDatabase_.xml b/.idea/runConfigurations/Telraam__migrateDevelopmentDatabase_.xml
deleted file mode 100644
index 202127f..0000000
--- a/.idea/runConfigurations/Telraam__migrateDevelopmentDatabase_.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Telraam__migrateProductionDatabase_.xml b/.idea/runConfigurations/Telraam__migrateProductionDatabase_.xml
deleted file mode 100644
index ffc82b4..0000000
--- a/.idea/runConfigurations/Telraam__migrateProductionDatabase_.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Telraam__migrateTestingDatabase_.xml b/.idea/runConfigurations/Telraam__migrateTestingDatabase_.xml
deleted file mode 100644
index b2859c2..0000000
--- a/.idea/runConfigurations/Telraam__migrateTestingDatabase_.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Telraam__runDev_.xml b/.idea/runConfigurations/Telraam__runDev_.xml
deleted file mode 100644
index c3766a2..0000000
--- a/.idea/runConfigurations/Telraam__runDev_.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Telraam__runProd_.xml b/.idea/runConfigurations/Telraam__runProd_.xml
deleted file mode 100644
index 0f6b693..0000000
--- a/.idea/runConfigurations/Telraam__runProd_.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Telraam__test_.xml b/.idea/runConfigurations/Telraam__test_.xml
deleted file mode 100644
index fdffce2..0000000
--- a/.idea/runConfigurations/Telraam__test_.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Telraam__test_force_.xml b/.idea/runConfigurations/Telraam__test_force_.xml
deleted file mode 100644
index f18cffe..0000000
--- a/.idea/runConfigurations/Telraam__test_force_.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
\ No newline at end of file
diff --git a/.idea/sonarlint-state.xml b/.idea/sonarlint-state.xml
deleted file mode 100644
index 0b9835d..0000000
--- a/.idea/sonarlint-state.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- 1634050067000
-
-
\ No newline at end of file
diff --git a/.idea/sonarlint.xml b/.idea/sonarlint.xml
deleted file mode 100644
index 4b4f6a7..0000000
--- a/.idea/sonarlint.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml
deleted file mode 100644
index 0840fc3..0000000
--- a/.idea/sqldialects.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 5269053..6dd0107 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,22 +1,27 @@
import org.flywaydb.gradle.task.FlywayMigrateTask
+buildscript {
+ dependencies {
+ classpath("org.flywaydb:flyway-database-postgresql:10.10.0")
+ }
+}
+
plugins {
id 'java'
id 'application'
- id 'jacoco'
- id 'org.sonarqube' version "3.0"
id 'idea'
- id 'org.flywaydb.flyway' version "8.0.0"
+ id 'org.flywaydb.flyway' version "10.0.0"
}
group 'telraam'
version '1.0-SNAPSHOT'
-sourceCompatibility = 16
+sourceCompatibility = 17
// Set our project variables
project.ext {
- dropwizardVersion = '2.0.25'
+ dropwizardVersion = '4.0.5'
+ jettyVersion = '11.0.19'
}
repositories {
@@ -26,7 +31,7 @@ application {
mainClass.set('telraam.App')
}
-task runDev {
+tasks.register('runDev') {
finalizedBy {
run.environment("CONFIG_KEY", "DEVELOPMENT")
@@ -34,7 +39,7 @@ task runDev {
run
}
}
-task runProd {
+tasks.register('runProd') {
finalizedBy {
run.environment("CONFIG_KEY", "PRODUCTION")
@@ -47,7 +52,9 @@ idea {
inheritOutputDirs = true
}
}
-build.finalizedBy(javadoc)
+build {
+ finalizedBy(javadoc)
+}
dependencies {
// Web framework stuff
@@ -56,26 +63,41 @@ dependencies {
'io.dropwizard:dropwizard-hibernate:' + dropwizardVersion,
'io.dropwizard:dropwizard-auth:' + dropwizardVersion,
'io.dropwizard:dropwizard-jdbi3:' + dropwizardVersion,
+ 'org.eclipse.jetty.websocket:websocket-jetty-api:' + jettyVersion,
+ 'org.eclipse.jetty.websocket:websocket-jetty-server:' + jettyVersion,
)
+
+ // Websocket client libs
+ compileOnly 'jakarta.websocket:jakarta.websocket-client-api:2.2.0-M1'
+ // Impl for jakarta websocket clients
+ implementation 'org.eclipse.jetty.websocket:websocket-jakarta-client:11.0.20'
+
// Database
- implementation('com.h2database:h2:1.4.200')
- implementation('org.postgresql:postgresql:42.2.24.jre7')
+ implementation('com.h2database:h2:2.2.220')
+ implementation('org.postgresql:postgresql:42.7.3')
// Testing
- testImplementation('org.junit.jupiter:junit-jupiter:5.8.1')
- testImplementation('org.flywaydb:flyway-core:7.14.1')
- testImplementation('org.mockito:mockito-core:3.12.4')
+ testImplementation('org.junit.jupiter:junit-jupiter:5.10.2')
+ testImplementation('org.flywaydb:flyway-core:10.10.0')
+ testImplementation('org.mockito:mockito-core:5.11.0')
testImplementation("io.dropwizard:dropwizard-testing:" + dropwizardVersion)
// Statistics for Viterbi-lapper
- implementation("org.apache.commons:commons-math3:3.0")
+ implementation("org.apache.commons:commons-math3:3.6.1")
// JAX-B dependencies for JDK 9+ -> https://stackoverflow.com/a/43574427
- implementation 'javax.xml.bind:jaxb-api:2.4.0-b180830.0359'
- implementation 'org.glassfish.jaxb:jaxb-runtime:3.0.1'
+ implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.2'
+ implementation 'org.glassfish.jaxb:jaxb-runtime:4.0.5'
// Swagger-UI
- implementation 'com.smoketurner:dropwizard-swagger:2.0.0-1'
+ implementation('com.smoketurner:dropwizard-swagger:4.0.5-1')
+
+ // Getter & Setter via annotations
+ compileOnly 'org.projectlombok:lombok:1.18.32'
+ annotationProcessor 'org.projectlombok:lombok:1.18.32'
+
+ testCompileOnly 'org.projectlombok:lombok:1.18.32'
+ testAnnotationProcessor 'org.projectlombok:lombok:1.18.32'
}
test {
@@ -84,51 +106,13 @@ test {
testLogging {
events "passed", "skipped", "failed"
}
- finalizedBy {
- jacocoTestReport
- }
}
-jacoco {
- toolVersion = "0.8.7"
- reportsDirectory = layout.buildDirectory.dir('coverage').get()
-}
-jacocoTestReport {
- dependsOn {
- test
- }
- reports {
- xml.required = true
- }
- afterEvaluate {
- classDirectories.setFrom files(classDirectories.files.collect {
- fileTree(dir: it, exclude: [
- '**/database/models/**'
- ])
- })
- }
-}
-jacocoTestCoverageVerification {
- afterEvaluate {
- classDirectories.setFrom files(classDirectories.files.collect {
- fileTree(dir: it, exclude: [
- '**/database/models/**'
- ])
- })
- }
- violationRules {
- rule {
- limit {
- minimum = 0.7
- }
- }
- }
-}
def prodProps = new Properties()
file("$rootProject.projectDir/src/main/resources/telraam/prodConfig.properties").withInputStream {
prodProps.load(it)
}
-task migrateProductionDatabase(type: FlywayMigrateTask) {
+tasks.register('migrateProductionDatabase', FlywayMigrateTask) {
url = prodProps.getProperty("DB_URL")
}
@@ -136,7 +120,7 @@ def devProps = new Properties()
file("$rootProject.projectDir/src/main/resources/telraam/devConfig.properties").withInputStream {
devProps.load(it)
}
-task migrateDevelopmentDatabase(type: FlywayMigrateTask) {
+tasks.register('migrateDevelopmentDatabase', FlywayMigrateTask) {
url = devProps.getProperty("DB_URL")
user = devProps.getProperty("DB_USER")
password = devProps.getProperty("DB_PASSWORD")
@@ -146,14 +130,7 @@ def testProps = new Properties()
file("$rootProject.projectDir/src/test/resources/telraam/testConfig.properties").withInputStream {
testProps.load(it)
}
-task migrateTestingDatabase(type: FlywayMigrateTask) {
+tasks.register('migrateTestingDatabase', FlywayMigrateTask) {
url = testProps.getProperty("DB_URL")
baselineOnMigrate = true
}
-sonarqube {
- properties {
- property "sonar.projectKey", "12urenloop_Telraam"
- property "sonar.organization", "12urenloop"
- property "sonar.host.url", "https://sonarcloud.io"
- }
-}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e708b1c..d64cd49 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ffed3a2..a80b22c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 4f906e0..1aa94a4 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
#
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,99 @@
#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +119,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,88 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=`expr $i + 1`
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- 0) set -- ;;
- 1) set -- "$args0" ;;
- 2) set -- "$args0" "$args1" ;;
- 3) set -- "$args0" "$args1" "$args2" ;;
- 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=`save "$@"`
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index ac1b06f..7101f8e 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/settings.gradle b/settings.gradle
index fee0901..0c809d4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1 @@
rootProject.name = 'telraam'
-
diff --git a/src/main/java/telraam/App.java b/src/main/java/telraam/App.java
index 6f02ab9..7b8cc07 100644
--- a/src/main/java/telraam/App.java
+++ b/src/main/java/telraam/App.java
@@ -1,39 +1,54 @@
package telraam;
-import io.dropwizard.Application;
+import io.dropwizard.core.Application;
+import io.dropwizard.core.setup.Bootstrap;
+import io.dropwizard.core.setup.Environment;
import io.dropwizard.jdbi3.JdbiFactory;
import io.dropwizard.jdbi3.bundles.JdbiExceptionsBundle;
import io.dropwizard.jersey.setup.JerseyEnvironment;
-import io.dropwizard.setup.Bootstrap;
-import io.dropwizard.setup.Environment;
import io.federecio.dropwizard.swagger.SwaggerBundle;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.FilterRegistration;
+import lombok.Getter;
+import lombok.Setter;
import org.eclipse.jetty.servlets.CrossOriginFilter;
+import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
import org.jdbi.v3.core.Jdbi;
import telraam.api.*;
import telraam.database.daos.*;
import telraam.database.models.Station;
import telraam.healthchecks.TemplateHealthCheck;
-import telraam.logic.Lapper;
-import telraam.logic.external.ExternalLapper;
-import telraam.logic.robustLapper.RobustLapper;
-import telraam.logic.viterbi.ViterbiLapper;
-import telraam.station.Fetcher;
+import telraam.logic.lapper.Lapper;
+import telraam.logic.lapper.external.ExternalLapper;
+import telraam.logic.lapper.robust.RobustLapper;
+import telraam.logic.lapper.slapper.Slapper;
+import telraam.logic.positioner.Positioner;
+import telraam.logic.positioner.Stationary.Stationary;
+import telraam.logic.positioner.nostradamus.v2.Nostradamus;
+import telraam.logic.positioner.nostradamus.v1.NostradamusV1;
+import telraam.station.FetcherFactory;
import telraam.util.AcceptedLapsUtil;
+import telraam.websocket.WebSocketConnection;
-import javax.servlet.DispatcherType;
-import javax.servlet.FilterRegistration;
-import java.io.IOException;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
public class App extends Application {
- private static Logger logger = Logger.getLogger(App.class.getName());
+ private static final Logger logger = Logger.getLogger(App.class.getName());
+
+ @Getter
private AppConfiguration config;
+
+ @Getter
private Environment environment;
+
+ @Getter
private Jdbi database;
+
+ @Setter
private boolean testing;
public static void main(String[] args) throws Exception {
@@ -46,10 +61,6 @@ public App() {
testing = true;
}
- public void setTesting(boolean testing) {
- this.testing = testing;
- }
-
@Override
public String getName() {
return "hello-world";
@@ -69,7 +80,7 @@ protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(AppConfigurat
}
@Override
- public void run(AppConfiguration configuration, Environment environment) throws IOException {
+ public void run(AppConfiguration configuration, Environment environment) {
this.config = configuration;
this.environment = environment;
// Add database
@@ -79,6 +90,15 @@ public void run(AppConfiguration configuration, Environment environment) throws
// Initialize AcceptedLapUtil
AcceptedLapsUtil.createInstance(this.database);
+ // Register websocket endpoint
+ JettyWebSocketServletContainerInitializer.configure(
+ environment.getApplicationContext(),
+ (servletContext, wsContainer) -> {
+ wsContainer.setMaxTextMessageSize(65535);
+ wsContainer.addMapping("/ws", (req, res) -> new WebSocketConnection());
+ }
+ );
+
// Add api resources
JerseyEnvironment jersey = environment.jersey();
jersey.register(new BatonResource(database.onDemand(BatonDAO.class)));
@@ -87,14 +107,15 @@ public void run(AppConfiguration configuration, Environment environment) throws
jersey.register(new LapResource(database.onDemand(LapDAO.class)));
jersey.register(new TeamResource(database.onDemand(TeamDAO.class), database.onDemand(BatonSwitchoverDAO.class)));
jersey.register(new LapSourceResource(database.onDemand(LapSourceDAO.class)));
+ jersey.register(new PositionSourceResource(database.onDemand(PositionSourceDAO.class)));
jersey.register(new BatonSwitchoverResource(database.onDemand(BatonSwitchoverDAO.class)));
jersey.register(new LapSourceSwitchoverResource(database.onDemand(LapSourceSwitchoverDAO.class)));
jersey.register(new AcceptedLapsResource());
jersey.register(new TimeResource());
- jersey.register(new LapCountResource(database.onDemand(TeamDAO.class)));
+ jersey.register(new LapCountResource(database.onDemand(TeamDAO.class), database.onDemand(LapDAO.class)));
+ jersey.register(new MonitoringResource(database));
environment.healthChecks().register("template", new TemplateHealthCheck(configuration.getTemplate()));
-
// Enable CORS
final FilterRegistration.Dynamic cors = environment.servlets().addFilter("CORS", CrossOriginFilter.class);
@@ -106,40 +127,34 @@ public void run(AppConfiguration configuration, Environment environment) throws
// Add URL mapping
cors.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
- if (! testing) {
+ if (!testing) {
// Set up lapper algorithms
Set lappers = new HashSet<>();
- // Old viterbi lapper is disabled
- //lappers.add(new ViterbiLapper(this.database));
-
lappers.add(new ExternalLapper(this.database));
lappers.add(new RobustLapper(this.database));
+ lappers.add(new Slapper(this.database));
// Enable lapper APIs
for (Lapper lapper : lappers) {
lapper.registerAPI(jersey);
}
+ // Set up positioners
+ Set positioners = new HashSet<>();
+
+ positioners.add(new Stationary(this.database));
+ positioners.add(new NostradamusV1(this.database));
+ positioners.add(new Nostradamus(configuration, this.database));
+
// Start fetch thread for each station
+ FetcherFactory fetcherFactory = new FetcherFactory(this.database, lappers, positioners);
StationDAO stationDAO = this.database.onDemand(StationDAO.class);
for (Station station : stationDAO.getAll()) {
- new Thread(() -> new Fetcher(this.database, station, lappers).fetch()).start();
+ new Thread(() -> fetcherFactory.create(station).fetch()).start();
}
}
logger.info("Up and running!");
}
-
- public AppConfiguration getConfig() {
- return config;
- }
-
- public Environment getEnvironment() {
- return environment;
- }
-
- public Jdbi getDatabase() {
- return database;
- }
}
diff --git a/src/main/java/telraam/AppConfiguration.java b/src/main/java/telraam/AppConfiguration.java
index 3a45777..9648e63 100644
--- a/src/main/java/telraam/AppConfiguration.java
+++ b/src/main/java/telraam/AppConfiguration.java
@@ -1,59 +1,34 @@
package telraam;
import com.fasterxml.jackson.annotation.JsonProperty;
-import io.dropwizard.Configuration;
+import io.dropwizard.core.Configuration;
import io.dropwizard.db.DataSourceFactory;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
-import telraam.api.responses.Template;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
public class AppConfiguration extends Configuration {
@NotNull
+ @Getter @Setter
private String template;
@NotNull
+ @Getter @Setter
private String defaultName = "Stranger";
+ @JsonProperty("swagger")
+ public SwaggerBundleConfiguration swaggerBundleConfiguration;
+
@Valid
@NotNull
- private DataSourceFactory database = new DataSourceFactory();
-
- @JsonProperty
- public String getTemplate() {
- return template;
- }
-
- @JsonProperty
- public void setTemplate(String template) {
- this.template = template;
- }
-
- public Template buildTemplate() {
- return new Template(template, defaultName);
- }
-
- @JsonProperty
- public String getDefaultName() {
- return defaultName;
- }
-
- @JsonProperty
- public void setDefaultName(String name) {
- this.defaultName = name;
- }
-
- @JsonProperty("database")
- public DataSourceFactory getDataSourceFactory() {
- return database;
- }
-
+ @Getter @Setter
@JsonProperty("database")
- public void setDataSourceFactory(DataSourceFactory factory) {
- this.database = factory;
- }
+ private DataSourceFactory dataSourceFactory = new DataSourceFactory();
- @JsonProperty("swagger")
- public SwaggerBundleConfiguration swaggerBundleConfiguration;
+ @NotNull
+ @Getter
+ @JsonProperty("finish_offset")
+ private int finishOffset;
}
diff --git a/src/main/java/telraam/api/AbstractListableResource.java b/src/main/java/telraam/api/AbstractListableResource.java
index e600a1c..b9e5030 100644
--- a/src/main/java/telraam/api/AbstractListableResource.java
+++ b/src/main/java/telraam/api/AbstractListableResource.java
@@ -1,6 +1,7 @@
package telraam.api;
+import io.swagger.v3.oas.annotations.Operation;
import telraam.database.daos.DAO;
import java.util.List;
@@ -11,6 +12,7 @@ protected AbstractListableResource(DAO dao) {
}
@Override
+ @Operation(summary = "Find all")
public List getListOf() {
return dao.getAll();
}
diff --git a/src/main/java/telraam/api/AbstractResource.java b/src/main/java/telraam/api/AbstractResource.java
index ce0e097..62f9bd7 100644
--- a/src/main/java/telraam/api/AbstractResource.java
+++ b/src/main/java/telraam/api/AbstractResource.java
@@ -1,12 +1,15 @@
package telraam.api;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Response;
+import org.checkerframework.checker.units.qual.C;
import telraam.database.daos.DAO;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
import java.util.Optional;
public abstract class AbstractResource implements Resource {
@@ -18,17 +21,17 @@ protected AbstractResource(DAO dao) {
}
@Override
+ @Operation(summary = "Add new to the database")
// TODO Validate model and return 405 for wrong input
- public int create(@ApiParam(required = true) T t) {
+ public int create(@Parameter(required = true) T t) {
return dao.insert(t);
}
@Override
- @ApiResponses(value = {
- @ApiResponse(code = 400, message = "Invalid or no ID supplied"), // TODO validate ID, return 400 on wrong ID format
- @ApiResponse(code = 404, message = "Entity with specified ID not found")
- })
- public T get(@ApiParam(value = "ID of entity that needs to be fetched", required = true) Optional id) {
+ @Operation(summary = "Find by ID")
+ @ApiResponse(responseCode = "400", description = "Invalid or no ID supplied") // TODO validate ID, return 400 on wrong ID format
+ @ApiResponse(responseCode = "404", description = "Entity with specified ID not found")
+ public T get(@Parameter(description = "ID of entity that needs to be fetched", required = true) Optional id) {
if (id.isPresent()) {
Optional optional = dao.getById(id.get());
if (optional.isPresent()) {
@@ -42,12 +45,12 @@ public T get(@ApiParam(value = "ID of entity that needs to be fetched", required
}
@Override
- @ApiResponses(value = {
- @ApiResponse(code = 400, message = "Invalid or no ID supplied"), // TODO validate ID, return 400 on wrong ID format
- @ApiResponse(code = 404, message = "Entity with specified ID not found"),
- @ApiResponse(code = 405, message = "Validation exception")}) // TODO validate input, 405 on wrong input
- public T update(@ApiParam(value = "Entity object that needs to be updated in the database", required = true) T t,
- @ApiParam(value = "ID of entity that needs to be fetched", required = true) Optional id) {
+ @Operation(summary = "Update an existing")
+ @ApiResponse(responseCode = "400", description = "Invalid or no ID supplied") // TODO validate ID, return 400 on wrong ID format
+ @ApiResponse(responseCode = "404", description = "Entity with specified ID not found")
+ @ApiResponse(responseCode = "405", description = "Validation exception") // TODO validate input, 405 on wrong input
+ public T update(@Parameter(description = "Entity object that needs to be updated in the database", required = true) T t,
+ @Parameter(description = "ID of entity that needs to be fetched", required = true) Optional id) {
if (id.isPresent()) {
Optional optionalBaton = dao.getById(id.get());
if (optionalBaton.isPresent()) {
@@ -62,11 +65,12 @@ public T update(@ApiParam(value = "Entity object that needs to be updated in the
}
@Override
+ @Operation(summary = "Delete an existing")
@ApiResponses(value = {
- @ApiResponse(code = 400, message = "Invalid or no ID supplied"), // TODO validate ID, return 400 on wrong ID format
+ @ApiResponse(responseCode = "400", description = "Invalid or no ID supplied"), // TODO validate ID, return 400 on wrong ID format
})
public boolean delete(
- @ApiParam(value = "ID of entity that needs to be deleted", required = true) Optional id) {
+ @Parameter(description = "ID of entity that needs to be deleted", required = true) Optional id) {
if (id.isPresent()) {
return dao.deleteById(id.get()) == 1;
} else {
diff --git a/src/main/java/telraam/api/AcceptedLapsResource.java b/src/main/java/telraam/api/AcceptedLapsResource.java
index 6b14dc4..b413511 100644
--- a/src/main/java/telraam/api/AcceptedLapsResource.java
+++ b/src/main/java/telraam/api/AcceptedLapsResource.java
@@ -1,27 +1,22 @@
package telraam.api;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import telraam.database.daos.LapDAO;
-import telraam.database.daos.LapSourceSwitchoverDAO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import telraam.database.models.Lap;
-import telraam.database.models.LapSourceSwitchover;
import telraam.util.AcceptedLapsUtil;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.util.ArrayList;
-import java.util.Comparator;
import java.util.List;
@Path("/accepted-laps")
-@Api("/accepted-laps")
+@Tag(name="Accpted Laps")
@Produces(MediaType.APPLICATION_JSON)
public class AcceptedLapsResource {
@GET
- @ApiOperation("Get all accepted laps")
+ @Operation(summary = "Get all accepted laps")
public List getLaps() {
return AcceptedLapsUtil.getInstance().getAcceptedLaps();
}
diff --git a/src/main/java/telraam/api/BatonResource.java b/src/main/java/telraam/api/BatonResource.java
index a584432..faa802b 100644
--- a/src/main/java/telraam/api/BatonResource.java
+++ b/src/main/java/telraam/api/BatonResource.java
@@ -1,50 +1,18 @@
package telraam.api;
-import io.swagger.annotations.*;
-import telraam.database.daos.BatonDAO;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import telraam.database.daos.DAO;
import telraam.database.models.Baton;
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-import java.util.List;
-import java.util.Optional;
-
@Path("/baton") // dropwizard
-@Api(value = "/baton") // Swagger
+@Tag(name = "Baton")
@Produces(MediaType.APPLICATION_JSON)
public class BatonResource extends AbstractListableResource {
- public BatonResource(BatonDAO dao) {
+ public BatonResource(DAO dao) {
super(dao);
}
-
- @Override
- @ApiOperation(value = "Find all batons")
- public List getListOf() {
- return super.getListOf();
- }
-
- @Override
- @ApiOperation(value = "Add a new baton to the database")
- public int create(Baton baton) {
- return super.create(baton);
- }
-
- @Override
- @ApiOperation(value = "Find baton by ID")
- public Baton get(Optional id) {
- return super.get(id);
- }
-
- @Override
- @ApiOperation(value = "Update an existing baton")
- public Baton update(Baton baton, Optional id) {
- return super.update(baton, id);
- }
-
- @Override
- @ApiOperation(value = "Delete an existing baton")
- public boolean delete(Optional id) {
- return super.delete(id);
- }
}
diff --git a/src/main/java/telraam/api/BatonSwitchoverResource.java b/src/main/java/telraam/api/BatonSwitchoverResource.java
index 6cc6611..9b1a173 100644
--- a/src/main/java/telraam/api/BatonSwitchoverResource.java
+++ b/src/main/java/telraam/api/BatonSwitchoverResource.java
@@ -1,43 +1,18 @@
package telraam.api;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import telraam.database.daos.BatonDAO;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import telraam.database.daos.BatonSwitchoverDAO;
-import telraam.database.models.Baton;
import telraam.database.models.BatonSwitchover;
-import telraam.database.models.LapSourceSwitchover;
-
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.util.List;
-import java.util.Optional;
@Path("/batonswitchover") // dropwizard
-@Api(value = "/batonswitchover") // Swagger
+@Tag(name = "Baton Switchover")
@Produces(MediaType.APPLICATION_JSON)
public class BatonSwitchoverResource extends AbstractListableResource {
public BatonSwitchoverResource(BatonSwitchoverDAO dao) {
super(dao);
}
-
- @Override
- @ApiOperation(value = "Find all baton switchovers")
- public List getListOf() {
- return super.getListOf();
- }
-
- @Override
- @ApiOperation(value = "Find baton switchover by ID")
- public BatonSwitchover get(Optional id) {
- return super.get(id);
- }
-
- @Override
- @ApiOperation(value = "Add a new baton switchover to the database")
- public int create(BatonSwitchover batonSwitchover) {
- return super.create(batonSwitchover);
- }
}
diff --git a/src/main/java/telraam/api/DetectionResource.java b/src/main/java/telraam/api/DetectionResource.java
index 6ab0f35..b7566cc 100644
--- a/src/main/java/telraam/api/DetectionResource.java
+++ b/src/main/java/telraam/api/DetectionResource.java
@@ -1,18 +1,18 @@
package telraam.api;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
import telraam.database.daos.DetectionDAO;
import telraam.database.models.Detection;
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
import java.util.List;
import java.util.Optional;
@Path("/detection")
-@Api(value = "/detection") // Swagger
@Produces(MediaType.APPLICATION_JSON)
+@Tag(name="Detection")
public class DetectionResource extends AbstractListableResource {
private final DetectionDAO detectionDAO;
@@ -22,39 +22,9 @@ public DetectionResource(DetectionDAO dao) {
detectionDAO = dao;
}
- @Override
- @ApiOperation(value = "Find all detections")
- public List getListOf() {
- return super.getListOf();
- }
-
- @Override
- @ApiOperation(value = "Add a new detection to the database")
- public int create(Detection detection) {
- return super.create(detection);
- }
-
- @Override
- @ApiOperation(value = "Find detection by ID")
- public Detection get(Optional id) {
- return super.get(id);
- }
-
- @Override
- @ApiOperation(value = "Update an existing detection")
- public Detection update(Detection detection, Optional id) {
- return super.update(detection, id);
- }
-
- @Override
- @ApiOperation(value = "Delete an existing detection")
- public boolean delete(Optional id) {
- return super.delete(id);
- }
-
@GET
@Path("/since/{id}")
- @ApiOperation(value = "Get detections with ID larger than given ID")
+ @Operation(summary = "Get detections with ID larger than given ID")
public List getListSince(@PathParam("id") Integer id, @QueryParam("limit") Optional limit) {
return detectionDAO.getSinceId(id, limit.orElse(1000));
}
diff --git a/src/main/java/telraam/api/LapCountResource.java b/src/main/java/telraam/api/LapCountResource.java
index c3a857d..edb7b03 100644
--- a/src/main/java/telraam/api/LapCountResource.java
+++ b/src/main/java/telraam/api/LapCountResource.java
@@ -1,32 +1,37 @@
package telraam.api;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
import telraam.database.daos.LapDAO;
-import telraam.database.daos.LapSourceSwitchoverDAO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
import telraam.database.daos.TeamDAO;
import telraam.database.models.Lap;
-import telraam.database.models.LapSourceSwitchover;
+import telraam.database.models.LapCount;
import telraam.database.models.Team;
import telraam.util.AcceptedLapsUtil;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.util.*;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
@Path("/lap-counts")
-@Api("/lap-counts")
+@Tag(name="Lap Counts")
@Produces(MediaType.APPLICATION_JSON)
public class LapCountResource {
- TeamDAO teamDAO;
+ private TeamDAO teamDAO;
+ private LapDAO lapDAO;
- public LapCountResource(TeamDAO teamDAO) {
+ public LapCountResource(TeamDAO teamDAO, LapDAO lapDAO) {
this.teamDAO = teamDAO;
+ this.lapDAO = lapDAO;
}
+
@GET
- @ApiOperation("Get the current lap counts per team")
+ @Operation(summary = "Get the current lap counts per team")
public Map getLapCounts() {
Map perId = new HashMap<>();
for (Lap lap : AcceptedLapsUtil.getInstance().getAcceptedLaps()) {
@@ -55,4 +60,27 @@ public Map getLapCounts() {
return perName;
}
+
+ @GET
+ @Path("/{lapSourceId}")
+ public List getLapCountForLapSource(@PathParam("lapSourceId") Integer id, @QueryParam("end") Optional endTimestamp) {
+ LocalDateTime dateTime = LocalDateTime.now();
+ if (endTimestamp.isPresent()) {
+ dateTime = LocalDateTime.parse(endTimestamp.get());
+ }
+ List laps = lapDAO.getAllBeforeTime(id, Timestamp.valueOf(dateTime));
+ return laps;
+ }
+
+ // EndTimestamp should be a ISO formatted date timestamp
+ @GET
+ @Path("/{lapSourceId}/{teamId}")
+ public Integer getLapCountForLapSource(@PathParam("lapSourceId") Integer id, @PathParam("teamId") Integer teamId, @QueryParam("end") Optional endTimestamp) {
+ LocalDateTime dateTime = LocalDateTime.now();
+ if (endTimestamp.isPresent()) {
+ dateTime = LocalDateTime.parse(endTimestamp.get());
+ }
+ LapCount lapInfo = lapDAO.getAllForTeamBeforeTime(id, teamId, Timestamp.valueOf(dateTime));
+ return lapInfo.getCount();
+ }
}
diff --git a/src/main/java/telraam/api/LapResource.java b/src/main/java/telraam/api/LapResource.java
index 29186e9..a0ef3db 100644
--- a/src/main/java/telraam/api/LapResource.java
+++ b/src/main/java/telraam/api/LapResource.java
@@ -1,20 +1,17 @@
package telraam.api;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
import telraam.database.daos.LapDAO;
import telraam.database.models.Lap;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
import java.util.List;
import java.util.Optional;
@Path("/lap")
-@Api("/lap")
+@Tag(name="Lap")
@Produces(MediaType.APPLICATION_JSON)
public class LapResource extends AbstractResource {
private final LapDAO lapDAO;
@@ -25,7 +22,7 @@ public LapResource(LapDAO dao) {
}
@GET
- @ApiOperation(value = "Find all laps")
+ @Operation(summary = "Find all laps")
public List getListOf(@QueryParam("source") final Integer source) {
if (source == null) {
return lapDAO.getAll();
@@ -33,28 +30,4 @@ public List getListOf(@QueryParam("source") final Integer source) {
return lapDAO.getAllBySource(source);
}
}
-
- @Override
- @ApiOperation(value = "Add a new lap to the database")
- public int create(Lap lap) {
- return super.create(lap);
- }
-
- @Override
- @ApiOperation(value = "Find lap by ID")
- public Lap get(Optional id) {
- return super.get(id);
- }
-
- @Override
- @ApiOperation(value = "Update an existing lap")
- public Lap update(Lap lap, Optional id) {
- return super.update(lap, id);
- }
-
- @Override
- @ApiOperation(value = "Delete an existing lap")
- public boolean delete(Optional id) {
- return super.delete(id);
- }
}
diff --git a/src/main/java/telraam/api/LapSourceResource.java b/src/main/java/telraam/api/LapSourceResource.java
index e2037e3..630e6db 100644
--- a/src/main/java/telraam/api/LapSourceResource.java
+++ b/src/main/java/telraam/api/LapSourceResource.java
@@ -1,51 +1,17 @@
package telraam.api;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import telraam.database.daos.DAO;
import telraam.database.models.LapSource;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.util.List;
-import java.util.Optional;
-
@Path("/lap-source")
-@Api("/lap-source")
+@Tag(name = "Lap Source")
@Produces(MediaType.APPLICATION_JSON)
public class LapSourceResource extends AbstractListableResource {
public LapSourceResource(DAO dao) {
super(dao);
}
-
- @Override
- @ApiOperation(value = "Find all lap sources")
- public List getListOf() {
- return super.getListOf();
- }
-
- @Override
- @ApiOperation(value = "Add a new lap source to the database")
- public int create(LapSource lapSource) {
- return super.create(lapSource);
- }
-
- @Override
- @ApiOperation(value = "Find lap source by ID")
- public LapSource get(Optional id) {
- return super.get(id);
- }
-
- @Override
- @ApiOperation(value = "Update an existing lap source")
- public LapSource update(LapSource lapSource, Optional id) {
- return super.update(lapSource, id);
- }
-
- @Override
- @ApiOperation(value = "Delete an existing lap source")
- public boolean delete(Optional id) {
- return super.delete(id);
- }
}
diff --git a/src/main/java/telraam/api/LapSourceSwitchoverResource.java b/src/main/java/telraam/api/LapSourceSwitchoverResource.java
index 06290bf..598cdf0 100644
--- a/src/main/java/telraam/api/LapSourceSwitchoverResource.java
+++ b/src/main/java/telraam/api/LapSourceSwitchoverResource.java
@@ -1,41 +1,18 @@
package telraam.api;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import telraam.database.daos.LapSourceSwitchoverDAO;
-import telraam.database.models.LapSource;
import telraam.database.models.LapSourceSwitchover;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.util.List;
-import java.util.Optional;
-
@Path("/lapsourceswitchover") // dropwizard
-@Api(value = "/lapsourceswitchover") // Swagger
+@Tag(name = "Lap Source Switchover")
@Produces(MediaType.APPLICATION_JSON)
public class LapSourceSwitchoverResource extends AbstractListableResource {
public LapSourceSwitchoverResource(LapSourceSwitchoverDAO dao) {
super(dao);
}
-
- @Override
- @ApiOperation(value = "Find all lap source switchovers")
- public List getListOf() {
- return super.getListOf();
- }
-
- @Override
- @ApiOperation(value = "Find lap source switchover by ID")
- public LapSourceSwitchover get(Optional id) {
- return super.get(id);
- }
-
- @Override
- @ApiOperation(value = "Add a new lap source switchover to the database")
- public int create(LapSourceSwitchover lapSourceSwitchover) {
- return super.create(lapSourceSwitchover);
- }
}
diff --git a/src/main/java/telraam/api/ListableResource.java b/src/main/java/telraam/api/ListableResource.java
index e8bc2d5..24d84ea 100644
--- a/src/main/java/telraam/api/ListableResource.java
+++ b/src/main/java/telraam/api/ListableResource.java
@@ -1,6 +1,6 @@
package telraam.api;
-import javax.ws.rs.GET;
+import jakarta.ws.rs.GET;
import java.util.List;
/**
diff --git a/src/main/java/telraam/api/MonitoringResource.java b/src/main/java/telraam/api/MonitoringResource.java
new file mode 100644
index 0000000..732b01a
--- /dev/null
+++ b/src/main/java/telraam/api/MonitoringResource.java
@@ -0,0 +1,127 @@
+package telraam.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.jdbi.v3.core.Jdbi;
+import telraam.database.daos.*;
+import telraam.database.models.Lap;
+import telraam.database.models.LapSource;
+import telraam.database.models.Team;
+import telraam.database.models.TeamLapCount;
+import telraam.monitoring.BatonDetectionManager;
+import telraam.monitoring.BatonStatusHolder;
+import telraam.monitoring.StationDetectionManager;
+import telraam.monitoring.models.BatonDetection;
+import telraam.monitoring.models.BatonStatus;
+import telraam.monitoring.models.LapCountForTeam;
+import telraam.monitoring.models.TeamLapInfo;
+
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+
+import java.util.*;
+
+@Path("/monitoring")
+@Tag(name = "Monitoring")
+@Produces(MediaType.APPLICATION_JSON)
+public class MonitoringResource {
+ private final BatonStatusHolder batonStatusHolder;
+ private final BatonDetectionManager batonDetectionManager;
+ private final StationDetectionManager stationDetectionManager;
+ private final TeamDAO teamDAO;
+ private final LapDAO lapDAO;
+ private final LapSourceDAO lapSourceDAO;
+
+ public MonitoringResource(Jdbi jdbi) {
+ this.teamDAO = jdbi.onDemand(TeamDAO.class);
+ this.lapDAO = jdbi.onDemand(LapDAO.class);
+ this.lapSourceDAO = jdbi.onDemand(LapSourceDAO.class);
+ this.batonStatusHolder = new BatonStatusHolder(jdbi.onDemand(BatonDAO.class), jdbi.onDemand(DetectionDAO.class));
+ this.batonDetectionManager = new BatonDetectionManager(jdbi.onDemand(DetectionDAO.class), this.teamDAO, jdbi.onDemand(BatonSwitchoverDAO.class));
+ this.stationDetectionManager = new StationDetectionManager(jdbi.onDemand(DetectionDAO.class), jdbi.onDemand(StationDAO.class));
+ }
+
+ @GET
+ @Path("/batons")
+ @Operation(summary = "Get the status of all the batons, including unused batons which are toggleable via a parameter")
+ public List getBatonMetrics(@QueryParam("filter_assigned") boolean filterAssigned) {
+ List batonStatuses = batonStatusHolder.GetAllBatonStatuses();
+ if (filterAssigned) {
+ List teams = teamDAO.getAll();
+ Set usedBatonIds = new HashSet<>();
+ for (Team team : teams) {
+ usedBatonIds.add(team.getBatonId());
+ }
+ return batonStatuses.stream().filter(batonStatus -> usedBatonIds.contains(batonStatus.getId())).toList();
+ }
+ return batonStatuses;
+ }
+
+ @POST
+ @Path("/reset-rebooted/{batonId}")
+ @Operation(summary = "Reset the rebooted flag of a baton")
+ public void resetRebooted(@PathParam("batonId") Integer batonId) {
+ batonStatusHolder.resetRebooted(batonId);
+ }
+
+ @GET
+ @Path("/team-detection-times")
+ @Operation(summary = "A map of all detections per batons")
+ public Map> getTeamDetectionTimes() {
+ return batonDetectionManager.getBatonDetections();
+ }
+
+ @GET
+ @Path("/stations-latest-detection-time")
+ @Operation(summary = "Get the map of all station name to time since last detection")
+ public Map getStationIDToLatestDetectionTimeMap() {
+ return stationDetectionManager.timeSinceLastDetectionPerStation();
+ }
+
+ @GET
+ @Path("/team-lap-times/{lapperId}")
+ @Operation(summary = "Get monitoring data that can be used as grafana datasource")
+ public Map> getTeamLapTimes(@PathParam("lapperId") Integer id) {
+ List laps = lapDAO.getAllBySourceSorted(id);
+ List teams = teamDAO.getAll();
+ Map teamMap = new HashMap<>();
+ for (Team team : teams) {
+ teamMap.put(team.getId(), team);
+ }
+ Map> teamLapInfos = new HashMap<>();
+ Map previousLap = new HashMap<>();
+ for (Lap lap : laps) {
+ if (!previousLap.containsKey(lap.getTeamId())) {
+ previousLap.put(lap.getTeamId(), lap);
+ continue;
+ }
+ Lap prevLap = previousLap.get(lap.getTeamId());
+ previousLap.put(lap.getTeamId(), lap);
+ if (!teamLapInfos.containsKey(lap.getTeamId())) {
+ teamLapInfos.put(lap.getTeamId(), new ArrayList<>());
+ }
+ Team team = teamMap.get(lap.getTeamId());
+ teamLapInfos.get(lap.getTeamId()).add(new TeamLapInfo((lap.getTimestamp().getTime() - prevLap.getTimestamp().getTime()) / 1000, lap.getTimestamp().getTime() / 1000, lap.getTeamId(), team.getName()));
+ }
+ return teamLapInfos;
+ }
+
+ @GET
+ @Path("/team-lap-counts")
+ @Operation(summary = "Get monitoring data that can be used as grafana datasource")
+ public List getTeamLapCounts() {
+ List teams = teamDAO.getAll();
+ List lapSources = lapSourceDAO.getAll();
+ List lapCountForTeams = new ArrayList<>();
+ for (Team team : teams) {
+ var teamLapsCount = lapDAO.getAllBySourceAndTeam(team.getId());
+ Map lapCounts = new HashMap<>();
+ lapSources.forEach(lapSource -> lapCounts.put(lapSource.getId(), 0));
+ for (TeamLapCount teamLapCount : teamLapsCount) {
+ lapCounts.put(teamLapCount.getLapSourceId(), teamLapCount.getLapCount());
+ }
+ lapCountForTeams.add(new LapCountForTeam(team.getName(), lapCounts));
+ }
+ return lapCountForTeams;
+ }
+}
diff --git a/src/main/java/telraam/api/PositionSourceResource.java b/src/main/java/telraam/api/PositionSourceResource.java
new file mode 100644
index 0000000..f59c7bb
--- /dev/null
+++ b/src/main/java/telraam/api/PositionSourceResource.java
@@ -0,0 +1,20 @@
+package telraam.api;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import telraam.database.daos.DAO;
+import telraam.database.models.PositionSource;
+
+
+import java.awt.*;
+
+@Path("/position-source")
+@Tag(name = "Position Source")
+@Produces(MediaType.APPLICATION_JSON)
+public class PositionSourceResource extends AbstractListableResource {
+ public PositionSourceResource(DAO dao) {
+ super(dao);
+ }
+}
diff --git a/src/main/java/telraam/api/Resource.java b/src/main/java/telraam/api/Resource.java
index 6228da0..5546cba 100644
--- a/src/main/java/telraam/api/Resource.java
+++ b/src/main/java/telraam/api/Resource.java
@@ -1,7 +1,8 @@
package telraam.api;
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+
import java.util.Optional;
public interface Resource {
diff --git a/src/main/java/telraam/api/StationResource.java b/src/main/java/telraam/api/StationResource.java
index 58c11ed..106131c 100644
--- a/src/main/java/telraam/api/StationResource.java
+++ b/src/main/java/telraam/api/StationResource.java
@@ -1,51 +1,17 @@
package telraam.api;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import telraam.database.daos.DAO;
import telraam.database.models.Station;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.util.List;
-import java.util.Optional;
-
@Path("/station")
-@Api(value = "/station") // Swagger
+@Tag(name = "Station")
@Produces(MediaType.APPLICATION_JSON)
public class StationResource extends AbstractListableResource {
public StationResource(DAO dao) {
super(dao);
}
-
- @Override
- @ApiOperation(value = "Find all stations")
- public List getListOf() {
- return super.getListOf();
- }
-
- @Override
- @ApiOperation(value = "Add a new station to the database")
- public int create(Station station) {
- return super.create(station);
- }
-
- @Override
- @ApiOperation(value = "Find station by ID")
- public Station get(Optional id) {
- return super.get(id);
- }
-
- @Override
- @ApiOperation(value = "Update an existing station")
- public Station update(Station station, Optional id) {
- return super.update(station, id);
- }
-
- @Override
- @ApiOperation(value = "Delete an existing station")
- public boolean delete(Optional id) {
- return super.delete(id);
- }
}
diff --git a/src/main/java/telraam/api/TeamResource.java b/src/main/java/telraam/api/TeamResource.java
index 67c5b04..9bf36c3 100644
--- a/src/main/java/telraam/api/TeamResource.java
+++ b/src/main/java/telraam/api/TeamResource.java
@@ -1,15 +1,15 @@
package telraam.api;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import telraam.database.daos.BatonSwitchoverDAO;
import telraam.database.daos.TeamDAO;
import telraam.database.models.BatonSwitchover;
import telraam.database.models.Team;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.List;
@@ -18,23 +18,18 @@
@Path("/team")
-@Api("/team")
+@Tag(name="Team")
@Produces(MediaType.APPLICATION_JSON)
public class TeamResource extends AbstractListableResource {
BatonSwitchoverDAO batonSwitchoverDAO;
+
public TeamResource(TeamDAO teamDAO, BatonSwitchoverDAO batonSwitchoverDAO) {
super(teamDAO);
this.batonSwitchoverDAO = batonSwitchoverDAO;
}
@Override
- @ApiOperation(value = "Find all teams")
- public List getListOf() {
- return super.getListOf();
- }
-
- @Override
- @ApiOperation(value = "Add a new team to the database")
+ @Operation(summary = "Add a new team to the database")
public int create(Team team) {
int ret = super.create(team);
@@ -51,35 +46,20 @@ public int create(Team team) {
}
@Override
- @ApiOperation(value = "Find team by ID")
- public Team get(Optional id) {
- return super.get(id);
- }
-
- @Override
- @ApiOperation(value = "Update an existing team")
+ @Operation(summary = "Update an existing team")
public Team update(Team team, Optional id) {
Team previousTeam = this.get(id);
Team ret = super.update(team, id);
- System.out.println(previousTeam.getBatonId());
- System.out.println(team.getBatonId());
-
if (!Objects.equals(previousTeam.getBatonId(), team.getBatonId())) {
this.batonSwitchoverDAO.insert(new BatonSwitchover(
- team.getId(),
- previousTeam.getBatonId(),
- team.getBatonId(),
- Timestamp.from(Instant.now())
+ team.getId(),
+ previousTeam.getBatonId(),
+ team.getBatonId(),
+ Timestamp.from(Instant.now())
));
}
return ret;
}
-
- @Override
- @ApiOperation(value = "Delete an existing team")
- public boolean delete(Optional id) {
- return super.delete(id);
- }
}
diff --git a/src/main/java/telraam/api/TimeResource.java b/src/main/java/telraam/api/TimeResource.java
index 0c85770..f49e0c3 100644
--- a/src/main/java/telraam/api/TimeResource.java
+++ b/src/main/java/telraam/api/TimeResource.java
@@ -1,19 +1,17 @@
package telraam.api;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.time.Instant;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
@Path("/time")
-@Api("/time")
+@Tag(name = "Time")
@Produces(MediaType.APPLICATION_JSON)
public class TimeResource {
- static class TimeResponse {
+ public static class TimeResponse {
public long timestamp;
public TimeResponse() {
@@ -22,7 +20,7 @@ public TimeResponse() {
}
@GET
- @ApiOperation(value = "Get current time")
+ @Operation(summary = "Get current time")
public TimeResponse get() {
return new TimeResponse();
}
diff --git a/src/main/java/telraam/api/responses/Saying.java b/src/main/java/telraam/api/responses/Saying.java
index 79afdf9..5750eea 100644
--- a/src/main/java/telraam/api/responses/Saying.java
+++ b/src/main/java/telraam/api/responses/Saying.java
@@ -1,30 +1,16 @@
package telraam.api.responses;
-import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
public class Saying {
private long id;
@Length(max = 3)
private String content;
-
- public Saying() {
- // Jackson deserialization
- }
-
- public Saying(long id, String content) {
- this.id = id;
- this.content = content;
- }
-
- @JsonProperty
- public long getId() {
- return id;
- }
-
- @JsonProperty
- public String getContent() {
- return content;
- }
}
\ No newline at end of file
diff --git a/src/main/java/telraam/api/responses/Template.java b/src/main/java/telraam/api/responses/Template.java
index ce15c84..d41829d 100644
--- a/src/main/java/telraam/api/responses/Template.java
+++ b/src/main/java/telraam/api/responses/Template.java
@@ -1,18 +1,16 @@
package telraam.api.responses;
+import lombok.AllArgsConstructor;
+
import java.util.Optional;
import static java.lang.String.format;
+@AllArgsConstructor
public class Template {
private final String content;
private final String defaultName;
- public Template(String content, String defaultName) {
- this.content = content;
- this.defaultName = defaultName;
- }
-
public String render(Optional name) {
return format(content, name.orElse(defaultName));
}
diff --git a/src/main/java/telraam/database/daos/BatonDAO.java b/src/main/java/telraam/database/daos/BatonDAO.java
index f0859d1..2aefda9 100644
--- a/src/main/java/telraam/database/daos/BatonDAO.java
+++ b/src/main/java/telraam/database/daos/BatonDAO.java
@@ -28,6 +28,10 @@ public interface BatonDAO extends DAO {
@RegisterBeanMapper(Baton.class)
Optional getById(@Bind("id") int id);
+ @SqlQuery("SELECT * FROM baton WHERE mac = :mac")
+ @RegisterBeanMapper(Baton.class)
+ Optional getByMac(@Bind("mac") String mac);
+
@Override
@SqlUpdate("DELETE FROM baton WHERE id = :id")
@RegisterBeanMapper(Baton.class)
diff --git a/src/main/java/telraam/database/daos/DetectionDAO.java b/src/main/java/telraam/database/daos/DetectionDAO.java
index be6e6f9..982b92c 100644
--- a/src/main/java/telraam/database/daos/DetectionDAO.java
+++ b/src/main/java/telraam/database/daos/DetectionDAO.java
@@ -3,13 +3,13 @@
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.customizer.Bind;
import org.jdbi.v3.sqlobject.customizer.BindBean;
-import org.jdbi.v3.sqlobject.customizer.BindBeanList;
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
import org.jdbi.v3.sqlobject.statement.SqlBatch;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import telraam.database.models.Detection;
+import java.sql.Timestamp;
import java.util.List;
import java.util.Optional;
@@ -33,6 +33,16 @@ INSERT INTO detection (station_id, baton_id, timestamp, rssi, battery, remote_id
@GetGeneratedKeys({"id"})
int insertAll(@BindBean List detection);
+ @SqlBatch("""
+ INSERT INTO detection (station_id, baton_id, timestamp, rssi, battery, remote_id, uptime_ms, timestamp_ingestion)
+ SELECT :stationId, b.id, :timestamp, :rssi, :battery, :remoteId, :uptimeMs, :timestampIngestion
+ FROM baton b
+ WHERE b.mac = :batonMac
+ """)
+ @GetGeneratedKeys({"id", "baton_id"})
+ @RegisterBeanMapper(Detection.class)
+ List insertAllWithoutBaton(@BindBean List detection, @Bind("batonMac") List batonMac);
+
@SqlQuery("SELECT * FROM detection WHERE id = :id")
@RegisterBeanMapper(Detection.class)
Optional getById(@Bind("id") int id);
@@ -55,4 +65,16 @@ INSERT INTO detection (station_id, baton_id, timestamp, rssi, battery, remote_id
@SqlQuery("SELECT * FROM detection WHERE id > :id ORDER BY id LIMIT :limit")
@RegisterBeanMapper(Detection.class)
List getSinceId(@Bind("id") int id, @Bind("limit") int limit);
+
+
+ @SqlQuery("SELECT * FROM detection WHERE baton_id = :batonId AND timestamp >= :timestamp ORDER BY timestamp DESC LIMIT 1")
+ @RegisterBeanMapper(Detection.class)
+ Optional latestDetectionByBatonId(@Bind("batonId") int batonId, @Bind("timestamp") Timestamp timestamp);
+
+ @SqlQuery("""
+ WITH bso AS (SELECT teamid, newbatonid, timestamp AS current_timestamp, COALESCE( LEAD(timestamp) OVER (PARTITION BY teamid ORDER BY timestamp), timestamp + INTERVAL '1 year') AS next_baton_switch FROM batonswitchover)
+ SELECT baton_id, station_id, rssi, timestamp, teamid FROM detection d LEFT JOIN bso ON d.baton_id = bso.newbatonid AND d.timestamp BETWEEN bso.current_timestamp AND bso.next_baton_switch WHERE rssi > :minRssi
+ """)
+ @RegisterBeanMapper(Detection.class)
+ List getAllWithTeamId(@Bind("minRssi") int minRssi);
}
diff --git a/src/main/java/telraam/database/daos/LapDAO.java b/src/main/java/telraam/database/daos/LapDAO.java
index ce98a1d..8afd163 100644
--- a/src/main/java/telraam/database/daos/LapDAO.java
+++ b/src/main/java/telraam/database/daos/LapDAO.java
@@ -3,13 +3,13 @@
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.customizer.Bind;
import org.jdbi.v3.sqlobject.customizer.BindBean;
-import org.jdbi.v3.sqlobject.customizer.BindBeanList;
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
import org.jdbi.v3.sqlobject.statement.SqlBatch;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import telraam.database.models.Lap;
-
+import telraam.database.models.LapCount;
+import telraam.database.models.TeamLapCount;
import java.sql.Timestamp;
import java.util.Iterator;
@@ -26,6 +26,18 @@ public interface LapDAO extends DAO {
@RegisterBeanMapper(Lap.class)
List getAllBySource(@Bind("lapSourceId") Integer lapSourceId);
+ @SqlQuery("SELECT * FROM lap WHERE lap_source_id = :lapSourceId ORDER BY timestamp ASC")
+ @RegisterBeanMapper(Lap.class)
+ List getAllBySourceSorted(@Bind("lapSourceId") Integer lapSourceId);
+
+ @SqlQuery("SELECT t.id as team_id, (SELECT COUNT(*) FROM lap WHERE lap_source_id = :lapSourceId AND timestamp <= :timestamp and team_id = t.id) as count FROM team t")
+ @RegisterBeanMapper(LapCount.class)
+ List getAllBeforeTime(@Bind("lapSourceId") Integer lapSourceId, @Bind("timestamp") Timestamp timestamp);
+
+ @SqlQuery("SELECT t.id as team_id, (SELECT COUNT(*) FROM lap WHERE lap_source_id = :lapSourceId AND timestamp <= :timestamp and team_id = t.id) as count FROM team t where id = :teamId")
+ @RegisterBeanMapper(LapCount.class)
+ LapCount getAllForTeamBeforeTime(@Bind("lapSourceId") Integer lapSourceId, @Bind("teamId") Integer teamId, @Bind("timestamp") Timestamp timestamp);
+
@SqlUpdate("INSERT INTO lap (team_id, lap_source_id, timestamp) " +
"VALUES (:teamId, :lapSourceId, :timestamp)")
@GetGeneratedKeys({"id"})
@@ -54,6 +66,19 @@ public interface LapDAO extends DAO {
@SqlUpdate("DELETE FROM lap WHERE lap_source_id = :lapSourceId")
void deleteByLapSourceId(@Bind("lapSourceId") int lapSourceId);
+ @SqlBatch("DELETE FROM lap WHERE id = :id")
+ void deleteAllById(@BindBean Iterator laps);
+
@SqlBatch("INSERT INTO lap (team_id, lap_source_id, timestamp) VALUES (:teamId, :lapSourceId, :timestamp)")
void insertAll(@BindBean Iterator laps);
+
+ @SqlBatch("UPDATE lap SET timestamp = :timestamp WHERE id = :id")
+ void updateAll(@BindBean Iterator laps);
+
+ @SqlBatch("DELETE FROM lap WHERE id = :id")
+ void deleteAll(@BindBean Iterator laps);
+
+ @SqlQuery("SELECT COUNT(*) as lapCount, lap_source_id FROM lap WHERE team_id = :teamId GROUP BY lap_source_id")
+ @RegisterBeanMapper(TeamLapCount.class)
+ List getAllBySourceAndTeam(@Bind("teamId") int teamId);
}
diff --git a/src/main/java/telraam/database/daos/PositionSourceDAO.java b/src/main/java/telraam/database/daos/PositionSourceDAO.java
new file mode 100644
index 0000000..36f172f
--- /dev/null
+++ b/src/main/java/telraam/database/daos/PositionSourceDAO.java
@@ -0,0 +1,27 @@
+package telraam.database.daos;
+
+import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
+import org.jdbi.v3.sqlobject.customizer.Bind;
+import org.jdbi.v3.sqlobject.customizer.BindBean;
+import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
+import org.jdbi.v3.sqlobject.statement.SqlQuery;
+import org.jdbi.v3.sqlobject.statement.SqlUpdate;
+import telraam.database.models.PositionSource;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface PositionSourceDAO extends DAO {
+ @Override
+ @SqlQuery("SELECT * FROM position_source")
+ @RegisterBeanMapper(PositionSource.class)
+ List getAll();
+
+ @SqlUpdate("INSERT INTO position_source (name) VALUES (:name)")
+ @GetGeneratedKeys({"id"})
+ int insert(@BindBean PositionSource positionSource);
+
+ @SqlQuery("SELECT * FROM position_source WHERE name = :name")
+ @RegisterBeanMapper(PositionSource.class)
+ Optional getByName(@Bind("name") String name);
+}
diff --git a/src/main/java/telraam/database/daos/StationDAO.java b/src/main/java/telraam/database/daos/StationDAO.java
index cd73051..983eecf 100644
--- a/src/main/java/telraam/database/daos/StationDAO.java
+++ b/src/main/java/telraam/database/daos/StationDAO.java
@@ -19,7 +19,7 @@ public interface StationDAO extends DAO {
List getAll();
@Override
- @SqlUpdate("INSERT INTO station (name, distance_from_start, broken, url, coord_x, coord_y) VALUES (:name, :distanceFromStart, :isBroken, :url, :coordX, :coordY)")
+ @SqlUpdate("INSERT INTO station (name, distance_from_start, broken, url, coord_x, coord_y) VALUES (:name, :distanceFromStart, :broken, :url, :coordX, :coordY)")
@GetGeneratedKeys({"id"})
int insert(@BindBean Station station);
@@ -33,6 +33,6 @@ public interface StationDAO extends DAO {
int deleteById(@Bind("id") int id);
@Override
- @SqlUpdate("UPDATE station SET name = :name, distance_from_start = :distanceFromStart, broken = :isBroken, url = :url, coord_x = :coordX, coord_y = :coordY WHERE id = :id")
+ @SqlUpdate("UPDATE station SET name = :name, distance_from_start = :distanceFromStart, broken = :broken, url = :url, coord_x = :coordX, coord_y = :coordY WHERE id = :id")
int update(@Bind("id") int id, @BindBean Station station);
}
diff --git a/src/main/java/telraam/database/daos/TeamDAO.java b/src/main/java/telraam/database/daos/TeamDAO.java
index e983c57..a251884 100644
--- a/src/main/java/telraam/database/daos/TeamDAO.java
+++ b/src/main/java/telraam/database/daos/TeamDAO.java
@@ -14,17 +14,17 @@
public interface TeamDAO extends DAO {
@Override
- @SqlQuery("SELECT * FROM team")
+ @SqlQuery("SELECT t.*, tb.baton_id FROM team t LEFT JOIN team_baton_ids tb ON tb.team_id = t.id")
@RegisterBeanMapper(Team.class)
List getAll();
@Override
- @SqlUpdate("INSERT INTO team (name, baton_id) VALUES (:name, :batonId)")
+ @SqlUpdate("INSERT INTO team (name, jacket_nr) VALUES (:name, :jacketNr)")
@GetGeneratedKeys({"id"})
int insert(@BindBean Team team);
@Override
- @SqlQuery("SELECT * FROM team WHERE id = :id")
+ @SqlQuery("SELECT t.*, tb.baton_id FROM team t LEFT JOIN team_baton_ids tb ON tb.team_id = t.id WHERE t.id = :id")
@RegisterBeanMapper(Team.class)
Optional getById(@Bind("id") int id);
@@ -33,9 +33,6 @@ public interface TeamDAO extends DAO {
int deleteById(@Bind("id") int id);
@Override
- @SqlUpdate("UPDATE team SET " +
- "name = :name," +
- "baton_id = :batonId " +
- "WHERE id = :id")
+ @SqlUpdate("UPDATE team SET name = :name, jacket_nr = :jacketNr WHERE id = :id")
int update(@Bind("id") int id, @BindBean Team modelObj);
}
diff --git a/src/main/java/telraam/database/models/Baton.java b/src/main/java/telraam/database/models/Baton.java
index 525b95b..f5889c0 100644
--- a/src/main/java/telraam/database/models/Baton.java
+++ b/src/main/java/telraam/database/models/Baton.java
@@ -1,16 +1,17 @@
package telraam.database.models;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
import java.util.Objects;
+@Getter @Setter @NoArgsConstructor
public class Baton {
private Integer id;
private String name;
private String mac;
- // DO NOT REMOVE
- public Baton() {
- }
-
public Baton(String name) {
this.name = name;
}
@@ -20,30 +21,6 @@ public Baton(String name, String mac) {
this.mac = mac;
}
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getMac() {
- return mac;
- }
-
- public void setMac(String mac) {
- this.mac = mac;
- }
-
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/src/main/java/telraam/database/models/BatonSwitchover.java b/src/main/java/telraam/database/models/BatonSwitchover.java
index 67a024a..d888870 100644
--- a/src/main/java/telraam/database/models/BatonSwitchover.java
+++ b/src/main/java/telraam/database/models/BatonSwitchover.java
@@ -1,8 +1,13 @@
package telraam.database.models;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
import java.sql.Timestamp;
import java.util.Objects;
+@Getter @Setter @NoArgsConstructor
public class BatonSwitchover {
private Integer id;
private Integer teamId;
@@ -10,9 +15,6 @@ public class BatonSwitchover {
private Integer newBatonId;
private Timestamp timestamp;
- // DO NOT REMOVE
- public BatonSwitchover() {}
-
public BatonSwitchover(Integer teamId, Integer previousBatonId, Integer newBatonId, Timestamp timestamp) {
this.teamId = teamId;
this.previousBatonId = previousBatonId;
@@ -20,46 +22,6 @@ public BatonSwitchover(Integer teamId, Integer previousBatonId, Integer newBaton
this.timestamp = timestamp;
}
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public Integer getTeamId() {
- return teamId;
- }
-
- public void setTeamId(Integer teamId) {
- this.teamId = teamId;
- }
-
- public Integer getPreviousBatonId() {
- return previousBatonId;
- }
-
- public void setPreviousBatonId(Integer previousBatonId) {
- this.previousBatonId = previousBatonId;
- }
-
- public Integer getNewBatonId() {
- return newBatonId;
- }
-
- public void setNewBatonId(Integer newBatonId) {
- this.newBatonId = newBatonId;
- }
-
- public Timestamp getTimestamp() {
- return timestamp;
- }
-
- public void setTimestamp(Timestamp timestamp) {
- this.timestamp = timestamp;
- }
-
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/src/main/java/telraam/database/models/Detection.java b/src/main/java/telraam/database/models/Detection.java
index 410167e..c00264b 100644
--- a/src/main/java/telraam/database/models/Detection.java
+++ b/src/main/java/telraam/database/models/Detection.java
@@ -1,7 +1,14 @@
package telraam.database.models;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
import java.sql.Timestamp;
+@Setter
+@Getter
+@NoArgsConstructor
public class Detection {
private Integer id;
private Integer batonId;
@@ -12,9 +19,7 @@ public class Detection {
private Integer remoteId;
private Timestamp timestamp;
private Timestamp timestampIngestion;
-
- public Detection() {
- }
+ private Integer teamId;
public Detection(Integer batonId, Integer stationId, Integer rssi, Float battery, Long uptimeMs, Integer remoteId, Timestamp timestamp, Timestamp timestampIngestion) {
this.batonId = batonId;
@@ -27,75 +32,16 @@ public Detection(Integer batonId, Integer stationId, Integer rssi, Float battery
this.timestampIngestion = timestampIngestion;
}
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
+ public Detection(Integer id, Integer stationId, Integer rssi) {
this.id = id;
- }
-
- public Integer getBatonId() {
- return batonId;
- }
-
- public void setBatonId(Integer batonId) {
- this.batonId = batonId;
- }
-
- public Integer getStationId() {
- return stationId;
- }
-
- public void setStationId(Integer stationId) {
this.stationId = stationId;
- }
-
- public Integer getRssi() {
- return rssi;
- }
-
- public void setRssi(Integer rssi) {
this.rssi = rssi;
}
- public Float getBattery() {
- return battery;
- }
-
- public void setBattery(Float battery) {
- this.battery = battery;
- }
-
- public Long getUptimeMs() {
- return uptimeMs;
- }
-
- public void setUptimeMs(Long uptimeMs) {
- this.uptimeMs = uptimeMs;
- }
-
- public Integer getRemoteId() {
- return remoteId;
- }
-
- public void setRemoteId(Integer remoteId) {
- this.remoteId = remoteId;
- }
-
- public Timestamp getTimestamp() {
- return timestamp;
- }
-
- public void setTimestamp(Timestamp timestamp) {
+ public Detection(Integer id, Integer stationId, Integer rssi, Timestamp timestamp) {
+ this.id = id;
+ this.stationId = stationId;
+ this.rssi = rssi;
this.timestamp = timestamp;
}
-
- public Timestamp getTimestampIngestion() {
- return timestampIngestion;
- }
-
- public void setTimestampIngestion(Timestamp timestampIngestion) {
- this.timestampIngestion = timestampIngestion;
- }
}
diff --git a/src/main/java/telraam/database/models/Id.java b/src/main/java/telraam/database/models/Id.java
deleted file mode 100644
index 97132af..0000000
--- a/src/main/java/telraam/database/models/Id.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package telraam.database.models;
-
-public class Id {
-
- private int id;
-
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = id;
- }
-
- @Override
- public String toString() {
- return String.format("Id: %d", id);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/telraam/database/models/Lap.java b/src/main/java/telraam/database/models/Lap.java
index cf45139..7573562 100644
--- a/src/main/java/telraam/database/models/Lap.java
+++ b/src/main/java/telraam/database/models/Lap.java
@@ -1,52 +1,23 @@
package telraam.database.models;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
import java.sql.Timestamp;
+@Getter @Setter @NoArgsConstructor
public class Lap {
private Integer id;
private Integer teamId;
private Integer lapSourceId;
+
private Boolean manual;
private Timestamp timestamp;
- public Lap() {
- }
-
public Lap(Integer teamId, Integer lapSourceId, Timestamp timestamp) {
this.teamId = teamId;
this.lapSourceId = lapSourceId;
this.timestamp = timestamp;
}
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public Integer getTeamId() {
- return teamId;
- }
-
- public void setTeamId(Integer teamId) {
- this.teamId = teamId;
- }
-
- public Integer getLapSourceId() {
- return lapSourceId;
- }
-
- public void setLapSourceId(Integer lapSourceId) {
- this.lapSourceId = lapSourceId;
- }
-
- public Timestamp getTimestamp() {
- return timestamp;
- }
-
- public void setTimestamp(Timestamp timestamp) {
- this.timestamp = timestamp;
- }
}
diff --git a/src/main/java/telraam/database/models/LapCount.java b/src/main/java/telraam/database/models/LapCount.java
new file mode 100644
index 0000000..a3831a5
--- /dev/null
+++ b/src/main/java/telraam/database/models/LapCount.java
@@ -0,0 +1,11 @@
+package telraam.database.models;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter @Setter @NoArgsConstructor
+public class LapCount {
+ private int teamId;
+ private int count;
+}
diff --git a/src/main/java/telraam/database/models/LapSource.java b/src/main/java/telraam/database/models/LapSource.java
index 82ff02f..aa39fa3 100644
--- a/src/main/java/telraam/database/models/LapSource.java
+++ b/src/main/java/telraam/database/models/LapSource.java
@@ -1,33 +1,18 @@
package telraam.database.models;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
/**
* The lap source tells you where the lap comes from.
*/
+@Getter @Setter @NoArgsConstructor
public class LapSource {
private Integer id;
private String name;
- public LapSource() {
-
- }
-
public LapSource(String name) {
this.name = name;
}
-
- public Integer getId() {
- return id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public void setName(String name) {
- this.name = name;
- }
}
diff --git a/src/main/java/telraam/database/models/LapSourceSwitchover.java b/src/main/java/telraam/database/models/LapSourceSwitchover.java
index 6d645ca..4b3a445 100644
--- a/src/main/java/telraam/database/models/LapSourceSwitchover.java
+++ b/src/main/java/telraam/database/models/LapSourceSwitchover.java
@@ -1,45 +1,23 @@
package telraam.database.models;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
import java.sql.Timestamp;
import java.util.Objects;
+@Getter @Setter @NoArgsConstructor
public class LapSourceSwitchover {
private Integer id;
private Integer newLapSource;
private Timestamp timestamp;
- // DO NOT REMOVE
- public LapSourceSwitchover() {}
-
public LapSourceSwitchover(Integer newLapSource, Timestamp timestamp) {
this.newLapSource = newLapSource;
this.timestamp = timestamp;
}
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public Integer getNewLapSource() {
- return newLapSource;
- }
-
- public void setNewLapSource(Integer newLapSource) {
- this.newLapSource = newLapSource;
- }
-
- public Timestamp getTimestamp() {
- return timestamp;
- }
-
- public void setTimestamp(Timestamp timestamp) {
- this.timestamp = timestamp;
- }
-
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/src/main/java/telraam/database/models/PositionSource.java b/src/main/java/telraam/database/models/PositionSource.java
new file mode 100644
index 0000000..19d2fd1
--- /dev/null
+++ b/src/main/java/telraam/database/models/PositionSource.java
@@ -0,0 +1,17 @@
+package telraam.database.models;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class PositionSource {
+ private Integer id;
+ private String name;
+
+ public PositionSource(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/telraam/database/models/Station.java b/src/main/java/telraam/database/models/Station.java
index 4439b83..b1f1220 100644
--- a/src/main/java/telraam/database/models/Station.java
+++ b/src/main/java/telraam/database/models/Station.java
@@ -1,83 +1,42 @@
package telraam.database.models;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter @Setter
public class Station {
private Integer id;
private String name;
private Double distanceFromStart;
- private Boolean isBroken;
+ @Getter @Setter
+ private Boolean broken;
private String url;
private Double coordX;
private Double coordY;
public Station() {
- this.isBroken = false;
+ this.broken = false;
}
public Station(String name, String url) {
this.name = name;
- this.isBroken = false;
+ this.broken = false;
this.url = url;
}
public Station(String name, Double distanceFromStart, String url) {
this.name = name;
- this.isBroken = false;
+ this.broken = false;
this.distanceFromStart = distanceFromStart;
this.url = url;
}
public Station(String name, boolean isBroken) {
this.name = name;
- this.isBroken = isBroken;
- }
-
- public Integer getId() {
- return id;
+ this.broken = isBroken;
}
- public void setId(Integer id) {
+ public Station(Integer id) {
this.id = id;
}
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public Double getDistanceFromStart() {
- return distanceFromStart;
- }
-
- public void setDistanceFromStart(Double distanceFromStart) {
- this.distanceFromStart = distanceFromStart;
- }
-
- public Boolean getIsBroken() {
- return isBroken;
- }
-
- public void setBroken(Boolean isBroken) { this.isBroken = isBroken; }
-
- public String getUrl() {
- return this.url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- public Double getCoordX() { return this.coordX; };
-
- public void setCoordX(Double coordX) {
- this.coordX = coordX;
- }
-
- public Double getCoordY() { return this.coordY; }
-
- public void setCoordY(Double coordY) {
- this.coordY = coordY;
- }
}
diff --git a/src/main/java/telraam/database/models/Team.java b/src/main/java/telraam/database/models/Team.java
index 1713d93..317b2ed 100644
--- a/src/main/java/telraam/database/models/Team.java
+++ b/src/main/java/telraam/database/models/Team.java
@@ -1,14 +1,19 @@
package telraam.database.models;
-import telraam.database.daos.BatonSwitchoverDAO;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import java.util.Objects;
+
+@Getter
+@Setter
+@NoArgsConstructor
public class Team {
private Integer id;
private String name;
private Integer batonId;
-
- public Team() {
- }
+ private String jacketNr = "INVALID";
public Team(String name) {
this.name = name;
@@ -19,27 +24,7 @@ public Team(String name, int batonId) {
this.batonId = batonId;
}
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public Integer getBatonId() {
- return batonId;
- }
-
- public void setBatonId(Integer batonId) {
- this.batonId = batonId;
+ public boolean equals(Team obj) {
+ return Objects.equals(id, obj.getId());
}
}
diff --git a/src/main/java/telraam/database/models/TeamLapCount.java b/src/main/java/telraam/database/models/TeamLapCount.java
new file mode 100644
index 0000000..797c659
--- /dev/null
+++ b/src/main/java/telraam/database/models/TeamLapCount.java
@@ -0,0 +1,12 @@
+package telraam.database.models;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter @Setter @NoArgsConstructor @AllArgsConstructor
+public class TeamLapCount {
+ private Integer lapSourceId;
+ private Integer lapCount;
+}
diff --git a/src/main/java/telraam/logic/external/ExternalLapper.java b/src/main/java/telraam/logic/external/ExternalLapper.java
deleted file mode 100644
index f82d55d..0000000
--- a/src/main/java/telraam/logic/external/ExternalLapper.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package telraam.logic.external;
-
-import io.dropwizard.jersey.setup.JerseyEnvironment;
-import org.jdbi.v3.core.Jdbi;
-import telraam.database.daos.LapDAO;
-import telraam.database.daos.LapSourceDAO;
-import telraam.database.models.Detection;
-import telraam.database.models.Lap;
-import telraam.database.models.LapSource;
-import telraam.logic.Lapper;
-
-import java.sql.Timestamp;
-import java.util.LinkedList;
-import java.util.List;
-
-public class ExternalLapper implements Lapper {
-
- static final String SOURCE_NAME = "external-lapper";
- private final LapDAO lapDAO;
- private int lapSourceId;
-
- public ExternalLapper(Jdbi jdbi) {
- this.lapDAO = jdbi.onDemand(LapDAO.class);
-
- // Get the lapSourceId, create the source if needed
- LapSourceDAO lapSourceDAO = jdbi.onDemand(LapSourceDAO.class);
- lapSourceDAO.getByName(SOURCE_NAME).ifPresentOrElse(
- lapSource -> this.lapSourceId = lapSource.getId(),
- () -> this.lapSourceId = lapSourceDAO.insert(new LapSource(SOURCE_NAME))
- );
- }
-
- @Override
- public void handle(Detection msg) {
- // Do nothing here. The external lappers polls periodically using the general api.
- }
-
- public void saveLaps(List teamLaps) {
- //TODO: Be less destructive on the database: Only delete and add the required laps.
- lapDAO.deleteByLapSourceId(this.lapSourceId);
-
- LinkedList laps = new LinkedList<>();
-
- for (ExternalLapperTeamLaps teamLap : teamLaps) {
- for (ExternalLapperLap lap : teamLap.laps) {
- laps.add(new Lap(teamLap.teamId, this.lapSourceId, new Timestamp((long) (lap.timestamp))));
- }
- }
-
- lapDAO.insertAll(laps.iterator());
- }
-
- @Override
- public void registerAPI(JerseyEnvironment jersey) {
- jersey.register(new ExternalLapperResource(this));
- }
-}
diff --git a/src/main/java/telraam/logic/external/ExternalLapperLap.java b/src/main/java/telraam/logic/external/ExternalLapperLap.java
deleted file mode 100644
index d694994..0000000
--- a/src/main/java/telraam/logic/external/ExternalLapperLap.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package telraam.logic.external;
-
-public class ExternalLapperLap {
- public double timestamp;
-}
diff --git a/src/main/java/telraam/logic/external/ExternalLapperResource.java b/src/main/java/telraam/logic/external/ExternalLapperResource.java
deleted file mode 100644
index add3ceb..0000000
--- a/src/main/java/telraam/logic/external/ExternalLapperResource.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package telraam.logic.external;
-
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.util.List;
-
-
-@Path("/lappers/external")
-@Api("/lappers/external")
-@Produces(MediaType.APPLICATION_JSON)
-public class ExternalLapperResource {
- private final ExternalLapper lapper;
-
- public ExternalLapperResource(ExternalLapper lapper) {
- this.lapper = lapper;
- }
-
- @POST
- @Path("/laps")
- @ApiOperation(value = "Post the current laps")
- public void postLaps(List teamLaps) {
- this.lapper.saveLaps(teamLaps);
- }
-
- //TODO: Give the lapper an option to publish some of its internal state for debugging.
- //@GET
- //@Path("/stats")
- //@ApiOperation(value = "Get lapper statistics")
- //public Map> getStats() {
- // //return this.lapper.getLapCounts();
- //}
-//
- //@POST
- //@Path("/stats")
- //@ApiOperation(value = "Post lapper statistics")
- //public Map> postStats() {
- // return this.lapper.getLapCounts();
- //}
-}
-
diff --git a/src/main/java/telraam/logic/external/ExternalLapperStats.java b/src/main/java/telraam/logic/external/ExternalLapperStats.java
deleted file mode 100644
index c285729..0000000
--- a/src/main/java/telraam/logic/external/ExternalLapperStats.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package telraam.logic.external;
-
-public class ExternalLapperStats {
-}
diff --git a/src/main/java/telraam/logic/external/ExternalLapperTeamLaps.java b/src/main/java/telraam/logic/external/ExternalLapperTeamLaps.java
deleted file mode 100644
index a003f3f..0000000
--- a/src/main/java/telraam/logic/external/ExternalLapperTeamLaps.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package telraam.logic.external;
-
-import java.util.List;
-
-public class ExternalLapperTeamLaps {
- public int teamId;
- public List laps;
-}
diff --git a/src/main/java/telraam/logic/Lapper.java b/src/main/java/telraam/logic/lapper/Lapper.java
similarity index 86%
rename from src/main/java/telraam/logic/Lapper.java
rename to src/main/java/telraam/logic/lapper/Lapper.java
index 995d067..d999307 100644
--- a/src/main/java/telraam/logic/Lapper.java
+++ b/src/main/java/telraam/logic/lapper/Lapper.java
@@ -1,9 +1,10 @@
-package telraam.logic;
+package telraam.logic.lapper;
import io.dropwizard.jersey.setup.JerseyEnvironment;
import telraam.database.models.Detection;
public interface Lapper {
void handle(Detection msg);
+
void registerAPI(JerseyEnvironment jersey);
}
diff --git a/src/main/java/telraam/logic/lapper/external/ExternalLapper.java b/src/main/java/telraam/logic/lapper/external/ExternalLapper.java
new file mode 100644
index 0000000..510e28a
--- /dev/null
+++ b/src/main/java/telraam/logic/lapper/external/ExternalLapper.java
@@ -0,0 +1,87 @@
+package telraam.logic.lapper.external;
+
+import io.dropwizard.jersey.setup.JerseyEnvironment;
+import org.jdbi.v3.core.Jdbi;
+import telraam.database.daos.LapDAO;
+import telraam.database.daos.LapSourceDAO;
+import telraam.database.models.Detection;
+import telraam.database.models.Lap;
+import telraam.database.models.LapSource;
+import telraam.logic.lapper.Lapper;
+import telraam.logic.lapper.external.models.ExternalLapperTeamLaps;
+
+import java.sql.Timestamp;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+
+public class ExternalLapper implements Lapper {
+
+ static final String SOURCE_NAME = "external-lapper";
+ private final LapDAO lapDAO;
+ private int lapSourceId;
+
+ public ExternalLapper(Jdbi jdbi) {
+ this.lapDAO = jdbi.onDemand(LapDAO.class);
+
+ // Get the lapSourceId, create the source if needed
+ LapSourceDAO lapSourceDAO = jdbi.onDemand(LapSourceDAO.class);
+ lapSourceDAO.getByName(SOURCE_NAME).ifPresentOrElse(
+ lapSource -> this.lapSourceId = lapSource.getId(),
+ () -> this.lapSourceId = lapSourceDAO.insert(new LapSource(SOURCE_NAME))
+ );
+ }
+
+ @Override
+ public void handle(Detection msg) {
+ // Do nothing here. The external lappers polls periodically using the general api.
+ }
+
+ public void saveLaps(List teamLaps) {
+ List laps = lapDAO.getAllBySource(lapSourceId).stream().filter(l -> !l.getManual()).toList();
+
+ // Remember laps we have to take actions on
+ List lapsToDelete = new LinkedList<>();
+ List lapsToAdd = new LinkedList<>();
+
+ // Find which laps are no longer needed or have to be added
+ for (ExternalLapperTeamLaps teamLap : teamLaps) {
+ List lapsForTeam = laps.stream().filter(l -> l.getTeamId() == teamLap.getTeamId()).sorted(Comparator.comparing(Lap::getTimestamp)).toList();
+ List newLapsForTeam = teamLap.getLaps().stream().map(nl -> new Lap(teamLap.getTeamId(), lapSourceId, new Timestamp((long) (nl.getTimestamp())))).sorted(Comparator.comparing(Lap::getTimestamp)).toList();
+
+ int lapsIndex = 0;
+ int newLapsIndex = 0;
+ while (lapsIndex != lapsForTeam.size() || newLapsIndex != newLapsForTeam.size()) {
+ if (lapsIndex != lapsForTeam.size() && newLapsIndex != newLapsForTeam.size()) {
+ Lap lap = lapsForTeam.get(lapsIndex);
+ Lap newLap = newLapsForTeam.get(newLapsIndex);
+ if (lap.getTimestamp().before(newLap.getTimestamp())) {
+ lapsToDelete.add(lap);
+ lapsIndex++;
+ } else if (lap.getTimestamp().after(newLap.getTimestamp())) {
+ lapsToAdd.add(newLap);
+ newLapsIndex++;
+ } else { // Lap is present in both lists. Keep it.
+ lapsIndex++;
+ newLapsIndex++;
+ }
+ } else if (lapsIndex != lapsForTeam.size()) {
+ lapsToDelete.add(lapsForTeam.get(lapsIndex));
+ lapsIndex++;
+ } else {
+ lapsToAdd.add(newLapsForTeam.get(newLapsIndex));
+ newLapsIndex++;
+ }
+ }
+ }
+
+ // Do the required actions
+ lapDAO.deleteAllById(lapsToDelete.iterator());
+ lapDAO.insertAll(lapsToAdd.iterator());
+ }
+
+ @Override
+ public void registerAPI(JerseyEnvironment jersey) {
+ jersey.register(new ExternalLapperResource(this));
+ }
+}
diff --git a/src/main/java/telraam/logic/lapper/external/ExternalLapperResource.java b/src/main/java/telraam/logic/lapper/external/ExternalLapperResource.java
new file mode 100644
index 0000000..55f6aa0
--- /dev/null
+++ b/src/main/java/telraam/logic/lapper/external/ExternalLapperResource.java
@@ -0,0 +1,45 @@
+package telraam.logic.lapper.external;
+
+import io.swagger.v3.oas.annotations.Operation;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+import telraam.logic.lapper.external.models.ExternalLapperStats;
+import telraam.logic.lapper.external.models.ExternalLapperTeamLaps;
+
+import java.util.List;
+
+
+@Path("/lappers/external")
+@Produces(MediaType.APPLICATION_JSON)
+public class ExternalLapperResource {
+ private final ExternalLapper lapper;
+
+ private ExternalLapperStats externalLapperStats;
+
+ public ExternalLapperResource(ExternalLapper lapper) {
+ this.lapper = lapper;
+ this.externalLapperStats = new ExternalLapperStats();
+ }
+
+ @POST
+ @Path("/laps")
+ @Operation(summary = "Post the current laps")
+ public void postLaps(List teamLaps) {
+ this.lapper.saveLaps(teamLaps);
+ }
+
+ @GET
+ @Path("/stats")
+ @Operation(summary = "Get lapper statistics")
+ public ExternalLapperStats getStats() {
+ return externalLapperStats;
+ }
+
+ @POST
+ @Path("/stats")
+ @Operation(summary = "Post lapper statistics")
+ public void postStats(ExternalLapperStats externalLapperStats) {
+ this.externalLapperStats = externalLapperStats;
+ }
+}
+
diff --git a/src/main/java/telraam/logic/lapper/external/models/ExternalLapperLap.java b/src/main/java/telraam/logic/lapper/external/models/ExternalLapperLap.java
new file mode 100644
index 0000000..3623891
--- /dev/null
+++ b/src/main/java/telraam/logic/lapper/external/models/ExternalLapperLap.java
@@ -0,0 +1,9 @@
+package telraam.logic.lapper.external.models;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter @Setter
+public class ExternalLapperLap {
+ private double timestamp;
+}
diff --git a/src/main/java/telraam/logic/lapper/external/models/ExternalLapperStats.java b/src/main/java/telraam/logic/lapper/external/models/ExternalLapperStats.java
new file mode 100644
index 0000000..8c875bc
--- /dev/null
+++ b/src/main/java/telraam/logic/lapper/external/models/ExternalLapperStats.java
@@ -0,0 +1,13 @@
+package telraam.logic.lapper.external.models;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Setter @Getter
+public class ExternalLapperStats {
+ private List errorHistory;
+ private List> transitionMatrix;
+ private List> emissionMatrix;
+}
diff --git a/src/main/java/telraam/logic/lapper/external/models/ExternalLapperTeamLaps.java b/src/main/java/telraam/logic/lapper/external/models/ExternalLapperTeamLaps.java
new file mode 100644
index 0000000..fa37f63
--- /dev/null
+++ b/src/main/java/telraam/logic/lapper/external/models/ExternalLapperTeamLaps.java
@@ -0,0 +1,13 @@
+package telraam.logic.lapper.external.models;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+
+@Getter @Setter
+public class ExternalLapperTeamLaps {
+ private int teamId;
+ private List laps;
+}
diff --git a/src/main/java/telraam/logic/robustLapper/RobustLapper.java b/src/main/java/telraam/logic/lapper/robust/RobustLapper.java
similarity index 56%
rename from src/main/java/telraam/logic/robustLapper/RobustLapper.java
rename to src/main/java/telraam/logic/lapper/robust/RobustLapper.java
index 6774299..62ae807 100644
--- a/src/main/java/telraam/logic/robustLapper/RobustLapper.java
+++ b/src/main/java/telraam/logic/lapper/robust/RobustLapper.java
@@ -1,11 +1,16 @@
-package telraam.logic.robustLapper;
+package telraam.logic.lapper.robust;
import io.dropwizard.jersey.setup.JerseyEnvironment;
import org.jdbi.v3.core.Jdbi;
-import telraam.database.daos.*;
-import telraam.database.models.*;
-import telraam.logic.Lapper;
-import telraam.logic.viterbi.ViterbiLapper;
+import telraam.database.daos.DetectionDAO;
+import telraam.database.daos.LapDAO;
+import telraam.database.daos.LapSourceDAO;
+import telraam.database.daos.StationDAO;
+import telraam.database.models.Detection;
+import telraam.database.models.Lap;
+import telraam.database.models.LapSource;
+import telraam.database.models.Station;
+import telraam.logic.lapper.Lapper;
import java.sql.Timestamp;
import java.util.*;
@@ -13,7 +18,6 @@
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
-import java.util.stream.Collectors;
// Implement Lapper for easier use in App and Fetcher
public class RobustLapper implements Lapper {
@@ -30,14 +34,13 @@ public class RobustLapper implements Lapper {
private boolean debounceScheduled;
private int lapSourceId;
private Map> teamDetections;
- private List teams;
private List stations;
- private Map> teamLaps;
+ private Map> teamLaps;
public RobustLapper(Jdbi jdbi) {
this.jdbi = jdbi;
this.scheduler = Executors.newScheduledThreadPool(1);
- this.logger = Logger.getLogger(ViterbiLapper.class.getName());
+ this.logger = Logger.getLogger(RobustLapper.class.getName());
this.lapDAO = jdbi.onDemand(LapDAO.class);
this.debounceScheduled = false;
@@ -49,47 +52,32 @@ public RobustLapper(Jdbi jdbi) {
);
}
+ // Group all detections by time and keep only one detection per timestamp
private void processData() {
- // Maps a baton id to the current team using it
- Map batonTeam = new HashMap<>();
- // Map containing all detections belonging to a team
- teamDetections = new HashMap<>();
-
- TeamDAO teamDAO = this.jdbi.onDemand(TeamDAO.class);
DetectionDAO detectionDAO = this.jdbi.onDemand(DetectionDAO.class);
- BatonSwitchoverDAO batonSwitchoverDAO = this.jdbi.onDemand(BatonSwitchoverDAO.class);
-
- teams = teamDAO.getAll();
- List detections = detectionDAO.getAll();
- List switchovers = batonSwitchoverDAO.getAll();
-
- switchovers.sort(Comparator.comparing(BatonSwitchover::getTimestamp));
+ List detections = detectionDAO.getAllWithTeamId(MIN_RSSI);
detections.sort(Comparator.comparing(Detection::getTimestamp));
+ teamDetections = new HashMap<>();
- Map teamById = teams.stream().collect(Collectors.toMap(Team::getId, team -> team));
- teams.forEach(team -> teamDetections.put(team.getId(), new ArrayList<>()));
-
- int switchoverIndex = 0;
for (Detection detection : detections) {
- // Switch teams batons if it happened before the current detection
- while (switchoverIndex < switchovers.size() && switchovers.get(switchoverIndex).getTimestamp().before(detection.getTimestamp())) {
- BatonSwitchover switchover = switchovers.get(switchoverIndex);
- batonTeam.put(switchover.getNewBatonId(), teamById.get(switchover.getTeamId()));
- batonTeam.remove(switchover.getPreviousBatonId());
- switchoverIndex++;
- }
-
- // Check if detection belongs to a team, and it's signal is strong enough
- if (batonTeam.containsKey(detection.getBatonId()) && detection.getRssi() > MIN_RSSI) {
- List currentDetections = teamDetections.get(batonTeam.get(detection.getBatonId()).getId());
- // If team already has a detection for that timestamp keep the one with the strongest signal
- if (! currentDetections.isEmpty() && currentDetections.get(currentDetections.size() - 1).getTimestamp().compareTo(detection.getTimestamp()) == 0) {
- if (currentDetections.get(currentDetections.size() - 1).getRssi() < detection.getRssi()) {
- currentDetections.remove(currentDetections.size() - 1);
- currentDetections.add(detection);
+ if (detection.getTeamId() != null) {
+ if (teamDetections.containsKey(detection.getTeamId())) {
+ // teamDetections already contains teamId
+ List teamDetectionsList = teamDetections.get(detection.getTeamId());
+ if (teamDetectionsList.get(teamDetectionsList.size() - 1).getTimestamp().compareTo(detection.getTimestamp()) == 0) {
+ // There's already a detection for that timestamp, keep the one with the highest rssi
+ if (teamDetectionsList.get(teamDetectionsList.size() - 1).getRssi() < detection.getRssi()) {
+ teamDetectionsList.remove(teamDetectionsList.size() - 1);
+ teamDetectionsList.add(detection);
+ }
+ } else {
+ // No detection yet for that timestamp so let's add it
+ teamDetectionsList.add(detection);
}
} else {
- currentDetections.add(detection);
+ // Team id isn't in teamDetections yet so let's add it
+ teamDetections.put(detection.getTeamId(), new ArrayList<>());
+ teamDetections.get(detection.getTeamId()).add(detection);
}
}
}
@@ -108,7 +96,7 @@ public void calculateLaps() {
// List containing station id's and sorted based on their distance from the start
List stationIdToPosition = stations.stream().map(Station::getId).toList();
- for (Team team : teams) {
+ for (Map.Entry> entry : teamDetections.entrySet()) {
List lapTimes = new ArrayList<>();
// Station that is used for current interval
@@ -117,9 +105,7 @@ public void calculateLaps() {
int currentStationRssi = MIN_RSSI;
int currentStationPosition = 0;
- List detections = teamDetections.get(team.getId());
-
- for (Detection detection : detections) {
+ for (Detection detection : entry.getValue()) {
// Group all detections based on INTERVAL_TIME
if (detection.getTimestamp().getTime() - currentStationTime < INTERVAL_TIME) {
// We're still in the same interval
@@ -132,7 +118,7 @@ public void calculateLaps() {
} else {
// We're in a new interval, use the detection with the highest RSSI to update trajectory
// Check if new station is more likely to be in front of the runner
- if (! (backwardPathDistance(lastStationPosition, currentStationPosition) <= 2)) {
+ if (!(backwardPathDistance(lastStationPosition, currentStationPosition) <= 3)) {
if (isStartBetween(lastStationPosition, currentStationPosition)) {
// Add lap if we passed the start line
lapTimes.add(detection.getTimestamp());
@@ -146,7 +132,7 @@ public void calculateLaps() {
}
}
// Save result for team
- teamLaps.put(team.getId(), lapTimes);
+ teamLaps.put(entry.getKey(), lapTimes.stream().map(time -> new Lap(entry.getKey(), lapSourceId, time)).toList());
}
save();
@@ -158,22 +144,60 @@ private int backwardPathDistance(int fromStation, int toStation) {
return (((fromStation - toStation) % stations.size()) + stations.size()) % stations.size();
}
- // Is the finish line between from_station and to_station when running forwards?
+ // Returns whether the finish line is between from_station and to_station when running forwards
private boolean isStartBetween(int fromStation, int toStation) {
return fromStation > toStation;
}
private void save() {
- lapDAO.deleteByLapSourceId(this.lapSourceId);
+ // Get all the old laps and sort by team
+ List laps = lapDAO.getAllBySource(lapSourceId);
+ laps = laps.stream().filter(lap -> !lap.getManual()).toList();
+ Map> oldLaps = new HashMap<>();
+
+ for (Integer teamId : teamLaps.keySet()) {
+ oldLaps.put(teamId, new ArrayList<>());
+ }
+
+ for (Lap lap : laps) {
+ oldLaps.get(lap.getTeamId()).add(lap);
+ }
+
+ List lapsToUpdate = new ArrayList<>();
+ List lapsToInsert = new ArrayList<>();
+ List lapsToDelete = new ArrayList<>();
+
+ for (Map.Entry> entries : teamLaps.entrySet()) {
+ List newLapsTeam = entries.getValue();
+ List oldLapsTeam = oldLaps.get(entries.getKey());
+ oldLapsTeam.sort(Comparator.comparing(Lap::getTimestamp));
+ int i = 0;
+ // Go over each lap and compare timestamp
+ while (i < oldLapsTeam.size() && i < newLapsTeam.size()) {
+ // Update the timestamp if it isn't equal
+ if (!oldLapsTeam.get(i).getTimestamp().equals(newLapsTeam.get(i).getTimestamp())) {
+ oldLapsTeam.get(i).setTimestamp(newLapsTeam.get(i).getTimestamp());
+ lapsToUpdate.add(oldLapsTeam.get(i));
+ }
+ i++;
+ }
+
+ // More old laps so delete the surplus
+ while (i < oldLapsTeam.size()) {
+ lapsToDelete.add(oldLapsTeam.get(i));
+ i++;
+ }
- LinkedList laps = new LinkedList<>();
- for (Map.Entry> entries : teamLaps.entrySet()) {
- for (Timestamp timestamp : entries.getValue()) {
- laps.add(new Lap(entries.getKey(), lapSourceId, timestamp));
+ // Add the new laps
+ while (i < newLapsTeam.size()) {
+ lapsToInsert.add(newLapsTeam.get(i));
+ i++;
}
}
- lapDAO.insertAll(laps.iterator());
+ lapDAO.updateAll(lapsToUpdate.iterator());
+ lapDAO.insertAll(lapsToInsert.iterator());
+ lapDAO.deleteAll(lapsToDelete.iterator());
}
@Override
diff --git a/src/main/java/telraam/logic/SimpleLapper.java b/src/main/java/telraam/logic/lapper/simple/SimpleLapper.java
similarity index 93%
rename from src/main/java/telraam/logic/SimpleLapper.java
rename to src/main/java/telraam/logic/lapper/simple/SimpleLapper.java
index 5ed367e..608e724 100644
--- a/src/main/java/telraam/logic/SimpleLapper.java
+++ b/src/main/java/telraam/logic/lapper/simple/SimpleLapper.java
@@ -1,10 +1,11 @@
-package telraam.logic;
+package telraam.logic.lapper.simple;
import io.dropwizard.jersey.setup.JerseyEnvironment;
import org.jdbi.v3.core.Jdbi;
import telraam.database.daos.LapDAO;
import telraam.database.daos.LapSourceDAO;
import telraam.database.models.*;
+import telraam.logic.lapper.Lapper;
import java.util.ArrayList;
import java.util.HashMap;
@@ -13,7 +14,7 @@
public class SimpleLapper implements Lapper {
// Needs to be the same as in the lap_source database table.
- static final String SOURCE_NAME = "simple-lapper";
+ public static final String SOURCE_NAME = "simple-lapper";
private static final int MAX_SPEED = 50;
private final LapSource source;
@@ -66,7 +67,8 @@ public void handle(Detection msg) {
}
@Override
- public void registerAPI(JerseyEnvironment jersey) {}
+ public void registerAPI(JerseyEnvironment jersey) {
+ }
private void generateLap(List detections) {
Detection first = detections.get(0);
diff --git a/src/main/java/telraam/logic/lapper/slapper/Slapper.java b/src/main/java/telraam/logic/lapper/slapper/Slapper.java
new file mode 100644
index 0000000..e4a34af
--- /dev/null
+++ b/src/main/java/telraam/logic/lapper/slapper/Slapper.java
@@ -0,0 +1,139 @@
+package telraam.logic.lapper.slapper;
+
+import io.dropwizard.jersey.setup.JerseyEnvironment;
+import org.jdbi.v3.core.Jdbi;
+import telraam.database.daos.LapSourceDAO;
+import telraam.database.models.Detection;
+import telraam.database.models.LapSource;
+import telraam.logic.lapper.Lapper;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Logger;
+
+// Lapper that only uses a single sql query
+public class Slapper implements Lapper {
+ private final String SOURCE_NAME = "slapper";
+ private final int DEBOUNCE_TIMEOUT = 10;
+ private final ScheduledExecutorService scheduler;
+ private boolean debounceScheduled;
+ private final Logger logger;
+ private final Jdbi jdbi;
+
+ public Slapper(Jdbi jdbi) {
+ this.jdbi = jdbi;
+ this.scheduler = Executors.newScheduledThreadPool(1);
+ this.logger = Logger.getLogger(Slapper.class.getName());
+ this.debounceScheduled = false;
+
+ // Get the lapSourceId, create the source if needed
+ LapSourceDAO lapSourceDAO = jdbi.onDemand(LapSourceDAO.class);
+ if (lapSourceDAO.getByName(SOURCE_NAME).isEmpty()) {
+ lapSourceDAO.insert(new LapSource(SOURCE_NAME));
+ }
+ }
+
+ @Override
+ public void handle(Detection msg) {
+ if (!this.debounceScheduled) {
+ this.debounceScheduled = true;
+ this.scheduler.schedule(() -> {
+ try {
+ this.calculateLaps();
+ } catch (Exception e) {
+ logger.severe(e.getMessage());
+ }
+ this.debounceScheduled = false;
+ }, DEBOUNCE_TIMEOUT, TimeUnit.SECONDS);
+ }
+ }
+
+ private void calculateLaps() {
+ logger.info("Slapper: Calculating laps...");
+ this.jdbi.useHandle(handle -> handle.execute(
+ """
+ WITH switchovers AS (
+ SELECT teamid AS team_id,
+ newbatonid,
+ timestamp AS start_timestamp,
+ COALESCE(
+ LEAD(timestamp) OVER (PARTITION BY teamid ORDER BY timestamp),
+ timestamp + INTERVAL '1 MONTH'
+ ) AS next_baton_switch
+ FROM batonswitchover
+ ),
+ team_detections AS (
+ SELECT station_id,
+ MAX(rssi) as rssi,
+ date_trunc('second', timestamp) AS timestamp_seconds,
+ team_id
+ FROM detection d
+ LEFT JOIN switchovers s ON d.baton_id = s.newbatonid
+ AND d.timestamp BETWEEN s.start_timestamp AND s.next_baton_switch
+ WHERE station_id NOT BETWEEN 3 AND 5
+ AND rssi > -84
+ AND team_id IS NOT NULL
+ GROUP BY date_trunc('second', timestamp), team_id, station_id
+ ),
+ start_times AS (
+ SELECT DISTINCT ON (team_id) team_id,
+ timestamp_seconds AS start_seconds
+ FROM team_detections
+ WHERE station_id BETWEEN 2 AND 3
+ ORDER BY team_id, timestamp_seconds
+ ),
+ new_laps AS (
+ SELECT previous.team_id,
+ timestamp_seconds
+ FROM (
+ SELECT *,
+ LAG(station_id) OVER (
+ PARTITION BY team_id
+ ORDER BY timestamp_seconds
+ ) AS prev_station_id
+ FROM team_detections
+ ) AS previous
+ LEFT JOIN start_times s_t
+ ON previous.team_id = s_t.team_id
+ WHERE station_id - prev_station_id < -4
+ AND timestamp_seconds > start_seconds
+ ),
+ cst_source_id AS (
+ SELECT COALESCE(id, -1) AS source_id
+ FROM lap_source
+ WHERE name ILIKE 'slapper'
+ ),
+ deletions AS (
+ DELETE FROM lap l
+ WHERE lap_source_id = (SELECT source_id FROM cst_source_id)
+ AND NOT EXISTS (
+ SELECT 1
+ FROM new_laps n_l
+ WHERE l.team_id = n_l.team_id
+ AND l.timestamp = n_l.timestamp_seconds
+ )
+ )
+ INSERT INTO lap (team_id, timestamp, lap_source_id)
+ SELECT team_id,
+ timestamp_seconds,
+ source_id
+ FROM new_laps n_l, cst_source_id
+ WHERE NOT EXISTS (
+ SELECT 1
+ FROM lap l, cst_source_id
+ WHERE l.lap_source_id = source_id
+ AND l.team_id = n_l.team_id
+ AND l.timestamp = n_l.timestamp_seconds
+ )
+ """
+ )
+ );
+ logger.info("Slapper: Done calculating laps");
+ }
+
+ @Override
+ public void registerAPI(JerseyEnvironment jersey) {
+
+ }
+}
diff --git a/src/main/java/telraam/logic/positioner/Position.java b/src/main/java/telraam/logic/positioner/Position.java
new file mode 100644
index 0000000..28a4e37
--- /dev/null
+++ b/src/main/java/telraam/logic/positioner/Position.java
@@ -0,0 +1,14 @@
+package telraam.logic.positioner;
+
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import lombok.Getter;
+import lombok.Setter;
+
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public record Position (
+ int teamId,
+ double progress,
+ double speed,
+ long timestamp
+) {}
diff --git a/src/main/java/telraam/logic/positioner/PositionSender.java b/src/main/java/telraam/logic/positioner/PositionSender.java
new file mode 100644
index 0000000..a111746
--- /dev/null
+++ b/src/main/java/telraam/logic/positioner/PositionSender.java
@@ -0,0 +1,28 @@
+package telraam.logic.positioner;
+
+import telraam.websocket.WebSocketMessage;
+import telraam.websocket.WebSocketMessageSingleton;
+
+import java.util.List;
+import java.util.Map;
+
+public class PositionSender {
+ private final WebSocketMessage