mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-13 22:15:26 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
b794aa579b
1251 files changed
+37282
-8743
No files matched your search
+4
-4
@@ -13,7 +13,7 @@ buildscript {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||
classpath 'com.android.tools.build:gradle:3.6.4'
|
||||
classpath "com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.3"
|
||||
classpath "org.ajoberstar:grgit:2.3.0"
|
||||
}
|
||||
@@ -45,10 +45,10 @@ allprojects {
|
||||
// dependency versions for all sub modules
|
||||
ext {
|
||||
// regular
|
||||
buildTools = "28.0.3"
|
||||
compileSdk = 28
|
||||
buildTools = "29.0.3"
|
||||
compileSdk = 29
|
||||
minSdk = 16
|
||||
targetSdk = 28
|
||||
targetSdk = 29
|
||||
|
||||
sourceCompatibilityVersion = JavaVersion.VERSION_1_8
|
||||
targetCompatibilityVersion = JavaVersion.VERSION_1_8
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.4.63
|
||||
1.4.91
|
||||
+22
-22
@@ -1,22 +1,22 @@
|
||||
{
|
||||
"ANDROID":[
|
||||
{
|
||||
"version": "1.4.63",
|
||||
"groupid": "com.sap.sailing",
|
||||
"file": "src/java/com.sap.sailing.www/apps/com.sap.sailing.racecommittee.app-unsigned.apk",
|
||||
"artifactid": "com.sap.sailing.racecommittee.app"
|
||||
},
|
||||
{
|
||||
"version": "1.4.63",
|
||||
"groupid": "com.sap.sailing",
|
||||
"file": "src/java/com.sap.sailing.www/apps/com.sap.sailing.android.tracking.app-unsigned.apk",
|
||||
"artifactid": "com.sap.sailing.android.tracking.app"
|
||||
},
|
||||
{
|
||||
"version": "1.4.63",
|
||||
"groupid": "com.sap.sailing",
|
||||
"file": "src/java/com.sap.sailing.www/apps/com.sap.sailing.android.buoy.positioning.app-unsigned.apk",
|
||||
"artifactid": "com.sap.sailing.android.buoy.positioning.app"
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"ANDROID":[
|
||||
{
|
||||
"version": "1.4.91",
|
||||
"groupid": "com.sap.sailing",
|
||||
"file": "src/java/com.sap.sailing.www/apps/com.sap.sailing.racecommittee.app-unsigned.apk",
|
||||
"artifactid": "com.sap.sailing.racecommittee.app"
|
||||
},
|
||||
{
|
||||
"version": "1.4.91",
|
||||
"groupid": "com.sap.sailing",
|
||||
"file": "src/java/com.sap.sailing.www/apps/com.sap.sailing.android.tracking.app-unsigned.apk",
|
||||
"artifactid": "com.sap.sailing.android.tracking.app"
|
||||
},
|
||||
{
|
||||
"version": "1.4.91",
|
||||
"groupid": "com.sap.sailing",
|
||||
"file": "src/java/com.sap.sailing.www/apps/com.sap.sailing.android.buoy.positioning.app-unsigned.apk",
|
||||
"artifactid": "com.sap.sailing.android.buoy.positioning.app"
|
||||
}
|
||||
]
|
||||
}
|
||||
+5
-5
@@ -5,17 +5,17 @@ imports dslVersion:"1.3", {
|
||||
artifactFile "com.oracle.download.java:jdk:tar.gz:linux-x64:1.8.0_66-sap-01"
|
||||
|
||||
artifactFile "com.google.download.android:tools:zip:linux:26.1.1"
|
||||
artifactFile "com.google.download.android:platform-tools:zip:linux:28.0.0"
|
||||
artifactFile "com.google.download.android:build-tools:zip:linux:28.0.3"
|
||||
artifactFile "com.google.download.android:platform:zip:28.6"
|
||||
artifactFile "com.google.download.android:platform-tools:zip:linux:30.0.5"
|
||||
artifactFile "com.google.download.android:build-tools:zip:linux:29.0.3"
|
||||
artifactFile "com.google.download.android:platform:zip:29.5"
|
||||
|
||||
// optional dependencies for Android SDK - use when required (e.g. appcompat-v7)
|
||||
artifactFile "com.google.download.android:google-repository:zip:58"
|
||||
|
||||
// tools required to sign + zipalign APKs
|
||||
unzip {
|
||||
artifactFile "com.sap.prd.codesign.mavenclient:com.sap.prd.codesign.mavenclient.dist.cli:zip:dist:1.1.1"
|
||||
artifactFile "com.google.download.android:build-tools:zip:linux:27.0.3"
|
||||
artifactFile "com.sap.prd.codesign.mavenclient:com.sap.prd.codesign.mavenclient.dist.cli:zip:dist:1.4.0"
|
||||
artifactFile "com.google.download.android:build-tools:zip:linux:27.0.3"
|
||||
}
|
||||
artifactFile "com.sap.ldi.signing:localSigningKeystore:jks:1.0.0"
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
AVAILABILITY_ZONE=eu-west-1c
|
||||
INSTANCE_TYPE=i3.xlarge
|
||||
# eu-west-1:
|
||||
#IMAGE_ID=ami-080cce167279f643c
|
||||
IMAGE_ID=ami-054a4c20d297ab81e
|
||||
# eu-west-2:
|
||||
IMAGE_ID=ami-0c0907685eae2dbab
|
||||
#IMAGE_ID=ami-0c0907685eae2dbab
|
||||
# eu-west-1:
|
||||
#SECURITY_GROUP_ID=sg-0a9bc2fb61f10a342
|
||||
SECURITY_GROUP_ID=sg-0a9bc2fb61f10a342
|
||||
# eu-west-2:
|
||||
SECURITY_GROUP_ID=sg-02649c35a73ee0ae5
|
||||
#SECURITY_GROUP_ID=sg-02649c35a73ee0ae5
|
||||
KEY_NAME=Axel
|
||||
REPLICA_SET_NAME=
|
||||
REPLICA_SET_PRIMARY=
|
||||
|
||||
@@ -277,6 +277,8 @@ if [[ "$@" == "release" ]]; then
|
||||
cp -v $PROJECT_HOME/java/target/refreshInstance.sh $ACDIR/
|
||||
|
||||
cp -v $PROJECT_HOME/java/target/env.sh $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/env-default-rules.sh $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/defineReverseProxyMappings.sh $ACDIR/
|
||||
cp -v $p2PluginRepository/configuration/config.ini configuration/
|
||||
|
||||
cp -v $PROJECT_HOME/java/target/configuration/jetty/etc/jetty.xml configuration/jetty/etc
|
||||
@@ -335,7 +337,7 @@ INSTALL_FROM_RELEASE=$SIMPLE_VERSION_INFO
|
||||
SSH_CMD="ssh $REMOTE_SERVER_LOGIN"
|
||||
SCP_CMD="scp -r"
|
||||
|
||||
echo "Packaged release $PROJECT_HOME/dist/$SIMPLE_VERSION_INFO.tar.gz! I've put an env.sh that matches the current branch to $PROJECT_HOME/dist/$SIMPLE_VERSION_INFO/env.sh!"
|
||||
echo "Packaged release $PROJECT_HOME/dist/$SIMPLE_VERSION_INFO.tar.gz! I've put an env.sh that matches the current branch to $PROJECT_HOME/dist/$SIMPLE_VERSION_INFO/env.sh!"
|
||||
|
||||
echo "Checking the remote connection..."
|
||||
REMOTE_HOME=`ssh $REMOTE_SERVER_LOGIN 'echo $HOME/releases'`
|
||||
@@ -816,6 +818,8 @@ if [[ "$@" == "install" ]] || [[ "$@" == "all" ]]; then
|
||||
|
||||
if [ ! -f "$ACDIR/env.sh" ]; then
|
||||
cp -v $PROJECT_HOME/java/target/env.sh $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/env-default-rules.sh $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/defineReverseProxyMappings.sh $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/configuration/monitoring.properties $ACDIR/configuration/
|
||||
cp -v $PROJECT_HOME/java/target/configuration/mail.properties $ACDIR/configuration/
|
||||
cp -v $PROJECT_HOME/java/target/configuration/logging.properties $ACDIR/configuration/
|
||||
@@ -831,6 +835,7 @@ if [[ "$@" == "install" ]] || [[ "$@" == "all" ]]; then
|
||||
|
||||
# make sure to read the information from env.sh
|
||||
. $ACDIR/env.sh
|
||||
. $ACDIR/env-default-rules.sh
|
||||
|
||||
echo "$VERSION_INFO System:" > $ACDIR/configuration/jetty/version.txt
|
||||
|
||||
@@ -901,6 +906,8 @@ if [[ "$@" == "remote-deploy" ]]; then
|
||||
$SCP_CMD $PROJECT_HOME/java/target/configuration/mail.properties $REMOTE_SERVER_LOGIN:$REMOTE_SERVER/configuration/
|
||||
|
||||
$SCP_CMD $PROJECT_HOME/java/target/env.sh $REMOTE_SERVER_LOGIN:$REMOTE_SERVER/
|
||||
$SCP_CMD $PROJECT_HOME/java/target/env-default-rules.sh $REMOTE_SERVER_LOGIN:$REMOTE_SERVER/
|
||||
$SCP_CMD $PROJECT_HOME/java/target/defineReverseProxyMappings.sh $REMOTE_SERVER_LOGIN:$REMOTE_SERVER/
|
||||
$SCP_CMD $PROJECT_HOME/java/target/start $REMOTE_SERVER_LOGIN:$REMOTE_SERVER/
|
||||
$SCP_CMD $PROJECT_HOME/java/target/stop $REMOTE_SERVER_LOGIN:$REMOTE_SERVER/
|
||||
$SCP_CMD $PROJECT_HOME/java/target/status $REMOTE_SERVER_LOGIN:$REMOTE_SERVER/
|
||||
|
||||
@@ -3,14 +3,16 @@
|
||||
# Upgrades the AWS EC2 instance that this script is assumed to be executed on.
|
||||
# The steps are as follows:
|
||||
|
||||
REBOOT_INDICATOR=/var/run/is-rebooted
|
||||
|
||||
run_yum_update() {
|
||||
echo "Updating packages using yum" >>/var/log/sailing.err
|
||||
yum -y update
|
||||
}
|
||||
|
||||
run_git_pull() {
|
||||
echo "Pulling git master to /home/sailing/code" >>/var/log/sailing.err
|
||||
su - sailing -c "cd code; git fetch; git merge origin/master"
|
||||
echo "Pulling git to /home/sailing/code" >>/var/log/sailing.err
|
||||
su - sailing -c "cd code; git pull"
|
||||
}
|
||||
|
||||
run_refresh_instance_install_release() {
|
||||
@@ -25,7 +27,9 @@ clean_logrotate_target() {
|
||||
|
||||
clean_httpd_logs() {
|
||||
echo "Clearing httpd logs" >>/var/log/sailing.err
|
||||
service httpd stop
|
||||
rm -rf /var/log/httpd/*
|
||||
rm /etc/httpd/conf.d/001-internals.conf
|
||||
}
|
||||
|
||||
clean_sailing_logs() {
|
||||
@@ -36,6 +40,8 @@ clean_sailing_logs() {
|
||||
clean_startup_logs() {
|
||||
echo "Clearing bootstrap logs" >>/var/log/sailing.err
|
||||
rm /var/log/sailing*
|
||||
# Ensure that upon the next boot the reboot indicator is not present, indicating that it's the first boot
|
||||
rm "${REBOOT_INDICATOR}"
|
||||
}
|
||||
|
||||
run_yum_update
|
||||
@@ -49,6 +55,7 @@ clean_startup_logs
|
||||
# Finally, shut down the node unless "no-shutdown" was provided in the user data, so that a new AMI can be constructed cleanly
|
||||
if /opt/aws/bin/ec2-metadata -d | grep "^no-shutdown$"; then
|
||||
echo "Shutdown disabled by no-shutdown option in user data"
|
||||
touch /tmp/image-upgrade-finished
|
||||
else
|
||||
shutdown -h now &
|
||||
fi
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/bin/bash
|
||||
AWS=/root/.local/bin/aws
|
||||
REGION=eu-west-1
|
||||
#HUDSON_SLAVE_AMI_ID=ami-04956fe5a5293da6f
|
||||
HUDSON_SLAVE_AMI_ID=ami-0251a199f8d4a4729
|
||||
#HUDSON_SLAVE_AMI_ID=ami-05c12a89e3371ba45
|
||||
HUDSON_SLAVE_AMI_ID=ami-0c153e4928f340fe5
|
||||
echo Launching instance...
|
||||
instanceid=`$AWS ec2 run-instances --image-id $HUDSON_SLAVE_AMI_ID --count 1 --instance-type c5d.4xlarge --key-name Axel --security-groups "Sailing Analytics App" --region $REGION --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=Hudson Ubuntu Slave}]' --instance-initiated-shutdown-behavior terminate | tee /tmp/slavelaunch.out | jq .Instances[0].InstanceId | sed -e 's/"//g'`
|
||||
if [ "$instanceid" = "" ]; then
|
||||
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
|
||||
REGION=`wget -q -O - http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/[a-z]$//'`
|
||||
AMI_ID=`wget -q -O - http://169.254.169.254/latest/meta-data/ami-id`
|
||||
AMI_INFO=`aws ec2 describe-images --region ${REGION} --image-ids "$AMI_ID"`
|
||||
AMI_NAME=`echo $AMI_INFO | python -c "import sys,json; print json.load(sys.stdin)['Images'][0]['Name']"`
|
||||
AMI_CREATED=`echo $AMI_INFO | python -c "import sys,json; print json.load(sys.stdin)['Images'][0]['CreationDate']"`
|
||||
|
||||
INSTANCE_ID=`wget -q -O - http://169.254.169.254/latest/meta-data/instance-id`
|
||||
INSTANCE_NAME_INFO=`aws ec2 describe-tags --region ${REGION} --filter "Name=resource-id,Values=$INSTANCE_ID"`
|
||||
INSTANCE_AWS_NAME=`echo $INSTANCE_NAME_INFO | python -c "import sys,json; print json.load(sys.stdin)['Tags'][0]['Value']"`
|
||||
|
||||
source /home/sailing/servers/server/env.sh
|
||||
cat << EOF
|
||||
...........................................................
|
||||
/////////////////////////////////////////////////////////,
|
||||
///////////////////////////////////////////////////////,
|
||||
///* .*////// ///// .*/////////////,
|
||||
(. /((/ (((( /((((((((,
|
||||
. ,((((/.,(((( .((( /(/* ((((((,
|
||||
. ./((((((((, , *(( /(((* /(((,
|
||||
(. ./((* ,(. (( */*. ((,
|
||||
(((* ( ((( .( /*
|
||||
((((((((/ , .,/(*
|
||||
(/ .*(((* (((((*
|
||||
, (((/((/ (##*
|
||||
##(,. ./#,,,,,/#######,,,,,,,,,(*
|
||||
#################################* .*,
|
||||
###############################* ,./ *
|
||||
.............................. .
|
||||
|
||||
Welcome to instance running image $AMI_NAME!
|
||||
The image has been created at <$AMI_CREATED>.
|
||||
|
||||
This instance is named <$INSTANCE_AWS_NAME> and
|
||||
is running the Analytics server <$SERVER_NAME>.
|
||||
|
||||
It will use a maximum of <$MEMORY> memory and is configured to
|
||||
be a <$USE_ENVIRONMENT>. Please handle with love and care!
|
||||
|
||||
EOF
|
||||
+58
-64
@@ -22,13 +22,16 @@
|
||||
|
||||
RETVAL=0
|
||||
|
||||
JAVA_START_INSTANCES="server"
|
||||
SERVERS_DIR=/home/sailing/servers
|
||||
cd "${SERVERS_DIR}"
|
||||
JAVA_START_INSTANCES="$(find * -type d -prune)"
|
||||
GIT_REPOSITORY=/home/sailing/code
|
||||
APACHE_CONFIG_DIR=/etc/httpd/conf.d
|
||||
APACHE_INTERNALS_CONFIG_FILE="$APACHE_CONFIG_DIR/001-internals.conf"
|
||||
EC2_METADATA_CMD=/opt/aws/bin/ec2-metadata
|
||||
REBOOT_INDICATOR=/var/run/is-rebooted
|
||||
|
||||
echo "Executing with $1" >>/var/log/sailing.out
|
||||
echo "Executing with $1 at `date`" >>/var/log/sailing.err
|
||||
|
||||
start_tmux() {
|
||||
su - sailing -c "/home/sailing/bin/tmuxConsole.sh unattended"
|
||||
@@ -36,61 +39,48 @@ start_tmux() {
|
||||
}
|
||||
|
||||
start_servers() {
|
||||
su - sailing -c "cd $GIT_REPOSITORY && git fetch && git merge origin/master" 2>>/var/log/sailing.err >>/var/log/sailing.out
|
||||
if which $EC2_METADATA_CMD && $EC2_METADATA_CMD -d | sed "s/user-data\: //g" | grep "^image-upgrade$"; then
|
||||
echo "Found image-upgrade in EC2 user data; upgrading image, then shutting down for AMI creation..." >>/var/log/sailing.err
|
||||
echo "Found image-upgrade in EC2 user data; upgrading image, then probably shutting down for AMI creation depending on the no-shutdown user data string..." >>/var/log/sailing.err
|
||||
$GIT_REPOSITORY/configuration/imageupgrade.sh
|
||||
else
|
||||
echo "No image-upgrade request found in EC2 user data $($EC2_METADATA_CMD -d); proceding with regular server launch..." >>/var/log/sailing.err
|
||||
echo "No image-upgrade request found in EC2 user data $($EC2_METADATA_CMD -d); proceeding with regular server launch..." >>/var/log/sailing.err
|
||||
echo "Servers to launch: ${JAVA_START_INSTANCES}" >>/var/log/sailing.err
|
||||
NUMBER_OF_INSTANCES=`echo "$JAVA_START_INSTANCES" | wc -w`
|
||||
MINIMUM_MEMORY_IN_MB=2000
|
||||
MEM_TOTAL=`cat /proc/meminfo | grep MemTotal | awk '{print $2;}'`
|
||||
MEMORY_COMPUTED=$(( ${MEM_TOTAL} / 1024 * 3 / 4 - 1500 / 1 ))
|
||||
MEMORY_PER_INSTANCE_IN_MB=$(( $MEMORY_COMPUTED < $MINIMUM_MEMORY_IN_MB ? $MINIMUM_MEMORY_IN_MB : $MEMORY_COMPUTED ))
|
||||
echo "Using ${MEMORY_PER_INSTANCE_IN_MB}MB as default heap size per instance."
|
||||
for conf in $JAVA_START_INSTANCES; do
|
||||
echo "Checking for amazon update..." >>/var/log/sailing.out
|
||||
echo "MEMORY=\"${MEMORY_PER_INSTANCE_IN_MB}m\"" >>$SERVERS_DIR/$conf/env.sh
|
||||
su - sailing -c "cd $SERVERS_DIR/$conf && $GIT_REPOSITORY/java/target/refreshInstance.sh auto-install" 2>>/var/log/sailing.err >>/var/log/sailing.out
|
||||
(
|
||||
# execute env.sh in a subshell which now has the same set of variables that the server will see
|
||||
source $SERVERS_DIR/$conf/env.sh
|
||||
echo "Starting Java server \"$conf\"" >>/var/log/sailing.out
|
||||
su - sailing -c "cd $SERVERS_DIR/$conf && ./start" 2>>/var/log/sailing.err >>/var/log/sailing.out
|
||||
server_name="`echo $SERVER_NAME | tr [A-Z] [a-z]`"
|
||||
echo "Appending macro invocation to $APACHE_CONFIG_DIR/001-events.conf to map internal IP $INSTANCE_INTERNAL_IP4 to plain server running $SERVER_PORT..." >>/var/log/sailing.out
|
||||
echo "Use Plain-SSL ${INSTANCE_INTERNAL_IP4} 127.0.0.1 $SERVER_PORT" >>$APACHE_CONFIG_DIR/001-events.conf
|
||||
echo "Appending macro invocation to $APACHE_CONFIG_DIR/001-events.conf to map ${server_name}.sapsailing.com to event with ID $EVENT_ID with server running on local port $SERVER_PORT..." >>/var/log/sailing.out
|
||||
if [ "$EVENT_ID" != "" ]; then
|
||||
echo "## EVENT ${server_name}" >>$APACHE_CONFIG_DIR/001-events.conf
|
||||
echo "Use Event-SSL ${server_name}.sapsailing.com \"$EVENT_ID\" 127.0.0.1 $SERVER_PORT" >>$APACHE_CONFIG_DIR/001-events.conf
|
||||
else
|
||||
echo "## No event ID provided; forwarding domain to /gwt/Home.html" >>$APACHE_CONFIG_DIR/001-events.conf
|
||||
echo "Use Home-SSL ${server_name}.sapsailing.com 127.0.0.1 $SERVER_PORT" >>$APACHE_CONFIG_DIR/001-events.conf
|
||||
fi
|
||||
# check if n secondary event shall be pasted to 001-events.conf
|
||||
if [[ ${HTTP_SEC_EVENT} && ${HTTP_SEC_EVENT_ID} ]]; then
|
||||
http_sec_event="`echo $HTTP_SEC_EVENT | tr [A-Z] [a-z]`"
|
||||
echo "Appending macro invocation to $APACHE_CONFIG_DIR/001-events.conf to map ${http_sec_event}.sapsailing.com to event with ID ${HTTP_SEC_EVENT_ID} with server running on local port $SERVER_PORT..." >>/var/log/sailing.out
|
||||
echo "## EVENT ${http_sec_event}" >>$APACHE_CONFIG_DIR/001-events.conf
|
||||
echo "Use Event ${http_sec_event}.sapsailing.com \"$HTTP_SEC_EVENT_ID\" 127.0.0.1 $SERVER_PORT" >>$APACHE_CONFIG_DIR/001-events.conf
|
||||
echo "Use Event-SSL ${http_sec_event}.sapsailing.com \"$HTTP_SEC_EVENT_ID\" 127.0.0.1 $SERVER_PORT" >>$APACHE_CONFIG_DIR/001-events.conf
|
||||
fi
|
||||
HTTP_LOGROTATE=/etc/logrotate.d/httpd
|
||||
echo "Patching $HTTP_LOGROTATE so that old logs go to /var/log/old/$SERVER_NAME/$INSTANCE_IP4" >>/var/log/sailing.out
|
||||
sed -i -e "s/\/var\/log\/old\/\([^/]*\)\/\([^/ ]*\)/\/var\/log\/old\/$SERVER_NAME\/$INSTANCE_IP4/" $HTTP_LOGROTATE
|
||||
# terminating the subshell will forget all the variable assignments brought in by env.sh, clearing for the next server instance
|
||||
)
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && success || failure
|
||||
done
|
||||
launch_httpd
|
||||
FIRST_SERVER=`echo $JAVA_START_INSTANCES | awk '{print $1;}'`
|
||||
if [ -f "${REBOOT_INDICATOR}" ]; then
|
||||
echo "This is a re-boot. No EC2 user data is evaluated for server configuration; no server configuration is performed. Only configured applications are launched." >>/var/log/sailing.err
|
||||
for conf in ${JAVA_START_INSTANCES}; do
|
||||
su - sailing -c "cd ${SERVERS_DIR}/${conf} && ./start" 2>>/var/log/sailing.err >>/var/log/sailing.err
|
||||
done
|
||||
else
|
||||
echo "This is a first-time boot. EC2 user data is evaluated for potential application deployment and configuration; reverse proxy entries may be created, and applications are launched." >>/var/log/sailing.err
|
||||
if [ ${NUMBER_OF_INSTANCES} -gt 1 ]; then
|
||||
echo "More than one server cannot be configured from user data; only configuring ${FIRST_SERVER}" >>/var/log/sailing.err
|
||||
fi
|
||||
configure_and_start_server "${FIRST_SERVER}"
|
||||
create_basic_httpd_config
|
||||
reload_httpd
|
||||
echo 1 >"${REBOOT_INDICATOR}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Call with the server directory name (not the full path, just a single element from ${JAVA_START_INSTANCE}) as parameter
|
||||
# Example: configure_and_start_server server
|
||||
# This is expected to be called only in case there is only one server to configure; otherwise, the same EC2 user data
|
||||
# would get applied to all application configurations which would not be a good idea.
|
||||
configure_and_start_server() {
|
||||
conf="$1"
|
||||
mkdir -p "${SERVERS_DIR}/${conf}" >/dev/null 2>/dev/null
|
||||
local ENV_SH="${SERVERS_DIR}/$conf/env.sh"
|
||||
su - sailing -c "cd ${SERVERS_DIR}/${conf} && ${GIT_REPOSITORY}/java/target/refreshInstance.sh auto-install; ./start; ./defineReverseProxyMappings.sh" 2>>/var/log/sailing.err >>/var/log/sailing.err
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && success || failure
|
||||
}
|
||||
|
||||
stop_servers() {
|
||||
for conf in $JAVA_START_INSTANCES; do
|
||||
echo "Stopping Java server $conf" >> /var/log/sailing.out
|
||||
echo "Stopping Java server $conf" >> /var/log/sailing.err
|
||||
su - sailing -c "cd $SERVERS_DIR/$conf && ./stop"
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && success || failure
|
||||
@@ -100,41 +90,45 @@ stop_servers() {
|
||||
}
|
||||
|
||||
sync_logs() {
|
||||
echo "Executing logrotate followed by a sync to ensure that logs are synchronized" >> /var/log/sailing.out
|
||||
echo "Executing logrotate followed by a sync to ensure that logs are synchronized" >> /var/log/sailing.err
|
||||
logrotate -f /etc/logrotate.conf
|
||||
sync
|
||||
}
|
||||
|
||||
# launch_httpd(server_name, port, event_id)
|
||||
launch_httpd() {
|
||||
echo "Will try to launch httpd so this replica can work with an ELB easily." >>/var/log/sailing.out
|
||||
reload_httpd() {
|
||||
echo "Will try to launch httpd so this replica can work with an ELB easily." >>/var/log/sailing.err
|
||||
if [ -x /etc/init.d/httpd ]; then
|
||||
FIRST_SERVER=`echo $JAVA_START_INSTANCES | awk '{print $1;}'`
|
||||
source $SERVERS_DIR/$FIRST_SERVER/env.sh
|
||||
# Append Apache macro invocation for /internal-server-status based on mod_status and INSTANCE_DNS to $APACHE_CONFIG_DIR/001-events.conf
|
||||
echo "Appending macro usage for $INSTANCE_DNS/internal-server-status URL for mod_status based Apache monitoring to $APACHE_CONFIG_DIR/001-events.conf" >>/var/log/sailing.out
|
||||
echo "## SERVER STATUS" >>$APACHE_CONFIG_DIR/001-events.conf
|
||||
echo "Use Status $INSTANCE_DNS internal-server-status" >>$APACHE_CONFIG_DIR/001-events.conf
|
||||
echo "Launching httpd..." >>/var/log/sailing.out
|
||||
service httpd start
|
||||
echo "Reloading httpd configuration..." >>/var/log/sailing.err
|
||||
service httpd reload
|
||||
else
|
||||
echo "Can't launch httpd; start script doesn't seem to be installed at /etc/init.d/httpd"
|
||||
echo "Can't launch httpd; start script doesn't seem to be installed at /etc/init.d/httpd"
|
||||
fi
|
||||
}
|
||||
|
||||
# Adds a Plain-SSL mapping to the first server's port and a mapping for /internal-server-status, both to 001-internals.conf
|
||||
create_basic_httpd_config() {
|
||||
FIRST_SERVER=`echo $JAVA_START_INSTANCES | awk '{print $1;}'`
|
||||
source $SERVERS_DIR/$FIRST_SERVER/env.sh
|
||||
echo "Writing macro invocation to ${APACHE_INTERNALS_CONFIG_FILE} to map internal IP $INSTANCE_INTERNAL_IP4 to plain server running $SERVER_PORT..." >>/var/log/sailing.err
|
||||
echo "Use Plain-SSL ${INSTANCE_INTERNAL_IP4} 127.0.0.1 $SERVER_PORT" >"${APACHE_INTERNALS_CONFIG_FILE}"
|
||||
# Append Apache macro invocation for /internal-server-status based on mod_status and INSTANCE_DNS to "${APACHE_INTERNALS_CONFIG_FILE}"
|
||||
echo "Appending macro usage for $INSTANCE_DNS/internal-server-status URL for mod_status based Apache monitoring to ${APACHE_INTERNALS_CONFIG_FILE}" >>/var/log/sailing.err
|
||||
echo "## SERVER STATUS" >>"${APACHE_INTERNALS_CONFIG_FILE}"
|
||||
echo "Use Status $INSTANCE_DNS internal-server-status" >>"${APACHE_INTERNALS_CONFIG_FILE}"
|
||||
}
|
||||
|
||||
stop_httpd() {
|
||||
if [ -x /etc/init.d/httpd ]; then
|
||||
service httpd stop
|
||||
echo "Stopped httpd..." >>/var/log/sailing.out
|
||||
echo "Stopped httpd..." >>/var/log/sailing.err
|
||||
fi
|
||||
}
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
/usr/local/bin/mountnvmeswap
|
||||
/usr/sbin/update-motd
|
||||
start_servers
|
||||
/usr/sbin/update-motd
|
||||
touch /var/lock/subsys/sailing
|
||||
;;
|
||||
stop)
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
<feature
|
||||
id="com.amazon.aws.aws-java-api"
|
||||
label="AWS API"
|
||||
version="2.15.16"
|
||||
version="2.15.57"
|
||||
provider-name="Amazon">
|
||||
|
||||
<plugin
|
||||
id="com.amazon.aws.aws-java-api"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="2.15.16"
|
||||
version="2.15.57"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.amazon.aws.aws-java-api.source"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="2.15.16"
|
||||
version="2.15.57"
|
||||
unpack="false"/>
|
||||
|
||||
</feature>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<site>
|
||||
<feature url="features/aws-sdk/com.amazon.aws.aws-java-api_2.15.16.jar" id="com.amazon.aws.aws-java-api" version="2.15.16">
|
||||
<feature url="features/aws-sdk/com.amazon.aws.aws-java-api_2.15.57.jar" id="com.amazon.aws.aws-java-api" version="2.15.57">
|
||||
<category name="aws-java-api"/>
|
||||
</feature>
|
||||
<category-def name="com.amazon.aws.aws-java-api" label="aws-java-api"/>
|
||||
|
||||
@@ -5,8 +5,9 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation platform('software.amazon.awssdk:bom:2.15.16')
|
||||
implementation platform('software.amazon.awssdk:bom:2.15.57')
|
||||
implementation 'software.amazon.awssdk:s3'
|
||||
implementation 'software.amazon.awssdk:lambda'
|
||||
implementation 'software.amazon.awssdk:ec2'
|
||||
implementation 'software.amazon.awssdk:route53'
|
||||
implementation 'software.amazon.awssdk:cloudwatch'
|
||||
@@ -17,6 +18,7 @@ dependencies {
|
||||
implementation group: 'software.amazon.awssdk', name: 'aws-core', classifier: 'sources'
|
||||
implementation group: 'software.amazon.awssdk', name: 'auth', classifier: 'sources'
|
||||
implementation group: 'software.amazon.awssdk', name: 's3', classifier: 'sources'
|
||||
implementation group: 'software.amazon.awssdk', name: 'lambda', classifier: 'sources'
|
||||
implementation group: 'software.amazon.awssdk', name: 'ec2', classifier: 'sources'
|
||||
implementation group: 'software.amazon.awssdk', name: 'regions', classifier: 'sources'
|
||||
implementation group: 'software.amazon.awssdk', name: 'profiles', classifier: 'sources'
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.amazon.aws.aws-java-api</artifactId>
|
||||
<version>2.15.16</version>
|
||||
<version>2.15.57</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
Regular → Executable
+1
@@ -20,6 +20,7 @@
|
||||
</listAttribute>
|
||||
<booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
|
||||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8" javaProject="com.sap.sailing.gwt.ui" path="1" type="4"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="com.sap.sailing.dashboards.gwt"/> </runtimeClasspathEntry> "/>
|
||||
|
||||
Regular → Executable
+1
@@ -22,6 +22,7 @@
|
||||
<booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_CLASSPATH_ONLY_JAR" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
|
||||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8" javaProject="com.sap.sailing.gwt.ui" path="1" type="4"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="com.sap.sailing.dashboards.gwt"/> </runtimeClasspathEntry> "/>
|
||||
|
||||
+2
-4
@@ -8,7 +8,6 @@ import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.declination.Declination;
|
||||
@@ -35,14 +34,13 @@ public abstract class DeclinationServiceTest<I extends DeclinationImporter> exte
|
||||
assertEquals(0.+09./60., result.getAnnualChange().getDegrees(), 0.0000001);
|
||||
}
|
||||
|
||||
@Ignore("Currently NOAA service ends Dec 2019; this test for now is only available for the Colorado importer")
|
||||
@Test
|
||||
public void testDeclinationQueryNotMatchedInStore() throws IOException, ClassNotFoundException, ParseException {
|
||||
Declination result = service.getDeclination(new MillisecondsTimePoint(simpleDateFormat.parse("2020-02-03").getTime()),
|
||||
new DegreePosition(51, -5), /* timeoutForOnlineFetchInMilliseconds */ 5000);
|
||||
assertNotNull(result);
|
||||
assertEquals(-1.80464, result.getBearing().getDegrees(), 0.001);
|
||||
assertEquals(0.15244, result.getAnnualChange().getDegrees(), 0.001);
|
||||
assertEquals(-1.531, result.getBearing().getDegrees(), 0.001);
|
||||
assertEquals(0.20272, result.getAnnualChange().getDegrees(), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<listEntry value="1"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.sap.sailing.declination.impl.DeclinationStore"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="2020 2020 1"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="com.sap.sailing.declination"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="2021 2021 1"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.declination"/>
|
||||
</launchConfiguration>
|
||||
+8
@@ -11,6 +11,14 @@ public class BranchIOConstants {
|
||||
public static final String OPEN_REGATTA_2_APP_BRANCHIO_PATH = "checkinUrl";
|
||||
public static final String OPEN_REGATTA_3_APP_BRANCHIO = "https://sailinsight30-app.sapsailing.com/publicInvite";
|
||||
public static final String OPEN_REGATTA_3_APP_BRANCHIO_PATH = "checkinUrl";
|
||||
public static final String RACEMANAGER_APP_BRANCH_QUICK_LINK = "https://racemanager-app.sapsailing.com/invite";
|
||||
public static final String RACEMANAGER_APP_BRANCH_PARAM_SERVER_URL = "server_url";
|
||||
public static final String RACEMANAGER_APP_BRANCH_PARAM_DEVICE_CONFIG_IDENTIFIER = "device_config_identifier";
|
||||
public static final String RACEMANAGER_APP_BRANCH_PARAM_DEVICE_CONFIG_UUID = "device_config_uuid";
|
||||
public static final String RACEMANAGER_APP_BRANCH_PARAM_TOKEN = "token";
|
||||
public static final String RACEMANAGER_APP_BRANCH_PARAM_EVENT_ID = "event_id";
|
||||
public static final String RACEMANAGER_APP_BRANCH_PARAM_COURSE_AREA_UUID = "course_area_uuid";
|
||||
public static final String RACEMANAGER_APP_BRANCH_PARAM_PRIORITY = "priority";
|
||||
|
||||
private BranchIOConstants() {
|
||||
}
|
||||
|
||||
+11
-11
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.dto.PersonDTO;
|
||||
import com.sap.sse.common.CountryCode;
|
||||
@@ -15,8 +15,8 @@ import com.sap.sse.common.impl.NamedImpl;
|
||||
public class CompetitorDescriptor extends NamedImpl implements Named {
|
||||
private static final long serialVersionUID = -6645726854552711646L;
|
||||
|
||||
private final UUID competitorUUID;
|
||||
private final UUID boatUUID;
|
||||
private final Serializable competitorId;
|
||||
private final Serializable boatId;
|
||||
private final String shortName;
|
||||
private final String eventName;
|
||||
private final String regattaName;
|
||||
@@ -32,23 +32,23 @@ public class CompetitorDescriptor extends NamedImpl implements Named {
|
||||
private final Duration timeOnDistanceAllowancePerNauticalMile;
|
||||
|
||||
public CompetitorDescriptor(String eventName, String regattaName, String raceName, String fleetName,
|
||||
UUID competitorUUID, String fullName, String shortName, String teamName, Iterable<PersonDTO> persons,
|
||||
Serializable competitorId, String fullName, String shortName, String teamName, Iterable<PersonDTO> persons,
|
||||
CountryCode countryCode, Double timeOnTimeFactor,
|
||||
Duration timeOnDistanceAllowancePerNauticalMile, UUID boatUUID, String boatName, String boatClassName, String sailNumber) {
|
||||
Duration timeOnDistanceAllowancePerNauticalMile, Serializable boatId, String boatName, String boatClassName, String sailNumber) {
|
||||
super(fullName);
|
||||
this.shortName = shortName;
|
||||
this.eventName = eventName;
|
||||
this.regattaName = regattaName;
|
||||
this.raceName = raceName;
|
||||
this.fleetName = fleetName;
|
||||
this.competitorUUID = competitorUUID;
|
||||
this.competitorId = competitorId;
|
||||
this.teamName = teamName;
|
||||
this.countryCode = countryCode;
|
||||
this.persons = new ArrayList<>();
|
||||
Util.addAll(persons, this.persons);
|
||||
this.timeOnTimeFactor = timeOnTimeFactor;
|
||||
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
|
||||
this.boatUUID = boatUUID;
|
||||
this.boatId = boatId;
|
||||
this.boatName = boatName;
|
||||
this.boatClassName = boatClassName;
|
||||
this.sailNumber = sailNumber;
|
||||
@@ -106,12 +106,12 @@ public class CompetitorDescriptor extends NamedImpl implements Named {
|
||||
return timeOnDistanceAllowancePerNauticalMile;
|
||||
}
|
||||
|
||||
public UUID getCompetitorUUID() {
|
||||
return competitorUUID;
|
||||
public Serializable getCompetitorId() {
|
||||
return competitorId;
|
||||
}
|
||||
|
||||
public UUID getBoatUUID() {
|
||||
return boatUUID;
|
||||
public Serializable getBoatId() {
|
||||
return boatId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+25
-1
@@ -6,4 +6,28 @@ public interface LeaderboardNameConstants {
|
||||
static final String DEFAULT_FLEET_NAME = "Default";
|
||||
|
||||
static final String DEFAULT_SERIES_NAME = "Default";
|
||||
}
|
||||
|
||||
static final String NAME = "name";
|
||||
static final String DISPLAYNAME = "displayName";
|
||||
static final String ISMETALEADERBOARD = "isMetaLeaderboard";
|
||||
static final String ISREGATTALEADERBOARD = "isRegattaLeaderboard";
|
||||
static final String SCORINGSCHEME = "scoringScheme";
|
||||
static final String SCORINGCOMMENT = "scoringComment";
|
||||
static final String LASTSCORINGUPDATE = "lastScoringUpdate";
|
||||
static final String REGATTANAME = "regattaName";
|
||||
static final String SERIES = "series";
|
||||
static final String ISMEDALSERIES = "isMedalSeries";
|
||||
static final String FLEETS = "fleets";
|
||||
static final String COLOR = "color";
|
||||
static final String ORDERING = "ordering";
|
||||
static final String RACES = "races";
|
||||
static final String ISMEDALRACE = "isMedalRace";
|
||||
static final String ISTRACKED = "isTracked";
|
||||
static final String TRACKEDRACENAME = "trackedRaceName";
|
||||
static final String TRACKINGPROVIDERTYPE = "trackingProviderType";
|
||||
static final String RACEID = "raceId";
|
||||
static final String RACEVIEWERURLS = "raceViewerUrls";
|
||||
static final String HASGPSDATA = "hasGpsData";
|
||||
static final String HASWINDDATA = "hasWindData";
|
||||
|
||||
}
|
||||
+10
-10
@@ -2,7 +2,6 @@ package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.security.SecuredDomainType;
|
||||
import com.sap.sse.security.shared.HasPermissions;
|
||||
import com.sap.sse.security.shared.QualifiedObjectIdentifier;
|
||||
@@ -36,22 +35,23 @@ public class RaceDTO extends BasicRaceDTO implements SecuredDTO {
|
||||
|
||||
public TrackedRaceStatisticsDTO trackedRaceStatistics;
|
||||
|
||||
private String regattaName;
|
||||
public String boatClass;
|
||||
|
||||
private RankingMetrics rankingMetricType;
|
||||
|
||||
private RegattaAndRaceIdentifier raceIdentifier;
|
||||
|
||||
public RaceDTO() {}
|
||||
|
||||
public RaceDTO(RegattaAndRaceIdentifier raceIdentifier, TrackedRaceDTO trackedRace, boolean isCurrentlyTracked, RankingMetrics rankingMetricType) {
|
||||
super(raceIdentifier, trackedRace);
|
||||
this.regattaName = raceIdentifier.getRegattaName();
|
||||
this.raceIdentifier = raceIdentifier;
|
||||
this.isTracked = isCurrentlyTracked;
|
||||
this.rankingMetricType = rankingMetricType;
|
||||
}
|
||||
|
||||
public RegattaAndRaceIdentifier getRaceIdentifier() {
|
||||
return new RegattaNameAndRaceName(regattaName, getName());
|
||||
return raceIdentifier;
|
||||
}
|
||||
|
||||
public RankingMetrics getRankingMetricType() {
|
||||
@@ -59,7 +59,7 @@ public class RaceDTO extends BasicRaceDTO implements SecuredDTO {
|
||||
}
|
||||
|
||||
public String getRegattaName() {
|
||||
return regattaName;
|
||||
return raceIdentifier.getRegattaName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,7 +69,7 @@ public class RaceDTO extends BasicRaceDTO implements SecuredDTO {
|
||||
result = prime * result + ((boatClass == null) ? 0 : boatClass.hashCode());
|
||||
result = prime * result + (isTracked ? 1231 : 1237);
|
||||
result = prime * result + ((places == null) ? 0 : places.hashCode());
|
||||
result = prime * result + ((regattaName == null) ? 0 : regattaName.hashCode());
|
||||
result = prime * result + ((getRegattaName() == null) ? 0 : getRegattaName().hashCode());
|
||||
result = prime * result + ((status == null) ? 0 : status.hashCode());
|
||||
return result;
|
||||
}
|
||||
@@ -95,10 +95,10 @@ public class RaceDTO extends BasicRaceDTO implements SecuredDTO {
|
||||
return false;
|
||||
} else if (!places.equals(other.places))
|
||||
return false;
|
||||
if (regattaName == null) {
|
||||
if (other.regattaName != null)
|
||||
if (getRegattaName() == null) {
|
||||
if (other.getRegattaName() != null)
|
||||
return false;
|
||||
} else if (!regattaName.equals(other.regattaName))
|
||||
} else if (!getRegattaName().equals(other.getRegattaName()))
|
||||
return false;
|
||||
if (status == null) {
|
||||
if (other.status != null)
|
||||
@@ -139,7 +139,7 @@ public class RaceDTO extends BasicRaceDTO implements SecuredDTO {
|
||||
}
|
||||
|
||||
public TypeRelativeObjectIdentifier getTypeRelativeObjectIdentifier() {
|
||||
return new TypeRelativeObjectIdentifier(regattaName, getName());
|
||||
return raceIdentifier.getTypeRelativeObjectIdentifier();
|
||||
}
|
||||
|
||||
}
|
||||
+36
-14
@@ -7,42 +7,64 @@ import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class is used by our backend, in GWT-client code and by the Android app. Therefore we cannot use classes like
|
||||
* {@link URLEncoder} to help us with the encoding.
|
||||
* {@link URLEncoder} to help us with the encoding.<p>
|
||||
*
|
||||
* Example URL:<pre>
|
||||
* https://racemanager-app.sapsailing.com/invite?server_url=https://dev.sapsailing.com/&device_config_identifier=D-Labs+Test&device_config_uuid=6fb0e2e3-23e6-4d2e-b66a-77d98feb7fdd&token=KY5G48LdOiTysCCiRfvFIVO87Ljbfzo3a4%2Bal63H%2Fvw%3D&event_id=8c3bdd16-a3d1-4a38-bf82-29d98ce18bec&course_area_uuid=fe96623a-d570-4dc5-8cc4-7fe8c5e7e2c0&priority=2
|
||||
* </pre>
|
||||
*/
|
||||
public class DeviceConfigurationQRCodeUtils {
|
||||
public static final String deviceIdentifierKey = "identifier";
|
||||
private static final String BASE_INVITATION_URL = "https://racemanager-app.sapsailing.com/invite";
|
||||
public static final String serverUrl = "server_url";
|
||||
public static final String eventId = "event_id";
|
||||
public static final String courseAreaId = "course_area_uuid";
|
||||
public static final String priority = "priority";
|
||||
public static final String deviceIdentifierKey = "device_config_identifier";
|
||||
public static final String deviceUuidKey = "device_config_uuid";
|
||||
public static final String accessTokenKey = "token";
|
||||
public static final String deviceUuidKey = "uuid";
|
||||
|
||||
|
||||
public static class DeviceConfigurationDetails {
|
||||
private final String apkUrl;
|
||||
private final String url;
|
||||
private final String deviceIdentifier;
|
||||
private final UUID uuid;
|
||||
private final String accessToken;
|
||||
public DeviceConfigurationDetails(String apkUrl, UUID uuid, String deviceConfigurationName, String accessToken) {
|
||||
|
||||
public DeviceConfigurationDetails(String url, UUID uuid, String deviceConfigurationName, String accessToken) {
|
||||
super();
|
||||
this.apkUrl = apkUrl;
|
||||
this.url = url;
|
||||
this.uuid = uuid;
|
||||
this.deviceIdentifier = deviceConfigurationName;
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
public String getApkUrl() {
|
||||
return apkUrl;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public UUID getUuid() { return uuid; }
|
||||
|
||||
public String getDeviceIdentifier() { return deviceIdentifier; }
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static interface URLDecoder {
|
||||
String decode(String encodedURL);
|
||||
}
|
||||
|
||||
public static String composeQRContent(String urlEncodedDeviceConfigName, String apkUrl, String accessToken, String urlEncodedDeviceIdAsString) {
|
||||
return apkUrl + "#" + deviceIdentifierKey + "=" + urlEncodedDeviceConfigName + "&" + deviceUuidKey + "="
|
||||
+ urlEncodedDeviceIdAsString + "&" + accessTokenKey + "=" + accessToken;
|
||||
public static String composeQRContent(String serverUrlWithoutFinalSlash, String urlEncodedDeviceConfigName,
|
||||
String urlEncodedDeviceIdAsString, UUID eventId, UUID courseAreaId, Integer priority,
|
||||
String accessToken) {
|
||||
return BASE_INVITATION_URL
|
||||
+ "?"+serverUrl+"="+serverUrlWithoutFinalSlash
|
||||
+ "&" + deviceIdentifierKey + "=" + urlEncodedDeviceConfigName
|
||||
+ "&" + deviceUuidKey + "=" + urlEncodedDeviceIdAsString
|
||||
+ (eventId != null ? ("&" + DeviceConfigurationQRCodeUtils.eventId + "=" + eventId) : "")
|
||||
+ (courseAreaId != null ? ("&" + DeviceConfigurationQRCodeUtils.courseAreaId + "=" + courseAreaId) : "")
|
||||
+ (priority != null ? ("&" + DeviceConfigurationQRCodeUtils.priority + "=" + priority) : "")
|
||||
+ (accessToken != null ? ("&" + accessTokenKey + "=" + accessToken) : "");
|
||||
}
|
||||
|
||||
public static DeviceConfigurationDetails splitQRContent(String qrCodeContent, URLDecoder urlDecoder) {
|
||||
@@ -50,7 +72,7 @@ public class DeviceConfigurationQRCodeUtils {
|
||||
if (fragmentIndex == -1 || fragmentIndex == 0 || qrCodeContent.length() == fragmentIndex + 1) {
|
||||
throw new IllegalArgumentException("There is no server or identifier.");
|
||||
}
|
||||
String fragment = qrCodeContent.substring(fragmentIndex + 1, qrCodeContent.length());
|
||||
String fragment = qrCodeContent.substring(fragmentIndex + 1);
|
||||
final String[] params = fragment.split("&");
|
||||
final Map<String, String> paramMap = new HashMap<>();
|
||||
for (String param : params) {
|
||||
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
package com.sap.sailing.domain.common.racelog;
|
||||
|
||||
/**
|
||||
* Generally, any {@code AbstractLogEvent} has an author of type {@code AbstractLogEventAuthor} which has a numerical
|
||||
* non-negative priority. Lesser numerical values represent higher priority/precedence. This enumeration captures
|
||||
* the default priorities the Race Manager App is expected to handle.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public enum AuthorPriority {
|
||||
ADMIN(0),
|
||||
OFFICER_ON_VESSEL(1),
|
||||
SHORE_CONTROL(2),
|
||||
DEMO_MODE(3);
|
||||
|
||||
private final int priority;
|
||||
|
||||
private AuthorPriority(int priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ package com.sap.sailing.domain.common.racelog.tracking;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MarkAlreadyUsedInRaceException extends Exception implements Serializable {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 2040461905745135256L;
|
||||
|
||||
public MarkAlreadyUsedInRaceException() {
|
||||
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.domain.common.racelog.tracking;
|
||||
|
||||
import com.sap.sse.common.TransformationException;
|
||||
|
||||
/**
|
||||
* Handle transformation between two types. Most likely use-case is serialization,
|
||||
* e.g. for JSON documents or database persistence.
|
||||
|
||||
@@ -3,4 +3,5 @@ source.. = src/,\
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.,\
|
||||
WEB-INF/
|
||||
WEB-INF/,\
|
||||
redirect.html
|
||||
@@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Igtimi</title>
|
||||
<script>
|
||||
function loadAndReplace() {
|
||||
var request = new XMLHttpRequest();
|
||||
var base64 = window.location.href.substring(window.location.href.lastIndexOf("?")+1);
|
||||
var target = atob(base64);
|
||||
console.log("decode post target " + base64 + " -> " + target);
|
||||
request.open("POST", target);
|
||||
request.setRequestHeader("X-SAPSSE-Forward-Request-To","master");
|
||||
request.addEventListener("load", function(event) {
|
||||
if (request.status >= 200 && request.status < 300) {
|
||||
document.getElementById("body").innerHTML = request.responseText;
|
||||
} else {
|
||||
document.getElementById("body").innerHTML = "<b>error reading data from server</b>";
|
||||
}
|
||||
});
|
||||
request.send();
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
loadAndReplace();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body id="body" onload="refresh()" >
|
||||
</body>
|
||||
</html>
|
||||
+15
-2
@@ -4,10 +4,12 @@ import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Base64;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
@@ -55,7 +57,10 @@ public class AuthorizationCallback {
|
||||
Response result;
|
||||
if (state != null) {
|
||||
// redirect to the server whose base URL is contained in the state parameter
|
||||
result = Response.temporaryRedirect(new URI(state+"/igtimi/oauth/v1"+AUTHORIZATIONCALLBACK+"?code="+URLEncoder.encode(code, "UTF-8"))).build();
|
||||
String target = Base64.getEncoder().encodeToString(
|
||||
(state + "/igtimi/oauth/v1" + AUTHORIZATIONCALLBACK + "?code=" + URLEncoder.encode(code, "UTF-8"))
|
||||
.getBytes());
|
||||
result = Response.temporaryRedirect(new URI(state + "/igtimi/redirect.html?" + target)).build();
|
||||
} else {
|
||||
if (code != null) {
|
||||
try {
|
||||
@@ -82,7 +87,15 @@ public class AuthorizationCallback {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@POST
|
||||
@Produces("text/plain;charset=UTF-8")
|
||||
@Path(AUTHORIZATIONCALLBACK)
|
||||
public Response obtainAccessTokenPost(@QueryParam("code") String code, @QueryParam("state") String state)
|
||||
throws ClientProtocolException, IOException, IllegalStateException, ParseException, URISyntaxException {
|
||||
return obtainAccessToken(code, state);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
@Path("uri")
|
||||
|
||||
+14
-3
@@ -72,6 +72,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
|
||||
@@ -95,6 +96,7 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPathfinderEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogProtestStartTimeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogResultsAreOfficialEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRevokeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartOfTrackingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartProcedureChangedEventImpl;
|
||||
@@ -246,8 +248,6 @@ import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.BoatJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.CompetitorWithBoatRefJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.DeviceConfigurationJsonDeserializer;
|
||||
@@ -278,6 +278,8 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.common.impl.RGBColor;
|
||||
import com.sap.sse.common.impl.TimeRangeImpl;
|
||||
import com.sap.sse.common.media.MimeType;
|
||||
import com.sap.sse.shared.json.JsonDeserializationException;
|
||||
import com.sap.sse.shared.json.JsonDeserializer;
|
||||
import com.sap.sse.shared.media.ImageDescriptor;
|
||||
import com.sap.sse.shared.media.VideoDescriptor;
|
||||
import com.sap.sse.shared.media.impl.ImageDescriptorImpl;
|
||||
@@ -1341,7 +1343,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
: buoyZoneRadiusInHullLengths,
|
||||
useStartTimeInference == null ? true : useStartTimeInference,
|
||||
controlTrackingFromStartAndFinishTimes == null ? false : controlTrackingFromStartAndFinishTimes,
|
||||
autoRestartTrackingUponCompetitorSetChange, rankingMetricConstructor, new MongoObjectFactoryImpl(database), registrationLinkSecret);
|
||||
autoRestartTrackingUponCompetitorSetChange == null ? false : autoRestartTrackingUponCompetitorSetChange, rankingMetricConstructor,
|
||||
new MongoObjectFactoryImpl(database), registrationLinkSecret);
|
||||
} else {
|
||||
result = new RegattaImpl(getRaceLogStore(), getRegattaLogStore(), name, boatClass,
|
||||
canBoatsOfCompetitorsChangePerRace, competitorRegistrationType, startDate, endDate, series, /* persistent */true,
|
||||
@@ -1660,6 +1663,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
resultEvent = loadRaceLogORCScratchBoatEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
|
||||
} else if (eventClass.equals(RaceLogORCImpliedWindSourceEvent.class.getSimpleName())) {
|
||||
resultEvent = loadRaceLogORCSetImpliedWindEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
|
||||
} else if (eventClass.equals(RaceLogResultsAreOfficialEvent.class.getSimpleName())) {
|
||||
resultEvent = loadRaceLogResultsAreOfficialEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject);
|
||||
} else {
|
||||
throw new IllegalStateException(String.format("Unknown RaceLogEvent type %s", eventClass));
|
||||
}
|
||||
@@ -1685,6 +1690,12 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
}
|
||||
return new RaceLogORCImpliedWindSourceEventImpl(createdAt, logicalTimePoint, author, id, passId, impliedWindSource);
|
||||
}
|
||||
|
||||
private RaceLogEvent loadRaceLogResultsAreOfficialEvent(TimePoint createdAt,
|
||||
AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId,
|
||||
List<Competitor> competitors, Document dbObject) throws JsonDeserializationException, ParseException {
|
||||
return new RaceLogResultsAreOfficialEventImpl(createdAt, logicalTimePoint, author, id, passId);
|
||||
}
|
||||
|
||||
private RaceLogEvent loadRaceLogUseCompetitorsFromRaceLogEvent(TimePoint createdAt, AbstractLogEventAuthor author,
|
||||
TimePoint logicalTimePoint, Serializable id, Integer passId, List<Competitor> competitors,
|
||||
|
||||
+18
-2
@@ -53,6 +53,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
|
||||
@@ -111,7 +112,6 @@ import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.dto.AnniversaryType;
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
@@ -128,7 +128,6 @@ import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.BoatClassJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.BoatJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer;
|
||||
@@ -146,11 +145,13 @@ import com.sap.sse.common.Speed;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.TypeBasedServiceFinder;
|
||||
import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.shared.json.JsonSerializer;
|
||||
import com.sap.sse.shared.media.ImageDescriptor;
|
||||
import com.sap.sse.shared.media.VideoDescriptor;
|
||||
|
||||
@@ -940,6 +941,13 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogWindFix(event));
|
||||
return result;
|
||||
}
|
||||
|
||||
public Document storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogResultsAreOfficialEvent event) {
|
||||
Document result = new Document();
|
||||
storeRaceLogIdentifier(raceLogIdentifier, result);
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogResultsAreOfficialEvent(event));
|
||||
return result;
|
||||
}
|
||||
|
||||
public Document storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDenoteForTrackingEvent event) {
|
||||
Document result = new Document();
|
||||
@@ -1143,6 +1151,14 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
storeTimePoint(event.getToInclusive(), result, toField);
|
||||
}
|
||||
}
|
||||
|
||||
private Object storeRaceLogResultsAreOfficialEvent(RaceLogResultsAreOfficialEvent event) {
|
||||
Document result = new Document();
|
||||
storeRaceLogEventProperties(event, result);
|
||||
result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogResultsAreOfficialEvent.class.getSimpleName());
|
||||
// currently there are no further properties; the event speaks for itself
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object storeRaceLogDenoteForTrackingEvent(RaceLogDenoteForTrackingEvent event) {
|
||||
Document result = new Document();
|
||||
|
||||
+7
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
|
||||
@@ -216,4 +217,10 @@ public class MongoRaceLogStoreVisitor implements RaceLogEventVisitor {
|
||||
Document object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event);
|
||||
mongoObjectFactory.storeRaceLogEventEvent(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaceLogResultsAreOfficialEvent event) {
|
||||
Document object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event);
|
||||
mongoObjectFactory.storeRaceLogEventEvent(object);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -16,7 +16,6 @@ import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.model.Filters;
|
||||
import com.mongodb.client.model.UpdateOptions;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.persistence.impl.FieldNames;
|
||||
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
|
||||
@@ -25,6 +24,7 @@ import com.sap.sailing.shared.persistence.device.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.TypeBasedServiceFinder;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -7,9 +7,9 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.util.ThreadPoolUtil;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -2,12 +2,12 @@ package com.sap.sailing.domain.persistence.racelog.tracking.impl;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.impl.FieldNames;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.FixMongoHandler;
|
||||
import com.sap.sailing.shared.persistence.device.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.TypeBasedServiceFinder;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -23,7 +23,6 @@ import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.model.Filters;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.impl.FieldNames;
|
||||
@@ -37,6 +36,7 @@ import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.TypeBasedServiceFinder;
|
||||
import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
+1
-1
@@ -49,7 +49,6 @@ import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPoint;
|
||||
@@ -72,6 +71,7 @@ import com.sap.sailing.server.interfaces.RacingEventService;
|
||||
import com.sap.sailing.server.util.WaitForTrackedRaceUtil;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,6 @@ import com.mongodb.client.MongoDatabase;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
@@ -33,6 +32,7 @@ import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServi
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.common.impl.TimeRangeImpl;
|
||||
|
||||
+1
-1
@@ -31,7 +31,6 @@ import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
@@ -44,6 +43,7 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.common.impl.TimeRangeImpl;
|
||||
|
||||
|
||||
+1
-1
@@ -34,7 +34,6 @@ import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.CompetitorRegistrationType;
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
|
||||
@@ -51,6 +50,7 @@ import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ Require-Bundle: com.sap.sailing.domain.shared.android,
|
||||
org.junit;bundle-version="4.8.2",
|
||||
com.sap.sse.common,
|
||||
com.sap.sailing.server.gateway.serialization.shared.android,
|
||||
org.mongodb.mongo-java-driver;bundle-version="3.6.4"
|
||||
org.mongodb.mongo-java-driver;bundle-version="3.6.4",
|
||||
com.sap.sse.shared.android
|
||||
Export-Package: com.sap.sailing.domain.racelog.tracking.test.mock
|
||||
Automatic-Module-Name: com.sap.sailing.domain.racelogtrackingadapter.testsupport
|
||||
Import-Package: com.sap.sailing.shared.persistence.device
|
||||
+1
-1
@@ -4,10 +4,10 @@ import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.GPSFixMovingJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.GPSFixMovingJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.tracking.GPSFixJsonHandler;
|
||||
import com.sap.sse.shared.json.JsonDeserializationException;
|
||||
|
||||
public class MockGPSFixJsonHandler implements GPSFixJsonHandler {
|
||||
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.racelog.tracking.test.mock;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
|
||||
public class SmartphoneImeiJsonHandler extends SmartphoneImeiSerializationHandler
|
||||
implements DeviceIdentifierJsonHandler {
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.racelog.tracking.test.mock;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.shared.persistence.device.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
|
||||
public class SmartphoneImeiMongoHandler extends SmartphoneImeiSerializationHandler
|
||||
implements DeviceIdentifierMongoHandler {
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.domain.racelog.tracking.test.mock;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class SmartphoneImeiSerializationHandler {
|
||||
|
||||
@@ -20,7 +20,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.server.gateway.serialization.shared.android,
|
||||
com.sap.sse.mail,
|
||||
org.mongodb.mongo-java-driver;bundle-version="3.6.4",
|
||||
com.sap.sailing.shared.persistence;bundle-version="1.0.0"
|
||||
com.sap.sailing.shared.persistence;bundle-version="1.0.0",
|
||||
com.sap.sse.shared.android
|
||||
Import-Package: com.google.zxing;version="3.1.0",
|
||||
com.mongodb,
|
||||
com.sap.sse.concurrent,
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ followBranchDeeplink=Clique no link seguinte para iniciar o app {0} e efetuar o
|
||||
welcomeTo=Bem-vindo(a) a
|
||||
buoyTender=navio-balizador
|
||||
buoyPingerAppName=SAP Sailing Buoy Pinger
|
||||
sailInSightAppName=SAP Sail Insight suportado pela SAP
|
||||
sailInSightAppName=SAP Sail InSight suportado pela SAP
|
||||
register=Registro
|
||||
|
||||
scanQRCodeOrVisitUrlToRegisterAs=Certifique-se de que tem o app {0} instalado. Depois, digitalize o QRCode seguinte ou clique no link utilizando o seu smartphone para se registrar como
|
||||
|
||||
Executable → Regular
+1
-1
@@ -3,7 +3,7 @@ followBranchDeeplink=点击以下链接启动 {0} 应用并注册为 <b>{1}</b>
|
||||
welcomeTo=欢迎使用
|
||||
buoyTender=浮标供应船
|
||||
buoyPingerAppName=SAP Sailing Buoy Pinger
|
||||
sailInSightAppName=SAP 提供支持的 Sail Insight
|
||||
sailInSightAppName=SAP 提供支持的 Sail InSight
|
||||
register=注册
|
||||
|
||||
scanQRCodeOrVisitUrlToRegisterAs=确保已安装 {0} 应用。然后,使用智能手机扫描以下二维码或点击链接注册
|
||||
|
||||
+2
-2
@@ -22,10 +22,8 @@ import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RegattaLogFixTrack
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaListener;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.GPSFixJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.GPSFixMovingJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.GPSFixJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.GPSFixMovingJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
|
||||
@@ -38,6 +36,8 @@ import com.sap.sse.MasterDataImportClassLoaderService;
|
||||
import com.sap.sse.common.TypeBasedServiceFinder;
|
||||
import com.sap.sse.replication.FullyInitializedReplicableTracker;
|
||||
import com.sap.sse.replication.Replicable;
|
||||
import com.sap.sse.shared.json.JsonDeserializer;
|
||||
import com.sap.sse.shared.json.JsonSerializer;
|
||||
import com.sap.sse.util.ServiceTrackerFactory;
|
||||
|
||||
public class Activator implements BundleActivator {
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
|
||||
public class PingDeviceIdentifierJsonHandler extends PingDeviceIdentifierSerializationHandler
|
||||
implements DeviceIdentifierJsonHandler {
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.shared.persistence.device.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
|
||||
public class PingDeviceIdentifierMongoHandler extends PingDeviceIdentifierSerializationHandler
|
||||
implements DeviceIdentifierMongoHandler {
|
||||
|
||||
+1
-1
@@ -3,8 +3,8 @@ package com.sap.sailing.domain.racelogtracking.impl;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.PingDeviceIdentifier;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class PingDeviceIdentifierSerializationHandler {
|
||||
|
||||
+1
-1
@@ -1,9 +1,9 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.SmartphoneUUIDSerializationHandler;
|
||||
import com.sap.sailing.shared.persistence.device.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
|
||||
public class SmartphoneUUIDMongoHandler extends SmartphoneUUIDSerializationHandler
|
||||
implements DeviceIdentifierMongoHandler {
|
||||
|
||||
+1
-1
@@ -5,11 +5,11 @@ import java.util.UUID;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
|
||||
+1
-1
@@ -5,11 +5,11 @@ import java.util.UUID;
|
||||
import org.bson.Document;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
|
||||
import com.sap.sailing.shared.persistence.device.DeviceIdentifierMongoHandler;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class TrackFileImportDeviceIdentifierMongoHandler implements DeviceIdentifierMongoHandler {
|
||||
|
||||
+1
-1
@@ -3,10 +3,10 @@ package com.sap.sailing.domain.racelogtracking.impl;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifierStringSerializationHandler;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class TrackFileImportDeviceIdentifierStringSerializationHandler implements
|
||||
|
||||
+5
-2
@@ -35,7 +35,6 @@ import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
@@ -63,6 +62,7 @@ import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
@@ -693,7 +693,10 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
|
||||
|
||||
private TimeRange getTrackingTimeRange() {
|
||||
final TimePoint startOfTracking = trackedRace.getStartOfTracking();
|
||||
final TimePoint endOfTracking = trackedRace.getEndOfTracking();
|
||||
// in case (erroneously) startOfTracking is *after* endOfTracking, return an empty interval starting and ending
|
||||
// at startOfTracking (see also bug 5354).
|
||||
final TimePoint endOfTracking = startOfTracking != null && trackedRace.getEndOfTracking() != null &&
|
||||
startOfTracking.after(trackedRace.getEndOfTracking()) ? startOfTracking : trackedRace.getEndOfTracking();
|
||||
return new TimeRangeImpl(startOfTracking == null ? TimePoint.BeginningOfTime : startOfTracking,
|
||||
endOfTracking == null ? TimePoint.EndOfTime : endOfTracking);
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.sap.sailing.domain.racelog.analyzing.test;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.ResultsAreOfficialFinder;
|
||||
|
||||
public class ResultsAreOfficialFinderTest extends RaceLogAnalyzerTest<ResultsAreOfficialFinder> {
|
||||
@Override
|
||||
protected ResultsAreOfficialFinder createAnalyzer(RaceLog raceLog) {
|
||||
return new ResultsAreOfficialFinder(raceLog);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFalseForNoResultsAreOfficialEvent() {
|
||||
RaceLogEvent event1 = createEvent(RaceLogEvent.class, 1);
|
||||
raceLog.add(event1);
|
||||
assertNull(analyzer.analyze());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleLast() {
|
||||
RaceLogResultsAreOfficialEvent event1 = createEvent(RaceLogResultsAreOfficialEvent.class, 1);
|
||||
RaceLogResultsAreOfficialEvent event2 = createEvent(RaceLogResultsAreOfficialEvent.class, 2);
|
||||
raceLog.add(event1);
|
||||
raceLog.add(event2);
|
||||
RaceLogResultsAreOfficialEvent result = analyzer.analyze();
|
||||
assertSame(event2, result);
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -197,11 +197,15 @@ public class RaceStateTest {
|
||||
|
||||
@Test
|
||||
public void testGetRacingProcedure() throws InterruptedException {
|
||||
|
||||
state.setRacingProcedure(nowMock, RacingProcedureType.RRS26);
|
||||
|
||||
GateStartRacingProcedure procedure = state.getTypedRacingProcedure(GateStartRacingProcedure.class);
|
||||
assertNull(procedure);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultsAreOfficial() {
|
||||
assertFalse(state.isResultsAreOfficial());
|
||||
state.setResultsAreOfficial(TimePoint.now());
|
||||
assertTrue(state.isResultsAreOfficial());
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -19,10 +19,9 @@ public interface AbstractLogEventAuthor extends Named, Comparable<AbstractLogEve
|
||||
/**
|
||||
* A lesser number represents a higher priority. Suggested priority levels:
|
||||
* <ol>
|
||||
* <li>Start Vessel</li>
|
||||
* <li>Finish Vessel</li>
|
||||
* <li>Race Officer on a Vessel</li>
|
||||
* <li>Shore Control</li>
|
||||
* <li>Compatibility priority for old events</li>
|
||||
* <li>Demo Mode</li>
|
||||
* </ol>
|
||||
*/
|
||||
int getPriority();
|
||||
|
||||
+2
@@ -66,4 +66,6 @@ public interface RaceLogEventVisitor {
|
||||
void visit(RaceLogORCScratchBoatEvent event);
|
||||
|
||||
void visit(RaceLogORCImpliedWindSourceEvent event);
|
||||
|
||||
void visit(RaceLogResultsAreOfficialEvent event);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.sap.sailing.domain.abstractlog.race;
|
||||
|
||||
public interface RaceLogResultsAreOfficialEvent extends RaceLogEvent {
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
|
||||
/**
|
||||
* Analysis returns the most recent {@link RaceLogResultsAreOfficialEvent}.
|
||||
* <p>
|
||||
*
|
||||
* If there is no {@link RaceLogResultsAreOfficialEvent} in log, <code>null</code> is returned. Otherwise a single
|
||||
* {@link RaceLogResultsAreOfficialEvent} is returned.
|
||||
*
|
||||
*/
|
||||
public class ResultsAreOfficialFinder extends RaceLogAnalyzer<RaceLogResultsAreOfficialEvent> {
|
||||
|
||||
public ResultsAreOfficialFinder(RaceLog raceLog) {
|
||||
super(raceLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RaceLogResultsAreOfficialEvent performAnalysis() {
|
||||
for (final RaceLogEvent e : getAllEventsDescending()) {
|
||||
if (e instanceof RaceLogResultsAreOfficialEvent) {
|
||||
return (RaceLogResultsAreOfficialEvent) e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+6
@@ -18,6 +18,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
|
||||
@@ -168,4 +169,9 @@ public abstract class AbstractRaceLogChangedVisitor implements RaceLogEventVisit
|
||||
public void visit(RaceLogORCImpliedWindSourceEvent event) {
|
||||
notifyListenerAboutEventAdded(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaceLogResultsAreOfficialEvent event) {
|
||||
notifyListenerAboutEventAdded(event);
|
||||
}
|
||||
}
|
||||
+6
@@ -17,6 +17,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
|
||||
@@ -174,4 +175,9 @@ public abstract class BaseRaceLogEventVisitor implements RaceLogEventVisitor {
|
||||
public void visit(RaceLogORCImpliedWindSourceEvent event) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaceLogResultsAreOfficialEvent event) {
|
||||
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
public class RaceLogResultsAreOfficialEventImpl extends RaceLogEventImpl implements RaceLogResultsAreOfficialEvent {
|
||||
private static final long serialVersionUID = -1796278009919318553L;
|
||||
|
||||
public RaceLogResultsAreOfficialEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
|
||||
AbstractLogEventAuthor author, Serializable pId, int pPassId) {
|
||||
super(createdAt, logicalTimePoint, author, pId, pPassId);
|
||||
}
|
||||
|
||||
public RaceLogResultsAreOfficialEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author, int pPassId) {
|
||||
this(now(), logicalTimePoint, author, randId(), pPassId);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void accept(RaceLogEventVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortInfo() {
|
||||
return "Indicates that the results of this race are now official";
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
|
||||
import com.sap.sailing.domain.abstractlog.race.scoring.AdditionalScoringInformationType;
|
||||
import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent;
|
||||
@@ -146,7 +147,6 @@ public interface RaceState extends ReadonlyRaceState {
|
||||
|
||||
/**
|
||||
* Enters a new wind fix for this race.
|
||||
* @param isMagnetic TODO
|
||||
*/
|
||||
void setWindFix(TimePoint now, Wind wind, boolean isMagnetic);
|
||||
|
||||
@@ -162,4 +162,14 @@ public interface RaceState extends ReadonlyRaceState {
|
||||
* forces a RaceStateUpdate
|
||||
*/
|
||||
void forceUpdate();
|
||||
|
||||
/**
|
||||
* Marks the results of the race to which this state belongs as official, using a
|
||||
* {@link RaceLogResultsAreOfficialEvent}.
|
||||
*
|
||||
* @param timePoint
|
||||
* the time point at which the results were declared official
|
||||
* @see #isResultsAreOfficial()
|
||||
*/
|
||||
void setResultsAreOfficial(TimePoint timePoint);
|
||||
}
|
||||
+1
-1
@@ -18,5 +18,5 @@ public interface RaceStateChangedListener {
|
||||
void onCourseDesignChanged(ReadonlyRaceState state);
|
||||
void onWindFixChanged(ReadonlyRaceState state);
|
||||
void onTagEventsChanged(ReadonlyRaceState state);
|
||||
|
||||
void onResultsAreOfficialChanged(ReadonlyRaceState state);
|
||||
}
|
||||
+5
@@ -102,6 +102,11 @@ public interface ReadonlyRaceState extends RaceStateEventProcessor {
|
||||
* Gets the races overall status.
|
||||
*/
|
||||
RaceLogRaceStatus getStatus();
|
||||
|
||||
/**
|
||||
* Tells if the results found for this race have been confirmed officially.
|
||||
*/
|
||||
boolean isResultsAreOfficial();
|
||||
|
||||
/**
|
||||
* If there is a start time set for the current pass, returns it. Otherwise <code>null</code>.
|
||||
|
||||
+4
@@ -68,4 +68,8 @@ public abstract class BaseRaceStateChangedListener implements RaceStateChangedLi
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResultsAreOfficialChanged(ReadonlyRaceState state) {
|
||||
|
||||
}
|
||||
}
|
||||
+7
@@ -118,4 +118,11 @@ public class RaceStateChangedListeners extends HashSet<RaceStateChangedListener>
|
||||
listener.onTagEventsChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResultsAreOfficialChanged(ReadonlyRaceState state) {
|
||||
for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) {
|
||||
listener.onResultsAreOfficialChanged(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -20,6 +20,7 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFlagEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogProtestStartTimeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogResultsAreOfficialEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartProcedureChangedEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogWindFixEventImpl;
|
||||
@@ -135,6 +136,11 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState {
|
||||
// ensure caches are synched
|
||||
forceUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResultsAreOfficial(TimePoint timePoint) {
|
||||
raceLog.add(new RaceLogResultsAreOfficialEventImpl(timePoint, author, raceLog.getCurrentPassId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtestTime(TimePoint now, TimeRange protestTime) {
|
||||
|
||||
+16
-2
@@ -13,6 +13,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogChangedListener;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogDependentStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogTagEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
|
||||
@@ -27,6 +28,7 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceStatusAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceStatusAnalyzer.Clock;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RacingProcedureTypeAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.ResultsAreOfficialFinder;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinderResult;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.TagFinder;
|
||||
@@ -165,6 +167,7 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
private final FinishingTimeFinder finishingTimeAnalyzer;
|
||||
private final FinishedTimeFinder finishedTimeAnalyzer;
|
||||
private final ProtestTimeFinder protestTimeAnalyzer;
|
||||
private final ResultsAreOfficialFinder resultsAreOfficialAnalyzer;
|
||||
|
||||
private final FinishPositioningListFinder finishPositioningListAnalyzer;
|
||||
private final ConfirmedFinishPositioningListFinder confirmedFinishPositioningListAnalyzer;
|
||||
@@ -205,6 +208,8 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
|
||||
private Iterable<RaceLogTagEvent> cachedTagEvents;
|
||||
|
||||
private boolean cachedResultsAreOfficial;
|
||||
|
||||
private int cachedPassId;
|
||||
private StartTimeFinderResult cachedStartTimeFinderResult;
|
||||
private TimePoint cachedFinishingTime;
|
||||
@@ -250,19 +255,18 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
this.finishingTimeAnalyzer = new FinishingTimeFinder(raceLog);
|
||||
this.finishedTimeAnalyzer = new FinishedTimeFinder(raceLog);
|
||||
this.protestTimeAnalyzer = new ProtestTimeFinder(raceLog);
|
||||
this.resultsAreOfficialAnalyzer = new ResultsAreOfficialFinder(raceLog);
|
||||
this.finishPositioningListAnalyzer = new FinishPositioningListFinder(raceLog);
|
||||
this.confirmedFinishPositioningListAnalyzer = new ConfirmedFinishPositioningListFinder(raceLog);
|
||||
this.courseDesignerAnalyzer = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ false);
|
||||
this.lastWindFixAnalyzer = new LastWindFixFinder(raceLog);
|
||||
this.tagAnalyzer = new TagFinder(raceLog);
|
||||
|
||||
this.raceStateToObserveListener = new BaseRaceStateChangedListener() {
|
||||
@Override
|
||||
public void onStartTimeChanged(ReadonlyRaceState state) {
|
||||
update();
|
||||
}
|
||||
};
|
||||
|
||||
this.cachedRacingProcedureTypeNoFallback = determineInitialProcedureType();
|
||||
if (this.cachedRacingProcedureTypeNoFallback == null
|
||||
|| this.cachedRacingProcedureTypeNoFallback == RacingProcedureType.UNKNOWN) {
|
||||
@@ -368,6 +372,11 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
return cachedRaceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResultsAreOfficial() {
|
||||
return cachedResultsAreOfficial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds out whether any of the time points in {@link #timePointsWhenRaceStatusMayChange} falls into the time range
|
||||
* provided. In this case we assume that a race status update may have happened between the time point when the
|
||||
@@ -581,6 +590,11 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
cachedTagEvents = tagEvents;
|
||||
changedListeners.onTagEventsChanged(this);
|
||||
}
|
||||
final RaceLogResultsAreOfficialEvent resultsAreOfficialEvent = resultsAreOfficialAnalyzer.analyze();
|
||||
if ((resultsAreOfficialEvent != null) != cachedResultsAreOfficial) {
|
||||
cachedResultsAreOfficial = resultsAreOfficialEvent != null;
|
||||
changedListeners.onResultsAreOfficialChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-7
@@ -17,20 +17,18 @@ public class DetailedRaceInfo extends SimpleRaceInfo {
|
||||
private final String eventName;
|
||||
private final String leaderboardDisplayName;
|
||||
private final String leaderboardName;
|
||||
private final UUID eventID;
|
||||
private EventType eventType;
|
||||
|
||||
public DetailedRaceInfo(RegattaAndRaceIdentifier identifier, String leaderboardName, String leaderboardDisplayName,
|
||||
TimePoint timePoint, UUID eventId, String eventName, EventType eventType,
|
||||
URL remoteUrl) {
|
||||
super(identifier, timePoint, remoteUrl);
|
||||
super(identifier, timePoint, remoteUrl, eventId);
|
||||
if (leaderboardName == null || eventId == null) {
|
||||
throw new IllegalStateException("DetailedRaceInfo Data is not allowed to contain any null values!");
|
||||
}
|
||||
this.leaderboardName = leaderboardName;
|
||||
this.leaderboardDisplayName = leaderboardDisplayName;
|
||||
this.eventName = eventName;
|
||||
this.eventID = eventId;
|
||||
this.eventType = eventType;
|
||||
}
|
||||
|
||||
@@ -54,10 +52,6 @@ public class DetailedRaceInfo extends SimpleRaceInfo {
|
||||
return leaderboardName;
|
||||
}
|
||||
|
||||
public UUID getEventID() {
|
||||
return eventID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DetailedRaceInfo [identifier=" + getIdentifier() + ", leaderboardName=" + leaderboardName
|
||||
|
||||
+14
-1
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.anniversary;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
@@ -20,19 +21,21 @@ public class SimpleRaceInfo implements Serializable {
|
||||
private final RegattaAndRaceIdentifier identifier;
|
||||
private final TimePoint startOfRace;
|
||||
private final URL remoteUrl;
|
||||
protected final UUID eventID;
|
||||
|
||||
/**
|
||||
* @param remoteUrl
|
||||
* use {@code null} to mean "local"; a local server does not necessarily know under which URL it is being
|
||||
* reached and therefore cannot provide this
|
||||
*/
|
||||
public SimpleRaceInfo(RegattaAndRaceIdentifier identifier, TimePoint startOfRace, URL remoteUrl) {
|
||||
public SimpleRaceInfo(RegattaAndRaceIdentifier identifier, TimePoint startOfRace, URL remoteUrl, UUID eventId) {
|
||||
if (identifier == null || startOfRace == null) {
|
||||
throw new IllegalStateException("SimpleRaceInfo Data is not allowed to contain any null values!");
|
||||
}
|
||||
this.identifier = identifier;
|
||||
this.startOfRace = startOfRace;
|
||||
this.remoteUrl = remoteUrl;
|
||||
this.eventID = eventId;
|
||||
}
|
||||
|
||||
public RegattaAndRaceIdentifier getIdentifier() {
|
||||
@@ -51,12 +54,17 @@ public class SimpleRaceInfo implements Serializable {
|
||||
return startOfRace;
|
||||
}
|
||||
|
||||
public UUID getEventID() {
|
||||
return eventID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
|
||||
result = prime * result + ((startOfRace == null) ? 0 : startOfRace.hashCode());
|
||||
result = prime * result + ((eventID == null) ? 0 : eventID.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -79,6 +87,11 @@ public class SimpleRaceInfo implements Serializable {
|
||||
return false;
|
||||
} else if (!startOfRace.equals(other.startOfRace))
|
||||
return false;
|
||||
if (eventID == null) {
|
||||
if (other.eventID != null)
|
||||
return false;
|
||||
} else if (!eventID.equals(other.eventID))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+47
@@ -1,8 +1,12 @@
|
||||
package com.sap.sailing.domain.base.configuration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.domain.base.Venue;
|
||||
import com.sap.sse.common.Named;
|
||||
import com.sap.sse.common.WithID;
|
||||
import com.sap.sse.security.shared.WithQualifiedObjectIdentifier;
|
||||
@@ -38,4 +42,47 @@ public interface DeviceConfiguration extends WithID, WithQualifiedObjectIdentifi
|
||||
* Copy me.
|
||||
*/
|
||||
DeviceConfiguration copy();
|
||||
|
||||
/**
|
||||
* The optional ID of an {@link EventBase} object that can be resolved by the server and which has a
|
||||
* {@link EventBase#getVenue() venue} with {@link Venue#getCourseAreas() course areas}. If a valid event ID is set
|
||||
* here, any {@link #getCourseAreaId() course area} specified by ID should be part of the event's venue, and UIs as
|
||||
* well as service methods taking in a {@link DeviceConfiguration} shall make sure to validate this constraint.
|
||||
* Likewise, if an event ID of an existing event is specified, the {@link #getAllowedCourseAreaNames()} results are
|
||||
* expected to match {@link CourseArea#getName() course area names} of those course areas in the event's venue.
|
||||
*/
|
||||
Optional<UUID> getEventId();
|
||||
|
||||
/**
|
||||
* @param eventId if {@code null}, an {@link Optional#empty() empty} optional will result from {@link #getEventId()}.
|
||||
*/
|
||||
void setEventId(UUID eventId);
|
||||
|
||||
/**
|
||||
* If a valid {@link #getEventId() event ID} is specified, a course area ID can be specified here to default the
|
||||
* log-in to that course area. This may come in handy if devices are to be pre-configured for hand-out to a specific
|
||||
* course area only. Make sure that this ID references a course area whose name is part of the result of calling
|
||||
* {@link #getAllowedCourseAreaNames()}.
|
||||
*/
|
||||
Optional<UUID> getCourseAreaId();
|
||||
|
||||
/**
|
||||
* @param courseAreaId if {@code null}, an {@link Optional#empty() empty} optional will result from {@link #getCourseAreaId()}.
|
||||
*/
|
||||
void setCourseAreaId(UUID courseAreaId);
|
||||
|
||||
/**
|
||||
* During the Race Manager App's login process the user is asked to choose a "role" such as "Race Officer on the
|
||||
* Water" or "Shore Control." These map to numeric priorities, with lesser numerical values taking higher
|
||||
* precedence. "Race Officer on the Water" would map to the number 1, "Shore Control" to 2. An exceptional priority
|
||||
* of 3 may be translated by the app into "Demo Mode" if that is permissible. The field may not be set, then
|
||||
* returning an empty {@link Optional}, meaning that this device configuration leaves it up for the user to choose
|
||||
* the priority during the login process.
|
||||
*/
|
||||
Optional<Integer> getPriority();
|
||||
|
||||
/**
|
||||
* Sets the {@link #getPriority() priority}.
|
||||
*/
|
||||
void setPriority(Integer priority);
|
||||
}
|
||||
+40
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.base.configuration.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.base.configuration.DeviceConfiguration;
|
||||
@@ -21,6 +22,9 @@ public class DeviceConfigurationImpl extends NamedImpl implements DeviceConfigur
|
||||
private String resultsMailRecipient;
|
||||
private List<String> byNameDesignerCourseNames;
|
||||
private final UUID id;
|
||||
private UUID eventId;
|
||||
private UUID courseAreaId;
|
||||
private Integer priority;
|
||||
|
||||
public DeviceConfigurationImpl(RegattaConfiguration regattaConfiguration, UUID id, String name) {
|
||||
super(name);
|
||||
@@ -37,11 +41,47 @@ public class DeviceConfigurationImpl extends NamedImpl implements DeviceConfigur
|
||||
this.regattaConfiguration = proceduresConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<UUID> getEventId() {
|
||||
return Optional.ofNullable(eventId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEventId(UUID eventId) {
|
||||
this.eventId = eventId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<UUID> getCourseAreaId() {
|
||||
return Optional.ofNullable(courseAreaId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCourseAreaId(UUID courseAreaId) {
|
||||
this.courseAreaId = courseAreaId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> getPriority() {
|
||||
return Optional.ofNullable(priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriority(Integer priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* May return {@code null}
|
||||
*/
|
||||
@Override
|
||||
public RegattaConfiguration getRegattaConfiguration() {
|
||||
return regattaConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* May return {@code null}
|
||||
*/
|
||||
@Override
|
||||
public List<String> getAllowedCourseAreaNames() {
|
||||
return allowedCourseAreaNames;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.domain.racelogtracking;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -3,8 +3,8 @@ package com.sap.sailing.domain.racelogtracking;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class SmartphoneUUIDSerializationHandler {
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelogtracking.PlaceHolderDeviceIdentifier;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/**
|
||||
|
||||
-28
@@ -1,20 +1,15 @@
|
||||
package com.sap.sailing.domain.orc;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.junit.Rule;
|
||||
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
|
||||
public abstract class AbstractORCCertificateImporterTest {
|
||||
@@ -29,27 +24,4 @@ public abstract class AbstractORCCertificateImporterTest {
|
||||
ORCCertificate milan = importer.getCertificateById(expectedCertificateId);
|
||||
assertNotNull(milan);
|
||||
}
|
||||
|
||||
@FailIfNoValidOrcCertificates
|
||||
protected void testSimpleOnlineFileRead(String rmsOrJsonFormat) throws IOException, ParseException, InterruptedException {
|
||||
Collection<ORCCertificate> certificates = customIgnoreRule.getAvailableCerts();
|
||||
final ORCCertificate cert = certificates.stream().findFirst().get();
|
||||
String countryCode = cert.getIssuingCountry().getThreeLetterIOCCode();
|
||||
String url = String.format("https://data.orc.org/public/WPub.dll?action=DownRMS&CountryId=%s&ext=%s", countryCode, rmsOrJsonFormat);
|
||||
ORCCertificatesCollection importer = ORCCertificatesImporter.INSTANCE.read(new URL(url).openStream());
|
||||
ORCCertificate someValidCert = null, referenceCert = null;
|
||||
for (ORCCertificate orcCertificate : certificates) {
|
||||
someValidCert = importer.getCertificateById(orcCertificate.getId());
|
||||
if (someValidCert != null) {
|
||||
referenceCert = orcCertificate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertNotNull("None of the certificates "+String.join(", ", Util.map(certificates, c->c.toString()))+
|
||||
" was found when importing the country document from "+url, someValidCert);
|
||||
assertNotNull(referenceCert);
|
||||
assertEquals(referenceCert.getGPHInSecondsToTheMile(), someValidCert.getGPHInSecondsToTheMile(), 0.0000001);
|
||||
assertTrue(referenceCert.getWindwardLeewardSpeedPrediction().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificate.NAUTICAL_MILE).asSeconds() > 10);
|
||||
assertTrue(referenceCert.getLongDistanceSpeedPredictions().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificate.NAUTICAL_MILE).asSeconds() > 10);
|
||||
}
|
||||
}
|
||||
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/orc/FailIfNoValidOrcCertificateRule.java
Regular → Executable
+43
-28
@@ -1,21 +1,22 @@
|
||||
package com.sap.sailing.domain.orc;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sailing.domain.orc.ORCPublicCertificateDatabase.CertificateHandle;
|
||||
import com.sap.sailing.domain.orc.ORCPublicCertificateDatabase.CountryOverview;
|
||||
import com.sap.sailing.domain.orc.impl.ORCPublicCertificateDatabaseImpl;
|
||||
import com.sap.sse.common.CountryCode;
|
||||
import com.sap.sse.common.CountryCodeFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/***
|
||||
* A IgnoreInvalidOrcCerticatesRule is an implementation of TestRule. This class execution depends on
|
||||
@@ -34,9 +35,40 @@ import com.sap.sse.common.CountryCodeFactory;
|
||||
*/
|
||||
|
||||
public class FailIfNoValidOrcCertificateRule implements TestRule {
|
||||
private ORCPublicCertificateDatabase db = new ORCPublicCertificateDatabaseImpl();
|
||||
private static final Logger logger = Logger.getLogger(FailIfNoValidOrcCertificateRule.class.getName());
|
||||
private static final int NUMBER_OF_CERTIFICATES_TO_PROBE = 3;
|
||||
|
||||
private List<ORCCertificate> availableCerts;
|
||||
private static List<ORCCertificate> availableCerts;
|
||||
private static boolean certificateExists;
|
||||
|
||||
static {
|
||||
certificateExists = false;
|
||||
availableCerts = new ArrayList<>();
|
||||
final ORCPublicCertificateDatabase db = new ORCPublicCertificateDatabaseImpl();
|
||||
CountryOverview countryWithMostValidCertificates;
|
||||
try {
|
||||
countryWithMostValidCertificates = StreamSupport
|
||||
.stream(db.getCountriesWithValidCertificates().spliterator(), /* parallel */ false)
|
||||
.max((c1, c2) -> c1.getCertCount() - c2.getCertCount()).get();
|
||||
Iterable<CertificateHandle> certificateHandles = db.search(countryWithMostValidCertificates.getIssuingCountry(),
|
||||
countryWithMostValidCertificates.getVPPYear(), null, null, null, null, /* includeInvalid */ false);
|
||||
final List<CertificateHandle> randomSubset = new ArrayList<>();
|
||||
Util.addAll(certificateHandles, randomSubset);
|
||||
Collections.shuffle(randomSubset);
|
||||
Iterable<ORCCertificate> orcCertificates = db.getCertificates(randomSubset.subList(0, NUMBER_OF_CERTIFICATES_TO_PROBE));
|
||||
orcCertificates.forEach(availableCerts::add);
|
||||
if (orcCertificates.iterator().hasNext()) {
|
||||
certificateExists = true;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.WARNING, "Problem trying to fetch certificates tests");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public FailIfNoValidOrcCertificateRule() {
|
||||
logger.info("FailIfNoValidOrcCertificateRule created");
|
||||
}
|
||||
|
||||
public Collection<ORCCertificate> getAvailableCerts() {
|
||||
return Collections.unmodifiableCollection(availableCerts);
|
||||
@@ -54,9 +86,8 @@ public class FailIfNoValidOrcCertificateRule implements TestRule {
|
||||
public IgnorableStatement(Statement base, Description description) {
|
||||
this.base = base;
|
||||
this.description = description;
|
||||
availableCerts = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* This method executes for every test case having {@link TestRule} annotation of
|
||||
* {@link FailIfNoValidOrcCertificateRule} class. Assume statement at the end of this method evaluates whether
|
||||
@@ -64,28 +95,12 @@ public class FailIfNoValidOrcCertificateRule implements TestRule {
|
||||
*/
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
boolean certificateExists = true;
|
||||
FailIfNoValidOrcCertificates annotation = description.getAnnotation(FailIfNoValidOrcCertificates.class);
|
||||
if (annotation != null) {
|
||||
int year = LocalDate.now().getYear();
|
||||
certificateExists = false;
|
||||
for (CountryCode cc : CountryCodeFactory.INSTANCE.getAll()) {
|
||||
try {
|
||||
Iterable<CertificateHandle> certificateHandles = db.search(cc, year, null, null, null, null, /* includeInvalid */ false);
|
||||
Iterable<ORCCertificate> orcCertificates = db.getCertificates(certificateHandles);
|
||||
orcCertificates.forEach(availableCerts::add);
|
||||
if (orcCertificates.iterator().hasNext()) {
|
||||
certificateExists = true;
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// Exceptions are ignored because we are searching for any countries orc certificate's
|
||||
// availability.
|
||||
}
|
||||
}
|
||||
if (annotation == null || certificateExists) {
|
||||
base.evaluate();
|
||||
} else if (annotation != null) {
|
||||
logger.warning("No certificates found. Are we at the beginning of a new year (January)? Then this may be okay. Otherwise, please check what's up!");
|
||||
}
|
||||
Assert.assertTrue(certificateExists);
|
||||
base.evaluate();
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -7,10 +7,9 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/***
|
||||
* A IgnoreInvalidOrcCerticates is a annotation which is used to identify whether we need to execute the
|
||||
* {@link FailIfNoValidOrcCertificateRule} for that particular test case. i.e. you can find
|
||||
* the usage of {@link FailIfNoValidOrcCertificates} in
|
||||
* {@link TestORCPublicCertificateDatabase} class.
|
||||
* A {@link FailIfNoValidOrcCertificates} is an annotation which is used to identify whether we need to execute the
|
||||
* {@link FailIfNoValidOrcCertificateRule} for that particular test case. i.e. you can find the usage of
|
||||
* {@link FailIfNoValidOrcCertificates} in {@link TestORCPublicCertificateDatabase} class.
|
||||
*
|
||||
* @author Usman Ali
|
||||
*
|
||||
|
||||
+13
-4
@@ -1,13 +1,18 @@
|
||||
package com.sap.sailing.domain.orc;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
|
||||
|
||||
public class TestORCCertificateImporterJSON extends AbstractORCCertificateImporterTest {
|
||||
|
||||
@Test
|
||||
public void testSimpleLocalJSONFileRead() throws IOException, ParseException {
|
||||
testSimpleLocalFileRead("GER2019.json", "GER20041179");
|
||||
@@ -17,10 +22,14 @@ public class TestORCCertificateImporterJSON extends AbstractORCCertificateImport
|
||||
public void testReadingJSONWithSpecificBins() throws IOException, ParseException {
|
||||
testSimpleLocalFileRead("03600000HUH.json", "03600000HUH");
|
||||
}
|
||||
|
||||
|
||||
@FailIfNoValidOrcCertificates
|
||||
@Test
|
||||
public void testSimpleOnlineJSONFileRead() throws IOException, ParseException, InterruptedException {
|
||||
testSimpleOnlineFileRead("json");
|
||||
public void testSimpleOnlineFileRead() throws IOException, ParseException, InterruptedException {
|
||||
Collection<ORCCertificate> certificates = customIgnoreRule.getAvailableCerts();
|
||||
final ORCCertificate referenceCert = certificates.stream().findFirst().get();
|
||||
assertNotNull(referenceCert);
|
||||
assertTrue(referenceCert.getWindwardLeewardSpeedPrediction().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificate.NAUTICAL_MILE).asSeconds() > 10);
|
||||
assertTrue(referenceCert.getLongDistanceSpeedPredictions().get(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0]).getDuration(ORCCertificate.NAUTICAL_MILE).asSeconds() > 10);
|
||||
}
|
||||
}
|
||||
-6
@@ -36,12 +36,6 @@ public class TestORCCertificateImporterRMS extends AbstractORCCertificateImporte
|
||||
assertEquals(500.0, runAllowanceAtTenKnots.asSeconds(), 0.01);
|
||||
}
|
||||
|
||||
@FailIfNoValidOrcCertificates
|
||||
@Test
|
||||
public void testSimpleOnlineRMSFileRead() throws IOException, ParseException, InterruptedException {
|
||||
testSimpleOnlineFileRead("rms");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRMSFileReadWithIdenticalSailnumbers() throws IOException, ParseException {
|
||||
// additional test to ensure certificates with same sailnumbers but different ids are equally parsed and saved
|
||||
|
||||
+20
-3
@@ -10,6 +10,10 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.commons.math.ArgumentOutsideDomainException;
|
||||
import org.apache.commons.math.FunctionEvaluationException;
|
||||
@@ -20,6 +24,8 @@ import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ErrorCollector;
|
||||
import org.w3c.dom.DOMException;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
|
||||
@@ -31,7 +37,9 @@ import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveCourseImpl;
|
||||
import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveLegImpl;
|
||||
import com.sap.sailing.domain.orc.impl.ORCCertificatesJsonImporter;
|
||||
import com.sap.sailing.domain.orc.impl.ORCPerformanceCurveImpl;
|
||||
import com.sap.sailing.domain.orc.impl.ORCPublicCertificateDatabaseImpl;
|
||||
import com.sap.sse.common.Bearing;
|
||||
import com.sap.sse.common.CountryCode;
|
||||
import com.sap.sse.common.Distance;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Speed;
|
||||
@@ -44,6 +52,8 @@ import com.sap.sse.common.impl.DegreeBearingImpl;
|
||||
*
|
||||
*/
|
||||
public class TestORCPerformanceCurve {
|
||||
private static final Logger logger = Logger.getLogger(TestORCPerformanceCurve.class.getName());
|
||||
|
||||
// set true to see all the differences i
|
||||
private final boolean collectErrors = true;
|
||||
|
||||
@@ -81,7 +91,8 @@ public class TestORCPerformanceCurve {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void initialize() throws IOException, ParseException {
|
||||
public static void initialize() throws IOException, ParseException, DOMException, SAXException,
|
||||
ParserConfigurationException, java.text.ParseException {
|
||||
List<ORCPerformanceCurveLeg> legs = new ArrayList<>();
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(2.23), new DegreeBearingImpl(10)));
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(2.00), new DegreeBearingImpl(170)));
|
||||
@@ -89,7 +100,7 @@ public class TestORCPerformanceCurve {
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.03), new DegreeBearingImpl(15)));
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.03), new DegreeBearingImpl(165)));
|
||||
legs.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1.17), new DegreeBearingImpl(180)));
|
||||
alturaCourse = new ORCPerformanceCurveCourseImpl(legs); //this course is the same course as seen in the Altura "IMS Explanation" sheet
|
||||
alturaCourse = new ORCPerformanceCurveCourseImpl(legs); // this course is the same course as seen in the Altura "IMS Explanation" sheet
|
||||
// Local File:
|
||||
File fileGER = new File(RESOURCES + "GER2019.json");
|
||||
importerLocal = new ORCCertificatesJsonImporter().read(new FileInputStream(fileGER));
|
||||
@@ -97,7 +108,13 @@ public class TestORCPerformanceCurve {
|
||||
File fileWithSpecificBins = new File(RESOURCES + "newFormatCertificate.json");
|
||||
importerWithSpecificBins = new ORCCertificatesJsonImporter().read(new FileInputStream(fileWithSpecificBins));
|
||||
// Online File:
|
||||
importerOnline = new ORCCertificatesJsonImporter().read(new URL("https://data.orc.org/public/WPub.dll?action=DownBoatRMS&CountryId=GER&ext=json").openStream());
|
||||
final CountryCode countryWithMostValidCertificates = StreamSupport
|
||||
.stream(ORCPublicCertificateDatabaseImpl.INSTANCE.getCountriesWithValidCertificates().spliterator(),
|
||||
/* parallel */ false)
|
||||
.max((c1, c2) -> c1.getCertCount() - c2.getCertCount()).get().getIssuingCountry();
|
||||
logger.info("Trying to read country certificates for "+countryWithMostValidCertificates);
|
||||
importerOnline = new ORCCertificatesJsonImporter().read(new URL("https://data.orc.org/public/WPub.dll?action=DownBoatRMS&CountryId="+
|
||||
countryWithMostValidCertificates.getThreeLetterIOCCode()+"&ext=json").openStream());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+9
-1
@@ -160,6 +160,14 @@ public class TestORCPublicCertificateDatabase {
|
||||
* boat class name; could be set to cert.getBoatClassName() but there are
|
||||
* deviations in ORC DBs and query API, so leaving null:
|
||||
*/ null, /* includeInvalid */ false);
|
||||
if (Util.isEmpty(certHandles)) {
|
||||
// there were certs; get one from the previous year
|
||||
certHandles = db.search(null, LocalDate.now().getYear()-1, null, cert.getBoatName(),
|
||||
cert.getSailNumber(), /*
|
||||
* boat class name; could be set to cert.getBoatClassName() but there are
|
||||
* deviations in ORC DBs and query API, so leaving null:
|
||||
*/ null, /* includeInvalid */ false);
|
||||
}
|
||||
Optional<CertificateHandle> certificateHandle = Optional.ofNullable(certHandles.iterator().hasNext() ? certHandles.iterator().next() : null);
|
||||
assertTrue("No certificate found for handle "+certificateHandle+
|
||||
" extracted from certificates "+certificates, certificateHandle.isPresent());
|
||||
@@ -188,7 +196,7 @@ public class TestORCPublicCertificateDatabase {
|
||||
new BoatClassImpl(orcCertificate.getBoatClassName(), true)));
|
||||
}
|
||||
for (Future<Set<ORCCertificate>> futureResult : futures) {
|
||||
isYearFound = isYearFound || assertFoundYear(futureResult.get(), year);
|
||||
isYearFound = isYearFound || assertFoundYear(futureResult.get(), year) || assertFoundYear(futureResult.get(), year-1);
|
||||
}
|
||||
assertTrue(isYearFound);
|
||||
}
|
||||
|
||||
+1
-2
@@ -15,8 +15,8 @@ import com.sap.sailing.domain.tractracadapter.impl.TracTracRaceTrackerImpl;
|
||||
* @author Frederik Petersen
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface LoadingQueueDoneCallBack {
|
||||
|
||||
/**
|
||||
* Callback method
|
||||
* See {@link AbstractReceiverWithQueue} and {@link TracTracRaceTrackerImpl} for example usage.
|
||||
@@ -24,5 +24,4 @@ public interface LoadingQueueDoneCallBack {
|
||||
* @param receiver Receiver that handled the marked event.
|
||||
*/
|
||||
void loadingQueueDone(Receiver receiver);
|
||||
|
||||
}
|
||||
+10
-2
@@ -32,16 +32,19 @@ import com.tractrac.subscription.lib.api.race.IRaceCompetitorListener;
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CompetitorChangeReceiver extends AbstractReceiverWithQueue<IRaceCompetitor, Void, Void> {
|
||||
public class CompetitorChangeReceiver extends AbstractReceiverWithQueue<IRaceCompetitor, Void, Void>
|
||||
implements OfficialCompetitorUpdateProvider {
|
||||
private static final Logger logger = Logger.getLogger(CompetitorChangeReceiver.class.getName());
|
||||
private final IRaceCompetitorListener listener;
|
||||
private final RaceAndCompetitorStatusWithRaceLogReconciler reconciler;
|
||||
|
||||
public CompetitorChangeReceiver(DynamicTrackedRegatta trackedRegatta, IEvent tractracEvent,
|
||||
IRace tractracRace, Simulator simulator, DomainFactory domainFactory,
|
||||
IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, long timeoutInMilliseconds, RaceAndCompetitorStatusWithRaceLogReconciler raceAndCompetitorStatusWithRaceLogReconciler) {
|
||||
IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, long timeoutInMilliseconds,
|
||||
RaceAndCompetitorStatusWithRaceLogReconciler raceAndCompetitorStatusWithRaceLogReconciler) {
|
||||
super(domainFactory, tractracEvent, trackedRegatta, simulator, eventSubscriber, raceSubscriber, timeoutInMilliseconds);
|
||||
reconciler = raceAndCompetitorStatusWithRaceLogReconciler;
|
||||
reconciler.setOfficialCompetitorUpdateProvider(this);
|
||||
listener = new IRaceCompetitorListener() {
|
||||
@Override
|
||||
public void addRaceCompetitor(IRaceCompetitor raceCompetitor) {
|
||||
@@ -99,4 +102,9 @@ public class CompetitorChangeReceiver extends AbstractReceiverWithQueue<IRaceCom
|
||||
+ ". Dropping competitor change event " + event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runWhenNoMoreOfficialCompetitorUpdatesPending(Runnable runnable) {
|
||||
callBackWhenLoadingQueueIsDone(receiver->runnable.run());
|
||||
}
|
||||
}
|
||||
+8
-2
@@ -7,6 +7,7 @@ import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -578,12 +579,17 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm, long timeoutInMilliseconds,
|
||||
RaceTrackingHandler raceTrackingHandler,
|
||||
RaceAndCompetitorStatusWithRaceLogReconciler raceAndCompetitorStatusWithRaceLogReconciler) {
|
||||
final List<ReceiverType> receiverTypes = new ArrayList<>();
|
||||
receiverTypes.addAll(Arrays.asList(ReceiverType.RACECOURSE, ReceiverType.MARKPASSINGS, ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH,
|
||||
ReceiverType.RAWPOSITIONS, ReceiverType.SENSORDATA));
|
||||
if (raceAndCompetitorStatusWithRaceLogReconciler != null) {
|
||||
receiverTypes.add(ReceiverType.COMPETITOR);
|
||||
}
|
||||
return getUpdateReceivers(trackedRegatta, tractracRace, windStore, delayToLiveInMillis, simulator,
|
||||
raceDefinitionSetToUpdate, trackedRegattaRegistry, raceLogResolver, leaderboardGroupResolver, courseDesignUpdateURI,
|
||||
tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber,
|
||||
useInternalMarkPassingAlgorithm, timeoutInMilliseconds, raceTrackingHandler, raceAndCompetitorStatusWithRaceLogReconciler,
|
||||
ReceiverType.RACECOURSE, ReceiverType.MARKPASSINGS, ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH,
|
||||
ReceiverType.RAWPOSITIONS, ReceiverType.SENSORDATA);
|
||||
receiverTypes.toArray(new ReceiverType[receiverTypes.size()]));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.sap.sailing.domain.tractracadapter.impl;
|
||||
|
||||
public interface OfficialCompetitorUpdateProvider {
|
||||
/**
|
||||
* Runs the {@link Runnable} when all competitor update requests enqueued so far have been
|
||||
* processed.
|
||||
*/
|
||||
void runWhenNoMoreOfficialCompetitorUpdatesPending(Runnable runnable);
|
||||
}
|
||||
+39
-4
@@ -6,6 +6,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
|
||||
@@ -27,7 +28,9 @@ import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningConfirmedEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFlagEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.RaceState;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CompetitorWithBoat;
|
||||
@@ -58,11 +61,13 @@ import com.tractrac.model.lib.api.event.RaceStatusType;
|
||||
*
|
||||
*/
|
||||
public class RaceAndCompetitorStatusWithRaceLogReconciler {
|
||||
private static final Logger logger = Logger.getLogger(RaceAndCompetitorStatusWithRaceLogReconciler.class.getName());
|
||||
private final DomainFactory domainFactory;
|
||||
private final RaceLogResolver raceLogResolver;
|
||||
private final LogEventAuthorImpl raceLogEventAuthor;
|
||||
private final IRace tractracRace;
|
||||
private final Map<Pair<TrackedRace, RaceLog>, RaceLogListener> raceLogListeners;
|
||||
private OfficialCompetitorUpdateProvider officialCompetitorUpdateProvider;
|
||||
private final static Map<RaceStatusType, Flags> flagForRaceStatus;
|
||||
|
||||
static {
|
||||
@@ -157,7 +162,7 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler {
|
||||
this.raceLogResolver = raceLogResolver;
|
||||
this.tractracRace = tractracRace;
|
||||
raceLogListeners = Collections.synchronizedMap(new HashMap<>());
|
||||
raceLogEventAuthor = new LogEventAuthorImpl(getClass().getName(), 1);
|
||||
raceLogEventAuthor = new LogEventAuthorImpl(getClass().getName(), 1); // equally important as race officer on water
|
||||
}
|
||||
|
||||
public void raceLogAttached(TrackedRace trackedRace, RaceLog raceLog) {
|
||||
@@ -207,7 +212,7 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler {
|
||||
*/
|
||||
public void reconcileRaceStatus(IRace tractracRace, TrackedRace trackedRace) {
|
||||
final RaceStatusType raceStatus = tractracRace.getStatus();
|
||||
final MillisecondsTimePoint raceStatusUpdateTime = new MillisecondsTimePoint(tractracRace.getStatusTime());
|
||||
final TimePoint raceStatusUpdateTime = TimePoint.of(tractracRace.getStatusTime());
|
||||
RaceLogFlagEvent abortingFlagEvent = null;
|
||||
for (final RaceLog raceLog : trackedRace.getAttachedRaceLogs()) {
|
||||
if (abortingFlagEvent == null) {
|
||||
@@ -216,6 +221,14 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler {
|
||||
}
|
||||
}
|
||||
final RaceLog defaultRaceLog = getDefaultRaceLog(trackedRace);
|
||||
if (raceStatus == RaceStatusType.OFFICIAL && !ReadonlyRaceStateImpl.getOrCreate(raceLogResolver, defaultRaceLog).isResultsAreOfficial()) {
|
||||
final Runnable setResultsAreOfficial = ()->RaceStateImpl.create(raceLogResolver, defaultRaceLog, raceLogEventAuthor).setResultsAreOfficial(raceStatusUpdateTime);
|
||||
if (officialCompetitorUpdateProvider != null) {
|
||||
officialCompetitorUpdateProvider.runWhenNoMoreOfficialCompetitorUpdatesPending(setResultsAreOfficial);
|
||||
} else {
|
||||
setResultsAreOfficial.run();
|
||||
}
|
||||
}
|
||||
if (abortingFlagEvent != null && !isAbortedState(raceStatus) && raceStatusUpdateTime.after(abortingFlagEvent.getLogicalTimePoint())) {
|
||||
startNewPass(raceStatusUpdateTime, defaultRaceLog);
|
||||
} else if (isAbortedState(raceStatus) &&
|
||||
@@ -227,7 +240,7 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler {
|
||||
}
|
||||
}
|
||||
|
||||
protected void startNewPass(final MillisecondsTimePoint timePointForStartOfNewPass, final RaceLog raceLog) {
|
||||
protected void startNewPass(final TimePoint timePointForStartOfNewPass, final RaceLog raceLog) {
|
||||
raceLog.add(new RaceLogPassChangeEventImpl(timePointForStartOfNewPass, raceLogEventAuthor, raceLog.getCurrentPassId() + 1));
|
||||
}
|
||||
|
||||
@@ -331,6 +344,8 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler {
|
||||
final int officialRank = raceCompetitor.getOfficialRank();
|
||||
final long officialFinishingTime = raceCompetitor.getOfficialFinishTime();
|
||||
final long timePointForStatusEvent = raceCompetitor.getStatusTime();
|
||||
logger.info("Received a status change for competitor " + raceCompetitor + " in race "+trackedRace.getRaceIdentifier()+": officialRank: " + officialRank
|
||||
+ ", officialFinishingTime: " + officialFinishingTime + ", statusTime: " + timePointForStatusEvent);
|
||||
if (timePointForStatusEvent != 0) {
|
||||
// there is an official result for the competitor on TracTrac's side
|
||||
// find out if we already have this information represented in the race log(s) and if not if the TracTrac information is newer:
|
||||
@@ -361,9 +376,18 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler {
|
||||
resultsForRaceLog.add(resultForRaceLog);
|
||||
final RaceLog defaultRaceLog = getDefaultRaceLog(trackedRace);
|
||||
defaultRaceLog.add(new RaceLogFinishPositioningConfirmedEventImpl(officialResultTime, officialResultTime,
|
||||
new LogEventAuthorImpl("Official TracTrac Result Provider", 1), // equally important as race officer on water
|
||||
raceLogEventAuthor,
|
||||
UUID.randomUUID(), defaultRaceLog.getCurrentPassId(), resultsForRaceLog));
|
||||
logger.info("Added the following result to the race log of " + trackedRace.getRaceIdentifier()
|
||||
+ " for competitor " + raceCompetitor + ": " + resultForRaceLog);
|
||||
} else {
|
||||
logger.info("Did not produce a new competitor result for competitor " + raceCompetitor + " in race "
|
||||
+ trackedRace.getRaceIdentifier() + " because existing result "
|
||||
+ resultFromRaceLogAndItsCreationTimePoint + " was not older than status time "
|
||||
+ officialResultTime + " or was an equal result");
|
||||
}
|
||||
} else {
|
||||
logger.info("Ignoring status change for competitor " + raceCompetitor + " in race "+trackedRace.getRaceIdentifier()+" because the status time was 0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,4 +408,15 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler {
|
||||
}
|
||||
return resultFromRaceLogAndItsCreationTimePoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called by the object later calling {@link #reconcileCompetitorStatus(IRaceCompetitor, TrackedRace)}. This
|
||||
* way, this object can tell when the race is to be {@link RaceState#setResultsAreOfficial(TimePoint) moved to
|
||||
* OFFICIAL state} whether any updates are pending and defer the race state transition to that moment.
|
||||
*
|
||||
* @see OfficialCompetitorUpdateProvider#runWhenNoMoreOfficialCompetitorUpdatesPending(Runnable)
|
||||
*/
|
||||
public void setOfficialCompetitorUpdateProvider(OfficialCompetitorUpdateProvider officialCompetitorUpdateProvider) {
|
||||
this.officialCompetitorUpdateProvider = officialCompetitorUpdateProvider;
|
||||
}
|
||||
}
|
||||
+35
-31
@@ -58,19 +58,19 @@ import com.sap.sse.common.Util;
|
||||
import com.sap.sse.util.impl.ThreadFactoryWithPriority;
|
||||
import com.tractrac.model.lib.api.event.CreateModelException;
|
||||
import com.tractrac.model.lib.api.event.DataSource;
|
||||
import com.tractrac.model.lib.api.event.ICompetitor;
|
||||
import com.tractrac.model.lib.api.event.IEvent;
|
||||
import com.tractrac.model.lib.api.event.IRace;
|
||||
import com.tractrac.model.lib.api.event.IRaceCompetitor;
|
||||
import com.tractrac.model.lib.api.route.IControl;
|
||||
import com.tractrac.subscription.lib.api.IEventSubscriber;
|
||||
import com.tractrac.subscription.lib.api.IRaceSubscriber;
|
||||
import com.tractrac.subscription.lib.api.ISubscriberFactory;
|
||||
import com.tractrac.subscription.lib.api.SubscriberInitializationException;
|
||||
import com.tractrac.subscription.lib.api.SubscriptionLocator;
|
||||
import com.tractrac.subscription.lib.api.competitor.ICompetitorsListener;
|
||||
import com.tractrac.subscription.lib.api.event.IConnectionStatusListener;
|
||||
import com.tractrac.subscription.lib.api.event.ILiveDataEvent;
|
||||
import com.tractrac.subscription.lib.api.event.IStoredDataEvent;
|
||||
import com.tractrac.subscription.lib.api.race.IRaceCompetitorListener;
|
||||
import com.tractrac.subscription.lib.api.race.IRacesListener;
|
||||
import com.tractrac.util.lib.api.exceptions.TimeOutException;
|
||||
|
||||
@@ -199,7 +199,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
private final IEventSubscriber eventSubscriber;
|
||||
private final IRaceSubscriber raceSubscriber;
|
||||
private final IRacesListener racesListener;
|
||||
private final ICompetitorsListener competitorsListener;
|
||||
private final IRaceCompetitorListener competitorsListener;
|
||||
private final Set<Receiver> receivers;
|
||||
private final DomainFactory domainFactory;
|
||||
private final WindStore windStore;
|
||||
@@ -351,33 +351,6 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
// Initialize data controller using live and stored data sources
|
||||
ISubscriberFactory subscriberFactory = SubscriptionLocator.getSusbcriberFactory();
|
||||
eventSubscriber = subscriberFactory.createEventSubscriber(tractracEvent, liveURI, effectiveStoredURI);
|
||||
competitorsListener = new ICompetitorsListener() {
|
||||
@Override
|
||||
public void updateCompetitor(ICompetitor competitor) {
|
||||
if (!competitor.isNonCompeting()) {
|
||||
TracTracRaceTrackerImpl.this.domainFactory.updateCompetitor(competitor, raceTrackingHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteCompetitor(UUID competitorId) {
|
||||
try {
|
||||
trackedRegattaRegistry.updateRaceCompetitors(getRegatta(), getRace());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCompetitor(ICompetitor competitor) {
|
||||
try {
|
||||
trackedRegattaRegistry.updateRaceCompetitors(getRegatta(), getRace());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
eventSubscriber.subscribeCompetitors(competitorsListener);
|
||||
if (useOfficialEventsToUpdateRaceLog) {
|
||||
reconciler = new RaceAndCompetitorStatusWithRaceLogReconciler(domainFactory, raceLogResolver, tractracRace);
|
||||
} else {
|
||||
@@ -456,6 +429,37 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
useInternalMarkPassingAlgorithm, timeoutInMilliseconds, raceTrackingHandler, reconciler)) {
|
||||
receivers.add(receiver);
|
||||
}
|
||||
competitorsListener = new IRaceCompetitorListener() {
|
||||
@Override
|
||||
public void addRaceCompetitor(IRaceCompetitor raceCompetitor) {
|
||||
try {
|
||||
trackedRegattaRegistry.updateRaceCompetitors(getRegatta(), getRace());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRaceCompetitor(IRaceCompetitor raceCompetitor) {
|
||||
if (!raceCompetitor.getCompetitor().isNonCompeting()) {
|
||||
TracTracRaceTrackerImpl.this.domainFactory.updateCompetitor(raceCompetitor.getCompetitor(), raceTrackingHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRaceCompetitor(UUID competitorId) {
|
||||
try {
|
||||
trackedRegattaRegistry.updateRaceCompetitors(getRegatta(), getRace());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOffsetPositions(UUID competitorId, int offset) {
|
||||
}
|
||||
};
|
||||
raceSubscriber.subscribeRaceCompetitor(competitorsListener);
|
||||
addListenersForStoredDataAndStartController(receivers);
|
||||
}
|
||||
|
||||
@@ -598,7 +602,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
if (!stopped) {
|
||||
stopped = true;
|
||||
eventSubscriber.unsubscribeRaces(racesListener);
|
||||
eventSubscriber.unsubscribeCompetitors(competitorsListener);
|
||||
raceSubscriber.unsubscribeRaceCompetitor(competitorsListener);
|
||||
raceSubscriber.stop();
|
||||
eventSubscriber.stop();
|
||||
raceSubscriber.unsubscribeConnectionStatus(this);
|
||||
|
||||
+6
@@ -20,6 +20,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
|
||||
@@ -192,4 +193,9 @@ public class RaceColumnRaceLogReplicator implements RaceLogEventVisitor, Seriali
|
||||
public void visit(RaceLogORCImpliedWindSourceEvent event) {
|
||||
notifyOnAdd(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaceLogResultsAreOfficialEvent event) {
|
||||
notifyOnAdd(event);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -28,7 +28,6 @@ import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
@@ -37,6 +36,7 @@ import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/**
|
||||
|
||||
+40
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.domain.orc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
@@ -9,6 +11,11 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.w3c.dom.DOMException;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sailing.domain.orc.impl.ORCPublicCertificateDatabaseImpl;
|
||||
@@ -128,6 +135,36 @@ public interface ORCPublicCertificateDatabase {
|
||||
return familyById.get(familyId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data about valid certificates in a country, as obtained, e.g., from http://data.orc.org/public/WPub.dll/RMS. Such a
|
||||
* record, in its original XML representation, looks like this:
|
||||
*
|
||||
* <pre>
|
||||
<CountryId>AUS</CountryId>
|
||||
<Family></Family>
|
||||
<CertType>3</CertType>
|
||||
<VPPYear>2020</VPPYear>
|
||||
<CertCount>161</CertCount>
|
||||
<CountryName>Australia</CountryName>
|
||||
<LastUpdate>2021-01-08T08:12:57.000Z</LastUpdate>
|
||||
<CertName>Club</CertName>
|
||||
<RMSCode>CLUB</RMSCode>
|
||||
* </pre>
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*/
|
||||
public interface CountryOverview {
|
||||
CountryCode getIssuingCountry();
|
||||
CertificateFamily getFamily();
|
||||
Integer getCertType();
|
||||
Integer getVPPYear();
|
||||
int getCertCount();
|
||||
TimePoint getLastUpdate();
|
||||
String getCertName();
|
||||
String getRMSCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality and hash code of such handles is based on the {@link #getReferenceNumber() reference number} only.
|
||||
*
|
||||
@@ -229,4 +266,7 @@ public interface ORCPublicCertificateDatabase {
|
||||
Future<Set<ORCCertificate>> search(String yachtName, String sailNumber, BoatClass boatClass);
|
||||
|
||||
Date parseDate(final String dateString) throws DateTimeParseException;
|
||||
|
||||
Iterable<CountryOverview> getCountriesWithValidCertificates()
|
||||
throws SAXException, IOException, ParserConfigurationException, DOMException, ParseException;
|
||||
}
|
||||
+1
-1
@@ -317,7 +317,7 @@ implements com.sap.sailing.domain.orc.ORCPerformanceCurveRankingMetric {
|
||||
Duration minGPH = new MillisecondsDurationImpl(Long.MAX_VALUE);
|
||||
Boat boatWithMinGPH = null;
|
||||
for (final Entry<Boat, ORCCertificate> e : certificates.entrySet()) {
|
||||
if (e.getValue().getGPH().compareTo(minGPH) < 0) {
|
||||
if (e.getValue().getGPH() != null && e.getValue().getGPH().compareTo(minGPH) < 0) {
|
||||
boatWithMinGPH = e.getKey();
|
||||
minGPH = e.getValue().getGPH();
|
||||
}
|
||||
|
||||
+2
-2
@@ -70,8 +70,8 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
|
||||
/**
|
||||
* This PolynomialSplineFunction is created with the array of course specific allowances for the boat which this
|
||||
* ORCPerformanceCurve belongs to. This function contains subfunctions for each interval between two given
|
||||
* calculated points. The input for the function is the value of the implied wind (speed in kts) and the output an
|
||||
* allowance in sec/nm.
|
||||
* calculated points. The input for the function is the implied wind speed in knots and the output the expected
|
||||
* average speed over ground in knots.
|
||||
*/
|
||||
private final UnivariateDifferentiableFunction functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse;
|
||||
|
||||
|
||||
+155
-21
@@ -2,7 +2,9 @@ package com.sap.sailing.domain.orc.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
@@ -11,9 +13,7 @@ import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
@@ -25,12 +25,14 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.http.HttpMessage;
|
||||
import org.apache.http.HttpResponse;
|
||||
@@ -46,6 +48,7 @@ import org.w3c.dom.DOMException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.common.BoatClassMasterdata;
|
||||
@@ -76,7 +79,10 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
private static final NameValuePair ACTION_PARAM = new BasicNameValuePair(ACTION_PARAM_NAME, ACTION_PARAM_VALUE_LIST_CERT);
|
||||
private static final NameValuePair XSLP_PARAM = new BasicNameValuePair(XSLP_PARAM_NAME, XSLP_PARAM_VALUE_LIST_CERT);
|
||||
private static final String SEARCH_URL = "http://data.orc.org/public/WPub.dll";
|
||||
private static final String SINGLE_CERTIFICATE_DOWNLOAD_URL = "http://data.orc.org/public/WPub.dll?action=DownBoatRMS";
|
||||
private static final String COUNTRY_OVERVIEW_URL = SEARCH_URL+"/RMS";
|
||||
private static final String SINGLE_CERTIFICATE_DOWNLOAD_URL = SEARCH_URL+"?action=DownBoatRMS";
|
||||
// For possible future use: to download all certificates of, e.g., a country in one go, use the following action:
|
||||
// private static final String MANY_CERTIFICATES_DOWNLOAD_URL = SEARCH_URL+"?action=DownRMS";
|
||||
private static final String ROOT_ELEMENT = "ROOT";
|
||||
private static final String DATA_ELEMENT = "DATA";
|
||||
private static final String ROW_ELEMENT = "ROW";
|
||||
@@ -96,6 +102,62 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
|
||||
};
|
||||
|
||||
private static class CountryOverviewImpl implements CountryOverview {
|
||||
private final CountryCode issuingCountry;
|
||||
private final CertificateFamily family;
|
||||
private final Integer certType;
|
||||
private final Integer vppYear;
|
||||
private final int certCount;
|
||||
private final TimePoint lastUpdate;
|
||||
private final String certName;
|
||||
private final String rmsCode;
|
||||
|
||||
protected CountryOverviewImpl(CountryCode issuingCountry, CertificateFamily family, Integer certType,
|
||||
Integer vppYear, int certCount, TimePoint lastUpdate, String certName, String rmsCode) {
|
||||
super();
|
||||
this.issuingCountry = issuingCountry;
|
||||
this.family = family;
|
||||
this.certType = certType;
|
||||
this.vppYear = vppYear;
|
||||
this.certCount = certCount;
|
||||
this.lastUpdate = lastUpdate;
|
||||
this.certName = certName;
|
||||
this.rmsCode = rmsCode;
|
||||
}
|
||||
@Override
|
||||
public CountryCode getIssuingCountry() {
|
||||
return issuingCountry;
|
||||
}
|
||||
@Override
|
||||
public CertificateFamily getFamily() {
|
||||
return family;
|
||||
}
|
||||
@Override
|
||||
public Integer getCertType() {
|
||||
return certType;
|
||||
}
|
||||
@Override
|
||||
public Integer getVPPYear() {
|
||||
return vppYear;
|
||||
}
|
||||
@Override
|
||||
public int getCertCount() {
|
||||
return certCount;
|
||||
}
|
||||
@Override
|
||||
public TimePoint getLastUpdate() {
|
||||
return lastUpdate;
|
||||
}
|
||||
@Override
|
||||
public String getCertName() {
|
||||
return certName;
|
||||
}
|
||||
@Override
|
||||
public String getRMSCode() {
|
||||
return rmsCode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash code and equality as based on {@link #getReferenceNumber() the reference number field} only.
|
||||
*
|
||||
@@ -325,6 +387,81 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<CountryOverview> getCountriesWithValidCertificates()
|
||||
throws SAXException, IOException, ParserConfigurationException, DOMException, ParseException {
|
||||
final Set<ORCPublicCertificateDatabase.CountryOverview> result = new HashSet<>();
|
||||
final HttpClient client = HttpClientBuilder.create().build();
|
||||
final List<NameValuePair> params = new ArrayList<>();
|
||||
final HttpGet getRequest = new HttpGet(COUNTRY_OVERVIEW_URL);
|
||||
addAuthorizationHeader(getRequest);
|
||||
logger.fine(()->"Searching for "+params+"...");
|
||||
final HttpResponse processorResponse = client.execute(getRequest);
|
||||
final InputStream content = processorResponse.getEntity().getContent();
|
||||
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
final Document document = builder.parse(content);
|
||||
final NodeList dataNodes = document.getElementsByTagName(ROOT_ELEMENT).item(0).getChildNodes();
|
||||
for (int dataNodeIndex=0; dataNodeIndex<dataNodes.getLength(); dataNodeIndex++) {
|
||||
final Node dataNode = dataNodes.item(dataNodeIndex);
|
||||
if (dataNode.getNodeName().equals(DATA_ELEMENT)) {
|
||||
final NodeList rowNodes = dataNode.getChildNodes();
|
||||
for (int rowNodeIndex=0; rowNodeIndex<rowNodes.getLength(); rowNodeIndex++) {
|
||||
final Node rowNode = rowNodes.item(rowNodeIndex);
|
||||
if (rowNode.getNodeName().equals(ROW_ELEMENT)) {
|
||||
final CountryOverview countryOverview = parseCountryOverview(rowNode);
|
||||
if (countryOverview.getVPPYear() != null) {
|
||||
result.add(countryOverview);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.fine(()->"Search for "+params+" returned "+result.size()+" results");
|
||||
return result;
|
||||
}
|
||||
|
||||
private CountryOverview parseCountryOverview(Node rowNode) throws DOMException, ParseException {
|
||||
final DateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.mmmX");
|
||||
CountryCode issuingCountry = null;
|
||||
CertificateFamily family = null;
|
||||
Integer certType = null;
|
||||
Integer vppYear = null;
|
||||
int certCount = 0;
|
||||
TimePoint lastUpdate = null;
|
||||
String certName = null;
|
||||
String rmsCode = null;
|
||||
for (int i=0; i<rowNode.getChildNodes().getLength(); i++) {
|
||||
final Node child = rowNode.getChildNodes().item(i);
|
||||
switch (child.getNodeName()) {
|
||||
case "CountryId":
|
||||
issuingCountry = CountryCodeFactory.INSTANCE.getFromThreeLetterIOCName(child.getTextContent().trim());
|
||||
break;
|
||||
case "Family":
|
||||
family = Util.hasLength(child.getTextContent().trim()) ? CertificateFamily.fromId(new Integer(child.getTextContent().trim())) : null;
|
||||
break;
|
||||
case "CertType":
|
||||
certType = child.getTextContent().trim().isEmpty() ? null : Integer.valueOf(child.getTextContent().trim());
|
||||
break;
|
||||
case "VPPYear":
|
||||
vppYear = child.getTextContent().trim().isEmpty() ? null : Integer.valueOf(child.getTextContent().trim());
|
||||
break;
|
||||
case "CertCount":
|
||||
certCount = Integer.valueOf(child.getTextContent().trim()).intValue();
|
||||
break;
|
||||
case "LastUpdate":
|
||||
lastUpdate = TimePoint.of(isoDateFormat.parse(child.getTextContent().trim()));
|
||||
break;
|
||||
case "CertName":
|
||||
certName = child.getTextContent().trim();
|
||||
break;
|
||||
case "RMSCode":
|
||||
rmsCode = child.getTextContent().trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new CountryOverviewImpl(issuingCountry, family, certType, vppYear, certCount, lastUpdate, certName, rmsCode);
|
||||
}
|
||||
|
||||
private void addAuthorizationHeader(final HttpMessage httpMessage) {
|
||||
httpMessage.addHeader("Authorization", "Basic "+new String(Base64.getEncoder().encode((USER_NAME+":"+getDecodedCredentials()).getBytes())));
|
||||
}
|
||||
@@ -486,7 +623,13 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
public ORCCertificate getCertificate(String referenceNumber, CertificateFamily family) throws Exception {
|
||||
final String queryParameters = "ext=json&RefNo="+referenceNumber+"&family="+family.getFamilyQueryParamValue();
|
||||
logger.fine("Obtaining certificate for reference number "+referenceNumber);
|
||||
final ORCCertificate result = getSingleCertificate(queryParameters);
|
||||
ORCCertificate result;
|
||||
try {
|
||||
result = getSingleCertificate(queryParameters);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "Error trying to find ORC certificate with reference number "+referenceNumber, e);
|
||||
result = null;
|
||||
}
|
||||
if (result == null) {
|
||||
logger.info("Couldn't find ORC certificate with reference number "+referenceNumber);
|
||||
}
|
||||
@@ -541,7 +684,7 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
final FutureTask<Set<ORCCertificate>> result = new FutureTask<Set<ORCCertificate>>(()->{
|
||||
final Set<ORCCertificate> certificates = new HashSet<>();
|
||||
Iterable<CertificateHandle> certificateHandles = fuzzySearchVaryingSailNumberPadding(yachtName, sailNumber, boatClass);
|
||||
if (!containsHandleForCurrentYear(certificateHandles)) {
|
||||
if (!containsValidHandle(certificateHandles)) {
|
||||
// try swapping yacht name and sail number and go again:
|
||||
logger.fine(()->"Nothing found for "+yachtName+"/"+sailNumber+"/"+boatClass+
|
||||
"; trying by swapping sail number and yacht name");
|
||||
@@ -569,7 +712,7 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
for (final String sailNumberVariant : getSailNumberVariants(sailNumber)) {
|
||||
logger.fine(()->"Trying sail number variation "+sailNumberVariant);
|
||||
final Iterable<CertificateHandle> certificateHandles = fuzzySearchVaryingBoatClassName(yachtName, sailNumberVariant, boatClass);
|
||||
Util.addAll(filterHandlesForCurrentYear(certificateHandles), result);
|
||||
Util.addAll(filterValidHandles(certificateHandles), result);
|
||||
}
|
||||
if (sailNumber != null && result.isEmpty() && (yachtName != null || boatClass != null)) {
|
||||
logger.fine(()->"Nothing found; trying without restricting sail number to "+sailNumber);
|
||||
@@ -579,21 +722,12 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean containsHandleForCurrentYear(Iterable<CertificateHandle> certificateHandles) {
|
||||
return filterHandlesForCurrentYear(certificateHandles).iterator().hasNext();
|
||||
private boolean containsValidHandle(Iterable<CertificateHandle> certificateHandles) {
|
||||
return filterValidHandles(certificateHandles).iterator().hasNext();
|
||||
}
|
||||
|
||||
private Iterable<CertificateHandle> filterHandlesForCurrentYear(Iterable<CertificateHandle> certificateHandles) {
|
||||
final List<CertificateHandle> result = new LinkedList<>();
|
||||
final Calendar cal = new GregorianCalendar();
|
||||
final int currentYear = cal.get(Calendar.YEAR);
|
||||
for (final CertificateHandle handle : certificateHandles) {
|
||||
cal.setTime(handle.getIssueDate().asDate());
|
||||
if (cal.get(Calendar.YEAR) == currentYear) {
|
||||
result.add(handle);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
private Iterable<CertificateHandle> filterValidHandles(Iterable<CertificateHandle> certificateHandles) {
|
||||
return Util.filter(certificateHandles, handle->handle.isValid());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -613,7 +747,7 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
private Iterable<CertificateHandle> fuzzySearchVaryingBoatClassName(final String yachtName, final String sailNumber, final BoatClass boatClass) throws Exception {
|
||||
String successfulBoatClassName = boatClass==null?null:boatClass.getName();
|
||||
Iterable<CertificateHandle> certificateHandles = search(/* issuingCountry */ null, /* yearOfIssuance */ null, /* referenceNumber */ null, yachtName, sailNumber, successfulBoatClassName, /* includeInvalid */ false);
|
||||
if (!containsHandleForCurrentYear(certificateHandles) && successfulBoatClassName != null) {
|
||||
if (!containsValidHandle(certificateHandles) && successfulBoatClassName != null) {
|
||||
if (yachtName != null || sailNumber != null) {
|
||||
logger.fine(()->"Nothing found; removing boat class name restriction "+boatClass.getName());
|
||||
// try without boat class restriction
|
||||
@@ -627,7 +761,7 @@ public class ORCPublicCertificateDatabaseImpl implements ORCPublicCertificateDat
|
||||
// if a valid boatClass was specified, try to filter; if none match the filter, return unfiltered
|
||||
if (boatClass != null) {
|
||||
final Set<CertificateHandle> restrictedResults = new HashSet<>();
|
||||
for (final CertificateHandle handle : filterHandlesForCurrentYear(certificateHandles)) {
|
||||
for (final CertificateHandle handle : filterValidHandles(certificateHandles)) {
|
||||
final BoatClassMasterdata boatClassMasterData = BoatClassMasterdata.resolveBoatClass(handle.getBoatClassName());
|
||||
if (boatClassMasterData != null && boatClassMasterData.getDisplayName().equals(boatClass.getName())) {
|
||||
restrictedResults.add(handle);
|
||||
|
||||
+1
-1
@@ -7,12 +7,12 @@ import java.util.function.Consumer;
|
||||
|
||||
import com.sap.sailing.domain.common.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TransformationException;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
|
||||
public enum EmptySensorFixStore implements SensorFixStore {
|
||||
|
||||
Loaded 100 of 1251 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user