Merge branch 'master' into polars

This commit is contained in:
Frederik Petersen committed 2013-10-01 10:19:58 +02:00
commit f15cd53ee4
251 files changed
+4771 -1660

No files matched your search

+37 -11
View File
@@ -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.
Binary file not shown.
Binary file not shown.
+5
View File
@@ -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
View File
@@ -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 -3
View File
@@ -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
+28
View File
@@ -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
@@ -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,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();
}
/**
@@ -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);
}
}
}
@@ -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;
}
@@ -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());
}
}
@@ -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);
}
@@ -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();
}
@@ -12,7 +12,7 @@ public class AbortingFlagFinder extends RaceLogAnalyzer<RaceLogFlagEvent> {
}
@Override
protected RaceLogFlagEvent performAnalyzation() {
protected RaceLogFlagEvent performAnalysis() {
if (raceLog.getCurrentPassId() <= RaceLog.DefaultPassId) {
return null;
}
@@ -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();
}
}
@@ -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();
}
}
@@ -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;
@@ -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;
@@ -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();
@@ -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;
@@ -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);
@@ -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;
@@ -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;
@@ -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();
@@ -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();
@@ -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()) {
@@ -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();
@@ -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;
@@ -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;
@@ -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();
@@ -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) {
@@ -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;
}
@@ -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) {
@@ -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
@@ -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";
@@ -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;
}
}
@@ -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"
@@ -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;
}
}
@@ -21,4 +21,8 @@ public interface RaceSpecificMessageLoader {
Iterable<Race> getRaces();
Race getRace(String raceID);
boolean hasRaceStartlist(String raceID);
boolean hasRaceCourse(String raceID);
}
@@ -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;
@@ -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;
@@ -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) {
@@ -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"
@@ -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
@@ -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;
@@ -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);
@@ -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
@@ -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
* 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
@@ -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());
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");
}
}
}
@@ -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()) {
@@ -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();
}
@@ -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);
/**
@@ -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);
/**
@@ -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) {
@@ -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--;
@@ -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)));
}
@@ -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");
@@ -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);
}
@@ -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;
}
}
@@ -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<>();
@@ -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;
@@ -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() {
@@ -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();
}
@@ -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;
@@ -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>
+23 -33
View File
@@ -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
+1 -1
View File
@@ -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,
+1
View File
@@ -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>
@@ -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);
@@ -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,
@@ -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,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();
@@ -31,4 +31,6 @@ public interface MediaPlayer {
void close();
boolean isCoveringCurrentRaceTime();
}
@@ -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>>();
@@ -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);
@@ -181,7 +180,7 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac
}
CompetitorsFilterSets loadedCompetitorsFilterSets = loadCompetitorsFilterSets();
if(loadedCompetitorsFilterSets != null) {
if (loadedCompetitorsFilterSets != null) {
competitorsFilterSets = loadedCompetitorsFilterSets;
insertSelectedCompetitorsFilter(competitorsFilterSets);
} else {
@@ -190,9 +189,9 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac
}
// in case the URL configuration contains the name of a competitors filter set we try to activate it
if(raceboardViewConfiguration.getActiveCompetitorsFilterSetName() != null) {
for(FilterSet<CompetitorDTO, FilterWithUI<CompetitorDTO>> filterSet: competitorsFilterSets.getFilterSets()) {
if(filterSet.getName().equals(raceboardViewConfiguration.getActiveCompetitorsFilterSetName())) {
if (raceboardViewConfiguration.getActiveCompetitorsFilterSetName() != null) {
for (FilterSet<CompetitorDTO, FilterWithUI<CompetitorDTO>> filterSet: competitorsFilterSets.getFilterSets()) {
if (filterSet.getName().equals(raceboardViewConfiguration.getActiveCompetitorsFilterSetName())) {
competitorsFilterSets.setActiveFilterSet(filterSet);
break;
}
@@ -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);
@@ -461,7 +460,7 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac
private <SettingsType> void addComponentToNavigationMenu(final ComponentViewer componentViewer,
final Component<SettingsType> component, boolean isToogleCheckboxEnabled) {
final CheckBox checkBox= new CheckBox(component.getLocalizedShortName());
final CheckBox checkBox = new CheckBox(component.getLocalizedShortName());
checkBox.getElement().getStyle().setFloat(Style.Float.LEFT);
checkBox.setEnabled(isToogleCheckboxEnabled);
@@ -489,7 +488,7 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac
componentControlsPanel.add(checkBox);
if(component.hasSettings()) {
if (component.hasSettings()) {
Button settingsButton = new Button("");
settingsButton.addClickHandler(new ClickHandler() {
@Override
@@ -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;
}
}
@@ -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;
@@ -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) {
@@ -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
@@ -169,7 +169,7 @@ public class TVViewController implements RaceTimesInfoProviderListener {
ScrollPanel leaderboardContentPanel = new ScrollPanel();
leaderboardContentPanel.add(leaderboardPanel);
dockPanel.add(leaderboardContentPanel);
if(logoAndTitlePanel != null) {
if (logoAndTitlePanel != null) {
logoAndTitlePanel.setSubTitle(leaderboardName);
}
currentLiveRace = null;
@@ -180,7 +180,7 @@ public class TVViewController implements RaceTimesInfoProviderListener {
}
private void showRaceBoard() {
if(activeTvView != TVViews.Raceboard) {
if (activeTvView != TVViews.Raceboard) {
clearContentPanels();
RaceBoardPanel raceBoardPanel = createRaceBoardPanel(leaderboardName, currentLiveRace);
raceBoardPanel.setSize("100%", "100%");
@@ -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
Loaded 100 of 251 files, more files were not shown because too many files have changed in this diff. Show more