Merge remote-tracking branch 'origin/master' into leaderboardView2

This commit is contained in:
fmittag committed 2013-10-01 14:15:30 +02:00
commit 744eb458ab
95 files changed
+1415 -620

No files matched your search

+80 -37
View File
@@ -61,16 +61,19 @@ HAS_OVERWRITTEN_TARGET=0
TARGET_SERVER_NAME=$active_branch
gwtcompile=1
onegwtpermutationonly=0
testing=1
clean="clean"
offline=0
proxy=0
no_confirmation=1
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 -u -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)"
@@ -81,10 +84,11 @@ if [ $# -eq 0 ]; then
echo "-l <telnet port> Telnet port the OSGi server is running. Optional but enables fully automatic hot-deploy."
echo "-s <target server> Name of server you want to use as target for install, hot-deploy or remote-reploy. This overrides default behaviour."
echo "-w <ssh target> Target for remote-deploy. Must comply with the following format: user@server."
echo "-u Run without confirmation messages. Use with extreme care."
echo ""
echo "build: builds the server code using Maven to $PROJECT_HOME (log to $START_DIR/build.log)"
echo "install: installs product and configuration to $SERVERS_HOME/$active_branch. Overwrites any configuration by using config from branch."
echo "all: calls build and then install"
echo "all: invokes build and then install"
echo ""
echo "hot-deploy: performs hot deployment of named bundle into OSGi server"
echo "Example: $0 -n com.sap.sailing.www -l 14888 hot-deploy"
@@ -104,12 +108,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:u'
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;;
@@ -119,6 +124,7 @@ do
s) TARGET_SERVER_NAME=$OPTARG
HAS_OVERWRITTEN_TARGET=1;;
w) REMOTE_SERVER_LOGIN=$OPTARG;;
u) no_confirmation=1;;
\?) echo "Invalid option"
exit 4;;
esac
@@ -179,12 +185,14 @@ if [[ "$@" == "hot-deploy" ]]; then
echo "WARNING: Bundle versions do not differ. Update not needed."
fi
read -s -n1 -p "Do you really want to hot-deploy bundle $OSGI_BUNDLE_NAME to $SERVERS_HOME/$active_branch? (y/N): " answer
case $answer in
"Y" | "y") echo "Continuing";;
*) echo "Aborting..."
exit;;
esac
if [ $no_confirmation -eq 0 ]; then
read -s -n1 -p "Do you really want to hot-deploy bundle $OSGI_BUNDLE_NAME to $SERVERS_HOME/$active_branch? (y/N): " answer
case $answer in
"Y" | "y") echo "Continuing";;
*) echo "Aborting..."
exit;;
esac
fi
# deploy new bundle physically
mkdir -p $SERVERS_HOME/$active_branch/plugins/deploy
@@ -223,12 +231,15 @@ if [[ "$@" == "hot-deploy" ]]; then
BUNDLE_ID=`echo $OLD_BUNDLE_INFORMATION | cut -d " " -f 1`
OLD_ACTIVATED_NAME=`echo $OLD_BUNDLE_INFORMATION | cut -d " " -f 3`
echo "Could identify bundle-id $BUNDLE_ID for $OLD_ACTIVATED_NAME"
read -s -n1 -p "I will now stop and reinstall the bundle mentioned in the line above. Is this right? (y/N): " answer
case $answer in
"Y" | "y") echo "Continuing";;
*) echo "Aborting..."
exit;;
esac
if [ $no_confirmation -eq 0 ]; then
read -s -n1 -p "I will now stop and reinstall the bundle mentioned in the line above. Is this right? (y/N): " answer
case $answer in
"Y" | "y") echo "Continuing";;
*) echo "Aborting..."
exit;;
esac
fi
# stop and uninstall
echo -n stop $BUNDLE_ID | $NC_CMD > /dev/null
@@ -270,6 +281,24 @@ 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
echo "INFO: Patching $i files such that only one GWT permutation needs to be compiled"
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
echo "INFO: Patching $i files such that all GWT permutations are compiled"
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,17 +327,27 @@ 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
echo "INFO: restoring backup copies of .gwt.xml files after they has been patched before"
for i in com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/*.gwt.xml; do
mv -v $i.bak $i
done
fi
echo "Build complete. Do not forget to install product..."
fi
if [[ "$@" == "install" ]] || [[ "$@" == "all" ]]; then
read -s -n1 -p "Currently branch $active_branch is active and I will deploy to $ACDIR. Do you want to proceed with $@ (y/N): " answer
case $answer in
"Y" | "y") echo "Continuing";;
*) echo "Aborting..."
exit;;
esac
if [ $no_confirmation -eq 0 ]; then
read -s -n1 -p "Currently branch $active_branch is active and I will deploy to $ACDIR. Do you want to proceed with $@ (y/N): " answer
case $answer in
"Y" | "y") echo "Continuing";;
*) echo "Aborting..."
exit;;
esac
fi
if [ ! -d $ACDIR ]; then
echo "Could not find directory $ACDIR - perhaps you are on a wrong branch?"
@@ -427,12 +466,14 @@ if [[ "$@" == "remote-deploy" ]]; then
REMOTE_HOME=`ssh $REMOTE_SERVER_LOGIN 'echo $HOME/servers'`
REMOTE_SERVER="$REMOTE_HOME/$SERVER"
read -s -n1 -p "I will deploy the current GIT branch to $REMOTE_SERVER_LOGIN:$REMOTE_SERVER. Is this correct (y/n)? " answer
case $answer in
"Y" | "y") OK=1;;
*) echo "Aborting... nothing has been changed on remote server!"
exit;;
esac
if [ $no_confirmation -eq 0 ]; then
read -s -n1 -p "I will deploy the current GIT branch to $REMOTE_SERVER_LOGIN:$REMOTE_SERVER. Is this correct (y/n)? " answer
case $answer in
"Y" | "y") OK=1;;
*) echo "Aborting... nothing has been changed on remote server!"
exit;;
esac
fi
$SSH_CMD "test -d $REMOTE_SERVER/plugins"
if [[ $? -eq 1 ]]; then
@@ -474,18 +515,20 @@ if [[ "$@" == "remote-deploy" ]]; then
echo "Deployed successfully. I did NOT change any configuration (no env.sh or config.ini or jetty.xml adaption), only code!"
read -s -n1 -p "Do you want me to restart the remote server (y/n)? " answer
case $answer in
"Y" | "y") OK=1;;
*) echo "Aborting... deployment should be ready by now!"
exit;;
esac
if [ $no_confirmation -eq 0 ]; then
read -s -n1 -p "Do you want me to restart the remote server (y/n)? " answer
case $answer in
"Y" | "y") OK=1;;
*) echo "Aborting... deployment should be ready by now!"
exit;;
esac
echo ""
$SSH_CMD "cd $REMOTE_SERVER && bash -l -c $REMOTE_SERVER/stop"
$SSH_CMD "cd $REMOTE_SERVER && bash -l -c $REMOTE_SERVER/start"
echo ""
$SSH_CMD "cd $REMOTE_SERVER && bash -l -c $REMOTE_SERVER/stop"
$SSH_CMD "cd $REMOTE_SERVER && bash -l -c $REMOTE_SERVER/start"
echo "Restarted remote server. Please check."
echo "Restarted remote server. Please check."
fi
fi
if [[ "$@" == "deploy-startpage" ]]; then
Binary file not shown.
Binary file not shown.
@@ -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>();
@@ -1025,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;
}
@@ -88,6 +88,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) {
@@ -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"
@@ -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
@@ -526,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() {
@@ -551,6 +553,11 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
// 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);
@@ -560,10 +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) {
// can't update a race status once it has been set to FINISHED
if (lastStatus != null && trackedRace.getStatus() != null && trackedRace.getStatus().getStatus() != TrackedRaceStatusEnum.FINISHED) {
trackedRace.setStatus(lastStatus);
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);
}
}
@@ -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);
/**
@@ -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;
/**
@@ -57,8 +60,11 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
private TimePoint timePointOfLastCorrectionsValidity;
private transient Set<ScoreCorrectionListener> scoreCorrectionListeners;
private final Leaderboard leaderboard;
public ScoreCorrectionImpl() {
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
@@ -145,31 +152,199 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
Double oldScore = correctedScores.remove(raceColumn.getKey(competitor));
notifyListeners(competitor, raceColumn, oldScore, null);
}
/**
* 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;
}
/**
* 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) {
public MaxPointsReason getMaxPointsReason(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
MaxPointsReason result = maxPointsReasons.get(raceColumn.getKey(competitor));
if (result == null) {
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)} for the <code>competitor</code> for the
* 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
@@ -43,11 +40,16 @@ public class MetaLeaderboardScoreCorrection extends ScoreCorrectionImpl {
MaxPointsReason newMaxPointsReason) {
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());
}
}
+2 -1
View File
@@ -48,7 +48,8 @@
<!-- GWT version detected from dependencyManagement -->
<execution>
<configuration>
<extraJvmArgs>-Dgwt.persistentunitcache=false</extraJvmArgs>
<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>
@@ -224,7 +224,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
trackedRegatta[0] = new DynamicTrackedRegattaImpl(loadedRegatta);
resForLoading.apply(new ConnectTrackedRaceToLeaderboardColumn(loadedLeaderboard.getName(), loadedQ2.getName(), loadedYellow
.getName(), q2YellowTrackedRace.getRaceIdentifier()));
MaxPointsReason hassosLoadedMaxPointsReason = loadedLeaderboard.getScoreCorrection().getMaxPointsReason(hasso, loadedQ2);
MaxPointsReason hassosLoadedMaxPointsReason = loadedLeaderboard.getScoreCorrection().getMaxPointsReason(hasso, loadedQ2, MillisecondsTimePoint.now());
assertEquals(MaxPointsReason.DNF, hassosLoadedMaxPointsReason);
}
@@ -40,7 +40,6 @@ import com.sap.sailing.domain.leaderboard.impl.HighPointExtremeSailingSeriesOver
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
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.leaderboard.meta.LeaderboardGroupMetaLeaderboard;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
@@ -76,17 +75,17 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String groupDescription = "A leaderboard group";
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
final LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl(groupName, groupDescription, false, leaderboards);
@@ -124,19 +123,19 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String groupName = "Leaderboard Group";
final String groupDescription = "A leaderboard group";
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
racingEventService.addLeaderboard(leaderboard);
leaderboard.addRace(raceWithTwoCompetitors, raceColumnName1, /* medalRace */ false,
leaderboard.getFleet(null));
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
racingEventService.addLeaderboard(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
racingEventService.addLeaderboard(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
racingEventService.addLeaderboard(leaderboard);
LeaderboardGroup leaderboardGroup = racingEventService.addLeaderboardGroup(groupName, groupDescription, false, Arrays.asList(leaderboardNames), new int[0],
@@ -181,19 +180,19 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String groupDescription = "A leaderboard group";
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard.addRace(raceWithTwoCompetitors, raceColumnName1, /* medalRace */ false,
leaderboard.getFleet(null));
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
final LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl(groupName, groupDescription, false, leaderboards);
@@ -238,19 +237,19 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String groupDescription = "A leaderboard group";
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard.addRace(raceWithTwoCompetitors, raceColumnName1, /* medalRace */ false,
leaderboard.getFleet(null));
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
final LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl(groupName, groupDescription, false, leaderboards);
@@ -286,14 +285,14 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String groupName1 = "Leaderboard Group 1";
final String groupDescription1 = "A leaderboard group 1";
final ArrayList<Leaderboard> leaderboards1 = new ArrayList<>();
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards1.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards1.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards1.add(leaderboard);
final LeaderboardGroup leaderboardGroup1 = new LeaderboardGroupImpl(groupName1, groupDescription1, false, leaderboards1);
mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup1);
@@ -301,11 +300,11 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String groupName2 = "Leaderboard Group 2";
final String groupDescription2= "A leaderboard group 2";
final ArrayList<Leaderboard> leaderboards2 = new ArrayList<>();
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards2.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards2.add(leaderboard);
final LeaderboardGroup leaderboardGroup2 = new LeaderboardGroupImpl(groupName2, groupDescription2, false, leaderboards2);
mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup2);
@@ -331,17 +330,17 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String groupDescription = "A leaderboard group";
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
final LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl(groupName, groupDescription, false, leaderboards);
@@ -369,11 +368,11 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String groupDescription = "A leaderboard group";
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboards.add(leaderboard);
final LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl(groupName, groupDescription, false, leaderboards);
@@ -382,12 +381,12 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String[] ungroupedLeaderboardNames = {"Ungrouped Leaderboard 0", "Ungrouped Leaderboard 1", "Ungrouped Leaderboard 2"};
final FlexibleLeaderboard[] ungroupedLeaderboards = {
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[0], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null),
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[1], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null),
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[2], new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null) };
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[0], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null),
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[1], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null),
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[2], new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null) };
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[0]);
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[1]);
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[2]);
@@ -424,7 +423,7 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String groupDescription = "A leaderboard group";
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
final FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(), new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
final FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
final Fleet fleet = leaderboard.getFleet(null);
final RaceColumn race = leaderboard.addRaceColumn(columnName, false, fleet);
leaderboards.add(leaderboard);
@@ -26,13 +26,11 @@ import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.HighPoint;
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.persistence.impl.DomainObjectFactoryImpl;
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithFixedRank;
@@ -48,8 +46,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
public void testStoreAndRetrieveSimpleLeaderboardWithSpecificColumnFactors() {
final String leaderboardName = "TestLeaderboard";
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboard.addRaceColumn("R1", /* medalRace */ false);
RaceColumn r2 = leaderboard.addRaceColumn("R2", /* medalRace */ false);
r2.setFactor(1.5);
@@ -66,8 +64,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
public void testStoreAndRetrieveLeaderboardWithSuppressedCompetitors() {
final String leaderboardName = "TestLeaderboard";
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
Competitor wolfgang = createCompetitor();
Competitor hasso = new CompetitorImpl(234, "Hasso Plattner", new TeamImpl("STG", Collections.singleton(
new PersonImpl("Hasso Plattner", new NationalityImpl("GER"),
@@ -94,12 +92,11 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
public void testStoreAndRetrieveLeaderboardWithCommentedScoreCorrection() {
final String leaderboardName = "TestLeaderboard";
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
SettableScoreCorrection scoreCorrection = new ScoreCorrectionImpl();
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, scoreCorrection,
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
scoreCorrection.setComment("Humba");
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
leaderboard.getScoreCorrection().setComment("Humba");
MillisecondsTimePoint now = MillisecondsTimePoint.now();
scoreCorrection.setTimePointOfLastCorrectionsValidity(now);
leaderboard.getScoreCorrection().setTimePointOfLastCorrectionsValidity(now);
new MongoObjectFactoryImpl(db).storeLeaderboard(leaderboard);
Leaderboard loadedLeaderboard = new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName, /* regattaRegistry */ null);
assertEquals("Humba", loadedLeaderboard.getScoreCorrection().getComment());
@@ -110,9 +107,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
public void testStoreAndRetrieveLeaderboardWithDisplayNameSet() {
final String leaderboardName = "TestLeaderboard";
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
SettableScoreCorrection scoreCorrection = new ScoreCorrectionImpl();
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, scoreCorrection,
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
Competitor competitor = createCompetitor();
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
final String raceColumnName1 = "My First Race 1";
@@ -132,8 +128,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
public void testStoreAndRetrieveSimpleLeaderboard() {
final String leaderboardName = "TestLeaderboard";
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
new MongoObjectFactoryImpl(db).storeLeaderboard(leaderboard);
Leaderboard loadedLeaderboard = new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName, /* regattaRegistry */ null);
assertEquals(leaderboardName, loadedLeaderboard.getName());
@@ -145,8 +141,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
public void testStoreAndRetrieveSimpleLeaderboardWithHighPointScoringScheme() {
final String leaderboardName = "TestLeaderboard";
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new HighPoint(), null);
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new HighPoint(), null);
new MongoObjectFactoryImpl(db).storeLeaderboard(leaderboard);
Leaderboard loadedLeaderboard = new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName, /* regattaRegistry */ null);
assertSame(HighPoint.class, loadedLeaderboard.getScoringScheme().getClass());
@@ -159,8 +155,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final String raceColumnName = "My First Race";
final double carriedPointsForWolfgangHunger = 3.7;
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
Competitor competitor = createCompetitor();
TrackedRace raceWithOneCompetitor = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
leaderboard.addRace(raceWithOneCompetitor, raceColumnName, /* medalRace */ false, leaderboard.getFleet(null));
@@ -184,8 +180,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final String raceColumnName2 = "My First Race 2";
final double correctedPoints = 2.75;
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
Competitor competitor = createCompetitor();
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
@@ -200,9 +196,9 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
RaceColumn loadedColumn2 = loadedLeaderboard.addRace(raceWithOneCompetitor2, raceColumnName2, /* medalRace, ignored */ false,
leaderboard.getFleet(null));
assertEquals(leaderboardName, loadedLeaderboard.getName());
assertTrue(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn1));
assertTrue(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn1, MillisecondsTimePoint.now()));
assertEquals(correctedPoints, (double) loadedLeaderboard.getScoreCorrection().getExplicitScoreCorrection(competitor, loadedColumn1), 0.00000001);
assertFalse(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn2));
assertFalse(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn2, MillisecondsTimePoint.now()));
}
@Test
@@ -212,8 +208,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final String raceColumnName2 = "My.First$Race$2";
final double correctedPoints = 2.75;
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
Competitor competitor = createCompetitor();
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
@@ -226,9 +222,9 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
RaceColumn loadedColumn1 = loadedLeaderboard.addRace(raceWithOneCompetitor1, raceColumnName1, /* medalRace, ignored */ false, leaderboard.getFleet(null));
RaceColumn loadedColumn2 = loadedLeaderboard.addRace(raceWithOneCompetitor2, raceColumnName2, /* medalRace, ignored */ false, leaderboard.getFleet(null));
assertEquals(leaderboardName, loadedLeaderboard.getName());
assertTrue(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn1));
assertTrue(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn1, MillisecondsTimePoint.now()));
assertEquals(correctedPoints, (double) loadedLeaderboard.getScoreCorrection().getExplicitScoreCorrection(competitor, loadedColumn1), 0.00000001);
assertFalse(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn2));
assertFalse(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn2, MillisecondsTimePoint.now()));
}
@Test
@@ -238,8 +234,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final String raceColumnName2 = "My First Race 2";
final MaxPointsReason maxPointsReason = MaxPointsReason.DNF;
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
Competitor competitor = createCompetitor();
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
@@ -254,9 +250,9 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
RaceColumn loadedColumn2 = loadedLeaderboard.addRace(raceWithOneCompetitor2, raceColumnName2, /* medalRace, ignored */ false,
leaderboard.getFleet(null));
assertEquals(leaderboardName, loadedLeaderboard.getName());
assertFalse(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn1));
assertTrue(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn2));
assertEquals(maxPointsReason, loadedLeaderboard.getScoreCorrection().getMaxPointsReason(competitor, loadedColumn2));
assertFalse(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn1, MillisecondsTimePoint.now()));
assertTrue(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn2, MillisecondsTimePoint.now()));
assertEquals(maxPointsReason, loadedLeaderboard.getScoreCorrection().getMaxPointsReason(competitor, loadedColumn2, MillisecondsTimePoint.now()));
}
@Test
@@ -267,8 +263,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final double correctedPoints = 2.55;
final MaxPointsReason maxPointsReason = MaxPointsReason.DNF;
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
Competitor competitor = createCompetitor();
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
@@ -286,10 +282,10 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
RaceColumn loadedColumn2 = loadedLeaderboard.addRace(raceWithOneCompetitor2, raceColumnName2, /* medalRace, ignored */ false,
leaderboard.getFleet(null));
assertEquals(leaderboardName, loadedLeaderboard.getName());
assertTrue(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn1));
assertTrue(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn1, MillisecondsTimePoint.now()));
assertEquals(correctedPoints, (double) loadedLeaderboard.getScoreCorrection().getExplicitScoreCorrection(competitor, loadedColumn1), 0.000000001);
assertTrue(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn2));
assertEquals(maxPointsReason, loadedLeaderboard.getScoreCorrection().getMaxPointsReason(competitor, loadedColumn2));
assertTrue(loadedLeaderboard.getScoreCorrection().isScoreCorrected(competitor, loadedColumn2, MillisecondsTimePoint.now()));
assertEquals(maxPointsReason, loadedLeaderboard.getScoreCorrection().getMaxPointsReason(competitor, loadedColumn2, MillisecondsTimePoint.now()));
}
private Competitor createCompetitor() {
@@ -32,7 +32,6 @@ import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard;
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.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
import com.sap.sailing.domain.persistence.MongoFactory;
import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
@@ -77,8 +76,8 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD
RaceLogStore raceLogStore = MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore(mongoObjectFactory, domainObjectFactory);
leaderboard = new FlexibleLeaderboardImpl(raceLogStore, leaderboardName, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowPoint(), null);
leaderboard = new FlexibleLeaderboardImpl(raceLogStore, leaderboardName, new ThresholdBasedResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces),
new LowPoint(), null);
Fleet defaultFleet = leaderboard.getFleet(null);
leaderboard.addRaceColumn(raceColumnName, /* medalRace */ false, defaultFleet);
@@ -248,8 +247,8 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD
assertEquals(now, loadedConfirmedEvent.getTimePoint());
assertEquals(0, loadedConfirmedEvent.getPassId());
assertEquals(0, loadedConfirmedEvent.getInvolvedBoats().size());
assertNull(event.getPositionedCompetitors());
assertNull(loadedConfirmedEvent.getPositionedCompetitors());
assertNull(event.getPositionedCompetitorsIDsNamesMaxPointsReasons());
assertNull(loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons());
assertEquals(1, Util.size(loadedRaceLog.getFixes()));
} finally {
loadedRaceLog.unlockAfterRead();
@@ -297,10 +296,10 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD
assertEquals(event.getPassId(), loadedPositioningEvent.getPassId());
assertEquals(event.getId(), loadedPositioningEvent.getId());
assertEquals(event.getInvolvedBoats().size(), loadedPositioningEvent.getInvolvedBoats().size());
assertEquals(event.getPositionedCompetitors().size(), loadedPositioningEvent.getPositionedCompetitors().size());
assertEquals(event.getPositionedCompetitors().get(0).getA(), loadedPositioningEvent.getPositionedCompetitors().get(0).getA());
assertEquals(event.getPositionedCompetitors().get(0).getB(), loadedPositioningEvent.getPositionedCompetitors().get(0).getB());
assertEquals(event.getPositionedCompetitors().get(0).getC().name(), loadedPositioningEvent.getPositionedCompetitors().get(0).getC().name());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().size(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name());
assertEquals(1, Util.size(loadedRaceLog.getFixes()));
} finally {
loadedRaceLog.unlockAfterRead();
@@ -259,10 +259,10 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends RaceLogMongoDBTest
assertEquals(event.getPassId(), loadedPositioningEvent.getPassId());
assertEquals(event.getId(), loadedPositioningEvent.getId());
assertEquals(event.getInvolvedBoats().size(), loadedPositioningEvent.getInvolvedBoats().size());
assertEquals(event.getPositionedCompetitors().size(), loadedPositioningEvent.getPositionedCompetitors().size());
assertEquals(event.getPositionedCompetitors().get(0).getA(), loadedPositioningEvent.getPositionedCompetitors().get(0).getA());
assertEquals(event.getPositionedCompetitors().get(0).getB(), loadedPositioningEvent.getPositionedCompetitors().get(0).getB());
assertEquals(event.getPositionedCompetitors().get(0).getC().name(), loadedPositioningEvent.getPositionedCompetitors().get(0).getC().name());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().size(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name(), loadedPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name());
assertEquals(1, Util.size(loadedRaceLog.getFixes()));
} finally {
loadedRaceLog.unlockAfterRead();
@@ -289,10 +289,10 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends RaceLogMongoDBTest
assertEquals(event.getPassId(), loadedConfirmedEvent.getPassId());
assertEquals(event.getId(), loadedConfirmedEvent.getId());
assertEquals(event.getInvolvedBoats().size(), loadedConfirmedEvent.getInvolvedBoats().size());
assertEquals(event.getPositionedCompetitors().size(), loadedConfirmedEvent.getPositionedCompetitors().size());
assertEquals(event.getPositionedCompetitors().get(0).getA(), loadedConfirmedEvent.getPositionedCompetitors().get(0).getA());
assertEquals(event.getPositionedCompetitors().get(0).getB(), loadedConfirmedEvent.getPositionedCompetitors().get(0).getB());
assertEquals(event.getPositionedCompetitors().get(0).getC().name(), loadedConfirmedEvent.getPositionedCompetitors().get(0).getC().name());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().size(), loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA(), loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB(), loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name(), loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC().name());
assertEquals(1, Util.size(loadedRaceLog.getFixes()));
} finally {
loadedRaceLog.unlockAfterRead();
@@ -314,8 +314,8 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends RaceLogMongoDBTest
assertEquals(now, loadedConfirmedEvent.getTimePoint());
assertEquals(0, loadedConfirmedEvent.getPassId());
assertEquals(0, loadedConfirmedEvent.getInvolvedBoats().size());
assertNull(event.getPositionedCompetitors());
assertNull(loadedConfirmedEvent.getPositionedCompetitors());
assertNull(event.getPositionedCompetitorsIDsNamesMaxPointsReasons());
assertNull(loadedConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons());
assertEquals(1, Util.size(loadedRaceLog.getFixes()));
} finally {
loadedRaceLog.unlockAfterRead();
@@ -64,15 +64,15 @@ public class RaceLogFinishPositioningConfirmedEventSerializerTest {
assertEquals(event.getTimePoint(), deserializedEvent.getTimePoint());
assertEquals(0, Util.size(event.getInvolvedBoats()));
assertEquals(0, Util.size(deserializedEvent.getInvolvedBoats()));
assertNotNull(event.getPositionedCompetitors());
assertNotNull(deserializedEvent.getPositionedCompetitors());
assertEquals(1, event.getPositionedCompetitors().size());
assertEquals(1, deserializedEvent.getPositionedCompetitors().size());
assertEquals(event.getPositionedCompetitors().get(0).getA(), deserializedEvent.getPositionedCompetitors()
assertNotNull(event.getPositionedCompetitorsIDsNamesMaxPointsReasons());
assertNotNull(deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons());
assertEquals(1, event.getPositionedCompetitorsIDsNamesMaxPointsReasons().size());
assertEquals(1, deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size());
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getA(), deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()
.get(0).getA());
assertEquals(event.getPositionedCompetitors().get(0).getB(), deserializedEvent.getPositionedCompetitors()
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getB(), deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()
.get(0).getB());
assertEquals(event.getPositionedCompetitors().get(0).getC(), deserializedEvent.getPositionedCompetitors()
assertEquals(event.getPositionedCompetitorsIDsNamesMaxPointsReasons().get(0).getC(), deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()
.get(0).getC());
}
@@ -89,9 +89,9 @@ public class RaceLogFinishPositioningConfirmedEventSerializerTest {
assertEquals(event.getTimePoint(), deserializedEvent.getTimePoint());
assertEquals(0, Util.size(event.getInvolvedBoats()));
assertEquals(0, Util.size(deserializedEvent.getInvolvedBoats()));
assertNull(event.getPositionedCompetitors());
assertNotNull(deserializedEvent.getPositionedCompetitors());
assertEquals(0, deserializedEvent.getPositionedCompetitors().size());
assertNull(event.getPositionedCompetitorsIDsNamesMaxPointsReasons());
assertNotNull(deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons());
assertEquals(0, deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size());
}
@Test
@@ -107,10 +107,10 @@ public class RaceLogFinishPositioningConfirmedEventSerializerTest {
assertEquals(event.getTimePoint(), deserializedEvent.getTimePoint());
assertEquals(0, Util.size(event.getInvolvedBoats()));
assertEquals(0, Util.size(deserializedEvent.getInvolvedBoats()));
assertNotNull(event.getPositionedCompetitors());
assertNotNull(deserializedEvent.getPositionedCompetitors());
assertEquals(0, event.getPositionedCompetitors().size());
assertEquals(0, deserializedEvent.getPositionedCompetitors().size());
assertNotNull(event.getPositionedCompetitorsIDsNamesMaxPointsReasons());
assertNotNull(deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons());
assertEquals(0, event.getPositionedCompetitorsIDsNamesMaxPointsReasons().size());
assertEquals(0, deserializedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons().size());
}
}
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.base.CourseArea;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
@@ -272,12 +273,14 @@ public class LeaderboardMasterDataJsonSerializer implements JsonSerializer<Leade
RaceColumn raceColumn, Leaderboard leaderboard) {
JSONArray scoreCorrectionsForCompetitors = new JSONArray();
for (Competitor competitor : leaderboard.getAllCompetitors()) {
if (correction.isScoreCorrected(competitor, raceColumn)) {
// TODO bug 655: score corrections shall be time dependent
final MillisecondsTimePoint now = MillisecondsTimePoint.now();
if (correction.isScoreCorrected(competitor, raceColumn, now)) {
JSONObject scoreCorrectionForCompetitor = new JSONObject();
scoreCorrectionForCompetitor.put(FIELD_EXPLICIT_SCORE_CORRECTION,
correction.getExplicitScoreCorrection(competitor, raceColumn));
scoreCorrectionForCompetitor.put(FIELD_MAX_POINTS_REASON,
correction.getMaxPointsReason(competitor, raceColumn).toString());
correction.getMaxPointsReason(competitor, raceColumn, now).toString());
scoreCorrectionForCompetitor.put(FIELD_COMPETITOR_ID, competitor.getId().toString());
scoreCorrectionsForCompetitors.add(scoreCorrectionForCompetitor);
}
@@ -37,7 +37,7 @@ public class RaceLogFinishPositioningConfirmedEventSerializer extends BaseRaceLo
JSONObject result = super.serialize(finishPositioningConfirmedEvent);
result.put(FIELD_POSITIONED_COMPETITORS, serializePositionedCompetitors(finishPositioningConfirmedEvent.getPositionedCompetitors()));
result.put(FIELD_POSITIONED_COMPETITORS, serializePositionedCompetitors(finishPositioningConfirmedEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()));
return result;
}
@@ -36,7 +36,7 @@ public class RaceLogFinishPositioningListChangedEventSerializer extends BaseRace
JSONObject result = super.serialize(finishPositioningListEvent);
result.put(FIELD_POSITIONED_COMPETITORS, serializePositionedCompetitors(finishPositioningListEvent.getPositionedCompetitors()));
result.put(FIELD_POSITIONED_COMPETITORS, serializePositionedCompetitors(finishPositioningListEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons()));
return result;
}
@@ -315,7 +315,7 @@ public class LeaderboardJsonGetServlet extends AbstractJsonHttpServlet implement
jsonEntry.put("raceRank", trackedRace.getRank(competitor, resultTimePoint));
}
jsonEntry.put("isDiscarded", leaderboard.isDiscarded(competitor, raceColumn, resultTimePoint));
jsonEntry.put("isCorrected", leaderboard.getScoreCorrection().isScoreCorrected(competitor, raceColumn));
jsonEntry.put("isCorrected", leaderboard.getScoreCorrection().isScoreCorrected(competitor, raceColumn, resultTimePoint));
}
counter++;
}
@@ -38,6 +38,7 @@ import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.CourseAreaImpl;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.NationalityImpl;
import com.sap.sailing.domain.base.impl.PersonImpl;
@@ -47,15 +48,19 @@ import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.common.media.MediaTrack;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
import com.sap.sailing.domain.racelog.RaceLogEventFactory;
import com.sap.sailing.domain.racelog.RaceLogFinishPositioningConfirmedEvent;
import com.sap.sailing.domain.racelog.RaceLogStartTimeEvent;
import com.sap.sailing.domain.racelog.impl.RaceLogEventFactoryImpl;
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.mongodb.MongoDBService;
import com.sap.sailing.server.RacingEventService;
@@ -282,7 +287,7 @@ public class MasterDataImportTest {
leaderboardOnTarget.getScoreCorrection().getExplicitScoreCorrection(competitorOnTarget,
raceColumnOnTarget));
Assert.assertEquals(maxPointsReason,
leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget));
leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget, MillisecondsTimePoint.now()));
// Check for carried points
Assert.assertEquals(carriedPoints, leaderboardOnTarget.getCarriedPoints(competitorOnTarget));
@@ -371,6 +376,15 @@ public class MasterDataImportTest {
RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, 1, logTimePoint);
raceColumn.getRaceLog(testFleet1).add(logEvent);
storedLogUUIDs.add(logEvent.getId());
// Add a competitor-related race log event to ensure that no competitor resolution is attempted while receiving
TimePoint logTimePoint2 = logTimePoint.plus(10);
List<Triple<Serializable, String, MaxPointsReason>> positionedCompetitors = new ArrayList<Triple<Serializable, String, MaxPointsReason>>();
positionedCompetitors.add(new Triple<Serializable, String, MaxPointsReason>(competitor.getId(), competitor.getName(), MaxPointsReason.BFD));
positionedCompetitors.add(new Triple<Serializable, String, MaxPointsReason>(competitor2.getId(), competitor2.getName(), MaxPointsReason.NONE));
RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent = factory.createFinishPositioningConfirmedEvent(logTimePoint2, 1, positionedCompetitors);
raceColumn.getRaceLog(testFleet1).add(finishPositioningConfirmedEvent);
storedLogUUIDs.add(finishPositioningConfirmedEvent.getId());
// Set score correction
double scoreCorrection = 12.0;
@@ -392,7 +406,7 @@ public class MasterDataImportTest {
// Deserialization copied from doPost in MasterDataByLeaderboardGroupJsonPostServlet
RacingEventService destService = new RacingEventServiceImplMock();
DomainFactory domainFactory = DomainFactory.INSTANCE;
DomainFactory domainFactory = new DomainFactoryImpl(); // create a new, empty domain factory to ensure all competitors are removed
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(
masterDataOverallObject.toString(), false);
@@ -433,11 +447,154 @@ public class MasterDataImportTest {
leaderboardOnTarget.getScoreCorrection().getExplicitScoreCorrection(competitorOnTarget,
raceColumnOnTarget));
Assert.assertEquals(maxPointsReason,
leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget));
leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget, MillisecondsTimePoint.now()));
// Checks if score correction was not set if not set on source
Assert.assertFalse(leaderboardOnTarget.getScoreCorrection().isScoreCorrected(competitorOnTarget2,
raceColumnOnTarget));
raceColumnOnTarget, MillisecondsTimePoint.now()));
}
/**
* When a race log entry references a competitor, e.g., by its UUID, these cannot be resolved when the TrackedRace isn't
* connected to the race column / leaderboard yet. Such a resolution would occur if importing the race log event triggered
* a listener which would try to resolve the competitor ID. This test ensures that the import does not fail due to such a
* look-up.
*/
@Test
public void testMasterDataImportForRaceLogEventsReferencingCompetitors() throws MalformedURLException, IOException,
InterruptedException {
// Setup source service
DomainFactory sourceDomainFactory = new DomainFactoryImpl();
RacingEventService sourceService = new RacingEventServiceImpl(MongoDBService.INSTANCE,
SwissTimingFactory.INSTANCE, new com.sap.sailing.domain.swisstimingadapter.impl.DomainFactoryImpl(
sourceDomainFactory), new com.sap.sailing.domain.tractracadapter.impl.DomainFactoryImpl(
sourceDomainFactory), MediaDBFactory.INSTANCE.getDefaultMediaDB());
Event event = sourceService.addEvent(TEST_EVENT_NAME, "testVenue", "", false, eventUUID,
new ArrayList<String>());
UUID courseAreaUUID = UUID.randomUUID();
CourseArea courseArea = new CourseAreaImpl("testArea", courseAreaUUID);
event.getVenue().addCourseArea(courseArea);
List<String> raceColumnNames = new ArrayList<String>();
String raceColumnName = "T1";
raceColumnNames.add(raceColumnName);
raceColumnNames.add("T2");
final List<String> emptyRaceColumnNamesList = Collections.emptyList();
List<Series> series = new ArrayList<Series>();
List<Fleet> fleets = new ArrayList<Fleet>();
FleetImpl testFleet1 = new FleetImpl("testFleet1");
fleets.add(testFleet1);
fleets.add(new FleetImpl("testFleet2"));
series.add(new SeriesImpl("testSeries", false, fleets, emptyRaceColumnNamesList, sourceService));
UUID regattaUUID = UUID.randomUUID();
Regatta regatta = sourceService.createRegatta("testRegatta", "29er", regattaUUID, series, true, new LowPoint(),
courseAreaUUID);
event.addRegatta(regatta);
for (String name : raceColumnNames) {
series.get(0).addRaceColumn(name, sourceService);
}
int[] discardRule = { 1, 2, 3, 4 };
Leaderboard leaderboard = sourceService.addRegattaLeaderboard(regatta.getRegattaIdentifier(),
"testDisplayName", discardRule);
List<String> leaderboardNames = new ArrayList<String>();
leaderboardNames.add(leaderboard.getName());
sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null);
// Set tracked Race with competitors
Set<Competitor> competitors = new HashSet<Competitor>();
UUID competitorUUID = UUID.randomUUID();
Set<Person> sailors = new HashSet<Person>();
sailors.add(new PersonImpl("Froderik Poterson", new NationalityImpl("GER"), new Date(645487200000L),
"Oberhoschy"));
Person coach = new PersonImpl("Lennart Hensler", new NationalityImpl("GER"), new Date(645487200000L),
"Der Lennart halt");
Team team = new TeamImpl("Pros", sailors, coach);
BoatClass boatClass = new BoatClassImpl("H16", true);
Boat boat = new BoatImpl("Wingy", boatClass, "GER70133");
Competitor competitor = sourceDomainFactory.getOrCreateCompetitor(competitorUUID, "Froderik", team, boat);
competitors.add(competitor);
UUID competitor2UUID = UUID.randomUUID();
Set<Person> sailors2 = new HashSet<Person>();
sailors2.add(new PersonImpl("Test Mustermann", new NationalityImpl("GER"), new Date(645487200000L), "desc"));
Person coach2 = new PersonImpl("Max Test", new NationalityImpl("GER"), new Date(645487200000L), "desc");
Team team2 = new TeamImpl("Pros2", sailors2, coach2);
Boat boat2 = new BoatImpl("FastBoat", boatClass, "GER70133");
Competitor competitor2 = sourceDomainFactory.getOrCreateCompetitor(competitor2UUID, "Froderik", team2, boat2);
competitors.add(competitor2);
TrackedRace trackedRace = new DummyTrackedRace(competitors, regatta);
RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName);
raceColumn.setTrackedRace(testFleet1, trackedRace);
// Set log event
RaceLogEventFactory factory = new RaceLogEventFactoryImpl();
TimePoint logTimePoint = new MillisecondsTimePoint(1372489200000L);
RaceLogStartTimeEvent logEvent = factory.createStartTimeEvent(logTimePoint, 1, logTimePoint);
raceColumn.getRaceLog(testFleet1).add(logEvent);
storedLogUUIDs.add(logEvent.getId());
// Add a competitor-related race log event to ensure that no competitor resolution is attempted while receiving
TimePoint logTimePoint2 = logTimePoint.plus(10);
List<Triple<Serializable, String, MaxPointsReason>> positionedCompetitors = new ArrayList<Triple<Serializable, String, MaxPointsReason>>();
positionedCompetitors.add(new Triple<Serializable, String, MaxPointsReason>(competitor.getId(), competitor.getName(), MaxPointsReason.DNS));
positionedCompetitors.add(new Triple<Serializable, String, MaxPointsReason>(competitor2.getId(), competitor2.getName(), MaxPointsReason.NONE));
RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent = factory.createFinishPositioningConfirmedEvent(logTimePoint2, 1, positionedCompetitors);
raceColumn.getRaceLog(testFleet1).add(finishPositioningConfirmedEvent);
storedLogUUIDs.add(finishPositioningConfirmedEvent.getId());
// Serialize
TopLevelMasterDataSerializer serializer = new TopLevelMasterDataSerializer(
sourceService.getLeaderboardGroups(), sourceService.getAllEvents(),
sourceService.getPersistentRegattasForRaceIDs(), sourceService.getAllMediaTracks());
Set<String> names = new HashSet<String>();
names.add(TEST_GROUP_NAME);
JSONObject masterDataOverallObject = serializer.serialize(names);
Assert.assertNotNull(masterDataOverallObject);
// Delete all data above from the database, to allow recreating all of it on target server
deleteCreatedDataFromDatabase();
// Deserialization copied from doPost in MasterDataByLeaderboardGroupJsonPostServlet
RacingEventService destService = new RacingEventServiceImplMock();
DomainFactory domainFactory = new DomainFactoryImpl(); // create a new, empty domain factory to ensure all competitors are removed
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
MasterDataImportObjectCreationCount creationCount = importer.importMasterData(
masterDataOverallObject.toString(), false);
Assert.assertNotNull(creationCount);
Event eventOnTarget = destService.getEvent(eventUUID);
Assert.assertNotNull(eventOnTarget);
LeaderboardGroup leaderboardGroupOnTarget = destService.getLeaderboardGroupByName(TEST_GROUP_NAME);
Assert.assertNotNull(leaderboardGroupOnTarget);
Leaderboard leaderboardOnTarget = destService.getLeaderboardByName(TEST_LEADERBOARD_NAME);
Assert.assertNotNull(leaderboardOnTarget);
Regatta regattaOnTarget = destService.getRegattaByName(TEST_LEADERBOARD_NAME);
Assert.assertNotNull(regattaOnTarget);
Assert.assertEquals(courseAreaUUID, eventOnTarget.getVenue().getCourseAreas().iterator().next().getId());
RaceColumn raceColumnOnTarget = leaderboardOnTarget.getRaceColumnByName(raceColumnName);
Assert.assertNotNull(raceColumnOnTarget);
Assert.assertTrue(leaderboardOnTarget.getScoreCorrection().hasCorrectionFor(raceColumnOnTarget));
Competitor competitorOnTarget = domainFactory.getExistingCompetitorById(competitorUUID);
Set<Competitor> competitorsCreatedOnTarget = new HashSet<Competitor>();
competitorsCreatedOnTarget.add(competitorOnTarget);
TrackedRace trackedRaceForTarget = new DummyTrackedRace(competitorsCreatedOnTarget, regattaOnTarget);
Fleet fleet1OnTarget = raceColumnOnTarget.getFleetByName(testFleet1.getName());
raceColumnOnTarget.setTrackedRace(fleet1OnTarget, trackedRaceForTarget);
Iterable<Competitor> competitorsOnTarget = leaderboardOnTarget.getAllCompetitors();
Iterator<Competitor> competitorIterator = competitorsOnTarget.iterator();
Assert.assertTrue(competitorIterator.hasNext());
Assert.assertEquals(competitorOnTarget, competitorIterator.next());
// Check for score corrections
Assert.assertEquals(MaxPointsReason.DNS,
leaderboardOnTarget.getScoreCorrection().getMaxPointsReason(competitorOnTarget, raceColumnOnTarget, MillisecondsTimePoint.now()));
}
@Test
@@ -22,10 +22,10 @@
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
<stringAttribute key="pde.version" value="3.3"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.activemq.activeio-core@default:default,org.apache.activemq.activemq-core@default:default,org.apache.activemq.kahadb@default:default,org.apache.commons.codec*1.4.0.v201209201156@default:default,org.apache.commons.codec*1.6.0@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.jasper.glassfish@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.jetty.continuation*8.1.10.v20130312@default:default,org.eclipse.jetty.continuation*9.0.4.v20130625@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http*8.1.10.v20130312@default:default,org.eclipse.jetty.http*9.0.4.v20130625@default:default,org.eclipse.jetty.io*8.1.10.v20130312@default:default,org.eclipse.jetty.io*9.0.4.v20130625@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security*8.1.10.v20130312@default:default,org.eclipse.jetty.security*9.0.4.v20130625@default:default,org.eclipse.jetty.server*8.1.10.v20130312@default:default,org.eclipse.jetty.server*9.0.4.v20130625@default:default,org.eclipse.jetty.servlet*8.1.10.v20130312@default:default,org.eclipse.jetty.servlet*9.0.4.v20130625@default:default,org.eclipse.jetty.util*8.1.10.v20130312@default:default,org.eclipse.jetty.util*9.0.4.v20130625@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.hamcrest.integration@default:default,org.hamcrest.library@default:default,org.hamcrest.text@default:default,org.hamcrest@default:default,org.jdom@default:default,org.junit4@default:default,org.mockito.mockito-core@default:default,org.objectweb.asm@default:default,org.objenesis@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.activemq.activeio-core@default:default,org.apache.activemq.activemq-core@default:default,org.apache.activemq.kahadb@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.hamcrest.integration@default:default,org.hamcrest.library@default:default,org.hamcrest.text@default:default,org.hamcrest@default:default,org.jdom@default:default,org.junit4@default:default,org.mockito.mockito-core@default:default,org.objectweb.asm@default:default,org.objenesis@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi*2.5.1.qualifier@default:default,com.googlecode.java-diff-utils.test@default:false,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination.test@default:false,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter.test@default:false,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter.test@default:false,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.test@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter.test@default:false,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport.test@default:false,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector.test@default:false,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport.test@default:false,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding.test@default:false,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui.test@default:false,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport.test@default:false,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb.test@default:false,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation.test@default:false,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway.test@default:false,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication.test@default:false,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.test@default:false,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport.test@default:false,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils.test@default:false,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination.test@default:false,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter.test@default:false,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter.test@default:false,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.test@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter.test@default:false,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport.test@default:false,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector.test@default:false,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport.test@default:false,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding.test@default:false,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui.test@default:false,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport.test@default:false,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb.test@default:false,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation.test@default:false,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway.test@default:false,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication.test@default:false,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.test@default:false,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport.test@default:false,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="yk-options" value="&#13;&#10;additional-options2=onexit\=snapshot&#13;&#10;"/>
</launchConfiguration>
@@ -22,10 +22,10 @@
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
<stringAttribute key="pde.version" value="3.3"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.activemq.activeio-core@default:default,org.apache.activemq.activemq-core@default:default,org.apache.activemq.kahadb@default:default,org.apache.commons.codec*1.4.0.v201209201156@default:default,org.apache.commons.codec*1.6.0@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.jasper.glassfish@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.jetty.continuation*8.1.10.v20130312@default:default,org.eclipse.jetty.continuation*9.0.4.v20130625@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http*8.1.10.v20130312@default:default,org.eclipse.jetty.http*9.0.4.v20130625@default:default,org.eclipse.jetty.io*8.1.10.v20130312@default:default,org.eclipse.jetty.io*9.0.4.v20130625@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security*8.1.10.v20130312@default:default,org.eclipse.jetty.security*9.0.4.v20130625@default:default,org.eclipse.jetty.server*8.1.10.v20130312@default:default,org.eclipse.jetty.server*9.0.4.v20130625@default:default,org.eclipse.jetty.servlet*8.1.10.v20130312@default:default,org.eclipse.jetty.servlet*9.0.4.v20130625@default:default,org.eclipse.jetty.util*8.1.10.v20130312@default:default,org.eclipse.jetty.util*9.0.4.v20130625@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.hyperic.sigar@default:default,org.jdom@default:default,org.junit4@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.activemq.activeio-core@default:default,org.apache.activemq.activemq-core@default:default,org.apache.activemq.kahadb@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hamcrest.core@default:default,org.hyperic.sigar@default:default,org.jdom@default:default,org.junit4@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi*2.5.1.qualifier@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.monitoring@5:true,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.monitoring@5:true,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="yk-options" value="&#13;&#10;additional-options2=onexit\=snapshot&#13;&#10;"/>
</launchConfiguration>
@@ -21,9 +21,9 @@
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Declipse.ignoreApp=true -Dosgi.noShutdown=true&#13;&#10;-Dexpedition.udp.port=2010 -Xmx1024m -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -XX:+UseMembar"/>
<stringAttribute key="pde.version" value="3.3"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,org.apache.commons.codec*1.4.0.v201209201156@default:default,org.apache.commons.codec*1.6.0@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.jasper.glassfish@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi*2.5.1.qualifier@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
</launchConfiguration>
@@ -21,9 +21,9 @@
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Xmx2048m -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -XX:+UseMembar"/>
<stringAttribute key="pde.version" value="3.3"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.activemq.activeio-core@default:default,org.apache.activemq.activemq-core@default:default,org.apache.activemq.kahadb@default:default,org.apache.commons.codec*1.4.0.v201209201156@default:default,org.apache.commons.codec*1.6.0@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.jasper.glassfish@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.jetty.continuation*8.1.10.v20130312@default:default,org.eclipse.jetty.continuation*9.0.4.v20130625@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http*8.1.10.v20130312@default:default,org.eclipse.jetty.http*9.0.4.v20130625@default:default,org.eclipse.jetty.io*8.1.10.v20130312@default:default,org.eclipse.jetty.io*9.0.4.v20130625@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security*8.1.10.v20130312@default:default,org.eclipse.jetty.security*9.0.4.v20130625@default:default,org.eclipse.jetty.server*8.1.10.v20130312@default:default,org.eclipse.jetty.server*9.0.4.v20130625@default:default,org.eclipse.jetty.servlet*8.1.10.v20130312@default:default,org.eclipse.jetty.servlet*9.0.4.v20130625@default:default,org.eclipse.jetty.util*8.1.10.v20130312@default:default,org.eclipse.jetty.util*9.0.4.v20130625@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.activemq.activeio-core@default:default,org.apache.activemq.activemq-core@default:default,org.apache.activemq.kahadb@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.hyperic.sigar@default:default,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi*2.5.1.qualifier@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.monitoring@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.monitoring@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
</launchConfiguration>
@@ -26,6 +26,6 @@
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@4:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.replication@4:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xcelsiusadapter@4:true,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@4:true,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.nmeaconnector@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@4:true,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@5:true,com.sap.sailing.server.replication@4:true,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@4:true,com.sap.sailing.www@4:true,com.sap.sailing.xcelsiusadapter@4:true,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,net.sf.marineapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="yk-options" value="&#13;&#10;additional-options2=onexit\=snapshot&#13;&#10;"/>
</launchConfiguration>
@@ -22,10 +22,10 @@
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
<stringAttribute key="pde.version" value="3.3"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.activemq.activeio-core@default:default,org.apache.activemq.activemq-core@default:default,org.apache.activemq.kahadb@default:default,org.apache.commons.codec*1.4.0.v201209201156@default:default,org.apache.commons.codec*1.6.0@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.jasper.glassfish@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.jetty.continuation*8.1.10.v20130312@default:default,org.eclipse.jetty.continuation*9.0.4.v20130625@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http*8.1.10.v20130312@default:default,org.eclipse.jetty.http*9.0.4.v20130625@default:default,org.eclipse.jetty.io*8.1.10.v20130312@default:default,org.eclipse.jetty.io*9.0.4.v20130625@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot.jsp@default:false,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security*8.1.10.v20130312@default:default,org.eclipse.jetty.security*9.0.4.v20130625@default:default,org.eclipse.jetty.server*8.1.10.v20130312@default:default,org.eclipse.jetty.server*9.0.4.v20130625@default:default,org.eclipse.jetty.servlet*8.1.10.v20130312@default:default,org.eclipse.jetty.servlet*9.0.4.v20130625@default:default,org.eclipse.jetty.util*8.1.10.v20130312@default:default,org.eclipse.jetty.util*9.0.4.v20130625@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.activemq.activeio-core@default:default,org.apache.activemq.activemq-core@default:default,org.apache.activemq.kahadb@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot.jsp@default:false,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi*2.5.1.qualifier@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway.serialization@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="yk-options" value="&#13;&#10;additional-options2=onexit\=snapshot&#13;&#10;"/>
</launchConfiguration>
@@ -22,9 +22,9 @@
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Xmx6000m -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dhttp.proxyHost=proxy.wdf.sap.corp -Dhttp.proxyPort=8080 -Dexpedition.udp.port=2010 -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -XX:+UseMembar"/>
<stringAttribute key="pde.version" value="3.3"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.activemq.activeio-core@default:default,org.apache.activemq.activemq-core@default:default,org.apache.activemq.kahadb@default:default,org.apache.commons.codec*1.4.0.v201209201156@default:default,org.apache.commons.codec*1.6.0@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jta_1.0.1B_spec@default:default,org.apache.jasper.glassfish@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.jetty.client@default:default,org.eclipse.jetty.continuation*8.1.10.v20130312@default:default,org.eclipse.jetty.continuation*9.0.4.v20130625@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http*8.1.10.v20130312@default:default,org.eclipse.jetty.http*9.0.4.v20130625@default:default,org.eclipse.jetty.io*8.1.10.v20130312@default:default,org.eclipse.jetty.io*9.0.4.v20130625@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot.jsp@default:false,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security*8.1.10.v20130312@default:default,org.eclipse.jetty.security*9.0.4.v20130625@default:default,org.eclipse.jetty.server*8.1.10.v20130312@default:default,org.eclipse.jetty.server*9.0.4.v20130625@default:default,org.eclipse.jetty.servlet*8.1.10.v20130312@default:default,org.eclipse.jetty.servlet*9.0.4.v20130625@default:default,org.eclipse.jetty.servlets@default:default,org.eclipse.jetty.util*8.1.10.v20130312@default:default,org.eclipse.jetty.util*9.0.4.v20130625@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jcl.over.slf4j@default:default,org.apache.activemq.activeio-core@default:default,org.apache.activemq.activemq-core@default:default,org.apache.activemq.kahadb@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-annotation_1.0_spec@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jta_1.0.1B_spec@default:default,org.eclipse.jetty.client@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot.jsp@default:false,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.servlets@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="true"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi*2.5.1.qualifier@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.resultimport@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
</launchConfiguration>
@@ -21,9 +21,9 @@
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-DsimulateLiveMode=true -DsimulateLiveMode.delayInMillis=250 -Declipse.ignoreApp=true -Dosgi.noShutdown=true&#13;&#10;-Dexpedition.udp.port=2010 -Xmx6000m -Dhttp.proxyHost=proxy.wdf.sap.corp -Dhttp.proxyPort=8080 -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -XX:+UseMembar"/>
<stringAttribute key="pde.version" value="3.3"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jul.to.slf4j@default:default,org.apache.commons.codec*1.4.0.v201209201156@default:default,org.apache.commons.codec*1.6.0@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.apache.jasper.glassfish@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.jetty.continuation*8.1.10.v20130312@default:default,org.eclipse.jetty.continuation*9.0.4.v20130625@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http*8.1.10.v20130312@default:default,org.eclipse.jetty.http*9.0.4.v20130625@default:default,org.eclipse.jetty.io*8.1.10.v20130312@default:default,org.eclipse.jetty.io*9.0.4.v20130625@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot.jsp@default:false,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security*8.1.10.v20130312@default:default,org.eclipse.jetty.security*9.0.4.v20130625@default:default,org.eclipse.jetty.server*8.1.10.v20130312@default:default,org.eclipse.jetty.server*9.0.4.v20130625@default:default,org.eclipse.jetty.servlet*8.1.10.v20130312@default:default,org.eclipse.jetty.servlet*9.0.4.v20130625@default:default,org.eclipse.jetty.util*8.1.10.v20130312@default:default,org.eclipse.jetty.util*9.0.4.v20130625@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<stringAttribute key="target_bundles" value="com.rabbitmq.client@default:default,com.sun.jersey@default:default,com.sun.mail.javax.mail@default:default,javax.servlet*3.0.0.v201112011016@default:default,javax.validation@default:default,javax.ws.rs@default:default,jul.to.slf4j@default:default,org.apache.commons.codec@default:default,org.apache.commons.fileupload@default:default,org.apache.commons.io@default:default,org.apache.geronimo.specs.geronimo-j2ee-management_1.1_spec@default:default,org.apache.geronimo.specs.geronimo-jms_1.1_spec@default:default,org.eclipse.jetty.continuation@default:default,org.eclipse.jetty.deploy@default:default,org.eclipse.jetty.http@default:default,org.eclipse.jetty.io@default:default,org.eclipse.jetty.jmx@default:default,org.eclipse.jetty.osgi.boot.jsp@default:false,org.eclipse.jetty.osgi.boot@default:default,org.eclipse.jetty.security@default:default,org.eclipse.jetty.server@default:default,org.eclipse.jetty.servlet@default:default,org.eclipse.jetty.util@default:default,org.eclipse.jetty.webapp@default:default,org.eclipse.jetty.websocket.api@default:default,org.eclipse.jetty.websocket.client@default:default,org.eclipse.jetty.websocket.common@default:default,org.eclipse.jetty.websocket.server@default:default,org.eclipse.jetty.websocket.servlet@default:default,org.eclipse.jetty.xml@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.jdom@default:default,org.objectweb.asm@default:default,rome@default:default,routeconverter@default:default,slf4j.api@default:default,slf4j.jdk14@default:false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi*2.5.1.qualifier@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.barbados.resultimport@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.shared.android@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.swisstimingreplayadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.ess40.resultimport@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.freg.resultimport@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.kiworesultimport@default:default,com.sap.sailing.manage2sail.resultimport@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.sailwave.resultimport@default:default,com.sap.sailing.server.gateway.ess40@default:default,com.sap.sailing.server.gateway@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server.trackfiles@default:default,com.sap.sailing.server@default:default,com.sap.sailing.simulator@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.velum.resultimport@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.sap.sailing.xrr.resultimport@default:default,com.tractrac.clientmodule@default:default,de.csenk.gwt.ws@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
</launchConfiguration>
@@ -5,7 +5,6 @@ import java.util.List;
import java.util.concurrent.Callable;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
@@ -111,12 +110,14 @@ public class RaceLogScoringReplicator implements RaceColumnListener {
}
/**
* Retrieves the last RaceLogFinishPositioningListChangedEvent from the racelog and compares the ranks and disqualifications
* entered by the race committee with the tracked ranks. When a tracked rank for a competitor is not the same as the rank of the race committee,
* a score correction is issued.
* The positioning list contains a list of competitors sorted by the positioning order when finishing. Additionally a MaxPointsReason might be entered by the
* Race Committee.
* @param timePoint the TimePoint at which the race committee confirmed their last rank list entered in the app.
* Retrieves the last RaceLogFinishPositioningListChangedEvent from the racelog and compares the ranks and
* disqualifications entered by the race committee with the tracked ranks. When a tracked rank for a competitor is
* not the same as the rank of the race committee, a score correction is issued. The positioning list contains a
* list of competitors sorted by the positioning order when finishing. Additionally a MaxPointsReason might be
* entered by the Race Committee.
*
* @param timePoint
* the TimePoint at which the race committee confirmed their last rank list entered in the app.
*/
private void checkNeedForScoreCorrectionByResultsOfRaceCommittee(Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, RaceLog raceLog, TimePoint timePoint) {
@@ -138,7 +139,7 @@ public class RaceLogScoringReplicator implements RaceColumnListener {
if (positioningList != null) {
for (Triple<Serializable, String, MaxPointsReason> positionedCompetitor : positioningList) {
Competitor competitor = DomainFactory.INSTANCE.getExistingCompetitorById(positionedCompetitor.getA());
Competitor competitor = service.getBaseDomainFactory().getExistingCompetitorById(positionedCompetitor.getA());
if (positionedCompetitor.getC().equals(MaxPointsReason.NONE)) {
try {
@@ -73,7 +73,6 @@ import com.sap.sailing.domain.leaderboard.ScoringScheme;
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;
@@ -377,8 +376,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
domainObjectFactory);
CourseArea courseArea = getCourseArea(courseAreaId);
FlexibleLeaderboard result = new FlexibleLeaderboardImpl(raceLogStore, leaderboardName,
new ScoreCorrectionImpl(), new ThresholdBasedResultDiscardingRuleImpl(discardThresholds),
scoringScheme, courseArea);
new ThresholdBasedResultDiscardingRuleImpl(discardThresholds), scoringScheme,
courseArea);
result.setDisplayName(leaderboardDisplayName);
synchronized (leaderboardsByName) {
if (getLeaderboardByName(leaderboardName) != null) {
@@ -410,8 +409,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
+ (regatta == null ? "null" : (regatta.getName() + " (" + regatta.hashCode() + ")")) + " to " + this);
RegattaLeaderboard result = null;
if (regatta != null) {
result = new RegattaLeaderboardImpl(regatta, new ScoreCorrectionImpl(),
new ThresholdBasedResultDiscardingRuleImpl(discardThresholds));
result = new RegattaLeaderboardImpl(regatta, new ThresholdBasedResultDiscardingRuleImpl(discardThresholds));
result.setDisplayName(leaderboardDisplayName);
synchronized (leaderboardsByName) {
if (getLeaderboardByName(result.getName()) != null) {
@@ -170,7 +170,7 @@ public class ImportMasterDataOperation extends
List<RaceLogEvent> logEvents = fleetEntry.getValue();
RaceLog raceLog = raceColumn.getRaceLog(fleet);
for (RaceLogEvent singleEvent : logEvents) {
raceLog.add(singleEvent);
raceLog.load(singleEvent);
}
}
}
@@ -50,7 +50,7 @@ public class UpdateLeaderboardMaxPointsReason extends AbstractLeaderboardColumnO
leaderboard.getScoreCorrection().setMaxPointsReason(competitor, raceColumn, newMaxPointsReason);
updateStoredLeaderboard(toState, leaderboard);
Entry updatedEntry = leaderboard.getEntry(competitor, raceColumn, timePoint);
boolean isScoreCorrected = leaderboard.getScoreCorrection().isScoreCorrected(competitor, raceColumn);
boolean isScoreCorrected = leaderboard.getScoreCorrection().isScoreCorrected(competitor, raceColumn, timePoint);
return new Triple<Double, Double, Boolean>(updatedEntry.getNetPoints(), updatedEntry.getTotalPoints(), isScoreCorrected);
} else {
throw new IllegalArgumentException("Didn't find competitor with ID "+competitorIdAsString+" in leaderboard "+getLeaderboardName());
@@ -56,7 +56,7 @@ public class UpdateLeaderboardScoreCorrection extends AbstractLeaderboardColumnO
newNetPoints = correctedScore;
}
newTotalPoints = leaderboard.getEntry(competitor, raceColumn, timePoint).getTotalPoints();
isScoreCorrected = leaderboard.getScoreCorrection().isScoreCorrected(competitor, raceColumn);
isScoreCorrected = leaderboard.getScoreCorrection().isScoreCorrected(competitor, raceColumn, timePoint);
} else {
throw new IllegalArgumentException("Didn't find competitor with ID "+competitorIdAsString+" in leaderboard "+getLeaderboardName());
}
@@ -23,7 +23,7 @@
Act 7 - Nice, France
</p>
<p>
September 2th - 6th
October 2th - 6th
</p>
</div>
<div id='navigation'>
@@ -32,10 +32,10 @@
</a>
<!--<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Rio%20%28Extreme40%29&displayName=Rio&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Rio de Janeiro
</a>
</a>-->
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Nice%20%28Extreme40%29&displayName=Nice&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Nice
</a>-->
</a>
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Cardiff%20%28Extreme40%29&displayName=Cardiff&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
Cardiff
</a>
+27 -24
View File
@@ -34,38 +34,17 @@
<div class='innerContent'>
<!-- Uncomment the following in case there are events in live state and add the timeBar plus raceSection -->
<!--
<h2 class='articleSubheadline'>Live</h2>
<div class="timeBar">
<div class='raceSection'>
<h5 class='date'>
Sep 19-22
</h5>
<div class='raceTimepoint'></div>
<a href='http://505idm2013.sapsailing.com' target='_blank'>
<ul class='racePanel'>
<li class='raceName'>
505 IDM 2013
</li>
<li class='raceLocation'>
Wannsee, Berlin
</li>
</ul>
</a>
<div class='raceDescription'>
<p>505 IDM 2013</p>
<a href='http://505idm2013.sapsailing.com' target='_blank'>SAP Sailing Analytics</a><br/>
<a href='http://www.vsaw.de/index.php?id=1027' target='_blank'>Official website</a>
</div>
</div>
</div>
<br/>
-->
<!-- Uncomment the following in case there are upcoming and add the timeBar plus raceSection -->
<h2 class='articleSubheadline'>Upcoming</h2>
<div class="timeBar">
<div class='raceSection'>
<h5 class='date'>
Sep 2 - 7
Oct 3 - 6
</h5>
<div class='raceTimepoint'></div>
<a href='http://ess40-2013.sapsailing.com' target='_blank'>
@@ -89,6 +68,29 @@
<br/>
<h2 class='articleSubheadline'>2013</h2>
<div class="timeBar">
<div class='raceSection'>
<h5 class='date'>
Sep 19-22
</h5>
<div class='raceTimepoint'></div>
<a href='http://505idm2013.sapsailing.com' target='_blank'>
<ul class='racePanel'>
<li class='raceName'>
505 IDM 2013
</li>
<li class='raceLocation'>
Wannsee, Berlin
</li>
</ul>
</a>
<div class='raceDescription'>
<p>505 IDM 2013</p>
<a href='http://505idm2013.sapsailing.com' target='_blank'>SAP Sailing Analytics</a><br/>
<a href='http://505idm2013.de' target='_blank'>Official website</a>
</div>
</div>
</div>
<div class="timeBar">
<div class='raceSection'>
<h5 class='date'>
@@ -432,3 +434,4 @@
</body>
</html>
+104 -2
View File
@@ -1,3 +1,105 @@
# Amazon EC2 for SAP
# Amazon EC2 for SAP Sailing Analytics
[[Creating a new application instance|wiki/amazon-ec2-create-new-app-instance]]
[[_TOC_]]
## General Information and Security
Since XXX 2013 this project is using EC2 as the server provider. Amazon Elastic Compute Cloud (EC2) is a central part of Amazon.com's cloud computing platform, Amazon Web Services (AWS). EC2 allows users to rent virtual computers on which to run their own computer applications. EC2 allows scalable deployment of applications by providing a Web service through which a user can boot an Amazon Machine Image to create a virtual machine, which Amazon calls an "instance", containing any software desired. A user can create, launch, and terminate server instances as needed, paying by the hour for active servers, hence the term "elastic".
This project is associated with an SAP Sailing Analytics account that, for billing purposes, is a subsidiary of a main SAP billing account. The Analytics account number is "0173-6397-0217 (simon.marcel.pamies@sap.com)" and connected to "SAP CMC Production (hagen.stanek@sap.com)". It has "Dr. Axel Uhl (axel.uhl@sap.com)" configured as operations officer that can be contacted by Amazon in case of problems with the instances.
The main entry point for the account is https://console.aws.amazon.com/. There you can only log in using the root account. You will then have access to not only the EC2 Console but also to the main account details (including billing details).
<img src="/wiki/images/amazon/RootAccount.JPG" width="100%" height="100%"/>
Associated to the root account are _n_ users that can be configured using the IAM (User Management, https://console.aws.amazon.com/iam/home). Each of these users can belong to different groups that have different rights associated. Currently two groups exist:
* **Administrators**: Users belonging to this group have access to all EC2 services (including IAM). They do not have the right to manage main account information (like billing).
* **Seniors**: Everyone belonging to this group can not access IAM but everything else.
Users configured in the IAM and at least belonging to the group Seniors can log in using the following url https://017363970217.signin.aws.amazon.com/console. All users that belong to one of these groups absolutely need to have MFA activated. MFA (Multi-Factor-Authentication) can be compared to the RSA token that needs to be input every time one wants to access the SAP network. After activation users need to synchronize their device using a barcode that is displayed in IAM. The device can be a software (Google Authenticator for iOS and Android) or a physical device.
<img src="/wiki/images/amazon/IAMUsers.JPG" width="100%" height="100%"/>
In addition to having a password and MFA set for one user one can activate "Access Keys". These keys are a combination of hashed username ("ID") and a password ("Key"). These are needed in case of API related access (e.g. S3 uploader scripts). One user should not have more than 1 access key active because of security concerns and never distribute them over insecure channels.
## EC2 Server Architecture for Sailing Analytics
The architecture is divided into 3 logical tiers. These are represented by firewall configurations (Security Groups) that can be associated to Instances. The following image depicts the parts of the architecture.
<img src="/wiki/images/amazon/EC2Architecture.JPG" width="100%" height="100%"/>
### Tiers
* **Webserver**: Holds one or more webserver instances that represent the public facing part of the architecture. Only instances running in this tier should have an Elastic IP assigned.
* **Database**: Instances handling all operations related to persistence. Must be reachable by the "Instance" and "Balancer+Group" tier.
* **Instances**: Space where all instances, that are not grouped, live.
* **Balancer+Group**: Analytics instances grouped and managed by an Elastic Load Balancer. A group is just a term describing multiple instances replicating from one master instance. The word "group" does in this context not refer to the so called "Placement Groups".
### Instances
<table>
<tr>
<td><b>Name</b></td>
<td><b>Access Key(s)</b></td>
<td><b>Security Group</b></td>
<td><b>Open Ports</b></td>
<td><b>Services</b></td>
<td><b>Description</b></td>
</tr>
<tr>
<td>Webserver (Elastic IP: 54.229.94.254)</td>
<td>Administrator</td>
<td>IN: 20, 80, 443, 2010-2015<br/>OUT: ALL</td>
<td>Webserver</td>
<td>Apache, GIT, Piwik, Bugzilla</td>
<td>This tier holds one instance that has one public Elastic IP associated. This instance manages all domains and subdomains associated with this project. It also contains the public GIT repository.</td>
</tr>
<tr>
<td>DB & Messaging</td>
<td>Administrator</td>
<td>IN: 22, 5672, 10200-10210, 27017<br/>OUT: ALL</td>
<td>Database and Messaging</td>
<td>MongoDB, MySQL</td>
<td>All databases needed by either the Analytics applications or tools like Piwik and Bugzilla are managed by this instance.</td>
</tr>
<tr>
<td>Archive</td>
<td>Administrator, Sailing User</td>
<td>IN: 22, 2010-2015, 8880-8899<br/>OUT: ALL</td>
<td>Sailing Analytics App</td>
<td>Java App</td>
<td>Instance handling the access to all historical races.</td>
</tr>
</table>
## HowTo
### Create a new Analytics application instance
Find detailed instructions on how to create a new instance here: [[wiki/amazon-ec2-create-new-app-instance]].
### Setup replicated instances with ELB
### Access MongoDB database
## Glossary
<table>
<tr>
<td><b>Term</b></td>
<td><b>Description</b></td>
</tr>
<tr><td>Instance</td><td>Virtual machine that runs on a Xen host. Such an instance runs forever until it is stopped. It will be billed by hours it ran. Each start will be billed by a full hour.</td></tr>
<tr><td>Spot Instance</td><td>Instances that run whenever there are free resources. It is not possible to control when or where these instances run. These instances are much cheaper than normal instances.</td></tr>
<tr><td>Amazon Machine Image (AMI)</td><td>Amazon Machine Image: Image file that contains a filesystem and a preinstalled operating system. One can create AMIs very easily from a stopped Instance by first creating a snapshot and then converting it to an AMI.</td></tr>
<tr><td>Volume</td><td>An active harddisk that can be associated to one Instance.</td></tr>
<tr><td>IOPS</td><td>Input/Output operations per second. Metric used to denote the performance of a volume. The higher the IOPS value the better the speed. Be aware of the fact that IOPS is metered by IOPS/h and is very expensive. Use with care!</td></tr>
<tr><td>Snapshot</td><td>Snapshot of a Volume</td></tr>
<tr><td>Elastic IP</td><td>IP address that can be associated to an instance. Any Elastic-IP not associated to a running Instance costs some amount of money per hour.</td></tr>
<tr><td>Security Group</td><td>Firewall configuration that can be associated to an instance. There is no need of configuring iptables or such. One can associate many instances the the same Security Group.</td></tr>
<tr><td>Elastic Load Balancer (ELB)</td><td>Service that makes it possible to balance over services running on different instances.</td></tr>
<tr><td>Network Interfaces</td><td>Virtual network interfaces that are mapped to physical network interfaces on instances. </td></tr>
<tr><td>Placement Groups</td><td>Enables applications to get the full-bisection bandwidth and low-latency network performance required for tightly coupled, node-to-node communication. Placement Groups can only contain HVM instance and have other limitations described here: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using_cluster_computing.html</td></tr>
</table>
+5
View File
@@ -0,0 +1,5 @@
# Monitoring and Improving Data Quality
Our data is obtained from sensors and user input. Both can be flaky and lack accuracy. We already detect major outliers in the GPS and wind data. However, many data quality issues remain. Particularly, aggregating data of different levels of quality may need to propagate some information about quality and confidence to the aggregated values so that consumers may judge the overall confidence of the aggregated results.
See also [Bug 1243](http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=1243).
Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

+10
View File
@@ -12,6 +12,16 @@ Since the OSGi manifest dependencies still require javax.servlet, the Eclipse an
As a workaround, use the buildAndUpdateProduct.sh script found in the top-level configuration/ directory in git. Together with the -t and -c options (no tests, no cleaning), the compilation speed may be found acceptable. If you really urgently need to compile GWT locally on a regular basis and would like to speed up compilation, please consider temporarily editing java/com.sap.sailing.gwt.ui/pom.xml to reduce the number of modules and permutations to be compiled.
Add restrictions with the following two tags to reduce the number of permutations so that gwt is compiled only in your language and browser:
<set-property name="locale" value="en" />
`<set-property name="user.agent" value="gecko1_8" />`
`<set-property name="locale" value="en" />`
Those tags must be put into the *.gwt.xml files e.g. "AdminConsole.gwt.xml".
## Debugging GWT
One of the great strengths of GWT is the use of Eclipse as a Java source-level debugging environment. To enjoy this feature, launch the SailingServer launch config appropriate for your environment (Proxy / No Proxy), then launch the SailingGWT launch configuration in debug mode. After a while it will show a "Development Mode" view that shows all entry points that have been initialized. Double-click on the one you want to debug, and your default browser (hopefully FireFox, because with other browsers the GWT debug plugin tends to be not very stable or not even present) will open.
+9
View File
@@ -6,6 +6,10 @@
[[Smartphone Tracking|wiki/smartphone-tracking]]
[[Sailing Community|wiki/planning/sailing-community]]
[[Monitoring and Improving Data Quality|wiki/data-quality]]
[[ORC|wiki/planning/ORC]]
[[Support Specific Analysis Scenarios|wiki/planning/AnalysisScenarios]]
@@ -20,9 +24,14 @@
[[Advanced Wind Field Analysis|wiki/planning/AdvancedWindFieldAnalysis]]
[[Simulator Integration|wiki/planning/SimulatorIntegration]]
[[ISAF SWC Engagement|wiki/planning/ISAFSWCEngagement]]
[[AirMAX vs. MikroTik|/wiki/planning/AirMAXvsMikroTik]]
[[Scaling by Server Replication|wiki/planning/scalebyreplication]]
[[ISAF-Internal Projects|wiki/planning/ISAFInternalProjects]]
[[Microcopter Integration|wiki/planning/Microcopter]]
+5
View File
@@ -0,0 +1,5 @@
# Engaging with the ISAF Sailing World Cup (SWC)
The ISAF SWC is a potential sponsorship target. While the cup is currently being redesigned, ISAF would like SAP to sponsor the tracking activities. So far, plans are that SwissTiming will be the tracking partner of choice. After two test events in 2013 with SwissTiming (Palma, Santander), there are still a number of open issues to be addressed. Besides a [number of smaller issues](http://bugzilla.sapsailing.com/bugzilla/buglist.cgi?query_format=advanced&order=Importance&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&component=SwissTiming%20Connector&product=Sailing%20Race%20Analytics) there is one major open strategic question. Both, SAP and SwissTiming, would like to operate their mobile tablet solution on the committee boats. However, it doesn't seem a reasonable option to require both tablets to be on board at the same time. How important is the mobile showcase for SAP? How much can and will SwissTiming insist on having their own tablet? To what extent should we aim for a solution where the SAP tablet provides all data required to SwissTiming?
If we engage with the ISAF SWC this will mean about five additional sailing events per year, each about the size and complexity of Kieler Woche. We need to discuss staffing, travel and technology budgets before committing to this.
+20
View File
@@ -0,0 +1,20 @@
# Sailing Community
In order to extend the reach of our sailing activities we want to build a community around our sailing solutions.
## Sailor accounts
tbd.
## Community website
tbd.
## Sharing features
- 'Share with my friends' functionality
- Bookmarkability
## Social media activities
tbd.
+4 -2
View File
@@ -1,7 +1,9 @@
## Scaling by Replication
When we want to offer our live leader board and race board with the "2D Tracking" to a larger audience, we need to work on a scale-out approach. Currently, our limit to scalability is the bandwidth required to transmit the live leader board to many clients because we don't send differences only but always transmit the full leader board. We will be able to handle a certain factor (maybe 10-100) more clients as we can right now by using a differential leader board transmission scheme. However, then, the bandwidth of a single host cannot be further extended by any typical data center.
When we want to offer our live leader board and race board with the "2D Tracking" to a larger audience, we need to work on a scale-out approach. Currently, our limit to scalability is the bandwidth required to transmit the live leader board to many clients because we don't send differences only but always transmit the full leader board. We have been able to handle a certain factor (maybe 10-100) more clients as we did before by using a differential leader board transmission scheme. However, now, the bandwidth of a single host cannot be further extended by any typical data center.
We then need to run the server on multiple hosts, making sure that the state across these nodes is at least eventually consistent. We have a prototypical replication feature that works under "lab conditions" that now needs to be matured to work in production environments.
We then need to run the server on multiple hosts, making sure that the state across these nodes is at least eventually consistent. We have a replication feature that has shown to work at least under the production conditions of the Extreme Sailing Series. We can now build on this to also use replication for a scale-out approach.
It comes in handy that we're now preparing for [moving our landscape to Amazon EC2](http://wiki.sapsailing.com/wiki/amazon-ec2) which Simon is preparing. There, we should be able to quickly launch and stop new replicas. We need to learn how to use load balancing components such as Pound or other typical components used in the EC2 environment.
See bug 523 (http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=523).
+3
View File
@@ -0,0 +1,3 @@
# Simulator Integration
The SAP Sailing Simulator, as can be seen, e.g., [here](http://www.sapsailing.com/gwt/Simulator.html), has a number of features that could nicely be integrated with the SAP Sailing Analytics. For example, at any point in a tracked race the user could ask the simulator for its prediction of the optimal course and then compare that to the course actually sailed.
+4 -1
View File
@@ -5,7 +5,10 @@
## Introduction
## Features
A Feature List collected in September 2013 at the Testevent in Santander can be seen here:
[Feature List RaceCommittee App](/doc/RaceCommittee Feature List.xlsx) (RaceCommittee Feature List, Sep. 2013, Julian Gimbel)
The Feedback a User gave to the Application and the Feedback the user gave to the Applikation and Hardware of SwissTiming can be seen here:
[Feature List RaceCommittee App](/doc/Swiss Timing Race Committee App.docx) (Swiss Timing App and Feedback for SAP RaceCommittee App, Sep. 2013, Julian Gimbel)
## Course Designer
## Etc
+26 -236
View File
@@ -9,248 +9,38 @@ On this page the decisions, architecture and API's for using smartphones as an a
* `race-board-admin`: manual UI based entry of mark passings for the time being, while we do not have a detection algorithm
* `cmd-android-tracking`: client side development branch for the tracking application, which enhances the existent race committee app, server side development of using the RaceLog to create a tracking adapter for Commodity Mobile Devices (CMD) such as smartphones
## Further links
* [Race Board Admin](/wiki/smartphone-tracking/race-board-admin)
* [GPSFixStore](/wiki/smartphone-tracking/gpsfixstore)
* [Servlets](/wiki/smartphone-tracking/servlets)
* [Race Log Events](/wiki/smartphone-tracking/race-log-events)
* [Server-side Architecture](/wiki/smartphone-tracking/server-side-architecture)
* [Tracking App Architecture](/wiki/smartphone-tracking/tracking-app-architecture)
* [To-Do](/wiki/smartphone-tracking/to-do)
## Communication
### Channels
The current plan is to use up to three channels for communicating:
1. [**Servlets:**](/wiki/smartphone-tracking/servlets) Everything that is not directly related to a specific Race (or rather RaceLog) is handled via POST and GET servlets, where the data should be described as JSON. Examples are: Creating a Race, managing Competitors. Ideally, this would on smartphone side however also benefit from the RaceLog-underlying semi-connectedness functionality. _Caveats: replication and persistence!_
1. **Servlets:** Everything that is not directly related to a specific Race (or rather RaceLog) is handled via POST and GET servlets, where the data should be described as JSON. Examples are: Creating a Race, managing Competitors. Ideally, this would on smartphone side however also benefit from the RaceLog-underlying semi-connectedness functionality. _Caveats: replication and persistence!_
2. [**RaceLog:**](wiki/smartphone-tracking/race-log-events) All the "master data" communication concerning one race in particular should piggyback on the existing RaceLog-mechanism, which already deals with semi-connectedness, persistence and replication. Examples for this are: adding competitors to a race, mapping tracking devices to competitors, starting a race, defining the course layout.
2. **RaceLog:** All the "master data" communication concerning one race in particular should piggyback on the existing RaceLog-mechanism, which already deals with semi-connectedness, persistence and replication. Examples for this are: adding competitors to a race, mapping tracking devices to competitors, starting a race, defining the course layout.
3. **Other:** The actual tracking data (perhaps also additional data: wind etc.) also has to be transferred. On client side we want to reuse the communication mechanism which the RaceLog is built on top of. Right now, this is also handed by a [servlet](/wiki/smartphone-tracking/servlets#recordFixes) on server-side, and through the `EventSendingService` on Android-side (which handles semi-connectedness).
3. **Other:** The actual tracking data (perhaps also additional data: wind etc.) also has to be transferred. On client side we want to reuse the communication mechanism which the RaceLog is built on top of.
### Communication during creating a race
![Typical communication between the App, its backend and the SAP Sailing Analytics server during the creation of a race](http://i.imagebanana.com/img/e1blf6xl/Capture.PNG)
## Server-side Architecture
On the server-side, the architecture of smartphone tracking is intended to be open for extension, so that different types of input devices can be used for tracking one race. Currently, some parts are still tightly coupled to smartphone tracking (e.g. `RacingEventService#createTrackedRaceForSmartphoneTracking()`), but these can be refactored to be generic.
Generic device identifiers, that are qualified through a device type, are used for mapping a device to a competitor in the race log. When the race is then created, the OSGi service registry is used to find services to which the appropriate device mappings in the race log are provided, e.g. a smartphone adapter registers a `RaceLogTrackingDeviceHandler` service for the device type `smartphoneImei`, and then recieves all smartphone device mappings from the race log once the race is created. The same OSGi service logic is used to find services that deal with persisting device identifiers, so that loading and persisting race log events can be used for all types of device identifiers.
The reason for using the OSGi service registry is that it enables decentralized implementation of different kinds of device adapters. E.g., implementing a new Igtimi adapter does not mean that you have to modify the object factory for device identifier objects in the persistence bundle, but simply register a new service from within your own bundle. This is more hindering than helpful in this stage of development, but - in future - means that other device adapters could be developed without having to touch the Sailing Analytics core code, so a vendor of tracking devices could recieve a current Sailing Analytics version as an SDK and implement additional bundles only.
### Current communication process
1. create a flexible or regatta leaderboard in the Admin Console (and also a series with races if using a regatta leaderboard)
2. [create a persistent competitor](/wiki/smartphone-tracking/servlets#createPersistentCompetitor)
3. [create a race-log-tracked race](/wiki/smartphone-tracking/servlets#createRace)
4. [register the competitors](/wiki/smartphone-tracking/race-log-events#Persistent-Competitor-Registered)
5. [set the course](/wiki/smartphone-tracking/race-log-events#Course-Design-Changed)
5. [start the race](/wiki/smartphone-tracking/race-log-events#Pre-Race-Phase-Ended)
6. [set the start time](/wiki/smartphone-tracking/race-log-events#Start-Time)
7. [ping the marks](/wiki/smartphone-tracking/servlets#pingMark)
8. [send the competitor fixes](/wiki/smartphone-tracking/servlets#recordFixes)
9. [set the mark rounding times](/wiki/smartphone-tracking/race-board-admin)
10. view the race in the race viewer
11. [after a server restart, reload the race from the MongoDB](/wiki/smartphone-tracking/gpsfixstore)
## Mark Passings
Without a tracking provider that implements a mark passing algorithm, we have to identify mark passings on our own in the context of smartphone tracking, for Sailing Analytics to be able to do any analytics at all. While the mid-term goal definitely is to implement such a detection algorithm, as a workaround a UI entry option has been provided, that can be found in the branch `race-board-admin`, in which the mark passings can be set by hand. This can be accessed by clicking the _Administer Race_ button of a race in the leaderboard detail table, which can be found in the leaderboard configuration panel of the admin console.
## Servlets
The servlets are listed in the chronological order that they can be called. First, persistent competitors are needed, so that they can later on be registered for the race (`createPersistentCompetitor`). These can then be listed (`getPersistentCompetitors`). When this is completed, a race in its pre-race phase can be created (`createRace`), which is then also shown in `getRaceLogsInPreRacePhase`. By selecting one of these RaceLogs and sending `RaceLogPersistentCompetitorRegisteredEvent`s and a `RaceLogCourseDefinitionChangedEvent`, the race can then be moved from its pre race phase into the tracking phase by sending the `RaceLogPreRacePhaseEndedEvent` via the race log. From this moment on - given the fact that all necessary information was already included in the RaceLog, tracking data can be added to the race. On the one hand, marks can be pinged (`pingMark`, for which knowledge of the course layout is necessary, which can be accessed through `currentcourse`), on the other hand fixes of competitors can be recorded (`recordFixes`). Pinging the marks is of course only the first step, the plan is to allow the mapping of tracking devices such as smartphones to marks as well as competitors.
**Remember to set a start time via the race log**, as the race map relies heavily on it (e.g., the course based wind estimation needs a start time, and without any other wind sources a missing start time results in no boats and marks being displayed at all, as the `SailingService#getRaceMapData()` then fails with a no wind exception).
To test the servlets manually, in addition to the unit tests, the chrome plugin [Postman](https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm) in combination with this collection of [HTTP requests](http://www.getpostman.com/collections/d4eb46b5e4f566e6b7a3) for the servlets described below may come in handy.
### `/sailingserver/racelogtracking/createPersistentCompetitor`
`CreatePersistentCompetitorPostServlet`
**Expects**
* POST request body: Competitor-JSON with a nested Boat-JSON and Team-JSON (see `CompetitorJsonDeserializer`)
```
{"id": "",
"name": "Competitor Fredrik",
"sailID": "1234",
"team": {
"name": "Team Fredrik",
"sailors": [
{
"name": "Fredrik",
"description": "",
"dateOfBirth": 2394820480284,
"nationality": {"IOC": "GER"}
}
]
},
"boat": {
"name": "Boat Fredrik",
"sailID": "1234",
"boatClass": {
"name": "49er"
}
}
}
```
**Returns**
* `200` Competitor created, body: Competitor as JSON
**Throws**
* `400` Invalid JSON in request
**Comments**
* The server choses the id, so this field can be left blank / not supplied
### `/sailingserver/racelogtracking/getPersistentCompetitors`
`PersistentCompetitorsGetServlet`
**Expects**
* GET request
**Returns**
* `200` body: JSON array of Competitor objects
### `/sailingserver/racelogtracking/getRaceLogsInPreRacePhase`
`RaceLogsInPreRacePhaseGetServlet`
**Expects**
* GET request
**Returns**
* `200` body: JSON array of RaceGroups
### `/sailingserver/racelogtracking/createRace?leaderboard=<leaderboardName>&raceColumn=<raceColumnName>&fleet=<fleetName>`
`CreateRaceLogTrackedRacePostServlet`
**Expects**
* POST request
**Returns**
* `200` RaceGroup JSON, containing only the Series/Row/Cell structure for the newly created race
**Throws**
* `404` Leaderboard does not exist, RaceColumn does not exist (if the leaderboard is a `RegattaLeaderboard`)
* `409` The RaceColumn already is linked to a tracked race`
**Comments**
* The behaviour of the servlet depends on the type of leaderboard with the name `leaderboardName`. If this is a `RegattaLeaderboard`, then the RaceColumn with the name `raceColumnName` has to already exist. If it is a `FlexibleLeaderboard`, the RaceColumn will be created if it does not yet exist.
### `/smartphone/recordFixes`
`RecordFixesPostServlet`
**Precondition**
* race has already been started by sending a `RaceLogPreRacePhaseEndedEvent`
**Expects**
* POST request body: DeviceIdentifierWithGPSFixMovingsDTO as JSON
```
{"imei": "12345678",
"data": [
{"unixtime": 2394820480284,
"nmea" : "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A"
},
{"unixtime": 2394820480285,
"nmea" : "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A"
}
]
}
```
**Returns**
* `200`: fixes recorded
**Throws**
* `409` Device not mapped to race and competitor
### `/sailingserver/racelogtracking/pingMark?leaderboard=<leaderboardName>&raceColumn=<raceColumnName>&fleet=<fleetName>`
`PingMarkPostServlet`
**Precondition**
* race has already been started by sending a `RaceLogPreRacePhaseEndedEvent` and has not been stopped yet
**Expects**
* POST request body: PingMark as JSON
```
{
"markStringId": "Leeward Mark"
"gpsFix": {
"unixtime": 1375951388465,
"nmea": "$GPRMC,084308,A,41.771311,N,86.933174,E,0.0,0.0,080813,0,W*4D"
},
}
```
**Returns**
* `200`: mark pinged
**Throws**
* `404` Leaderboard, RaceColumn or Fleet not found
* `409` Race not in tracking state
### `/sailingserver/rc/currentcourse`
`CourseJsonExportServlet`
**Expects**
* GET request
* URL Parameters leaderboard, raceColumn and fleet
**Returns**
* `200` body: CourseBase JSON
**Comments**
* Does not use the latest `RaceLogCourseDefinitionChangedEvent`, but instead requires the presence of a `TrackedRace` for this racelog, from which the `RaceDefinition` is acquired to get the course. We could build our own servlet, but as we can only ping the marks after having created the race anyway, this isn't too much of a problem.
## RaceLog Events
### RaceLogPersistentCompetitorRegisteredEvent
Includes a `Competitor` as well a `SmartphoneIdentifier`. On the one hand, every comptitor that is thus registered will be included in the `RaceDefinition` as soon as the race is created, on the other hand the mapping between smartphone identifier (e.g. IMEI for european phones) and competitor is later used for mapping the incoming fixes to the correct competitor.
### RaceLogPreRacePhaseEndedEvent
This does not include any additional data, and merely indicates that the race can be transformed from its pre-race definition state (e.g. waiting for competitors to register, waiting for boat class, waiting for course definition) to an actual race, where no additional competitors can be added, the boat class is fixes, and tracking may begin. This event is picked up by the `RaceLogRaceTracker`, which then creates the actual tracked race from the data in the RaceLog. For successful creation, at least one competitor has to be registered, and a course must have been set through a `RaceLogCourseDefinitionChangedEvent`.
##Tracking App Use Cases
![Use Cases](http://i.imagebanana.com/img/bda86luu/Use_Cases.jpg)
##Tracking App Architecture
![Activities and Fragments of the tracking app](http://i.imagebanana.com/img/20r2qf7g/overview_Fragments_and_Activities.JPG)
### `LocationChangedReceiver`
This class gets notified of location changes via intents. Depending on whether the App is in local or remote broadcast mode the corresponding service is started by using intents.
### `LocalLocationUpdateService`
Stores the location Information in a File by using the `FileWriterUtils` class.
### `NetworklocationUpdateService`
Sends the location information to a web service.
### `SAP Sailor Tracker Service`
Background process for starting, pausing and stopping tracking. Registers all receivers on a pending intent, which is send periodically.
### `AsyncJsonPostTask`
Async task that handles the execution of post requests with Json content.
### `OnlineDataManager`
Enables accessing of data from a `DataStore`. Loads data from Servlets using GET-Requests using a `DataLoader`. For an example how to use the `OnlineDataManager` refer to `SelectRaceFragment`, which loads the RaceLogsInPreRacePhase so that the user can select the race he wants to take part in.
### `DataStore`
Interface for the `DataStore` which stores all data that is relevant for the App (managed Races, Competitors, ...)
Implementation: `InMemoryDataStore`
### `DataLoader`
`AsyncDataLoader` which does an HTTP GET to a given URL, parses the data (with a `DataParser`) and sends the data to a `DataHandler`.
### `AppPreferences`
Helper Class for accessing the App Preferences specified in settings_view.xml
### `ListFragmentWithDataManager`
Base Class, which provides easy access to the data manager for a Fragment, which wants to display the data in a List.
Used for example in the `Select*Fragments`.
## ToDo
### Server
* only one competitor registered, even though multiple RegisteredEvents in RaceLog?
* change names of *Events, as they are not events -> also change names of abstract base classes
* use extension serializers
* exchange auto JSON to BSON conversion in MongoObjectFactory / DomainObjectFactory for something suited for productive use
* editing course in the RaceBoardAdmin
* mapping devices to marks
* generic method for registering listener for NMEA sentence types (e.g. to then process wind) -> move servlet for receiving NMEA out of smartphoneadapter
* accepting / removing competitors
* for this we first need racelog replication back to all clients
* also, not everybody should be able to do this -> see user management
* user management (Competitors as users, credentials so not everybody can do everything)
* -> integrate with OAuth, ISAF competitors etc.?
* security (not everybody can start race, goes hand in hand with user management)
* support dynamic mapping of smartphone to competitor -> so that it can change during the race
* support other input channels (e.g. Igtimi)
* only transfer competitor ID for registering etc. instead of whole competitor
### Android
* change format of sent position Data to degrees and minutes
* reuse existing course design functionality to create RaceLogCourseDesignChangedEvent before sending RaceLogPreRacePhaseEndedEvent
* abstract sending service, so that all POST / GET requests and not only RaceLogEvents can be sent using the semi-connectedness functionality --> just write JSONObjects/Strings directly into the file. The Servlet has to handle deserialization and the client doesn't have to know what type of object it is after having saved it (is this really the case?)
* simplify settings
* login/register Activity for registering the Team and Sailor the first time the App is started
Without a tracking provider that implements a mark passing algorithm, we have to identify mark passings on our own in the context of smartphone tracking, for Sailing Analytics to be able to do any analytics at all. While the mid-term goal definitely is to implement such a detection algorithm, as a workaround a UI entry option has been provided, that can be found in the branch `race-board-admin`, in which the mark passings can be set by hand. This can be accessed by clicking the _Administer Race_ button of a race in the leaderboard detail table, which can be found in the leaderboard configuration panel of the admin console.
+16
View File
@@ -0,0 +1,16 @@
# GPSFixStore
[[_TOC_]]
## Purpose
The GPSFixStore functions similar to the WindStore. A `TrackedRaceImpl` expects such a store for instantation, and then uses this store to resolve the corresponding `Track`. On replicas, a `Empty*Store` is used, on the master instance a `Mongo*Store` is used. This tries to load existing fixes from the MongoDB, and will write any new incoming fixes to the MongoDB.
## Loading race-log-tracked races in the Admin Console
After restarting the server, a tracked race can now be fully recovered from its race log, and the fixes of marks and competitors stored through the GPSFixStore.
To do this
1. open the Admin Console
2. switch to the _Leaderboard Configuration_ tab
3. select a leaderboard
4. click _Reload all RaceLogs_ (has to be done to reload the [Competitor Registered](/wiki/smartphone-tracking/race-log-events#Persistent-Competitor-Registered) events, which contain device identifiers for which deserializers need to be registered through the OSGi service registry -> these are not available when the `RacingEventService` initially loads all data from the database)
<img src="/wiki/images/load-racelog-tracked-race.png">
@@ -0,0 +1,11 @@
# Race Board Admin
[[_TOC_]]
## Purpose
This UI frontend can be used to administer a tracked race. At this point, this means manually setting mark passing times for competitors. It looks similar to the normal race viewer, but requires authentication (like the Admin Console).
## Branch
`race-board-admin`
## Accessing the Race Board Admin
<img src="/wiki/images/accessing-race-board-admin.png"/>
@@ -0,0 +1,27 @@
# RaceLog Events
[[_TOC_]]
## Persistent Competitor Registered
`RaceLogPersistentCompetitorRegisteredEvent`
Includes a `Competitor` as well a `SmartphoneIdentifier`. On the one hand, every comptitor that is thus registered will be included in the `RaceDefinition` as soon as the race is created, on the other hand the mapping between smartphone identifier (e.g. IMEI for european phones) and competitor is later used for mapping the incoming fixes to the correct competitor.
## Pre Race Phase Started
`RaceLogPreRacePhaseStartedEvent`
This event is added to the race log automatically by the server when calling the [createRace](/wiki/smartphone-tracking/servlets#createRace) servlet, to mark this race as race-log-tracked. It also includes the race name and boat class, so that the race can be properly reloaded after a server restart.
## Pre Race Phase Ended
`RaceLogPreRacePhaseEndedEvent`
This does not include any additional data, and merely indicates that the race can be transformed from its pre-race definition state (e.g. waiting for competitors to register, waiting for boat class, waiting for course definition) to an actual race, where no additional competitors can be added, the boat class is fixes, and tracking may begin. This event is picked up by the `RaceLogRaceTracker`, which then creates the actual tracked race from the data in the RaceLog. For successful creation, at least one competitor has to be registered, and a course must have been set through a `RaceLogCourseDefinitionChangedEvent`.
## Course Design Changed
`RaceLogCourseDesignChangedEvent`
This existing event is used to set the course definition, and is required before the race can be started.
## Start Time
`RaceLogStartTimeEvent`
This existing event should be used to set the start time, before attempting to view the race in the race viewer, as otherwise the time slider won't work.
@@ -0,0 +1,7 @@
# Server-side Architecture
On the server-side, the architecture of smartphone tracking is intended to be open for extension, so that different types of input devices can be used for tracking one race.
Generic device identifiers, that are qualified through a device type, are used for mapping a device to a competitor in the race log. When the race is then created, the OSGi service registry is used to find services to which the appropriate device mappings in the race log are provided, e.g. a smartphone adapter registers a `RaceLogTrackingDeviceHandler` service for the device type `smartphoneImei`, and then recieves all smartphone device mappings from the race log once the race is created. The same OSGi service logic is used to find services that deal with persisting device identifiers, so that loading and persisting race log events can be used for all types of device identifiers.
The reason for using the OSGi service registry is that it enables decentralized implementation of different kinds of device adapters. E.g., implementing a new Igtimi adapter does not mean that you have to modify the object factory for device identifier objects in the persistence bundle, but simply register a new service from within your own bundle. This is more hindering than helpful in this stage of development, but - in future - means that other device adapters could be developed without having to touch the Sailing Analytics core code, so a vendor of tracking devices could recieve a current Sailing Analytics version as an SDK and implement additional bundles only.
+152
View File
@@ -0,0 +1,152 @@
# Servlets
[[_TOC_]]
## createPersistentCompetitor
URL: `/sailingserver/racelogtracking/createPersistentCompetitor`
Servlet: `CreatePersistentCompetitorPostServlet`
**Expects**
* POST request body: Competitor-JSON with a nested Boat-JSON and Team-JSON (see `CompetitorJsonDeserializer`)
```
{"id": "",
"name": "Competitor Fredrik",
"sailID": "1234",
"team": {
"name": "Team Fredrik",
"sailors": [
{
"name": "Fredrik",
"description": "",
"dateOfBirth": 2394820480284,
"nationality": {"IOC": "GER"}
}
]
},
"boat": {
"name": "Boat Fredrik",
"sailID": "1234",
"boatClass": {
"name": "49er"
}
}
}
```
**Returns**
* `200` Competitor created, body: Competitor as JSON
**Throws**
* `400` Invalid JSON in request
**Comments**
* The server choses the id, so this field can be left blank / not supplied
## getPersistentCompetitors
URL: `/sailingserver/racelogtracking/getPersistentCompetitors`
Servlet: `PersistentCompetitorsGetServlet`
**Expects**
* GET request
**Returns**
* `200` body: JSON array of Competitor objects
## getRaceLogsInPreRacePhase
URL: `/sailingserver/racelogtracking/getRaceLogsInPreRacePhase`
Servlet: `RaceLogsInPreRacePhaseGetServlet`
**Expects**
* GET request
**Returns**
* `200` body: JSON array of RaceGroups
## createRace
URL: `/sailingserver/racelogtracking/createRace?leaderboard=<leaderboardName>&raceColumn=<raceColumnName>&fleet=<fleetName>`
Servlet: `CreateRaceLogTrackedRacePostServlet`
**Expects**
* POST request
**Returns**
* `200` RaceGroup JSON, containing only the Series/Row/Cell structure for the newly created race
**Throws**
* `404` Leaderboard does not exist, RaceColumn does not exist (if the leaderboard is a `RegattaLeaderboard`)
* `409` The RaceColumn already is linked to a tracked race`
**Comments**
* The behaviour of the servlet depends on the type of leaderboard with the name `leaderboardName`. If this is a `RegattaLeaderboard`, then the RaceColumn with the name `raceColumnName` has to already exist. If it is a `FlexibleLeaderboard`, the RaceColumn will be created if it does not yet exist.
## recordFixes
URL: `/smartphone/recordFixes`
Servlet: `RecordFixesPostServlet`
**Precondition**
* race has already been started by sending a `RaceLogPreRacePhaseEndedEvent`
**Expects**
* POST request body: DeviceIdentifierWithGPSFixMovingsDTO as JSON
```
{"imei": "12345678",
"data": [
{"unixtime": 2394820480284,
"nmea" : "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A"
},
{"unixtime": 2394820480285,
"nmea" : "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A"
}
]
}
```
**Returns**
* `200`: fixes recorded
**Throws**
* `409` Device not mapped to race and competitor
## pingMark
URL: `/sailingserver/racelogtracking/pingMark?leaderboard=<leaderboardName>&raceColumn=<raceColumnName>&fleet=<fleetName>`
Servlet: `PingMarkPostServlet`
**Precondition**
* race has already been started by sending a `RaceLogPreRacePhaseEndedEvent` and has not been stopped yet
**Expects**
* POST request body: PingMark as JSON
```
{
"markStringId": "Leeward Mark"
"gpsFix": {
"unixtime": 1375951388465,
"nmea": "$GPRMC,084308,A,41.771311,N,86.933174,E,0.0,0.0,080813,0,W*4D"
},
}
```
**Returns**
* `200`: mark pinged
**Throws**
* `404` Leaderboard, RaceColumn or Fleet not found
* `409` Race not in tracking state
## currentcourse
URL: `/sailingserver/rc/currentcourse`
Servlet: `CourseJsonExportServlet`
**Precondition**
* Race must have been started through a `RaceLogPreRacePhaseEndedEvent`
**Expects**
* GET request
* URL Parameters leaderboard, raceColumn and fleet
**Returns**
* `200` body: CourseBase JSON
**Comments**
* Does not use the latest `RaceLogCourseDefinitionChangedEvent`, but instead requires the presence of a `TrackedRace` for this racelog, from which the `RaceDefinition` is acquired to get the course. We could build our own servlet, but as we can only ping the marks after having created the race anyway, this isn't too much of a problem.
+27
View File
@@ -0,0 +1,27 @@
# To-Do
[[_TOC_]]
## Server
* change names of *Events, as they are not events -> also change names of abstract base classes
* use extension serializers
* exchange auto JSON to BSON conversion in MongoObjectFactory / DomainObjectFactory for something suited for productive use
* editing course in the RaceBoardAdmin
* mapping devices to marks
* generic method for registering listener for NMEA sentence types (e.g. to then process wind) -> move servlet for receiving NMEA out of smartphoneadapter
* accepting / removing competitors
* for this we first need racelog replication back to all clients
* also, not everybody should be able to do this -> see user management
* user management (Competitors as users, credentials so not everybody can do everything)
* -> integrate with OAuth, ISAF competitors etc.?
* security (not everybody can start race, goes hand in hand with user management)
* support dynamic mapping of smartphone to competitor -> so that it can change during the race
* support other input channels (e.g. Igtimi)
* only transfer competitor ID for registering etc. instead of whole competitor
## Android
* use EventSendingService for all outgoing requests, not only race log
* change format of sent position Data to degrees and minutes
* reuse existing course design functionality to create RaceLogCourseDesignChangedEvent before sending RaceLogPreRacePhaseEndedEvent
* abstract sending service, so that all POST / GET requests and not only RaceLogEvents can be sent using the semi-connectedness functionality --> just write JSONObjects/Strings directly into the file. The Servlet has to handle deserialization and the client doesn't have to know what type of object it is after having saved it (is this really the case?)
* simplify settings
* login/register Activity for registering the Team and Sailor the first time the App is started
@@ -0,0 +1,41 @@
# Tracking App Architecture
[[_TOC_]]
## Activities and Fragments of the tracking app
![Activities and Fragments of the tracking app](http://i.imagebanana.com/img/20r2qf7g/overview_Fragments_and_Activities.JPG)
## Communication during the race
![Typical communication between the App, its backend and the SAP Sailing Analytics server during the creation of a race](http://i.imagebanana.com/img/e1blf6xl/Capture.PNG)
## Components
### `LocationChangedReceiver`
This class gets notified of location changes via intents. Depending on whether the App is in local or remote broadcast mode the corresponding service is started by using intents.
### `LocalLocationUpdateService`
Stores the location Information in a File by using the `FileWriterUtils` class.
### `NetworklocationUpdateService`
Sends the location information to a web service.
### `SAP Sailor Tracker Service`
Background process for starting, pausing and stopping tracking. Registers all receivers on a pending intent, which is send periodically.
### `AsyncJsonPostTask`
Async task that handles the execution of post requests with Json content.
### `OnlineDataManager`
Enables accessing of data from a `DataStore`. Loads data from Servlets using GET-Requests using a `DataLoader`. For an example how to use the `OnlineDataManager` refer to `SelectRaceFragment`, which loads the RaceLogsInPreRacePhase so that the user can select the race he wants to take part in.
### `DataStore`
Interface for the `DataStore` which stores all data that is relevant for the App (managed Races, Competitors, ...)
Implementation: `InMemoryDataStore`
### `DataLoader`
`AsyncDataLoader` which does an HTTP GET to a given URL, parses the data (with a `DataParser`) and sends the data to a `DataHandler`.
### `AppPreferences`
Helper Class for accessing the App Preferences specified in settings_view.xml
### `ListFragmentWithDataManager`
Base Class, which provides easy access to the data manager for a Fragment, which wants to display the data in a List.
Used for example in the `Select*Fragments`.
+3 -1
View File
@@ -12,4 +12,6 @@ Now push your changes to the remote Git repository. It will take some time befor
## List of Theses
* [Server-side Integration of Mobile Devices](/doc/theses/20130210_Teschke_Server-side_Integration_Mobile_Devices.pdf) (Bachelor Thesis, Feb 2013, Fredrik Teschke)
* [Server-side Integration of Mobile Devices](/doc/theses/20130210_Teschke_Server-side_Integration_Mobile_Devices.pdf) (Bachelor Thesis, Feb 2013, Fredrik Teschke)
* [Tracking Sailing Races with mobile Devices](/doc/theses/20130913_Bross_Tracking_Sailing_Races_with_Mobile_Devices.pdf) (T2000_2 Project Thesis, Sep 2013, Jan Broß)