Merge branch 'master' into racecommittee_integrated

Conflicts:
	java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/MongoObjectFactory.java
	java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java
	java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java
	java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java
	java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/MarkImpl.java
	java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java
	java/com.sap.sailing.domain/META-INF/MANIFEST.MF
	java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/DomainFactory.java
	java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java
	java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java
	java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardColumn.java
	java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
	java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
	java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
	java/com.sap.sailing.gwt.ui/.settings/com.google.gwt.eclipse.core.prefs
	java/com.sap.sailing.gwt.ui/SailingGWT.launch
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardDialog.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardCreateDialog.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardDialog.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/FlexibleLeaderboardEditDialog.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardDescriptor.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLeaderboardCreateDialog.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLeaderboardDialog.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaLeaderboardEditDialog.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/AbstractLeaderboardDTO.java
	java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java
	java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF
	java/com.sap.sailing.server/SailingServer (No Proxy).launch
	java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
	java/pom.xml
This commit is contained in:
Lukas Niemeier committed 2013-02-18 16:53:55 +01:00
commit 5df89c7e7e
195 files changed
+10899 -5182

No files matched your search

+155
View File
@@ -0,0 +1,155 @@
#/bin/bash
# this holds for default installation
USER_HOME=~
PROJECT_HOME=$USER_HOME/git
SERVERS_HOME=$USER_HOME/servers
# x86 or x86_64 should work for most cases
ARCH=x86_64
# needed for maven to work correctly
source $USER_HOME/.bash_profile
cd $PROJECT_HOME
active_branch=$(git symbolic-ref -q HEAD)
active_branch=`basename $active_branch`
ACDIR=$SERVERS_HOME/$active_branch
gwtcompile=1
testing=1
clean="clean"
offline=0
proxy=0
extra=''
if [ $# -eq 0 ]; then
echo "buildAndUpdateProduct [-g -t -o -c] [build|install|all]"
echo ""
echo "Active branch is $active_branch"
echo ""
echo "-g Disable GWT compile, no gwt files will be generated, old ones will be preserved."
echo "-t Disable tests"
echo "-o Enable offline mode (does not work for tycho surefire plugin)"
echo "-c Disable cleaning (use only if you are sure that no java file has changed)"
echo "-p Enable proxy mode"
echo ""
echo "build: builds the server code using Maven to $PROJECT_HOME"
echo "install: installs product and configuration to $SERVERS_HOME/$active_branch. Overwrites any configuration by using config from branch."
echo "all: calls build and then install"
exit 2
fi
options=':gtocp'
while getopts $options option
do
case $option in
g) gwtcompile=0;;
t) testing=0;;
o) offline=1;;
c) clean="";;
p) proxy=1;;
\?) echo "Invalid option"
exit 2;;
esac
done
if [ ! -d $ACDIR ]; then
echo "Could not find directory $ACDIR - perhaps you are on a wrong branch?"
exit
fi
read -s -n1 -p "Currently branch $active_branch is active. Do you want to proceed (y/N): " answer
case $answer in
"Y" | "y") echo "Continuing";;
*) echo "Aborting..."
exit;;
esac
shift $((OPTIND-1))
if [[ $@ == "" ]]; then
echo "You need to specify an action [build|install]"
exit 2
fi
echo "Starting $@ of server..."
if [ ! -d "$ACDIR/plugins" ]; then
mkdir $ACDIR/plugins
fi
if [ ! -d "$ACDIR/configuration" ]; then
mkdir $ACDIR/configuration
fi
# make sure to have maven configuration here
cp -v $PROJECT_HOME/configuration/maven-settings.xml $ACDIR/
MAVEN_SETTINGS=$ACDIR/maven-settings.xml
if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
# yield build so that we get updated product
# preserve old build log
cp $ACDIR/build.log $ACDIR/build.log.old
cd $PROJECT_HOME/java
if [ $gwtcompile -eq 1 ]; then
echo "INFO: Compiling GWT (rm -rf com.sap.sailing.gwt.ui/com.sap.sailing.*)"
rm -rf com.sap.sailing.gwt.ui/com.sap.sailing.*
else
echo "INFO: GWT Compilation disabled"
extra="-Pdebug.no-gwt-compile"
fi
if [ $testing -eq 0 ]; then
echo "INFO: Skipping tests"
extra="$extra -Dmaven.test.skip=true"
fi
if [ $offline -eq 1 ]; then
echo "INFO: Activating offline mode"
extra="$extra -o"
fi
if [ $proxy -eq 1 ]; then
echo "INFO: Activating proxy profile"
extra="$extra -P no-debug.with-proxy"
else
extra="$extra -P no-debug.without-proxy"
fi
echo "Using following command: mvn $extra -fae -s $MAVEN_SETTINGS $clean install"
mvn $extra -fae -s $MAVEN_SETTINGS $clean install 2>&1 | tee $ACDIR/build.log
echo "Build complete. Do not forget to install product..."
fi
if [[ "$@" == "install" ]] || [[ "$@" == "all" ]]; then
cd $ACDIR
rm -rf $ACDIR/plugins/*.*
rm -rf $ACDIR/org.eclipse.*
rm -rf $ACDIR/configuration/org.eclipse.*
p2PluginRepository=$PROJECT_HOME/java/com.sap.sailing.feature.p2build/bin/products/raceanalysis.product.id/linux/gtk/$ARCH
cp -v $p2PluginRepository/configuration/config.ini configuration/
cp -r -v $p2PluginRepository/configuration/org.eclipse.equinox.simpleconfigurator configuration/
cp -v $p2PluginRepository/plugins/*.jar plugins/
mkdir -p configuration/jetty/etc
cp -v $PROJECT_HOME/java/target/configuration/jetty/etc/jetty.xml configuration/jetty/etc
cp -v $PROJECT_HOME/java/target/configuration/jetty/etc/realm.properties configuration/jetty/etc
cp -v $PROJECT_HOME/java/target/configuration/monitoring.properties configuration/
# Make sure mongodb configuration is active
cp -v $PROJECT_HOME/configuration/mongodb.cfg $ACDIR/
cp -rv $PROJECT_HOME/configuration/native-libraries $ACDIR/
# Make sure this script is up2date at least for the next run
cp -v $PROJECT_HOME/configuration/buildAndUpdateProduct.sh $ACDIR/
echo "Installation complete. You may now start the server using ./start"
fi
+39
View File
@@ -0,0 +1,39 @@
<settings>
<servers>
<server>
<id>ssh-repository</id>
<filePermissions>664</filePermissions>
<directoryPermissions>775</directoryPermissions>
</server>
</servers>
<proxies>
<proxy>
<active>false</active>
<protocol>http</protocol>
<host>proxy.wdf.sap.corp</host>
<port>8080</port>
<nonProxyHosts>localhost|*.sap.corp</nonProxyHosts>
</proxy>
</proxies>
<profiles>
<profile>
<id>sailing.analytics</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<!-- Leave empty, if no proxy is needed in your environment! -->
<parameters.proxy>
</parameters.proxy>
<!-- Change the configuration file to the one you like to use for the tests. -->
<parameters.integration-tests>
-Dselenium.test.environment.configuration=ci-test-environment.xml
</parameters.integration-tests>
</properties>
</profile>
</profiles>
</settings>
+8
View File
@@ -0,0 +1,8 @@
port = 27017
master = true
dbpath = /opt/mongodb/data//mongodb-data
logpath = /opt/mongodb/data/logs/mongodb-data/mongodb.log
logappend = true
directoryperdb = true
rest = true
syncdelay = 5
+36
View File
@@ -0,0 +1,36 @@
#!/bin/bash
command -v tmux >/dev/null 2>&1 || { echo "I require tmux but it's not installed. Aborting." >&2; exit 1; }
sn=sailing
SERVERS_DIR=/home/trac/servers
# options
tmux set-option default-path /home/trac/
tmux set-option default-shell /bin/bash
cd /home/trac/git
tmux new-session -s "$sn" -n "BUILD" -d "bash -c 'git symbolic-ref -q HEAD && echo \"./buildAndUpdateProduct.sh install\"'; bash"
counter=1
for dir in dev test prod1 prod2; do
cd $SERVERS_DIR/$dir
tmux new-window -t "$sn:$counter" -n `basename $dir` "bash -c 'start'; bash"
counter=$[counter + 1]
done
cd /home/trac/servers/prod1
tmux new-window -t "$sn:$counter" -n "UDP" "bash -c 'echo \"./udpmirror -v 2012 localhost 2010 localhost 2011 localhost 2013 localhost 2014\"'; bash"
cd /opt/mongodb/bin
tmux new-window -t "$sn:$[counter+1]" -n "MongoDf" "bash -c './mongod --dbpath ../data/mongodb-default'; bash"
cd /opt/
tmux new-window -t "$sn:$[counter+2]" -n "ATop" "bash -c 'apachetop -f /var/log/httpd/access_log'; bash"
cd /home/trac/servers
tmux new-window -t "$sn:$[counter+4]" -n "Logs" "bash -c 'ls -lah'; bash"
tmux select-window -t "$sn:0"
tmux -2 attach-session -t "$sn"
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
export JAVA_HOME=/home/trac/jdk1.7.0_02
jar=`find plugins -name 'com.sap.sailing.expeditionconnector_*.jar' | sort | tail -1`
echo Using JAR file $jar
if [ $# -eq 0 ]; then
ARGS="-v 2012 localhost 2010 localhost 2011 localhost 2013 localhost 2014"
else
ARGS=$*
fi
echo "Using $ARGS"
java -cp "$jar" -Djava.util.logging.config.file=udpmirrorLog.properties com.sap.sailing.expeditionconnector.UDPMirror $ARGS
@@ -1,7 +1,7 @@
Extreme Sailing Series 2012 - Cardiff
Move wind data from test
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Extreme Sailing Series (Extreme40)'}" > /tmp/windtracks-ess40_cardiff.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Extreme Sailing Series (Extreme40)'}" > /tmp/windtracks-ess40_cardiff.json
to prod
/opt/mongodb/bin/mongoimport --port 10202 -d winddb -c WIND_TRACKS /tmp/windtracks-ess40_cardiff.json
+11 -11
View File
@@ -1,18 +1,18 @@
Kieler Woche 2012
Move wind data from test to prod
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche 2012 (LASER)'}" > /tmp/windtracks-laser.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche 2012 (470M)'}" > /tmp/windtracks-470m.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche 2012 (470W)'}" > /tmp/windtracks-470w.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche 2012 (49er)'}" > /tmp/windtracks-49er.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche 2012 (SWAN)'}" > /tmp/windtracks-swan.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche 2012 (RAD W)'}" > /tmp/windtracks-laserradial.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche 2012 (Kite)'}" > /tmp/windtracks-kite.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche 2012 (Finn)'}" > /tmp/windtracks-finn.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche 2012 (LASER)'}" > /tmp/windtracks-laser.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche 2012 (470M)'}" > /tmp/windtracks-470m.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche 2012 (470W)'}" > /tmp/windtracks-470w.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche 2012 (49er)'}" > /tmp/windtracks-49er.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche 2012 (SWAN)'}" > /tmp/windtracks-swan.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche 2012 (RAD W)'}" > /tmp/windtracks-laserradial.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche 2012 (Kite)'}" > /tmp/windtracks-kite.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche 2012 (Finn)'}" > /tmp/windtracks-finn.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche 2012 (29er)'}" > /tmp/windtracks-29er.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche IC 2012 (STAR)'}" > /tmp/windtracks-star.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'Kieler Woche IC 2012 (5o5)'}" > /tmp/windtracks-5o5.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche 2012 (29er)'}" > /tmp/windtracks-29er.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche IC 2012 (STAR)'}" > /tmp/windtracks-star.json
/opt/mongodb/bin/mongoexport --port 10201 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'Kieler Woche IC 2012 (5o5)'}" > /tmp/windtracks-5o5.json
/opt/mongodb/bin/mongoimport --port 10202 -d winddb -c WIND_TRACKS /tmp/windtracks-laser.json
+1 -1
View File
@@ -1,7 +1,7 @@
505 WM La Rochelle
Move wind data from prod to test/dev
/opt/mongodb/bin/mongoexport --port 10202 -d winddb -c WIND_TRACKS -q "{ EVENT_NAME: 'SAP 505 World Championship 2012 (505)'}" > /tmp/windtracks-505.json
/opt/mongodb/bin/mongoexport --port 10202 -d winddb -c WIND_TRACKS -q "{ REGATTA_NAME: 'SAP 505 World Championship 2012 (505)'}" > /tmp/windtracks-505.json
to test
/opt/mongodb/bin/mongoimport --port 10201 -d winddb -c WIND_TRACKS /tmp/windtracks-505.json
+30
View File
@@ -26,7 +26,37 @@ http://germanmaster.traclive.dk/events/event_20100725_OWorlds/jsonservice.php
Live-URI: tcp://germanmaster.traclive.dk:1520
Stored-URI: tcp://germanmaster.traclive.dk:1521
505 World Championship 2012:
http://germanmaster.traclive.dk/events/event_20120714_SAPWorldCh/jsonservice.php
Kieler Woche 2012:
http://germanmaster.traclive.dk/events/event_20120615_KielerWoch/jsonservice.php
http://germanmaster.traclive.dk/events/event_20120621_KielerWoch/jsonservice.php
http://germanmaster.traclive.dk/events/event_20120615_KielerWoch1/jsonservice.php
Extreme Sailing Series 2012:
http://germanmaster.traclive.dk/events/event_20120101_ExtremeSai/jsonservice.php
OBMR 2012:
http://germanmaster.traclive.dk/events/event_20121031_OBMR/jsonservice.php
Academy Tracking 2011:
http://germanmaster.traclive.dk/events/event_20110505_SailingTea/jsonservice.php
Academy Tracking 2012:
http://germanmaster.traclive.dk/events/event_20120501_SailingTea/jsonservice.php
BMW Cup:
http://kml.skitrac.traclive.dk/events/event_20120803_BMWCup/jsonservice.php
YES 2012:
http://germanmaster.traclive.dk/events/event_20120525_YES/jsonservice.php
IDM Drachen 2012:
http://kml.skitrac.traclive.dk/events/event_20120730_IDMDrachen/jsonservice.php
49er European Championship:
http://traclive.dk/events/event_20120905_erEuropean/jsonservice.php
RC44 Sweden Cup:
http://germanmaster.traclive.dk/events/event_20110815_RCSwedenCu/jsonservice.php
+25
View File
@@ -0,0 +1,25 @@
# Welcome to the SAP Sailing Wiki
This is the <img src="http://analysis.sapsailing.com/themes/logo.png" height="58" width="200" /> Wiki where useful information regarding this project can be found. This Wiki is being stored directly into the default GIT repository on branch **master**. You can edit information here freely but do not leave any nonsense here.
The syntax is relatively easy and is documented here http://daringfireball.net/projects/markdown/dingus. When you create a new Page then make sure to put some thinking into the right tree structure and then just extend the URL above.
**ATTENTION**:
* Make sure to always have _wiki/_ as the base path. So if you want to create `server/SystemBoot` then the correct URL is `wiki/server/SystemBoot`. Make sure to add you Page to the Table of Contents below by editing the document.
* Password can be found in the encrypted page [[Passwords|wiki/passwords]]. You can decrypt it by using `gpg -d < passwords.md` after having entered the password. If you want to edit, first decrypt and then encrypt again using `gpg -a --symmetric passwords.md`. Make sure to never save the unencrypted version!
If you have any questions then either contact Axel Uhl, Jens Rommel, Frank Mittag or Simon Pamiés.
### Table of Contents Wiki
* [[Architecture and Infrastructure|wiki/architecture-and-infrastructure]]
* [[Configure Races on Server|wiki/configure-races-on-server]]
### Internal services (not related to wiki but useful)
* [Bugzilla Issue Tracking System](http://bugzilla.sapsailing.com/bugzilla/)
* [Maven Repository Browser](http://maven.sapsailing.com/maven/)
* [Main Sailing Website](http://www.sapsailing.com)
* [Visitor Statistics](http://analysis.sapsailing.com/)
@@ -12,7 +12,7 @@ import static com.sap.sailing.domain.common.SortingOrder.*;
*
*/
public enum DetailType implements Serializable {
DISTANCE_TRAVELED(0, ASCENDING), AVERAGE_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING), RACE_RANK(0, ASCENDING),
DISTANCE_TRAVELED(0, ASCENDING), AVERAGE_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING), RACE_RANK(0, ASCENDING), REGATTA_RANK(0, ASCENDING), OVERALL_RANK(0, ASCENDING),
RANK_GAIN(0, DESCENDING), NUMBER_OF_MANEUVERS(0, ASCENDING), CURRENT_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING),
ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS(1, ASCENDING), VELOCITY_MADE_GOOD_IN_KNOTS(2, DESCENDING),
GAP_TO_LEADER_IN_SECONDS(0, ASCENDING), GAP_CHANGE_SINCE_LEG_START_IN_SECONDS(0, ASCENDING),
@@ -0,0 +1,11 @@
package com.sap.sailing.domain.common;
import java.io.Serializable;
public interface PolarSheetGenerationTriggerResponse extends Serializable{
public String getId();
public String getBoatClassName();
}
@@ -0,0 +1,15 @@
package com.sap.sailing.domain.common;
import java.io.Serializable;
public interface PolarSheetsData extends Serializable {
Number[][] getAveragedPolarDataByWindSpeed();
int getDataCount();
boolean isComplete();
Integer[] getDataCountPerAngleForWindspeed(int beaufort);
}
@@ -0,0 +1,16 @@
package com.sap.sailing.domain.common;
import java.io.Serializable;
public interface PolarSheetsHistogramData extends Serializable{
public int getAngle();
public int getDataCount();
public Number[] getyValues();
public Number[] getxValues();
}
@@ -0,0 +1,30 @@
package com.sap.sailing.domain.common.impl;
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
public class PolarSheetGenerationTriggerResponseImpl implements PolarSheetGenerationTriggerResponse {
private static final long serialVersionUID = -2160795576114448218L;
private String id;
private String boatClassName;
// For GWT serialization
PolarSheetGenerationTriggerResponseImpl() {
};
public PolarSheetGenerationTriggerResponseImpl(String id, String boatClassName) {
this.id = id;
this.boatClassName = boatClassName;
}
@Override
public String getId() {
return id;
}
@Override
public String getBoatClassName() {
return boatClassName;
}
}
@@ -0,0 +1,50 @@
package com.sap.sailing.domain.common.impl;
import java.util.Map;
import com.sap.sailing.domain.common.PolarSheetsData;
public class PolarSheetsDataImpl implements PolarSheetsData {
private static final long serialVersionUID = -4649254807341866894L;
private Number[][] averagedPolarDataByWindSpeed;
private boolean complete;
private int dataCount;
private Map<Integer,Integer[]> dataCountPerAngleForWindspeed;
//For GWT Serialization
PolarSheetsDataImpl() {};
public PolarSheetsDataImpl(Number[][] averagedPolarDataByWindSpeed, boolean complete, int dataCount, Map<Integer,Integer[]> dataCountPerAngleForWindspeed) {
this.averagedPolarDataByWindSpeed = averagedPolarDataByWindSpeed;
this.complete = complete;
this.dataCount = dataCount;
this.dataCountPerAngleForWindspeed = dataCountPerAngleForWindspeed;
}
@Override
public Number[][] getAveragedPolarDataByWindSpeed() {
return averagedPolarDataByWindSpeed;
}
@Override
public boolean isComplete() {
return complete;
}
@Override
public int getDataCount() {
return dataCount;
}
@Override
public Integer[] getDataCountPerAngleForWindspeed(int beaufort) {
return dataCountPerAngleForWindspeed.get(beaufort);
}
}
@@ -0,0 +1,48 @@
package com.sap.sailing.domain.common.impl;
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
public class PolarSheetsHistogramDataImpl implements PolarSheetsHistogramData {
private static final long serialVersionUID = 7492650285773447757L;
private Number[] yValues;
private Number[] xValues;
private int angle;
private int dataCount;
//For GWT serialization
PolarSheetsHistogramDataImpl() {}
public PolarSheetsHistogramDataImpl(int angle, Number[] xValues, Number[] yValues, int dataCount) {
super();
this.angle = angle;
this.yValues = yValues;
this.xValues = xValues;
this.dataCount = dataCount;
}
@Override
public Number[] getyValues() {
return yValues;
}
@Override
public Number[] getxValues() {
return xValues;
}
@Override
public int getAngle() {
return angle;
}
@Override
public int getDataCount() {
return dataCount;
}
}
@@ -84,4 +84,6 @@ public interface MongoObjectFactory {
void storeRegattaForRaceID(String id, Regatta regatta);
void removeRegattaForRaceID(String raceIDAsString, Regatta regatta);
}
@@ -219,6 +219,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
if (result != null) {
final Leaderboard finalResult = result;
finalResult.setDisplayName((String) dbLeaderboard.get(FieldNames.LEADERBOARD_DISPLAY_NAME.name()));
DelayedLeaderboardCorrections loadedLeaderboardCorrections = new DelayedLeaderboardCorrectionsImpl(result);
final boolean[] needsMigration = new boolean[1];
loadedLeaderboardCorrections.addLeaderboardCorrectionsResolvedListener(new LeaderboardCorrectionsResolvedListener() {
@@ -50,7 +50,7 @@ public enum FieldNames {
COMPETITOR_ID, COMPETITOR_DISPLAY_NAME,
// leaderboard:
LEADERBOARD_NAME, LEADERBOARD_SUPPRESSED_COMPETITORS, LEADERBOARD_SUPPRESSED_COMPETITOR_IDS,
LEADERBOARD_NAME, LEADERBOARD_DISPLAY_NAME, LEADERBOARD_SUPPRESSED_COMPETITORS, LEADERBOARD_SUPPRESSED_COMPETITOR_IDS,
LEADERBOARD_COLUMNS, LEADERBOARD_COLUMN_NAME, LEADERBOARD_COMPETITOR_DISPLAY_NAMES,
LEADERBOARD_IS_MEDAL_RACE_COLUMN, LEADERBOARD_CARRIED_POINTS, LEADERBOARD_CARRIED_POINTS_BY_ID,
LEADERBOARD_SCORE_CORRECTIONS, LEADERBOARD_DISCARDING_THRESHOLDS,
@@ -150,6 +150,9 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName());
BasicDBObject dbLeaderboard = new BasicDBObject();
dbLeaderboard.put(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName());
if(leaderboard.getDisplayName() != null) {
dbLeaderboard.put(FieldNames.LEADERBOARD_DISPLAY_NAME.name(), leaderboard.getDisplayName());
}
BasicDBList dbSuppressedCompetitorIds = new BasicDBList();
for (Competitor suppressedCompetitor : leaderboard.getSuppressedCompetitors()) {
dbSuppressedCompetitorIds.add(suppressedCompetitor.getId());
@@ -476,6 +479,13 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
regattaForRaceIDCollection.update(query, entry, /* upsrt */ true, /* multi */ false);
}
@Override
public void removeRegattaForRaceID(String raceIDAsString, Regatta regatta) {
DBCollection regattaForRaceIDCollection = database.getCollection(CollectionNames.REGATTA_FOR_RACE_ID.name());
DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString);
regattaForRaceIDCollection.remove(query);
}
public DBCollection getRaceLogCollection() {
DBCollection result = database.getCollection(CollectionNames.RACE_LOGS.name());
result.ensureIndex(new BasicDBObject(FieldNames.RACE_LOG_IDENTIFIER.name(), null));
@@ -1,7 +1,8 @@
package com.sap.sailing.domain.base;
import com.sap.sailing.domain.common.Named;
import com.sap.sailing.domain.common.WithID;
public interface ControlPoint extends Named {
public interface ControlPoint extends WithID, Named {
Iterable<Mark> getMarks();
}
@@ -1,27 +1,54 @@
package com.sap.sailing.domain.base;
import java.io.Serializable;
import java.util.UUID;
import com.sap.sailing.domain.common.MarkType;
public interface SharedDomainFactory {
/**
* Looks up or, if not found, creates a {@link Nationality} object and re-uses <code>threeLetterIOCCode</code> also as the
* nationality's name.
*/
Nationality getOrCreateNationality(String threeLetterIOCCode);
Mark getOrCreateMark(String id);
/**
* The name will also be used as the mark's ID. If you have a unique ID, use {@link #getOrCreateMark(Serializable, String)} instead.
*/
Mark getOrCreateMark(String name);
/**
* Since some ID types, such as {@link UUID}, cannot be serialized as objects to a GWT client, only the
* {@link Object#toString()} representations of those IDs are serialized to the clients. When a client then requests
* to identify a mark again, only the ID's string representation will be submitted to the server and now needs to be
* mapped to the actual ID. This domain factory keeps a mapping of all mark ID's string representations to the
* actual ID for all marks ever managed through any of the <code>getOrCreateMark(...)</code> overloads.
* <p>
*
* This method first looks up the actual ID whose string representation is <code>toStringRepresentationOfID</code>
* and then calls {@link #getOrCreateMark(Serializable, String)} with the result and the <code>name</code>
* parameter, or with <code>ToStringRepresentationOfID</code> and <code>name</code> in case the string
* representation of the ID is not known. So in the latter case, the string is used as the ID for the new mark.
*/
Mark getOrCreateMark(String toStringRepresentationOfID, String name);
Mark getOrCreateMark(Serializable id, String name);
/**
* If the single mark with ID <code>id</code> already exists, it is returned. Its color may differ from <code>color</code>
* in that case. Otherwise, a new {@link Mark} is created with <code>color</code> as its {@link Mark#getColor()}
* and <code>shape</code> as its {@link Mark#getShape()}.
*/
Mark getOrCreateMark(String id, MarkType type, String color, String shape, String pattern);
Mark getOrCreateMark(Serializable id, String name, MarkType type, String color, String shape, String pattern);
/**
* @param name also uses the name as the gate's ID; if you have a real ID, use {@link #createGate(Serializable, Mark, Mark, String)} instead
*/
Gate createGate(Mark left, Mark right, String name);
Gate createGate(Serializable id, Mark left, Mark right, String name);
/**
* The waypoint created is weakly cached so that when requested again by
* {@link #getExistingWaypointById(Waypoint)} it is found.
@@ -1,19 +1,28 @@
package com.sap.sailing.domain.base.impl;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Gate;
import com.sap.sailing.domain.base.Mark;
public class GateImpl implements Gate {
private static final long serialVersionUID = 2807354812133070574L;
private final Mark left;
private final Mark right;
private final String name;
private final Serializable id;
/**
* @param name also used as ID for the mark; if you have a better ID, use {@link GateImpl(Serializable, Mark, Mark, String)} instead.
*/
public GateImpl(Mark left, Mark right, String name) {
super();
this(/* ID */ name, left, right, name);
}
public GateImpl(Serializable id, Mark left, Mark right, String name) {
this.id = id;
this.left = left;
this.right = right;
this.name = name;
@@ -46,4 +55,9 @@ public class GateImpl implements Gate {
result.add(getRight());
return result;
}
@Override
public Serializable getId() {
return id;
}
}
@@ -15,41 +15,19 @@ public class MarkImpl extends NamedImpl implements Mark {
private final String shape;
private final String pattern;
private final MarkType type;
private final Serializable id;
public MarkImpl(String name) {
super(name);
type = MarkType.BUOY;
color = null;
shape = null;
pattern = null;
this(name, name);
}
public MarkImpl(String name, MarkType type) {
super(name);
this.type = type;
color = null;
shape = null;
pattern = null;
public MarkImpl(Serializable id, String name) {
this(id, name, MarkType.BUOY, /* color */ null, /* shape */ null, /* pattern */ null);
}
public MarkImpl(String name, MarkType type, String color) {
super(name);
this.type = type;
this.color = color;
shape = null;
pattern = null;
}
public MarkImpl(String name, MarkType type, String color, String shape) {
super(name);
this.type = type;
this.color = color;
this.shape = shape;
pattern = null;
}
public MarkImpl(String name, MarkType type, String color, String shape, String pattern) {
public MarkImpl(Serializable id, String name, MarkType type, String color, String shape, String pattern) {
super(name);
this.id = id;
this.type = type;
this.color = color;
this.shape = shape;
@@ -58,7 +36,7 @@ public class MarkImpl extends NamedImpl implements Mark {
@Override
public Serializable getId() {
return getName();
return id;
}
@SuppressWarnings("unchecked")
@@ -70,7 +48,7 @@ public class MarkImpl extends NamedImpl implements Mark {
@Override
public Mark resolve(SharedDomainFactory domainFactory) {
Mark result = domainFactory.getOrCreateMark(getName(), type, color, shape, pattern);
Mark result = domainFactory.getOrCreateMark(getId(), getName(), type, color, shape, pattern);
return result;
}
@@ -28,6 +28,7 @@ import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.ScoringSchemeType;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.WithID;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.swisstimingadapter.Course;
@@ -248,13 +249,13 @@ public class DomainFactoryImpl implements DomainFactory {
}
/**
* @param id
* the ID which is probably also used as the "device name" and the "sail number" in case of an
* {@link MessageType#RPD RPD} message
* @param trackerID
* the "device name" and the "sail number" in case of an {@link MessageType#RPD RPD} message, used as the mark's
* {@link Named#getName() name} and {@link WithID#getId() ID}.
*/
@Override
public com.sap.sailing.domain.base.Mark getOrCreateMark(String id) {
return baseDomainFactory.getOrCreateMark(id);
public com.sap.sailing.domain.base.Mark getOrCreateMark(String trackerID) {
return baseDomainFactory.getOrCreateMark(trackerID);
}
@Override
@@ -0,0 +1,137 @@
package com.sap.sailing.domain.test;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.NavigableSet;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.junit.Assert;
import org.junit.Test;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.PolarSheetsData;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.polarsheets.PerRaceAndCompetitorPolarSheetGenerationWorker;
import com.sap.sailing.domain.polarsheets.PolarSheetGenerationWorker;
import com.sap.sailing.domain.test.mock.MockedTrackedRace;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.tracking.impl.WindImpl;
public class PolarSheetGenerationTest {
@Test
public void testPolarSheetRawDataGeneration() throws InterruptedException {
Executor executor = new ThreadPoolExecutor(/* corePoolSize */ 0,
/* maximumPoolSize */ Runtime.getRuntime().availableProcessors(),
/* keepAliveTime */ 60, TimeUnit.SECONDS,
/* workQueue */ new LinkedBlockingQueue<Runnable>());
MockTrackedRaceForPolarSheetGeneration race = new MockTrackedRaceForPolarSheetGeneration();
TimePoint startTime = new MillisecondsTimePoint(1);
TimePoint endTime = new MillisecondsTimePoint(4);
//Only used for storing and exporting results in this test case:
PolarSheetGenerationWorker resultContainer = new PolarSheetGenerationWorker(new HashSet<TrackedRace>(), executor);
BoatClass forelle = new BoatClassImpl("Forelle", true);
Competitor competitor = new CompetitorImpl(UUID.randomUUID(), "Hans Frantz", new TeamImpl("SAP", null, null), new BoatImpl("Schnelle Forelle", forelle, "GER000"));
PerRaceAndCompetitorPolarSheetGenerationWorker task = new PerRaceAndCompetitorPolarSheetGenerationWorker(race, resultContainer, startTime, endTime, competitor);
executor.execute(task);
double timeUntilTimeout = 1000;
while (!task.isDone() && timeUntilTimeout > 0) {
Thread.sleep(100);
timeUntilTimeout = timeUntilTimeout - 0.1;
}
Assert.assertTrue(task.isDone());
PolarSheetsData data = resultContainer.getPolarData();
Assert.assertEquals(4, data.getDataCount());
Assert.assertEquals(4.0, data.getAveragedPolarDataByWindSpeed()[1][45]);
Assert.assertEquals(2.0, data.getAveragedPolarDataByWindSpeed()[1][55]);
Assert.assertEquals(6.0, data.getAveragedPolarDataByWindSpeed()[1][30]);
}
@SuppressWarnings("serial")
private class MockTrackedRaceForPolarSheetGeneration extends MockedTrackedRace {
@Override
public DynamicGPSFixTrack<Competitor, GPSFixMoving> getTrack(Competitor competitor) {
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = new MockDynamicGPSFixMovinTrackForPolarSheetGeneration<Competitor>(competitor, 0);
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.0, 1.0), new MillisecondsTimePoint(1), new KnotSpeedWithBearingImpl(3.0, new DegreeBearingImpl(-45.0))));
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.001, 1.001), new MillisecondsTimePoint(2), new KnotSpeedWithBearingImpl(5.0, new DegreeBearingImpl(-45.0))));
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.002, 1.002), new MillisecondsTimePoint(3), new KnotSpeedWithBearingImpl(2.0, new DegreeBearingImpl(-55.0))));
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.003, 1.003), new MillisecondsTimePoint(4), new KnotSpeedWithBearingImpl(6.0, new DegreeBearingImpl(-30.0))));
return track;
}
@Override
public Wind getWind(Position p, TimePoint at) {
Wind wind = new WindImpl(p, at, new KnotSpeedWithBearingImpl(2.0, new DegreeBearingImpl(180.0)));
return wind;
}
@Override
public RaceDefinition getRace() {
BoatClass forelle = new BoatClassImpl("Forelle", true);
RaceDefinition race = new RaceDefinitionImpl("Forelle1", new CourseImpl("ForelleCourse", new ArrayList<Waypoint>()), forelle, new ArrayList<Competitor>());
return race;
}
}
@SuppressWarnings("serial")
private class MockGPSFixMovingForPolarSheetGeneration extends GPSFixMovingImpl {
public MockGPSFixMovingForPolarSheetGeneration(Position position, TimePoint timePoint, SpeedWithBearing speed) {
super(position, timePoint, speed);
}
@Override
public boolean isValid() {
return true;
}
}
@SuppressWarnings("serial")
private class MockDynamicGPSFixMovinTrackForPolarSheetGeneration<ItemType> extends DynamicGPSFixMovingTrackImpl<ItemType> {
public MockDynamicGPSFixMovinTrackForPolarSheetGeneration(ItemType trackedItem,
long millisecondsOverWhichToAverage) {
super(trackedItem, millisecondsOverWhichToAverage);
}
@Override
protected boolean isValid(NavigableSet<GPSFixMoving> rawFixes, GPSFixMoving e) {
return true;
}
}
}
@@ -160,17 +160,19 @@ public class DomainFactoryImpl implements DomainFactory {
String shape2 = controlPointMetadata.get("P2.Shape");
String pattern1 = controlPointMetadata.get("P1.Pattern");
String pattern2 = controlPointMetadata.get("P2.Pattern");
Mark mark1 = baseDomainFactory.getOrCreateMark(controlPointName + " (1)", type1, color1, shape1, pattern1);
Mark mark2 = baseDomainFactory.getOrCreateMark(controlPointName + " (2)", type2, color2, shape2, pattern2);
domainControlPoint = baseDomainFactory.createGate(mark1, mark2, controlPointName);
final String name1 = controlPointName + " (1)";
final Serializable id1 = name1; // TODO bug 1184; need to obtain mark ID through TTCM
Mark mark1 = baseDomainFactory.getOrCreateMark(id1, name1, type1, color1, shape1, pattern1);
final String name2 = controlPointName + " (2)";
final Serializable id2 = name2; // TODO bug 1184; need to obtain mark ID through TTCM
Mark mark2 = baseDomainFactory.getOrCreateMark(id2, name2, type2, color2, shape2, pattern2);
domainControlPoint = baseDomainFactory.createGate(controlPoint.getId(), mark1, mark2, controlPointName);
} else {
MarkType type = resolveMarkTypeFromMetadata(controlPointMetadata, "Type");
String color = controlPointMetadata.get("Color");
String shape = controlPointMetadata.get("Shape");
String pattern = controlPointMetadata.get("Pattern");
Mark mark = baseDomainFactory.getOrCreateMark(controlPointName, type, color, shape, pattern);
Mark mark = baseDomainFactory.getOrCreateMark(controlPoint.getId(), controlPointName, type, color, shape, pattern);
domainControlPoint = mark;
}
controlPointCache.put(controlPoint, domainControlPoint);
@@ -13,6 +13,7 @@ Export-Package: com.sap.sailing.domain.base,
com.sap.sailing.domain.leaderboard,
com.sap.sailing.domain.leaderboard.impl,
com.sap.sailing.domain.leaderboard.meta,
com.sap.sailing.domain.polarsheets,
com.sap.sailing.domain.racelog.impl,
com.sap.sailing.domain.tracking,
com.sap.sailing.domain.tracking.impl,
@@ -12,7 +12,6 @@ import com.sap.sailing.domain.tracking.MarkPassing;
public interface DomainFactory extends SharedDomainFactory {
static DomainFactory INSTANCE = new DomainFactoryImpl();
MarkPassing createMarkPassing(TimePoint timePoint, Waypoint waypoint, Competitor competitor);
/**
@@ -1,6 +1,5 @@
package com.sap.sailing.domain.base.impl;
import java.awt.TrayIcon.MessageType;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
@@ -44,7 +43,14 @@ public class DomainFactoryImpl implements DomainFactory {
*/
private final Map<String, Nationality> nationalityCache;
private final Map<String, Mark> markCache;
private final Map<Serializable, Mark> markCache;
/**
* For all marks ever created by this factory, the mark {@link WithID#getId() ID}'s string representation
* is mapped here to the actual ID. This allows clients to send only the string representation to the server
* and still be able to identify a mark uniquely this way.
*/
private final Map<String, Serializable> markIdCache;
private final Map<String, BoatClass> boatClassCache;
@@ -87,7 +93,8 @@ public class DomainFactoryImpl implements DomainFactory {
public DomainFactoryImpl() {
waypointCacheReferenceQueue = new ReferenceQueue<Waypoint>();
nationalityCache = new HashMap<String, Nationality>();
markCache = new HashMap<String, Mark>();
markCache = new HashMap<Serializable, Mark>();
markIdCache = new HashMap<>();
boatClassCache = new HashMap<String, BoatClass>();
competitorCache = new HashMap<Serializable, Competitor>();
waypointCache = new ConcurrentHashMap<Serializable, WeakWaypointReference>();
@@ -106,27 +113,47 @@ public class DomainFactoryImpl implements DomainFactory {
}
}
/**
* @param id
* the ID which is probably also used as the "device name" and the "sail number" in case of an
* {@link MessageType#RPD RPD} message
*/
@Override
public Mark getOrCreateMark(String id) {
Mark result = markCache.get(id);
if (result == null) {
result = new MarkImpl(id);
markCache.put(id, result);
}
return result;
public Mark getOrCreateMark(String name) {
return getOrCreateMark(name, name);
}
@Override
public Mark getOrCreateMark(String id, MarkType type, String color, String shape, String pattern) {
public Mark getOrCreateMark(Serializable id, String name) {
Mark result = markCache.get(id);
if (result == null) {
result = new MarkImpl(id, type, color, shape, pattern);
markCache.put(id, result);
result = new MarkImpl(id, name);
cacheMark(id, result);
}
return result;
}
@Override
public Mark getOrCreateMark(String toStringRepresentationOfID, String name) {
final Mark result;
if (markIdCache.containsKey(toStringRepresentationOfID)) {
Serializable id = markIdCache.get(toStringRepresentationOfID);
result = getOrCreateMark(id, name);
} else {
result = new MarkImpl(toStringRepresentationOfID, name);
cacheMark(toStringRepresentationOfID, result);
}
return result;
}
private void cacheMark(Serializable id, Mark result) {
markCache.put(id, result);
markIdCache.put(id.toString(), id);
}
@Override
public Mark getOrCreateMark(Serializable id, String name, MarkType type, String color, String shape, String pattern) {
Mark result = markCache.get(id);
if (result == null) {
result = new MarkImpl(id, name, type, color, shape, pattern);
cacheMark(id, result);
}
return result;
}
@@ -136,6 +163,11 @@ public class DomainFactoryImpl implements DomainFactory {
return new GateImpl(left, right, name);
}
@Override
public Gate createGate(Serializable id, Mark left, Mark right, String name) {
return new GateImpl(id, left, right, name);
}
@Override
public Waypoint createWaypoint(ControlPoint controlPoint) {
synchronized (waypointCache) {
@@ -213,6 +213,15 @@ public interface Leaderboard extends Named {
* @throws NoWindException
*/
List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) throws NoWindException;
/**
* Returns the total rank of the given competitor.
* @param competitor
* @param timePoint
* @return
* @throws NoWindException
*/
int getTotalRankOfCompetitor(Competitor competitor, TimePoint timePoint) throws NoWindException;
/**
* Fetches all entries for all competitors of all races tracked by this leaderboard in one sweep. This saves some
@@ -268,12 +277,20 @@ public interface Leaderboard extends Named {
void setDisplayName(Competitor competitor, String displayName);
/**
* If a display name for the leaderboard has been defined,
* this method returns it; otherwise, <code>null</code> is returned.
*/
String getDisplayName();
void setDisplayName(String displayName);
/**
* If a display name different from the competitor's {@link Competitor#getName() name} has been defined,
* this method returns it; otherwise, <code>null</code> is returned.
*/
String getDisplayName(Competitor competitor);
/**
* Tells if the column represented by <code>raceColumn</code> shall be considered when counting the number of "races
* so far" for discarding. Although medal races are never discarded themselves, they still count in determining the
@@ -25,6 +25,9 @@ public interface LeaderboardGroup extends Renamable {
void removeLeaderboard(Leaderboard leaderboard);
void removeAllLeaderboards(Collection<Leaderboard> leaderboards);
void clearLeaderboards();
/**
* @return The overall leaderboard of this group or null if there is none.
*/
Leaderboard getOverallLeaderboard();
void setOverallLeaderboard(Leaderboard leaderboard);
}
@@ -30,12 +30,6 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
private static final long serialVersionUID = 2370461218294770084L;
private final Regatta regatta;
/**
* If this member is <code>null</code>, {@link #getName()} will use the regatta name as the default name for this
* leaderboard. Otherwise, the {@link #displayName} is used.
*/
private String displayName;
public RegattaLeaderboardImpl(Regatta regatta, SettableScoreCorrection scoreCorrection,
ThresholdBasedResultDiscardingRule resultDiscardingRule, CourseArea courseArea) {
super(scoreCorrection, resultDiscardingRule, courseArea);
@@ -48,7 +42,7 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
*/
@Override
public void setName(String newName) {
displayName = newName;
setDisplayName(newName);
}
@Override
@@ -59,8 +53,8 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
@Override
public String getName() {
String result;
if (displayName != null) {
result = displayName;
if (getDisplayName() != null) {
result = getDisplayName();
} else {
result = getRegatta().getName();
}
@@ -37,7 +37,7 @@ public class MetaLeaderboardColumn extends SimpleAbstractRaceColumn implements R
@Override
public String getName() {
return leaderboard.getName();
return leaderboard.getDisplayName() != null ? leaderboard.getDisplayName() : leaderboard.getName();
}
@Override
@@ -0,0 +1,11 @@
package com.sap.sailing.domain.polarsheets;
import com.sap.sailing.domain.common.Speed;
public interface BoatAndWindSpeed {
public Speed getBoatSpeed();
public Speed getWindSpeed();
}
@@ -0,0 +1,28 @@
package com.sap.sailing.domain.polarsheets;
import com.sap.sailing.domain.common.Speed;
public class BoatAndWindSpeedImpl implements BoatAndWindSpeed{
private Speed boatSpeed;
private Speed windSpeed;
public BoatAndWindSpeedImpl(Speed boatSpeed, Speed windSpeed) {
this.boatSpeed = boatSpeed;
this.windSpeed = windSpeed;
}
@Override
public Speed getBoatSpeed() {
return boatSpeed;
}
@Override
public Speed getWindSpeed() {
return windSpeed;
}
}
@@ -0,0 +1,109 @@
package com.sap.sailing.domain.polarsheets;
import java.util.Iterator;
import java.util.NavigableSet;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.Wind;
/**
* Iterates through the fixes of one competitor in one tracked race and fills the {@link PolarSheetGenerationWorker}
* with datapoints that are found for the speed of the boat and its angle to the wind
*
* @author D054528 Frederik Petersen
*
*/
public class PerRaceAndCompetitorPolarSheetGenerationWorker implements Runnable{
private final TrackedRace race;
private final PolarSheetGenerationWorker polarSheetGenerationWorker;
private TimePoint startTime;
private TimePoint endTime;
private final Competitor competitor;
private boolean done = false;
public PerRaceAndCompetitorPolarSheetGenerationWorker(TrackedRace race,
PolarSheetGenerationWorker polarSheetGenerationWorker, TimePoint startTime, TimePoint endTime,
Competitor competitor) {
super();
this.race = race;
this.polarSheetGenerationWorker = polarSheetGenerationWorker;
this.startTime = startTime;
this.endTime = endTime;
this.competitor = competitor;
optimizeStartTime();
optimizeEndTime();
}
private void optimizeEndTime() {
NavigableSet<MarkPassing> markPassings = race.getMarkPassings(competitor);
if (markPassings == null || markPassings.size() < 1) {
return;
}
MarkPassing passedFinish = markPassings.last();
TimePoint passedFinishTimePoint = passedFinish.getTimePoint();
if (passedFinishTimePoint.before(endTime)) {
endTime = passedFinishTimePoint;
}
}
private void optimizeStartTime() {
NavigableSet<MarkPassing> markPassings = race.getMarkPassings(competitor);
if (markPassings == null || markPassings.size() < 1) {
return;
}
MarkPassing passedStart = markPassings.first();
TimePoint passedStartTimePoint = passedStart.getTimePoint();
if (passedStartTimePoint.after(startTime)) {
startTime = passedStartTimePoint;
}
}
@Override
public void run() {
GPSFixTrack<Competitor, GPSFixMoving> track = race.getTrack(competitor);
track.lockForRead();
Iterator<GPSFixMoving> fixesIterator = track.getFixesIterator(startTime, true);
while (fixesIterator.hasNext()) {
GPSFixMoving fix = fixesIterator.next();
if (fix.getTimePoint().after(endTime)) {
break;
}
if (track.hasDirectionChange(fix.getTimePoint(), race.getRace().getBoatClass()
.getManeuverDegreeAngleThreshold())) {
continue;
}
SpeedWithBearing speedWithBearing = fix.getSpeed();
Bearing bearing = speedWithBearing.getBearing();
Position position = fix.getPosition();
Wind wind = race.getWind(position, fix.getTimePoint());
Bearing windBearing = wind.getFrom();
double angleToWind = bearing.getDifferenceTo(windBearing).getDegrees();
polarSheetGenerationWorker.addPolarData(Math.round(angleToWind), speedWithBearing, wind);
}
track.unlockAfterRead();
done = true;
}
public boolean isDone() {
return done;
}
}
@@ -0,0 +1,174 @@
package com.sap.sailing.domain.polarsheets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.common.PolarSheetsData;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.PolarSheetsDataImpl;
import com.sap.sailing.domain.tracking.TrackedRace;
/**
* Allows extracting data about average speed for each angle creating the foundation of polar-sheet generation. Tasks
* are assigned to the executor per race & per competitor and the results are filled on the go to allow progress
* indication in the polar-sheet itself.
*
* @author D054528 Frederik Petersen
*
*/
public class PolarSheetGenerationWorker {
private final Set<PerRaceAndCompetitorPolarSheetGenerationWorker> workers;
private final List<List<BoatAndWindSpeed>> polarData;
private final Executor executor;
/**
* Will prepare the {@link PerRaceAndCompetitorPolarSheetGenerationWorker}s per race & per competitor. This includes
* determining start and end time.
*
* @param trackedRaces
* from which the data is to be collected
* @param executor
* executes the tasks upon {@link #startPolarSheetGeneration()}
*/
public PolarSheetGenerationWorker(Set<TrackedRace> trackedRaces, Executor executor) {
polarData = initializePolarDataContainer();
this.executor = executor;
workers = new HashSet<PerRaceAndCompetitorPolarSheetGenerationWorker>();
for (TrackedRace race : trackedRaces) {
TimePoint startTime = race.getStartOfRace();
TimePoint endTime = race.getEndOfRace();
if (endTime == null) {
// TODO Figure out if there is an alternative:
endTime = race.getTimePointOfNewestEvent();
}
RaceDefinition raceDefinition = race.getRace();
Iterable<Competitor> competitors = raceDefinition.getCompetitors();
for (Competitor competitor : competitors) {
PerRaceAndCompetitorPolarSheetGenerationWorker task = new PerRaceAndCompetitorPolarSheetGenerationWorker(race, this, startTime, endTime, competitor);
workers.add(task);
}
}
}
private List<List<BoatAndWindSpeed>> initializePolarDataContainer() {
List<List<BoatAndWindSpeed>> container = new ArrayList<List<BoatAndWindSpeed>>();
for (int i = 0; i < 360; i++) {
container.add(new ArrayList<BoatAndWindSpeed>());
}
return container;
}
/**
* Starts the {@link PerRaceAndCompetitorPolarSheetGenerationWorker}s
*/
public void startPolarSheetGeneration() {
for (Runnable task : workers) {
executor.execute(task);
}
}
/**
* To be called from {@link PerRaceAndCompetitorPolarSheetGenerationWorker} for adding a datapoint to the list of
* results
*
* @param roundedAngle
* boat's angle to the wind
* @param boatSpeed
* boat's speed in knots
* @param windSpeed
* wind's speed in knots
*/
protected void addPolarData(long roundedAngle, Speed boatSpeed, Speed windSpeed) {
int angle = (int) roundedAngle;
if (angle < 0) {
angle = (360 + angle);
}
BoatAndWindSpeed speeds = new BoatAndWindSpeedImpl(boatSpeed, windSpeed);
polarData.get(angle).add(speeds);
}
/**
*
* @return results already averaged per angle. Also datacount overall and per angle. And a completion flag to show
* if the complete polar sheet has been generated or if the current results are only an intermediate
* product.
*/
public PolarSheetsData getPolarData() {
Number[][] averagedPolarDataByWindSpeed = new Number[13][360];
Integer[] dataCountPerAngle = new Integer[360];
int dataCount = 0;
Map<Integer, Integer[]> dataCountPerAngleForWindspeed = new HashMap<Integer, Integer[]>();
for (int i = 0; i < 13; i++) {
dataCountPerAngleForWindspeed.put(i, new Integer[360]);
}
for (int i = 0; i < 360; i++) {
// Avoid Concurrent modification, lock would slow things down
BoatAndWindSpeed[] values = polarData.get(i).toArray(new BoatAndWindSpeed[polarData.get(i).size()]);
dataCount = dataCount + values.length;
dataCountPerAngle[i] = values.length;
double[] sumsPerWindSpeed = new double[13];
int[] dataCountPerWindSpeed = new int[13];
for (BoatAndWindSpeed singleDataPoint : values) {
if (singleDataPoint != null) {
int windSpeed = (int) singleDataPoint.getWindSpeed().getBeaufort();
//Somehow beaufort sometimes gets bigger than twelve. TODO: Investigation
if (windSpeed > 12) {
windSpeed = 12;
}
//TODO enable different kinds of metrics for boats speed
sumsPerWindSpeed[windSpeed] = sumsPerWindSpeed[windSpeed] + singleDataPoint.getBoatSpeed().getKnots();
dataCountPerWindSpeed[windSpeed]++;
}
}
for (int j = 0; j < 13; j++) {
Double average = sumsPerWindSpeed[j] / dataCountPerWindSpeed[j];
if (average.isNaN()) {
average = new Double(0);
}
averagedPolarDataByWindSpeed[j][i] = average;
dataCountPerAngleForWindspeed.get(j)[i] = dataCountPerWindSpeed[j];
}
}
boolean complete = true;
for (PerRaceAndCompetitorPolarSheetGenerationWorker task : workers) {
if (!task.isDone()) {
complete = false;
break;
}
}
PolarSheetsData data = new PolarSheetsDataImpl(averagedPolarDataByWindSpeed, complete, dataCount,
dataCountPerAngleForWindspeed);
return data;
}
/**
* Can be used to present more detailed data.
*
* @return The complete set of datapoints that have been added. Can be quite big, depending on the amount of races
* and competitors.
*/
public List<List<BoatAndWindSpeed>> getCompleteData() {
return polarData;
}
}
@@ -42,41 +42,42 @@ import com.sap.sailing.domain.racelog.RaceLog;
*/
public interface TrackedRace extends Serializable {
final long MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS = 30000;
final long DEFAULT_LIVE_DELAY_IN_MILLISECONDS = 5000;
RaceDefinition getRace();
RegattaAndRaceIdentifier getRaceIdentifier();
/**
* Computes the estimated start time for this race (not to be confused with the {@link #getStartOfTracking()} time point
* which is expected to be before the race start time). When there are no {@link MarkPassing}s for the first mark, <code>null</code>
* is returned. If there are mark passings for the first mark and the start time is less than
* {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} before the first mark passing for the
* Computes the estimated start time for this race (not to be confused with the {@link #getStartOfTracking()} time
* point which is expected to be before the race start time). When there are no {@link MarkPassing}s for the first
* mark, <code>null</code> is returned. If there are mark passings for the first mark and the start time is less
* than {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} before the first mark passing for the
* first mark. Otherwise, the first mark passing for the first mark minus
* {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} is returned as the race start time.<p>
* {@link #MAX_TIME_BETWEEN_START_AND_FIRST_MARK_PASSING_IN_MILLISECONDS} is returned as the race start time.
* <p>
*
* If no start time can be determined this way, <code>null</code> is returned.
*/
TimePoint getStartOfRace();
/**
* Determine the race end time is tricky. Boats may sink, stop, not finish, although they started the race. We therefore
* cannot wait for all boats to reach the finish line.
* The following rules are used to calculate the endOfRace:
* Determine the race end time is tricky. Boats may sink, stop, not finish, although they started the race. We
* therefore cannot wait for all boats to reach the finish line. The following rules are used to calculate the
* endOfRace:
* <ol>
* <li>Returns <code>null</code> if no boat passed the finish line</li>
* <li>Returns time of the last mark passing recorded for the finish line</li>
* <li>TODO: Returns the time of the first passing of the finish line + the target window (defined in the competition rules)
* if a target window has been defined for the race</li>
* </ol>
* <li>Returns <code>null</code> if no boat passed the finish line</li>
* <li>Returns time of the last mark passing recorded for the finish line</li>
* <li>TODO: Returns the time of the first passing of the finish line + the target window (defined in the
* competition rules) if a target window has been defined for the race</li>
* </ol>
*/
TimePoint getEndOfRace();
/**
* Returns a list of the first and last mark passing times of all course waypoints. Callers wanting to iterate over the
* result must <code>synchronize</code> on the result.
* Returns a list of the first and last mark passing times of all course waypoints. Callers wanting to iterate over
* the result must <code>synchronize</code> on the result.
*/
Iterable<Pair<Waypoint, Pair<TimePoint, TimePoint>>> getMarkPassingsTimes();
@@ -84,89 +85,84 @@ public interface TrackedRace extends Serializable {
* Shorthand for <code>{@link #getStart()}.{@link TimePoint#compareTo(TimePoint) compareTo(at)} &lt;= 0</code>
*/
boolean hasStarted(TimePoint at);
/**
* Clients can safely iterate over the iterable returned because it's a non-live copy of the tracked legs of this
* tracked race. This implies that should an update to the underlying list of waypoints in this race's {@link Course}
* take place after this method has returned, then this won't be reflected in the result returned. Callers should
* obtain the {@link Course#lockForRead() course's read lock} while using the result of this call if they want to
* ensure that no course update is applied concurrently.
* tracked race. This implies that should an update to the underlying list of waypoints in this race's
* {@link Course} take place after this method has returned, then this won't be reflected in the result returned.
* Callers should obtain the {@link Course#lockForRead() course's read lock} while using the result of this call if
* they want to ensure that no course update is applied concurrently.
*/
Iterable<TrackedLeg> getTrackedLegs();
TrackedLeg getTrackedLeg(Leg leg);
/**
* Tracking information about the leg <code>competitor</code> is on at <code>timePoint</code>, or
* <code>null</code> if the competitor hasn't started any leg yet at <code>timePoint</code> or has
* already finished the race.
* Tracking information about the leg <code>competitor</code> is on at <code>timePoint</code>, or <code>null</code>
* if the competitor hasn't started any leg yet at <code>timePoint</code> or has already finished the race.
*/
TrackedLegOfCompetitor getCurrentLeg(Competitor competitor, TimePoint timePoint);
/**
* Tells which leg the leader at <code>timePoint</code> is on
*/
TrackedLeg getCurrentLeg(TimePoint timePoint);
/**
* Precondition: waypoint must still be part of {@link #getRace()}.{@link RaceDefinition#getCourse() getCourse()}.
*/
TrackedLeg getTrackedLegFinishingAt(Waypoint endOfLeg);
/**
* Precondition: waypoint must still be part of {@link #getRace()}.{@link RaceDefinition#getCourse() getCourse()}.
*/
TrackedLeg getTrackedLegStartingAt(Waypoint startOfLeg);
/**
* The raw, updating feed of a single competitor participating in this race
*/
GPSFixTrack<Competitor, GPSFixMoving> getTrack(Competitor competitor);
/**
* Tells the leg on which the <code>competitor</code> was at time <code>at</code>.
* If the competitor hasn't passed the start waypoint yet, <code>null</code> is
* returned because the competitor was not yet on any leg at that point in time. If
* the time point happens to be after the last fix received from that competitor,
* the last known leg for that competitor is returned. If the time point is after the
* competitor's mark passing for the finish line, <code>null</code> is returned.
* For all legs except the last, if the time point equals a mark passing time point
* of the leg's starting waypoint, that leg is returned. For the time point of
* the mark passing for the finish line, the last leg is returned.
* Tells the leg on which the <code>competitor</code> was at time <code>at</code>. If the competitor hasn't passed
* the start waypoint yet, <code>null</code> is returned because the competitor was not yet on any leg at that point
* in time. If the time point happens to be after the last fix received from that competitor, the last known leg for
* that competitor is returned. If the time point is after the competitor's mark passing for the finish line,
* <code>null</code> is returned. For all legs except the last, if the time point equals a mark passing time point
* of the leg's starting waypoint, that leg is returned. For the time point of the mark passing for the finish line,
* the last leg is returned.
*/
TrackedLegOfCompetitor getTrackedLeg(Competitor competitor, TimePoint at);
TrackedLegOfCompetitor getTrackedLeg(Competitor competitor, Leg leg);
/**
* @return a sequential number counting the updates that occurred to this tracked race. Callers may use this to ask
* for updates newer than such a sequence number.
*/
long getUpdateCount();
int getRankDifference(Competitor competitor, Leg leg, TimePoint timePoint);
/**
* Computes the rank of the competitor in this race for the current time.
* Computes the rank of the competitor in this race for the current time.
*/
int getRank(Competitor competitor) throws NoWindException;
/**
* Computes the rank of <code>competitor</code> in this race. A competitor is ahead of all
* competitors that are one or more legs behind. Within the same leg, the rank is determined
* by the windward distance to go and therefore depends on the assumptions of the wind direction
* for the given <code>timePoint</code>. If the race hasn't {@link #hasStarted(TimePoint) started}
* yet, the result is undefined.
* Computes the rank of <code>competitor</code> in this race. A competitor is ahead of all competitors that are one
* or more legs behind. Within the same leg, the rank is determined by the windward distance to go and therefore
* depends on the assumptions of the wind direction for the given <code>timePoint</code>. If the race hasn't
* {@link #hasStarted(TimePoint) started} yet, the result is undefined.
*
* @return <code>0</code> in case the competitor hasn't participated in the race; a rank starting
* with <code>1</code> where rank <code>1</code> identifies the leader otherwise
* @return <code>0</code> in case the competitor hasn't participated in the race; a rank starting with
* <code>1</code> where rank <code>1</code> identifies the leader otherwise
*/
int getRank(Competitor competitor, TimePoint timePoint) throws NoWindException;
/**
* For a competitor, computes the distance (TODO not yet clear whether over ground or
* projected onto wind direction) into the race <code>secondsIntoTheRace</code> after
* the race {@link TrackedRace#getStart() started}.
* For a competitor, computes the distance (TODO not yet clear whether over ground or projected onto wind direction)
* into the race <code>secondsIntoTheRace</code> after the race {@link TrackedRace#getStart() started}.
*/
Distance getStartAdvantage(Competitor competitor, double secondsIntoTheRace);
@@ -184,14 +180,14 @@ public interface TrackedRace extends Serializable {
Iterable<MarkPassing> getMarkPassingsInOrder(Waypoint waypoint);
/**
* Obtains the {@link MarkPassing} for <code>competitor</code> passing <code>waypoint</code>. If no such
* mark passing has been reported (yet), <code>null</code> is returned.
* Obtains the {@link MarkPassing} for <code>competitor</code> passing <code>waypoint</code>. If no such mark
* passing has been reported (yet), <code>null</code> is returned.
*/
MarkPassing getMarkPassing(Competitor competitor, Waypoint waypoint);
/**
* Yields the track describing <code>mark</code>'s movement over time; never <code>null</code> because a
* new track will be created in case no track was present for <code>mark</code> so far.
* Yields the track describing <code>mark</code>'s movement over time; never <code>null</code> because a new track
* will be created in case no track was present for <code>mark</code> so far.
*/
GPSFixTrack<Mark, GPSFix> getOrCreateTrack(Mark mark);
@@ -205,7 +201,7 @@ public interface TrackedRace extends Serializable {
* is returned. Otherwise, the center of gravity between the mark positions is computed and returned.
*/
Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint);
/**
* Same as {@link #getWind(Position, TimePoint, Iterable) getWind(p, at, Collections.emptyList())}
*/
@@ -213,8 +209,8 @@ public interface TrackedRace extends Serializable {
/**
* Obtains estimated interpolated wind information for a given position and time point. The information is taken
* from all wind sources available except for those listed in <code>windSourcesToExclude</code>, using the confidences
* of the wind values provided by the various sources during averaging.
* from all wind sources available except for those listed in <code>windSourcesToExclude</code>, using the
* confidences of the wind values provided by the various sources during averaging.
*/
Wind getWind(Position p, TimePoint at, Iterable<WindSource> windSourcesToExclude);
@@ -232,10 +228,11 @@ public interface TrackedRace extends Serializable {
Iterable<WindSource> getWindSources();
/**
* Same as {@link #getOrCreateWindTrack(WindSource, long) getOrCreateWindTrack(windSource, getMillisecondsOverWhichToAverageWind())}.
* Same as {@link #getOrCreateWindTrack(WindSource, long) getOrCreateWindTrack(windSource,
* getMillisecondsOverWhichToAverageWind())}.
*/
WindTrack getOrCreateWindTrack(WindSource windSource);
WindTrack getOrCreateWindTrack(WindSource windSource, long delayForWindEstimationCacheInvalidation);
/**
@@ -244,26 +241,26 @@ public interface TrackedRace extends Serializable {
void waitForNextUpdate(int sinceUpdate) throws InterruptedException;
/**
* Time stamp of the start of the actual tracking.
* The value can be null (e.g. if we have not received any signal from the tracking infrastructure)
* Time stamp of the start of the actual tracking. The value can be null (e.g. if we have not received any signal
* from the tracking infrastructure)
*/
TimePoint getStartOfTracking();
/**
* Time stamp of the end of the actual tracking.
* The value can be null (e.g. if we have not received any signal from the tracking infrastructure)
* Time stamp of the end of the actual tracking. The value can be null (e.g. if we have not received any signal from
* the tracking infrastructure)
*/
TimePoint getEndOfTracking();
/**
* Regardless of the order in which events were received, this method returns the latest time point contained by any of
* the events received and processed.
* Regardless of the order in which events were received, this method returns the latest time point contained by any
* of the events received and processed.
*/
TimePoint getTimePointOfNewestEvent();
/**
* Regardless of the order in which events were received, this method returns the oldest time point contained by any of
* the events received and processed.
* Regardless of the order in which events were received, this method returns the oldest time point contained by any
* of the events received and processed.
*/
TimePoint getTimePointOfOldestEvent();
@@ -275,17 +272,18 @@ public interface TrackedRace extends Serializable {
* some tracking providers such as TracTrac. If the caller wants to iterate on the resulting collection or
* construct a {@link SortedSet#headSet(Object)} or {@link SortedSet#tailSet(Object)} and then iterate over
* that, the caller needs to invoke {@link #lockForRead(Iterable)} with the collection returned as parameter
* because insertions into the competitor's mark passing collection will obtain the corresponding write lock.
* because insertions into the competitor's mark passing collection will obtain the corresponding write
* lock.
*/
NavigableSet<MarkPassing> getMarkPassings(Competitor competitor);
void lockForRead(Iterable<MarkPassing> markPassings);
void unlockAfterRead(Iterable<MarkPassing> markPassings);
/**
* Time stamp that the event received last from the underlying push service carried on it.
* Note that these times may not increase monotonically.
* Time stamp that the event received last from the underlying push service carried on it. Note that these times may
* not increase monotonically.
*/
TimePoint getTimePointOfLastEvent();
@@ -297,7 +295,7 @@ public interface TrackedRace extends Serializable {
* Gets the current delay of incoming events to the real time of the events in milliseconds
*/
long getDelayToLiveInMillis();
/**
* Estimates the wind direction based on the observed boat courses at the time given for the position provided. The
* estimate is based on the assumption that the boats which are on an upwind or a downwind leg sail with very
@@ -322,13 +320,12 @@ public interface TrackedRace extends Serializable {
* we may be able to also infer the wind speed from the boat tracks.
*/
Wind getEstimatedWindDirection(Position position, TimePoint timePoint);
/**
* Determines whether the <code>competitor</code> is sailing on port or starboard tack at the
* <code>timePoint</code> requested. Note that this will have to retrieve information about the wind.
* This, in turn, can lead to the current thread obtaining the monitor of the various wind tracks,
* and, if the {@link WindSource#TRACK_BASED_ESTIMATION} source is used, also the monitors of the
* competitors' GPS tracks.
* Determines whether the <code>competitor</code> is sailing on port or starboard tack at the <code>timePoint</code>
* requested. Note that this will have to retrieve information about the wind. This, in turn, can lead to the
* current thread obtaining the monitor of the various wind tracks, and, if the
* {@link WindSource#TRACK_BASED_ESTIMATION} source is used, also the monitors of the competitors' GPS tracks.
*/
Tack getTack(Competitor competitor, TimePoint timePoint) throws NoWindException;
@@ -346,30 +343,34 @@ public interface TrackedRace extends Serializable {
* mark positions are not known (yet)
*/
Wind getDirectionFromStartToNextMark(TimePoint at);
/**
* Uses a {@link DouglasPeucker Douglas-Peucker} algorithm to approximate this track's fixes starting at
* time <code>from</code> until time point <code>to</code> such that the maximum distance between the
* track's fixes and the approximation is at most <code>maxDistance</code>.
* Uses a {@link DouglasPeucker Douglas-Peucker} algorithm to approximate this track's fixes starting at time
* <code>from</code> until time point <code>to</code> such that the maximum distance between the track's fixes and
* the approximation is at most <code>maxDistance</code>.
*/
List<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to);
/**
* @return a non-<code>null</code> but perhaps empty list of the maneuvers that <code>competitor</code> performed in
* this race between <code>from</code> and <code>to</code>.
* this race between <code>from</code> and <code>to</code>. Depending on <code>waitForLatest</code> the
* result is taken from the cache straight away (<code>waitForLatest==false</code>) or, if a re-calculation
* for the <code>key</code> is still ongoing, the result of that ongoing re-calculation is returned.
*/
List<Maneuver> getManeuvers(Competitor competitor, TimePoint from, TimePoint to, boolean waitForLatest) throws NoWindException;
List<Maneuver> getManeuvers(Competitor competitor, TimePoint from, TimePoint to, boolean waitForLatest)
throws NoWindException;
/**
* @return <code>true</code> if this race is known to start with an {@link LegType#UPWIND upwind} leg.
* If this is the case, the wind estimation may default to using the first leg's direction at race start
* time as the direction the wind comes from.
* @return <code>true</code> if this race is known to start with an {@link LegType#UPWIND upwind} leg. If this is
* the case, the wind estimation may default to using the first leg's direction at race start time as the
* direction the wind comes from.
*/
boolean raceIsKnownToStartUpwind();
/**
* Many calculations require valid wind data. In order to prevent NoWindException's to be handled by those calculation
* this method can be used to check whether the tracked race has sufficient wind information available.
* Many calculations require valid wind data. In order to prevent NoWindException's to be handled by those
* calculation this method can be used to check whether the tracked race has sufficient wind information available.
*
* @return <code>true</code> if {@link #getWind(Position, TimePoint)} delivers a (not null) wind fix.
*/
boolean hasWindData();
@@ -381,23 +382,23 @@ public interface TrackedRace extends Serializable {
boolean hasGPSData();
/**
* Adds a race change listener to the set of listeners that will be notified about changes to this race.
* The listener won't be serialized together with this object.
* Adds a race change listener to the set of listeners that will be notified about changes to this race. The
* listener won't be serialized together with this object.
*/
void addListener(RaceChangeListener listener);
void removeListener(RaceChangeListener listener);
Distance getDistanceTraveled(Competitor competitor, TimePoint timePoint);
Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint) throws NoWindException;
/**
* Calls {@link #getWindWithConfidence(Position, TimePoint, Iterable)} and excludes those wind sources listed in
* {@link #getWindSourcesToExclude}.
*/
WindWithConfidence<Pair<Position, TimePoint>> getWindWithConfidence(Position p, TimePoint at);
/**
* Lists those wind sources which by default are not considered in {@link #getWind(Position, TimePoint)} and
* {@link #getWindWithConfidence(Position, TimePoint)}.
@@ -407,8 +408,8 @@ public interface TrackedRace extends Serializable {
/**
* Loops over this tracked race's wind sources and from each asks its averaged wind for the position <code>p</code>
* and time point <code>at</code>, using the particular wind source's averaging interval. The confidences delivered
* by each wind source are used during computing the averaged result across the wind sources. The result has the averaged
* confidence attached.
* by each wind source are used during computing the averaged result across the wind sources. The result has the
* averaged confidence attached.
*/
WindWithConfidence<Pair<Position, TimePoint>> getWindWithConfidence(Position p, TimePoint at,
Iterable<WindSource> windSourcesToExclude);
@@ -420,7 +421,8 @@ public interface TrackedRace extends Serializable {
WindWithConfidence<TimePoint> getEstimatedWindDirectionWithConfidence(Position position, TimePoint timePoint);
/**
* After the call returns, {@link #getWindSourcesToExclude()} returns an iterable that equals <code>windSourcesToExclude</code>
* After the call returns, {@link #getWindSourcesToExclude()} returns an iterable that equals
* <code>windSourcesToExclude</code>
*/
void setWindSourcesToExclude(Iterable<? extends WindSource> windSourcesToExclude);
@@ -431,25 +433,27 @@ public interface TrackedRace extends Serializable {
* if <code>true</code> and any cache update is currently going on, wait for the update to complete and
* then fetch the updated value; otherwise, serve this requests from whatever is currently in the cache
*/
Distance getAverageCrossTrackError(Competitor competitor, TimePoint timePoint, boolean waitForLatestAnalysis) throws NoWindException;
Distance getAverageCrossTrackError(Competitor competitor, TimePoint timePoint, boolean waitForLatestAnalysis)
throws NoWindException;
WindStore getWindStore();
Competitor getOverallLeader(TimePoint timePoint) throws NoWindException;
/**
* Returns the competitors of this tracked race, according to their ranking. Competitors whose {@link #getRank(Competitor)} is 0 will
* be sorted "worst".
* Returns the competitors of this tracked race, according to their ranking. Competitors whose
* {@link #getRank(Competitor)} is 0 will be sorted "worst".
*/
List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) throws NoWindException;
Distance getAverageCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly, boolean waitForLatestAnalyses) throws NoWindException;
Distance getAverageCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly,
boolean waitForLatestAnalyses) throws NoWindException;
/**
* When provided with a {@link WindStore} during construction, the tracked race will asynchronously load the wind
* data for this tracked race from the wind store in a background thread and update this tracked race with the results.
* Clients that want to wait for the wind loading process to complete can do so by calling this method which will block
* until the wind loading has completed.
* data for this tracked race from the wind store in a background thread and update this tracked race with the
* results. Clients that want to wait for the wind loading process to complete can do so by calling this method
* which will block until the wind loading has completed.
*/
void waitUntilWindLoadingComplete() throws InterruptedException;
@@ -68,7 +68,6 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
windSourcesToExclude.add(new WindSourceImpl(WindSourceType.COURSE_BASED));
setWindSourcesToExclude(windSourcesToExclude);
}
for (Competitor competitor : getRace().getCompetitors()) {
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = getTrack(competitor);
track.addListener(this);
@@ -90,7 +89,11 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
* {@link #raceIsKnownToStartUpwind} (see also {@link #raceIsKnownToStartUpwind()}) is initialized based on the <code>race</code>'s
* {@link RaceDefinition#getBoatClass()} boat class's {@link BoatClass#typicallyStartsUpwind()} result. It can be changed
* using {@link #setRaceIsKnownToStartUpwind(boolean)}. Uses <code>millisecondsOverWhichToAverageWind/2</code> for the
* <code>delayForCacheInvalidationOfWindEstimation</code> argument of the constructor.
* <code>delayForCacheInvalidationOfWindEstimation</code> argument of the constructor.<p>
*
* Loading wind tracks from the <code>windStore</code> happens asynchronously which means that when the constructor returns,
* the caller cannot assume that all wind tracks have yet been loaded completely. The caller may call {@link #waitUntilWindLoadingComplete()}
* to wait until all persistent wind sources have been successfully and completely loaded.
*/
public DynamicTrackedRaceImpl(TrackedRegatta trackedRegatta, RaceDefinition race,
WindStore windStore, long delayToLiveInMillis,
@@ -542,8 +545,8 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
/**
* In addition to calling the super class implementation, notifies all race listeners registered with this tracked
* race which in particular replicates all wind fixes that may have been loaded from the wind store for the new
* track.
* race using their {@link RaceChangeListener#windDataReceived(Wind, WindSource)} method. In particular this
* replicates all wind fixes that may have been loaded from the wind store for the new track.
*/
@Override
protected WindTrack createWindTrack(WindSource windSource, long delayForWindEstimationCacheInvalidation) {
@@ -553,8 +556,8 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
result.lockForRead();
try {
for (Wind wind : result.getRawFixes()) {
notifyListeners(wind, windSource);
}
notifyListeners(wind, windSource); // Note that this doesn't notify the track's listeners but the tracked race's listeners.
} // In particular, the wind store won't receive events (again) for the wind fixes it already has.
} finally {
result.unlockAfterRead();
}
@@ -305,7 +305,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
MarkPassingByTimeComparator.INSTANCE));
}
markPassingsTimes = new ArrayList<Pair<Waypoint, Pair<TimePoint, TimePoint>>>();
windTracks = new HashMap<WindSource, WindTrack>();
windTracks = new ConcurrentHashMap<WindSource, WindTrack>();
new Thread("Wind loader for tracked race "+getRace().getName()) {
@Override
public void run() {
@@ -316,20 +316,20 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
try {
final Map<? extends WindSource, ? extends WindTrack> loadedWindTracks = windStore.loadWindTracks(
trackedRegatta, TrackedRaceImpl.this, millisecondsOverWhichToAverageWind);
windTracks.putAll(loadedWindTracks);
synchronized (windTracks) {
windTracks.putAll(loadedWindTracks);
}
} finally {
LockUtil.unlockAfterRead(serializationLock);
}
synchronized (TrackedRaceImpl.this) {
windLoadingCompleted = true;
TrackedRaceImpl.this.notifyAll();
synchronized (TrackedRaceImpl.this) {
windLoadingCompleted = true;
TrackedRaceImpl.this.notifyAll();
}
}
}
}.start();
// by default, a tracked race offers one course-based wind estimation, one track-based wind estimation track and
// one "WEB" track for manual or REST-based wind reception; other wind tracks may be added as fixes are received
// for them.
// by default, a tracked race offers one course-based wind estimation and one track-based wind estimation track;
// other wind tracks may be added as fixes are received for them and as they are loaded from the persistent store
WindSource courseBasedWindSource = new WindSourceImpl(WindSourceType.COURSE_BASED);
windTracks.put(courseBasedWindSource, getOrCreateWindTrack(courseBasedWindSource, delayForWindEstimationCacheInvalidation));
WindSource trackBasedWindSource = new WindSourceImpl(WindSourceType.TRACK_BASED_ESTIMATION);
@@ -41,6 +41,7 @@
<plugin id="com.sap.sailing.monitoring" autoStart="true" startLevel="5" />
<plugin id="com.sap.sailing.server" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.server.gateway" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.server.gateway.ess40" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.server.replication" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.www" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.www.events" autoStart="true" startLevel="4" />
+7
View File
@@ -71,6 +71,13 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
version="0.0.0"
unpack="false"/>
<plugin
id="com.sap.sailing.server.gateway.ess40"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="com.tractrac.clientmodule"
download-size="0"
@@ -7,7 +7,8 @@ Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Fragment-Host: com.sap.sailing.gwt.ui
Require-Bundle: com.sap.sailing.server,
org.hamcrest.core;bundle-version="1.1.0"
org.hamcrest.core;bundle-version="1.1.0",
com.sap.sailing.expeditionconnector
Bundle-ClassPath: .
Import-Package: javax.jms;version="1.1.0",
javax.servlet;version="2.5.0",
@@ -0,0 +1,734 @@
package com.sap.sailing.gwt.ui.test;
import java.io.Serializable;
import java.util.List;
import java.util.NavigableSet;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.RegattaListener;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceChangeListener;
import com.sap.sailing.domain.tracking.RaceListener;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRaceStatus;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
public class MockedTrackedRace implements DynamicTrackedRace {
private static final long serialVersionUID = 5827912985564121181L;
private final WindTrack windTrack = new WindTrackImpl(/* millisecondsOverWhichToAverage */ 30000, /* useSpeed */ true, "TestWindTrack");
public WindTrack getWindTrack() {
return windTrack;
}
@Override
public RaceDefinition getRace() {
// TODO Auto-generated method stub
return null;
}
@Override
public TimePoint getStartOfRace() {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<TrackedLeg> getTrackedLegs() {
// TODO Auto-generated method stub
return null;
}
@Override
public TrackedLeg getTrackedLeg(Leg leg) {
// TODO Auto-generated method stub
return null;
}
@Override
public TrackedLegOfCompetitor getCurrentLeg(Competitor competitor, TimePoint timePoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public TrackedLeg getCurrentLeg(TimePoint timePoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public TrackedLeg getTrackedLegFinishingAt(Waypoint endOfLeg) {
// TODO Auto-generated method stub
return null;
}
@Override
public TrackedLeg getTrackedLegStartingAt(Waypoint startOfLeg) {
// TODO Auto-generated method stub
return null;
}
@Override
public TrackedLegOfCompetitor getTrackedLeg(Competitor competitor, TimePoint at) {
// TODO Auto-generated method stub
return null;
}
@Override
public TrackedLegOfCompetitor getTrackedLeg(Competitor competitor, Leg leg) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getUpdateCount() {
// TODO Auto-generated method stub
return 0;
}
@Override
public int getRankDifference(Competitor competitor, Leg leg, TimePoint timePoint) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int getRank(Competitor competitor) throws NoWindException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int getRank(Competitor competitor, TimePoint timePoint) throws NoWindException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Distance getStartAdvantage(Competitor competitor, double secondsIntoTheRace) {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<MarkPassing> getMarkPassingsInOrder(Waypoint waypoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public MarkPassing getMarkPassing(Competitor competitor, Waypoint waypoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public DynamicGPSFixTrack<Mark, GPSFix> getOrCreateTrack(Mark mark) {
// TODO Auto-generated method stub
return null;
}
@Override
public WindTrack getOrCreateWindTrack(WindSource windSource, long delayForWindEstimationCacheInvalidation) {
// TODO Auto-generated method stub
return null;
}
@Override
public void waitForNextUpdate(int sinceUpdate) throws InterruptedException {
// TODO Auto-generated method stub
}
@Override
public TimePoint getStartOfTracking() {
// TODO Auto-generated method stub
return null;
}
@Override
public TimePoint getTimePointOfNewestEvent() {
// TODO Auto-generated method stub
return null;
}
@Override
public NavigableSet<MarkPassing> getMarkPassings(Competitor competitor) {
// TODO Auto-generated method stub
return null;
}
@Override
public void recordFix(Competitor competitor, GPSFixMoving fix) {
// TODO Auto-generated method stub
}
@Override
public void recordWind(Wind wind, WindSource windSource) {
if (windSource.getType() == WindSourceType.EXPEDITION) {
windTrack.add(wind);
}
}
@Override
public void addListener(RaceChangeListener listener) {
// TODO Auto-generated method stub
}
@Override
public void updateMarkPassings(Competitor competitor, Iterable<MarkPassing> markPassings) {
// TODO Auto-generated method stub
}
@Override
public void setStartTimeReceived(TimePoint start) {
// TODO Auto-generated method stub
}
@Override
public DynamicGPSFixTrack<Competitor, GPSFixMoving> getTrack(Competitor competitor) {
// TODO Auto-generated method stub
return null;
}
@Override
public void removeWind(Wind wind, WindSource windSource) {
// TODO Auto-generated method stub
}
@Override
public TimePoint getTimePointOfLastEvent() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setMillisecondsOverWhichToAverageSpeed(long millisecondsOverWhichToAverageSpeed) {
// TODO Auto-generated method stub
}
@Override
public void setMillisecondsOverWhichToAverageWind(long millisecondsOverWhichToAverageWind) {
// TODO Auto-generated method stub
}
@Override
public long getMillisecondsOverWhichToAverageSpeed() {
// TODO Auto-generated method stub
return 0;
}
@Override
public long getMillisecondsOverWhichToAverageWind() {
// TODO Auto-generated method stub
return 0;
}
@Override
public Wind getEstimatedWindDirection(Position position, TimePoint timePoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean hasStarted(TimePoint at) {
// TODO Auto-generated method stub
return false;
}
@Override
public DynamicTrackedRegatta getTrackedRegatta() {
return new DynamicTrackedRegatta() {
private static final long serialVersionUID = 2651590861333064588L;
@Override
public Regatta getRegatta() {
return new Regatta() {
private static final long serialVersionUID = -4908774269425170811L;
@Override
public String getName() {
return "A Mocked Test Regatta";
}
@Override
public Serializable getId() {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<RaceDefinition> getAllRaces() {
// TODO Auto-generated method stub
return null;
}
@Override
public BoatClass getBoatClass() {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<Competitor> getCompetitors() {
// TODO Auto-generated method stub
return null;
}
@Override
public void addRace(RaceDefinition race) {
// TODO Auto-generated method stub
}
@Override
public void removeRace(RaceDefinition raceDefinition) {
// TODO Auto-generated method stub
}
@Override
public RaceDefinition getRaceByName(String raceName) {
// TODO Auto-generated method stub
return null;
}
@Override
public void addRegattaListener(RegattaListener listener) {
// TODO Auto-generated method stub
}
@Override
public void removeRegattaListener(RegattaListener listener) {
// TODO Auto-generated method stub
}
@Override
public RegattaIdentifier getRegattaIdentifier() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getBaseName() {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<? extends Series> getSeries() {
// TODO Auto-generated method stub
return null;
}
@Override
public Series getSeriesByName(String seriesName) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isPersistent() {
// TODO Auto-generated method stub
return false;
}
@Override
public void addRaceColumnListener(RaceColumnListener listener) {
// TODO Auto-generated method stub
}
@Override
public void removeRaceColumnListener(RaceColumnListener listener) {
// TODO Auto-generated method stub
}
@Override
public ScoringScheme getScoringScheme() {
// TODO Auto-generated method stub
return null;
}
};
}
@Override
public Iterable<TrackedRace> getTrackedRaces() {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<TrackedRace> getTrackedRaces(BoatClass boatClass) {
// TODO Auto-generated method stub
return null;
}
@Override
public void addTrackedRace(TrackedRace trackedRace) {
// TODO Auto-generated method stub
}
@Override
public void removeTrackedRace(TrackedRace trackedRace) {
// TODO Auto-generated method stub
}
@Override
public void addRaceListener(RaceListener listener) {
// TODO Auto-generated method stub
}
@Override
public int getNetPoints(Competitor competitor, TimePoint timePoint) throws NoWindException {
// TODO Auto-generated method stub
return 0;
}
@Override
public DynamicTrackedRace getTrackedRace(RaceDefinition race) {
// TODO Auto-generated method stub
return null;
}
@Override
public DynamicTrackedRace getExistingTrackedRace(RaceDefinition race) {
// TODO Auto-generated method stub
return null;
}
@Override
public void removeTrackedRace(RaceDefinition raceDefinition) {
// TODO Auto-generated method stub
}
@Override
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore,
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
// TODO Auto-generated method stub
return null;
}
};
}
@Override
public Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public Tack getTack(Competitor competitor, TimePoint timePoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public Wind getDirectionFromStartToNextMark(TimePoint at) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<Maneuver> getManeuvers(Competitor competitor, TimePoint from, TimePoint to, boolean waitForLatest) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean raceIsKnownToStartUpwind() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setRaceIsKnownToStartUpwind(boolean raceIsKnownToStartUpwind) {
// TODO Auto-generated method stub
}
@Override
public RegattaAndRaceIdentifier getRaceIdentifier() {
// TODO Auto-generated method stub
return null;
}
@Override
public TimePoint getEndOfRace() {
// TODO Auto-generated method stub
return null;
}
@Override
public Distance getDistanceTraveled(Competitor competitor, TimePoint timePoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint)
throws NoWindException {
// TODO Auto-generated method stub
return null;
}
@Override
public Wind getWind(Position p, TimePoint at) {
// TODO Auto-generated method stub
return null;
}
@Override
public Wind getWind(Position p, TimePoint at, Iterable<WindSource> windSourcesToExclude) {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<WindSource> getWindSources(WindSourceType type) {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<WindSource> getWindSources() {
// TODO Auto-generated method stub
return null;
}
@Override
public WindWithConfidence<Pair<Position, TimePoint>> getWindWithConfidence(Position p, TimePoint at,
Iterable<WindSource> windSourcesToExclude) {
// TODO Auto-generated method stub
return null;
}
@Override
public WindWithConfidence<TimePoint> getEstimatedWindDirectionWithConfidence(Position position, TimePoint timePoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public WindWithConfidence<Pair<Position, TimePoint>> getWindWithConfidence(Position p, TimePoint at) {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<WindSource> getWindSourcesToExclude() {
// TODO Auto-generated method stub
return null;
}
@Override
public TimePoint getEndOfTracking() {
// TODO Auto-generated method stub
return null;
}
@Override
public TimePoint getTimePointOfOldestEvent() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setStartOfTrackingReceived(TimePoint startOfTrackingReceived) {
// TODO Auto-generated method stub
}
@Override
public void setEndOfTrackingReceived(TimePoint endOfTrackingReceived) {
// TODO Auto-generated method stub
}
@Override
public Iterable<Pair<Waypoint, Pair<TimePoint, TimePoint>>> getMarkPassingsTimes() {
// TODO Auto-generated method stub
return null;
}
@Override
public Distance getAverageCrossTrackError(Competitor competitor, TimePoint timePoint, boolean waitForLatestAnalysis) throws NoWindException {
// TODO Auto-generated method stub
return null;
}
@Override
public WindTrack getOrCreateWindTrack(WindSource windSource) {
// TODO Auto-generated method stub
return null;
}
@Override
public void recordFix(Mark mark, GPSFix fix) {
// TODO Auto-generated method stub
}
@Override
public void removeListener(RaceChangeListener listener) {
// TODO Auto-generated method stub
}
@Override
public WindStore getWindStore() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setWindSourcesToExclude(Iterable<? extends WindSource> windSourcesToExclude) {
// TODO Auto-generated method stub
}
@Override
public Competitor getOverallLeader(TimePoint timePoint) throws NoWindException {
// TODO Auto-generated method stub
return null;
}
@Override
public long getDelayToLiveInMillis() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void setDelayToLiveInMillis(long delayToLiveInMillis) {
// TODO Auto-generated method stub
}
@Override
public void setAndFixDelayToLiveInMillis(long delayToLiveInMillis) {
// TODO Auto-generated method stub
}
@Override
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public Distance getAverageCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly, boolean waitForLatestAnalyses)
throws NoWindException {
// TODO Auto-generated method stub
return null;
}
@Override
public void waitUntilWindLoadingComplete() throws InterruptedException {
// TODO Auto-generated method stub
}
@Override
public Iterable<Mark> getMarks() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean hasWindData() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean hasGPSData() {
// TODO Auto-generated method stub
return false;
}
@Override
public void lockForRead(Iterable<MarkPassing> markPassings) {
// TODO Auto-generated method stub
}
@Override
public void unlockAfterRead(Iterable<MarkPassing> markPassings) {
// TODO Auto-generated method stub
}
@Override
public TrackedRaceStatus getStatus() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setStatus(TrackedRaceStatus newStatus) {
// TODO Auto-generated method stub
}
@Override
public void waitUntilNotLoading() {
// TODO Auto-generated method stub
}
@Override
public RaceLog getRaceLog() {
// TODO Auto-generated method stub
return null;
}
}
@@ -0,0 +1,203 @@
package com.sap.sailing.gwt.ui.test;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableSet;
import java.util.UUID;
import junit.framework.Assert;
import org.junit.Test;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
import com.sap.sailing.domain.common.PolarSheetsData;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.ScoreCorrectionProvider;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.tracking.impl.WindImpl;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.server.SailingServiceImpl;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sailing.server.replication.ReplicationService;
public class PolarSheetGenerationServiceTest {
private static final String BOAT_CLASS = "Forelle";
@Test
public void testPolarSheetGenerationService() throws InterruptedException {
SailingService service = new MockSailingServiceForPolarSheetGeneration();
List<RegattaAndRaceIdentifier> idList = new ArrayList<RegattaAndRaceIdentifier>();
idList.add(new RegattaNameAndRaceName("IrgendeineRegatta", "IrgendeinRennen"));
PolarSheetGenerationTriggerResponse triggerData = service.generatePolarSheetForRaces(idList);
Assert.assertNotNull(triggerData);
Assert.assertEquals(BOAT_CLASS, triggerData.getBoatClassName());
Assert.assertNotNull(triggerData.getId());
boolean complete = false;
PolarSheetsData results = null;
double timeOut = 10;
while (!complete && timeOut > 0) {
Thread.sleep(200);
timeOut = timeOut - 0.2;
results = service.getPolarSheetsGenerationResults(triggerData.getId());
complete = results.isComplete();
}
Assert.assertTrue(complete);
Assert.assertNotNull(results);
Assert.assertEquals(4, results.getDataCount());
Assert.assertEquals(4.0, results.getAveragedPolarDataByWindSpeed()[1][45]);
Assert.assertEquals(2.0, results.getAveragedPolarDataByWindSpeed()[1][55]);
Assert.assertEquals(6.0, results.getAveragedPolarDataByWindSpeed()[1][30]);
}
@SuppressWarnings("serial")
private class MockSailingServiceForPolarSheetGeneration extends SailingServiceImpl {
@Override
protected RacingEventService getService() {
RacingEventService service = new MockRacingEventServiceForPolarSheetGeneration();
return service;
}
@Override
protected ServiceTracker<RacingEventService, RacingEventService> createAndOpenRacingEventServiceTracker(
BundleContext context) {
return null;
}
@Override
protected ServiceTracker<ReplicationService, ReplicationService> createAndOpenReplicationServiceTracker(
BundleContext context) {
return null;
}
@Override
protected ServiceTracker<ScoreCorrectionProvider, ScoreCorrectionProvider> createAndOpenScoreCorrectionProviderServiceTracker(
BundleContext bundleContext) {;
return null;
}
}
private class MockRacingEventServiceForPolarSheetGeneration extends RacingEventServiceImpl {
@Override
public TrackedRace getTrackedRace(RegattaAndRaceIdentifier raceIdentifier) {
MockTrackedRaceForPolarSheetGeneration trackedRace = new MockTrackedRaceForPolarSheetGeneration();
return trackedRace;
}
}
@SuppressWarnings("serial")
private class MockTrackedRaceForPolarSheetGeneration extends MockedTrackedRace {
@Override
public DynamicGPSFixTrack<Competitor, GPSFixMoving> getTrack(Competitor competitor) {
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = new MockDynamicGPSFixMovinTrackForPolarSheetGeneration<Competitor>(competitor, 0);
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.0, 1.0), new MillisecondsTimePoint(1), new KnotSpeedWithBearingImpl(3.0, new DegreeBearingImpl(-45.0))));
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.001, 1.001), new MillisecondsTimePoint(2), new KnotSpeedWithBearingImpl(5.0, new DegreeBearingImpl(-45.0))));
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.002, 1.002), new MillisecondsTimePoint(3), new KnotSpeedWithBearingImpl(2.0, new DegreeBearingImpl(-55.0))));
track.addGPSFix(new MockGPSFixMovingForPolarSheetGeneration(new DegreePosition(1.003, 1.003), new MillisecondsTimePoint(4), new KnotSpeedWithBearingImpl(6.0, new DegreeBearingImpl(-30.0))));
//Should not be taken into consideration because it happens after the race has ended
track.addGPSFix(new GPSFixMovingImpl(new DegreePosition(2.0, 3.0), new MillisecondsTimePoint(7), new KnotSpeedWithBearingImpl(5.0, new DegreeBearingImpl(-45.0))));
return track;
}
@Override
public Wind getWind(Position p, TimePoint at) {
Wind wind = new WindImpl(p, at, new KnotSpeedWithBearingImpl(2.0, new DegreeBearingImpl(180.0)));
return wind;
}
@Override
public RaceDefinition getRace() {
BoatClass forelle = new BoatClassImpl(BOAT_CLASS, true);
Competitor competitor = new CompetitorImpl(UUID.randomUUID(), "Hans Frantz", new TeamImpl("SAP", null, null), new BoatImpl("Schnelle Forelle", forelle, "GER000"));
ArrayList<Competitor> competitors = new ArrayList<Competitor>();
competitors.add(competitor);
RaceDefinition race = new RaceDefinitionImpl("Forelle1", new CourseImpl("ForelleCourse", new ArrayList<Waypoint>()), forelle, competitors);
return race;
}
@Override
public TimePoint getStartOfRace() {
return new MillisecondsTimePoint(1);
}
@Override
public TimePoint getEndOfRace() {
return new MillisecondsTimePoint(5);
}
}
@SuppressWarnings("serial")
private class MockGPSFixMovingForPolarSheetGeneration extends GPSFixMovingImpl {
public MockGPSFixMovingForPolarSheetGeneration(Position position, TimePoint timePoint, SpeedWithBearing speed) {
super(position, timePoint, speed);
}
@Override
public boolean isValid() {
return true;
}
}
@SuppressWarnings("serial")
private class MockDynamicGPSFixMovinTrackForPolarSheetGeneration<ItemType> extends DynamicGPSFixMovingTrackImpl<ItemType> {
public MockDynamicGPSFixMovinTrackForPolarSheetGeneration(ItemType trackedItem,
long millisecondsOverWhichToAverage) {
super(trackedItem, millisecondsOverWhichToAverage);
}
@Override
protected boolean isValid(NavigableSet<GPSFixMoving> rawFixes, GPSFixMoving e) {
return true;
}
}
}
@@ -1,4 +1,4 @@
eclipse.preferences.version=1
entryPointModules=
filesCopiedToWebInfLib=gwt-servlet.jar
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBW11dPjwvZXh0cmEtYXJncz48dm0tYXJncz48IVtDREFUQVstWG14NTEybV1dPjwvdm0tYXJncz48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuQWRtaW5Db25zb2xlPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLkxlYWRlcmJvYXJkPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLkxlYWRlcmJvYXJkRWRpdGluZzwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5SYWNlQm9hcmQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuU3BlY3RhdG9yPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlVzZXJNYW5hZ2VtZW50PC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlR2VmlldzwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5WaWRlb1BvcHVwPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLllvdXR1YmVQb3B1cDwvZW50cnktcG9pbnQtbW9kdWxlPjwvZ3d0LWNvbXBpbGUtc2V0dGluZ3M+
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDEwMjRtXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5BZG1pbkNvbnNvbGU8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmRFZGl0aW5nPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlJhY2VCb2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5TcGVjdGF0b3I8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVXNlck1hbmFnZW1lbnQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVHZWaWV3PC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlZpZGVvUG9wdXA8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuWW91dHViZVBvcHVwPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlBvbGFyU2hlZXRzPC9lbnRyeS1wb2ludC1tb2R1bGU+PC9nd3QtY29tcGlsZS1zZXR0aW5ncz4\=
+4 -4
View File
@@ -32,10 +32,6 @@ h1 {
}
/** Most GWT widgets already have a style name defined */
.gwt-DialogBox {
width: 400px;
z-index: 20;
}
.dialogVPanel {
margin: 5px;
@@ -96,6 +92,10 @@ h1 {
font-weight: bold;
}
.gwt-DialogBox {
z-index: 20;
}
.gwt-DialogBox .Caption {
background: none repeat scroll 0 0 #e5e5e5;
}
+133
View File
@@ -0,0 +1,133 @@
@import url(fontface.css);
@import url(CommonControls.css);
/** Add css rules here for your application. */
/*
body #calendar:after
content: " ";
display: block;
height: 0;
clear: both;
visibility: hidden;
*/
.clear {
clear: both;
font-size: 1px;
height: 0px;
line-height: 0px;
margin: -1px 0 0;
width: 100%; }
.cover {
left: -1000px;
overflow: hidden;
position: absolute;
top: -1000px; }
body {
background: #fff;
font-family: 'UbuntuRegular', Arial, Verdana, sans-serif;
line-height: 1;
font-size: 14px;
font-weight: 400;
padding: 85px 0 120px 0;
margin: 0;
}
/** Example rules used by the template application (remove for your app) */
h1 {
font-size: 2em;
font-weight: bold;
color: #777777;
margin: 40px 0px 70px;
text-align: center;
}
table {
border-collapse: separate; }
.leaderboardMargin {
margin: 5px;
}
.leaderboardContent {
}
.leaderboardContent td, .leaderboardContent th {
vertical-align: bottom;
line-height: 1.3;
padding-top: 2px;
}
.leaderboardContent-toolbar {
}
.leaderboardLabel {
border-bottom: 2px solid #007dc0;
font-weight: bold;
margin: 5px;
}
.refreshAndSettings {
background: #f2f2f2;
border-bottom: 2px solid #fff;
border-top: 2px solid #fff;
height: 30px; }
.refreshAndSettings table td {
padding: 0 10px 0 0;}
.refreshAndSettings table table td{
padding: 0 0 0 0;}
input.magnifier{
display: block;
margin: 3px auto 0 auto !important;
}
body, table td, select, button {
font-family: 'UbuntuLight', Arial, Verdana, sans-serif;
font-size: 14px;
}
.busyIndicator-simpleBusyIndicator {
margin-top: 7px;
}
.errorLabel {
color: #FF0000;
}
.abstractChartPanel-importantMessageOfChart {
font-family: 'UbuntuBold',Arial,Verdana,sans-serif;
font-size: 20px;
height: 70px;
margin: 0 auto;
padding: 49px 0 0 80px;
width: 300px;
color: #7c7c7c;
background: url(images/important-message.png) left center no-repeat;
}
.LeaderboardHeader {
position: relative;
margin: 0 auto;
width: 400px;
text-align: center;
font-family: 'UbuntuRegular', Arial, Verdana, sans-serif;
font-size: 18px;
color: #fff;
margin-top: 22px;
}
.leaderboardHeading {
font-size: 16px;
font-family: 'UbuntuRegular', Arial, Verdana, sans-serif;
font-weight: bold;
}
.gwt-DialogBox {
z-index: 20;
}
@@ -0,0 +1,34 @@
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>SAP Sailing Analytics Polar Sheets</title>
<meta content='width = device-width, initial-scale = 1.0, user-scalable = yes' name='viewport'>
<meta content='yes' name='apple-mobile-web-app-capable'>
<meta content='black' name='apple-mobile-web-app-status-bar-style'>
<!-- <link href='iphone-splash-screen.png' rel='apple-touch-startup-image'> -->
<link href='images/sap-sailing-app-icon.png' rel='apple-touch-icon'>
<link rel="shortcut icon" type="image/x-icon" href="images/sap.ico" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="highcharts/js/highcharts.js"></script>
<script type="text/javascript" src="highcharts/js/highcharts-more.js"></script>
<!-- Optionally, add a highcharts theme file -->
<script type="text/javascript" src="highcharts/js/themes/grid.js"></script>
<script type="text/javascript" language="javascript" src="com.sap.sailing.gwt.ui.PolarSheets/com.sap.sailing.gwt.ui.PolarSheets.nocache.js"></script>
</head>
<body>
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
<!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
<noscript>
<div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
Your web browser must have JavaScript enabled
in order for this application to display correctly.
</div>
</noscript>
</body>
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 18 KiB

@@ -18,9 +18,12 @@ public class GetCompetitorsRaceDataAction extends DefaultAsyncAction<Competitors
private final Date toDate;
private final long stepSizeInMs;
private final DetailType detailType;
private final String leaderboarGroupName;
private final String leaderboardName;
public GetCompetitorsRaceDataAction(SailingServiceAsync sailingService, RegattaAndRaceIdentifier raceIdentifier, List<CompetitorDTO> competitors,
Date fromDate, Date toDate, long stepSizeInMs, DetailType detailType, AsyncCallback<CompetitorsRaceDataDTO> callback) {
public GetCompetitorsRaceDataAction(SailingServiceAsync sailingService, RegattaAndRaceIdentifier raceIdentifier,
List<CompetitorDTO> competitors, Date fromDate, Date toDate, long stepSizeInMs, DetailType detailType,
String leaderboardGroupName, String leaderboardName, AsyncCallback<CompetitorsRaceDataDTO> callback) {
super(callback);
this.sailingService = sailingService;
this.raceIdentifier = raceIdentifier;
@@ -29,11 +32,13 @@ public class GetCompetitorsRaceDataAction extends DefaultAsyncAction<Competitors
this.toDate = toDate;
this.stepSizeInMs = stepSizeInMs;
this.detailType = detailType;
this.leaderboarGroupName = leaderboardGroupName;
this.leaderboardName = leaderboardName;
}
@Override
public void execute(AsyncActionsExecutor asyncActionsExecutor) {
sailingService.getCompetitorsRaceData(raceIdentifier, competitors, fromDate, toDate, stepSizeInMs, detailType,
sailingService.getCompetitorsRaceData(raceIdentifier, competitors, fromDate, toDate, stepSizeInMs, detailType, leaderboarGroupName, leaderboardName,
(AsyncCallback<CompetitorsRaceDataDTO>) getWrapperCallback(asyncActionsExecutor));
}
}
@@ -0,0 +1,32 @@
package com.sap.sailing.gwt.ui.actions;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
public class GetPolarSheetDataByAngleAction extends DefaultAsyncAction<PolarSheetsHistogramData> {
private final SailingServiceAsync sailingService;
private final String polarSheetId;
private final int angle;
private final int windSpeed;
public GetPolarSheetDataByAngleAction(SailingServiceAsync sailingService,
String polarSheetId, int angle, int windSpeed, AsyncCallback<PolarSheetsHistogramData> callback) {
super(callback);
this.sailingService = sailingService;
this.polarSheetId = polarSheetId;
this.angle = angle;
this.windSpeed = windSpeed;
}
@Override
public void execute(AsyncActionsExecutor asyncActionsExecutor) {
sailingService.getPolarSheetData(polarSheetId, angle, windSpeed, (AsyncCallback<PolarSheetsHistogramData>) getWrapperCallback(asyncActionsExecutor));
}
}
@@ -19,6 +19,7 @@ import com.sap.sailing.gwt.ui.shared.EventDTO;
public abstract class AbstractLeaderboardDialog extends DataEntryDialog<LeaderboardDescriptor> {
protected final StringMessages stringMessages;
protected TextBox nameTextBox;
protected TextBox displayNameTextBox;
protected LeaderboardDescriptor leaderboard;
protected ListBox sailingEventsListBox;
protected Collection<EventDTO> existingEvents;
@@ -41,6 +42,7 @@ public abstract class AbstractLeaderboardDialog extends DataEntryDialog<Leaderbo
protected LeaderboardDescriptor getResult() {
int[] discardThresholdsBoxContents = getDiscardThresholds(discardThresholdBoxes);
leaderboard.setName(nameTextBox.getValue());
leaderboard.setDisplayName(displayNameTextBox.getValue());
leaderboard.setDiscardThresholds(discardThresholdsBoxContents);
CourseAreaDTO courseArea = getSelectedCourseArea();
if (courseArea == null) {
@@ -13,6 +13,7 @@ public class FlexibleLeaderboardCreateDialog extends FlexibleLeaderboardDialog {
Collection<EventDTO> existingEvents, ErrorReporter errorReporter, DialogCallback<LeaderboardDescriptor> callback) {
super(stringMessages.createFlexibleLeaderboard(), new LeaderboardDescriptor(), stringMessages, existingEvents, errorReporter, new FlexibleLeaderboardDialog.LeaderboardParameterValidator(stringMessages, existingLeaderboards), callback);
nameTextBox = createTextBox(null);
displayNameTextBox = createTextBox(null);
scoringSchemeListBox = createScoringSchemeListBox(this, stringMessages);
sailingEventsListBox = createSailingEventListBox(this, stringMessages);
discardThresholdBoxes = initEmptyDiscardThresholdBoxes(this);
@@ -2,11 +2,12 @@ package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Collection;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.StringMessages;
@@ -78,17 +79,19 @@ public abstract class FlexibleLeaderboardDialog extends AbstractLeaderboardDialo
@Override
protected Widget getAdditionalWidget() {
VerticalPanel mainPanel = new VerticalPanel();
Grid formGrid = new Grid(5,2);
FlowPanel mainPanel = new FlowPanel();
Grid formGrid = new Grid(5,3);
formGrid.setCellSpacing(3);
formGrid.setWidget(0, 0, new Label(stringMessages.name() + ":"));
formGrid.setWidget(0, 0, createLabel(stringMessages.name()));
formGrid.setWidget(0, 1, nameTextBox);
formGrid.setWidget(1, 0, new Label(stringMessages.scoringSystem() + ":"));
formGrid.setWidget(1, 1, scoringSchemeListBox);
formGrid.setWidget(2, 0, new Label(stringMessages.event() + ":"));
formGrid.setWidget(2, 1, sailingEventsListBox);
formGrid.setWidget(3, 0, new Label(stringMessages.courseArea() + ":"));
formGrid.setWidget(3, 1, courseAreaListBox);
formGrid.setWidget(1, 0, createLabel(stringMessages.displayName()));
formGrid.setWidget(1, 1, displayNameTextBox);
formGrid.setWidget(2, 0, createLabel(stringMessages.scoringSystem()));
formGrid.setWidget(2, 1, scoringSchemeListBox);
formGrid.setWidget(3, 0, new Label(stringMessages.event() + ":"));
formGrid.setWidget(3, 1, sailingEventsListBox);
formGrid.setWidget(4, 0, new Label(stringMessages.courseArea() + ":"));
formGrid.setWidget(4, 1, courseAreaListBox);
mainPanel.add(formGrid);
mainPanel.add(new Label(stringMessages.discardRacesFromHowManyStartedRacesOn()));
HorizontalPanel hp = new HorizontalPanel();
@@ -97,7 +100,9 @@ public abstract class FlexibleLeaderboardDialog extends AbstractLeaderboardDialo
hp.add(new Label("" + (i + 1) + "."));
hp.add(discardThresholdBoxes[i]);
}
alignAllPanelWidgetsVertically(hp, HasVerticalAlignment.ALIGN_MIDDLE);
mainPanel.add(hp);
return mainPanel;
}
}
@@ -18,7 +18,7 @@ public class FlexibleLeaderboardEditDialog extends FlexibleLeaderboardDialog {
stringConstants, otherExistingLeaderboards), callback);
nameTextBox = createTextBox(leaderboard.getName());
displayNameTextBox = createTextBox(leaderboard.getDisplayName());
scoringSchemeListBox = createListBox(false);
int j = 0;
for (ScoringSchemeType scoringSchemeType: ScoringSchemeType.values()) {
@@ -199,6 +199,14 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
return sortList.size() > 0 & sortList.get(0).isAscending();
}
});
TextColumn<StrippedLeaderboardDTO> leaderboardDisplayNameColumn = new TextColumn<StrippedLeaderboardDTO>() {
@Override
public String getValue(StrippedLeaderboardDTO leaderboard) {
return leaderboard.getDisplayName() !=null ? leaderboard.getDisplayName() : "";
}
};
TextColumn<StrippedLeaderboardDTO> discardingOptionsColumn = new TextColumn<StrippedLeaderboardDTO>() {
@Override
public String getValue(StrippedLeaderboardDTO leaderboard) {
@@ -266,6 +274,7 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
}
});
leaderboardTable.addColumn(linkColumn, stringMessages.name());
leaderboardTable.addColumn(leaderboardDisplayNameColumn, stringMessages.displayName());
leaderboardTable.addColumn(discardingOptionsColumn, stringMessages.discarding());
leaderboardTable.addColumn(leaderboardTypeColumn, stringMessages.type());
leaderboardTable.addColumn(scoringSystemColumn, stringMessages.scoringSystem());
@@ -1022,7 +1031,7 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
}
private void updateLeaderboard(final String oldLeaderboardName, final LeaderboardDescriptor leaderboardToUdate) {
sailingService.updateLeaderboard(oldLeaderboardName, leaderboardToUdate.getName(),
sailingService.updateLeaderboard(oldLeaderboardName, leaderboardToUdate.getName(), leaderboardToUdate.getDisplayName(),
leaderboardToUdate.getDiscardThresholds(), new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable t) {
@@ -1036,6 +1045,7 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
StrippedLeaderboardDTO dao = leaderboardList.getList().get(i);
if (dao.name.equals(oldLeaderboardName)) {
dao.name = leaderboardToUdate.getName();
dao.displayName = leaderboardToUdate.getDisplayName();
dao.discardThresholds = leaderboardToUdate.getDiscardThresholds();
break;
}
@@ -9,6 +9,15 @@ import com.sap.sailing.domain.common.ScoringSchemeType;
*/
public class LeaderboardDescriptor {
private String name;
private String displayName;
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
private ScoringSchemeType scoringScheme;
private int[] discardThresholds;
private String regattaName;
@@ -126,7 +126,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
MarkDTO left;
MarkDTO right;
String gateName;
if (first.name.toLowerCase().contains("left")) {
if (first.name.matches("^.*"+REGEX_FOR_LEFT+".*$")) {
left = first;
right = second;
} else {
@@ -134,7 +134,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
right = first;
}
gateName = left.name.replaceFirst(REGEX_FOR_LEFT, "");
result = new GateDTO(gateName, left, right);
result = new GateDTO(/* generate UUID on the server */ null, gateName, left, right);
}
return result;
}
@@ -145,7 +145,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
}
}
private static final String REGEX_FOR_LEFT = "( \\()?[lL][eE][fF][tT]\\)?";
private static final String REGEX_FOR_LEFT = "( \\()?(([lL][eE][fF][tT])|(1))\\)?";
/**
* A table that lists the marks for which events have been received for the race selected. Note that this list may
@@ -375,7 +375,8 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
}
}
assert newLeft != null && newRight != null;
return new GateDTO(oldGate.name, newLeft, newRight);
// if old gate had null ID, the new gate will have a null ID too, causing the server to generate one
return new GateDTO(oldGate.getIdAsString(), oldGate.name, newLeft, newRight);
}
private CellTable<MarkDTO> createAvailableMarksTable(final StringMessages stringMessages, AdminConsoleTableResources tableRes,
@@ -15,6 +15,7 @@ public class RegattaLeaderboardCreateDialog extends RegattaLeaderboardDialog {
super(stringConstants.createRegattaLeaderboard(), new LeaderboardDescriptor(), existingRegattas, stringConstants, existingEvents, errorReporter, new RegattaLeaderboardDialog.LeaderboardParameterValidator(stringConstants, existingLeaderboards), callback);
nameTextBox = createTextBox(null);
displayNameTextBox = createTextBox(null);
regattaListBox = createListBox(false);
regattaListBox.addItem(stringConstants.pleaseSelectARegatta());
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Collection;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
@@ -86,16 +87,18 @@ public abstract class RegattaLeaderboardDialog extends AbstractLeaderboardDialog
protected Widget getAdditionalWidget() {
VerticalPanel mainPanel = new VerticalPanel();
Grid formGrid = new Grid(5,2);
Grid formGrid = new Grid(5,3);
formGrid.setCellSpacing(3);
formGrid.setWidget(0, 0, new Label(stringMessages.name() + ":"));
formGrid.setWidget(0, 0, createLabel(stringMessages.name()));
formGrid.setWidget(0, 1, nameTextBox);
formGrid.setWidget(1, 0, new Label(stringMessages.regatta() + ":"));
formGrid.setWidget(1, 1, regattaListBox);
formGrid.setWidget(2, 0, new Label(stringMessages.event() + ":"));
formGrid.setWidget(2, 1, sailingEventsListBox);
formGrid.setWidget(3, 0, new Label(stringMessages.courseArea() + ":"));
formGrid.setWidget(3, 1, courseAreaListBox);
formGrid.setWidget(1, 0, createLabel(stringMessages.displayName()));
formGrid.setWidget(1, 1, displayNameTextBox);
formGrid.setWidget(2, 0, createLabel(stringMessages.regatta()));
formGrid.setWidget(2, 1, regattaListBox);
formGrid.setWidget(3, 0, new Label(stringMessages.event() + ":"));
formGrid.setWidget(3, 1, sailingEventsListBox);
formGrid.setWidget(4, 0, new Label(stringMessages.courseArea() + ":"));
formGrid.setWidget(4, 1, courseAreaListBox);
mainPanel.add(formGrid);
@@ -106,6 +109,7 @@ public abstract class RegattaLeaderboardDialog extends AbstractLeaderboardDialog
hp.add(new Label("" + (i + 1) + "."));
hp.add(discardThresholdBoxes[i]);
}
alignAllPanelWidgetsVertically(hp, HasVerticalAlignment.ALIGN_MIDDLE);
mainPanel.add(hp);
return mainPanel;
}
@@ -17,6 +17,7 @@ public class RegattaLeaderboardEditDialog extends RegattaLeaderboardDialog {
stringConstants, otherExistingLeaderboards), callback);
nameTextBox = createTextBox(leaderboard.getName());
displayNameTextBox = createTextBox(leaderboard.getDisplayName());
regattaListBox = createListBox(false);
regattaListBox.addItem(stringConstants.pleaseSelectARegatta());
@@ -89,6 +89,7 @@ public abstract class DataEntryDialog<T> {
okButton = new Button(okButtonName);
okButton.getElement().getStyle().setMargin(3, Unit.PX);
FlowPanel dialogFPanel = new FlowPanel();
dialogFPanel.setWidth("100%");
statusLabel = new Label();
dialogFPanel.add(statusLabel);
if (message != null) {
@@ -98,6 +99,7 @@ public abstract class DataEntryDialog<T> {
}
panelForAdditionalWidget = new FlowPanel();
panelForAdditionalWidget.setWidth("100%");
dialogFPanel.add(panelForAdditionalWidget);
FlowPanel buttonPanel = new FlowPanel();
dialogFPanel.add(buttonPanel);
@@ -139,7 +141,7 @@ public abstract class DataEntryDialog<T> {
}
protected abstract T getResult();
/**
* Creates a text box with a key-up listener attached which ensures the value is updated after each
* key-up event and the entire dialog is {@link #validate() validated} in this case.
@@ -335,6 +337,18 @@ public abstract class DataEntryDialog<T> {
AbstractEntryPoint.linkEscapeToButton(getCancelButton(), result);
return result;
}
/**
* Creates a standard label for input fields.
* The label has some default formatting like "no wrap" and a colon right after the label text
* @param name
* @return
*/
public Label createLabel(String name) {
Label result = new Label(name + ":");
result.setWordWrap(false);
return result;
}
public ListBox createListBox(boolean isMultipleSelect) {
ListBox result = new ListBox(isMultipleSelect);
@@ -20,6 +20,10 @@ public class DetailTypeFormatter {
return stringMessages.rankGain();
case RACE_RANK:
return stringMessages.rank();
case REGATTA_RANK:
return stringMessages.regattaRank();
case OVERALL_RANK:
return stringMessages.overallRank();
case NUMBER_OF_MANEUVERS:
return stringMessages.numberOfManeuvers();
case CURRENT_SPEED_OVER_GROUND_IN_KNOTS:
@@ -128,6 +132,8 @@ public class DetailTypeFormatter {
// Cases for detail types without unit, so that an empty string is returned.
case RACE_RANK:
case REGATTA_RANK:
case OVERALL_RANK:
case CURRENT_LEG:
case TACK:
case JIBE:
@@ -205,6 +211,10 @@ public class DetailTypeFormatter {
return stringMessages.gapToLeaderInSecondsTooltip();
case RACE_RANK:
return stringMessages.rankTooltip();
case REGATTA_RANK:
return stringMessages.regattaRankTooltip();
case OVERALL_RANK:
return stringMessages.overallRankTooltip();
case RANK_GAIN:
return stringMessages.rankGainTooltip();
case TACK:
File mode changed.
@@ -14,6 +14,9 @@ import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
import com.sap.sailing.domain.common.PolarSheetsData;
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.common.ScoringSchemeType;
@@ -54,333 +57,247 @@ import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
/**
* The client side stub for the RPC service. Usually, when a <code>null</code>
* date is passed to the time-dependent service methods, an empty (non-
* <code>null</code>) result is returned.
* The client side stub for the RPC service. Usually, when a <code>null</code> date is passed to
* the time-dependent service methods, an empty (non-<code>null</code>) result is returned.
*/
@RemoteServiceRelativePath("sailing")
public interface SailingService extends RemoteService {
List<TracTracConfigurationDTO> getPreviousTracTracConfigurations()
throws Exception;
List<TracTracConfigurationDTO> getPreviousTracTracConfigurations() throws Exception;
List<RegattaDTO> getRegattas();
List<RegattaDTO> getRegattas();
List<EventDTO> getEvents();
List<EventDTO> getEvents();
Pair<String, List<TracTracRaceRecordDTO>> listTracTracRacesInEvent(String eventJsonURL) throws Exception;
Pair<String, List<TracTracRaceRecordDTO>> listTracTracRacesInEvent(
String eventJsonURL) throws Exception;
void trackWithTracTrac(RegattaIdentifier regattaToAddTo, Iterable<TracTracRaceRecordDTO> rrs, String liveURI,
String storedURI, boolean trackWind, boolean correctWindByDeclination, boolean simulateWithStartTimeNow) throws Exception;
void trackWithTracTrac(RegattaIdentifier regattaToAddTo,
Iterable<TracTracRaceRecordDTO> rrs, String liveURI,
String storedURI, boolean trackWind,
boolean correctWindByDeclination, boolean simulateWithStartTimeNow)
throws Exception;
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable<SwissTimingRaceRecordDTO> rrs, String hostname, int port,
boolean canSendRequests, boolean trackWind, boolean correctWindByDeclination) throws Exception;
void replaySwissTimingRace(RegattaIdentifier regattaIdentifier, Iterable<SwissTimingReplayRaceDTO> replayRaces,
boolean trackWind, boolean correctWindByDeclination, boolean simulateWithStartTimeNow);
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo,
Iterable<SwissTimingRaceRecordDTO> rrs, String hostname, int port,
boolean canSendRequests, boolean trackWind,
boolean correctWindByDeclination) throws Exception;
void storeTracTracConfiguration(String name, String jsonURL, String liveDataURI, String storedDataURI) throws Exception;
void replaySwissTimingRace(RegattaIdentifier regattaIdentifier,
Iterable<SwissTimingReplayRaceDTO> replayRaces, boolean trackWind,
boolean correctWindByDeclination, boolean simulateWithStartTimeNow);
void stopTrackingEvent(RegattaIdentifier eventIdentifier) throws Exception;
void storeTracTracConfiguration(String name, String jsonURL,
String liveDataURI, String storedDataURI) throws Exception;
void stopTrackingRaces(Iterable<RegattaAndRaceIdentifier> racesToStopTracking) throws Exception;
void removeAndUntrackRaces(Iterable<RegattaAndRaceIdentifier> regattaNamesAndRaceNames);
void stopTrackingEvent(RegattaIdentifier eventIdentifier) throws Exception;
WindInfoForRaceDTO getRawWindFixes(RegattaAndRaceIdentifier raceIdentifier, Collection<WindSource> windSources);
void stopTrackingRaces(
Iterable<RegattaAndRaceIdentifier> racesToStopTracking)
throws Exception;
void setWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO wind);
void removeAndUntrackRaces(
Iterable<RegattaAndRaceIdentifier> regattaNamesAndRaceNames);
WindInfoForRaceDTO getAveragedWindInfo(RegattaAndRaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth,
int numberOfFixes, Collection<String> windSourceTypeNames) throws NoWindException;
WindInfoForRaceDTO getRawWindFixes(RegattaAndRaceIdentifier raceIdentifier,
Collection<WindSource> windSources);
WindInfoForRaceDTO getAveragedWindInfo(RegattaAndRaceIdentifier raceIdentifier, Date from, Date to, long resolutionInMilliseconds,
Collection<String> windSourceTypeNames);
void setWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO wind);
WindInfoForRaceDTO getAveragedWindInfo(RegattaAndRaceIdentifier raceIdentifier, Date from, long millisecondsStepWidth,
int numberOfFixes, double latDeg, double lngDeg, Collection<String> windSources) throws NoWindException;
WindInfoForRaceDTO getAveragedWindInfo(
RegattaAndRaceIdentifier raceIdentifier, Date from,
long millisecondsStepWidth, int numberOfFixes,
Collection<String> windSourceTypeNames) throws NoWindException;
RaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to,
boolean extrapolate) throws NoWindException;
Map<CompetitorDTO, List<GPSFixDTO>> getBoatPositions(RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, Date> from,
Map<CompetitorDTO, Date> to, boolean extrapolate) throws NoWindException;
WindInfoForRaceDTO getAveragedWindInfo(
RegattaAndRaceIdentifier raceIdentifier, Date from, Date to,
long resolutionInMilliseconds,
Collection<String> windSourceTypeNames);
RaceTimesInfoDTO getRaceTimesInfo(RegattaAndRaceIdentifier raceIdentifier);
List<RaceTimesInfoDTO> getRaceTimesInfos(Collection<RegattaAndRaceIdentifier> raceIdentifiers);
CourseDTO getCoursePositions(RegattaAndRaceIdentifier raceIdentifier, Date date);
WindInfoForRaceDTO getAveragedWindInfo(
RegattaAndRaceIdentifier raceIdentifier, Date from,
long millisecondsStepWidth, int numberOfFixes, double latDeg,
double lngDeg, Collection<String> windSources)
throws NoWindException;
List<ControlPointDTO> getRaceCourse(RegattaAndRaceIdentifier raceIdentifier, Date date);
RaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier,
Date date, Map<CompetitorDTO, Date> from,
Map<CompetitorDTO, Date> to, boolean extrapolate)
throws NoWindException;
List<QuickRankDTO> getQuickRanks(RegattaAndRaceIdentifier raceIdentifier, Date date) throws NoWindException;
Map<CompetitorDTO, List<GPSFixDTO>> getBoatPositions(
RegattaAndRaceIdentifier raceIdentifier,
Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to,
boolean extrapolate) throws NoWindException;
void removeWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO windDTO);
RaceTimesInfoDTO getRaceTimesInfo(RegattaAndRaceIdentifier raceIdentifier);
public List<String> getLeaderboardNames() throws Exception;
LeaderboardDTO getLeaderboardByName(String leaderboardName, Date date,
Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails) throws Exception;
List<RaceTimesInfoDTO> getRaceTimesInfos(
Collection<RegattaAndRaceIdentifier> raceIdentifiers);
List<StrippedLeaderboardDTO> getLeaderboards();
List<StrippedLeaderboardDTO> getLeaderboardsByEvent(RegattaDTO regatta);
void updateLeaderboard(String leaderboardName, String newLeaderboardName, String newLeaderboardDisplayName, int[] newDiscardingThreasholds);
CourseDTO getCoursePositions(RegattaAndRaceIdentifier raceIdentifier,
Date date);
StrippedLeaderboardDTO createFlexibleLeaderboard(String leaderboardName, int[] discardThresholds, ScoringSchemeType scoringSchemeType, Serializable courseAreaId);
List<ControlPointDTO> getRaceCourse(
RegattaAndRaceIdentifier raceIdentifier, Date date);
StrippedLeaderboardDTO createRegattaLeaderboard(RegattaIdentifier regattaIdentifier, int[] discardThresholds, Serializable courseAreaId);
List<QuickRankDTO> getQuickRanks(RegattaAndRaceIdentifier raceIdentifier,
Date date) throws NoWindException;
void removeLeaderboard(String leaderboardName);
void removeWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO windDTO);
void renameLeaderboard(String leaderboardName, String newLeaderboardName);
public List<String> getLeaderboardNames() throws Exception;
void renameLeaderboardColumn(String leaderboardName, String oldColumnName, String newColumnName);
LeaderboardDTO getLeaderboardByName(String leaderboardName, Date date,
Collection<String> namesOfRaceColumnsForWhichToLoadLegDetails)
throws Exception;
void removeLeaderboardColumn(String leaderboardName, String columnName);
void addColumnToLeaderboard(String columnName, String leaderboardName, boolean medalRace);
void moveLeaderboardColumnUp(String leaderboardName, String columnName);
void moveLeaderboardColumnDown(String leaderboardName, String columnName);
RegattaDTO createRegatta(String regattaName, String boatClassName,
LinkedHashMap<String, Pair<List<Triple<String, Integer, Color>>, Boolean>> seriesNamesWithFleetNamesAndFleetOrderingAndMedal,
boolean persistent, ScoringSchemeType scoringSchemeType);
void removeRegatta(RegattaIdentifier regattaIdentifier);
List<RaceColumnInSeriesDTO> addRaceColumnsToSeries(RegattaIdentifier regattaIdentifier, String seriesName, List<String> columnNames);
List<StrippedLeaderboardDTO> getLeaderboards();
RaceColumnInSeriesDTO addRaceColumnToSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName);
List<StrippedLeaderboardDTO> getLeaderboardsByEvent(RegattaDTO regatta);
void removeRaceColumnsFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, List<String> columnNames);
void updateLeaderboard(String leaderboardName, String newLeaderboardName,
int[] newDiscardingThreasholds);
void removeRaceColumnFromSeries(RegattaIdentifier regattaIdentifier, String seriesName, String columnName);
StrippedLeaderboardDTO createFlexibleLeaderboard(String leaderboardName,
int[] discardThresholds, ScoringSchemeType scoringSchemeType,
Serializable courseAreaId);
void moveRaceColumnInSeriesUp(RegattaIdentifier regattaIdentifier, String seriesName, String columnName);
StrippedLeaderboardDTO createRegattaLeaderboard(
RegattaIdentifier regattaIdentifier, int[] discardThresholds,
Serializable courseAreaId);
void moveRaceColumnInSeriesDown(RegattaIdentifier regattaIdentifier, String seriesName, String columnName);
void removeLeaderboard(String leaderboardName);
boolean connectTrackedRaceToLeaderboardColumn(String leaderboardName, String raceColumnName,
String fleetName, RegattaAndRaceIdentifier raceIdentifier);
void disconnectLeaderboardColumnFromTrackedRace(String leaderboardName, String raceColumnName, String fleetName);
Map<String, RegattaAndRaceIdentifier> getRegattaAndRaceNameOfTrackedRaceConnectedToLeaderboardColumn(String leaderboardName, String raceColumnName);
void renameLeaderboard(String leaderboardName, String newLeaderboardName);
void updateLeaderboardCarryValue(String leaderboardName, String competitorIdAsString, Double carriedPoints);
void renameLeaderboardColumn(String leaderboardName, String oldColumnName,
String newColumnName);
/**
* @return the new net points in {@link Pair#getA()} and the new total points in {@link Pair#getB()} for time point
* <code>date</code> after the max points reason has been updated to <code>maxPointsReasonAsString</code>.
*/
Triple<Double, Double, Boolean> updateLeaderboardMaxPointsReason(String leaderboardName, String competitorIdAsString,
String raceColumnName, MaxPointsReason maxPointsReason, Date date) throws NoWindException;
void removeLeaderboardColumn(String leaderboardName, String columnName);
Triple<Double, Double, Boolean> updateLeaderboardScoreCorrection(String leaderboardName, String competitorIdAsString,
String columnName, Double correctedScore, Date date) throws NoWindException;
void addColumnToLeaderboard(String columnName, String leaderboardName,
boolean medalRace);
void updateCompetitorDisplayNameInLeaderboard(String leaderboardName, String competitorIdAsString, String displayName);
void updateIsMedalRace(String leaderboardName, String columnName, boolean isMedalRace);
void moveLeaderboardColumnUp(String leaderboardName, String columnName);
List<SwissTimingConfigurationDTO> getPreviousSwissTimingConfigurations();
void moveLeaderboardColumnDown(String leaderboardName, String columnName);
List<SwissTimingRaceRecordDTO> listSwissTimingRaces(String hostname, int port, boolean canSendRequests) throws Exception;
RegattaDTO createRegatta(
String regattaName,
String boatClassName,
LinkedHashMap<String, Pair<List<Triple<String, Integer, Color>>, Boolean>> seriesNamesWithFleetNamesAndFleetOrderingAndMedal,
boolean persistent, ScoringSchemeType scoringSchemeType);
void storeSwissTimingConfiguration(String configName, String hostname, int port, boolean canSendRequests);
void removeRegatta(RegattaIdentifier regattaIdentifier);
void sendSwissTimingDummyRace(String racMessage, String stlMesssage, String ccgMessage) throws IllegalArgumentException;
List<RaceColumnInSeriesDTO> addRaceColumnsToSeries(
RegattaIdentifier regattaIdentifier, String seriesName,
List<String> columnNames);
String[] getCountryCodes();
Map<CompetitorDTO, List<GPSFixDTO>> getDouglasPoints(RegattaAndRaceIdentifier raceIdentifier,
Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to, double meters) throws NoWindException;
RaceColumnInSeriesDTO addRaceColumnToSeries(
RegattaIdentifier regattaIdentifier, String seriesName,
String columnName);
Map<CompetitorDTO, List<ManeuverDTO>> getManeuvers(RegattaAndRaceIdentifier raceIdentifier,
Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to) throws NoWindException;
void removeRaceColumnsFromSeries(RegattaIdentifier regattaIdentifier,
String seriesName, List<String> columnNames);
List<StrippedLeaderboardDTO> getLeaderboardsByRace(RaceDTO race);
List<LeaderboardGroupDTO> getLeaderboardGroups(boolean withGeoLocationData);
LeaderboardGroupDTO getLeaderboardGroupByName(String groupName, boolean withGeoLocationData);
void renameLeaderboardGroup(String oldName, String newName);
void removeLeaderboardGroup(String groupName);
LeaderboardGroupDTO createLeaderboardGroup(String groupName, String description,
boolean displayGroupsInReverseOrder, int[] overallLeaderboardDiscardThresholds,
ScoringSchemeType overallLeaderboardScoringSchemeType);
void updateLeaderboardGroup(String oldName, String newName, String description, List<String> leaderboardNames,
int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType);
void removeRaceColumnFromSeries(RegattaIdentifier regattaIdentifier,
String seriesName, String columnName);
CompetitorsRaceDataDTO getCompetitorsRaceData(RegattaAndRaceIdentifier race, List<CompetitorDTO> competitors, Date from, Date to,
long stepSizeInMs, DetailType detailType, String leaderboardGroupName, String leaderboardName) throws NoWindException;
void moveRaceColumnInSeriesUp(RegattaIdentifier regattaIdentifier,
String seriesName, String columnName);
void setRaceIsKnownToStartUpwind(RegattaAndRaceIdentifier raceIdentifier, boolean raceIsKnownToStartUpwind);
void moveRaceColumnInSeriesDown(RegattaIdentifier regattaIdentifier,
String seriesName, String columnName);
void setWindSourcesToExclude(RegattaAndRaceIdentifier raceIdentifier, Iterable<WindSource> windSourcesToExclude);
ReplicationStateDTO getReplicaInfo();
boolean connectTrackedRaceToLeaderboardColumn(String leaderboardName,
String raceColumnName, String fleetName,
RegattaAndRaceIdentifier raceIdentifier);
void startReplicatingFromMaster(String masterName, String exchangeName, int servletPort, int messagingPort) throws Exception;
void disconnectLeaderboardColumnFromTrackedRace(String leaderboardName,
String raceColumnName, String fleetName);
void updateRaceDelayToLive(RegattaAndRaceIdentifier regattaAndRaceIdentifier, long delayToLiveInMs);
Map<String, RegattaAndRaceIdentifier> getRegattaAndRaceNameOfTrackedRaceConnectedToLeaderboardColumn(
String leaderboardName, String raceColumnName);
void updateRacesDelayToLive(List<RegattaAndRaceIdentifier> regattaAndRaceIdentifiers, long delayToLiveInMs);
void updateLeaderboardCarryValue(String leaderboardName,
String competitorIdAsString, Double carriedPoints);
void updateEvent(String eventName, Serializable id, VenueDTO venue, String publicationUrl, boolean isPublic,
List<String> regattaNames);
/**
* @return the new net points in {@link Pair#getA()} and the new total
* points in {@link Pair#getB()} for time point <code>date</code>
* after the max points reason has been updated to
* <code>maxPointsReasonAsString</code>.
*/
Triple<Double, Double, Boolean> updateLeaderboardMaxPointsReason(
String leaderboardName, String competitorIdAsString,
String raceColumnName, MaxPointsReason maxPointsReason, Date date)
throws NoWindException;
EventDTO createEvent(String eventName, String venueName, String publicationUrl, boolean isPublic, List<String> courseAreaNames);
Triple<Double, Double, Boolean> updateLeaderboardScoreCorrection(
String leaderboardName, String competitorIdAsString,
String columnName, Double correctedScore, Date date)
throws NoWindException;
void removeEvent(Serializable id);
void updateCompetitorDisplayNameInLeaderboard(String leaderboardName,
String competitorIdAsString, String displayName);
void renameEvent(Serializable id, String newName);
void updateIsMedalRace(String leaderboardName, String columnName,
boolean isMedalRace);
EventDTO getEventByName(String eventName);
List<SwissTimingConfigurationDTO> getPreviousSwissTimingConfigurations();
Iterable<ScoreCorrectionProviderDTO> getScoreCorrectionProviderDTOs() throws Exception;
List<SwissTimingRaceRecordDTO> listSwissTimingRaces(String hostname,
int port, boolean canSendRequests) throws Exception;
RegattaScoreCorrectionDTO getScoreCorrections(String scoreCorrectionProviderName, String eventName, String boatClassName,
Date timePointWhenResultPublished) throws Exception;
void storeSwissTimingConfiguration(String configName, String hostname,
int port, boolean canSendRequests);
void updateLeaderboardScoreCorrectionsAndMaxPointsReasons(BulkScoreCorrectionDTO updates) throws NoWindException;
void sendSwissTimingDummyRace(String racMessage, String stlMesssage,
String ccgMessage) throws IllegalArgumentException;
WindInfoForRaceDTO getWindSourcesInfo(RegattaAndRaceIdentifier raceIdentifier);
String[] getCountryCodes();
List<String> getFregResultUrls();
Map<CompetitorDTO, List<GPSFixDTO>> getDouglasPoints(
RegattaAndRaceIdentifier raceIdentifier,
Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to,
double meters) throws NoWindException;
void removeFregURLs(Set<String> toRemove) throws Exception;
Map<CompetitorDTO, List<ManeuverDTO>> getManeuvers(
RegattaAndRaceIdentifier raceIdentifier,
Map<CompetitorDTO, Date> from, Map<CompetitorDTO, Date> to)
throws NoWindException;
void addFragUrl(String result) throws Exception;
List<StrippedLeaderboardDTO> getLeaderboardsByRace(RaceDTO race);
Void updateLeaderboardScoreCorrectionMetadata(String leaderboardName, Date timePointOfLastCorrectionValidity,
String comment);
List<LeaderboardGroupDTO> getLeaderboardGroups(boolean withGeoLocationData);
RaceCourseMarksDTO getRaceCourseMarks(RegattaAndRaceIdentifier raceIdentifier, Date date);
LeaderboardGroupDTO getLeaderboardGroupByName(String groupName,
boolean withGeoLocationData);
void updateRaceCourse(RegattaAndRaceIdentifier raceIdentifier, List<ControlPointDTO> controlPoints);
void addColumnsToLeaderboard(String leaderboardName, List<Pair<String, Boolean>> columnsToAdd);
void removeLeaderboardGroup(String groupName);
void removeLeaderboardColumns(String leaderboardName, List<String> columnsToRemove);
LeaderboardGroupDTO createLeaderboardGroup(String groupName,
String description, boolean displayGroupsInReverseOrder,
int[] overallLeaderboardDiscardThresholds,
ScoringSchemeType overallLeaderboardScoringSchemeType);
StrippedLeaderboardDTO getLeaderboard(String leaderboardName);
void updateLeaderboardGroup(String oldName, String newName,
String description, List<String> leaderboardNames,
int[] overallLeaderboardDiscardThresholds,
ScoringSchemeType overallLeaderboardScoringSchemeType);
void suppressCompetitorInLeaderboard(String leaderboardName, String competitorIdAsString, boolean suppressed);
CompetitorsRaceDataDTO getCompetitorsRaceData(
RegattaAndRaceIdentifier race, List<CompetitorDTO> competitors,
Date from, Date to, long stepSizeInMs, DetailType detailType)
throws NoWindException;
void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double newFactor);
void setRaceIsKnownToStartUpwind(RegattaAndRaceIdentifier raceIdentifier,
boolean raceIsKnownToStartUpwind);
List<SwissTimingReplayRaceDTO> listSwissTiminigReplayRaces(String swissTimingUrl);
void setWindSourcesToExclude(RegattaAndRaceIdentifier raceIdentifier,
Iterable<WindSource> windSourcesToExclude);
List<Pair<String, List<CompetitorDTO>>> getRankedCompetitorsFromBestToWorstAfterEachRaceColumn(String leaderboardName, Date date) throws NoWindException;
ReplicationStateDTO getReplicaInfo();
List<String> getOverallLeaderboardNamesContaining(String leaderboardName);
void startReplicatingFromMaster(String masterName, String exchangeName,
int servletPort, int messagingPort) throws Exception;
List<SwissTimingArchiveConfigurationDTO> getPreviousSwissTimingArchiveConfigurations();
void updateRaceDelayToLive(
RegattaAndRaceIdentifier regattaAndRaceIdentifier,
long delayToLiveInMs);
void storeSwissTimingArchiveConfiguration(String swissTimingUrl);
void updateRacesDelayToLive(
List<RegattaAndRaceIdentifier> regattaAndRaceIdentifiers,
long delayToLiveInMs);
void updateEvent(String eventName, Serializable id, VenueDTO venue,
String publicationUrl, boolean isPublic, List<String> regattaNames);
EventDTO createEvent(String eventName, String venueName,
String publicationUrl, boolean isPublic, List<String> courseAreas);
void removeEvent(Serializable id);
void renameEvent(Serializable id, String newName);
EventDTO getEventByName(String eventName);
CourseAreaDTO createCourseArea(Serializable id, String courseAreaName);
EventDTO getEventById(Serializable id);
Iterable<ScoreCorrectionProviderDTO> getScoreCorrectionProviderDTOs()
throws Exception;
RegattaScoreCorrectionDTO getScoreCorrections(
String scoreCorrectionProviderName, String eventName,
String boatClassName, Date timePointWhenResultPublished)
throws Exception;
void updateLeaderboardScoreCorrectionsAndMaxPointsReasons(
BulkScoreCorrectionDTO updates) throws NoWindException;
WindInfoForRaceDTO getWindSourcesInfo(
RegattaAndRaceIdentifier raceIdentifier);
List<String> getFregResultUrls();
void removeFregURLs(Set<String> toRemove) throws Exception;
void addFragUrl(String result) throws Exception;
Void updateLeaderboardScoreCorrectionMetadata(String leaderboardName,
Date timePointOfLastCorrectionValidity, String comment);
RaceCourseMarksDTO getRaceCourseMarks(
RegattaAndRaceIdentifier raceIdentifier, Date date);
void updateRaceCourse(RegattaAndRaceIdentifier raceIdentifier,
List<ControlPointDTO> controlPoints);
void removeLeaderboardColumns(String leaderboardName,
List<String> columnsToRemove);
StrippedLeaderboardDTO getLeaderboard(String leaderboardName);
void suppressCompetitorInLeaderboard(String leaderboardName,
String competitorIdAsString, boolean suppressed);
RaceEventLogDTO getRaceEventLog();
void updateLeaderboardColumnFactor(String leaderboardName,
String columnName, Double newFactor);
List<SwissTimingReplayRaceDTO> listSwissTiminigReplayRaces(
String swissTimingUrl);
List<Pair<String, List<CompetitorDTO>>> getRankedCompetitorsFromBestToWorstAfterEachRaceColumn(
String leaderboardName, Date date) throws NoWindException;
List<String> getOverallLeaderboardNamesContaining(String leaderboardName);
List<SwissTimingArchiveConfigurationDTO> getPreviousSwissTimingArchiveConfigurations();
void storeSwissTimingArchiveConfiguration(String swissTimingUrl);
void renameLeaderboardGroup(String oldName, String newName);
}
PolarSheetGenerationTriggerResponse generatePolarSheetForRaces(List<RegattaAndRaceIdentifier> selectedRaces);
PolarSheetsData getPolarSheetsGenerationResults(String id);
PolarSheetsHistogramData getPolarSheetData(String polarSheetId, int angle, int windSpeed);
RaceEventLogDTO getRaceEventLog();
EventDTO getEventById(Serializable id);
CourseAreaDTO createCourseArea(Serializable id, String courseAreaName);
}
@@ -12,6 +12,9 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.PolarSheetGenerationTriggerResponse;
import com.sap.sailing.domain.common.PolarSheetsData;
import com.sap.sailing.domain.common.PolarSheetsHistogramData;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaIdentifier;
@@ -206,8 +209,8 @@ public interface SailingServiceAsync {
void getLeaderboardsByRace(RaceDTO race, AsyncCallback<List<StrippedLeaderboardDTO>> callback);
void updateLeaderboard(String leaderboardName, String newLeaderboardName, int[] newDiscardingThreasholds,
AsyncCallback<Void> callback);
void updateLeaderboard(String leaderboardName, String newLeaderboardName, String newLeaderboardDisplayName,
int[] newDiscardingThreasholds, AsyncCallback<Void> callback);
void createFlexibleLeaderboard(String leaderboardName, int[] discardThresholds, ScoringSchemeType scoringSchemeType, Serializable courseAreaId,
AsyncCallback<StrippedLeaderboardDTO> asyncCallback);
@@ -429,7 +432,7 @@ public interface SailingServiceAsync {
AsyncCallback<List<Pair<String, List<CompetitorDTO>>>> callback);
void getCompetitorsRaceData(RegattaAndRaceIdentifier race, List<CompetitorDTO> competitors, Date from, Date to,
long stepSize, DetailType detailType, AsyncCallback<CompetitorsRaceDataDTO> callback);
long stepSize, DetailType detailType, String leaderboarGroupName, String leaderboardName, AsyncCallback<CompetitorsRaceDataDTO> callback);
/**
* Finds out the names of all {@link com.sap.sailing.domain.leaderboard.MetaLeaderboard}s managed by this server that
@@ -443,4 +446,10 @@ public interface SailingServiceAsync {
AsyncCallback<List<SwissTimingArchiveConfigurationDTO>> asyncCallback);
void storeSwissTimingArchiveConfiguration(String swissTimingUrl, AsyncCallback<Void> asyncCallback);
void generatePolarSheetForRaces(List<RegattaAndRaceIdentifier> selectedRaces, AsyncCallback<PolarSheetGenerationTriggerResponse> asyncCallback);
void getPolarSheetsGenerationResults(String id, AsyncCallback<PolarSheetsData> asyncCallback);
void getPolarSheetData(String polarSheetId, int angle, int windSpeed, AsyncCallback<PolarSheetsHistogramData> wrapperCallback);
}
@@ -482,6 +482,8 @@ public interface StringMessages extends Messages {
String gapChangeSinceLegStartInSecondsTooltip();
String velocityMadeGoodInKnotsTooltip();
String sideToWhichMarkAtLegStartWasRoundedTooltip();
String generatePolarSheet();
String polarSheetChart();
String numberOfManeuversInRaceTooltip();
String competitorColumnTooltip();
String sailIdColumnTooltip();
@@ -491,6 +493,15 @@ public interface StringMessages extends Messages {
String windData();
String gpsData();
String status();
String regattaRank();
String regattaRankTooltip();
String overallRank();
String overallRankTooltip();
String noDataFound();
String displayName();
String histogram();
String numberOfDataPoints();
String angleAndTotalNumberOfDataPoints(int angle, int numberOfDataPoints);
String addCourseArea();
String courseAreas();
String courseArea();
@@ -59,6 +59,10 @@ renameRace=Rename Race
openSelectedLeaderboard=Open Selected Leaderboard
rank=Rank
rankTooltip=Competitor''s rank in the race
regattaRank=Regatta Rank
regattaRankTooltip=Competitor''s rank in the regatta
overallRank=Overall Rank
overallRankTooltip=Competitor''s rank in the series
totalRank=Total rank
collapse=-
expand=+
@@ -482,8 +486,11 @@ sideToWhichMarkAtLegStartWasRounded=Mark rounded to
sideToWhichMarkAtLegStartWasRoundedTooltip=Side to which the mark at leg start was rounded.
raceIsLive=Race {0} is live
racesAreLive=Races {0} are live
knotsUnit=kts
scoringSchemeHighPointFirstGetsTen=High Point, winner gets 10 points
knotsUnit=kts
generatePolarSheet=Generate Polar Sheet
polarSheetChart=Polar Sheet
competitorColumnTooltip=Names of the members of this competitor.
sailIdColumnTooltip=Shows the flag of the country and the sail number of the competitor.
rankColumnTooltip=The overall rank of this competitor in the regatta.
@@ -492,6 +499,11 @@ totalsColumnTooltip=The total of all points of a competitor in the regatta.
windData=Wind data
gpsData=GPS data
status=Status
noDataFound=No data found
displayName=Display name
histogram=Histogram
numberOfDataPoints=Number of data points
angleAndTotalNumberOfDataPoints=Angle: {0}; Total number of data-points: {1}
addCourseArea=Add course area
courseAreas=Course areas
courseArea=Course area
@@ -59,6 +59,10 @@ renameRace=Rennen umbenennen
openSelectedLeaderboard=Ausgewählte Rangliste öffnen
rank=Platz
rankTooltip=Platzierung des Teilnehmers im Rennen
regattaRank=Platz in der Regatta
regattaRankTooltip=Platzierung des Teilnehmers in der Regatta
overallRank=Platz in der Serie
overallRankTooltip=Platzierung des Teilnehmers in der Serie
totalRank=Gesamtplatz
collapse=-
expand=+
@@ -485,6 +489,8 @@ raceIsLive=Rennen {0} ist live
racesAreLive=Rennen {0} sind live
scoringSchemeHighPointFirstGetsTen=High Point System, Gewinner erhält 10 Punkte
knotsUnit=kn
generatePolarSheet=Polardiagramm erstellen
polarSheetChart=Polardiagramm
competitorColumnTooltip=Namen der Segler dieses Teilnehmers
sailIdColumnTooltip=Zeigt die Länderflagge und die Segelnummer des Teilnehmers
rankColumnTooltip=Der Gesamtplatz des Teilnehmers in der Regatta
@@ -493,6 +499,11 @@ totalsColumnTooltip=Summe aller Punkte eines Teilnehmers in der Regatta
windData=Winddaten
gpsData=GPS-Daten
status=Status
noDataFound=Keine Daten gefunden
displayName=Anzeigename
histogram=Histogramm
numberOfDataPoints=Anzahl Datenpunkte
angleAndTotalNumberOfDataPoints=Winkel: {0}; Anzahl Datenpunkte: {1}
addCourseArea=Kursbereich hinzufügen
courseAreas=Kursbereiche
courseArea=Kursbereich
@@ -55,7 +55,7 @@ public class CompareCompetitorsChartDialog extends DialogBoxExt implements RaceT
public CompareCompetitorsChartDialog(SailingServiceAsync sailingService,
List<RegattaAndRaceIdentifier> races, final RaceTimesInfoProvider raceTimesInfoProvider, final CompetitorSelectionProvider competitorSelectionProvider,
Timer timer, StringMessages stringMessages, ErrorReporter errorReporter) {
Timer timer, StringMessages stringMessages, ErrorReporter errorReporter, String leaderboardGroupName, String leaderboardName) {
super(new Label(stringMessages.close()));
this.sailingService = sailingService;
this.timer = timer;
@@ -71,7 +71,7 @@ public class CompareCompetitorsChartDialog extends DialogBoxExt implements RaceT
raceSelectionProvider.setAllRaces(races);
multiChartPanel = new MultiChartPanel(sailingService, new AsyncActionsExecutor(), competitorSelectionProvider, raceSelectionProvider,
timer, timeRangeWithZoomProvider, stringMessages, errorReporter, false, false);
timer, timeRangeWithZoomProvider, stringMessages, errorReporter, false, false, leaderboardGroupName, leaderboardName);
multiChartPanel.setSize("100%", "100%");
VerticalPanel contentPanel = new VerticalPanel();
@@ -125,9 +125,9 @@ public class LeaderboardEntryPoint extends AbstractEntryPoint {
LeaderboardPanel leaderboardPanel = new LeaderboardPanel(sailingService, new AsyncActionsExecutor(),
leaderboardSettings,
preselectedRace, new CompetitorSelectionModel(
/* hasMultiSelection */true), timer, leaderboardName, LeaderboardEntryPoint.this,
stringMessages, userAgent, showRaceDetails, /* raceTimesInfoProvider */ null, Window.Location.getParameterMap().containsKey(PARAM_AUTO_EXPAND_LAST_RACE_COLUMN) ?
Boolean.valueOf(Window.Location.getParameterMap().get(PARAM_AUTO_EXPAND_LAST_RACE_COLUMN).get(0)) : false);
/* hasMultiSelection */true), timer, leaderboardGroupName, leaderboardName,
LeaderboardEntryPoint.this, stringMessages, userAgent, showRaceDetails, /* raceTimesInfoProvider */ null, Window.Location.getParameterMap().containsKey(PARAM_AUTO_EXPAND_LAST_RACE_COLUMN) ?
Boolean.valueOf(Window.Location.getParameterMap().get(PARAM_AUTO_EXPAND_LAST_RACE_COLUMN).get(0)) : false);
leaderboardPanel.addStyleName(LeaderboardPanel.LEADERBOARD_MARGIN_STYLE);
contentScrollPanel.setWidget(leaderboardPanel);
@@ -0,0 +1,31 @@
package com.sap.sailing.gwt.ui.polarsheets;
import com.sap.sailing.gwt.ui.adminconsole.AbstractTrackedRacesListComposite;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.RaceDTO;
public abstract class AbstractFilteredTrackedRacesList extends AbstractTrackedRacesListComposite {
private RaceFilter filter;
public AbstractFilteredTrackedRacesList(SailingServiceAsync sailingService, ErrorReporter errorReporter,
RegattaRefresher regattaRefresher, RaceSelectionProvider raceSelectionProvider,
StringMessages stringMessages, boolean hasMultiSelection, RaceFilter filter) {
super(sailingService, errorReporter, regattaRefresher, raceSelectionProvider, stringMessages, hasMultiSelection);
this.filter = filter;
}
@Override
protected boolean raceIsToBeAddedToList(RaceDTO race) {
if (filter!=null) {
return filter.compliesToFilter(race);
}
return true;
}
}
Loaded 100 of 195 files, more files were not shown because too many files have changed in this diff. Show more