mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-25 21:43:49 +00:00
Merge branch 'master' into polars
This commit is contained in:
commit
f15cd53ee4
250 files changed
+4759
-1648
No files matched your search
@@ -61,6 +61,7 @@ HAS_OVERWRITTEN_TARGET=0
|
||||
TARGET_SERVER_NAME=$active_branch
|
||||
|
||||
gwtcompile=1
|
||||
onegwtpermutationonly=0
|
||||
testing=1
|
||||
clean="clean"
|
||||
offline=0
|
||||
@@ -68,9 +69,10 @@ proxy=0
|
||||
extra=''
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "buildAndUpdateProduct [-g -t -o -c -m <config> -n <package> -l <port>] [build|install|all|hot-deploy|remote-deploy]"
|
||||
echo "buildAndUpdateProduct [-b -g -t -o -c -m <config> -n <package> -l <port>] [build|install|all|hot-deploy|remote-deploy]"
|
||||
echo ""
|
||||
echo "-g Disable GWT compile, no gwt files will be generated, old ones will be preserved."
|
||||
echo "-b Build GWT permutation only for one browser and English language."
|
||||
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)"
|
||||
@@ -104,12 +106,13 @@ echo PROJECT_HOME is $PROJECT_HOME
|
||||
echo SERVERS_HOME is $SERVERS_HOME
|
||||
echo BRANCH is $active_branch
|
||||
|
||||
options=':gtocpm:n:l:s:w:'
|
||||
options=':bgtocpm:n:l:s:w:'
|
||||
while getopts $options option
|
||||
do
|
||||
case $option in
|
||||
g) gwtcompile=0;;
|
||||
t) testing=0;;
|
||||
b) onegwtpermutationonly=1;;
|
||||
o) offline=1;;
|
||||
c) clean="";;
|
||||
p) proxy=1;;
|
||||
@@ -146,15 +149,15 @@ if [[ "$@" == "hot-deploy" ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
if [[ $HAS_OVERWRITTEN_TARGET -eq 1 ]]; then
|
||||
active_branch=$TARGET_SERVER_NAME
|
||||
fi
|
||||
|
||||
if [ ! -d $SERVERS_HOME/$active_branch/plugins ]; then
|
||||
echo "Could not find target directory $SERVERS_HOME/$active_branch/plugins!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [[ $HAS_OVERWRITTEN_TARGET -eq 1 ]]; then
|
||||
active_branch=$TARGET_SERVER_NAME
|
||||
fi
|
||||
|
||||
# locate old bundle
|
||||
BUNDLE_COUNT=`find $SERVERS_HOME/$active_branch/plugins -maxdepth 1 -name "${OSGI_BUNDLE_NAME}_*.jar" | wc -l`
|
||||
OLD_BUNDLE=`find $SERVERS_HOME/$active_branch/plugins -maxdepth 1 -name "${OSGI_BUNDLE_NAME}_*.jar"`
|
||||
@@ -270,6 +273,21 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
|
||||
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.*
|
||||
if [ $onegwtpermutationonly -eq 1 ]; then
|
||||
echo "INFO: Patching .gwt.xml files such that only one GWT permutation needs to be compiled"
|
||||
for i in com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/*.gwt.xml; do
|
||||
cp $i $i.bak
|
||||
cat $i | sed -e 's/^[ ]*<extend-property name="locale" values="de"\/>[ ]*$/<!-- <extend-property name="locale" values="de"\/> --> <set-property name="user.agent" value="safari" \/>/' >$i.sed
|
||||
mv $i.sed $i
|
||||
done
|
||||
else
|
||||
echo "INFO: Patching .gwt.xml files such that all GWT permutations are compiled"
|
||||
for i in com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/*.gwt.xml; do
|
||||
cp $i $i.bak
|
||||
cat $i | sed -e 's/<!-- <extend-property name="locale" values="de"\/> --> <set-property name="user.agent" value="safari" \/>/<extend-property name="locale" values="de"\/>/' >$i.sed
|
||||
mv $i.sed $i
|
||||
done
|
||||
fi
|
||||
else
|
||||
echo "INFO: GWT Compilation disabled"
|
||||
extra="-Pdebug.no-gwt-compile"
|
||||
@@ -298,6 +316,14 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
|
||||
echo "Using following command: mvn $extra -fae -s $MAVEN_SETTINGS $clean install"
|
||||
mvn $extra -fae -s $MAVEN_SETTINGS $clean install 2>&1 | tee $START_DIR/build.log
|
||||
|
||||
if [ $gwtcompile -eq 1 ]; then
|
||||
# Now move back the backup .gwt.xml files before they were (maybe) patched
|
||||
for i in com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/*.gwt.xml; do
|
||||
echo "INFO: restoring backup copy of $i after it was patched before"
|
||||
mv -v $i.bak $i
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Build complete. Do not forget to install product..."
|
||||
fi
|
||||
|
||||
@@ -344,11 +370,14 @@ if [[ "$@" == "install" ]] || [[ "$@" == "all" ]]; then
|
||||
rm -rf $ACDIR/org.eclipse.*
|
||||
rm -rf $ACDIR/configuration/org.eclipse.*
|
||||
|
||||
if [ ! -f "$ACDIR/env.sh" ]; then
|
||||
cp -v $PROJECT_HOME/java/target/env.sh $ACDIR/
|
||||
# always overwrite start and stop scripts as they
|
||||
# should never contain any custom logic
|
||||
cp -v $PROJECT_HOME/java/target/start $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/stop $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/status $ACDIR/
|
||||
|
||||
if [ ! -f "$ACDIR/env.sh" ]; then
|
||||
cp -v $PROJECT_HOME/java/target/env.sh $ACDIR/
|
||||
fi
|
||||
|
||||
if [ ! -f $ACDIR/no-overwrite ]; then
|
||||
@@ -363,9 +392,6 @@ if [[ "$@" == "install" ]] || [[ "$@" == "all" ]]; then
|
||||
cp -v $PROJECT_HOME/configuration/mongodb.cfg $ACDIR/
|
||||
|
||||
cp -v $PROJECT_HOME/java/target/env.sh $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/start $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/stop $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/status $ACDIR/
|
||||
cp -v $PROJECT_HOME/java/target/udpmirror $ACDIR/
|
||||
|
||||
cp -v $PROJECT_HOME/java/target/http2udpmirror $ACDIR
|
||||
|
||||
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -18,16 +18,21 @@ Like businesses, sailors need the latest information to make strategic decisions
|
||||
* Information for Developers
|
||||
* [[Cook Book|wiki/cook-book]]
|
||||
* [[OnBoarding Information|wiki/onboarding]]
|
||||
* [[UI Tests with Selenium|wiki/selenium-ui-tests]]
|
||||
* [[Typical Development Scenarios|wiki/typical-development-scenarios]]
|
||||
* [[Server Replication|wiki/server-replication]]
|
||||
* [[Configure Races on Server|wiki/typical-development-scenarios]]
|
||||
* [[Development Environment|wiki/development-environment]]
|
||||
* [[Working with GWT Locally|wiki/local-gwt]]
|
||||
* [[Mobile Development|wiki/mobile-development]]
|
||||
* General Information
|
||||
* [[Architecture and Infrastructure|wiki/architecture-and-infrastructure]]
|
||||
* [[Sailing Domain Algorithms|wiki/sailing-domain-algorithms]]
|
||||
* [[Inventory|wiki/inventar-liste]]
|
||||
* [[Smartphone Tracking|wiki/smartphone-tracking]]
|
||||
* [[Racecommittee App|wiki/racecommittee-app]]
|
||||
* [[Web Services API|wiki/sailing-webservices]]
|
||||
* [[Theses (Bachelor, Master, ...)|wiki/theses]]
|
||||
* Planning and Event Information
|
||||
* [[Project Planning (bigger development)|wiki/planning]]
|
||||
* [[General Event Planning|wiki/general-event-planning]]
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
<classpath>
|
||||
<classpathentry exported="true" kind="lib" path="lib/gwt-dev.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="lib/gwt-user.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="lib/validation-api-1.0.0.GA-sources.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="lib/validation-api-1.0.0.GA.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
|
||||
@@ -7,10 +7,7 @@ Bundle-Vendor: GOOGLE
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||
Bundle-ClassPath: lib/gwt-dev.jar,
|
||||
lib/gwt-user.jar,
|
||||
lib/validation-api-1.0.0.GA-sources.jar,
|
||||
lib/validation-api-1.0.0.GA.jar,
|
||||
.
|
||||
Eclipse-BuddyPolicy: registered
|
||||
Export-Package: com.gargoylesoftware.htmlunit,
|
||||
com.gargoylesoftware.htmlunit.attachment,
|
||||
com.gargoylesoftware.htmlunit.gae,
|
||||
@@ -601,4 +598,6 @@ Export-Package: com.gargoylesoftware.htmlunit,
|
||||
org.mortbay.util,
|
||||
org.mortbay.util.ajax,
|
||||
org.mortbay.xml
|
||||
Require-Bundle: javax.servlet;bundle-version="2.5.0";visibility:=reexport
|
||||
Require-Bundle: javax.validation;bundle-version="1.0.0"
|
||||
Import-Package: javax.servlet;version="2.5.0",
|
||||
javax.servlet.http;version="2.5.0"
|
||||
@@ -1,6 +1,4 @@
|
||||
bin.includes = META-INF/,\
|
||||
.,\
|
||||
lib/gwt-dev.jar,\
|
||||
lib/gwt-user.jar,\
|
||||
lib/validation-api-1.0.0.GA-sources.jar,\
|
||||
lib/validation-api-1.0.0.GA.jar
|
||||
lib/gwt-user.jar
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.google.gwt.user.osgi</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -6,8 +6,7 @@ Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||
Fragment-Host: com.sap.sailing.declination
|
||||
Require-Bundle: org.junit4;bundle-version="4.8.2"
|
||||
Import-Package: com.sap.sailing.domain.common,
|
||||
com.sap.sailing.domain.common.impl,
|
||||
com.sap.sailing.domain.common.quadtree,
|
||||
junit.framework;version="4.8.1",
|
||||
org.junit;version="4.8.1"
|
||||
com.sap.sailing.domain.common.quadtree
|
||||
+3
@@ -59,6 +59,9 @@ public class NOAAImporter {
|
||||
URL url = new URL(QUERY_URL+"?lon1="+position.getLngDeg()+"&lat1="+position.getLatDeg()+"&startYear=" + calendar.get(Calendar.YEAR) + "&startMonth="
|
||||
+ (calendar.get(Calendar.MONTH) + 1) + "&startDay=" + calendar.get(Calendar.DAY_OF_MONTH)+"&resultFormat=xml");
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
conn.setRequestProperty("Accept-Language", "en-US,en;q=0.8");
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36");
|
||||
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
final InputStream inputStream = conn.getInputStream();
|
||||
Document doc = builder.parse(inputStream);
|
||||
|
||||
+1
-4
@@ -1,6 +1,5 @@
|
||||
package com.sap.sailing.domain.common.impl;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
|
||||
@@ -9,8 +8,6 @@ import com.sap.sailing.domain.common.TimePoint;
|
||||
public abstract class AbstractTimePoint implements TimePoint {
|
||||
private static final long serialVersionUID = 8825508619301420378L;
|
||||
|
||||
public static SimpleDateFormat TIMEPOINT_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||
|
||||
public static Comparator<TimePoint> TIMEPOINT_COMPARATOR = new SerializableComparator<TimePoint>() {
|
||||
private static final long serialVersionUID = 7644726881387366025L;
|
||||
|
||||
@@ -68,7 +65,7 @@ public abstract class AbstractTimePoint implements TimePoint {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return TIMEPOINT_FORMATTER.format(asDate());
|
||||
return asDate().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+10
-15
@@ -82,7 +82,6 @@ import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
@@ -238,16 +237,15 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
result = leaderboardRegistry.getLeaderboardByName(leaderboardName);
|
||||
}
|
||||
if (result == null) {
|
||||
SettableScoreCorrection scoreCorrection = new ScoreCorrectionImpl();
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule = loadResultDiscardingRule(dbLeaderboard, FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS);
|
||||
String regattaName = (String) dbLeaderboard.get(FieldNames.REGATTA_NAME.name());
|
||||
if (groupForMetaLeaderboard != null) {
|
||||
result = new LeaderboardGroupMetaLeaderboard(groupForMetaLeaderboard, loadScoringScheme(dbLeaderboard), resultDiscardingRule);
|
||||
groupForMetaLeaderboard.setOverallLeaderboard(result);
|
||||
} else if (regattaName == null) {
|
||||
result = loadFlexibleLeaderboard(dbLeaderboard, scoreCorrection, resultDiscardingRule);
|
||||
result = loadFlexibleLeaderboard(dbLeaderboard, resultDiscardingRule);
|
||||
} else {
|
||||
result = loadRegattaLeaderboard(leaderboardName, regattaName, dbLeaderboard, scoreCorrection, resultDiscardingRule, regattaRegistry);
|
||||
result = loadRegattaLeaderboard(leaderboardName, regattaName, dbLeaderboard, resultDiscardingRule, regattaRegistry);
|
||||
}
|
||||
if (result != null) {
|
||||
final Leaderboard finalResult = result;
|
||||
@@ -263,7 +261,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
}
|
||||
}
|
||||
});
|
||||
needsMigration[0] = loadLeaderboardCorrections(dbLeaderboard, loadedLeaderboardCorrections, scoreCorrection) || needsMigration[0];
|
||||
needsMigration[0] = loadLeaderboardCorrections(dbLeaderboard, loadedLeaderboardCorrections, result.getScoreCorrection()) || needsMigration[0];
|
||||
needsMigration[0] = loadSuppressedCompetitors(dbLeaderboard, loadedLeaderboardCorrections) || needsMigration[0];
|
||||
loadColumnFactors(dbLeaderboard, result);
|
||||
// add the leaderboard to the registry
|
||||
@@ -338,20 +336,20 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
* @return <code>null</code> if the regatta cannot be resolved; otherwise the leaderboard for the regatta specified
|
||||
*/
|
||||
private RegattaLeaderboard loadRegattaLeaderboard(String leaderboardName, String regattaName, DBObject dbLeaderboard,
|
||||
SettableScoreCorrection scoreCorrection, ThresholdBasedResultDiscardingRule resultDiscardingRule, RegattaRegistry regattaRegistry) {
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule, RegattaRegistry regattaRegistry) {
|
||||
RegattaLeaderboard result = null;
|
||||
Regatta regatta = regattaRegistry.getRegatta(new RegattaName(regattaName));
|
||||
if (regatta == null) {
|
||||
logger.info("Couldn't find regatta "+regattaName+" for corresponding regatta leaderboard. Not loading regatta leaderboard.");
|
||||
} else {
|
||||
result = new RegattaLeaderboardImpl(regatta, scoreCorrection, resultDiscardingRule);
|
||||
result = new RegattaLeaderboardImpl(regatta, resultDiscardingRule);
|
||||
result.setName(leaderboardName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private FlexibleLeaderboard loadFlexibleLeaderboard(DBObject dbLeaderboard,
|
||||
SettableScoreCorrection scoreCorrection, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
final FlexibleLeaderboardImpl result;
|
||||
BasicDBList dbRaceColumns = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_COLUMNS.name());
|
||||
if (dbRaceColumns == null) {
|
||||
@@ -372,7 +370,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
}
|
||||
|
||||
result = new FlexibleLeaderboardImpl(raceLogStore, (String) dbLeaderboard.get(FieldNames.LEADERBOARD_NAME
|
||||
.name()), scoreCorrection, resultDiscardingRule, scoringScheme, courseArea);
|
||||
.name()), resultDiscardingRule, scoringScheme, courseArea);
|
||||
// For a FlexibleLeaderboard, fleets are owned by the leaderboard's RaceColumn objects. We need to manage
|
||||
// them here:
|
||||
Map<String, Fleet> fleetsByName = new HashMap<String, Fleet>();
|
||||
@@ -1009,11 +1007,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(identifier.getIdentifier()));
|
||||
loadRaceLogEvents(result, query);
|
||||
|
||||
// query for obsolete events
|
||||
query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(String.format("%s.%s.%s",
|
||||
identifier.getTemplate().getParentObjectName(),
|
||||
identifier.getRaceColumnName(),
|
||||
identifier.getFleetName())));
|
||||
// query for events with deprecated identifier format
|
||||
query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(identifier.getDeprecatedIdentifier()));
|
||||
loadRaceLogEvents(result, query);
|
||||
} catch (Throwable t) {
|
||||
// something went wrong during DB access; report, then use empty new race log
|
||||
@@ -1028,7 +1023,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
for (DBObject o : raceLog.find(query)) {
|
||||
RaceLogEvent raceLogEvent = loadRaceLogEvent((DBObject) o.get(FieldNames.RACE_LOG_EVENT.name()));
|
||||
if (raceLogEvent != null) {
|
||||
result.add(raceLogEvent);
|
||||
result.load(raceLogEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -36,6 +36,7 @@ import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
@@ -280,14 +281,16 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
}
|
||||
|
||||
private void storeScoreCorrections(Leaderboard leaderboard, BasicDBObject dbScoreCorrections) {
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection();
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
BasicDBList dbCorrectionForRace = new BasicDBList();
|
||||
for (Competitor competitor : leaderboard.getCompetitors()) {
|
||||
if (scoreCorrection.isScoreCorrected(competitor, raceColumn)) {
|
||||
// TODO bug 655: make score corrections time dependent
|
||||
if (scoreCorrection.isScoreCorrected(competitor, raceColumn, now)) {
|
||||
BasicDBObject dbCorrectionForCompetitor = new BasicDBObject();
|
||||
dbCorrectionForCompetitor.put(FieldNames.COMPETITOR_ID.name(), competitor.getId());
|
||||
MaxPointsReason maxPointsReason = scoreCorrection.getMaxPointsReason(competitor, raceColumn);
|
||||
MaxPointsReason maxPointsReason = scoreCorrection.getMaxPointsReason(competitor, raceColumn, now);
|
||||
if (maxPointsReason != MaxPointsReason.NONE) {
|
||||
dbCorrectionForCompetitor.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name(),
|
||||
maxPointsReason.name());
|
||||
@@ -751,7 +754,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
|
||||
result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningListChangedEvent.class.getSimpleName());
|
||||
|
||||
result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningListChangedEvent.getPositionedCompetitors()));
|
||||
result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningListChangedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -762,7 +765,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
|
||||
result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningConfirmedEvent.class.getSimpleName());
|
||||
|
||||
result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningConfirmedEvent.getPositionedCompetitors()));
|
||||
result.put(FieldNames.RACE_LOG_POSITIONED_COMPETITORS.name(), storePositionedCompetitors(finishPositioningConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+4
-4
@@ -29,9 +29,9 @@ public class ConfirmedFinishPositioningListFinderTest extends
|
||||
@Override
|
||||
protected List<Triple<Serializable, String, MaxPointsReason>> setupTargetEventsForPassAwareTests(int passId) {
|
||||
RaceLogFinishPositioningConfirmedEvent event = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 1, passId);
|
||||
when(event.getPositionedCompetitors()).thenReturn(mock(List.class));
|
||||
when(event.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(mock(List.class));
|
||||
raceLog.add(event);
|
||||
return event.getPositionedCompetitors();
|
||||
return event.getPositionedCompetitorsIDsNamesMaxPointsReasons();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -45,11 +45,11 @@ public class ConfirmedFinishPositioningListFinderTest extends
|
||||
public void testMostRecent() {
|
||||
RaceLogFinishPositioningConfirmedEvent event1 = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 1);
|
||||
RaceLogFinishPositioningConfirmedEvent event2 = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 2);
|
||||
when(event2.getPositionedCompetitors()).thenReturn(mock(List.class));
|
||||
when(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(mock(List.class));
|
||||
|
||||
raceLog.add(event1);
|
||||
raceLog.add(event2);
|
||||
|
||||
assertEquals(event2.getPositionedCompetitors(), analyzer.analyze());
|
||||
assertEquals(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons(), analyzer.analyze());
|
||||
}
|
||||
}
|
||||
+9
@@ -66,4 +66,13 @@ public interface RaceLog extends Track<RaceLogEvent>, WithID {
|
||||
void addAllListeners(HashSet<RaceLogEventVisitor> listeners);
|
||||
|
||||
Iterable<RaceLogEventVisitor> getAllListeners();
|
||||
|
||||
/**
|
||||
* Like {@link #add(RaceLogEvent)}, only that no events are triggered. Use this method only when loading a race log,
|
||||
* e.g., from a replication or master data import or when loading from the database.
|
||||
*
|
||||
* @return <code>true</code> if the event was actually added which is the case if there was no equal event contained
|
||||
* in this race log yet
|
||||
*/
|
||||
boolean load(RaceLogEvent event);
|
||||
}
|
||||
+5
-1
@@ -8,5 +8,9 @@ import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
|
||||
public abstract interface RaceLogFinishPositioningEvent extends RaceLogEvent {
|
||||
|
||||
List<Triple<Serializable, String, MaxPointsReason>> getPositionedCompetitors();
|
||||
/**
|
||||
* @return a triple holding the competitor ID, the competitor name and the {@link MaxPointReason} documenting the
|
||||
* score for the competitor
|
||||
*/
|
||||
List<Triple<Serializable, String, MaxPointsReason>> getPositionedCompetitorsIDsNamesMaxPointsReasons();
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@ public class AbortingFlagFinder extends RaceLogAnalyzer<RaceLogFlagEvent> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RaceLogFlagEvent performAnalyzation() {
|
||||
protected RaceLogFlagEvent performAnalysis() {
|
||||
if (raceLog.getCurrentPassId() <= RaceLog.DefaultPassId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+2
-2
@@ -16,11 +16,11 @@ public class ConfirmedFinishPositioningListFinder extends RaceLogAnalyzer<List<T
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Triple<Serializable, String, MaxPointsReason>> performAnalyzation() {
|
||||
protected List<Triple<Serializable, String, MaxPointsReason>> performAnalysis() {
|
||||
for (RaceLogEvent event : getPassEventsDescending()) {
|
||||
if (event instanceof RaceLogFinishPositioningConfirmedEvent) {
|
||||
RaceLogFinishPositioningConfirmedEvent finishPositioningEvent = (RaceLogFinishPositioningConfirmedEvent) event;
|
||||
return finishPositioningEvent.getPositionedCompetitors();
|
||||
return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -16,11 +16,11 @@ public class FinishPositioningListFinder extends RaceLogAnalyzer<List<Triple<Ser
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Triple<Serializable, String, MaxPointsReason>> performAnalyzation() {
|
||||
protected List<Triple<Serializable, String, MaxPointsReason>> performAnalysis() {
|
||||
for (RaceLogEvent event : getPassEventsDescending()) {
|
||||
if (event instanceof RaceLogFinishPositioningListChangedEvent) {
|
||||
RaceLogFinishPositioningListChangedEvent finishPositioningEvent = (RaceLogFinishPositioningListChangedEvent) event;
|
||||
return finishPositioningEvent.getPositionedCompetitors();
|
||||
return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ public class FinishedTimeFinder extends RaceLogAnalyzer<TimePoint> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TimePoint performAnalyzation() {
|
||||
protected TimePoint performAnalysis() {
|
||||
for (RaceLogEvent event : getPassEventsDescending()) {
|
||||
if (event instanceof RaceLogRaceStatusEvent) {
|
||||
RaceLogRaceStatusEvent statusEvent = (RaceLogRaceStatusEvent) event;
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ public class FinishingTimeFinder extends RaceLogAnalyzer<TimePoint> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TimePoint performAnalyzation() {
|
||||
protected TimePoint performAnalysis() {
|
||||
for (RaceLogEvent event : getPassEventsDescending()) {
|
||||
if (event instanceof RaceLogRaceStatusEvent) {
|
||||
RaceLogRaceStatusEvent statusEvent = (RaceLogRaceStatusEvent) event;
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ public class GateLineOpeningTimeFinder extends RaceLogAnalyzer<Long> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long performAnalyzation() {
|
||||
protected Long performAnalysis() {
|
||||
for (RaceLogEvent event : getPassEvents()) {
|
||||
if (event instanceof RaceLogGateLineOpeningTimeEvent) {
|
||||
return ((RaceLogGateLineOpeningTimeEvent) event).getGateLineOpeningTime();
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ public abstract class IndividualRecallFinder extends RaceLogAnalyzer<TimePoint>
|
||||
protected abstract boolean isRelevant(RaceLogFlagEvent flagEvent);
|
||||
|
||||
@Override
|
||||
protected TimePoint performAnalyzation() {
|
||||
protected TimePoint performAnalysis() {
|
||||
for (RaceLogEvent event : getPassEvents()) {
|
||||
if (event instanceof RaceLogFlagEvent) {
|
||||
RaceLogFlagEvent flagEvent = (RaceLogFlagEvent) event;
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class LastFlagsFinder extends RaceLogAnalyzer<List<RaceLogFlagEvent>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<RaceLogFlagEvent> performAnalyzation() {
|
||||
protected List<RaceLogFlagEvent> performAnalysis() {
|
||||
|
||||
Iterator<RaceLogEvent> iterator = getPassEventsDescending().iterator();
|
||||
RaceLogFlagEvent flagEvent = getNextFlagEvent(iterator);
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ public class LastPublishedCourseDesignFinder extends RaceLogAnalyzer<CourseBase>
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CourseBase performAnalyzation() {
|
||||
protected CourseBase performAnalysis() {
|
||||
for (RaceLogEvent event : getAllEventsDescending()) {
|
||||
if (event instanceof RaceLogCourseDesignChangedEvent) {
|
||||
RaceLogCourseDesignChangedEvent courseDesignEvent = (RaceLogCourseDesignChangedEvent) event;
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ public class LastWindFixFinder extends RaceLogAnalyzer<Wind> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Wind performAnalyzation() {
|
||||
protected Wind performAnalysis() {
|
||||
for (RaceLogEvent event : getAllEventsDescending()) {
|
||||
if (event instanceof RaceLogWindFixEvent) {
|
||||
RaceLogWindFixEvent windFixEvent = (RaceLogWindFixEvent) event;
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ public class PathfinderFinder extends RaceLogAnalyzer<String> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String performAnalyzation() {
|
||||
protected String performAnalysis() {
|
||||
for (RaceLogEvent event : getPassEventsDescending()) {
|
||||
if (event instanceof RaceLogPathfinderEvent) {
|
||||
return ((RaceLogPathfinderEvent) event).getPathfinderId();
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ public class ProtestStartTimeFinder extends RaceLogAnalyzer<TimePoint> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TimePoint performAnalyzation() {
|
||||
protected TimePoint performAnalysis() {
|
||||
for (RaceLogEvent event : getPassEventsDescending()) {
|
||||
if (event instanceof RaceLogProtestStartTimeEvent) {
|
||||
return ((RaceLogProtestStartTimeEvent) event).getProtestStartTime();
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ public class RRS26StartModeFlagFinder extends RaceLogAnalyzer<Flags> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Flags performAnalyzation() {
|
||||
protected Flags performAnalysis() {
|
||||
StartProcedureType type = procedureAnalyzer.analyze();
|
||||
if (StartProcedureType.RRS26.equals(type)) {
|
||||
for (RaceLogEvent event : getPassEventsDescending()) {
|
||||
|
||||
+2
-2
@@ -24,13 +24,13 @@ public abstract class RaceLogAnalyzer<ResultType> {
|
||||
public ResultType analyze() {
|
||||
raceLog.lockForRead();
|
||||
try {
|
||||
return performAnalyzation();
|
||||
return performAnalysis();
|
||||
} finally {
|
||||
raceLog.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract ResultType performAnalyzation();
|
||||
protected abstract ResultType performAnalysis();
|
||||
|
||||
protected Iterable<RaceLogEvent> getPassEvents() {
|
||||
return raceLog.getFixes();
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ public class RaceStatusAnalyzer extends RaceLogAnalyzer<RaceLogRaceStatus> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RaceLogRaceStatus performAnalyzation() {
|
||||
protected RaceLogRaceStatus performAnalysis() {
|
||||
for (RaceLogEvent event : getPassEventsDescending()) {
|
||||
if (event instanceof RaceLogRaceStatusEvent) {
|
||||
RaceLogRaceStatusEvent statusEvent = (RaceLogRaceStatusEvent) event;
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ public class StartProcedureTypeAnalyzer extends RaceLogAnalyzer<StartProcedureTy
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StartProcedureType performAnalyzation() {
|
||||
protected StartProcedureType performAnalysis() {
|
||||
for (RaceLogEvent event : getAllEventsDescending()) {
|
||||
if (event instanceof RaceLogStartProcedureChangedEvent) {
|
||||
RaceLogStartProcedureChangedEvent startProcedureEvent = (RaceLogStartProcedureChangedEvent) event;
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ public class StartTimeFinder extends RaceLogAnalyzer<TimePoint> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TimePoint performAnalyzation() {
|
||||
protected TimePoint performAnalysis() {
|
||||
for (RaceLogEvent event : getPassEventsDescending()) {
|
||||
if (event instanceof RaceLogStartTimeEvent) {
|
||||
return ((RaceLogStartTimeEvent) event).getStartTime();
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ public class WindFixesFinder extends RaceLogAnalyzer<List<Wind>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Wind> performAnalyzation() {
|
||||
protected List<Wind> performAnalysis() {
|
||||
final List<Wind> windFixes = new ArrayList<Wind>();
|
||||
for (RaceLogEvent event : getAllEventsDescending()) {
|
||||
if (event instanceof RaceLogWindFixEvent) {
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ public abstract class RaceLogFinishPositioningEventImpl extends RaceLogEventImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Triple<Serializable, String, MaxPointsReason>> getPositionedCompetitors() {
|
||||
public List<Triple<Serializable, String, MaxPointsReason>> getPositionedCompetitorsIDsNamesMaxPointsReasons() {
|
||||
return positionedCompetitors;
|
||||
}
|
||||
|
||||
|
||||
+18
@@ -89,6 +89,24 @@ public class RaceLogImpl extends TrackImpl<RaceLogEvent> implements RaceLog {
|
||||
return isAdded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load(RaceLogEvent event) {
|
||||
boolean isAdded = false;
|
||||
lockForWrite();
|
||||
try {
|
||||
isAdded = getInternalRawFixes().add(event);
|
||||
} finally {
|
||||
unlockAfterWrite();
|
||||
}
|
||||
if (isAdded) {
|
||||
logger.finer(String.format("%s (%s) was loaded into log.", event, event.getClass().getName()));
|
||||
setCurrentPassId(Math.max(event.getPassId(), this.currentPassId));
|
||||
} else {
|
||||
logger.warning(String.format("%s (%s) was not loaded into log. Ignoring", event, event.getClass().getName()));
|
||||
}
|
||||
return isAdded;
|
||||
}
|
||||
|
||||
protected void notifyListenersAboutReceive(RaceLogEvent event) {
|
||||
synchronized (listeners) {
|
||||
for (RaceLogEventVisitor listener : listeners) {
|
||||
|
||||
+20
@@ -185,6 +185,26 @@ public class SwissTimingAdapterPersistenceImpl implements SwissTimingAdapterPers
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRaceStartlist(String raceID) {
|
||||
DBCollection races = database.getCollection(CollectionNames.RACES_MESSAGES.name());
|
||||
BasicDBObject query = new BasicDBObject();
|
||||
query.append(FieldNames.RACE_ID.name(), raceID);
|
||||
query.append(FieldNames.MESSAGE_COMMAND.name(), MessageType.STL.name());
|
||||
DBObject object = races.findOne(query);
|
||||
return object != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRaceCourse(String raceID) {
|
||||
DBCollection races = database.getCollection(CollectionNames.RACES_MESSAGES.name());
|
||||
BasicDBObject query = new BasicDBObject();
|
||||
query.append(FieldNames.RACE_ID.name(), raceID);
|
||||
query.append(FieldNames.MESSAGE_COMMAND.name(), MessageType.CCG.name());
|
||||
DBObject object = races.findOne(query);
|
||||
return object != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Race> getRaces() {
|
||||
DBCollection races = database.getCollection(CollectionNames.RACES_MASTERDATA.name());
|
||||
|
||||
@@ -16,9 +16,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sailing.domain.swisstimingadapter.persistence;bundle-version="1.0.0",
|
||||
org.junit4;bundle-version="4.8.2",
|
||||
org.hamcrest.core;bundle-version="1.1.0"
|
||||
Bundle-ClassPath: resources/,
|
||||
.
|
||||
Import-Package: com.sap.sailing.server,
|
||||
junit.framework;version="4.8.1",
|
||||
org.junit;version="4.8.1"
|
||||
Import-Package: com.sap.sailing.server
|
||||
-8
@@ -47,14 +47,6 @@ public class DomainFactoryTest {
|
||||
assertThat(raceType.getRaceCode(), is(OlympicRaceCode._470_WOMEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet470WomenBoatClass2() throws Exception {
|
||||
String raceID = "SAW005_xxx";
|
||||
RaceType raceType = swissTimingDomainFactory.getRaceTypeFromRaceID(raceID );
|
||||
assertThat(raceType, is(notNullValue()));
|
||||
assertThat(raceType.getRaceCode(), is(OlympicRaceCode._470_WOMEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDontGetWrongBoatClass() throws Exception {
|
||||
String raceID = "ABC";
|
||||
|
||||
+12
@@ -208,4 +208,16 @@ public class OverlappingStoredAndReceivedMessagesTest implements RaceSpecificMes
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRaceStartlist(String raceID) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRaceCourse(String raceID) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -45,7 +45,7 @@ public class SimpleDomainFactoryTest {
|
||||
|
||||
@Test
|
||||
public void testExtractBoatClassFromRaceIDWithEventID() {
|
||||
String raceID = "QINSWC12013;SAW005901";
|
||||
String raceID = "QINSWC12013_SAW005901";
|
||||
RaceType raceType = DomainFactory.INSTANCE.getRaceTypeFromRaceID(raceID);
|
||||
assertEquals("470", raceType.getBoatClass().getName());
|
||||
}
|
||||
|
||||
@@ -10,4 +10,5 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.udpconnector,
|
||||
com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||
com.sap.sailing.domain.common
|
||||
Export-Package: com.sap.sailing.domain.swisstimingadapter
|
||||
Export-Package: com.sap.sailing.domain.swisstimingadapter,
|
||||
com.sap.sailing.domain.swisstimingadapter.impl;x-friends:="com.sap.sailing.server.test"
|
||||
+12
-1
@@ -7,11 +7,15 @@ public class RaceRecord {
|
||||
private String raceID;
|
||||
private String description;
|
||||
private Date startTime;
|
||||
private boolean hasCourse;
|
||||
private boolean hasStartlist;
|
||||
|
||||
public RaceRecord(String raceID, String description, Date startTime) {
|
||||
public RaceRecord(String raceID, String description, Date startTime, boolean hasCourse, boolean hasStartlist) {
|
||||
this.raceID = raceID;
|
||||
this.description = description;
|
||||
this.startTime = startTime;
|
||||
this.hasCourse = hasCourse;
|
||||
this.hasStartlist = hasStartlist;
|
||||
}
|
||||
|
||||
public String getRaceID() {
|
||||
@@ -26,4 +30,11 @@ public class RaceRecord {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public boolean hasCourse() {
|
||||
return hasCourse;
|
||||
}
|
||||
|
||||
public boolean hasStartlist() {
|
||||
return hasStartlist;
|
||||
}
|
||||
}
|
||||
+4
@@ -21,4 +21,8 @@ public interface RaceSpecificMessageLoader {
|
||||
Iterable<Race> getRaces();
|
||||
|
||||
Race getRace(String raceID);
|
||||
|
||||
boolean hasRaceStartlist(String raceID);
|
||||
|
||||
boolean hasRaceCourse(String raceID);
|
||||
}
|
||||
+3
-3
@@ -26,12 +26,12 @@ public interface RaceType {
|
||||
_470_MEN("SAM005", "470", Gender.male),
|
||||
STAR("SAM007", "Star", Gender.male),
|
||||
_49ER("SAM009", "49er", Gender.male),
|
||||
_49ERFX("SAW009", "49erFX", Gender.female),
|
||||
ELLIOTT6M("SAW007", "Elliott 6M", Gender.female),
|
||||
RSX_WOMEN("SAW102", "RS:X", Gender.female),
|
||||
RSX_MEN("SAM102", "RS:X", Gender.male),
|
||||
LASER_RADIAL("SAW103", "Laser Radial", Gender.female),
|
||||
_49ERFX_TODO("xxxxx_TODO_xxxxx", "49er FX", Gender.female),
|
||||
NACRA17_TOTO("xxxxx_TODO_xxxxx", "Nacra 17", Gender.mixed);
|
||||
NACRA17("SAX017", "Nacra 17", Gender.mixed),
|
||||
LASER_RADIAL("SAW103", "Laser Radial", Gender.female);
|
||||
|
||||
enum Gender {
|
||||
male, female, mixed, unspecified;
|
||||
|
||||
+4
@@ -19,8 +19,12 @@ public interface SailMasterConnector {
|
||||
|
||||
Course getCourse(String raceID) throws UnknownHostException, IOException, InterruptedException;
|
||||
|
||||
boolean hasCourse(String raceID);
|
||||
|
||||
StartList getStartList(String raceID) throws UnknownHostException, IOException, InterruptedException;
|
||||
|
||||
boolean hasStartlist(String raceID);
|
||||
|
||||
TimePoint getStartTime(String raceID) throws UnknownHostException, IOException, ParseException, InterruptedException;
|
||||
|
||||
Distance getDistanceToMark(String raceID, int markIndex, String boatID) throws UnknownHostException, IOException, InterruptedException;
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
public RaceType getRaceTypeFromRaceID(String raceID) {
|
||||
final RaceType result;
|
||||
if (raceID != null && raceID.length() >= 6) {
|
||||
final String[] optionalEventIDAndMandatoryRaceID = raceID.split(";");
|
||||
final String[] optionalEventIDAndMandatoryRaceID = raceID.split("_");
|
||||
final String swissTimingRaceCode = optionalEventIDAndMandatoryRaceID[optionalEventIDAndMandatoryRaceID.length-1].substring(0, 6).toUpperCase();
|
||||
RaceType raceType = raceTypeByID.get(swissTimingRaceCode);
|
||||
if (raceType == null) {
|
||||
|
||||
+18
@@ -606,6 +606,24 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCourse(String raceID) {
|
||||
boolean result = false;
|
||||
if (messageLoader != null) {
|
||||
result = messageLoader.hasRaceCourse(raceID);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStartlist(String raceID) {
|
||||
boolean result = false;
|
||||
if (messageLoader != null) {
|
||||
result = messageLoader.hasRaceStartlist(raceID);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Race> parseAvailableRacesMessage(SailMasterMessage availableRacesMessage) {
|
||||
assertMessageType(MessageType.RAC, availableRacesMessage);
|
||||
int count = Integer.valueOf(availableRacesMessage.getSections()[1]);
|
||||
|
||||
@@ -7,6 +7,6 @@ Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||
Fragment-Host: com.sap.sailing.domain.swisstimingreplayadapter
|
||||
Import-Package: org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.junit;version="4.8.2"
|
||||
Require-Bundle: com.sap.sailing.domain.test
|
||||
org.json.simple.parser
|
||||
Require-Bundle: com.sap.sailing.domain.test,
|
||||
org.junit4;bundle-version="4.8.2"
|
||||
@@ -14,10 +14,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
org.mockito.mockito-core;bundle-version="1.9.5",
|
||||
com.sap.sailing.domain.test,
|
||||
org.hamcrest;bundle-version="1.1.0",
|
||||
org.objenesis;bundle-version="1.3.0"
|
||||
org.objenesis;bundle-version="1.3.0",
|
||||
org.junit4;bundle-version="4.8.2",
|
||||
org.json.simple;bundle-version="1.1.0"
|
||||
Export-Package: com.sap.sailing.domain.test,
|
||||
com.sap.sailing.domain.test.mock
|
||||
Import-Package: junit.framework;version="4.8.1",
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.junit;version="4.8.1"
|
||||
+2
-3
@@ -23,7 +23,6 @@ import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
import com.sap.sailing.domain.tractracadapter.ReceiverType;
|
||||
|
||||
@@ -38,8 +37,8 @@ public class LeaderboardForKielWeekTest extends OnlineTracTracBasedTest {
|
||||
|
||||
@Test
|
||||
public void leaderboardWithOneRaceTest() throws URISyntaxException, NoWindException, IOException, InterruptedException {
|
||||
leaderboard = new FlexibleLeaderboardImpl("Kiel Week 2011 505s", new ScoreCorrectionImpl(),
|
||||
new ThresholdBasedResultDiscardingRuleImpl(new int[] { 3, 6 }), new LowPoint(), null);
|
||||
leaderboard = new FlexibleLeaderboardImpl("Kiel Week 2011 505s", new ThresholdBasedResultDiscardingRuleImpl(new int[] { 3, 6 }),
|
||||
new LowPoint(), null);
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
MillisecondsTimePoint now = MillisecondsTimePoint.now();
|
||||
loadRace("357c700a-9d9a-11e0-85be-406186cbf87c"); // 505 Race 2
|
||||
|
||||
+10
-15
@@ -40,7 +40,6 @@ import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithFixedRank;
|
||||
import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithFixedRankAndManyCompetitors;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
@@ -102,7 +101,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
|
||||
@Test
|
||||
public void ensureMedalRaceParamIsIgnoredIfRaceColumnAlreadyExists() {
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ScoreCorrectionImpl(), new ThresholdBasedResultDiscardingRuleImpl(
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ThresholdBasedResultDiscardingRuleImpl(
|
||||
new int[] { 5, 8 }), new LowPoint(), null);
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
final String columnName = "abc";
|
||||
@@ -115,7 +114,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
|
||||
@Test
|
||||
public void testRepeatedLeaderboardDTOCacheInvalidation() throws NoWindException, InterruptedException, ExecutionException {
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ScoreCorrectionImpl(), new ThresholdBasedResultDiscardingRuleImpl(
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ThresholdBasedResultDiscardingRuleImpl(
|
||||
new int[] { 5, 8 }), new LowPoint(), null);
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
final String columnName = "abc";
|
||||
@@ -174,8 +173,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
r.addCompetitor(c3); // this makes maxPoints==4
|
||||
testRaces.add(r); // hash set should take care of more or less randomly permuting the races
|
||||
}
|
||||
ScoreCorrectionImpl scoreCorrection = new ScoreCorrectionImpl();
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", scoreCorrection, new ThresholdBasedResultDiscardingRuleImpl(
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ThresholdBasedResultDiscardingRuleImpl(
|
||||
new int[] { 1 }), new LowPoint(), null);
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
int i=0;
|
||||
@@ -190,7 +188,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
bestScoringRaceColumn = raceColumn;
|
||||
}
|
||||
}
|
||||
scoreCorrection.setMaxPointsReason(competitor, bestScoringRaceColumn, MaxPointsReason.DSQ);
|
||||
leaderboard.getScoreCorrection().setMaxPointsReason(competitor, bestScoringRaceColumn, MaxPointsReason.DSQ);
|
||||
// assert that best scoring but now disqualified race gets max net points because of disqualification:
|
||||
assertEquals(Util.size(bestScoringRaceColumn.getTrackedRace(defaultFleet).getRace().getCompetitors())+1,
|
||||
leaderboard.getEntry(competitor, bestScoringRaceColumn, MillisecondsTimePoint.now()).getNetPoints(), 0.000000001);
|
||||
@@ -208,8 +206,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
competitor, /* rank */ 1, /* started */true);
|
||||
testRace.addCompetitor(c2);
|
||||
testRace.addCompetitor(c3); // this makes maxPoints==4
|
||||
ScoreCorrectionImpl scoreCorrection = new ScoreCorrectionImpl();
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", scoreCorrection, new ThresholdBasedResultDiscardingRuleImpl(
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ThresholdBasedResultDiscardingRuleImpl(
|
||||
new int[] { 2 }), new LowPoint(), null);
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
leaderboard.addRace(testRace, "R1", /* medalRace */ false, defaultFleet);
|
||||
@@ -237,14 +234,13 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
competitor, /* rank */ 1, /* started */true);
|
||||
testRace.addCompetitor(c2);
|
||||
testRace.addCompetitor(c3); // this makes maxPoints==4
|
||||
ScoreCorrectionImpl scoreCorrection = new ScoreCorrectionImpl();
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", scoreCorrection, new ThresholdBasedResultDiscardingRuleImpl(
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ThresholdBasedResultDiscardingRuleImpl(
|
||||
new int[] { 2 }), new LowPoint(), null);
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
RaceColumn r1 = leaderboard.addRace(testRace, "R1", /* medalRace */ false, defaultFleet);
|
||||
raceColumnsInLeaderboard.put(testRace, r1);
|
||||
RaceColumn r2 = leaderboard.addRaceColumn("R2", /* medalRace */ false, defaultFleet);
|
||||
scoreCorrection.setMaxPointsReason(competitor, r2, MaxPointsReason.DND); // non-discardable disqualification
|
||||
leaderboard.getScoreCorrection().setMaxPointsReason(competitor, r2, MaxPointsReason.DND); // non-discardable disqualification
|
||||
// assert that max points were given before discarding...
|
||||
assertEquals(4.0, leaderboard.getEntry(competitor, r2, MillisecondsTimePoint.now()).getNetPoints(), 0.000000001);
|
||||
// ...and after...
|
||||
@@ -265,8 +261,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
r.addCompetitor(c3); // this makes maxPoints==4
|
||||
testRaces.add(r); // hash set should take care of more or less randomly permuting the races
|
||||
}
|
||||
ScoreCorrectionImpl scoreCorrection = new ScoreCorrectionImpl();
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", scoreCorrection, new ThresholdBasedResultDiscardingRuleImpl(
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ThresholdBasedResultDiscardingRuleImpl(
|
||||
new int[] { 1 }), new LowPoint(), null);
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
int i=0;
|
||||
@@ -281,7 +276,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
bestScoringRaceColumn = raceColumn;
|
||||
}
|
||||
}
|
||||
scoreCorrection.setMaxPointsReason(competitor, bestScoringRaceColumn, MaxPointsReason.DND);
|
||||
leaderboard.getScoreCorrection().setMaxPointsReason(competitor, bestScoringRaceColumn, MaxPointsReason.DND);
|
||||
// assert that best scoring but now disqualified race gets max net points because of disqualification:
|
||||
assertEquals(Util.size(bestScoringRaceColumn.getTrackedRace(defaultFleet).getRace().getCompetitors())+1,
|
||||
leaderboard.getEntry(competitor, bestScoringRaceColumn, MillisecondsTimePoint.now()).getNetPoints(), 0.000000001);
|
||||
@@ -293,7 +288,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
protected void testLeaderboard(int numberOfStartedRaces, int numberOfNotStartedRaces, int firstDiscardingThreshold,
|
||||
int secondDiscardingThreshold, Integer carry, boolean addOneMedalRace, int numberOfUntrackedRaces) throws NoWindException {
|
||||
setupRaces(numberOfStartedRaces, numberOfNotStartedRaces);
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ScoreCorrectionImpl(), new ThresholdBasedResultDiscardingRuleImpl(
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ThresholdBasedResultDiscardingRuleImpl(
|
||||
new int[] { firstDiscardingThreshold, secondDiscardingThreshold }), new LowPoint(), null);
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
int i=0;
|
||||
|
||||
+102
-9
@@ -44,9 +44,9 @@ import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPoint;
|
||||
import com.sap.sailing.domain.leaderboard.impl.HighPointExtremeSailingSeriesOverall;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard;
|
||||
import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithStartTimeAndRanks;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
@@ -59,9 +59,8 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
private ArrayList<Series> series;
|
||||
|
||||
private Leaderboard createLeaderboard(Regatta regatta, int[] discardingThresholds) {
|
||||
ScoreCorrectionImpl scoreCorrections = new ScoreCorrectionImpl();
|
||||
ThresholdBasedResultDiscardingRuleImpl discardingRules = new ThresholdBasedResultDiscardingRuleImpl(discardingThresholds);
|
||||
return new RegattaLeaderboardImpl(regatta, scoreCorrections, discardingRules);
|
||||
return new RegattaLeaderboardImpl(regatta, discardingRules);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -800,24 +799,24 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
Competitor[] f6 = new Competitor[] { c[3], c[0] };
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
|
||||
FlexibleLeaderboard leaderboard1 = new FlexibleLeaderboardImpl("Leaderboard 1", new ScoreCorrectionImpl(),
|
||||
new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]), new HighPoint(), null);
|
||||
FlexibleLeaderboard leaderboard1 = new FlexibleLeaderboardImpl("Leaderboard 1", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]),
|
||||
new HighPoint(), null);
|
||||
leaderboard1.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(f1)), "R1", /* medalRace */ false,
|
||||
leaderboard1.getFleet(null));
|
||||
leaderboard1.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(f2)), "R2", /* medalRace */ false,
|
||||
leaderboard1.getFleet(null));
|
||||
assertTrue(leaderboard1.getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false).compare(
|
||||
leaderboard1.getTotalPoints(c[0], later), leaderboard1.getTotalPoints(c[3], later)) < 0); // c0 better than c3
|
||||
FlexibleLeaderboard leaderboard2 = new FlexibleLeaderboardImpl("Leaderboard 3", new ScoreCorrectionImpl(),
|
||||
new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]), new HighPoint(), null);
|
||||
FlexibleLeaderboard leaderboard2 = new FlexibleLeaderboardImpl("Leaderboard 3", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]),
|
||||
new HighPoint(), null);
|
||||
leaderboard2.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(f3)), "R1", /* medalRace */ false,
|
||||
leaderboard1.getFleet(null));
|
||||
leaderboard2.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(f4)), "R2", /* medalRace */ false,
|
||||
leaderboard1.getFleet(null));
|
||||
assertTrue(leaderboard2.getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false).compare(
|
||||
leaderboard2.getTotalPoints(c[3], later), leaderboard2.getTotalPoints(c[0], later)) < 0); // c3 better than c0
|
||||
FlexibleLeaderboard leaderboard3 = new FlexibleLeaderboardImpl("Leaderboard 3", new ScoreCorrectionImpl(),
|
||||
new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]), new HighPoint(), null);
|
||||
FlexibleLeaderboard leaderboard3 = new FlexibleLeaderboardImpl("Leaderboard 3", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]),
|
||||
new HighPoint(), null);
|
||||
leaderboard3.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(f5)), "R1", /* medalRace */ false,
|
||||
leaderboard1.getFleet(null));
|
||||
leaderboard3.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(f6)), "R2", /* medalRace */ false,
|
||||
@@ -838,6 +837,100 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
assertEquals(29 /* two wins, one second */, leaderboardGroup.getOverallLeaderboard().getTotalPoints(c[3], later), 0.000000001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplicationOfScoreCorrectionsInRacesWithNoTrackedRaceAfterLastTrackedRaceWithoutMarkPassings() throws NoWindException {
|
||||
// Let c0 lead the series, c3 trail it, c1 and c2 are one-time competitors which are then suppressed in the
|
||||
// overall leaderboard, expecting c3 to rank second overall, after c0 ranking first, with c1 and c2 not appearing
|
||||
// in the overall leaderboard's sorted competitor list
|
||||
Competitor[] c = createCompetitors(4).toArray(new Competitor[0]);
|
||||
Competitor[] f1 = new Competitor[] { c[2], c[0], c[1], c[3] };
|
||||
final TimePoint endOfR1 = MillisecondsTimePoint.now();
|
||||
final TimePoint withinR1 = endOfR1.minus(1000);
|
||||
final TimePoint startOfR1 = withinR1.minus(10000);
|
||||
final TimePoint beforeStartOfR1 = startOfR1.minus(10000);
|
||||
final TimePoint afterEndOfR1 = endOfR1.plus(1000);
|
||||
FlexibleLeaderboard leaderboard1 = new FlexibleLeaderboardImpl("Leaderboard 1", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]),
|
||||
new LowPoint(), null);
|
||||
leaderboard1.addRace(new MockedTrackedRaceWithStartTimeAndRanks(startOfR1, Arrays.asList(f1)) {
|
||||
private static final long serialVersionUID = 8705622361027154428L;
|
||||
public TimePoint getEndOfRace() {
|
||||
return endOfR1;
|
||||
}
|
||||
}, "R1", /* medalRace */ false,
|
||||
leaderboard1.getFleet(null));
|
||||
RaceColumn r2 = leaderboard1.addRaceColumn("R2", /* medalRace */ false, new Fleet[] { new FleetImpl("Default Fleet") });
|
||||
leaderboard1.getScoreCorrection().correctScore(c[0], r2, 123.);
|
||||
assertEquals(2. + 123., leaderboard1.getTotalPoints(c[0], afterEndOfR1), 0.00000001); // correction expected to apply after end of last tracked race before the corrected column
|
||||
assertEquals(2. + 0., leaderboard1.getTotalPoints(c[0], withinR1), 0.00000001); // correction expected NOT to apply before end of last tracked race before the corrected column
|
||||
assertEquals(0., leaderboard1.getTotalPoints(c[0], beforeStartOfR1), 0.00000001); // not even the R1 scores apply before the start time of R1
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplicationOfScoreCorrectionsInRacesWithNoTrackedRaceAfterLastTrackedRaceWithMarkPassings() throws NoWindException {
|
||||
// Let c0 lead the series, c3 trail it, c1 and c2 are one-time competitors which are then suppressed in the
|
||||
// overall leaderboard, expecting c3 to rank second overall, after c0 ranking first, with c1 and c2 not appearing
|
||||
// in the overall leaderboard's sorted competitor list
|
||||
Competitor[] c = createCompetitors(4).toArray(new Competitor[0]);
|
||||
Competitor[] f1 = new Competitor[] { c[2], c[0], c[1], c[3] };
|
||||
final TimePoint endOfR1 = MillisecondsTimePoint.now();
|
||||
final TimePoint withinR1 = endOfR1.minus(1000);
|
||||
final TimePoint startOfR1 = withinR1.minus(10000);
|
||||
final TimePoint beforeStartOfR1 = startOfR1.minus(10000);
|
||||
final TimePoint afterEndOfR1 = endOfR1.plus(1000);
|
||||
final Waypoint start = new WaypointImpl(new GateImpl(new MarkImpl("Start Pin End"), new MarkImpl("Start Committee Boat"), "Start"));
|
||||
final Waypoint finish = new WaypointImpl(new GateImpl(new MarkImpl("Finish Pin End"), new MarkImpl("Finish Committee Boat"), "Finish"));
|
||||
FlexibleLeaderboard leaderboard1 = new FlexibleLeaderboardImpl("Leaderboard 1", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]),
|
||||
new LowPoint(), null);
|
||||
final MockedTrackedRaceWithStartTimeAndRanks trackedRace = new MockedTrackedRaceWithStartTimeAndRanks(startOfR1, Arrays.asList(f1)) {
|
||||
private static final long serialVersionUID = 8705622361027154428L;
|
||||
@Override
|
||||
public TimePoint getEndOfRace() {
|
||||
return endOfR1;
|
||||
}
|
||||
@Override
|
||||
public NavigableSet<MarkPassing> getMarkPassings(Competitor competitor) {
|
||||
ArrayListNavigableSet<MarkPassing> result = new ArrayListNavigableSet<MarkPassing>(new TimedComparator());
|
||||
result.add(new MarkPassingImpl(startOfR1, start, competitor));
|
||||
result.add(new MarkPassingImpl(endOfR1, finish, competitor));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
trackedRace.getRace().getCourse().addWaypoint(0, start);
|
||||
trackedRace.getRace().getCourse().addWaypoint(1, finish);
|
||||
RaceColumn r1 = leaderboard1.addRace(trackedRace, "R1", /* medalRace */ false, leaderboard1.getFleet(null));
|
||||
RaceColumn r2 = leaderboard1.addRaceColumn("R2", /* medalRace */ false, new Fleet[] { new FleetImpl("Default Fleet") });
|
||||
leaderboard1.getScoreCorrection().correctScore(c[0], r2, 123.);
|
||||
assertEquals(2. + 123., leaderboard1.getTotalPoints(c[0], afterEndOfR1), 0.00000001); // correction expected to apply after end of last tracked race before the corrected column
|
||||
assertEquals(2. + 0., leaderboard1.getTotalPoints(c[0], withinR1), 0.00000001); // correction expected NOT to apply before end of last tracked race before the corrected column
|
||||
assertEquals(0., leaderboard1.getTotalPoints(c[0], beforeStartOfR1), 0.00000001); // not even the R1 scores apply before the start time of R1
|
||||
|
||||
leaderboard1.getScoreCorrection().setMaxPointsReason(c[1], r2, MaxPointsReason.DNS);
|
||||
assertEquals(3. + 5., leaderboard1.getTotalPoints(c[1], afterEndOfR1), 0.00000001); // DNS is applied at race start (not known), so at least after the end of R1
|
||||
assertEquals(3. + 0., leaderboard1.getTotalPoints(c[1], withinR1), 0.00000001); // correction expected NOT to apply before end of last tracked race before the corrected column
|
||||
assertEquals(0., leaderboard1.getTotalPoints(c[1], beforeStartOfR1), 0.00000001); // not even the R1 scores apply before the start time of R1
|
||||
|
||||
leaderboard1.getScoreCorrection().setMaxPointsReason(c[2], r2, MaxPointsReason.DNF);
|
||||
assertEquals(1. + 5., leaderboard1.getTotalPoints(c[2], afterEndOfR1), 0.00000001); // DNF is applied after R2 finish (not known), so at least after the end of R1
|
||||
assertEquals(1. + 0., leaderboard1.getTotalPoints(c[2], withinR1), 0.00000001); // correction expected NOT to apply before end of last tracked race before the corrected column
|
||||
assertEquals(0., leaderboard1.getTotalPoints(c[2], beforeStartOfR1), 0.00000001); // not even the R1 scores apply before the start time of R1
|
||||
|
||||
leaderboard1.getScoreCorrection().setMaxPointsReason(c[3], r1, MaxPointsReason.DNF);
|
||||
assertEquals(0., leaderboard1.getTotalPoints(c[3], beforeStartOfR1), 0.00000001); // DNF does not apply before the start
|
||||
assertEquals(4., leaderboard1.getTotalPoints(c[3], withinR1), 0.00000001); // correction expected NOT to apply before end of race
|
||||
assertEquals(5., leaderboard1.getTotalPoints(c[3], afterEndOfR1), 0.00000001); // after race is finished, DNF applies
|
||||
|
||||
leaderboard1.getScoreCorrection().setMaxPointsReason(c[3], r1, MaxPointsReason.DNS);
|
||||
assertEquals(0., leaderboard1.getTotalPoints(c[3], beforeStartOfR1), 0.00000001); // DNS does not apply before the start
|
||||
assertEquals(5., leaderboard1.getTotalPoints(c[3], withinR1), 0.00000001); // correction expected to apply after the start
|
||||
assertEquals(5., leaderboard1.getTotalPoints(c[3], afterEndOfR1), 0.00000001); // not even the R1 scores apply before the start time of R1
|
||||
|
||||
leaderboard1.getScoreCorrection().setMaxPointsReason(c[3], r1, null);
|
||||
leaderboard1.getScoreCorrection().correctScore(c[3], r1, 123.);
|
||||
assertEquals(4., leaderboard1.getTotalPoints(c[3], withinR1), 0.00000001); // correction expected NOT to apply before end of last tracked race before the corrected column
|
||||
assertEquals(123., leaderboard1.getTotalPoints(c[3], afterEndOfR1), 0.00000001); // correction is applied after R1 finish
|
||||
assertEquals(0., leaderboard1.getTotalPoints(c[3], beforeStartOfR1), 0.00000001); // not even the R1 scores apply before the start time of R1
|
||||
}
|
||||
|
||||
private TimePoint createAndAttachTrackedRaces(Series theSeries, String fleetName, Competitor[]... competitorLists) {
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
|
||||
|
||||
+1
-3
@@ -16,7 +16,6 @@ import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.racelog.RaceLog;
|
||||
import com.sap.sailing.domain.test.mock.MockedTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
@@ -48,8 +47,7 @@ public class RaceLogAttachOnTrackedRaceTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
ScoreCorrectionImpl scoreCorrection = new ScoreCorrectionImpl();
|
||||
leaderboard = new FlexibleLeaderboardImpl("", scoreCorrection, null, new LowPoint(), null);
|
||||
leaderboard = new FlexibleLeaderboardImpl("", null, new LowPoint(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -11,7 +11,7 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0"
|
||||
Export-Package: com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sailing.domain.tractracadapter.impl;x-friends:="com.sap.sailing.domain.test,com.sap.sailing.domain.swisstimingadapter.test"
|
||||
com.sap.sailing.domain.tractracadapter.impl;x-friends:="com.sap.sailing.domain.test,com.sap.sailing.domain.swisstimingadapter.test,com.sap.sailing.server.test"
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Import-Package: org.json.simple,
|
||||
org.json.simple.parser
|
||||
+12
-11
@@ -179,25 +179,26 @@ public interface DomainFactory {
|
||||
/**
|
||||
* Creates a {@link RaceDefinition} from a TracTrac {@link Race} and a domain {@link Course} definition. The
|
||||
* resulting {@link RaceDefinition} is added to the {@link com.sap.sailing.domain.base.Regatta} to which
|
||||
* <code>trackedRegatta</code> belongs (see {@link TrackedRegatta#getRegatta()}). It is added to the internal race cache.
|
||||
* The corresponding {@link TrackedRace} object is also created, and the notification of threads waiting on the race
|
||||
* cache such as a blocking {@link #getAndWaitForRaceDefinition(UUID)} happens only <em>after</em> the tracked race
|
||||
* has been created and the {@link RaceDefinition} was
|
||||
* <code>trackedRegatta</code> belongs (see {@link TrackedRegatta#getRegatta()}). It is added to the internal race
|
||||
* cache. The corresponding {@link TrackedRace} object is also created, and the notification of threads waiting on
|
||||
* the race cache such as a blocking {@link #getAndWaitForRaceDefinition(UUID)} happens only <em>after</em> the
|
||||
* tracked race has been created and the {@link RaceDefinition} was
|
||||
* {@link com.sap.sailing.domain.base.Regatta#addRace(RaceDefinition) added} to the domain event. This ensures that
|
||||
* waiters for the {@link RaceDefinition} are guaranteed to obtain a valid, non-<code>null</code> tracked race
|
||||
* already immediately after the notification was sent, and that the {@link RaceDefinition} is already
|
||||
* {@link com.sap.sailing.domain.base.Regatta#getAllRaces() known} by its containing
|
||||
* {@link com.sap.sailing.domain.base.Regatta}.
|
||||
* @param raceName TODO
|
||||
* @param competitors TODO
|
||||
* @param boatClass TODO
|
||||
*
|
||||
* @param raceDefinitionSetToUpdate
|
||||
* if not <code>null</code>, after creating the {@link TrackedRace}, the {@link RaceDefinition} is
|
||||
* {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that object.
|
||||
* {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that
|
||||
* object.
|
||||
*/
|
||||
DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta, UUID raceId,
|
||||
String raceName, Iterable<com.sap.sailing.domain.base.Competitor> competitors, BoatClass boatClass, Course course, Iterable<Sideline> sidelines,
|
||||
WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword);
|
||||
DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId,
|
||||
String raceName, Iterable<com.sap.sailing.domain.base.Competitor> competitors, BoatClass boatClass,
|
||||
Course course, Iterable<Sideline> sidelines, WindStore windStore, long delayToLiveInMillis,
|
||||
long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
|
||||
URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword);
|
||||
|
||||
/**
|
||||
* The record may be for a single mark or a gate. If for a gate, the
|
||||
|
||||
+20
-18
@@ -469,7 +469,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta, UUID raceId,
|
||||
public DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId,
|
||||
String raceName, Iterable<Competitor> competitors, BoatClass boatClass, Course course,
|
||||
Iterable<Sideline> sidelines, WindStore windStore, long delayToLiveInMillis,
|
||||
long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
|
||||
@@ -479,36 +479,38 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
if (raceDefinition == null) {
|
||||
logger.info("Creating RaceDefinitionImpl for race "+raceName);
|
||||
raceDefinition = new RaceDefinitionImpl(raceName, course, boatClass, competitors, raceId);
|
||||
} else {
|
||||
logger.info("Already found RaceDefinitionImpl for race "+raceName);
|
||||
}
|
||||
DynamicTrackedRace trackedRace = trackedRegatta.getExistingTrackedRace(raceDefinition);
|
||||
if (trackedRace == null) {
|
||||
// add to existing regatta only if boat class matches
|
||||
if (raceDefinition.getBoatClass() == trackedRegatta.getRegatta().getBoatClass()) {
|
||||
trackedRegatta.getRegatta().addRace(raceDefinition);
|
||||
DynamicTrackedRace trackedRace = createTrackedRace(trackedRegatta, raceDefinition, sidelines, windStore,
|
||||
trackedRace = createTrackedRace(trackedRegatta, raceDefinition, sidelines, windStore,
|
||||
delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate);
|
||||
logger.info("Added race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta());
|
||||
|
||||
TracTracCourseDesignUpdateHandler courseDesignHandler = new TracTracCourseDesignUpdateHandler(tracTracUpdateURI,
|
||||
tracTracUsername, tracTracPassword,
|
||||
tracTracEventUuid, raceDefinition.getId());
|
||||
TracTracCourseDesignUpdateHandler courseDesignHandler = new TracTracCourseDesignUpdateHandler(
|
||||
tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
|
||||
raceDefinition.getId());
|
||||
trackedRace.addCourseDesignChangedListener(courseDesignHandler);
|
||||
|
||||
TracTracStartTimeUpdateHandler startTimeHandler = new TracTracStartTimeUpdateHandler(tracTracUpdateURI,
|
||||
tracTracUsername, tracTracPassword, tracTracEventUuid, raceDefinition.getId());
|
||||
TracTracStartTimeUpdateHandler startTimeHandler = new TracTracStartTimeUpdateHandler(
|
||||
tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
|
||||
raceDefinition.getId());
|
||||
trackedRace.addStartTimeChangedListener(startTimeHandler);
|
||||
|
||||
synchronized (raceCache) {
|
||||
raceCache.put(raceId, raceDefinition);
|
||||
raceCache.notifyAll();
|
||||
} else {
|
||||
logger.warning("Not adding race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta()
|
||||
+ " because boat class " + raceDefinition.getBoatClass()
|
||||
+ " doesn't match regatta's boat class " + trackedRegatta.getRegatta().getBoatClass());
|
||||
}
|
||||
} else {
|
||||
logger.info("Found existing tracked race for race "+raceName+" with ID "+raceId);
|
||||
}
|
||||
return trackedRace;
|
||||
} else {
|
||||
logger.warning("Not adding race "+raceDefinition+" to regatta "+trackedRegatta.getRegatta()+
|
||||
" because boat class "+raceDefinition.getBoatClass()+" doesn't match regatta's boat class "+
|
||||
trackedRegatta.getRegatta().getBoatClass());
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Race "+raceName+" already exists");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-5
@@ -29,17 +29,21 @@ public class Simulator {
|
||||
private static final Logger logger = Logger.getLogger(Simulator.class.getName());
|
||||
|
||||
private DynamicTrackedRace trackedRace;
|
||||
private WindStore windStore;
|
||||
private final WindStore windStore;
|
||||
private long advanceInMillis = -1;
|
||||
private Timer timer = new Timer("Timer for TracTrac Simulator");
|
||||
private boolean stopped;
|
||||
|
||||
public Simulator(WindStore windStore) {
|
||||
super();
|
||||
assert windStore != null;
|
||||
this.windStore = windStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a wind store which replays the wind store events against a tracked race, correcting the wind fixes with
|
||||
* the simulation delay. The wind store returned is an {@link EmptyWindStore}.
|
||||
* The wind store returned is an {@link EmptyWindStore}.
|
||||
*/
|
||||
public WindStore simulatingWindStore(WindStore windStore) {
|
||||
this.windStore = windStore;
|
||||
return EmptyWindStore.INSTANCE;
|
||||
}
|
||||
|
||||
@@ -63,7 +67,6 @@ public class Simulator {
|
||||
*/
|
||||
private void startWindPlayer() {
|
||||
assert this.trackedRace != null;
|
||||
assert this.windStore != null;
|
||||
for (final Map.Entry<? extends WindSource, ? extends WindTrack> windSourceAndTrack : windStore.loadWindTracks(
|
||||
trackedRace.getTrackedRegatta(), trackedRace,
|
||||
/* millisecondsOverWhichToAverageWind doesn't matter because we only use raw fixes */ 10000).entrySet()) {
|
||||
|
||||
+31
-35
@@ -100,8 +100,6 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
*/
|
||||
private final boolean isLiveTracking;
|
||||
|
||||
private final TrackedRegattaRegistry trackedRegattaRegistry;
|
||||
|
||||
/**
|
||||
* Creates a race tracked for the specified URL/URIs and starts receiving all available existing and future push
|
||||
* data from there. Receiving continues until {@link #stop()} is called.
|
||||
@@ -183,7 +181,6 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
WindStore windStore, String tracTracUsername, String tracTracPassword, TrackedRegattaRegistry trackedRegattaRegistry)
|
||||
throws URISyntaxException, MalformedURLException, FileNotFoundException {
|
||||
super();
|
||||
this.trackedRegattaRegistry = trackedRegattaRegistry;
|
||||
this.tractracEvent = tractracEvent;
|
||||
urls = createID(paramURL, liveURI, storedURI);
|
||||
isLiveTracking = liveURI != null;
|
||||
@@ -192,7 +189,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
this.domainFactory = domainFactory;
|
||||
final Simulator simulator;
|
||||
if (simulateWithStartTimeNow) {
|
||||
simulator = new Simulator();
|
||||
simulator = new Simulator(windStore);
|
||||
} else {
|
||||
simulator = null;
|
||||
}
|
||||
@@ -225,8 +222,6 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
// in this case, create a default regatta based on the TracTrac event data
|
||||
this.regatta = effectiveRegatta == null ? domainFactory.getOrCreateDefaultRegatta(raceLogStore, tractracEvent, trackedRegattaRegistry) : effectiveRegatta;
|
||||
trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(this.regatta);
|
||||
// Read event data from configuration file
|
||||
controlPointPositionPoller = scheduleClientParamsPHPPoller(paramURL, simulator, tracTracUpdateURI, delayToLiveInMillis, tracTracUsername, tracTracPassword);
|
||||
receivers = new HashSet<Receiver>();
|
||||
Set<TypeController> typeControllers = new HashSet<TypeController>();
|
||||
for (Receiver receiver : domainFactory.getUpdateReceivers(getTrackedRegatta(), tractracEvent, startOfTracking,
|
||||
@@ -237,6 +232,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
}
|
||||
}
|
||||
addListenersForStoredDataAndStartController(typeControllers);
|
||||
// Read event data from configuration file
|
||||
controlPointPositionPoller = scheduleClientParamsPHPPoller(paramURL, simulator, tracTracUpdateURI, delayToLiveInMillis, tracTracUsername, tracTracPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -529,6 +526,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
} else {
|
||||
logger.info("Joined TracTrac IO thread for race(s) "+getRaces());
|
||||
}
|
||||
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, /* will be ignored */ 1.0);
|
||||
updateStatusOfTrackedRaces();
|
||||
}
|
||||
|
||||
protected DataController getController() {
|
||||
@@ -548,10 +547,17 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
@Override
|
||||
public void stopped() {
|
||||
logger.info("stopped TracTrac tracking for "+getRaces());
|
||||
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, 1.0);
|
||||
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 1.0);
|
||||
updateStatusOfTrackedRaces();
|
||||
// don't stop the tracker (see bug 1517) as it seems that the storedData... callbacks are unreliable, and
|
||||
// we have seen many more fixes been transmitted after having received stopped()
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagates {@link #lastStatus} to all tracked races to which this tracker writes.
|
||||
*
|
||||
* @see #updateStatusOfTrackedRace(DynamicTrackedRace)
|
||||
*/
|
||||
private void updateStatusOfTrackedRaces() {
|
||||
for (RaceDefinition race : getRaces()) {
|
||||
DynamicTrackedRace trackedRace = getTrackedRegatta().getExistingTrackedRace(race);
|
||||
@@ -561,9 +567,24 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagates {@link #lastStatus} to <code>trackedRace</code>'s {@link TrackedRace#getStatus() status}. If
|
||||
* {@link #lastStatus} is a {@link TrackedRaceStatusEnum#FINISHED FINISHED} status, the progress value is taken from
|
||||
* the tracked race's current status instead of overwriting it with the progress indicated by
|
||||
* {@link #lastStatus}.
|
||||
*/
|
||||
private void updateStatusOfTrackedRace(DynamicTrackedRace trackedRace) {
|
||||
if (lastStatus != null) {
|
||||
trackedRace.setStatus(lastStatus);
|
||||
// can't update a race status once it has been set to FINISHED
|
||||
if (lastStatus != null && trackedRace.getStatus() != null && trackedRace.getStatus().getStatus() != TrackedRaceStatusEnum.FINISHED) {
|
||||
final TrackedRaceStatus status;
|
||||
if (lastStatus.getStatus() == TrackedRaceStatusEnum.FINISHED) {
|
||||
// in this case use the tracked race's progress value:
|
||||
status = new TrackedRaceStatusImpl(lastStatus.getStatus(), trackedRace.getStatus() == null ? 0.0
|
||||
: trackedRace.getStatus().getLoadingProgress());
|
||||
} else {
|
||||
status = lastStatus;
|
||||
}
|
||||
trackedRace.setStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,38 +601,13 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
if (isLiveTracking) {
|
||||
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 1);
|
||||
updateStatusOfTrackedRaces();
|
||||
} else {
|
||||
// ask RacingEventService to cleanly stop and unregister this tracker
|
||||
// if the race has all data loaded. Doing this asynchronously because
|
||||
// stopping can take longer and if you're loading many races in parallel
|
||||
// this can slow down loading extremely
|
||||
for (final RaceDefinition race : getRaces()) {
|
||||
DynamicTrackedRace trackedRace = getTrackedRegatta().getExistingTrackedRace(race);
|
||||
final Regatta regatta = getRegatta();
|
||||
if (trackedRace.getStatus().getLoadingProgress() == 1.0) {
|
||||
Thread raceStopper = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
trackedRegattaRegistry.stopTracking(regatta, race);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error trying to stop tracker for race "+race.getName()+
|
||||
" in regatta "+getRegatta().getName(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
raceStopper.start();
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "Not stopping race "+race.getName()+" because it has not all data loaded! Progress: " + trackedRace.getStatus().getLoadingProgress());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storedDataProgress(float progress) {
|
||||
logger.info("Stored data progress for race(s) "+getRaces()+": "+progress);
|
||||
lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, progress);
|
||||
lastStatus = new TrackedRaceStatusImpl(progress==1.0 ? TrackedRaceStatusEnum.TRACKING : TrackedRaceStatusEnum.LOADING, progress);
|
||||
updateStatusOfTrackedRaces();
|
||||
}
|
||||
|
||||
|
||||
+40
-4
@@ -20,6 +20,12 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
*
|
||||
*/
|
||||
public interface ScoreCorrection extends Serializable {
|
||||
/**
|
||||
* A score correction as valid at the time point specified with the query that produced this object.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface Result {
|
||||
/**
|
||||
* @return <code>null</code> in case there is no score attributed to the competitor for the race column in
|
||||
@@ -31,6 +37,11 @@ public interface ScoreCorrection extends Serializable {
|
||||
MaxPointsReason getMaxPointsReason();
|
||||
|
||||
boolean isCorrected();
|
||||
|
||||
/**
|
||||
* @return the time point for which this result is valid
|
||||
*/
|
||||
TimePoint getTimePoint();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,26 +50,51 @@ public interface ScoreCorrection extends Serializable {
|
||||
* and {@link MaxPointsReason#NONE} will be listed as the {@link Result#getMaxPointsReason() correction reason}.
|
||||
* Note, though, that {@link MaxPointsReason#NONE} can also be the reason for an explicit score correction, e.g., if
|
||||
* the tracking results were overruled by the jury. Clients may use
|
||||
* {@link #isScoreCorrected(Competitor, TrackedRace)} to detect the difference.
|
||||
* {@link #isScoreCorrected(Competitor, TrackedRace, TimePoint)} to detect the difference.
|
||||
*
|
||||
* @param trackedRankProvider
|
||||
* can provide the tracked rank if needed; will only be called if there is no score correction for the
|
||||
* <code>timePoint</code> specified.
|
||||
* @param timePoint
|
||||
* the time point for which to get the corrected score; score corrections have a validity time interval.
|
||||
* Only the last score correction valid at <code>timePoint</code> is considered.
|
||||
*
|
||||
* @param numberOfCompetitorsFetcher
|
||||
* can determine the number of competitors to use as the basis for penalty score calculation
|
||||
* ("max points") if needed
|
||||
*/
|
||||
Result getCorrectedScore(Callable<Integer> trackedRank, Competitor competitor, RaceColumn raceColumn,
|
||||
Result getCorrectedScore(Callable<Integer> trackedRankProvider, Competitor competitor, RaceColumn raceColumn,
|
||||
TimePoint timePoint, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsFetcher, ScoringScheme scoringScheme);
|
||||
|
||||
/**
|
||||
* @param timePoint
|
||||
* the time point at which the max points reason is to be valid
|
||||
*
|
||||
* @return a non-<code>null</code> result
|
||||
*/
|
||||
MaxPointsReason getMaxPointsReason(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* Note the difference between what this method does and a more naive comparison of uncorrected and corrected score.
|
||||
* Should, for some reason, the uncorrected score change later, an existing score correction would still remain in
|
||||
* place whereas if no score correction exists for the competitor/race combination, the resulting score after
|
||||
* "correction" will still be the uncorrected value.<p>
|
||||
* "correction" will still be the uncorrected value.
|
||||
* <p>
|
||||
*
|
||||
* @param timePoint
|
||||
* the time point for which to check whether the competitor's score was corrected at that time point; in
|
||||
* other words, this method checks if there is a score correction for <code>competitor</code> in column
|
||||
* <code>raceColumn</code> that is valid at <code>timePoint</code>.
|
||||
*
|
||||
* @return if an explicit score correction was made for the combination of <code>competitor</code> and
|
||||
* <code>raceColumn</code>
|
||||
*/
|
||||
boolean isScoreCorrected(Competitor competitor, RaceColumn raceColumn);
|
||||
boolean isScoreCorrected(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* Checks if this score correction object has any score corrections for any competitor valid at any time point for
|
||||
* the race column specified by <code>raceInLeaderboard</code>.
|
||||
*/
|
||||
boolean hasCorrectionFor(RaceColumn raceInLeaderboard);
|
||||
|
||||
/**
|
||||
|
||||
+2
-7
@@ -13,17 +13,12 @@ public interface SettableScoreCorrection extends ScoreCorrection {
|
||||
/**
|
||||
* @param reason
|
||||
* if <code>null</code>, any existing max-points reason is removed; while
|
||||
* {@link #getMaxPointsReason(Competitor, RaceColumn)} will return {@link MaxPointsReason#NONE}, a
|
||||
* call to {@link #isScoreCorrected(Competitor, RaceColumn)} will return <code>false</code> if no
|
||||
* {@link #getMaxPointsReason(Competitor, RaceColumn, TimePoint)} will return {@link MaxPointsReason#NONE}, a
|
||||
* call to {@link #isScoreCorrected(Competitor, RaceColumn, TimePoint)} will return <code>false</code> if no
|
||||
* other explicit score correction was made for the <code>competitor</code>.
|
||||
*/
|
||||
void setMaxPointsReason(Competitor competitor, RaceColumn raceColumn, MaxPointsReason reason);
|
||||
|
||||
/**
|
||||
* @return a non-<code>null</code> result
|
||||
*/
|
||||
MaxPointsReason getMaxPointsReason(Competitor competitor, RaceColumn raceColumn);
|
||||
|
||||
void correctScore(Competitor competitor, RaceColumn raceColumn, double points);
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -82,8 +82,8 @@ public class LeaderboardDTOCache implements LeaderboardCache {
|
||||
public LeaderboardDTOCache(boolean waitForLatestAnalyses, Leaderboard leaderboard) {
|
||||
this.leaderboard = leaderboard;
|
||||
this.waitForLatestAnalyses = waitForLatestAnalyses;
|
||||
// if the leaderboard becomes weakly referenced and eventually GCed, then so can the cached results for it
|
||||
this.leaderboardCache = new LinkedHashMap<Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>>(16, 0.75f, /* access-based eviction */ true) {
|
||||
// Note: don't use access-based ordering as it turns the get(...) call into a "write" access
|
||||
this.leaderboardCache = new LinkedHashMap<Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>>(16, 0.75f) {
|
||||
private static final long serialVersionUID = 7287916997229815039L;
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<Pair<TimePoint, Collection<String>>, FutureTask<LeaderboardDTO>> e) {
|
||||
|
||||
+3
-7
@@ -14,7 +14,6 @@ import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.leaderboard.ScoreCorrection;
|
||||
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
@@ -38,14 +37,11 @@ public abstract class AbstractLeaderboardImpl extends AbstractSimpleLeaderboardI
|
||||
private transient Iterable<Competitor> allCompetitorsCache;
|
||||
|
||||
/**
|
||||
* @param scoreCorrection must not be <code>null</code>
|
||||
* @param scoreComparator the comparator to use to compare basic scores, such as net points
|
||||
* @param name must not be <code>null</code>
|
||||
*/
|
||||
public AbstractLeaderboardImpl(SettableScoreCorrection scoreCorrection,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(scoreCorrection, resultDiscardingRule);
|
||||
assert scoreCorrection != null;
|
||||
public AbstractLeaderboardImpl(ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(resultDiscardingRule);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,7 +129,7 @@ public abstract class AbstractLeaderboardImpl extends AbstractSimpleLeaderboardI
|
||||
Iterator<Competitor> ci = competitorsFromBestToWorst.iterator();
|
||||
while (betterCompetitorRank < rank && ci.hasNext()) {
|
||||
Competitor betterTrackedCompetitor = ci.next();
|
||||
MaxPointsReason maxPointsReasonForBetterCompetitor = getScoreCorrection().getMaxPointsReason(betterTrackedCompetitor, raceColumn);
|
||||
MaxPointsReason maxPointsReasonForBetterCompetitor = getScoreCorrection().getMaxPointsReason(betterTrackedCompetitor, raceColumn, timePoint);
|
||||
if (maxPointsReasonForBetterCompetitor != null && maxPointsReasonForBetterCompetitor != MaxPointsReason.NONE &&
|
||||
maxPointsReasonForBetterCompetitor.isAdvanceCompetitorsTrackedWorse()) {
|
||||
correctedRank--;
|
||||
|
||||
+13
-4
@@ -342,9 +342,9 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
}
|
||||
}
|
||||
|
||||
public AbstractSimpleLeaderboardImpl(SettableScoreCorrection scoreCorrection, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
public AbstractSimpleLeaderboardImpl(ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
this.carriedPoints = new HashMap<Competitor, Double>();
|
||||
this.scoreCorrection = scoreCorrection;
|
||||
this.scoreCorrection = createScoreCorrection();
|
||||
this.displayNames = new HashMap<Competitor, String>();
|
||||
this.crossLeaderboardResultDiscardingRule = resultDiscardingRule;
|
||||
this.suppressedCompetitors = new HashSet<Competitor>();
|
||||
@@ -354,6 +354,15 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
initTransientFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces the score correction object to use in this leaderboard. Used by the constructor. Subclasses may override
|
||||
* this method to create a more specific type of score correction. This implementation produces an object of type
|
||||
* {@link ScoreCorrectionImpl}.
|
||||
*/
|
||||
protected SettableScoreCorrection createScoreCorrection() {
|
||||
return new ScoreCorrectionImpl(this);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
ois.defaultReadObject();
|
||||
initTransientFields();
|
||||
@@ -459,7 +468,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
|
||||
@Override
|
||||
public MaxPointsReason getMaxPointsReason(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
|
||||
return getScoreCorrection().getMaxPointsReason(competitor, raceColumn);
|
||||
return getScoreCorrection().getMaxPointsReason(competitor, raceColumn, timePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -615,7 +624,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
public boolean countRaceForComparisonWithDiscardingThresholds(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
|
||||
TrackedRace trackedRaceForCompetitorInColumn;
|
||||
return getScoringScheme().isValidInTotalScore(this, raceColumn, timePoint) &&
|
||||
(getScoreCorrection().isScoreCorrected(competitor, raceColumn) ||
|
||||
(getScoreCorrection().isScoreCorrected(competitor, raceColumn, timePoint) ||
|
||||
((trackedRaceForCompetitorInColumn=raceColumn.getTrackedRace(competitor)) != null &&
|
||||
trackedRaceForCompetitorInColumn.hasStarted(timePoint)));
|
||||
}
|
||||
|
||||
+6
-7
@@ -18,7 +18,6 @@ import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
@@ -47,14 +46,14 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
private transient RaceLogStore raceLogStore;
|
||||
private CourseArea courseArea;
|
||||
|
||||
public FlexibleLeaderboardImpl(String name, SettableScoreCorrection scoreCorrection,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule, ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
this(EmptyRaceLogStore.INSTANCE, name, scoreCorrection, resultDiscardingRule, scoringScheme, courseArea);
|
||||
public FlexibleLeaderboardImpl(String name, ThresholdBasedResultDiscardingRule resultDiscardingRule,
|
||||
ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
this(EmptyRaceLogStore.INSTANCE, name, resultDiscardingRule, scoringScheme, courseArea);
|
||||
}
|
||||
|
||||
public FlexibleLeaderboardImpl(RaceLogStore raceLogStore, String name, SettableScoreCorrection scoreCorrection,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule, ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
super(scoreCorrection, resultDiscardingRule);
|
||||
public FlexibleLeaderboardImpl(RaceLogStore raceLogStore, String name, ThresholdBasedResultDiscardingRule resultDiscardingRule,
|
||||
ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
super(resultDiscardingRule);
|
||||
this.scoringScheme = scoringScheme;
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
|
||||
+2
-4
@@ -14,7 +14,6 @@ import com.sap.sailing.domain.base.impl.RaceColumnInSeriesImpl;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
@@ -31,9 +30,8 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
|
||||
private static final long serialVersionUID = 2370461218294770084L;
|
||||
private final Regatta regatta;
|
||||
|
||||
public RegattaLeaderboardImpl(Regatta regatta, SettableScoreCorrection scoreCorrection,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(scoreCorrection, resultDiscardingRule);
|
||||
public RegattaLeaderboardImpl(Regatta regatta, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(resultDiscardingRule);
|
||||
this.regatta = regatta;
|
||||
regatta.addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
+205
-21
@@ -5,6 +5,7 @@ import java.io.ObjectInputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@@ -14,10 +15,12 @@ import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher;
|
||||
import com.sap.sailing.domain.leaderboard.ScoreCorrectionListener;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
@@ -58,7 +61,10 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
|
||||
private transient Set<ScoreCorrectionListener> scoreCorrectionListeners;
|
||||
|
||||
public ScoreCorrectionImpl() {
|
||||
private final Leaderboard leaderboard;
|
||||
|
||||
public ScoreCorrectionImpl(Leaderboard leaderboard) {
|
||||
this.leaderboard = leaderboard;
|
||||
this.maxPointsReasons = new HashMap<Util.Pair<Competitor, RaceColumn>, MaxPointsReason>();
|
||||
this.correctedScores = new HashMap<Util.Pair<Competitor, RaceColumn>, Double>();
|
||||
this.scoreCorrectionListeners = new HashSet<ScoreCorrectionListener>();
|
||||
@@ -135,9 +141,10 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isScoreCorrected(Competitor competitor, RaceColumn raceColumn) {
|
||||
public boolean isScoreCorrected(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
|
||||
Pair<Competitor, RaceColumn> key = raceColumn.getKey(competitor);
|
||||
return correctedScores.containsKey(key) || maxPointsReasons.containsKey(key);
|
||||
return (correctedScores.containsKey(key) && !isCertainlyBeforeRaceFinish(timePoint, raceColumn, competitor))
|
||||
|| (maxPointsReasons.containsKey(key) && isMaxPointsReasonApplicable(maxPointsReasons.get(key), timePoint, raceColumn, competitor));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,30 +153,198 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
notifyListeners(competitor, raceColumn, oldScore, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaxPointsReason getMaxPointsReason(Competitor competitor, RaceColumn raceColumn) {
|
||||
MaxPointsReason result = maxPointsReasons.get(raceColumn.getKey(competitor));
|
||||
if (result == null) {
|
||||
result = MaxPointsReason.NONE;
|
||||
/**
|
||||
* Based on the order of the {@link Leaderboard#getRaceColumns() race columns} in the {@link #getLeaderboard()
|
||||
* leaderboard to which this score correction object belongs}, tries to determine whether the <code>timePoint</code>
|
||||
* is before the start of <code>competitor</code>'s race in the race column specified by <code>raceColumn</code>. If
|
||||
* there is a {@link RaceColumn#getTrackedRace(Competitor) tracked race for the competitor associated with the race
|
||||
* column}, that race's start time is used for the calculation. Otherwise, if there is a tracked race column prior
|
||||
* to <code>raceColumn</code> in the leaderboard in which <code>competitor</code> competes, and the competitor
|
||||
* hasn't finished that race at <code>timePoint</code>, we also know that this must be before the start of
|
||||
* <code>competitor</code>'s race in <code>raceColumn</code> because we assume that the same competitor can only
|
||||
* compete in one race at a time within a single leaderboard.
|
||||
* <p>
|
||||
*
|
||||
* In all other cases, <code>false</code> is returned which can either mean that <code>timePoint</code> is certainly
|
||||
* known to be after the race start of <code>competitor</code> in the race for <code>raceColumn</code>, or we just
|
||||
* can't tell, e.g., because <code>competitor</code>'s race for <code>raceColumn</code> is not tracked, and
|
||||
* <code>timePoint</code> is after all prior race column's finishing time for <code>competitor</code>.
|
||||
* <p>
|
||||
*
|
||||
* This method can be used to decide whether to apply a {@link MaxPointsReason#DNC}, {@link MaxPointsReason#DNS} or
|
||||
* {@link MaxPointsReason#OCS} correction for <code>competitor</code> at <code>timePoint</code> in the race for
|
||||
* <code>raceColumn</code>, because the correction can be applied at race start but should not be applied any
|
||||
* earlier than that because it would incorrectly influence the total scores displayed for the competitor during
|
||||
* earlier races.
|
||||
*/
|
||||
private boolean isCertainlyBeforeRaceStart(TimePoint timePoint, RaceColumn raceColumn, Competitor competitor) {
|
||||
final boolean result;
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(competitor);
|
||||
final TimePoint startOfRace;
|
||||
if (trackedRace != null && (startOfRace = trackedRace.getStartOfRace()) != null) {
|
||||
result = timePoint.before(startOfRace);
|
||||
} else {
|
||||
boolean preResult = false;
|
||||
for (RaceColumn rc : getLeaderboard().getRaceColumns()) {
|
||||
if (rc == raceColumn) {
|
||||
break;
|
||||
}
|
||||
TrackedRace rcTrackedRace = rc.getTrackedRace(competitor);
|
||||
if (rcTrackedRace != null) {
|
||||
NavigableSet<MarkPassing> markPassings = rcTrackedRace.getMarkPassings(competitor);
|
||||
if (markPassings != null && !markPassings.isEmpty()) {
|
||||
MarkPassing lastMarkPassing = markPassings.last();
|
||||
if (timePoint.before(lastMarkPassing.getTimePoint())) {
|
||||
preResult = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// if available, use the end of the race as indicator for how long competitor may have been in the race
|
||||
TimePoint endOfRace = rcTrackedRace.getEndOfRace();
|
||||
if (endOfRace != null && timePoint.before(endOfRace)) {
|
||||
preResult = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result = preResult;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the {@link #getMaxPointsReason(Competitor, TrackedRace)} for the <code>competitor</code> for the
|
||||
* Based on the order of the {@link Leaderboard#getRaceColumns() race columns} in the {@link #getLeaderboard()
|
||||
* leaderboard to which this score correction object belongs}, tries to determine whether the <code>timePoint</code>
|
||||
* is before the finish or abandoning of <code>competitor</code>'s race in the race column specified by
|
||||
* <code>raceColumn</code>. If there is a {@link RaceColumn#getTrackedRace(Competitor) tracked race for the
|
||||
* competitor associated with the race column}, that race's finish time for <code>competitor</code> (if defined) or
|
||||
* the {@link TrackedRace#getEndOfRace() end of the race} is used for the calculation. Otherwise, if there is a
|
||||
* tracked race column prior to <code>raceColumn</code> in the leaderboard in which <code>competitor</code>
|
||||
* competes, and the competitor has finished that race after <code>timePoint</code>, we also know that this must be
|
||||
* before the end of <code>competitor</code>'s race in <code>raceColumn</code> because we assume that the same
|
||||
* competitor can only compete in one race at a time within a single leaderboard.
|
||||
* <p>
|
||||
*
|
||||
* In all other cases, <code>false</code> is returned which can either mean that <code>timePoint</code> is certainly
|
||||
* known to be after the race finish of <code>competitor</code> in the race for <code>raceColumn</code>, or we just
|
||||
* can't tell, e.g., because <code>competitor</code>'s race for <code>raceColumn</code> is not tracked, and
|
||||
* <code>timePoint</code> is after all prior race column's finishing time for <code>competitor</code>.
|
||||
* <p>
|
||||
*
|
||||
* This method can be used to decide whether to apply a score correction for <code>competitor</code> at
|
||||
* <code>timePoint</code> in the race for <code>raceColumn</code>, because the correction should not be applied
|
||||
* before race end because it would incorrectly influence the total scores displayed for the competitor during
|
||||
* earlier races.
|
||||
*/
|
||||
private boolean isCertainlyBeforeRaceFinish(TimePoint timePoint, RaceColumn raceColumn, Competitor competitor) {
|
||||
final boolean result;
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(competitor);
|
||||
final TimePoint endOfRace;
|
||||
// endOfRace != null means we at least will have a fallback result even if there are no mark passings for the competitor
|
||||
if (trackedRace != null && (endOfRace = trackedRace.getEndOfRace()) != null) {
|
||||
NavigableSet<MarkPassing> markPassings = trackedRace.getMarkPassings(competitor);
|
||||
final MarkPassing lastMarkPassing;
|
||||
// count race as finished for the competitor if the finish mark passing exists or the time is after the end of race
|
||||
if (markPassings != null && !markPassings.isEmpty() &&
|
||||
(lastMarkPassing = markPassings.last()).getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint()) {
|
||||
result = timePoint.before(lastMarkPassing.getTimePoint());
|
||||
} else {
|
||||
// if available, use the end of the race as indicator for how long competitor may have been in the race
|
||||
result = timePoint.before(endOfRace);
|
||||
}
|
||||
} else {
|
||||
boolean preResult = false;
|
||||
for (RaceColumn rc : getLeaderboard().getRaceColumns()) {
|
||||
if (rc == raceColumn) {
|
||||
break;
|
||||
}
|
||||
TrackedRace rcTrackedRace = rc.getTrackedRace(competitor);
|
||||
if (rcTrackedRace != null) {
|
||||
NavigableSet<MarkPassing> markPassings = rcTrackedRace.getMarkPassings(competitor);
|
||||
if (markPassings != null && !markPassings.isEmpty()) {
|
||||
MarkPassing lastMarkPassing = markPassings.last();
|
||||
if (timePoint.before(lastMarkPassing.getTimePoint())) {
|
||||
preResult = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// if available, use the end of the race as indicator for how long competitor may have been in the race
|
||||
TimePoint rcEndOfRace = rcTrackedRace.getEndOfRace();
|
||||
if (rcEndOfRace != null) {
|
||||
if (timePoint.before(rcEndOfRace)) {
|
||||
preResult = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
TimePoint rcStartOfRace = rcTrackedRace.getStartOfRace();
|
||||
if (rcStartOfRace != null && timePoint.before(rcStartOfRace)) {
|
||||
preResult = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result = preResult;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean appliesAtStartOfRace(MaxPointsReason maxPointsReason) {
|
||||
final boolean result;
|
||||
switch (maxPointsReason) {
|
||||
case DNS:
|
||||
case DNC:
|
||||
case OCS:
|
||||
result = true;
|
||||
break;
|
||||
default:
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaxPointsReason getMaxPointsReason(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
|
||||
MaxPointsReason result = maxPointsReasons.get(raceColumn.getKey(competitor));
|
||||
if (result == null || !isMaxPointsReasonApplicable(result, timePoint, raceColumn, competitor)) {
|
||||
result = MaxPointsReason.NONE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isMaxPointsReasonApplicable(MaxPointsReason maxPointsReason, TimePoint timePoint, RaceColumn raceColumn, Competitor competitor) {
|
||||
return (appliesAtStartOfRace(maxPointsReason) && !isCertainlyBeforeRaceStart(timePoint, raceColumn, competitor))
|
||||
|| !isCertainlyBeforeRaceFinish(timePoint, raceColumn, competitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the {@link #getMaxPointsReason(Competitor, TrackedRace, TimePoint)} for the <code>competitor</code> for the
|
||||
* <code>raceColumn</code>'s tracked race is not {@link MaxPointsReason#NONE}, the
|
||||
* {@link #getMaxPoints(TrackedRace) maximum score} is computed for the competitor. Otherwise, the
|
||||
* <code>uncorrectedScore</code> is returned.
|
||||
* <p>
|
||||
*
|
||||
* The current implementation considers <code>timePoint</code> by comparing it to the <code>competitor</code>'s
|
||||
* times for the tracked race associated for that competitor in <code>raceColumn</code>. If there is no such tracked
|
||||
* race, any score correction available will be applied unchanged. If a tracked race is attached to the column for
|
||||
* the competitor's fleet, the score correction is applied if <code>timePoint</code> is after the competitor
|
||||
* finished or aborted the race. If the <code>timePoint</code> is after the {@link TrackedRace#getStartOfRace() race
|
||||
* start time}, a score correction for the competitor for that race is considered if it is a
|
||||
* {@link MaxPointsReason#DNS}, {@link MaxPointsReason#DNC} or {@link MaxPointsReason#OCS} code. Those penalties
|
||||
* apply already from the start of the race and will cause the penalty score to be applied already during the race
|
||||
* time interval, so the competitor will be sorted to the end of the leaderboard already during replay.
|
||||
* <p>
|
||||
*/
|
||||
@Override
|
||||
public Result getCorrectedScore(Callable<Integer> trackedRankProvider, final Competitor competitor,
|
||||
final RaceColumn raceColumn, TimePoint timePoint, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher,
|
||||
final RaceColumn raceColumn, final TimePoint timePoint, NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher,
|
||||
ScoringScheme scoringScheme) {
|
||||
Double result;
|
||||
final MaxPointsReason maxPointsReason = getMaxPointsReason(competitor, raceColumn);
|
||||
final MaxPointsReason maxPointsReason = getMaxPointsReason(competitor, raceColumn, timePoint);
|
||||
if (maxPointsReason == MaxPointsReason.NONE) {
|
||||
result = getCorrectedNonMaxedScore(competitor, raceColumn, trackedRankProvider, scoringScheme, numberOfCompetitorsInLeaderboardFetcher);
|
||||
result = getCorrectedNonMaxedScore(competitor, raceColumn, trackedRankProvider, scoringScheme, numberOfCompetitorsInLeaderboardFetcher, timePoint);
|
||||
} else {
|
||||
// allow explicit override even when max points reason is specified; calculation may be wrong,
|
||||
// e.g., in case we have an untracked race and the number of competitors is estimated incorrectly
|
||||
@@ -196,7 +371,12 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
|
||||
@Override
|
||||
public boolean isCorrected() {
|
||||
return isScoreCorrected(competitor, raceColumn);
|
||||
return isScoreCorrected(competitor, raceColumn, getTimePoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePoint() {
|
||||
return timePoint;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -216,21 +396,21 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
* Under the assumption that the competitor is not assigned the maximum score due to disqualification or other
|
||||
* reasons, computes the corrected score. If {@link #correctedScores} contains an entry for the
|
||||
* <code>competitor</code>'s key, it is used. Otherwise, the <code>uncorrectedScore</code> is returned.
|
||||
*
|
||||
* @param scoringScheme
|
||||
* used to transform the tracked rank into a score if there is no score correction applied
|
||||
*
|
||||
* @return <code>null</code> in case the <code>competitor</code> has no score assigned in that race which is the
|
||||
* case if the score is not corrected by these score corrections, and the <code>trackedRankProvider</code> delivers 0
|
||||
* as the rank, or if the score is not corrected and the scoring scheme cannot find the competitor in any tracked race
|
||||
* of the <code>raceColumn</code>, meaning there cannot be a tracked rank for the competitor regardless what
|
||||
* <code>trackedRankProvider</code> delivers.
|
||||
* case if the score is not corrected by these score corrections, and the <code>trackedRankProvider</code>
|
||||
* delivers 0 as the rank, or if the score is not corrected and the scoring scheme cannot find the
|
||||
* competitor in any tracked race of the <code>raceColumn</code>, meaning there cannot be a tracked rank for
|
||||
* the competitor regardless what <code>trackedRankProvider</code> delivers.
|
||||
*/
|
||||
protected Double getCorrectedNonMaxedScore(final Competitor competitor, final RaceColumn raceColumn,
|
||||
private Double getCorrectedNonMaxedScore(final Competitor competitor, final RaceColumn raceColumn,
|
||||
Callable<Integer> trackedRankProvider, ScoringScheme scoringScheme,
|
||||
final NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher) {
|
||||
final NumberOfCompetitorsInLeaderboardFetcher numberOfCompetitorsInLeaderboardFetcher, TimePoint timePoint) {
|
||||
Double correctedNonMaxedScore = correctedScores.get(raceColumn.getKey(competitor));
|
||||
Double result;
|
||||
if (correctedNonMaxedScore == null) {
|
||||
if (correctedNonMaxedScore == null || isCertainlyBeforeRaceFinish(timePoint, raceColumn, competitor)) {
|
||||
try {
|
||||
int trackedRank = trackedRankProvider.call();
|
||||
result = scoringScheme.getScoreForRank(raceColumn, competitor, trackedRank,
|
||||
@@ -289,4 +469,8 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
|
||||
this.comment = scoreCorrectionComment;
|
||||
}
|
||||
|
||||
protected Leaderboard getLeaderboard() {
|
||||
return leaderboard;
|
||||
}
|
||||
|
||||
}
|
||||
+9
-2
@@ -20,6 +20,7 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.MetaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoreCorrectionListener;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.leaderboard.impl.AbstractSimpleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
@@ -74,8 +75,7 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI
|
||||
}
|
||||
|
||||
public AbstractMetaLeaderboard(String name, ScoringScheme scoringScheme, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(new MetaLeaderboardScoreCorrection(), resultDiscardingRule);
|
||||
getScoreCorrection().setMetaLeaderboard(this);
|
||||
super(resultDiscardingRule);
|
||||
metaFleet = new FleetImpl("MetaFleet");
|
||||
this.scoringScheme = scoringScheme;
|
||||
this.name = name;
|
||||
@@ -83,6 +83,13 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI
|
||||
scoreCorrectionChangeForwardersByLeaderboard = new WeakHashMap<Leaderboard, ScoreCorrectionListener>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SettableScoreCorrection createScoreCorrection() {
|
||||
return new MetaLeaderboardScoreCorrection(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
ois.defaultReadObject();
|
||||
columnsForLeaderboards = new WeakHashMap<>();
|
||||
|
||||
+9
-7
@@ -6,18 +6,15 @@ import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.MetaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
|
||||
public class MetaLeaderboardScoreCorrection extends ScoreCorrectionImpl {
|
||||
private static final long serialVersionUID = 3773423384260065869L;
|
||||
private AbstractMetaLeaderboard metaLeaderboard;
|
||||
|
||||
public MetaLeaderboardScoreCorrection() {
|
||||
}
|
||||
|
||||
protected void setMetaLeaderboard(AbstractMetaLeaderboard metaLeaderboard) {
|
||||
this.metaLeaderboard = metaLeaderboard;
|
||||
public MetaLeaderboardScoreCorrection(MetaLeaderboard leaderboard) {
|
||||
super(leaderboard);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,10 +41,15 @@ public class MetaLeaderboardScoreCorrection extends ScoreCorrectionImpl {
|
||||
super.notifyListeners(competitor, oldMaxPointsReason, newMaxPointsReason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MetaLeaderboard getLeaderboard() {
|
||||
return (MetaLeaderboard) super.getLeaderboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePointOfLastCorrectionsValidity() {
|
||||
TimePoint result = super.getTimePointOfLastCorrectionsValidity();
|
||||
for (Leaderboard leaderboard : metaLeaderboard.getLeaderboards()) {
|
||||
for (Leaderboard leaderboard : getLeaderboard().getLeaderboards()) {
|
||||
TimePoint leaderboardLastCorrectionTimePoint = leaderboard.getScoreCorrection().getTimePointOfLastCorrectionsValidity();
|
||||
if (result == null || (leaderboardLastCorrectionTimePoint != null && leaderboardLastCorrectionTimePoint.after(result))) {
|
||||
result = leaderboardLastCorrectionTimePoint;
|
||||
|
||||
+2
-3
@@ -9,7 +9,6 @@ import com.sap.sailing.domain.base.LeaderboardMasterData;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||
|
||||
public class FlexibleLeaderboardMasterData extends LeaderboardMasterData {
|
||||
@@ -48,8 +47,8 @@ public class FlexibleLeaderboardMasterData extends LeaderboardMasterData {
|
||||
|
||||
@Override
|
||||
public Leaderboard getLeaderboard() {
|
||||
return new FlexibleLeaderboardImpl(getName(), new ScoreCorrectionImpl(), getResultDiscardingRule(),
|
||||
scoringScheme, courseArea);
|
||||
return new FlexibleLeaderboardImpl(getName(), getResultDiscardingRule(), scoringScheme,
|
||||
courseArea);
|
||||
}
|
||||
|
||||
public List<RaceColumnMasterData> getRaceColumns() {
|
||||
|
||||
+1
-2
@@ -10,7 +10,6 @@ import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaName;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||
|
||||
public class RegattaLeaderboardMasterData extends LeaderboardMasterData {
|
||||
@@ -40,7 +39,7 @@ public class RegattaLeaderboardMasterData extends LeaderboardMasterData {
|
||||
if (regatta == null) {
|
||||
return null;
|
||||
}
|
||||
return new RegattaLeaderboardImpl(regatta, new ScoreCorrectionImpl(), getResultDiscardingRule());
|
||||
return new RegattaLeaderboardImpl(regatta, getResultDiscardingRule());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,8 @@ public interface RaceLogIdentifier extends Serializable {
|
||||
|
||||
Triple<String, String, String> getIdentifier();
|
||||
|
||||
String getDeprecatedIdentifier();
|
||||
|
||||
RaceLogIdentifierTemplate getTemplate();
|
||||
|
||||
}
|
||||
+8
@@ -25,6 +25,14 @@ public class RaceLogIdentifierImpl implements RaceLogIdentifier {
|
||||
return new Util.Triple<String, String, String>(template.getParentObjectName(), raceColumnName, fleetName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeprecatedIdentifier() {
|
||||
return String.format("%s.%s.%s",
|
||||
this.getTemplate().getParentObjectName(),
|
||||
this.getRaceColumnName(),
|
||||
this.getFleetName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceLogIdentifierTemplate getTemplate() {
|
||||
return template;
|
||||
|
||||
+3
-3
@@ -31,7 +31,7 @@ import com.sap.sailing.domain.tracking.Wind;
|
||||
|
||||
public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
|
||||
|
||||
public static final Logger log = Logger.getLogger(DynamicTrackedRaceLogListener.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(DynamicTrackedRaceLogListener.class.getName());
|
||||
|
||||
private DynamicTrackedRace trackedRace;
|
||||
|
||||
@@ -112,7 +112,7 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
|
||||
// ... onCourseDesignChangedByRaceCommittee() might be called more than once.
|
||||
trackedRace.onCourseDesignChangedByRaceCommittee(courseDesign);
|
||||
} else {
|
||||
log.info("Could not find any course design update on race log of " + trackedRace.getRace().getName() + "! Not sending out any events.");
|
||||
logger.info("Could not find any course design update on race log of " + trackedRace.getRace().getName() + "! Not sending out any events.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
|
||||
/* invoke listeners with received start time, this will also trigger tractrac update */
|
||||
trackedRace.onStartTimeChangedByRaceCommittee(startTime);
|
||||
} else {
|
||||
log.info("Could not find any valid start time on race log of " + trackedRace.getRace().getName() + "! Not sending out any events.");
|
||||
logger.info("Could not find any valid start time on race log of " + trackedRace.getRace().getName() + "! Not sending out any events.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,5 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||
Fragment-Host: com.sap.sailing.expeditionconnector
|
||||
Require-Bundle: com.sap.sailing.server,
|
||||
com.sap.sailing.domain.test,
|
||||
com.sap.sailing.udpconnector
|
||||
Import-Package: junit.framework;version="4.8.1",
|
||||
org.junit;version="4.8.1",
|
||||
org.osgi.framework;version="1.6.0"
|
||||
com.sap.sailing.udpconnector,
|
||||
org.junit4;bundle-version="4.8.2"
|
||||
@@ -34,10 +34,10 @@
|
||||
<plugin id="com.sap.sailing.barbados.resultimport" autoStart="true" startLevel="3" />
|
||||
<plugin id="com.sap.sailing.ess40.resultimport" autoStart="true" startLevel="3" />
|
||||
<plugin id="com.sap.sailing.freg.resultimport" autoStart="true" startLevel="3" />
|
||||
<plugin id="com.sap.sailing.gwt.ui" autoStart="true" startLevel="4" />
|
||||
<plugin id="com.sap.sailing.gwt.ui" autoStart="true" startLevel="5" />
|
||||
<plugin id="com.sap.sailing.kiworesultimport" autoStart="true" startLevel="3" />
|
||||
<plugin id="com.sap.sailing.manage2sail.resultimport" autoStart="true" startLevel="3" />
|
||||
<plugin id="com.sap.sailing.monitoring" autoStart="true" startLevel="5" />
|
||||
<plugin id="com.sap.sailing.monitoring" autoStart="true" startLevel="6" />
|
||||
<plugin id="com.sap.sailing.resultimport" autoStart="true" startLevel="3" />
|
||||
<plugin id="com.sap.sailing.sailwave.resultimport" autoStart="true" startLevel="3" />
|
||||
<plugin id="com.sap.sailing.server" autoStart="true" startLevel="4" />
|
||||
|
||||
@@ -27,17 +27,15 @@
|
||||
<import plugin="org.eclipse.osgi"/>
|
||||
<import plugin="org.eclipse.osgi.services"/>
|
||||
<import plugin="slf4j.api"/>
|
||||
<import plugin="javax.el"/>
|
||||
<import plugin="javax.servlet.jsp"/>
|
||||
<import plugin="javax.servlet.jsp.jstl"/>
|
||||
<import plugin="org.apache.jasper.glassfish"/>
|
||||
<import plugin="org.apache.taglibs.standard.glassfish"/>
|
||||
<import plugin="org.eclipse.jetty.osgi.boot"/>
|
||||
<import plugin="org.eclipse.jetty.websocket.api"/>
|
||||
<import plugin="org.eclipse.jetty.websocket.client"/>
|
||||
<import plugin="org.eclipse.jetty.websocket.common"/>
|
||||
<import plugin="org.eclipse.jetty.websocket.server"/>
|
||||
<import plugin="org.eclipse.jetty.websocket.servlet"/>
|
||||
<import plugin="org.apache.felix.gogo.command"/>
|
||||
<import plugin="org.apache.felix.gogo.runtime"/>
|
||||
<import plugin="org.apache.felix.gogo.shell"/>
|
||||
</requires>
|
||||
|
||||
<plugin
|
||||
@@ -47,14 +45,6 @@
|
||||
version="9.0.4.v20130625"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="org.eclipse.jetty.osgi.boot.jsp"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="9.0.4.v20130625"
|
||||
fragment="true"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="jul.to.slf4j"
|
||||
download-size="0"
|
||||
@@ -98,4 +88,11 @@
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="org.eclipse.equinox.console"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
</feature>
|
||||
@@ -22,20 +22,38 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
|
||||
|
||||
<requires>
|
||||
<import plugin="com.googlecode.java-diff-utils" version="1.3.0" match="greaterOrEqual"/>
|
||||
<import plugin="org.eclipse.osgi"/>
|
||||
<import plugin="org.eclipse.osgi" version="3.9.0" match="greaterOrEqual"/>
|
||||
<import plugin="javax.servlet" version="2.6.0" match="greaterOrEqual"/>
|
||||
<import plugin="com.mongodb.driver" version="2.6.2" match="greaterOrEqual"/>
|
||||
<import plugin="com.google.gwt.osgi" version="2.4.0" match="greaterOrEqual"/>
|
||||
<import plugin="com.sap.sailing.domain.common"/>
|
||||
<import plugin="com.google.gwt.osgi" version="2.5.1" match="greaterOrEqual"/>
|
||||
<import plugin="org.json.simple" version="1.1.0" match="greaterOrEqual"/>
|
||||
<import plugin="com.sap.sailing.operationaltransformation"/>
|
||||
<import plugin="org.moxieapps.gwt.highcharts" version="1.1.4" match="greaterOrEqual"/>
|
||||
<import plugin="com.sap.sailing.geocoding"/>
|
||||
<import plugin="org.apache.geronimo.specs.geronimo-jms_1.1_spec"/>
|
||||
<import plugin="com.rabbitmq.client"/>
|
||||
<import plugin="org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec"/>
|
||||
</requires>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.geocoding"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.operationaltransformation"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain.common"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.domain"
|
||||
download-size="0"
|
||||
@@ -85,13 +103,6 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="org.json.simple"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.declination"
|
||||
download-size="0"
|
||||
@@ -99,13 +110,6 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.mongodb.driver"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.mongodb"
|
||||
download-size="0"
|
||||
@@ -176,20 +180,6 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.google.gwt.osgi"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.googlecode.java-diff-utils"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.www"
|
||||
download-size="0"
|
||||
|
||||
@@ -6,6 +6,5 @@ Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||
Fragment-Host: com.sap.sailing.geocoding
|
||||
Import-Package: junit.framework;version="4.8.2",
|
||||
org.json.simple.parser,
|
||||
org.junit;version="4.8.2"
|
||||
Require-Bundle: org.junit4;bundle-version="4.8.2"
|
||||
Import-Package: org.json.simple.parser
|
||||
@@ -3,8 +3,8 @@
|
||||
<classpathentry kind="src" path="src/main/resources"/>
|
||||
<classpathentry kind="src" path="src/main/java"/>
|
||||
<classpathentry exported="true" kind="lib" path="WEB-INF/classes/"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="lib" path="WEB-INF/lib/gwt-servlet.jar" sourcepath="/com.google.gwt.osgi/lib/gwt-user.jar"/>
|
||||
<classpathentry kind="lib" path="WEB-INF/lib/gwt-maps.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
|
||||
@@ -16,7 +16,6 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sailing.domain.swisstimingadapter.persistence,
|
||||
com.sap.sailing.domain.tractracadapter.persistence,
|
||||
com.google.gwt.osgi;bundle-version="2.4.0",
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sailing.resultimport,
|
||||
org.moxieapps.gwt.highcharts;bundle-version="1.5.0",
|
||||
@@ -27,12 +26,14 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.swisstimingreplayadapter,
|
||||
com.sap.sailing.simulator;bundle-version="1.0.0",
|
||||
com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0",
|
||||
de.csenk.gwt.ws
|
||||
de.csenk.gwt.ws,
|
||||
com.google.gwt.osgi;bundle-version="2.5.1"
|
||||
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Import-Package: javax.jms;version="1.1.0",
|
||||
javax.servlet;version="2.6.0",
|
||||
javax.servlet.http;version="2.6.0",
|
||||
javax.servlet.descriptor;version="2.6.0",
|
||||
org.json.simple,
|
||||
org.json.simple.parser,
|
||||
org.osgi.framework,
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
<execution>
|
||||
<configuration>
|
||||
<extraJvmArgs>-Dgwt.persistentunitcache=false</extraJvmArgs>
|
||||
<userAgents>chrome</userAgents>
|
||||
<modules>
|
||||
<module>com.sap.sailing.gwt.ui.AdminConsole</module>
|
||||
<module>com.sap.sailing.gwt.ui.Leaderboard</module>
|
||||
|
||||
+6
-2
@@ -816,8 +816,10 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
|
||||
private void selectTrackedRaceInRaceList() {
|
||||
final String selectedLeaderboardName = getSelectedLeaderboardName();
|
||||
if (selectedLeaderboardName != null) {
|
||||
final RaceColumnDTOAndFleetDTOWithNameBasedEquality selectedRaceColumnAndFleetNameInLeaderboard = getSelectedRaceColumnWithFleet();
|
||||
final String selectedRaceColumnName = selectedRaceColumnAndFleetNameInLeaderboard.getA().getRaceColumnName();
|
||||
final String selectedRaceColumnName = selectedRaceColumnAndFleetNameInLeaderboard.getA()
|
||||
.getRaceColumnName();
|
||||
final String selectedFleetName = selectedRaceColumnAndFleetNameInLeaderboard.getB().getName();
|
||||
sailingService.getRegattaAndRaceNameOfTrackedRaceConnectedToLeaderboardColumn(selectedLeaderboardName,
|
||||
selectedRaceColumnName, new AsyncCallback<Map<String, RegattaAndRaceIdentifier>>() {
|
||||
@@ -831,7 +833,8 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
@Override
|
||||
public void onSuccess(Map<String, RegattaAndRaceIdentifier> regattaAndRaceNamesPerFleet) {
|
||||
if (regattaAndRaceNamesPerFleet != null && !regattaAndRaceNamesPerFleet.isEmpty()) {
|
||||
RegattaAndRaceIdentifier raceIdentifier = regattaAndRaceNamesPerFleet.get(selectedFleetName);
|
||||
RegattaAndRaceIdentifier raceIdentifier = regattaAndRaceNamesPerFleet
|
||||
.get(selectedFleetName);
|
||||
if (raceIdentifier != null) {
|
||||
selectRaceInList(raceIdentifier.getRegattaName(), raceIdentifier.getRaceName());
|
||||
} else {
|
||||
@@ -843,6 +846,7 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void selectRaceInList(String regattaName, String raceName) {
|
||||
RegattaNameAndRaceName raceIdentifier = new RegattaNameAndRaceName(regattaName, raceName);
|
||||
|
||||
+44
-47
@@ -46,14 +46,9 @@ import com.sap.sailing.gwt.ui.shared.SwissTimingConfigurationDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SwissTimingRaceRecordDTO;
|
||||
|
||||
/**
|
||||
* Allows the user to start and stop tracking of events, regattas and races using the TracTrac connector. In particular,
|
||||
* Allows the user to start and stop tracking of races using the SwissTiming connector. In particular,
|
||||
* previously configured connections can be retrieved from a drop-down list which then pre-populates all connection
|
||||
* parameters. The user can also choose to enter connection information manually. Using a "hierarchical" entry system
|
||||
* comparable to that of, e.g., the Eclipse CVS connection setup wizard, components entered will be used to
|
||||
* automatically assemble the full URL which can still be overwritten manually. There is a propagation order across the
|
||||
* fields. Hostname propagates to JSON URL, Live URI and Stored URI. Port Live Data propagates to Port Stored Data,
|
||||
* incremented by one. The ports propagate to Live URI and Stored URI, respectively. The event name propagates to the
|
||||
* JSON URL.
|
||||
* parameters. The user can also choose to enter connection information manually.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
@@ -166,7 +161,16 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
}
|
||||
};
|
||||
|
||||
TextColumn<SwissTimingRaceRecordDTO> raceStartTrackingColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
|
||||
TextColumn<SwissTimingRaceRecordDTO> raceStateColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
|
||||
@Override
|
||||
public String getValue(SwissTimingRaceRecordDTO object) {
|
||||
String result = object.hasCourse ? "C✓ " : "";
|
||||
result += object.hasStartlist ? "S✓" : "";
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
TextColumn<SwissTimingRaceRecordDTO> raceStartTimeColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
|
||||
@Override
|
||||
public String getValue(SwissTimingRaceRecordDTO object) {
|
||||
return object.raceStartTime==null?"":dateFormatter.render(object.raceStartTime) + " " + timeFormatter.render(object.raceStartTime);
|
||||
@@ -176,36 +180,49 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
HorizontalPanel racesSplitPanel = new HorizontalPanel();
|
||||
mainPanel.add(racesSplitPanel);
|
||||
|
||||
CaptionPanel racesCaptionPanel = new CaptionPanel(stringConstants.trackableRaces());
|
||||
racesSplitPanel.add(racesCaptionPanel);
|
||||
racesCaptionPanel.setWidth("50%");
|
||||
CaptionPanel trackableRacesCaptionPanel = new CaptionPanel(stringConstants.trackableRaces());
|
||||
racesSplitPanel.add(trackableRacesCaptionPanel);
|
||||
trackableRacesCaptionPanel.setWidth("50%");
|
||||
|
||||
CaptionPanel trackedRacesCaptionPanel = new CaptionPanel(stringConstants.trackedRaces());
|
||||
racesSplitPanel.add(trackedRacesCaptionPanel);
|
||||
trackedRacesCaptionPanel.setWidth("50%");
|
||||
|
||||
VerticalPanel racesPanel = new VerticalPanel();
|
||||
racesCaptionPanel.setContentWidget(racesPanel);
|
||||
racesCaptionPanel.setStyleName("bold");
|
||||
VerticalPanel trackableRacesPanel = new VerticalPanel();
|
||||
trackableRacesCaptionPanel.setContentWidget(trackableRacesPanel);
|
||||
trackableRacesCaptionPanel.setStyleName("bold");
|
||||
|
||||
VerticalPanel trackedRacesPanel = new VerticalPanel();
|
||||
trackedRacesPanel.setWidth("100%");
|
||||
trackedRacesCaptionPanel.setContentWidget(trackedRacesPanel);
|
||||
trackedRacesCaptionPanel.setStyleName("bold");
|
||||
|
||||
// text box for filtering the cell table
|
||||
HorizontalPanel filterPanel = new HorizontalPanel();
|
||||
filterPanel.setSpacing(5);
|
||||
racesPanel.add(filterPanel);
|
||||
|
||||
// Regatta
|
||||
// Regatta selection
|
||||
HorizontalPanel regattaPanel = new HorizontalPanel();
|
||||
regattaPanel.setSpacing(5);
|
||||
Label regattaForTrackingLabel = new Label(stringMessages.regattaUsedForTheTrackedRace());
|
||||
regattaForTrackingLabel.setWordWrap(false);
|
||||
regattaPanel.add(regattaForTrackingLabel);
|
||||
regattaPanel.add(getAvailableRegattasListBox());
|
||||
racesPanel.add(regattaPanel);
|
||||
trackableRacesPanel.add(regattaPanel);
|
||||
|
||||
Label lblTrackSettings = new Label(stringConstants.trackSettings());
|
||||
trackableRacesPanel.add(lblTrackSettings);
|
||||
|
||||
final CheckBox trackWindCheckbox = new CheckBox(stringConstants.trackWind());
|
||||
trackWindCheckbox.setWordWrap(false);
|
||||
trackWindCheckbox.setValue(true);
|
||||
trackableRacesPanel.add(trackWindCheckbox);
|
||||
|
||||
final CheckBox declinationCheckbox = new CheckBox(stringConstants.declinationCheckbox());
|
||||
declinationCheckbox.setWordWrap(false);
|
||||
declinationCheckbox.setValue(true);
|
||||
trackableRacesPanel.add(declinationCheckbox);
|
||||
|
||||
// text box for filtering the cell table
|
||||
HorizontalPanel filterPanel = new HorizontalPanel();
|
||||
filterPanel.setSpacing(5);
|
||||
trackableRacesPanel.add(filterPanel);
|
||||
|
||||
Label lblFilterEvents = new Label(stringConstants.filterRacesByName() + ":");
|
||||
filterPanel.add(lblFilterEvents);
|
||||
@@ -218,51 +235,32 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
fillRaceListFromAvailableRacesApplyingFilter(SwissTimingEventManagementPanel.this.filterEventsTextbox.getText());
|
||||
}
|
||||
});
|
||||
|
||||
filterPanel.add(filterEventsTextbox);
|
||||
|
||||
HorizontalPanel racesHorizontalPanel = new HorizontalPanel();
|
||||
racesPanel.add(racesHorizontalPanel);
|
||||
|
||||
VerticalPanel trackPanel = new VerticalPanel();
|
||||
trackPanel.setStyleName("paddedPanel");
|
||||
|
||||
raceNameColumn.setSortable(true);
|
||||
raceStartTrackingColumn.setSortable(true);
|
||||
raceStartTimeColumn.setSortable(true);
|
||||
|
||||
AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
|
||||
raceTable = new CellTable<SwissTimingRaceRecordDTO>(/* pageSize */ 10000, tableRes);
|
||||
raceTable.addColumn(raceNameColumn, stringConstants.name());
|
||||
raceTable.addColumn(raceDescriptionColumn, stringConstants.description());
|
||||
raceTable.addColumn(boatClassColumn, stringConstants.boatClass());
|
||||
raceTable.addColumn(raceStartTrackingColumn, stringConstants.raceStartTimeColumn());
|
||||
raceTable.addColumn(raceStateColumn, stringConstants.status());
|
||||
raceTable.addColumn(raceStartTimeColumn, stringConstants.startTime());
|
||||
raceTable.setWidth("300px");
|
||||
raceTable.setSelectionModel(new MultiSelectionModel<SwissTimingRaceRecordDTO>() {});
|
||||
|
||||
racesHorizontalPanel.add(raceTable);
|
||||
racesHorizontalPanel.add(trackPanel);
|
||||
trackableRacesPanel.add(raceTable);
|
||||
|
||||
raceList = new ListDataProvider<SwissTimingRaceRecordDTO>();
|
||||
raceList.addDataDisplay(raceTable);
|
||||
Handler columnSortHandler = getRaceTableColumnSortHandler(raceList.getList(), raceNameColumn, raceStartTrackingColumn);
|
||||
Handler columnSortHandler = getRaceTableColumnSortHandler(raceList.getList(), raceNameColumn, raceStartTimeColumn);
|
||||
raceTable.addColumnSortHandler(columnSortHandler);
|
||||
|
||||
Label lblTrackSettings = new Label(stringConstants.trackSettings());
|
||||
trackPanel.add(lblTrackSettings);
|
||||
|
||||
final CheckBox trackWindCheckbox = new CheckBox(stringConstants.trackWind());
|
||||
trackWindCheckbox.setWordWrap(false);
|
||||
trackWindCheckbox.setValue(true);
|
||||
trackPanel.add(trackWindCheckbox);
|
||||
|
||||
final CheckBox declinationCheckbox = new CheckBox(stringConstants.declinationCheckbox());
|
||||
declinationCheckbox.setWordWrap(false);
|
||||
declinationCheckbox.setValue(true);
|
||||
trackPanel.add(declinationCheckbox);
|
||||
trackedRacesPanel.add(trackedRacesListComposite);
|
||||
|
||||
HorizontalPanel racesButtonPanel = new HorizontalPanel();
|
||||
racesPanel.add(racesButtonPanel);
|
||||
trackableRacesPanel.add(racesButtonPanel);
|
||||
|
||||
Button btnTrack = new Button(stringConstants.startTracking());
|
||||
racesButtonPanel.add(btnTrack);
|
||||
@@ -273,7 +271,6 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
trackSelectedRaces(trackWindCheckbox.getValue(), declinationCheckbox.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private ListHandler<SwissTimingRaceRecordDTO> getRaceTableColumnSortHandler(List<SwissTimingRaceRecordDTO> raceRecords,
|
||||
|
||||
+13
-7
@@ -65,6 +65,7 @@ public class MediaSelector implements PlayStateListener, TimeListener,
|
||||
private StringMessages stringMessages;
|
||||
private final ErrorReporter errorReporter;
|
||||
private final UserDTO user;
|
||||
private boolean autoSelectMedia;
|
||||
|
||||
private MediaPlayer activeAudioPlayer;
|
||||
private Date currentRaceTime;
|
||||
@@ -73,7 +74,7 @@ public class MediaSelector implements PlayStateListener, TimeListener,
|
||||
|
||||
public MediaSelector(RegattaAndRaceIdentifier selectedRaceIdentifier, RaceTimesInfoProvider raceTimesInfoProvider,
|
||||
Timer raceTimer, MediaServiceAsync mediaService, StringMessages stringMessages,
|
||||
ErrorReporter errorReporter, UserDTO user) {
|
||||
ErrorReporter errorReporter, UserDTO user, boolean autoSelectMedia) {
|
||||
this.raceIdentifier = selectedRaceIdentifier;
|
||||
this.raceTimesInfoProvider = raceTimesInfoProvider;
|
||||
this.raceTimer = raceTimer;
|
||||
@@ -81,6 +82,7 @@ public class MediaSelector implements PlayStateListener, TimeListener,
|
||||
this.stringMessages = stringMessages;
|
||||
this.errorReporter = errorReporter;
|
||||
this.user = user;
|
||||
this.autoSelectMedia = autoSelectMedia;
|
||||
|
||||
Window.addCloseHandler(this);
|
||||
Window.addWindowClosingHandler(this);
|
||||
@@ -120,7 +122,6 @@ public class MediaSelector implements PlayStateListener, TimeListener,
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
setWidgetsVisible(false);
|
||||
|
||||
}
|
||||
@@ -249,12 +250,12 @@ public class MediaSelector implements PlayStateListener, TimeListener,
|
||||
}
|
||||
|
||||
private void startPlaying() {
|
||||
if (activeAudioPlayer != null) {
|
||||
if ((activeAudioPlayer != null) && activeAudioPlayer.isCoveringCurrentRaceTime()) {
|
||||
activeAudioPlayer.playMedia();
|
||||
}
|
||||
for (MediaPlayer player : videoPlayers.values()) {
|
||||
if (player.isMediaPaused()) {
|
||||
player.playMedia();
|
||||
for (MediaPlayer videoPlayer : videoPlayers.values()) {
|
||||
if (videoPlayer.isMediaPaused() && videoPlayer.isCoveringCurrentRaceTime()) {
|
||||
videoPlayer.playMedia();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,6 +287,11 @@ public class MediaSelector implements PlayStateListener, TimeListener,
|
||||
setStatus(mediaTrack);
|
||||
}
|
||||
setWidgetsVisible((this.mediaTracks.size() > 0) || (this.user != null));
|
||||
|
||||
toggleMediaButton.setValue(autoSelectMedia);
|
||||
if (autoSelectMedia) {
|
||||
playDefault();
|
||||
}
|
||||
}
|
||||
|
||||
private void setWidgetsVisible(boolean isVisible) {
|
||||
@@ -452,7 +458,7 @@ public class MediaSelector implements PlayStateListener, TimeListener,
|
||||
private void ensurePlayState(final MediaPlayer mediaPlayer) {
|
||||
switch (this.currentPlayState) {
|
||||
case Playing:
|
||||
if (mediaPlayer.isMediaPaused()) {
|
||||
if (mediaPlayer.isMediaPaused() && mediaPlayer.isCoveringCurrentRaceTime()) {
|
||||
mediaPlayer.playMedia();
|
||||
}
|
||||
break;
|
||||
|
||||
+7
-1
@@ -7,7 +7,7 @@ import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
|
||||
public abstract class AbstractMediaPlayer implements MediaPlayer {
|
||||
|
||||
private static final int TOLERATED_LAG_IN_MILLISECONDS = 2000;
|
||||
private static final int TOLERATED_LAG_IN_MILLISECONDS = 4000;
|
||||
private final MediaTrack mediaTrack;
|
||||
private long raceTimeInMillis;
|
||||
|
||||
@@ -37,6 +37,12 @@ public abstract class AbstractMediaPlayer implements MediaPlayer {
|
||||
return Math.round(getCurrentMediaTime() * 1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCoveringCurrentRaceTime() {
|
||||
double mediaTime = (raceTimeInMillis - mediaTrack.startTime.getTime()) / 1000d;
|
||||
return (mediaTime >= 0) && (mediaTime <= getDuration());
|
||||
}
|
||||
|
||||
protected void alignTime() {
|
||||
long mediaStartTimeInMillis = mediaTrack.startTime.getTime();
|
||||
long mediaTimeInMillis = mediaStartTimeInMillis + getCurrentMediaTimeMillis();
|
||||
|
||||
+2
@@ -31,4 +31,6 @@ public interface MediaPlayer {
|
||||
|
||||
void close();
|
||||
|
||||
boolean isCoveringCurrentRaceTime();
|
||||
|
||||
}
|
||||
+2
-1
@@ -82,8 +82,9 @@ public class RaceBoardEntryPoint extends AbstractEntryPoint {
|
||||
boolean showCompetitorsChart = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_COMPETITORSCHART, false /* default*/);
|
||||
String activeCompetitorsFilterSetName = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_VIEW_COMPETITOR_FILTER, null /* default*/);
|
||||
final boolean canReplayWhileLiveIsPossible = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_CAN_REPLAY_DURING_LIVE_RACES, false);
|
||||
final boolean autoSelectMedia = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_AUTOSELECT_MEDIA, false);
|
||||
raceboardViewConfig = new RaceBoardViewConfiguration(viewMode, activeCompetitorsFilterSetName, showLeaderboard,
|
||||
showWindChart, showCompetitorsChart, canReplayWhileLiveIsPossible);
|
||||
showWindChart, showCompetitorsChart, canReplayWhileLiveIsPossible, autoSelectMedia);
|
||||
|
||||
final ParallelExecutionCallback<List<String>> getLeaderboardNamesCallback = new ParallelExecutionCallback<List<String>>();
|
||||
final ParallelExecutionCallback<List<RegattaDTO>> getRegattasCallback = new ParallelExecutionCallback<List<RegattaDTO>>();
|
||||
|
||||
+1
-2
@@ -160,7 +160,6 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac
|
||||
|
||||
toolbarPanel = new FlowPanel();
|
||||
toolbarPanel.setWidth("100%");
|
||||
mainPanel.add(toolbarPanel);
|
||||
componentControlsPanel = new FlowPanel();
|
||||
componentControlsPanel.addStyleName("raceBoardNavigation");
|
||||
toolbarPanel.add(componentControlsPanel);
|
||||
@@ -277,7 +276,7 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac
|
||||
}
|
||||
|
||||
private void addMediaSelectorToNavigationMenu() {
|
||||
MediaSelector mediaSelector = new MediaSelector(selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, stringMessages, errorReporter, this.user);
|
||||
MediaSelector mediaSelector = new MediaSelector(selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, stringMessages, errorReporter, this.user, getConfiguration().isAutoSelectMedia());
|
||||
// raceTimesInfoProvider.addRaceTimesInfoProviderListener(mediaSelector);
|
||||
timer.addPlayStateListener(mediaSelector);
|
||||
timer.addTimeListener(mediaSelector);
|
||||
|
||||
+10
-1
@@ -12,6 +12,7 @@ public class RaceBoardViewConfiguration {
|
||||
private ViewModes viewMode;
|
||||
private String activeCompetitorsFilterSetName;
|
||||
private boolean canReplayDuringLiveRaces;
|
||||
private final boolean autoSelectMedia;
|
||||
|
||||
public static final String PARAM_VIEW_MODE = "viewMode";
|
||||
public static final String PARAM_VIEW_SHOW_LEADERBOARD = "viewShowLeaderboard";
|
||||
@@ -20,6 +21,7 @@ public class RaceBoardViewConfiguration {
|
||||
public static final String PARAM_VIEW_SHOW_COMPETITORSCHART = "viewShowCompetitorsChart";
|
||||
public static final String PARAM_VIEW_COMPETITOR_FILTER = "viewCompetitorFilter";
|
||||
public static final String PARAM_CAN_REPLAY_DURING_LIVE_RACES = "canReplayDuringLiveRaces";
|
||||
public static final String PARAM_AUTOSELECT_MEDIA = "autoSelectMedia";
|
||||
|
||||
public static enum ViewModes { ONESCREEN };
|
||||
|
||||
@@ -28,16 +30,18 @@ public class RaceBoardViewConfiguration {
|
||||
showLeaderboard = true;
|
||||
showWindChart = false;
|
||||
showCompetitorsChart = false;
|
||||
autoSelectMedia = false;
|
||||
}
|
||||
|
||||
public RaceBoardViewConfiguration(ViewModes viewMode, String activeCompetitorsFilterSetName,
|
||||
boolean showLeaderboard, boolean showWindChart, boolean showCompetitorsChart, boolean canReplayDuringLiveRaces) {
|
||||
boolean showLeaderboard, boolean showWindChart, boolean showCompetitorsChart, boolean canReplayDuringLiveRaces, boolean autoSelectMedia) {
|
||||
this.viewMode = viewMode;
|
||||
this.activeCompetitorsFilterSetName = activeCompetitorsFilterSetName;
|
||||
this.showLeaderboard = showLeaderboard;
|
||||
this.showWindChart = showWindChart;
|
||||
this.showCompetitorsChart = showCompetitorsChart;
|
||||
this.canReplayDuringLiveRaces = canReplayDuringLiveRaces;
|
||||
this.autoSelectMedia = autoSelectMedia;
|
||||
}
|
||||
|
||||
public boolean isShowLeaderboard() {
|
||||
@@ -63,4 +67,9 @@ public class RaceBoardViewConfiguration {
|
||||
public boolean isCanReplayDuringLiveRaces() {
|
||||
return canReplayDuringLiveRaces;
|
||||
}
|
||||
|
||||
public boolean isAutoSelectMedia() {
|
||||
return autoSelectMedia;
|
||||
}
|
||||
|
||||
}
|
||||
+16
-4
@@ -1250,13 +1250,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
GPSFixMoving fix = fixIter.next();
|
||||
while (fix != null && (fix.getTimePoint().compareTo(toTimePointExcluding) < 0 ||
|
||||
(fix.getTimePoint().equals(toTimePointExcluding) && toTimePointExcluding.equals(fromTimePoint)))) {
|
||||
Tack tack = trackedRace.getTack(competitor, fix.getTimePoint());
|
||||
Tack tack;
|
||||
try {
|
||||
tack = trackedRace.getTack(competitor, fix.getTimePoint());
|
||||
} catch (NoWindException nwe) {
|
||||
tack = null;
|
||||
}
|
||||
TrackedLegOfCompetitor trackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor,
|
||||
fix.getTimePoint());
|
||||
LegType legType = trackedLegOfCompetitor == null ? null : trackedRace.getTrackedLeg(
|
||||
trackedLegOfCompetitor.getLeg()).getLegType(fix.getTimePoint());
|
||||
Wind wind = trackedRace.getWind(fix.getPosition(),toTimePointExcluding);
|
||||
WindDTO windDTO = createWindDTOFromAlreadyAveraged(wind, toTimePointExcluding);
|
||||
WindDTO windDTO = wind == null ? null : createWindDTOFromAlreadyAveraged(wind, toTimePointExcluding);
|
||||
GPSFixDTO fixDTO = createGPSFixDTO(fix, fix.getSpeed(), windDTO, tack, legType, /* extrapolate */
|
||||
false);
|
||||
fixesForCompetitor.add(fixDTO);
|
||||
@@ -1266,13 +1271,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
// check if fix was at date and if extrapolation is requested
|
||||
if (!fix.getTimePoint().equals(toTimePointExcluding) && extrapolate) {
|
||||
Position position = track.getEstimatedPosition(toTimePointExcluding, extrapolate);
|
||||
Tack tack2 = trackedRace.getTack(competitor, toTimePointExcluding);
|
||||
Tack tack2;
|
||||
try {
|
||||
tack2 = trackedRace.getTack(competitor, toTimePointExcluding);
|
||||
} catch (NoWindException nwe) {
|
||||
tack2 = null;
|
||||
}
|
||||
LegType legType2 = trackedLegOfCompetitor == null ? null : trackedRace
|
||||
.getTrackedLeg(trackedLegOfCompetitor.getLeg()).getLegType(
|
||||
fix.getTimePoint());
|
||||
SpeedWithBearing speedWithBearing = track.getEstimatedSpeed(toTimePointExcluding);
|
||||
Wind wind2 = trackedRace.getWind(position, toTimePointExcluding);
|
||||
WindDTO windDTO2 = createWindDTOFromAlreadyAveraged(wind2, toTimePointExcluding);
|
||||
WindDTO windDTO2 = wind2 == null ? null : createWindDTOFromAlreadyAveraged(wind2, toTimePointExcluding);
|
||||
GPSFixDTO extrapolated = new GPSFixDTO(
|
||||
toPerCompetitorIdAsString.get(competitorDTO.getIdAsString()),
|
||||
position==null?null:new PositionDTO(position.getLatDeg(), position.getLngDeg()),
|
||||
@@ -2022,6 +2032,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
BoatClass boatClass = com.sap.sailing.domain.swisstimingadapter.DomainFactory.INSTANCE.getRaceTypeFromRaceID(rr.getRaceID()).getBoatClass();
|
||||
swissTimingRaceRecordDTO.boatClass = boatClass != null ? boatClass.getName() : null;
|
||||
swissTimingRaceRecordDTO.discipline = rr.getRaceID().length() >= 3 ? rr.getRaceID().substring(2, 3) : null;
|
||||
swissTimingRaceRecordDTO.hasCourse = rr.hasCourse();
|
||||
swissTimingRaceRecordDTO.hasStartlist = rr.hasStartlist();
|
||||
result.add(swissTimingRaceRecordDTO);
|
||||
}
|
||||
return result;
|
||||
|
||||
+3
@@ -13,6 +13,9 @@ public class SwissTimingRaceRecordDTO implements IsSerializable {
|
||||
public String boatClass;
|
||||
public String discipline;
|
||||
|
||||
public boolean hasCourse;
|
||||
public boolean hasStartlist;
|
||||
|
||||
public SwissTimingRaceRecordDTO() {}
|
||||
|
||||
public SwissTimingRaceRecordDTO(String id, String description, Date raceStartTime) {
|
||||
|
||||
+2
-1
@@ -43,8 +43,9 @@ public class TVEntryPoint extends AbstractEntryPoint {
|
||||
final boolean showCompetitorsChart = GwtHttpRequestUtils.getBooleanParameter(
|
||||
RaceBoardViewConfiguration.PARAM_VIEW_SHOW_COMPETITORSCHART, false /* default */);
|
||||
String activeCompetitorsFilterSetName = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_VIEW_COMPETITOR_FILTER, null /* default*/);
|
||||
final boolean autoSelectMedia = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_AUTOSELECT_MEDIA, false);
|
||||
raceboardViewConfig = new RaceBoardViewConfiguration(RaceBoardViewConfiguration.ViewModes.ONESCREEN,
|
||||
activeCompetitorsFilterSetName, showLeaderboard, showWindChart, showCompetitorsChart, /* canReplayWhileLiveIsPossible */ false);
|
||||
activeCompetitorsFilterSetName, showLeaderboard, showWindChart, showCompetitorsChart, /* canReplayWhileLiveIsPossible */ false, autoSelectMedia);
|
||||
|
||||
sailingService.getLeaderboardNames(new AsyncCallback<List<String>>() {
|
||||
@Override
|
||||
|
||||
@@ -17,9 +17,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
org.json.simple;bundle-version="1.1.0",
|
||||
com.sap.sailing.domain.swisstimingadapter,
|
||||
org.objenesis;bundle-version="1.3.0",
|
||||
org.junit4;bundle-version="4.8.2",
|
||||
org.hamcrest;bundle-version="1.1.0",
|
||||
org.mockito.mockito-core;bundle-version="1.9.5"
|
||||
Import-Package: com.sap.sailing.domain.common.impl,
|
||||
junit.framework;version="4.8.2",
|
||||
org.junit;version="4.8.2"
|
||||
Import-Package: com.sap.sailing.domain.common.impl
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ public class StoreAndLoadRaceLogsTest extends AbstractMongoDBTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testdLoadObsoleteAndNewIdentifier() {
|
||||
public void testLoadObsoleteAndNewIdentifier() {
|
||||
// event1 stored with obsolete identifier
|
||||
DBObject dbEvent1 = (DBObject) com.mongodb.util.JSON.parse(createOldFormatRaceLogEventJson(UUID.randomUUID()));
|
||||
mongoFactory.getRaceLogCollection().insert(dbEvent1);
|
||||
|
||||
Loaded 100 of 250 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user