diff --git a/configuration/buildAndUpdateProduct.sh b/configuration/buildAndUpdateProduct.sh index ebb9d9a1c13..34968707604 100755 --- a/configuration/buildAndUpdateProduct.sh +++ b/configuration/buildAndUpdateProduct.sh @@ -61,6 +61,7 @@ HAS_OVERWRITTEN_TARGET=0 TARGET_SERVER_NAME=$active_branch gwtcompile=1 +onegwtpermutationonly=0 testing=1 clean="clean" offline=0 @@ -68,9 +69,10 @@ proxy=0 extra='' if [ $# -eq 0 ]; then - echo "buildAndUpdateProduct [-g -t -o -c -m -n -l ] [build|install|all|hot-deploy|remote-deploy]" + echo "buildAndUpdateProduct [-b -g -t -o -c -m -n -l ] [build|install|all|hot-deploy|remote-deploy]" echo "" echo "-g Disable GWT compile, no gwt files will be generated, old ones will be preserved." + echo "-b Build GWT permutation only for one browser and English language." echo "-t Disable tests" echo "-o Enable offline mode (does not work for tycho surefire plugin)" echo "-c Disable cleaning (use only if you are sure that no java file has changed)" @@ -104,12 +106,13 @@ echo PROJECT_HOME is $PROJECT_HOME echo SERVERS_HOME is $SERVERS_HOME echo BRANCH is $active_branch -options=':gtocpm:n:l:s:w:' +options=':bgtocpm:n:l:s:w:' while getopts $options option do case $option in g) gwtcompile=0;; t) testing=0;; + b) onegwtpermutationonly=1;; o) offline=1;; c) clean="";; p) proxy=1;; @@ -146,15 +149,15 @@ if [[ "$@" == "hot-deploy" ]]; then exit fi + if [[ $HAS_OVERWRITTEN_TARGET -eq 1 ]]; then + active_branch=$TARGET_SERVER_NAME + fi + if [ ! -d $SERVERS_HOME/$active_branch/plugins ]; then echo "Could not find target directory $SERVERS_HOME/$active_branch/plugins!" exit fi - if [[ $HAS_OVERWRITTEN_TARGET -eq 1 ]]; then - active_branch=$TARGET_SERVER_NAME - fi - # locate old bundle BUNDLE_COUNT=`find $SERVERS_HOME/$active_branch/plugins -maxdepth 1 -name "${OSGI_BUNDLE_NAME}_*.jar" | wc -l` OLD_BUNDLE=`find $SERVERS_HOME/$active_branch/plugins -maxdepth 1 -name "${OSGI_BUNDLE_NAME}_*.jar"` @@ -270,6 +273,21 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then if [ $gwtcompile -eq 1 ]; then echo "INFO: Compiling GWT (rm -rf com.sap.sailing.gwt.ui/com.sap.sailing.*)" rm -rf com.sap.sailing.gwt.ui/com.sap.sailing.* + if [ $onegwtpermutationonly -eq 1 ]; then + echo "INFO: Patching .gwt.xml files such that only one GWT permutation needs to be compiled" + for i in com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/*.gwt.xml; do + cp $i $i.bak + cat $i | sed -e 's/^[ ]*[ ]*$/ /' >$i.sed + mv $i.sed $i + done + else + echo "INFO: Patching .gwt.xml files such that all GWT permutations are compiled" + for i in com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/*.gwt.xml; do + cp $i $i.bak + cat $i | sed -e 's/ //' >$i.sed + mv $i.sed $i + done + fi else echo "INFO: GWT Compilation disabled" extra="-Pdebug.no-gwt-compile" @@ -298,6 +316,14 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then echo "Using following command: mvn $extra -fae -s $MAVEN_SETTINGS $clean install" mvn $extra -fae -s $MAVEN_SETTINGS $clean install 2>&1 | tee $START_DIR/build.log + if [ $gwtcompile -eq 1 ]; then + # Now move back the backup .gwt.xml files before they were (maybe) patched + for i in com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/*.gwt.xml; do + echo "INFO: restoring backup copy of $i after it was patched before" + mv -v $i.bak $i + done + fi + echo "Build complete. Do not forget to install product..." fi @@ -344,11 +370,14 @@ if [[ "$@" == "install" ]] || [[ "$@" == "all" ]]; then rm -rf $ACDIR/org.eclipse.* rm -rf $ACDIR/configuration/org.eclipse.* + # always overwrite start and stop scripts as they + # should never contain any custom logic + cp -v $PROJECT_HOME/java/target/start $ACDIR/ + cp -v $PROJECT_HOME/java/target/stop $ACDIR/ + cp -v $PROJECT_HOME/java/target/status $ACDIR/ + if [ ! -f "$ACDIR/env.sh" ]; then cp -v $PROJECT_HOME/java/target/env.sh $ACDIR/ - cp -v $PROJECT_HOME/java/target/start $ACDIR/ - cp -v $PROJECT_HOME/java/target/stop $ACDIR/ - cp -v $PROJECT_HOME/java/target/status $ACDIR/ fi if [ ! -f $ACDIR/no-overwrite ]; then @@ -363,9 +392,6 @@ if [[ "$@" == "install" ]] || [[ "$@" == "all" ]]; then cp -v $PROJECT_HOME/configuration/mongodb.cfg $ACDIR/ cp -v $PROJECT_HOME/java/target/env.sh $ACDIR/ - cp -v $PROJECT_HOME/java/target/start $ACDIR/ - cp -v $PROJECT_HOME/java/target/stop $ACDIR/ - cp -v $PROJECT_HOME/java/target/status $ACDIR/ cp -v $PROJECT_HOME/java/target/udpmirror $ACDIR/ cp -v $PROJECT_HOME/java/target/http2udpmirror $ACDIR diff --git a/doc/RaceCommittee Feature List.xlsx b/doc/RaceCommittee Feature List.xlsx new file mode 100644 index 00000000000..1a1a1fd521b Binary files /dev/null and b/doc/RaceCommittee Feature List.xlsx differ diff --git a/doc/SAPSailingAnalyticsArchitecture_Short.pptx b/doc/SAPSailingAnalyticsArchitecture_Short.pptx new file mode 100755 index 00000000000..ea6fd1d58c0 Binary files /dev/null and b/doc/SAPSailingAnalyticsArchitecture_Short.pptx differ diff --git a/doc/Swiss Timing Race Committee App.docx b/doc/Swiss Timing Race Committee App.docx new file mode 100644 index 00000000000..4cb663e44a1 Binary files /dev/null and b/doc/Swiss Timing Race Committee App.docx differ diff --git a/doc/theses/20130210_Teschke_Server-side_Integration_Mobile_Devices.pdf b/doc/theses/20130210_Teschke_Server-side_Integration_Mobile_Devices.pdf new file mode 100644 index 00000000000..634bec5e915 Binary files /dev/null and b/doc/theses/20130210_Teschke_Server-side_Integration_Mobile_Devices.pdf differ diff --git a/doc/theses/20130913_Bross_Tracking_Sailing_Races_with_Mobile_Devices.pdf b/doc/theses/20130913_Bross_Tracking_Sailing_Races_with_Mobile_Devices.pdf new file mode 100755 index 00000000000..9895bf632d4 Binary files /dev/null and b/doc/theses/20130913_Bross_Tracking_Sailing_Races_with_Mobile_Devices.pdf differ diff --git a/home.md b/home.md index ab68bb635dc..eb704525cc0 100644 --- a/home.md +++ b/home.md @@ -18,16 +18,21 @@ Like businesses, sailors need the latest information to make strategic decisions * Information for Developers * [[Cook Book|wiki/cook-book]] * [[OnBoarding Information|wiki/onboarding]] + * [[UI Tests with Selenium|wiki/selenium-ui-tests]] * [[Typical Development Scenarios|wiki/typical-development-scenarios]] * [[Server Replication|wiki/server-replication]] * [[Configure Races on Server|wiki/typical-development-scenarios]] * [[Development Environment|wiki/development-environment]] + * [[Working with GWT Locally|wiki/local-gwt]] * [[Mobile Development|wiki/mobile-development]] * General Information * [[Architecture and Infrastructure|wiki/architecture-and-infrastructure]] * [[Sailing Domain Algorithms|wiki/sailing-domain-algorithms]] * [[Inventory|wiki/inventar-liste]] * [[Smartphone Tracking|wiki/smartphone-tracking]] + * [[Racecommittee App|wiki/racecommittee-app]] + * [[Web Services API|wiki/sailing-webservices]] + * [[Theses (Bachelor, Master, ...)|wiki/theses]] * Planning and Event Information * [[Project Planning (bigger development)|wiki/planning]] * [[General Event Planning|wiki/general-event-planning]] @@ -40,4 +45,4 @@ Like businesses, sailors need the latest information to make strategic decisions * [Maven Repository Browser](http://maven.sapsailing.com/maven/) * [Main Sailing Website](http://www.sapsailing.com) * [Visitor Statistics](http://analysis.sapsailing.com/) -* [Traffic and CPU for app01](http://mrtg.sapsailing.com/) \ No newline at end of file +* [Traffic and CPU for app01](http://mrtg.sapsailing.com/) diff --git a/java/com.google.gwt.osgi/.classpath b/java/com.google.gwt.osgi/.classpath index 891b0029b64..7d23d84433e 100755 --- a/java/com.google.gwt.osgi/.classpath +++ b/java/com.google.gwt.osgi/.classpath @@ -2,8 +2,6 @@ - - diff --git a/java/com.google.gwt.osgi/META-INF/MANIFEST.MF b/java/com.google.gwt.osgi/META-INF/MANIFEST.MF index cdfed988e5a..ad79717c61c 100755 --- a/java/com.google.gwt.osgi/META-INF/MANIFEST.MF +++ b/java/com.google.gwt.osgi/META-INF/MANIFEST.MF @@ -7,10 +7,7 @@ Bundle-Vendor: GOOGLE Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Bundle-ClassPath: lib/gwt-dev.jar, lib/gwt-user.jar, - lib/validation-api-1.0.0.GA-sources.jar, - lib/validation-api-1.0.0.GA.jar, . -Eclipse-BuddyPolicy: registered Export-Package: com.gargoylesoftware.htmlunit, com.gargoylesoftware.htmlunit.attachment, com.gargoylesoftware.htmlunit.gae, @@ -601,4 +598,6 @@ Export-Package: com.gargoylesoftware.htmlunit, org.mortbay.util, org.mortbay.util.ajax, org.mortbay.xml -Require-Bundle: javax.servlet;bundle-version="2.5.0";visibility:=reexport +Require-Bundle: javax.validation;bundle-version="1.0.0" +Import-Package: javax.servlet;version="2.5.0", + javax.servlet.http;version="2.5.0" diff --git a/java/com.google.gwt.osgi/build.properties b/java/com.google.gwt.osgi/build.properties index f280c1b9a3a..6c4eae4a192 100755 --- a/java/com.google.gwt.osgi/build.properties +++ b/java/com.google.gwt.osgi/build.properties @@ -1,6 +1,4 @@ bin.includes = META-INF/,\ .,\ lib/gwt-dev.jar,\ - lib/gwt-user.jar,\ - lib/validation-api-1.0.0.GA-sources.jar,\ - lib/validation-api-1.0.0.GA.jar + lib/gwt-user.jar diff --git a/java/com.google.gwt.osgi/lib/validation-api-1.0.0.GA-sources.jar b/java/com.google.gwt.osgi/lib/validation-api-1.0.0.GA-sources.jar deleted file mode 100755 index 43611a2a501..00000000000 Binary files a/java/com.google.gwt.osgi/lib/validation-api-1.0.0.GA-sources.jar and /dev/null differ diff --git a/java/com.google.gwt.osgi/lib/validation-api-1.0.0.GA.jar b/java/com.google.gwt.osgi/lib/validation-api-1.0.0.GA.jar deleted file mode 100755 index 1ff2dd718e2..00000000000 Binary files a/java/com.google.gwt.osgi/lib/validation-api-1.0.0.GA.jar and /dev/null differ diff --git a/java/com.google.gwt.user.osgi/.project b/java/com.google.gwt.user.osgi/.project new file mode 100644 index 00000000000..7e721403906 --- /dev/null +++ b/java/com.google.gwt.user.osgi/.project @@ -0,0 +1,28 @@ + + + com.google.gwt.user.osgi + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/java/com.sap.sailing.declination.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.declination.test/META-INF/MANIFEST.MF index 08975c37cb4..7084100389d 100755 --- a/java/com.sap.sailing.declination.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.declination.test/META-INF/MANIFEST.MF @@ -6,8 +6,7 @@ Bundle-Version: 1.0.0.qualifier Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Fragment-Host: com.sap.sailing.declination +Require-Bundle: org.junit4;bundle-version="4.8.2" Import-Package: com.sap.sailing.domain.common, com.sap.sailing.domain.common.impl, - com.sap.sailing.domain.common.quadtree, - junit.framework;version="4.8.1", - org.junit;version="4.8.1" + com.sap.sailing.domain.common.quadtree diff --git a/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/NOAAImporter.java b/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/NOAAImporter.java index 17172360183..86fd5ac0043 100755 --- a/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/NOAAImporter.java +++ b/java/com.sap.sailing.declination/src/com/sap/sailing/declination/impl/NOAAImporter.java @@ -59,6 +59,9 @@ public class NOAAImporter { URL url = new URL(QUERY_URL+"?lon1="+position.getLngDeg()+"&lat1="+position.getLatDeg()+"&startYear=" + calendar.get(Calendar.YEAR) + "&startMonth=" + (calendar.get(Calendar.MONTH) + 1) + "&startDay=" + calendar.get(Calendar.DAY_OF_MONTH)+"&resultFormat=xml"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + conn.setRequestProperty("Accept-Language", "en-US,en;q=0.8"); + conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); final InputStream inputStream = conn.getInputStream(); Document doc = builder.parse(inputStream); diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractTimePoint.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractTimePoint.java index e3bb94e238d..72a9c8307ea 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractTimePoint.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/AbstractTimePoint.java @@ -1,6 +1,5 @@ package com.sap.sailing.domain.common.impl; -import java.text.SimpleDateFormat; import java.util.Comparator; import java.util.Date; @@ -9,8 +8,6 @@ import com.sap.sailing.domain.common.TimePoint; public abstract class AbstractTimePoint implements TimePoint { private static final long serialVersionUID = 8825508619301420378L; - public static SimpleDateFormat TIMEPOINT_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); - public static Comparator TIMEPOINT_COMPARATOR = new SerializableComparator() { private static final long serialVersionUID = 7644726881387366025L; @@ -68,7 +65,7 @@ public abstract class AbstractTimePoint implements TimePoint { @Override public String toString() { - return TIMEPOINT_FORMATTER.format(asDate()); + return asDate().toString(); } /** diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 17f2e879477..1163b1637c0 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -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 null 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 fleetsByName = new HashMap(); @@ -1009,11 +1007,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(identifier.getIdentifier())); loadRaceLogEvents(result, query); - // query for obsolete events - query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(String.format("%s.%s.%s", - identifier.getTemplate().getParentObjectName(), - identifier.getRaceColumnName(), - identifier.getFleetName()))); + // query for events with deprecated identifier format + query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(identifier.getDeprecatedIdentifier())); loadRaceLogEvents(result, query); } catch (Throwable t) { // something went wrong during DB access; report, then use empty new race log @@ -1028,7 +1023,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { for (DBObject o : raceLog.find(query)) { RaceLogEvent raceLogEvent = loadRaceLogEvent((DBObject) o.get(FieldNames.RACE_LOG_EVENT.name())); if (raceLogEvent != null) { - result.add(raceLogEvent); + result.load(raceLogEvent); } } } diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index 540da2d9cee..09ba9c0748e 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -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; } diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ConfirmedFinishPositioningListFinderTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ConfirmedFinishPositioningListFinderTest.java index fbc3b5dbe9c..e77d1e645cd 100644 --- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ConfirmedFinishPositioningListFinderTest.java +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ConfirmedFinishPositioningListFinderTest.java @@ -29,9 +29,9 @@ public class ConfirmedFinishPositioningListFinderTest extends @Override protected List> 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()); } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLog.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLog.java index bef4dd32eda..379133b2f19 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLog.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLog.java @@ -66,4 +66,13 @@ public interface RaceLog extends Track, WithID { void addAllListeners(HashSet listeners); Iterable 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 true 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); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLogFinishPositioningEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLogFinishPositioningEvent.java index 5c92d3e9a9b..cfc2d0af9dd 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLogFinishPositioningEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/RaceLogFinishPositioningEvent.java @@ -8,5 +8,9 @@ import com.sap.sailing.domain.common.impl.Util.Triple; public abstract interface RaceLogFinishPositioningEvent extends RaceLogEvent { - List> getPositionedCompetitors(); + /** + * @return a triple holding the competitor ID, the competitor name and the {@link MaxPointReason} documenting the + * score for the competitor + */ + List> getPositionedCompetitorsIDsNamesMaxPointsReasons(); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/AbortingFlagFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/AbortingFlagFinder.java index c3e606f939f..9c615632204 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/AbortingFlagFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/AbortingFlagFinder.java @@ -12,7 +12,7 @@ public class AbortingFlagFinder extends RaceLogAnalyzer { } @Override - protected RaceLogFlagEvent performAnalyzation() { + protected RaceLogFlagEvent performAnalysis() { if (raceLog.getCurrentPassId() <= RaceLog.DefaultPassId) { return null; } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/ConfirmedFinishPositioningListFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/ConfirmedFinishPositioningListFinder.java index 7784ec86be3..d11a7ca45e1 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/ConfirmedFinishPositioningListFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/ConfirmedFinishPositioningListFinder.java @@ -16,11 +16,11 @@ public class ConfirmedFinishPositioningListFinder extends RaceLogAnalyzer> performAnalyzation() { + protected List> performAnalysis() { for (RaceLogEvent event : getPassEventsDescending()) { if (event instanceof RaceLogFinishPositioningConfirmedEvent) { RaceLogFinishPositioningConfirmedEvent finishPositioningEvent = (RaceLogFinishPositioningConfirmedEvent) event; - return finishPositioningEvent.getPositionedCompetitors(); + return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons(); } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishPositioningListFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishPositioningListFinder.java index 62d0d9c67cb..545e0607875 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishPositioningListFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishPositioningListFinder.java @@ -16,11 +16,11 @@ public class FinishPositioningListFinder extends RaceLogAnalyzer> performAnalyzation() { + protected List> performAnalysis() { for (RaceLogEvent event : getPassEventsDescending()) { if (event instanceof RaceLogFinishPositioningListChangedEvent) { RaceLogFinishPositioningListChangedEvent finishPositioningEvent = (RaceLogFinishPositioningListChangedEvent) event; - return finishPositioningEvent.getPositionedCompetitors(); + return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons(); } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishedTimeFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishedTimeFinder.java index 0181fca9421..a75f215fb3f 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishedTimeFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishedTimeFinder.java @@ -13,7 +13,7 @@ public class FinishedTimeFinder extends RaceLogAnalyzer { } @Override - protected TimePoint performAnalyzation() { + protected TimePoint performAnalysis() { for (RaceLogEvent event : getPassEventsDescending()) { if (event instanceof RaceLogRaceStatusEvent) { RaceLogRaceStatusEvent statusEvent = (RaceLogRaceStatusEvent) event; diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishingTimeFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishingTimeFinder.java index e535008b5e7..76f683bf0b4 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishingTimeFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/FinishingTimeFinder.java @@ -13,7 +13,7 @@ public class FinishingTimeFinder extends RaceLogAnalyzer { } @Override - protected TimePoint performAnalyzation() { + protected TimePoint performAnalysis() { for (RaceLogEvent event : getPassEventsDescending()) { if (event instanceof RaceLogRaceStatusEvent) { RaceLogRaceStatusEvent statusEvent = (RaceLogRaceStatusEvent) event; diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/GateLineOpeningTimeFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/GateLineOpeningTimeFinder.java index 864a3cf2cba..0b7399a2606 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/GateLineOpeningTimeFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/GateLineOpeningTimeFinder.java @@ -11,7 +11,7 @@ public class GateLineOpeningTimeFinder extends RaceLogAnalyzer { } @Override - protected Long performAnalyzation() { + protected Long performAnalysis() { for (RaceLogEvent event : getPassEvents()) { if (event instanceof RaceLogGateLineOpeningTimeEvent) { return ((RaceLogGateLineOpeningTimeEvent) event).getGateLineOpeningTime(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/IndividualRecallFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/IndividualRecallFinder.java index a9d1a7fc1fd..61a5f97a31c 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/IndividualRecallFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/IndividualRecallFinder.java @@ -14,7 +14,7 @@ public abstract class IndividualRecallFinder extends RaceLogAnalyzer 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; diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastFlagsFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastFlagsFinder.java index 30748e187a1..475ab27f806 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastFlagsFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastFlagsFinder.java @@ -25,7 +25,7 @@ public class LastFlagsFinder extends RaceLogAnalyzer> { } @Override - protected List performAnalyzation() { + protected List performAnalysis() { Iterator iterator = getPassEventsDescending().iterator(); RaceLogFlagEvent flagEvent = getNextFlagEvent(iterator); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastPublishedCourseDesignFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastPublishedCourseDesignFinder.java index e67fbfa26ba..c700b59c17a 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastPublishedCourseDesignFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastPublishedCourseDesignFinder.java @@ -13,7 +13,7 @@ public class LastPublishedCourseDesignFinder extends RaceLogAnalyzer } @Override - protected CourseBase performAnalyzation() { + protected CourseBase performAnalysis() { for (RaceLogEvent event : getAllEventsDescending()) { if (event instanceof RaceLogCourseDesignChangedEvent) { RaceLogCourseDesignChangedEvent courseDesignEvent = (RaceLogCourseDesignChangedEvent) event; diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastWindFixFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastWindFixFinder.java index 996c0c0effa..9cbf1c716bf 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastWindFixFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/LastWindFixFinder.java @@ -12,7 +12,7 @@ public class LastWindFixFinder extends RaceLogAnalyzer { } @Override - protected Wind performAnalyzation() { + protected Wind performAnalysis() { for (RaceLogEvent event : getAllEventsDescending()) { if (event instanceof RaceLogWindFixEvent) { RaceLogWindFixEvent windFixEvent = (RaceLogWindFixEvent) event; diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/PathfinderFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/PathfinderFinder.java index d0849327c6c..a885ab5e5f0 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/PathfinderFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/PathfinderFinder.java @@ -11,7 +11,7 @@ public class PathfinderFinder extends RaceLogAnalyzer { } @Override - protected String performAnalyzation() { + protected String performAnalysis() { for (RaceLogEvent event : getPassEventsDescending()) { if (event instanceof RaceLogPathfinderEvent) { return ((RaceLogPathfinderEvent) event).getPathfinderId(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/ProtestStartTimeFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/ProtestStartTimeFinder.java index 38a3aa48248..18fb9bb852c 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/ProtestStartTimeFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/ProtestStartTimeFinder.java @@ -12,7 +12,7 @@ public class ProtestStartTimeFinder extends RaceLogAnalyzer { } @Override - protected TimePoint performAnalyzation() { + protected TimePoint performAnalysis() { for (RaceLogEvent event : getPassEventsDescending()) { if (event instanceof RaceLogProtestStartTimeEvent) { return ((RaceLogProtestStartTimeEvent) event).getProtestStartTime(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RRS26StartModeFlagFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RRS26StartModeFlagFinder.java index a018ee4f96a..2837c899871 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RRS26StartModeFlagFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RRS26StartModeFlagFinder.java @@ -30,7 +30,7 @@ public class RRS26StartModeFlagFinder extends RaceLogAnalyzer { } @Override - protected Flags performAnalyzation() { + protected Flags performAnalysis() { StartProcedureType type = procedureAnalyzer.analyze(); if (StartProcedureType.RRS26.equals(type)) { for (RaceLogEvent event : getPassEventsDescending()) { diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RaceLogAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RaceLogAnalyzer.java index aaf96731ae3..11ec94bebc8 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RaceLogAnalyzer.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RaceLogAnalyzer.java @@ -24,13 +24,13 @@ public abstract class RaceLogAnalyzer { public ResultType analyze() { raceLog.lockForRead(); try { - return performAnalyzation(); + return performAnalysis(); } finally { raceLog.unlockAfterRead(); } } - protected abstract ResultType performAnalyzation(); + protected abstract ResultType performAnalysis(); protected Iterable getPassEvents() { return raceLog.getFixes(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RaceStatusAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RaceStatusAnalyzer.java index a351e5440c7..7ca600b5125 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RaceStatusAnalyzer.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/RaceStatusAnalyzer.java @@ -12,7 +12,7 @@ public class RaceStatusAnalyzer extends RaceLogAnalyzer { } @Override - protected RaceLogRaceStatus performAnalyzation() { + protected RaceLogRaceStatus performAnalysis() { for (RaceLogEvent event : getPassEventsDescending()) { if (event instanceof RaceLogRaceStatusEvent) { RaceLogRaceStatusEvent statusEvent = (RaceLogRaceStatusEvent) event; diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/StartProcedureTypeAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/StartProcedureTypeAnalyzer.java index 1ccee75cd93..8d6bfc7db5a 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/StartProcedureTypeAnalyzer.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/StartProcedureTypeAnalyzer.java @@ -12,7 +12,7 @@ public class StartProcedureTypeAnalyzer extends RaceLogAnalyzer { } @Override - protected TimePoint performAnalyzation() { + protected TimePoint performAnalysis() { for (RaceLogEvent event : getPassEventsDescending()) { if (event instanceof RaceLogStartTimeEvent) { return ((RaceLogStartTimeEvent) event).getStartTime(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/WindFixesFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/WindFixesFinder.java index 218bfd2c42e..0c94fc329c6 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/WindFixesFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/analyzing/impl/WindFixesFinder.java @@ -15,7 +15,7 @@ public class WindFixesFinder extends RaceLogAnalyzer> { } @Override - protected List performAnalyzation() { + protected List performAnalysis() { final List windFixes = new ArrayList(); for (RaceLogEvent event : getAllEventsDescending()) { if (event instanceof RaceLogWindFixEvent) { diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogFinishPositioningEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogFinishPositioningEventImpl.java index cb7e21d9453..c80cef23f40 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogFinishPositioningEventImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogFinishPositioningEventImpl.java @@ -22,7 +22,7 @@ public abstract class RaceLogFinishPositioningEventImpl extends RaceLogEventImpl } @Override - public List> getPositionedCompetitors() { + public List> getPositionedCompetitorsIDsNamesMaxPointsReasons() { return positionedCompetitors; } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java index 49dee9c8a51..9813741b651 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelog/impl/RaceLogImpl.java @@ -88,6 +88,24 @@ public class RaceLogImpl extends TrackImpl 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) { diff --git a/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingAdapterPersistenceImpl.java b/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingAdapterPersistenceImpl.java index ba6815f66bc..7dbea47b59c 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingAdapterPersistenceImpl.java +++ b/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingAdapterPersistenceImpl.java @@ -185,6 +185,26 @@ public class SwissTimingAdapterPersistenceImpl implements SwissTimingAdapterPers return null; } + @Override + public boolean hasRaceStartlist(String raceID) { + DBCollection races = database.getCollection(CollectionNames.RACES_MESSAGES.name()); + BasicDBObject query = new BasicDBObject(); + query.append(FieldNames.RACE_ID.name(), raceID); + query.append(FieldNames.MESSAGE_COMMAND.name(), MessageType.STL.name()); + DBObject object = races.findOne(query); + return object != null; + } + + @Override + public boolean hasRaceCourse(String raceID) { + DBCollection races = database.getCollection(CollectionNames.RACES_MESSAGES.name()); + BasicDBObject query = new BasicDBObject(); + query.append(FieldNames.RACE_ID.name(), raceID); + query.append(FieldNames.MESSAGE_COMMAND.name(), MessageType.CCG.name()); + DBObject object = races.findOne(query); + return object != null; + } + @Override public Iterable getRaces() { DBCollection races = database.getCollection(CollectionNames.RACES_MASTERDATA.name()); diff --git a/java/com.sap.sailing.domain.swisstimingadapter.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.swisstimingadapter.test/META-INF/MANIFEST.MF index e1a540c0972..42d23bb81e3 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.swisstimingadapter.test/META-INF/MANIFEST.MF @@ -16,9 +16,8 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sailing.domain.persistence, com.sap.sailing.domain.tractracadapter, com.sap.sailing.domain.swisstimingadapter.persistence;bundle-version="1.0.0", + org.junit4;bundle-version="4.8.2", org.hamcrest.core;bundle-version="1.1.0" Bundle-ClassPath: resources/, . -Import-Package: com.sap.sailing.server, - junit.framework;version="4.8.1", - org.junit;version="4.8.1" +Import-Package: com.sap.sailing.server diff --git a/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryTest.java b/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryTest.java index 4a26685e7b3..99a9d34deac 100644 --- a/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryTest.java +++ b/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryTest.java @@ -47,14 +47,6 @@ public class DomainFactoryTest { assertThat(raceType.getRaceCode(), is(OlympicRaceCode._470_WOMEN)); } - @Test - public void testGet470WomenBoatClass2() throws Exception { - String raceID = "SAW005_xxx"; - RaceType raceType = swissTimingDomainFactory.getRaceTypeFromRaceID(raceID ); - assertThat(raceType, is(notNullValue())); - assertThat(raceType.getRaceCode(), is(OlympicRaceCode._470_WOMEN)); - } - @Test public void testDontGetWrongBoatClass() throws Exception { String raceID = "ABC"; diff --git a/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/OverlappingStoredAndReceivedMessagesTest.java b/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/OverlappingStoredAndReceivedMessagesTest.java index 40ca53f6b6e..09559f64714 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/OverlappingStoredAndReceivedMessagesTest.java +++ b/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/OverlappingStoredAndReceivedMessagesTest.java @@ -208,4 +208,16 @@ public class OverlappingStoredAndReceivedMessagesTest implements RaceSpecificMes return null; } + @Override + public boolean hasRaceStartlist(String raceID) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean hasRaceCourse(String raceID) { + // TODO Auto-generated method stub + return false; + } + } diff --git a/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/SimpleDomainFactoryTest.java b/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/SimpleDomainFactoryTest.java index 05353f616ba..9d873906c96 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/SimpleDomainFactoryTest.java +++ b/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/SimpleDomainFactoryTest.java @@ -45,7 +45,7 @@ public class SimpleDomainFactoryTest { @Test public void testExtractBoatClassFromRaceIDWithEventID() { - String raceID = "QINSWC12013;SAW005901"; + String raceID = "QINSWC12013_SAW005901"; RaceType raceType = DomainFactory.INSTANCE.getRaceTypeFromRaceID(raceID); assertEquals("470", raceType.getBoatClass().getName()); } diff --git a/java/com.sap.sailing.domain.swisstimingadapter/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.swisstimingadapter/META-INF/MANIFEST.MF index 80cd6d3e589..d00c4a9387a 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.swisstimingadapter/META-INF/MANIFEST.MF @@ -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" diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceRecord.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceRecord.java index 64d355200f0..0af51eba629 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceRecord.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceRecord.java @@ -7,11 +7,15 @@ public class RaceRecord { private String raceID; private String description; private Date startTime; + private boolean hasCourse; + private boolean hasStartlist; - public RaceRecord(String raceID, String description, Date startTime) { + public RaceRecord(String raceID, String description, Date startTime, boolean hasCourse, boolean hasStartlist) { this.raceID = raceID; this.description = description; this.startTime = startTime; + this.hasCourse = hasCourse; + this.hasStartlist = hasStartlist; } public String getRaceID() { @@ -26,4 +30,11 @@ public class RaceRecord { return startTime; } + public boolean hasCourse() { + return hasCourse; + } + + public boolean hasStartlist() { + return hasStartlist; + } } diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceSpecificMessageLoader.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceSpecificMessageLoader.java index f294792572d..e6a162e7322 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceSpecificMessageLoader.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceSpecificMessageLoader.java @@ -21,4 +21,8 @@ public interface RaceSpecificMessageLoader { Iterable getRaces(); Race getRace(String raceID); + + boolean hasRaceStartlist(String raceID); + + boolean hasRaceCourse(String raceID); } diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceType.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceType.java index ddb406caf4e..c96d1a67920 100644 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceType.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/RaceType.java @@ -26,12 +26,12 @@ public interface RaceType { _470_MEN("SAM005", "470", Gender.male), STAR("SAM007", "Star", Gender.male), _49ER("SAM009", "49er", Gender.male), + _49ERFX("SAW009", "49erFX", Gender.female), ELLIOTT6M("SAW007", "Elliott 6M", Gender.female), RSX_WOMEN("SAW102", "RS:X", Gender.female), RSX_MEN("SAM102", "RS:X", Gender.male), - LASER_RADIAL("SAW103", "Laser Radial", Gender.female), - _49ERFX_TODO("xxxxx_TODO_xxxxx", "49er FX", Gender.female), - NACRA17_TOTO("xxxxx_TODO_xxxxx", "Nacra 17", Gender.mixed); + NACRA17("SAX017", "Nacra 17", Gender.mixed), + LASER_RADIAL("SAW103", "Laser Radial", Gender.female); enum Gender { male, female, mixed, unspecified; diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SailMasterConnector.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SailMasterConnector.java index 107cc795758..6edf82ec7f6 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SailMasterConnector.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SailMasterConnector.java @@ -19,8 +19,12 @@ public interface SailMasterConnector { Course getCourse(String raceID) throws UnknownHostException, IOException, InterruptedException; + boolean hasCourse(String raceID); + StartList getStartList(String raceID) throws UnknownHostException, IOException, InterruptedException; - + + boolean hasStartlist(String raceID); + TimePoint getStartTime(String raceID) throws UnknownHostException, IOException, ParseException, InterruptedException; Distance getDistanceToMark(String raceID, int markIndex, String boatID) throws UnknownHostException, IOException, InterruptedException; diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java index 08629fbdbd7..44211a5fe3b 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java @@ -206,7 +206,7 @@ public class DomainFactoryImpl implements DomainFactory { public RaceType getRaceTypeFromRaceID(String raceID) { final RaceType result; if (raceID != null && raceID.length() >= 6) { - final String[] optionalEventIDAndMandatoryRaceID = raceID.split(";"); + final String[] optionalEventIDAndMandatoryRaceID = raceID.split("_"); final String swissTimingRaceCode = optionalEventIDAndMandatoryRaceID[optionalEventIDAndMandatoryRaceID.length-1].substring(0, 6).toUpperCase(); RaceType raceType = raceTypeByID.get(swissTimingRaceCode); if (raceType == null) { diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SailMasterConnectorImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SailMasterConnectorImpl.java index 6181cb91adc..02837a604cc 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SailMasterConnectorImpl.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SailMasterConnectorImpl.java @@ -606,6 +606,24 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement return result; } + @Override + public boolean hasCourse(String raceID) { + boolean result = false; + if (messageLoader != null) { + result = messageLoader.hasRaceCourse(raceID); + } + return result; + } + + @Override + public boolean hasStartlist(String raceID) { + boolean result = false; + if (messageLoader != null) { + result = messageLoader.hasRaceStartlist(raceID); + } + return result; + } + private List parseAvailableRacesMessage(SailMasterMessage availableRacesMessage) { assertMessageType(MessageType.RAC, availableRacesMessage); int count = Integer.valueOf(availableRacesMessage.getSections()[1]); diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.swisstimingreplayadapter.test/META-INF/MANIFEST.MF index b7627c03a0c..093df8892cd 100644 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter.test/META-INF/MANIFEST.MF @@ -7,6 +7,6 @@ Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Fragment-Host: com.sap.sailing.domain.swisstimingreplayadapter Import-Package: org.json.simple, - org.json.simple.parser, - org.junit;version="4.8.2" -Require-Bundle: com.sap.sailing.domain.test + org.json.simple.parser +Require-Bundle: com.sap.sailing.domain.test, + org.junit4;bundle-version="4.8.2" diff --git a/java/com.sap.sailing.domain.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.test/META-INF/MANIFEST.MF index fbdaa90b8be..dbccead117f 100755 --- a/java/com.sap.sailing.domain.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.test/META-INF/MANIFEST.MF @@ -14,10 +14,8 @@ Require-Bundle: com.sap.sailing.domain, org.mockito.mockito-core;bundle-version="1.9.5", com.sap.sailing.domain.test, org.hamcrest;bundle-version="1.1.0", - org.objenesis;bundle-version="1.3.0" + org.objenesis;bundle-version="1.3.0", + org.junit4;bundle-version="4.8.2", + org.json.simple;bundle-version="1.1.0" Export-Package: com.sap.sailing.domain.test, com.sap.sailing.domain.test.mock -Import-Package: junit.framework;version="4.8.1", - org.json.simple, - org.json.simple.parser, - org.junit;version="4.8.1" diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardForKielWeekTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardForKielWeekTest.java index cd97487b2e7..9abe5d413eb 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardForKielWeekTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardForKielWeekTest.java @@ -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 diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardOfflineTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardOfflineTest.java index 9081815008e..4df7ca3ee3b 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardOfflineTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardOfflineTest.java @@ -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; diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java index 7578c7a5f94..df2a4c7c104 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardScoringAndRankingTest.java @@ -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; 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 getMarkPassings(Competitor competitor) { + ArrayListNavigableSet result = new ArrayListNavigableSet(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); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RaceLogAttachOnTrackedRaceTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RaceLogAttachOnTrackedRaceTest.java index 80eb691ef57..78e7d9383fa 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RaceLogAttachOnTrackedRaceTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RaceLogAttachOnTrackedRaceTest.java @@ -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 diff --git a/java/com.sap.sailing.domain.tractracadapter/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.tractracadapter/META-INF/MANIFEST.MF index 55a083f5ccb..5457b5a986b 100755 --- a/java/com.sap.sailing.domain.tractracadapter/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.tractracadapter/META-INF/MANIFEST.MF @@ -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 diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java index ce090ce9271..fc4e0f1f6b0 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java @@ -179,25 +179,26 @@ public interface DomainFactory { /** * Creates a {@link RaceDefinition} from a TracTrac {@link Race} and a domain {@link Course} definition. The * resulting {@link RaceDefinition} is added to the {@link com.sap.sailing.domain.base.Regatta} to which - * trackedRegatta belongs (see {@link TrackedRegatta#getRegatta()}). It is added to the internal race cache. - * The corresponding {@link TrackedRace} object is also created, and the notification of threads waiting on the race - * cache such as a blocking {@link #getAndWaitForRaceDefinition(UUID)} happens only after the tracked race - * has been created and the {@link RaceDefinition} was + * trackedRegatta belongs (see {@link TrackedRegatta#getRegatta()}). It is added to the internal race + * cache. The corresponding {@link TrackedRace} object is also created, and the notification of threads waiting on + * the race cache such as a blocking {@link #getAndWaitForRaceDefinition(UUID)} happens only after the + * tracked race has been created and the {@link RaceDefinition} was * {@link com.sap.sailing.domain.base.Regatta#addRace(RaceDefinition) added} to the domain event. This ensures that - * waiters for the {@link RaceDefinition} are guaranteed to obtain a valid, non- null tracked race + * waiters for the {@link RaceDefinition} are guaranteed to obtain a valid, non-null tracked race * already immediately after the notification was sent, and that the {@link RaceDefinition} is already * {@link com.sap.sailing.domain.base.Regatta#getAllRaces() known} by its containing * {@link com.sap.sailing.domain.base.Regatta}. - * @param raceName TODO - * @param competitors TODO - * @param boatClass TODO + * * @param raceDefinitionSetToUpdate * if not null, after creating the {@link TrackedRace}, the {@link RaceDefinition} is - * {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that object. + * {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that + * object. */ - DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta, UUID raceId, - String raceName, Iterable competitors, BoatClass boatClass, Course course, Iterable sidelines, - WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword); + DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId, + String raceName, Iterable competitors, BoatClass boatClass, + Course course, Iterable sidelines, WindStore windStore, long delayToLiveInMillis, + long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, + URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword); /** * The record may be for a single mark or a gate. If for a gate, the diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java index 0d9d752796f..0b2e80123e3 100644 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java @@ -469,7 +469,7 @@ public class DomainFactoryImpl implements DomainFactory { } @Override - public DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta, UUID raceId, + public DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId, String raceName, Iterable competitors, BoatClass boatClass, Course course, Iterable sidelines, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, @@ -479,36 +479,38 @@ public class DomainFactoryImpl implements DomainFactory { if (raceDefinition == null) { logger.info("Creating RaceDefinitionImpl for race "+raceName); raceDefinition = new RaceDefinitionImpl(raceName, course, boatClass, competitors, raceId); + } else { + logger.info("Already found RaceDefinitionImpl for race "+raceName); + } + DynamicTrackedRace trackedRace = trackedRegatta.getExistingTrackedRace(raceDefinition); + if (trackedRace == null) { // add to existing regatta only if boat class matches if (raceDefinition.getBoatClass() == trackedRegatta.getRegatta().getBoatClass()) { trackedRegatta.getRegatta().addRace(raceDefinition); - DynamicTrackedRace trackedRace = createTrackedRace(trackedRegatta, raceDefinition, sidelines, windStore, + trackedRace = createTrackedRace(trackedRegatta, raceDefinition, sidelines, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate); - logger.info("Added race "+raceDefinition+" to regatta "+trackedRegatta.getRegatta()); - - TracTracCourseDesignUpdateHandler courseDesignHandler = new TracTracCourseDesignUpdateHandler(tracTracUpdateURI, - tracTracUsername, tracTracPassword, - tracTracEventUuid, raceDefinition.getId()); + logger.info("Added race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta()); + + TracTracCourseDesignUpdateHandler courseDesignHandler = new TracTracCourseDesignUpdateHandler( + tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid, + raceDefinition.getId()); trackedRace.addCourseDesignChangedListener(courseDesignHandler); - - TracTracStartTimeUpdateHandler startTimeHandler = new TracTracStartTimeUpdateHandler(tracTracUpdateURI, - tracTracUsername, tracTracPassword, tracTracEventUuid, raceDefinition.getId()); + + TracTracStartTimeUpdateHandler startTimeHandler = new TracTracStartTimeUpdateHandler( + tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid, + raceDefinition.getId()); trackedRace.addStartTimeChangedListener(startTimeHandler); - - synchronized (raceCache) { - raceCache.put(raceId, raceDefinition); - raceCache.notifyAll(); - } - return trackedRace; + raceCache.put(raceId, raceDefinition); + raceCache.notifyAll(); } else { - logger.warning("Not adding race "+raceDefinition+" to regatta "+trackedRegatta.getRegatta()+ - " because boat class "+raceDefinition.getBoatClass()+" doesn't match regatta's boat class "+ - trackedRegatta.getRegatta().getBoatClass()); - return null; + logger.warning("Not adding race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta() + + " because boat class " + raceDefinition.getBoatClass() + + " doesn't match regatta's boat class " + trackedRegatta.getRegatta().getBoatClass()); } } else { - throw new RuntimeException("Race "+raceName+" already exists"); + logger.info("Found existing tracked race for race "+raceName+" with ID "+raceId); } + return trackedRace; } } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/Simulator.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/Simulator.java index cc2022e1d01..a654f2a7153 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/Simulator.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/Simulator.java @@ -29,17 +29,21 @@ public class Simulator { private static final Logger logger = Logger.getLogger(Simulator.class.getName()); private DynamicTrackedRace trackedRace; - private WindStore windStore; + private final WindStore windStore; private long advanceInMillis = -1; private Timer timer = new Timer("Timer for TracTrac Simulator"); private boolean stopped; + public Simulator(WindStore windStore) { + super(); + assert windStore != null; + this.windStore = windStore; + } + /** - * Creates a wind store which replays the wind store events against a tracked race, correcting the wind fixes with - * the simulation delay. The wind store returned is an {@link EmptyWindStore}. + * The wind store returned is an {@link EmptyWindStore}. */ public WindStore simulatingWindStore(WindStore windStore) { - this.windStore = windStore; return EmptyWindStore.INSTANCE; } @@ -63,7 +67,6 @@ public class Simulator { */ private void startWindPlayer() { assert this.trackedRace != null; - assert this.windStore != null; for (final Map.Entry windSourceAndTrack : windStore.loadWindTracks( trackedRace.getTrackedRegatta(), trackedRace, /* millisecondsOverWhichToAverageWind doesn't matter because we only use raw fixes */ 10000).entrySet()) { diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java index 6d6d5280834..b5ce0b7c4a0 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java @@ -100,8 +100,6 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements */ private final boolean isLiveTracking; - private final TrackedRegattaRegistry trackedRegattaRegistry; - /** * Creates a race tracked for the specified URL/URIs and starts receiving all available existing and future push * data from there. Receiving continues until {@link #stop()} is called. @@ -183,7 +181,6 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements WindStore windStore, String tracTracUsername, String tracTracPassword, TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException, FileNotFoundException { super(); - this.trackedRegattaRegistry = trackedRegattaRegistry; this.tractracEvent = tractracEvent; urls = createID(paramURL, liveURI, storedURI); isLiveTracking = liveURI != null; @@ -192,7 +189,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements this.domainFactory = domainFactory; final Simulator simulator; if (simulateWithStartTimeNow) { - simulator = new Simulator(); + simulator = new Simulator(windStore); } else { simulator = null; } @@ -225,8 +222,6 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements // in this case, create a default regatta based on the TracTrac event data this.regatta = effectiveRegatta == null ? domainFactory.getOrCreateDefaultRegatta(raceLogStore, tractracEvent, trackedRegattaRegistry) : effectiveRegatta; trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(this.regatta); - // Read event data from configuration file - controlPointPositionPoller = scheduleClientParamsPHPPoller(paramURL, simulator, tracTracUpdateURI, delayToLiveInMillis, tracTracUsername, tracTracPassword); receivers = new HashSet(); Set typeControllers = new HashSet(); for (Receiver receiver : domainFactory.getUpdateReceivers(getTrackedRegatta(), tractracEvent, startOfTracking, @@ -237,6 +232,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements } } addListenersForStoredDataAndStartController(typeControllers); + // Read event data from configuration file + controlPointPositionPoller = scheduleClientParamsPHPPoller(paramURL, simulator, tracTracUpdateURI, delayToLiveInMillis, tracTracUsername, tracTracPassword); } @Override @@ -529,6 +526,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements } else { logger.info("Joined TracTrac IO thread for race(s) "+getRaces()); } + lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, /* will be ignored */ 1.0); + updateStatusOfTrackedRaces(); } protected DataController getController() { @@ -548,10 +547,17 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements @Override public void stopped() { logger.info("stopped TracTrac tracking for "+getRaces()); - lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, 1.0); + lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 1.0); updateStatusOfTrackedRaces(); + // don't stop the tracker (see bug 1517) as it seems that the storedData... callbacks are unreliable, and + // we have seen many more fixes been transmitted after having received stopped() } + /** + * Propagates {@link #lastStatus} to all tracked races to which this tracker writes. + * + * @see #updateStatusOfTrackedRace(DynamicTrackedRace) + */ private void updateStatusOfTrackedRaces() { for (RaceDefinition race : getRaces()) { DynamicTrackedRace trackedRace = getTrackedRegatta().getExistingTrackedRace(race); @@ -561,9 +567,24 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements } } + /** + * Propagates {@link #lastStatus} to trackedRace's {@link TrackedRace#getStatus() status}. If + * {@link #lastStatus} is a {@link TrackedRaceStatusEnum#FINISHED FINISHED} status, the progress value is taken from + * the tracked race's current status instead of overwriting it with the progress indicated by + * {@link #lastStatus}. + */ private void updateStatusOfTrackedRace(DynamicTrackedRace trackedRace) { - if (lastStatus != null) { - trackedRace.setStatus(lastStatus); + // can't update a race status once it has been set to FINISHED + if (lastStatus != null && trackedRace.getStatus() != null && trackedRace.getStatus().getStatus() != TrackedRaceStatusEnum.FINISHED) { + final TrackedRaceStatus status; + if (lastStatus.getStatus() == TrackedRaceStatusEnum.FINISHED) { + // in this case use the tracked race's progress value: + status = new TrackedRaceStatusImpl(lastStatus.getStatus(), trackedRace.getStatus() == null ? 0.0 + : trackedRace.getStatus().getLoadingProgress()); + } else { + status = lastStatus; + } + trackedRace.setStatus(status); } } @@ -580,38 +601,13 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements if (isLiveTracking) { lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 1); updateStatusOfTrackedRaces(); - } else { - // ask RacingEventService to cleanly stop and unregister this tracker - // if the race has all data loaded. Doing this asynchronously because - // stopping can take longer and if you're loading many races in parallel - // this can slow down loading extremely - for (final RaceDefinition race : getRaces()) { - DynamicTrackedRace trackedRace = getTrackedRegatta().getExistingTrackedRace(race); - final Regatta regatta = getRegatta(); - if (trackedRace.getStatus().getLoadingProgress() == 1.0) { - Thread raceStopper = new Thread(new Runnable() { - @Override - public void run() { - try { - trackedRegattaRegistry.stopTracking(regatta, race); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error trying to stop tracker for race "+race.getName()+ - " in regatta "+getRegatta().getName(), e); - } - } - }); - raceStopper.start(); - } else { - logger.log(Level.SEVERE, "Not stopping race "+race.getName()+" because it has not all data loaded! Progress: " + trackedRace.getStatus().getLoadingProgress()); - } - } } } @Override public void storedDataProgress(float progress) { logger.info("Stored data progress for race(s) "+getRaces()+": "+progress); - lastStatus = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, progress); + lastStatus = new TrackedRaceStatusImpl(progress==1.0 ? TrackedRaceStatusEnum.TRACKING : TrackedRaceStatusEnum.LOADING, progress); updateStatusOfTrackedRaces(); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrection.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrection.java index f8e9926b2fc..38c8ef1d754 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrection.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrection.java @@ -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 null 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 + * timePoint 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 timePoint 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 trackedRank, Competitor competitor, RaceColumn raceColumn, + Result getCorrectedScore(Callable 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-null 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.

+ * "correction" will still be the uncorrected value. + *

+ * + * @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 competitor in column + * raceColumn that is valid at timePoint. * * @return if an explicit score correction was made for the combination of competitor and * raceColumn */ - 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 raceInLeaderboard. + */ boolean hasCorrectionFor(RaceColumn raceInLeaderboard); /** diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/SettableScoreCorrection.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/SettableScoreCorrection.java index 736250540fe..732bf75467d 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/SettableScoreCorrection.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/SettableScoreCorrection.java @@ -13,17 +13,12 @@ public interface SettableScoreCorrection extends ScoreCorrection { /** * @param reason * if null, 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 false if no + * {@link #getMaxPointsReason(Competitor, RaceColumn, TimePoint)} will return {@link MaxPointsReason#NONE}, a + * call to {@link #isScoreCorrected(Competitor, RaceColumn, TimePoint)} will return false if no * other explicit score correction was made for the competitor. */ void setMaxPointsReason(Competitor competitor, RaceColumn raceColumn, MaxPointsReason reason); - /** - * @return a non-null result - */ - MaxPointsReason getMaxPointsReason(Competitor competitor, RaceColumn raceColumn); - void correctScore(Competitor competitor, RaceColumn raceColumn, double points); /** diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCache.java index f1f57e96038..af722f75216 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCache.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCache.java @@ -82,8 +82,8 @@ public class LeaderboardDTOCache implements LeaderboardCache { public LeaderboardDTOCache(boolean waitForLatestAnalyses, Leaderboard leaderboard) { this.leaderboard = leaderboard; this.waitForLatestAnalyses = waitForLatestAnalyses; - // if the leaderboard becomes weakly referenced and eventually GCed, then so can the cached results for it - this.leaderboardCache = new LinkedHashMap>, FutureTask>(16, 0.75f, /* access-based eviction */ true) { + // Note: don't use access-based ordering as it turns the get(...) call into a "write" access + this.leaderboardCache = new LinkedHashMap>, FutureTask>(16, 0.75f) { private static final long serialVersionUID = 7287916997229815039L; @Override protected boolean removeEldestEntry(Map.Entry>, FutureTask> e) { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java index 224a9e21d1c..59114f0d9a6 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java @@ -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 allCompetitorsCache; /** - * @param scoreCorrection must not be null * @param scoreComparator the comparator to use to compare basic scores, such as net points * @param name must not be null */ - 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 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--; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index dcc1ccbd896..24e7c7b2108 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -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(); - this.scoreCorrection = scoreCorrection; + this.scoreCorrection = createScoreCorrection(); this.displayNames = new HashMap(); this.crossLeaderboardResultDiscardingRule = resultDiscardingRule; this.suppressedCompetitors = new HashSet(); @@ -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))); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java index c78ae8d18bc..609fb016488 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java @@ -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"); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java index 02439785dd1..8d224a533d6 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java @@ -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); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java index 2b434fac0b1..5d8aadb4a91 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java @@ -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 scoreCorrectionListeners; + + private final Leaderboard leaderboard; - public ScoreCorrectionImpl() { + public ScoreCorrectionImpl(Leaderboard leaderboard) { + this.leaderboard = leaderboard; this.maxPointsReasons = new HashMap, MaxPointsReason>(); this.correctedScores = new HashMap, Double>(); this.scoreCorrectionListeners = new HashSet(); @@ -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 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 timePoint + * is before the start of competitor's race in the race column specified by raceColumn. 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 raceColumn in the leaderboard in which competitor competes, and the competitor + * hasn't finished that race at timePoint, we also know that this must be before the start of + * competitor's race in raceColumn because we assume that the same competitor can only + * compete in one race at a time within a single leaderboard. + *

+ * + * In all other cases, false is returned which can either mean that timePoint is certainly + * known to be after the race start of competitor in the race for raceColumn, or we just + * can't tell, e.g., because competitor's race for raceColumn is not tracked, and + * timePoint is after all prior race column's finishing time for competitor. + *

+ * + * This method can be used to decide whether to apply a {@link MaxPointsReason#DNC}, {@link MaxPointsReason#DNS} or + * {@link MaxPointsReason#OCS} correction for competitor at timePoint in the race for + * raceColumn, 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 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 timePoint + * is before the finish or abandoning of competitor's race in the race column specified by + * raceColumn. If there is a {@link RaceColumn#getTrackedRace(Competitor) tracked race for the + * competitor associated with the race column}, that race's finish time for competitor (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 raceColumn in the leaderboard in which competitor + * competes, and the competitor has finished that race after timePoint, we also know that this must be + * before the end of competitor's race in raceColumn because we assume that the same + * competitor can only compete in one race at a time within a single leaderboard. + *

+ * + * In all other cases, false is returned which can either mean that timePoint is certainly + * known to be after the race finish of competitor in the race for raceColumn, or we just + * can't tell, e.g., because competitor's race for raceColumn is not tracked, and + * timePoint is after all prior race column's finishing time for competitor. + *

+ * + * This method can be used to decide whether to apply a score correction for competitor at + * timePoint in the race for raceColumn, 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 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 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 competitor for the + * If the {@link #getMaxPointsReason(Competitor, TrackedRace, TimePoint)} for the competitor for the * raceColumn's tracked race is not {@link MaxPointsReason#NONE}, the * {@link #getMaxPoints(TrackedRace) maximum score} is computed for the competitor. Otherwise, the * uncorrectedScore is returned. *

+ * + * The current implementation considers timePoint by comparing it to the competitor's + * times for the tracked race associated for that competitor in raceColumn. 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 timePoint is after the competitor + * finished or aborted the race. If the timePoint 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. + *

*/ @Override public Result getCorrectedScore(Callable 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 * competitor's key, it is used. Otherwise, the uncorrectedScore is returned. + * * @param scoringScheme * used to transform the tracked rank into a score if there is no score correction applied - * * @return null in case the competitor has no score assigned in that race which is the - * case if the score is not corrected by these score corrections, and the trackedRankProvider 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 raceColumn, meaning there cannot be a tracked rank for the competitor regardless what - * trackedRankProvider delivers. + * case if the score is not corrected by these score corrections, and the trackedRankProvider + * 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 raceColumn, meaning there cannot be a tracked rank for + * the competitor regardless what trackedRankProvider delivers. */ - protected Double getCorrectedNonMaxedScore(final Competitor competitor, final RaceColumn raceColumn, + private Double getCorrectedNonMaxedScore(final Competitor competitor, final RaceColumn raceColumn, Callable 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; + } + } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java index 9673b67fcc3..aeb39a751b8 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java @@ -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(); } + @Override + protected SettableScoreCorrection createScoreCorrection() { + return new MetaLeaderboardScoreCorrection(this); + } + + + private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); columnsForLeaderboards = new WeakHashMap<>(); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardScoreCorrection.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardScoreCorrection.java index 2d4e49e5f49..8109435276c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardScoreCorrection.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardScoreCorrection.java @@ -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; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/FlexibleLeaderboardMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/FlexibleLeaderboardMasterData.java index c0c06e2c852..9e2ce14093c 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/FlexibleLeaderboardMasterData.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/FlexibleLeaderboardMasterData.java @@ -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 getRaceColumns() { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RegattaLeaderboardMasterData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RegattaLeaderboardMasterData.java index 689bbb30a75..8abeee6471a 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RegattaLeaderboardMasterData.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/masterdataimport/RegattaLeaderboardMasterData.java @@ -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()); } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/RaceLogIdentifier.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/RaceLogIdentifier.java index 42ee3d90d3a..b20e8651d9a 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/RaceLogIdentifier.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/RaceLogIdentifier.java @@ -12,6 +12,8 @@ public interface RaceLogIdentifier extends Serializable { Triple getIdentifier(); + String getDeprecatedIdentifier(); + RaceLogIdentifierTemplate getTemplate(); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/impl/RaceLogIdentifierImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/impl/RaceLogIdentifierImpl.java index 2f8c3815755..e80b0bc4e01 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/impl/RaceLogIdentifierImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/impl/RaceLogIdentifierImpl.java @@ -25,6 +25,14 @@ public class RaceLogIdentifierImpl implements RaceLogIdentifier { return new Util.Triple(template.getParentObjectName(), raceColumnName, fleetName); } + @Override + public String getDeprecatedIdentifier() { + return String.format("%s.%s.%s", + this.getTemplate().getParentObjectName(), + this.getRaceColumnName(), + this.getFleetName()); + } + @Override public RaceLogIdentifierTemplate getTemplate() { return template; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java index 739860a20e6..ae90f10abd2 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java @@ -31,7 +31,7 @@ import com.sap.sailing.domain.tracking.Wind; public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor { - public static final Logger log = Logger.getLogger(DynamicTrackedRaceLogListener.class.getName()); + private static final Logger logger = Logger.getLogger(DynamicTrackedRaceLogListener.class.getName()); private DynamicTrackedRace trackedRace; @@ -112,7 +112,7 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor { // ... onCourseDesignChangedByRaceCommittee() might be called more than once. trackedRace.onCourseDesignChangedByRaceCommittee(courseDesign); } else { - log.info("Could not find any course design update on race log of " + trackedRace.getRace().getName() + "! Not sending out any events."); + logger.info("Could not find any course design update on race log of " + trackedRace.getRace().getName() + "! Not sending out any events."); } } @@ -125,7 +125,7 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor { /* invoke listeners with received start time, this will also trigger tractrac update */ trackedRace.onStartTimeChangedByRaceCommittee(startTime); } else { - log.info("Could not find any valid start time on race log of " + trackedRace.getRace().getName() + "! Not sending out any events."); + logger.info("Could not find any valid start time on race log of " + trackedRace.getRace().getName() + "! Not sending out any events."); } } diff --git a/java/com.sap.sailing.expeditionconnector.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.expeditionconnector.test/META-INF/MANIFEST.MF index bc678bb59ff..ebd61fb4e94 100755 --- a/java/com.sap.sailing.expeditionconnector.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.expeditionconnector.test/META-INF/MANIFEST.MF @@ -8,7 +8,5 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Fragment-Host: com.sap.sailing.expeditionconnector Require-Bundle: com.sap.sailing.server, com.sap.sailing.domain.test, - com.sap.sailing.udpconnector -Import-Package: junit.framework;version="4.8.1", - org.junit;version="4.8.1", - org.osgi.framework;version="1.6.0" + com.sap.sailing.udpconnector, + org.junit4;bundle-version="4.8.2" diff --git a/java/com.sap.sailing.feature.p2build/raceanalysis.product b/java/com.sap.sailing.feature.p2build/raceanalysis.product index a10d7593af6..f5d6dbd8f89 100755 --- a/java/com.sap.sailing.feature.p2build/raceanalysis.product +++ b/java/com.sap.sailing.feature.p2build/raceanalysis.product @@ -34,10 +34,10 @@ - + - + diff --git a/java/com.sap.sailing.feature.runtime/feature.xml b/java/com.sap.sailing.feature.runtime/feature.xml index 83c7c1c87ec..2c04c5de481 100644 --- a/java/com.sap.sailing.feature.runtime/feature.xml +++ b/java/com.sap.sailing.feature.runtime/feature.xml @@ -27,17 +27,15 @@ - - - - - + + + - - + + diff --git a/java/com.sap.sailing.feature/feature.xml b/java/com.sap.sailing.feature/feature.xml index 1584ed414ba..597d486105b 100755 --- a/java/com.sap.sailing.feature/feature.xml +++ b/java/com.sap.sailing.feature/feature.xml @@ -22,20 +22,38 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al - + - - + - - + + + + + + - - - - - - - - - + diff --git a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF index 0ec55e0a7bf..f700130b024 100755 --- a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF @@ -16,7 +16,6 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sailing.domain.persistence, com.sap.sailing.domain.swisstimingadapter.persistence, com.sap.sailing.domain.tractracadapter.persistence, - com.google.gwt.osgi;bundle-version="2.4.0", com.sap.sailing.domain.common, com.sap.sailing.resultimport, org.moxieapps.gwt.highcharts;bundle-version="1.5.0", @@ -27,12 +26,14 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sailing.domain.swisstimingreplayadapter, com.sap.sailing.simulator;bundle-version="1.0.0", com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0", - de.csenk.gwt.ws + de.csenk.gwt.ws, + com.google.gwt.osgi;bundle-version="2.5.1" Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator Bundle-ActivationPolicy: lazy Import-Package: javax.jms;version="1.1.0", javax.servlet;version="2.6.0", javax.servlet.http;version="2.6.0", + javax.servlet.descriptor;version="2.6.0", org.json.simple, org.json.simple.parser, org.osgi.framework, diff --git a/java/com.sap.sailing.gwt.ui/pom.xml b/java/com.sap.sailing.gwt.ui/pom.xml index c7e27b25caf..c9df309c469 100644 --- a/java/com.sap.sailing.gwt.ui/pom.xml +++ b/java/com.sap.sailing.gwt.ui/pom.xml @@ -48,7 +48,8 @@ - -Dgwt.persistentunitcache=false + -Dgwt.persistentunitcache=false + chrome com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.ui.Leaderboard diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java index b0bc5ef009f..1b36e91f131 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java @@ -816,32 +816,36 @@ public class LeaderboardConfigPanel extends FormPanel implements SelectedLeaderb private void selectTrackedRaceInRaceList() { final String selectedLeaderboardName = getSelectedLeaderboardName(); - final RaceColumnDTOAndFleetDTOWithNameBasedEquality selectedRaceColumnAndFleetNameInLeaderboard = getSelectedRaceColumnWithFleet(); - final String selectedRaceColumnName = selectedRaceColumnAndFleetNameInLeaderboard.getA().getRaceColumnName(); - final String selectedFleetName = selectedRaceColumnAndFleetNameInLeaderboard.getB().getName(); - sailingService.getRegattaAndRaceNameOfTrackedRaceConnectedToLeaderboardColumn(selectedLeaderboardName, - selectedRaceColumnName, new AsyncCallback>() { - @Override - public void onFailure(Throwable t) { - errorReporter.reportError("Error trying to determine tracked race linked to race column " - + selectedRaceColumnName + " in leaderboard " + selectedLeaderboardName + ": " - + t.getMessage()); - } + if (selectedLeaderboardName != null) { + final RaceColumnDTOAndFleetDTOWithNameBasedEquality selectedRaceColumnAndFleetNameInLeaderboard = getSelectedRaceColumnWithFleet(); + final String selectedRaceColumnName = selectedRaceColumnAndFleetNameInLeaderboard.getA() + .getRaceColumnName(); + final String selectedFleetName = selectedRaceColumnAndFleetNameInLeaderboard.getB().getName(); + sailingService.getRegattaAndRaceNameOfTrackedRaceConnectedToLeaderboardColumn(selectedLeaderboardName, + selectedRaceColumnName, new AsyncCallback>() { + @Override + public void onFailure(Throwable t) { + errorReporter.reportError("Error trying to determine tracked race linked to race column " + + selectedRaceColumnName + " in leaderboard " + selectedLeaderboardName + ": " + + t.getMessage()); + } - @Override - public void onSuccess(Map regattaAndRaceNamesPerFleet) { - if (regattaAndRaceNamesPerFleet != null && !regattaAndRaceNamesPerFleet.isEmpty()) { - RegattaAndRaceIdentifier raceIdentifier = regattaAndRaceNamesPerFleet.get(selectedFleetName); - if (raceIdentifier != null) { - selectRaceInList(raceIdentifier.getRegattaName(), raceIdentifier.getRaceName()); - } else { - trackedRacesListComposite.clearSelection(); - } - } else { - trackedRacesListComposite.clearSelection(); - } - } - }); + @Override + public void onSuccess(Map regattaAndRaceNamesPerFleet) { + if (regattaAndRaceNamesPerFleet != null && !regattaAndRaceNamesPerFleet.isEmpty()) { + RegattaAndRaceIdentifier raceIdentifier = regattaAndRaceNamesPerFleet + .get(selectedFleetName); + if (raceIdentifier != null) { + selectRaceInList(raceIdentifier.getRegattaName(), raceIdentifier.getRaceName()); + } else { + trackedRacesListComposite.clearSelection(); + } + } else { + trackedRacesListComposite.clearSelection(); + } + } + }); + } } private void selectRaceInList(String regattaName, String raceName) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java index 58bb552ca3b..eb6dd5128f7 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java @@ -46,14 +46,9 @@ import com.sap.sailing.gwt.ui.shared.SwissTimingConfigurationDTO; import com.sap.sailing.gwt.ui.shared.SwissTimingRaceRecordDTO; /** - * Allows the user to start and stop tracking of events, regattas and races using the TracTrac connector. In particular, + * Allows the user to start and stop tracking of races using the SwissTiming connector. In particular, * previously configured connections can be retrieved from a drop-down list which then pre-populates all connection - * parameters. The user can also choose to enter connection information manually. Using a "hierarchical" entry system - * comparable to that of, e.g., the Eclipse CVS connection setup wizard, components entered will be used to - * automatically assemble the full URL which can still be overwritten manually. There is a propagation order across the - * fields. Hostname propagates to JSON URL, Live URI and Stored URI. Port Live Data propagates to Port Stored Data, - * incremented by one. The ports propagate to Live URI and Stored URI, respectively. The event name propagates to the - * JSON URL. + * parameters. The user can also choose to enter connection information manually. * * @author Axel Uhl (D043530) * @@ -166,7 +161,16 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane } }; - TextColumn raceStartTrackingColumn = new TextColumn() { + TextColumn raceStateColumn = new TextColumn() { + @Override + public String getValue(SwissTimingRaceRecordDTO object) { + String result = object.hasCourse ? "C✓ " : ""; + result += object.hasStartlist ? "S✓" : ""; + return result; + } + }; + + TextColumn raceStartTimeColumn = new TextColumn() { @Override public String getValue(SwissTimingRaceRecordDTO object) { return object.raceStartTime==null?"":dateFormatter.render(object.raceStartTime) + " " + timeFormatter.render(object.raceStartTime); @@ -176,36 +180,49 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane HorizontalPanel racesSplitPanel = new HorizontalPanel(); mainPanel.add(racesSplitPanel); - CaptionPanel racesCaptionPanel = new CaptionPanel(stringConstants.trackableRaces()); - racesSplitPanel.add(racesCaptionPanel); - racesCaptionPanel.setWidth("50%"); + CaptionPanel trackableRacesCaptionPanel = new CaptionPanel(stringConstants.trackableRaces()); + racesSplitPanel.add(trackableRacesCaptionPanel); + trackableRacesCaptionPanel.setWidth("50%"); CaptionPanel trackedRacesCaptionPanel = new CaptionPanel(stringConstants.trackedRaces()); racesSplitPanel.add(trackedRacesCaptionPanel); trackedRacesCaptionPanel.setWidth("50%"); - VerticalPanel racesPanel = new VerticalPanel(); - racesCaptionPanel.setContentWidget(racesPanel); - racesCaptionPanel.setStyleName("bold"); + VerticalPanel trackableRacesPanel = new VerticalPanel(); + trackableRacesCaptionPanel.setContentWidget(trackableRacesPanel); + trackableRacesCaptionPanel.setStyleName("bold"); VerticalPanel trackedRacesPanel = new VerticalPanel(); trackedRacesPanel.setWidth("100%"); trackedRacesCaptionPanel.setContentWidget(trackedRacesPanel); trackedRacesCaptionPanel.setStyleName("bold"); - // text box for filtering the cell table - HorizontalPanel filterPanel = new HorizontalPanel(); - filterPanel.setSpacing(5); - racesPanel.add(filterPanel); - - // Regatta + // Regatta selection HorizontalPanel regattaPanel = new HorizontalPanel(); regattaPanel.setSpacing(5); Label regattaForTrackingLabel = new Label(stringMessages.regattaUsedForTheTrackedRace()); regattaForTrackingLabel.setWordWrap(false); regattaPanel.add(regattaForTrackingLabel); regattaPanel.add(getAvailableRegattasListBox()); - racesPanel.add(regattaPanel); + trackableRacesPanel.add(regattaPanel); + + Label lblTrackSettings = new Label(stringConstants.trackSettings()); + trackableRacesPanel.add(lblTrackSettings); + + final CheckBox trackWindCheckbox = new CheckBox(stringConstants.trackWind()); + trackWindCheckbox.setWordWrap(false); + trackWindCheckbox.setValue(true); + trackableRacesPanel.add(trackWindCheckbox); + + final CheckBox declinationCheckbox = new CheckBox(stringConstants.declinationCheckbox()); + declinationCheckbox.setWordWrap(false); + declinationCheckbox.setValue(true); + trackableRacesPanel.add(declinationCheckbox); + + // text box for filtering the cell table + HorizontalPanel filterPanel = new HorizontalPanel(); + filterPanel.setSpacing(5); + trackableRacesPanel.add(filterPanel); Label lblFilterEvents = new Label(stringConstants.filterRacesByName() + ":"); filterPanel.add(lblFilterEvents); @@ -218,51 +235,32 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane fillRaceListFromAvailableRacesApplyingFilter(SwissTimingEventManagementPanel.this.filterEventsTextbox.getText()); } }); - filterPanel.add(filterEventsTextbox); - HorizontalPanel racesHorizontalPanel = new HorizontalPanel(); - racesPanel.add(racesHorizontalPanel); - - VerticalPanel trackPanel = new VerticalPanel(); - trackPanel.setStyleName("paddedPanel"); - raceNameColumn.setSortable(true); - raceStartTrackingColumn.setSortable(true); + raceStartTimeColumn.setSortable(true); AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class); raceTable = new CellTable(/* pageSize */ 10000, tableRes); raceTable.addColumn(raceNameColumn, stringConstants.name()); raceTable.addColumn(raceDescriptionColumn, stringConstants.description()); raceTable.addColumn(boatClassColumn, stringConstants.boatClass()); - raceTable.addColumn(raceStartTrackingColumn, stringConstants.raceStartTimeColumn()); + raceTable.addColumn(raceStateColumn, stringConstants.status()); + raceTable.addColumn(raceStartTimeColumn, stringConstants.startTime()); raceTable.setWidth("300px"); raceTable.setSelectionModel(new MultiSelectionModel() {}); - racesHorizontalPanel.add(raceTable); - racesHorizontalPanel.add(trackPanel); + trackableRacesPanel.add(raceTable); raceList = new ListDataProvider(); raceList.addDataDisplay(raceTable); - Handler columnSortHandler = getRaceTableColumnSortHandler(raceList.getList(), raceNameColumn, raceStartTrackingColumn); + Handler columnSortHandler = getRaceTableColumnSortHandler(raceList.getList(), raceNameColumn, raceStartTimeColumn); raceTable.addColumnSortHandler(columnSortHandler); - - Label lblTrackSettings = new Label(stringConstants.trackSettings()); - trackPanel.add(lblTrackSettings); - - final CheckBox trackWindCheckbox = new CheckBox(stringConstants.trackWind()); - trackWindCheckbox.setWordWrap(false); - trackWindCheckbox.setValue(true); - trackPanel.add(trackWindCheckbox); - - final CheckBox declinationCheckbox = new CheckBox(stringConstants.declinationCheckbox()); - declinationCheckbox.setWordWrap(false); - declinationCheckbox.setValue(true); - trackPanel.add(declinationCheckbox); + trackedRacesPanel.add(trackedRacesListComposite); HorizontalPanel racesButtonPanel = new HorizontalPanel(); - racesPanel.add(racesButtonPanel); + trackableRacesPanel.add(racesButtonPanel); Button btnTrack = new Button(stringConstants.startTracking()); racesButtonPanel.add(btnTrack); @@ -273,7 +271,6 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane trackSelectedRaces(trackWindCheckbox.getValue(), declinationCheckbox.getValue()); } }); - } private ListHandler getRaceTableColumnSortHandler(List raceRecords, diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSelector.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSelector.java index 3784062e484..4f5713431d5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSelector.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaSelector.java @@ -65,6 +65,7 @@ public class MediaSelector implements PlayStateListener, TimeListener, private StringMessages stringMessages; private final ErrorReporter errorReporter; private final UserDTO user; + private boolean autoSelectMedia; private MediaPlayer activeAudioPlayer; private Date currentRaceTime; @@ -73,7 +74,7 @@ public class MediaSelector implements PlayStateListener, TimeListener, public MediaSelector(RegattaAndRaceIdentifier selectedRaceIdentifier, RaceTimesInfoProvider raceTimesInfoProvider, Timer raceTimer, MediaServiceAsync mediaService, StringMessages stringMessages, - ErrorReporter errorReporter, UserDTO user) { + ErrorReporter errorReporter, UserDTO user, boolean autoSelectMedia) { this.raceIdentifier = selectedRaceIdentifier; this.raceTimesInfoProvider = raceTimesInfoProvider; this.raceTimer = raceTimer; @@ -81,6 +82,7 @@ public class MediaSelector implements PlayStateListener, TimeListener, this.stringMessages = stringMessages; this.errorReporter = errorReporter; this.user = user; + this.autoSelectMedia = autoSelectMedia; Window.addCloseHandler(this); Window.addWindowClosingHandler(this); @@ -120,7 +122,6 @@ public class MediaSelector implements PlayStateListener, TimeListener, } }); - setWidgetsVisible(false); } @@ -249,12 +250,12 @@ public class MediaSelector implements PlayStateListener, TimeListener, } private void startPlaying() { - if (activeAudioPlayer != null) { + if ((activeAudioPlayer != null) && activeAudioPlayer.isCoveringCurrentRaceTime()) { activeAudioPlayer.playMedia(); } - for (MediaPlayer player : videoPlayers.values()) { - if (player.isMediaPaused()) { - player.playMedia(); + for (MediaPlayer videoPlayer : videoPlayers.values()) { + if (videoPlayer.isMediaPaused() && videoPlayer.isCoveringCurrentRaceTime()) { + videoPlayer.playMedia(); } } } @@ -286,6 +287,11 @@ public class MediaSelector implements PlayStateListener, TimeListener, setStatus(mediaTrack); } setWidgetsVisible((this.mediaTracks.size() > 0) || (this.user != null)); + + toggleMediaButton.setValue(autoSelectMedia); + if (autoSelectMedia) { + playDefault(); + } } private void setWidgetsVisible(boolean isVisible) { @@ -452,7 +458,7 @@ public class MediaSelector implements PlayStateListener, TimeListener, private void ensurePlayState(final MediaPlayer mediaPlayer) { switch (this.currentPlayState) { case Playing: - if (mediaPlayer.isMediaPaused()) { + if (mediaPlayer.isMediaPaused() && mediaPlayer.isCoveringCurrentRaceTime()) { mediaPlayer.playMedia(); } break; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/shared/AbstractMediaPlayer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/shared/AbstractMediaPlayer.java index dd16e80d778..0ac8039b9fd 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/shared/AbstractMediaPlayer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/shared/AbstractMediaPlayer.java @@ -7,7 +7,7 @@ import com.sap.sailing.domain.common.media.MediaTrack; public abstract class AbstractMediaPlayer implements MediaPlayer { - private static final int TOLERATED_LAG_IN_MILLISECONDS = 2000; + private static final int TOLERATED_LAG_IN_MILLISECONDS = 4000; private final MediaTrack mediaTrack; private long raceTimeInMillis; @@ -15,7 +15,7 @@ public abstract class AbstractMediaPlayer implements MediaPlayer { this.mediaTrack = mediaTrack; } - public MediaTrack getMediaTrack() { + public MediaTrack getMediaTrack() { return mediaTrack; } @@ -37,6 +37,12 @@ public abstract class AbstractMediaPlayer implements MediaPlayer { return Math.round(getCurrentMediaTime() * 1000); } + @Override + public boolean isCoveringCurrentRaceTime() { + double mediaTime = (raceTimeInMillis - mediaTrack.startTime.getTime()) / 1000d; + return (mediaTime >= 0) && (mediaTime <= getDuration()); + } + protected void alignTime() { long mediaStartTimeInMillis = mediaTrack.startTime.getTime(); long mediaTimeInMillis = mediaStartTimeInMillis + getCurrentMediaTimeMillis(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/shared/MediaPlayer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/shared/MediaPlayer.java index a12b278f04e..6eeecd65843 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/shared/MediaPlayer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/shared/MediaPlayer.java @@ -31,4 +31,6 @@ public interface MediaPlayer { void close(); + boolean isCoveringCurrentRaceTime(); + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java index c17b2e008e3..ad1e4bb3724 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java @@ -82,8 +82,9 @@ public class RaceBoardEntryPoint extends AbstractEntryPoint { boolean showCompetitorsChart = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_COMPETITORSCHART, false /* default*/); String activeCompetitorsFilterSetName = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_VIEW_COMPETITOR_FILTER, null /* default*/); final boolean canReplayWhileLiveIsPossible = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_CAN_REPLAY_DURING_LIVE_RACES, false); + final boolean autoSelectMedia = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_AUTOSELECT_MEDIA, false); raceboardViewConfig = new RaceBoardViewConfiguration(viewMode, activeCompetitorsFilterSetName, showLeaderboard, - showWindChart, showCompetitorsChart, canReplayWhileLiveIsPossible); + showWindChart, showCompetitorsChart, canReplayWhileLiveIsPossible, autoSelectMedia); final ParallelExecutionCallback> getLeaderboardNamesCallback = new ParallelExecutionCallback>(); final ParallelExecutionCallback> getRegattasCallback = new ParallelExecutionCallback>(); @@ -221,7 +222,7 @@ public class RaceBoardEntryPoint extends AbstractEntryPoint { } FlowPanel logoAndTitlePanel = createLogoAndTitlePanel(raceBoardPanel); FlowPanel timePanel = createTimePanel(raceBoardPanel); - p.addNorth(logoAndTitlePanel, 68); + p.addNorth(logoAndTitlePanel, 68); p.addNorth(toolbarPanel, 40); p.addSouth(timePanel, 90); p.add(raceBoardPanel); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java index 33b9dfb35f8..5c1425206dc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java @@ -160,7 +160,6 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac toolbarPanel = new FlowPanel(); toolbarPanel.setWidth("100%"); - mainPanel.add(toolbarPanel); componentControlsPanel = new FlowPanel(); componentControlsPanel.addStyleName("raceBoardNavigation"); toolbarPanel.add(componentControlsPanel); @@ -181,7 +180,7 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac } CompetitorsFilterSets loadedCompetitorsFilterSets = loadCompetitorsFilterSets(); - if(loadedCompetitorsFilterSets != null) { + if (loadedCompetitorsFilterSets != null) { competitorsFilterSets = loadedCompetitorsFilterSets; insertSelectedCompetitorsFilter(competitorsFilterSets); } else { @@ -190,9 +189,9 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac } // in case the URL configuration contains the name of a competitors filter set we try to activate it - if(raceboardViewConfiguration.getActiveCompetitorsFilterSetName() != null) { - for(FilterSet> filterSet: competitorsFilterSets.getFilterSets()) { - if(filterSet.getName().equals(raceboardViewConfiguration.getActiveCompetitorsFilterSetName())) { + if (raceboardViewConfiguration.getActiveCompetitorsFilterSetName() != null) { + for (FilterSet> filterSet: competitorsFilterSets.getFilterSets()) { + if (filterSet.getName().equals(raceboardViewConfiguration.getActiveCompetitorsFilterSetName())) { competitorsFilterSets.setActiveFilterSet(filterSet); break; } @@ -277,7 +276,7 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac } private void addMediaSelectorToNavigationMenu() { - MediaSelector mediaSelector = new MediaSelector(selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, stringMessages, errorReporter, this.user); + MediaSelector mediaSelector = new MediaSelector(selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, stringMessages, errorReporter, this.user, getConfiguration().isAutoSelectMedia()); // raceTimesInfoProvider.addRaceTimesInfoProviderListener(mediaSelector); timer.addPlayStateListener(mediaSelector); timer.addTimeListener(mediaSelector); @@ -461,7 +460,7 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac private void addComponentToNavigationMenu(final ComponentViewer componentViewer, final Component component, boolean isToogleCheckboxEnabled) { - final CheckBox checkBox= new CheckBox(component.getLocalizedShortName()); + final CheckBox checkBox = new CheckBox(component.getLocalizedShortName()); checkBox.getElement().getStyle().setFloat(Style.Float.LEFT); checkBox.setEnabled(isToogleCheckboxEnabled); @@ -489,7 +488,7 @@ public class RaceBoardPanel extends SimplePanel implements RegattaDisplayer, Rac componentControlsPanel.add(checkBox); - if(component.hasSettings()) { + if (component.hasSettings()) { Button settingsButton = new Button(""); settingsButton.addClickHandler(new ClickHandler() { @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardViewConfiguration.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardViewConfiguration.java index 2cf0145934e..bf635989bf4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardViewConfiguration.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardViewConfiguration.java @@ -12,14 +12,16 @@ public class RaceBoardViewConfiguration { private ViewModes viewMode; private String activeCompetitorsFilterSetName; private boolean canReplayDuringLiveRaces; + private final boolean autoSelectMedia; - public static final String PARAM_VIEW_MODE = "viewMode"; + public static final String PARAM_VIEW_MODE = "viewMode"; public static final String PARAM_VIEW_SHOW_LEADERBOARD = "viewShowLeaderboard"; public static final String PARAM_VIEW_SHOW_NAVIGATION_PANEL = "viewShowNavigationPanel"; public static final String PARAM_VIEW_SHOW_WINDCHART = "viewShowWindChart"; public static final String PARAM_VIEW_SHOW_COMPETITORSCHART = "viewShowCompetitorsChart"; public static final String PARAM_VIEW_COMPETITOR_FILTER = "viewCompetitorFilter"; public static final String PARAM_CAN_REPLAY_DURING_LIVE_RACES = "canReplayDuringLiveRaces"; + public static final String PARAM_AUTOSELECT_MEDIA = "autoSelectMedia"; public static enum ViewModes { ONESCREEN }; @@ -28,16 +30,18 @@ public class RaceBoardViewConfiguration { showLeaderboard = true; showWindChart = false; showCompetitorsChart = false; - } + autoSelectMedia = false; + } public RaceBoardViewConfiguration(ViewModes viewMode, String activeCompetitorsFilterSetName, - boolean showLeaderboard, boolean showWindChart, boolean showCompetitorsChart, boolean canReplayDuringLiveRaces) { + boolean showLeaderboard, boolean showWindChart, boolean showCompetitorsChart, boolean canReplayDuringLiveRaces, boolean autoSelectMedia) { this.viewMode = viewMode; this.activeCompetitorsFilterSetName = activeCompetitorsFilterSetName; this.showLeaderboard = showLeaderboard; this.showWindChart = showWindChart; this.showCompetitorsChart = showCompetitorsChart; this.canReplayDuringLiveRaces = canReplayDuringLiveRaces; + this.autoSelectMedia = autoSelectMedia; } public boolean isShowLeaderboard() { @@ -63,4 +67,9 @@ public class RaceBoardViewConfiguration { public boolean isCanReplayDuringLiveRaces() { return canReplayDuringLiveRaces; } + + public boolean isAutoSelectMedia() { + return autoSelectMedia; + } + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 321c2a117e7..dac41fa7184 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -1250,13 +1250,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S GPSFixMoving fix = fixIter.next(); while (fix != null && (fix.getTimePoint().compareTo(toTimePointExcluding) < 0 || (fix.getTimePoint().equals(toTimePointExcluding) && toTimePointExcluding.equals(fromTimePoint)))) { - Tack tack = trackedRace.getTack(competitor, fix.getTimePoint()); + Tack tack; + try { + tack = trackedRace.getTack(competitor, fix.getTimePoint()); + } catch (NoWindException nwe) { + tack = null; + } TrackedLegOfCompetitor trackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor, fix.getTimePoint()); LegType legType = trackedLegOfCompetitor == null ? null : trackedRace.getTrackedLeg( trackedLegOfCompetitor.getLeg()).getLegType(fix.getTimePoint()); Wind wind = trackedRace.getWind(fix.getPosition(),toTimePointExcluding); - WindDTO windDTO = createWindDTOFromAlreadyAveraged(wind, toTimePointExcluding); + WindDTO windDTO = wind == null ? null : createWindDTOFromAlreadyAveraged(wind, toTimePointExcluding); GPSFixDTO fixDTO = createGPSFixDTO(fix, fix.getSpeed(), windDTO, tack, legType, /* extrapolate */ false); fixesForCompetitor.add(fixDTO); @@ -1266,13 +1271,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S // check if fix was at date and if extrapolation is requested if (!fix.getTimePoint().equals(toTimePointExcluding) && extrapolate) { Position position = track.getEstimatedPosition(toTimePointExcluding, extrapolate); - Tack tack2 = trackedRace.getTack(competitor, toTimePointExcluding); + Tack tack2; + try { + tack2 = trackedRace.getTack(competitor, toTimePointExcluding); + } catch (NoWindException nwe) { + tack2 = null; + } LegType legType2 = trackedLegOfCompetitor == null ? null : trackedRace .getTrackedLeg(trackedLegOfCompetitor.getLeg()).getLegType( fix.getTimePoint()); SpeedWithBearing speedWithBearing = track.getEstimatedSpeed(toTimePointExcluding); Wind wind2 = trackedRace.getWind(position, toTimePointExcluding); - WindDTO windDTO2 = createWindDTOFromAlreadyAveraged(wind2, toTimePointExcluding); + WindDTO windDTO2 = wind2 == null ? null : createWindDTOFromAlreadyAveraged(wind2, toTimePointExcluding); GPSFixDTO extrapolated = new GPSFixDTO( toPerCompetitorIdAsString.get(competitorDTO.getIdAsString()), position==null?null:new PositionDTO(position.getLatDeg(), position.getLngDeg()), @@ -2022,6 +2032,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S BoatClass boatClass = com.sap.sailing.domain.swisstimingadapter.DomainFactory.INSTANCE.getRaceTypeFromRaceID(rr.getRaceID()).getBoatClass(); swissTimingRaceRecordDTO.boatClass = boatClass != null ? boatClass.getName() : null; swissTimingRaceRecordDTO.discipline = rr.getRaceID().length() >= 3 ? rr.getRaceID().substring(2, 3) : null; + swissTimingRaceRecordDTO.hasCourse = rr.hasCourse(); + swissTimingRaceRecordDTO.hasStartlist = rr.hasStartlist(); result.add(swissTimingRaceRecordDTO); } return result; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SwissTimingRaceRecordDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SwissTimingRaceRecordDTO.java index 5c35646c466..e4de44f166e 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SwissTimingRaceRecordDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SwissTimingRaceRecordDTO.java @@ -13,6 +13,9 @@ public class SwissTimingRaceRecordDTO implements IsSerializable { public String boatClass; public String discipline; + public boolean hasCourse; + public boolean hasStartlist; + public SwissTimingRaceRecordDTO() {} public SwissTimingRaceRecordDTO(String id, String description, Date raceStartTime) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/tv/TVEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/tv/TVEntryPoint.java index 33baa271d78..66cc46ef4e4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/tv/TVEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/tv/TVEntryPoint.java @@ -43,8 +43,9 @@ public class TVEntryPoint extends AbstractEntryPoint { final boolean showCompetitorsChart = GwtHttpRequestUtils.getBooleanParameter( RaceBoardViewConfiguration.PARAM_VIEW_SHOW_COMPETITORSCHART, false /* default */); String activeCompetitorsFilterSetName = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_VIEW_COMPETITOR_FILTER, null /* default*/); + final boolean autoSelectMedia = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_AUTOSELECT_MEDIA, false); raceboardViewConfig = new RaceBoardViewConfiguration(RaceBoardViewConfiguration.ViewModes.ONESCREEN, - activeCompetitorsFilterSetName, showLeaderboard, showWindChart, showCompetitorsChart, /* canReplayWhileLiveIsPossible */ false); + activeCompetitorsFilterSetName, showLeaderboard, showWindChart, showCompetitorsChart, /* canReplayWhileLiveIsPossible */ false, autoSelectMedia); sailingService.getLeaderboardNames(new AsyncCallback>() { @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/tv/TVViewController.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/tv/TVViewController.java index ccd7b9b9ede..706dc7d4307 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/tv/TVViewController.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/tv/TVViewController.java @@ -169,7 +169,7 @@ public class TVViewController implements RaceTimesInfoProviderListener { ScrollPanel leaderboardContentPanel = new ScrollPanel(); leaderboardContentPanel.add(leaderboardPanel); dockPanel.add(leaderboardContentPanel); - if(logoAndTitlePanel != null) { + if (logoAndTitlePanel != null) { logoAndTitlePanel.setSubTitle(leaderboardName); } currentLiveRace = null; @@ -180,7 +180,7 @@ public class TVViewController implements RaceTimesInfoProviderListener { } private void showRaceBoard() { - if(activeTvView != TVViews.Raceboard) { + if (activeTvView != TVViews.Raceboard) { clearContentPanels(); RaceBoardPanel raceBoardPanel = createRaceBoardPanel(leaderboardName, currentLiveRace); raceBoardPanel.setSize("100%", "100%"); diff --git a/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF index a6c1bf2a0ec..d5eb223095b 100755 --- a/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.mongodb.test/META-INF/MANIFEST.MF @@ -17,9 +17,8 @@ Require-Bundle: com.sap.sailing.domain, org.json.simple;bundle-version="1.1.0", com.sap.sailing.domain.swisstimingadapter, org.objenesis;bundle-version="1.3.0", + org.junit4;bundle-version="4.8.2", org.hamcrest;bundle-version="1.1.0", org.mockito.mockito-core;bundle-version="1.9.5" -Import-Package: com.sap.sailing.domain.common.impl, - junit.framework;version="4.8.2", - org.junit;version="4.8.2" +Import-Package: com.sap.sailing.domain.common.impl diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogsTest.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogsTest.java index 307c33159c2..b6006cb819d 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogsTest.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogsTest.java @@ -108,7 +108,7 @@ public class StoreAndLoadRaceLogsTest extends AbstractMongoDBTest { } @Test - public void testdLoadObsoleteAndNewIdentifier() { + public void testLoadObsoleteAndNewIdentifier() { // event1 stored with obsolete identifier DBObject dbEvent1 = (DBObject) com.mongodb.util.JSON.parse(createOldFormatRaceLogEventJson(UUID.randomUUID())); mongoFactory.getRaceLogCollection().insert(dbEvent1); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java index 5223c642de0..35321662f18 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java @@ -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); } diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboardGroups.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboardGroups.java index 0e71b7b8415..be053083ef2 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboardGroups.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboardGroups.java @@ -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 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 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 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 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 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 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 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 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); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboards.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboards.java index 7a9c5ba94ed..baf2b19dd4e 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboards.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingLeaderboards.java @@ -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() { diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java index 02857b3b6fa..b24d5353232 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java @@ -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(); @@ -270,7 +269,7 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningConfirmedEvent.class.getSimpleName()); DBObject raceLogResult = new BasicDBObject(); - raceLogResult.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceColumn.getRaceLogIdentifier(defaultFleet).getIdentifier().toString())); + raceLogResult.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceColumn.getRaceLogIdentifier(defaultFleet).getDeprecatedIdentifier())); raceLogResult.put(FieldNames.RACE_LOG_EVENT.name(), result); MongoObjectFactoryImpl factoryImpl = (MongoObjectFactoryImpl) mongoObjectFactory; @@ -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(); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java index 43c70355943..c5ad19d801e 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java @@ -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(); @@ -337,7 +337,7 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends RaceLogMongoDBTest result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogFinishPositioningConfirmedEvent.class.getSimpleName()); DBObject raceLogResult = new BasicDBObject(); - raceLogResult.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceColumn.getRaceLogIdentifier(fleet).getIdentifier().toString())); + raceLogResult.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceColumn.getRaceLogIdentifier(fleet).getDeprecatedIdentifier())); raceLogResult.put(FieldNames.RACE_LOG_EVENT.name(), result); MongoObjectFactoryImpl factoryImpl = (MongoObjectFactoryImpl) mongoObjectFactory; diff --git a/java/com.sap.sailing.operationaltransformation.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.operationaltransformation.test/META-INF/MANIFEST.MF index fe6bfc231d8..cfbf1295ca0 100755 --- a/java/com.sap.sailing.operationaltransformation.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.operationaltransformation.test/META-INF/MANIFEST.MF @@ -5,5 +5,5 @@ Bundle-SymbolicName: com.sap.sailing.operationaltransformation.test Bundle-Version: 1.0.0.qualifier Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Require-Bundle: org.junit4;bundle-version="4.8.2" Fragment-Host: com.sap.sailing.operationaltransformation -Import-Package: org.junit;version="4.8.2" diff --git a/java/com.sap.sailing.selenium.test/ci-test-environment.xml b/java/com.sap.sailing.selenium.test/ci-test-environment.xml index 2cb73ec5cf8..ea3299033c0 100644 --- a/java/com.sap.sailing.selenium.test/ci-test-environment.xml +++ b/java/com.sap.sailing.selenium.test/ci-test-environment.xml @@ -13,7 +13,7 @@ - http://riccardo:riccardo@localhost:8086/ + http://riccardo:riccardo@localhost:8085/ + + Jersey REST API + com.sap.sailing.server.gateway.jaxrs.RestServletContainer + + javax.ws.rs.Application + com.sap.sailing.server.gateway.jaxrs.api.RestApiApplication + + 1 + + + Jersey REST API + /api/* + + + + Jersey REST SPI + com.sap.sailing.server.gateway.jaxrs.RestServletContainer + + javax.ws.rs.Application + com.sap.sailing.server.gateway.jaxrs.spi.RestSpiApplication + + 1 + + + Jersey REST SPI + /spi/* + + diff --git a/java/com.sap.sailing.server.gateway/main.css b/java/com.sap.sailing.server.gateway/main.css index 42f35247a3f..c2de8aa273b 100644 --- a/java/com.sap.sailing.server.gateway/main.css +++ b/java/com.sap.sailing.server.gateway/main.css @@ -26,7 +26,7 @@ body { font-size: 14px; font-family: OpenSansRegular, Arial, Verdana, sans-serif; font-weight: normal; - margin: 0px; + margin: 10px; padding: 0px; line-height: 18px; } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LeaderboardJsonGetServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LeaderboardJsonGetServlet.java index 2e281bb79ad..a4a7938d493 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LeaderboardJsonGetServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LeaderboardJsonGetServlet.java @@ -2,6 +2,7 @@ package com.sap.sailing.server.gateway.impl; import java.io.IOException; import java.io.StringWriter; +import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; @@ -59,6 +60,7 @@ public class LeaderboardJsonGetServlet extends AbstractJsonHttpServlet implement // for backward compatibility the default result state is live private final ResultStates DEFAULT_RESULT_STATE = ResultStates.Live; + private static SimpleDateFormat TIMEPOINT_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); private static final int MAX_TOTAL_NUMBER_OF_CACHE_ENTRIES = 1000; @@ -143,7 +145,8 @@ public class LeaderboardJsonGetServlet extends AbstractJsonHttpServlet implement totalNumberOfCacheEntries -= oldCacheValue.size(); } } else { - result = new LinkedHashMap, StringBuffer>(16, 0.75f, /* access-based eviction */ true) { + // Note: don't use access-based ordering as it turns the get(...) call into a "write" access + result = new LinkedHashMap, StringBuffer>(16, 0.75f) { private static final long serialVersionUID = -6197983565575024084L; @Override protected boolean removeEldestEntry(Entry, StringBuffer> eldest) { @@ -220,7 +223,7 @@ public class LeaderboardJsonGetServlet extends AbstractJsonHttpServlet implement setJsonResponseHeader(resp); synchronized (jsonLeaderboardAsString) { int indexOfFirstOpeningBrace = jsonLeaderboardAsString.indexOf("{"); - final String requestTimePointAsJson = "\"requestTimepoint\": \""+requestTimePoint.toString()+"\", "; + final String requestTimePointAsJson = "\"requestTimepoint\": \"" + formatTimePoint(requestTimePoint) + "\", "; if (indexOfFirstOpeningBrace >= 0) { jsonLeaderboardAsString.insert(indexOfFirstOpeningBrace+1, requestTimePointAsJson); } @@ -312,13 +315,17 @@ 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++; } return jsonLeaderboard; } + private String formatTimePoint(TimePoint timepoint) { + return timepoint == null ? null : TIMEPOINT_FORMATTER.format(timepoint.asDate()); + } + private JSONObject createEmptyLeaderboardJson(Leaderboard leaderboard, ResultStates resultState, TimePoint requestTimePoint, Integer maxCompetitorsCount) throws NoWindException { JSONObject jsonLeaderboard = new JSONObject(); @@ -365,9 +372,9 @@ public class LeaderboardJsonGetServlet extends AbstractJsonHttpServlet implement jsonLeaderboard.put("name", leaderboard.getName()); // for backward compatibility - jsonLeaderboard.put("timepoint", resultTimePoint != null ? resultTimePoint.toString() : null); + jsonLeaderboard.put("timepoint", formatTimePoint(resultTimePoint)); - jsonLeaderboard.put("resultTimepoint", resultTimePoint != null ? resultTimePoint.toString() : null); + jsonLeaderboard.put("resultTimepoint", formatTimePoint(resultTimePoint)); jsonLeaderboard.put("resultState", resultState.name()); jsonLeaderboard.put("maxCompetitorsCount", maxCompetitorsCount); @@ -375,7 +382,7 @@ public class LeaderboardJsonGetServlet extends AbstractJsonHttpServlet implement if (scoreCorrection != null) { jsonLeaderboard.put("scoringComment", scoreCorrection.getComment()); TimePoint lastUpdateTimepoint = scoreCorrection.getTimePointOfLastCorrectionsValidity(); - jsonLeaderboard.put("lastScoringUpdate", lastUpdateTimepoint != null ? lastUpdateTimepoint.asDate().toString(): null); + jsonLeaderboard.put("lastScoringUpdate", formatTimePoint(lastUpdateTimepoint)); } else { jsonLeaderboard.put("scoringComment", null); jsonLeaderboard.put("lastScoringUpdate", null); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LiveRaceRankingRssGetServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LiveRaceRankingRssGetServlet.java deleted file mode 100644 index 0d96201b131..00000000000 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/LiveRaceRankingRssGetServlet.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.sap.sailing.server.gateway.impl; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.RaceColumn; -import com.sap.sailing.domain.common.TimePoint; -import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.tracking.TrackedRace; -import com.sap.sailing.server.gateway.SailingServerHttpServlet; -import com.sun.syndication.feed.synd.SyndContent; -import com.sun.syndication.feed.synd.SyndContentImpl; -import com.sun.syndication.feed.synd.SyndEntry; -import com.sun.syndication.feed.synd.SyndEntryImpl; -import com.sun.syndication.feed.synd.SyndFeed; -import com.sun.syndication.feed.synd.SyndFeedImpl; -import com.sun.syndication.io.SyndFeedOutput; - -public class LiveRaceRankingRssGetServlet extends SailingServerHttpServlet { - private static final long serialVersionUID = -508373964426868319L; - private static final String PARAM_NAME_LEADERBOARDNAME = "leaderboardName"; - private static final String PARAM_MAX_COMPETITORS = "max"; - private String charEncoding = "UTF-8"; - private int maxCompetitorsToShow = 1000; - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - // to allow access to the rss feed directly from a client side javascript - resp.setHeader("Access-Control-Allow-Origin", "*"); - resp.setContentType("application/rss+xml"); - resp.setCharacterEncoding(charEncoding); - - TimePoint timePoint = MillisecondsTimePoint.now(); - String leaderboardName = req.getParameter(PARAM_NAME_LEADERBOARDNAME); - String maxCompetitorsParam = req.getParameter(PARAM_MAX_COMPETITORS); - if(maxCompetitorsParam != null) { - try { - maxCompetitorsToShow = Integer.parseInt(maxCompetitorsParam); - } catch (NumberFormatException e) { - } - } - - if (leaderboardName == null) { - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Need to specify a leaderboard name using the "+ - PARAM_NAME_LEADERBOARDNAME+" parameter"); - } else { - Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); - if (leaderboard == null) { - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Leaderboard "+leaderboardName+" not found"); - } else { - try { - RaceColumn raceColumnToShow = null; - TrackedRace liveTrackedRace = null; - - // find a live race in the leaderboard - Iterable races = leaderboard.getRaceColumns(); - for (RaceColumn raceInLeaderboard : races) { - for (Fleet fleet : raceInLeaderboard.getFleets()) { - TrackedRace trackedRaceOfFleet = raceInLeaderboard.getTrackedRace(fleet); - if(trackedRaceOfFleet != null && isLive(trackedRaceOfFleet)) { - raceColumnToShow = raceInLeaderboard; - liveTrackedRace = trackedRaceOfFleet; - break; - } - } - } - - SyndFeed feed = new SyndFeedImpl(); - String title = leaderboard.getName(); - feed.setTitle(title); - feed.setFeedType("rss_2.0"); - feed.setLink("http://www.sapsaling.com"); - feed.setDescription("SAP Sailing Analytics"); - feed.setPublishedDate(new Date()); - feed.setEncoding(charEncoding); - - List entries = new ArrayList(); - SyndContent description = new SyndContentImpl(); - SyndEntry entry = new SyndEntryImpl(); - entry.setLink("http://www.sapsailing.com"); - description.setType("text/plain"); - - if(raceColumnToShow != null && liveTrackedRace != null) { - String entryTitle = "Live ranking of race '" + raceColumnToShow.getName() + "'"; - entry.setTitle(entryTitle); - - - - List competitorsFromBestToWorst = leaderboard.getCompetitorsFromBestToWorst(raceColumnToShow, timePoint); - int currentCompetitorCounter = 0; - String feedText = ""; - - for (Competitor competitor : competitorsFromBestToWorst) { - if(currentCompetitorCounter == maxCompetitorsToShow) { - break; - } - currentCompetitorCounter++; - String sailID = competitor.getBoat().getSailID(); - feedText += currentCompetitorCounter + ". " + sailID + "\n"; - -// String competitorName = competitor.getName(); -// final String displayName = leaderboard.getDisplayName(competitor); -// String id = competitor.getId().toString(); -// Nationality nationality = competitor.getTeam().getNationality(); -// String nat = nationality != null ? nationality.getThreeLetterIOCAcronym(): null; -// String countryCode = nationality != null ? nationality.getCountryCode().getTwoLetterISOCode(): null; -// String totalRank = "" +competitorsFromBestToWorst.indexOf(competitor) + 1; -// String totalPoints = "" + leaderboard.getTotalPoints(competitor, timePoint); -// String raceColumnName = raceColumnToShow.getName(); -// final Fleet fleetOfCompetitor = raceColumnToShow.getFleetOfCompetitor(competitor); -// String fleet = fleetOfCompetitor==null?"":fleetOfCompetitor.getName(); -// String netpoints = String.valueOf(leaderboard.getNetPoints(competitor, raceColumnToShow, timePoint)); -// String totalPointsRaceColumn = String.valueOf(leaderboard.getTotalPoints(competitor, raceColumnToShow, timePoint)); -// MaxPointsReason maxPointsReason = leaderboard.getMaxPointsReason(competitor, raceColumnToShow, timePoint); -// String maxPoints = maxPointsReason != null ? maxPointsReason.toString(): null; -// String isDiscarded = String.valueOf(leaderboard.isDiscarded(competitor, raceColumnToShow, timePoint)); -// String isCorrected = String.valueOf(leaderboard.getScoreCorrection().isScoreCorrected(competitor, raceColumnToShow)); - - } - description.setValue(feedText); - } else { - String entryTitle = "No live race right now"; - entry.setTitle(entryTitle); - description.setValue(""); - } - - entry.setDescription(description); - entries.add(entry); - feed.setEntries(entries); - - PrintWriter writer = resp.getWriter(); - SyndFeedOutput feedOutput = new SyndFeedOutput(); - feedOutput.output(feed, writer); - } catch (Exception e) { - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); - } - } - } - } - - /** - * @return true if the startOfTracking is after the current date and there's no end of the race - */ - private boolean isLive(TrackedRace trackedRace) { - return trackedRace.getEndOfRace() == null && (trackedRace.getStartOfTracking() != null ? new Date().after(trackedRace.getStartOfTracking().asDate()) : false); - } - -} diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java new file mode 100644 index 00000000000..8a25a293f9d --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java @@ -0,0 +1,66 @@ +package com.sap.sailing.server.gateway.jaxrs; + +import javax.servlet.ServletContext; +import javax.ws.rs.core.Context; + +import org.osgi.util.tracker.ServiceTracker; + +import com.sap.sailing.domain.base.RaceDefinition; +import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; +import com.sap.sailing.domain.tracking.DynamicTrackedRegatta; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.server.RacingEventService; +import com.sap.sailing.util.DateParser; +import com.sap.sailing.util.InvalidDateException; + +public abstract class AbstractSailingServerResource { + @Context ServletContext servletContext; + + public RacingEventService getService() { + @SuppressWarnings("unchecked") + ServiceTracker tracker = (ServiceTracker) servletContext.getAttribute(RestServletContainer.RACING_EVENT_SERVICE_TRACKER_NAME); + return tracker.getService(); + } + + protected Regatta findRegattaByName(String regattaName) { + return getService().getRegattaByName(regattaName); + } + + protected RaceDefinition findRaceByName(Regatta regatta, String raceName) { + RaceDefinition result = null; + if(regatta != null) { + for (RaceDefinition race : regatta.getAllRaces()) { + if (race.getName().equals(raceName)) { + result = race; + break; + } + } + } + return result; + } + + protected TimePoint parseTimePoint(String isoTime, Long timeAsMillis, TimePoint defaultTime) throws InvalidDateException { + TimePoint timePoint; + if (isoTime != null && isoTime.length() > 0) { + timePoint = new MillisecondsTimePoint(DateParser.parse(isoTime).getTime()); + } else { + timePoint = timeAsMillis != null ? new MillisecondsTimePoint(timeAsMillis) : defaultTime; + } + return timePoint; + } + + protected TrackedRace findTrackedRace(String regattaName, String raceName) { + Regatta regatta = findRegattaByName(regattaName); + RaceDefinition race = findRaceByName(regatta, raceName); + TrackedRace trackedRace = null; + if (regatta != null && race != null) { + DynamicTrackedRegatta trackedRegatta = getService().getTrackedRegatta(regatta); + if(trackedRegatta != null) { + trackedRace = trackedRegatta.getTrackedRace(race); + } + } + return trackedRace; + } +} diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/RestServletContainer.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/RestServletContainer.java new file mode 100644 index 00000000000..70a6ae1eecd --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/RestServletContainer.java @@ -0,0 +1,57 @@ +package com.sap.sailing.server.gateway.jaxrs; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.ws.rs.core.Application; + +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; + +import com.sap.sailing.server.RacingEventService; +import com.sun.jersey.spi.container.servlet.ServletContainer; + +public class RestServletContainer extends ServletContainer { + private static final long serialVersionUID = -3132655822281021061L; + + private static final String OSGI_RFC66_WEBBUNDLE_BUNDLECONTEXT_NAME = "osgi-bundlecontext"; + + public static final String RACING_EVENT_SERVICE_TRACKER_NAME = "racingEventServiceTracker"; + + private ServiceTracker racingEventServiceTracker; + + public RestServletContainer() { + super(); + } + + public RestServletContainer(Application app) { + super(app); + } + + public RestServletContainer(Class appClass) { + super(appClass); + } + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + + BundleContext context = (BundleContext) config.getServletContext().getAttribute(OSGI_RFC66_WEBBUNDLE_BUNDLECONTEXT_NAME); + racingEventServiceTracker = new ServiceTracker(context, RacingEventService.class.getName(), null); + racingEventServiceTracker.open(); + + config.getServletContext().setAttribute(RACING_EVENT_SERVICE_TRACKER_NAME, racingEventServiceTracker); + } + + @Override + public void destroy() { + super.destroy(); + + if(racingEventServiceTracker != null) { + racingEventServiceTracker.close(); + } + } + + public RacingEventService getService() { + return racingEventServiceTracker.getService(); + } +} diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/UnitSerializationUtil.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/UnitSerializationUtil.java new file mode 100644 index 00000000000..6aa296f52db --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/UnitSerializationUtil.java @@ -0,0 +1,22 @@ +package com.sap.sailing.server.gateway.jaxrs; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; + +public class UnitSerializationUtil { + public static final DecimalFormat distanceDecimalFormatter = new DecimalFormat("#.##"); + public static final DecimalFormat knotsDecimalFormatter = new DecimalFormat("#.##"); + public static final DecimalFormat bearingDecimalFormatter = new DecimalFormat("#.#"); + public static final DecimalFormat speedDecimalFormatter = new DecimalFormat("#.#"); + public static final DecimalFormat latLngDecimalFormatter = new DecimalFormat("#.######"); + + static { + DecimalFormatSymbols symbol = DecimalFormatSymbols.getInstance(); + symbol.setDecimalSeparator('.'); + distanceDecimalFormatter.setDecimalFormatSymbols(symbol); + knotsDecimalFormatter.setDecimalFormatSymbols(symbol); + bearingDecimalFormatter.setDecimalFormatSymbols(symbol); + speedDecimalFormatter.setDecimalFormatSymbols(symbol); + latLngDecimalFormatter.setDecimalFormatSymbols(symbol); + } +} diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DefaultWindTrackJsonSerializer.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DefaultWindTrackJsonSerializer.java new file mode 100644 index 00000000000..5b2694af404 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DefaultWindTrackJsonSerializer.java @@ -0,0 +1,80 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.WindSource; +import com.sap.sailing.domain.tracking.Wind; +import com.sap.sailing.domain.tracking.WindTrack; +import com.sap.sailing.server.gateway.jaxrs.UnitSerializationUtil; + +public class DefaultWindTrackJsonSerializer implements WindTrackJsonSerializer { + public static final String FIELD_ID = "id"; + public static final String FIELD_NAME = "name"; + public static final String FIELD_PUBLICATION_URL = "publicationUrl"; + public static final String FIELD_VENUE = "venue"; + + private TimePoint fromTime; + private TimePoint toTime; + private WindSource windSource; + + public JSONObject serialize(WindTrack windTrack) { + JSONObject result = new JSONObject(); + JSONArray jsonWindFixes = new JSONArray(); + + // quickly extract relevant fixes to hold locks as shortly as possible; process later + ArrayList fixes = new ArrayList<>(); + windTrack.lockForRead(); + try { + Iterator windIter = windTrack.getFixesIterator(fromTime, /* inclusive */true); + while (windIter.hasNext()) { + Wind wind = windIter.next(); + if (wind.getTimePoint().compareTo(toTime) > 0) { + break; + } else { + fixes.add(wind); + } + } + } finally { + windTrack.unlockAfterRead(); + } + + for (Wind wind : fixes) { + JSONObject jsonWind = new JSONObject(); + jsonWind.put("trueBearing-deg", UnitSerializationUtil.bearingDecimalFormatter.format(wind.getBearing().getDegrees())); + jsonWind.put("speed-kts", UnitSerializationUtil.speedDecimalFormatter.format(wind.getKnots())); + jsonWind.put("speed-m/s", UnitSerializationUtil.speedDecimalFormatter.format(wind.getMetersPerSecond())); + if (wind.getTimePoint() != null) { + jsonWind.put("timepoint-ms", wind.getTimePoint().asMillis()); + final Wind averagedWind = windTrack.getAveragedWind(wind.getPosition(), wind.getTimePoint()); + jsonWind.put("dampenedTrueBearing-deg", UnitSerializationUtil.bearingDecimalFormatter.format(averagedWind.getBearing().getDegrees())); + jsonWind.put("dampenedSpeed-kts", UnitSerializationUtil.speedDecimalFormatter.format(averagedWind.getKnots())); + jsonWind.put("dampenedSpeed-m/s", UnitSerializationUtil.speedDecimalFormatter.format(averagedWind.getMetersPerSecond())); + } + if (wind.getPosition() != null) { + jsonWind.put("lat-deg", UnitSerializationUtil.latLngDecimalFormatter.format(wind.getPosition().getLatDeg())); + jsonWind.put("lng-deg", UnitSerializationUtil.latLngDecimalFormatter.format(wind.getPosition().getLngDeg())); + } + jsonWindFixes.add(jsonWind); + } + result.put(windSource.name(), jsonWindFixes); + + return result; + } + + public void setFromTime(TimePoint fromTime) { + this.fromTime = fromTime; + } + + public void setToTime(TimePoint toTime) { + this.toTime = toTime; + } + + public void setWindSource(WindSource windSource) { + this.windSource = windSource; + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java new file mode 100644 index 00000000000..d3acb9c1a24 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java @@ -0,0 +1,47 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; + +import org.json.simple.JSONArray; + +import com.sap.sailing.domain.base.EventBase; +import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; +import com.sap.sailing.server.gateway.serialization.JsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.CourseAreaJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.EventJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.VenueJsonSerializer; + +@Path("/v1/events") +public class EventsResource extends AbstractSailingServerResource { + + @GET + @Produces("application/json;charset=UTF-8") + public Response getEvents() { + JsonSerializer eventSerializer = new EventJsonSerializer(new VenueJsonSerializer(new CourseAreaJsonSerializer())); + JSONArray result = new JSONArray(); + for (EventBase event : getService().getAllEvents()) { + result.add(eventSerializer.serialize(event)); + } + byte[] json = result.toJSONString().getBytes(); + return Response.ok(json).build(); + } + + @GET + @Produces("application/json;charset=UTF-8") + @Path("{eventId}") + public Response getEvent(@PathParam("eventId") String eventId) { + return Response.noContent().build(); + } + + @GET + @Produces("application/json;charset=UTF-8") + @Path("{eventId}/racestates") + public Response getRaceStates(@PathParam("eventId") String eventId) { + return Response.noContent().build(); + } +} + \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java new file mode 100644 index 00000000000..ce7cfdd6039 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java @@ -0,0 +1,138 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import java.util.Map; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +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.LeaderboardNameConstants; +import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.leaderboard.MetaLeaderboard; +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; +import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; + +@Path("/v1/leaderboardgroups") +public class LeaderboardGroupsResource extends AbstractSailingServerResource { + + @GET + @Produces("application/json;charset=UTF-8") + public Response getLeaderboardGroups() { + JSONArray jsonLeaderboardGroups = new JSONArray(); + Map leaderboardGroups = getService().getLeaderboardGroups(); + for (String leaderboardGroupName : leaderboardGroups.keySet()) { + jsonLeaderboardGroups.add(leaderboardGroupName); + } + + byte[] json = jsonLeaderboardGroups.toJSONString().getBytes(); + return Response.ok(json).build(); + } + + @GET + @Produces("application/json;charset=UTF-8") + @Path("{name}") + public Response getLeaderboardGroup(@PathParam("name") String leaderboardGroupName) { + Response response; + LeaderboardGroup leaderboardGroup = getService().getLeaderboardGroupByName(leaderboardGroupName); + if (leaderboardGroup == null) { + response = Response.status(Status.NOT_FOUND).entity("Could not find a leaderboard group with name '"+leaderboardGroupName+"'.").type(MediaType.TEXT_PLAIN).build(); + } else { + TimePoint timePoint = MillisecondsTimePoint.now(); + JSONObject jsonLeaderboardGroup = new JSONObject(); + jsonLeaderboardGroup.put("name", leaderboardGroup.getName()); + jsonLeaderboardGroup.put("description", leaderboardGroup.getDescription()); + jsonLeaderboardGroup.put("timepoint", timePoint.toString()); + JSONArray jsonLeaderboardEntries = new JSONArray(); + jsonLeaderboardGroup.put("leaderboards", jsonLeaderboardEntries); + for (Leaderboard leaderboard: leaderboardGroup.getLeaderboards()) { + boolean isMetaLeaderboard = leaderboard instanceof MetaLeaderboard ? true : false; + boolean isRegattaLeaderboard = leaderboard instanceof RegattaLeaderboard ? true : false; + + JSONObject jsonLeaderboard = new JSONObject(); + jsonLeaderboard.put("name", leaderboard.getName()); + jsonLeaderboard.put("displayName", leaderboard.getDisplayName()); + jsonLeaderboard.put("isMetaLeaderboard", isMetaLeaderboard); + jsonLeaderboard.put("isRegattaLeaderboard", isRegattaLeaderboard); + jsonLeaderboardEntries.add(jsonLeaderboard); + + SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection(); + if (scoreCorrection != null) { + jsonLeaderboard.put("scoringComment", scoreCorrection.getComment()); + TimePoint lastUpdateTimepoint = scoreCorrection.getTimePointOfLastCorrectionsValidity(); + jsonLeaderboard.put("lastScoringUpdate", lastUpdateTimepoint != null ? lastUpdateTimepoint.asDate().toString(): null); + } else { + jsonLeaderboard.put("scoringComment", null); + jsonLeaderboard.put("lastScoringUpdate", null); + } + + if (isRegattaLeaderboard) { + RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard; + Regatta regatta = regattaLeaderboard.getRegatta(); + jsonLeaderboard.put("scoringScheme", leaderboard.getScoringScheme().getType()); + jsonLeaderboard.put("regattaName", regatta.getName()); + } else { + jsonLeaderboard.put("scoringScheme", leaderboard.getScoringScheme().getType()); + jsonLeaderboard.put("regattaName", null); + JSONArray jsonSeriesEntries = new JSONArray(); + jsonLeaderboard.put("series", jsonSeriesEntries); + + // write a 'default' series to be conform with our common regatta structure + JSONObject jsonSeries = new JSONObject(); + jsonSeriesEntries.add(jsonSeries); + jsonSeries.put("name", LeaderboardNameConstants.DEFAULT_SERIES_NAME); + jsonSeries.put("isMedalSeries", null); + JSONArray jsonFleetsEntries = new JSONArray(); + jsonSeries.put("fleets", jsonFleetsEntries); + Fleet fleet = leaderboard.getFleet(LeaderboardNameConstants.DEFAULT_FLEET_NAME); + if (fleet != null) { + JSONObject jsonFleet = new JSONObject(); + jsonFleet.put("name", fleet.getName()); + jsonFleet.put("color", fleet.getColor() != null ? fleet.getColor().getAsHtml() : null); + jsonFleet.put("ordering", fleet.getOrdering()); + jsonFleetsEntries.add(jsonFleet); + JSONArray jsonRacesEntries = new JSONArray(); + jsonFleet.put("races", jsonRacesEntries); + for (RaceColumn raceColumn: leaderboard.getRaceColumns()) { + JSONObject jsonRaceColumn = new JSONObject(); + jsonRaceColumn.put("name", raceColumn.getName()); + jsonRaceColumn.put("isMedalRace" , raceColumn.isMedalRace()); + TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); + if (trackedRace != null) { + jsonRaceColumn.put("isTracked", true); + jsonRaceColumn.put("regattaName", trackedRace.getTrackedRegatta().getRegatta().getName()); + jsonRaceColumn.put("trackedRaceName", trackedRace.getRace().getName()); + jsonRaceColumn.put("hasGpsData", trackedRace.hasGPSData()); + jsonRaceColumn.put("hasWindData", trackedRace.hasWindData()); + } else { + jsonRaceColumn.put("isTracked", false); + jsonRaceColumn.put("trackedRaceName", null); + jsonRaceColumn.put("hasGpsData", false); + jsonRaceColumn.put("hasWindData", false); + } + jsonRacesEntries.add(jsonRaceColumn); + } + } + } + } + byte[] json = jsonLeaderboardGroup.toJSONString().getBytes(); + response = Response.ok(json).build(); + } + return response; + } +} + \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java new file mode 100644 index 00000000000..0cac34acb55 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java @@ -0,0 +1,299 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.Nationality; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.common.LeaderboardNameConstants; +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.common.dto.CompetitorDTO; +import com.sap.sailing.domain.common.dto.FleetDTO; +import com.sap.sailing.domain.common.dto.LeaderboardDTO; +import com.sap.sailing.domain.common.dto.LeaderboardEntryDTO; +import com.sap.sailing.domain.common.dto.LeaderboardRowDTO; +import com.sap.sailing.domain.common.dto.RaceColumnDTO; +import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; +import com.sap.sailing.domain.common.impl.Util.Triple; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; +import com.sap.sailing.domain.tracking.MarkPassing; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; + +@Path("/v1/leaderboards") +public class LeaderboardsResource extends AbstractSailingServerResource { + + public enum ResultStates { Live, Preliminary, Final }; + + @GET + @Produces("application/json;charset=UTF-8") + public Response getLeaderboards() { + JSONArray jsonLeaderboards = new JSONArray(); + Map leaderboards = getService().getLeaderboards(); + for (String leaderboardName : leaderboards.keySet()) { + if(!leaderboardName.equals(LeaderboardNameConstants.DEFAULT_LEADERBOARD_NAME)) + jsonLeaderboards.add(leaderboardName); + } + + byte[] json = jsonLeaderboards.toJSONString().getBytes(); + return Response.ok(json).build(); + } + + @GET + @Produces("application/json;charset=UTF-8") + @Path("{name}") + public Response getLeaderboard(@PathParam("name") String leaderboardName, + @DefaultValue("Live") @QueryParam("resultState") ResultStates resultState, + @DefaultValue("true") @QueryParam("useCache") boolean useCache, + @DefaultValue("1000") @QueryParam("maxCompetitorsCount") int maxCompetitorsCount) { + Response response; + + TimePoint requestTimePoint = MillisecondsTimePoint.now(); + Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); + if (leaderboard == null) { + response = Response.status(Status.NOT_FOUND).entity("Could not find a leaderboard with name '" + leaderboardName + "'.").type(MediaType.TEXT_PLAIN).build(); + } else { + try { + TimePoint resultTimePoint = calculateTimePointForResultState(leaderboard, resultState); + JSONObject jsonLeaderboard; + if (resultTimePoint != null) { + Triple resultStateAndTimePoint = new Triple<>(resultTimePoint, resultState, maxCompetitorsCount); + jsonLeaderboard = getLeaderboardJson(leaderboard, resultStateAndTimePoint); + } else { + jsonLeaderboard = createEmptyLeaderboardJson(leaderboard, resultState, requestTimePoint, maxCompetitorsCount); + } + + StringWriter sw = new StringWriter(); + jsonLeaderboard.writeJSONString(sw); + + byte[] json = sw.getBuffer().toString().getBytes(); + response = Response.ok(json).build(); + } catch (NoWindException | InterruptedException | ExecutionException | IOException e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).type(MediaType.TEXT_PLAIN).build(); + } + } + + return response; + } + + private JSONObject getLeaderboardJson(Leaderboard leaderboard, Triple timePointAndResultStateAndMaxCompetitorsCount) + throws NoWindException, InterruptedException, ExecutionException { + LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO(timePointAndResultStateAndMaxCompetitorsCount.getA(), + Collections. emptyList(), getService(), getService().getBaseDomainFactory()); + + TimePoint resultTimePoint = timePointAndResultStateAndMaxCompetitorsCount.getA(); + ResultStates resultState = timePointAndResultStateAndMaxCompetitorsCount.getB(); + Integer maxCompetitorsCount = timePointAndResultStateAndMaxCompetitorsCount.getC(); + JSONObject jsonLeaderboard = new JSONObject(); + + writeCommonLeaderboardData(jsonLeaderboard, leaderboardDTO, resultState, resultTimePoint, maxCompetitorsCount); + + JSONArray jsonCompetitorEntries = new JSONArray(); + jsonLeaderboard.put("competitors", jsonCompetitorEntries); + int counter = 1; + for (CompetitorDTO competitor : leaderboardDTO.competitors) { + LeaderboardRowDTO leaderboardRowDTO = leaderboardDTO.rows.get(competitor); + + if(maxCompetitorsCount != null && counter > maxCompetitorsCount) { + break; + } + JSONObject jsonCompetitor = new JSONObject(); + jsonCompetitor.put("name", competitor.getName()); + final String displayName = leaderboardDTO.getDisplayName(competitor); + jsonCompetitor.put("displayName", displayName==null?competitor.getName():displayName); + jsonCompetitor.put("id", competitor.getIdAsString()); + jsonCompetitor.put("sailID", competitor.getSailID()); + jsonCompetitor.put("nationality", competitor.getThreeLetterIocCountryCode()); + jsonCompetitor.put("countryCode", competitor.getTwoLetterIsoCountryCode()); + + jsonCompetitor.put("rank", counter); + jsonCompetitor.put("carriedPoints", leaderboardRowDTO.carriedPoints); + jsonCompetitor.put("totalPoints", leaderboardRowDTO.totalPoints); + jsonCompetitorEntries.add(jsonCompetitor); + JSONObject jsonRaceColumns = new JSONObject(); + jsonCompetitor.put("raceScores", jsonRaceColumns); + for (RaceColumnDTO raceColumn : leaderboardDTO.getRaceList()) { + List rankedCompetitorsForColumn = leaderboardDTO.getCompetitorOrderingPerRaceColumnName().get(raceColumn.getName()); + JSONObject jsonEntry = new JSONObject(); + jsonRaceColumns.put(raceColumn.getName(), jsonEntry); + LeaderboardEntryDTO leaderboardEntry = leaderboardRowDTO.fieldsByRaceColumnName.get(raceColumn.getName()); + + final FleetDTO fleetOfCompetitor = leaderboardEntry.fleet; + jsonEntry.put("fleet", fleetOfCompetitor==null?"":fleetOfCompetitor.getName()); + jsonEntry.put("netPoints", leaderboardEntry.netPointsCorrected); + jsonEntry.put("uncorrectedNetPoints", leaderboardEntry.netPoints); + jsonEntry.put("totalPoints", leaderboardEntry.totalPoints); + MaxPointsReason maxPointsReason = leaderboardEntry.reasonForMaxPoints; + jsonEntry.put("maxPointsReason", maxPointsReason != null ? maxPointsReason.toString(): null); + jsonEntry.put("rank", rankedCompetitorsForColumn.indexOf(competitor)+1); +// final TrackedRace trackedRace = raceColumn.getTrackedRace(competitor); +// if (trackedRace != null) { +// jsonEntry.put("raceRank", trackedRace.getRank(competitor, resultTimePoint)); +// } + jsonEntry.put("isDiscarded", leaderboardEntry.discarded); + jsonEntry.put("isCorrected", leaderboardEntry.hasScoreCorrection()); + } + counter++; + } + return jsonLeaderboard; + } + + private JSONObject createEmptyLeaderboardJson(Leaderboard leaderboard, + ResultStates resultState, TimePoint requestTimePoint, Integer maxCompetitorsCount) throws NoWindException { + JSONObject jsonLeaderboard = new JSONObject(); + + writeCommonLeaderboardData(jsonLeaderboard, leaderboard, resultState, null, maxCompetitorsCount); + + JSONArray jsonCompetitorEntries = new JSONArray(); + jsonLeaderboard.put("competitors", jsonCompetitorEntries); + for (Competitor competitor : leaderboard.getCompetitors()) { + JSONObject jsonCompetitor = new JSONObject(); + jsonCompetitor.put("name", competitor.getName()); + final String displayName = leaderboard.getDisplayName(competitor); + jsonCompetitor.put("displayName", displayName==null?competitor.getName():displayName); + jsonCompetitor.put("id", competitor.getId().toString()); + jsonCompetitor.put("sailID", competitor.getBoat().getSailID()); + Nationality nationality = competitor.getTeam().getNationality(); + jsonCompetitor.put("nationality", nationality != null ? nationality.getThreeLetterIOCAcronym(): null); + jsonCompetitor.put("countryCode", nationality != null ? (nationality.getCountryCode() != null ? nationality.getCountryCode().getTwoLetterISOCode(): null) : null); + + jsonCompetitor.put("rank", 0); + jsonCompetitor.put("carriedPoints", null); + jsonCompetitor.put("totalPoints", null); + jsonCompetitorEntries.add(jsonCompetitor); + JSONObject jsonRaceColumns = new JSONObject(); + jsonCompetitor.put("raceScores", jsonRaceColumns); + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { + JSONObject jsonEntry = new JSONObject(); + jsonRaceColumns.put(raceColumn.getName(), jsonEntry); + final Fleet fleetOfCompetitor = raceColumn.getFleetOfCompetitor(competitor); + jsonEntry.put("fleet", fleetOfCompetitor==null?"":fleetOfCompetitor.getName()); + jsonEntry.put("netPoints", null); + jsonEntry.put("totalPoints", null); + jsonEntry.put("maxPointsReason", ""); + jsonEntry.put("rank", 0); + jsonEntry.put("isDiscarded", false); + jsonEntry.put("isCorrected", false); + } + } + return jsonLeaderboard; + } + + private void writeCommonLeaderboardData(JSONObject jsonLeaderboard, LeaderboardDTO leaderboard, ResultStates resultState, + TimePoint resultTimePoint, Integer maxCompetitorsCount) { + jsonLeaderboard.put("name", leaderboard.name); + + jsonLeaderboard.put("resultTimepoint", resultTimePoint != null ? resultTimePoint.asMillis() : null); + jsonLeaderboard.put("resultState", resultState.name()); + jsonLeaderboard.put("maxCompetitorsCount", maxCompetitorsCount); + + jsonLeaderboard.put("scoringComment", leaderboard.getComment()); + Date lastUpdateTimepoint = leaderboard.getTimePointOfLastCorrectionsValidity(); + jsonLeaderboard.put("lastScoringUpdate", lastUpdateTimepoint != null ? lastUpdateTimepoint.getTime(): null); + + JSONArray jsonColumnNames = new JSONArray(); + jsonLeaderboard.put("columnNames", jsonColumnNames); + for (RaceColumnDTO raceColumn : leaderboard.getRaceList()) { + jsonColumnNames.add(raceColumn.getName()); + } + } + + private void writeCommonLeaderboardData(JSONObject jsonLeaderboard, Leaderboard leaderboard, ResultStates resultState, + TimePoint resultTimePoint, Integer maxCompetitorsCount) { + jsonLeaderboard.put("name", leaderboard.getName()); + + jsonLeaderboard.put("resultTimepoint", resultTimePoint != null ? resultTimePoint.asMillis() : null); + jsonLeaderboard.put("resultState", resultState.name()); + jsonLeaderboard.put("maxCompetitorsCount", maxCompetitorsCount); + + SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection(); + if (scoreCorrection != null) { + jsonLeaderboard.put("scoringComment", scoreCorrection.getComment()); + TimePoint lastUpdateTimepoint = scoreCorrection.getTimePointOfLastCorrectionsValidity(); + jsonLeaderboard.put("lastScoringUpdate", lastUpdateTimepoint != null ? lastUpdateTimepoint.asMillis(): null); + } else { + jsonLeaderboard.put("scoringComment", null); + jsonLeaderboard.put("lastScoringUpdate", null); + } + + JSONArray jsonColumnNames = new JSONArray(); + jsonLeaderboard.put("columnNames", jsonColumnNames); + for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { + jsonColumnNames.add(raceColumn.getName()); + } + } + + private TimePoint calculateTimePointForResultState(Leaderboard leaderboard, ResultStates resultState) { + TimePoint result = null; + switch (resultState) { + case Live: + result = leaderboard.getTimePointOfLatestModification(); + if (result == null) { + result = MillisecondsTimePoint.now(); + } + break; + case Preliminary: + case Final: + if (leaderboard.getScoreCorrection() != null && leaderboard.getScoreCorrection().getTimePointOfLastCorrectionsValidity() != null) { + result = leaderboard.getScoreCorrection().getTimePointOfLastCorrectionsValidity(); + // As we don't have implemented bug 1246 (Define a clear result state for races and leaderboards) so far + // we need to make sure that the timpoint for the final state is not determined in the middle of a running race, + // because this would deliver not only final results but also some "mixed-in" live results. + // Therefore, if there is a race that hasn't finished yet and whose first start mark passing is before + // the current result, move result to before the start mark passing. + for (TrackedRace trackedRace : leaderboard.getTrackedRaces()) { + TimePoint endOfRace = trackedRace.getEndOfRace(); + if (endOfRace == null) { + Waypoint firstWaypoint = trackedRace.getRace().getCourse().getFirstWaypoint(); + if (firstWaypoint != null) { + Iterable markPassingsForFirstWaypoint = trackedRace.getMarkPassingsInOrder(firstWaypoint); + if (markPassingsForFirstWaypoint != null) { + trackedRace.lockForRead(markPassingsForFirstWaypoint); + try { + Iterator i = markPassingsForFirstWaypoint.iterator(); + if (i.hasNext()) { + TimePoint earliestMarkPassingTimePoint = i.next().getTimePoint(); + if (result == null || earliestMarkPassingTimePoint.before(result)) { + result = earliestMarkPassingTimePoint.minus(1); + } + } + } finally { + trackedRace.unlockAfterRead(markPassingsForFirstWaypoint); + } + } + } + } + } + } + break; + } + return result; + } + +} + \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java new file mode 100644 index 00000000000..e8125d2f38d --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -0,0 +1,571 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.Course; +import com.sap.sailing.domain.base.Mark; +import com.sap.sailing.domain.base.RaceDefinition; +import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.common.Distance; +import com.sap.sailing.domain.common.NoWindException; +import com.sap.sailing.domain.common.RegattaName; +import com.sap.sailing.domain.common.Tack; +import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; +import com.sap.sailing.domain.common.impl.Util; +import com.sap.sailing.domain.common.impl.Util.Pair; +import com.sap.sailing.domain.tracking.GPSFix; +import com.sap.sailing.domain.tracking.GPSFixMoving; +import com.sap.sailing.domain.tracking.GPSFixTrack; +import com.sap.sailing.domain.tracking.TrackedLeg; +import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; +import com.sap.sailing.server.gateway.jaxrs.UnitSerializationUtil; +import com.sap.sailing.server.gateway.serialization.JsonSerializer; +import com.sap.sailing.server.gateway.serialization.coursedata.impl.ControlPointJsonSerializer; +import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseBaseJsonSerializer; +import com.sap.sailing.server.gateway.serialization.coursedata.impl.GateJsonSerializer; +import com.sap.sailing.server.gateway.serialization.coursedata.impl.MarkJsonSerializer; +import com.sap.sailing.server.gateway.serialization.coursedata.impl.WaypointJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.ColorJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.FleetJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.NationalityJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.PersonJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.RegattaJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.SeriesJsonSerializer; +import com.sap.sailing.server.gateway.serialization.impl.TeamJsonSerializer; +import com.sap.sailing.util.InvalidDateException; + +@Path("/v1/regattas") +public class RegattasResource extends AbstractSailingServerResource { + + private Response getBadRegattaErrorResponse(String regattaName) { + return Response.status(Status.NOT_FOUND).entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN).build(); + } + + private Response getBadRaceErrorResponse(String regattaName, String raceName) { + return Response.status(Status.NOT_FOUND).entity("Could not find a race with name '" + raceName + "' in regatta '" + regattaName + "'.").type(MediaType.TEXT_PLAIN).build(); + } + + @GET + @Produces("application/json;charset=UTF-8") + public Response getRegattas() { + RegattaJsonSerializer regattaJsonSerializer = new RegattaJsonSerializer(); + + JSONArray regattasJson = new JSONArray(); + for (Regatta regatta : getService().getAllRegattas()) { + regattasJson.add(regattaJsonSerializer.serialize(regatta)); + } + byte[] json = regattasJson.toJSONString().getBytes(); + return Response.ok(json).build(); + } + + @GET + @Produces("application/json;charset=UTF-8") + @Path("{regattaname}") + public Response getRegatta(@PathParam("regattaname") String regattaName) { + Response response; + Regatta regatta = getService().getRegatta(new RegattaName(regattaName)); + if (regatta == null) { + response = getBadRegattaErrorResponse(regattaName); + } else { + SeriesJsonSerializer seriesJsonSerializer = new SeriesJsonSerializer(new FleetJsonSerializer(new ColorJsonSerializer())); + JsonSerializer regattaSerializer = new RegattaJsonSerializer(seriesJsonSerializer, null); + JSONObject serializedRegatta = regattaSerializer.serialize(regatta); + + byte[] json = serializedRegatta.toJSONString().getBytes(); + response = Response.ok(json).build(); + } + return response; + } + + /** + * Gets all entries for a regatta. + * @param regattaName the name of the regatta + * @return + */ + @GET + @Produces("application/json;charset=UTF-8") + @Path("{regattaname}/entries") + public Response getEntries(@PathParam("regattaname") String regattaName) { + Response response; + Regatta regatta = getService().getRegatta(new RegattaName(regattaName)); + if (regatta == null) { + response = getBadRegattaErrorResponse(regattaName); + } else { + NationalityJsonSerializer nationalityJsonSerializer = new NationalityJsonSerializer(); + CompetitorJsonSerializer competitorJsonSerializer = new CompetitorJsonSerializer( + new TeamJsonSerializer(new PersonJsonSerializer(nationalityJsonSerializer))); + JsonSerializer regattaSerializer = new RegattaJsonSerializer(null, competitorJsonSerializer); + JSONObject serializedRegatta = regattaSerializer.serialize(regatta); + + byte[] json = serializedRegatta.toJSONString().getBytes(); + response = Response.ok(json).build(); + } + return response; + } + + /** + * Gets all GPS positions of the competitors for a given race. + * @param regattaName the name of the regatta + * @return + */ + @GET + @Produces("application/json;charset=UTF-8") + @Path("{regattaname}/races/{racename}/competitors/positions") + public Response getCompetitorPositions(@PathParam("regattaname") String regattaName, @PathParam("racename") String raceName, + @QueryParam("fromtime") String fromtime, @QueryParam("fromtimeasmillis") Long fromtimeasmillis, + @QueryParam("totime") String totime, @QueryParam("totimeasmillis") Long totimeasmillis) { + Response response; + Regatta regatta = findRegattaByName(regattaName); + if (regatta == null) { + response = getBadRegattaErrorResponse(regattaName); + } else { + RaceDefinition race = findRaceByName(regatta, raceName); + if (race == null) { + response = getBadRaceErrorResponse(regattaName, raceName); + } else { + TrackedRace trackedRace = findTrackedRace(regattaName, raceName); + + TimePoint from; + TimePoint to; + try { + from = parseTimePoint(fromtime, fromtimeasmillis, + trackedRace.getStartOfRace() == null ? new MillisecondsTimePoint(0) : + /* 24h before race start */ new MillisecondsTimePoint(trackedRace.getStartOfRace().asMillis()-24*3600*1000)); + } catch (InvalidDateException e1) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not parse the 'from' time.").type(MediaType.TEXT_PLAIN).build(); + } + try { + to = parseTimePoint(totime, totimeasmillis, MillisecondsTimePoint.now()); + } catch (InvalidDateException e1) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not parse the 'to' time.").type(MediaType.TEXT_PLAIN).build(); + } + + JSONObject jsonRace = new JSONObject(); + jsonRace.put("name", trackedRace.getRace().getName()); + jsonRace.put("regatta", regatta.getName()); + JSONArray jsonCompetitors = new JSONArray(); + for (Competitor competitor : trackedRace.getRace().getCompetitors()) { + JSONObject jsonCompetitor = new JSONObject(); + jsonCompetitor.put("id", competitor.getId() != null ? competitor.getId().toString() : null); + jsonCompetitor.put("name", competitor.getName()); + jsonCompetitor.put("sailNumber", competitor.getBoat().getSailID()); + + GPSFixTrack track = trackedRace.getTrack(competitor); + JSONArray jsonFixes = new JSONArray(); + track.lockForRead(); + try { + Iterator fixIter; + if (from == null) { + fixIter = track.getFixes().iterator(); + } else { + fixIter = track.getFixesIterator(from, /* inclusive */true); + } + while (fixIter.hasNext()) { + GPSFixMoving fix = fixIter.next(); + if (to != null && fix.getTimePoint() != null && to.compareTo(fix.getTimePoint()) < 0) { + break; + } + JSONObject jsonFix = new JSONObject(); + jsonFix.put("timepoint-ms", fix.getTimePoint().asMillis()); + jsonFix.put("lat-deg", UnitSerializationUtil.latLngDecimalFormatter.format(fix.getPosition().getLatDeg())); + jsonFix.put("lng-deg", UnitSerializationUtil.latLngDecimalFormatter.format(fix.getPosition().getLngDeg())); + jsonFix.put("truebearing-deg", fix.getSpeed().getBearing().getDegrees()); + jsonFix.put("speed-kts", UnitSerializationUtil.knotsDecimalFormatter.format(fix.getSpeed().getKnots())); + String tackName; + try { + final Tack tack = trackedRace.getTack(competitor, fix.getTimePoint()); + if (tack != null) { + tackName = tack.name(); + jsonFix.put("tack", tackName); + } + } catch (NoWindException e) { + // don't output tack + } + jsonFixes.add(jsonFix); + } + } finally { + track.unlockAfterRead(); + } + jsonCompetitor.put("track", jsonFixes); + jsonCompetitors.add(jsonCompetitor); + } + jsonRace.put("competitors", jsonCompetitors); + + byte[] json = jsonRace.toJSONString().getBytes(); + response = Response.ok(json).build(); + } + } + return response; + } + + /** + * Gets all GPS positions of the course marks for a given race. + * @param regattaName the name of the regatta + * @return + */ + @GET + @Produces("application/json;charset=UTF-8") + @Path("{regattaname}/races/{racename}/marks/positions") + public Response getMarkPositions(@PathParam("regattaname") String regattaName, @PathParam("racename") String raceName, + @QueryParam("fromtime") String fromtime, @QueryParam("fromtimeasmillis") Long fromtimeasmillis, + @QueryParam("totime") String totime, @QueryParam("totimeasmillis") Long totimeasmillis) { + Response response; + Regatta regatta = findRegattaByName(regattaName); + if (regatta == null) { + response = getBadRegattaErrorResponse(regattaName); + } else { + RaceDefinition race = findRaceByName(regatta, raceName); + if (race == null) { + response = getBadRaceErrorResponse(regattaName, raceName); + } else { + TrackedRace trackedRace = findTrackedRace(regattaName, raceName); + + TimePoint from; + TimePoint to; + try { + from = parseTimePoint(fromtime, fromtimeasmillis, + trackedRace.getStartOfRace() == null ? new MillisecondsTimePoint(0) : + /* 24h before race start */ new MillisecondsTimePoint(trackedRace.getStartOfRace().asMillis()-24*3600*1000)); + } catch (InvalidDateException e1) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not parse the 'from' time.").type(MediaType.TEXT_PLAIN).build(); + } + try { + to = parseTimePoint(totime, totimeasmillis, MillisecondsTimePoint.now()); + } catch (InvalidDateException e1) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not parse the 'to' time.").type(MediaType.TEXT_PLAIN).build(); + } + + JSONObject jsonRace = new JSONObject(); + jsonRace.put("name", trackedRace.getRace().getName()); + jsonRace.put("regatta", regatta.getName()); + JSONArray jsonMarks = new JSONArray(); + Set marks = new HashSet(); + Course course = trackedRace.getRace().getCourse(); + for (Waypoint waypoint : course.getWaypoints()) { + for (Mark mark : waypoint.getMarks()) { + marks.add(mark); + } + } + + for (Mark mark : marks) { + JSONObject jsonMark = new JSONObject(); + jsonMark.put("name", mark.getName()); + jsonMark.put("id", mark.getId() != null ? mark.getId().toString() : null); + GPSFixTrack track = trackedRace.getOrCreateTrack(mark); + JSONArray jsonFixes = new JSONArray(); + track.lockForRead(); + try { + Iterator fixIter; + if (from == null) { + fixIter = track.getFixes().iterator(); + } else { + fixIter = track.getFixesIterator(from, /* inclusive */true); + } + while (fixIter.hasNext()) { + GPSFix fix = fixIter.next(); + if (to != null && fix.getTimePoint() != null && to.compareTo(fix.getTimePoint()) < 0) { + break; + } + JSONObject jsonFix = new JSONObject(); + jsonFix.put("timepoint-ms", fix.getTimePoint().asMillis()); + jsonFix.put("lat-deg", UnitSerializationUtil.latLngDecimalFormatter.format(fix.getPosition().getLatDeg())); + jsonFix.put("lng-deg", UnitSerializationUtil.latLngDecimalFormatter.format(fix.getPosition().getLngDeg())); + jsonFixes.add(jsonFix); + } + } finally { + track.unlockAfterRead(); + } + jsonMark.put("track", jsonFixes); + jsonMarks.add(jsonMark); + } + jsonRace.put("marks", jsonMarks); + + byte[] json = jsonRace.toJSONString().getBytes(); + response = Response.ok(json).build(); + } + } + return response; + } + + /** + * Gets the course of the race. + * @param regattaName the name of the regatta + * @return + */ + @GET + @Produces("application/json;charset=UTF-8") + @Path("{regattaname}/races/{racename}/course") + public Response getCourse(@PathParam("regattaname") String regattaName, @PathParam("racename") String raceName) { + Response response; + Regatta regatta = findRegattaByName(regattaName); + if (regatta == null) { + response = getBadRegattaErrorResponse(regattaName); + } else { + RaceDefinition race = findRaceByName(regatta, raceName); + if (race == null) { + response = getBadRaceErrorResponse(regattaName, raceName); + } else { + Course course = race.getCourse(); + CourseBaseJsonSerializer serializer = new CourseBaseJsonSerializer( + new WaypointJsonSerializer( + new ControlPointJsonSerializer( + new MarkJsonSerializer(), + new GateJsonSerializer(new MarkJsonSerializer())))); + + JSONObject jsonCourse = serializer.serialize(course); + byte[] json = jsonCourse.toJSONString().getBytes(); + response = Response.ok(json).build(); + } + } + return response; + } + + /** + * Gets the relevant times of the race. + * @param regattaName the name of the regatta + * @return + */ + @GET + @Produces("application/json;charset=UTF-8") + @Path("{regattaname}/races/{racename}/times") + public Response getTimes(@PathParam("regattaname") String regattaName, @PathParam("racename") String raceName) { + Response response = null; + Regatta regatta = findRegattaByName(regattaName); + if (regatta == null) { + response = getBadRegattaErrorResponse(regattaName); + } else { + RaceDefinition race = findRaceByName(regatta, raceName); + if (race == null) { + response = getBadRaceErrorResponse(regattaName, raceName); + } else { + TrackedRace trackedRace = findTrackedRace(regattaName, raceName); + + JSONObject jsonRaceTimes = new JSONObject(); + jsonRaceTimes.put("name", trackedRace.getRace().getName()); + jsonRaceTimes.put("regatta", regatta.getName()); + + jsonRaceTimes.put("startOfRace-ms", trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace().asMillis()); + jsonRaceTimes.put("startOfTracking-ms", trackedRace.getStartOfTracking() == null ? null : trackedRace.getStartOfTracking().asMillis()); + jsonRaceTimes.put("newestTrackingEvent-ms", trackedRace.getTimePointOfNewestEvent() == null ? null : trackedRace.getTimePointOfNewestEvent().asMillis()); + jsonRaceTimes.put("endOfTracking-ms", trackedRace.getEndOfTracking() == null ? null : trackedRace.getEndOfTracking().asMillis()); + jsonRaceTimes.put("endOfRace-ms", trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace().asMillis()); + jsonRaceTimes.put("delayToLive-ms", trackedRace.getDelayToLiveInMillis()); + + JSONArray jsonMarkPassingTimes = new JSONArray(); + List firstPassingTimepoints = new ArrayList<>(); + Iterable>> markPassingsTimes = trackedRace.getMarkPassingsTimes(); + synchronized (markPassingsTimes) { + int numberOfWaypoints = Util.size(markPassingsTimes); + int wayPointNumber = 1; + for (Pair> markPassingTimes : markPassingsTimes) { + JSONObject jsonMarkPassing = new JSONObject(); + String name = "M" + (wayPointNumber - 1); + if (wayPointNumber == numberOfWaypoints) { + name = "F"; + } + jsonMarkPassing.put("name", name); + Pair timesPair = markPassingTimes.getB(); + TimePoint firstPassingTime = timesPair.getA(); + TimePoint lastPassingTime = timesPair.getB(); + jsonMarkPassing.put("firstPassing-ms", firstPassingTime == null ? null : firstPassingTime.asMillis()); + jsonMarkPassing.put("lastPassing-ms", lastPassingTime == null ? null : lastPassingTime.asMillis()); + + firstPassingTimepoints.add(firstPassingTime); + + jsonMarkPassingTimes.add(jsonMarkPassing); + wayPointNumber++; + } + } + jsonRaceTimes.put("markPassings", jsonMarkPassingTimes); + + JSONArray jsonLegInfos = new JSONArray(); + trackedRace.getRace().getCourse().lockForRead(); + try { + Iterable trackedLegs = trackedRace.getTrackedLegs(); + int legNumber = 1; + for (TrackedLeg trackedLeg : trackedLegs) { + JSONObject jsonLegInfo = new JSONObject(); + jsonLegInfo.put("name", "L" + legNumber); + + try { + TimePoint firstPassingTime = firstPassingTimepoints.get(legNumber - 1); + if (firstPassingTime != null) { + jsonLegInfo.put("type", trackedLeg.getLegType(firstPassingTime)); + jsonLegInfo.put("bearing-deg", UnitSerializationUtil.bearingDecimalFormatter.format(trackedLeg.getLegBearing(firstPassingTime).getDegrees())); + } + } catch (NoWindException e) { + // do nothing + } + jsonLegInfos.add(jsonLegInfo); + + legNumber++; + } + } finally { + trackedRace.getRace().getCourse().unlockAfterRead(); + } + jsonRaceTimes.put("legs", jsonLegInfos); + + Date now = new Date(); + jsonRaceTimes.put("currentServerTime-ms", now.getTime()); + + byte[] json = jsonRaceTimes.toJSONString().getBytes(); + response = Response.ok(json).build(); + } + } + return response; + } + + @GET + @Produces("application/json;charset=UTF-8") + @Path("{regattaname}/races/{racename}/wind") + public Response getWind(@PathParam("regattaname") String regattaName, @PathParam("racename") String raceName, + @DefaultValue("COMBINED") @QueryParam("windsource") String windSource, + @QueryParam("fromtime") String fromtime, @QueryParam("fromtimeasmillis") Long fromtimeasmillis, + @QueryParam("totime") String totime, @QueryParam("totimeasmillis") Long totimeasmillis) { + Response response; + Regatta regatta = findRegattaByName(regattaName); + if (regatta == null) { + response = Response.status(Status.NOT_FOUND).entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN).build(); + } else { + RaceDefinition race = findRaceByName(regatta, raceName); + if (race == null) { + response = Response.status(Status.NOT_FOUND).entity("Could not find a race with name '" + raceName + "'.").type(MediaType.TEXT_PLAIN).build(); + } else { + TrackedRace trackedRace = findTrackedRace(regattaName, raceName); + + TimePoint from; + TimePoint to; + try { + from = parseTimePoint(fromtime, fromtimeasmillis, + trackedRace.getStartOfRace() == null ? new MillisecondsTimePoint(0) : + /* 24h before race start */ new MillisecondsTimePoint(trackedRace.getStartOfRace().asMillis()-24*3600*1000)); + } catch (InvalidDateException e1) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not parse the 'from' time.").type(MediaType.TEXT_PLAIN).build(); + } + try { + to = parseTimePoint(totime, totimeasmillis, MillisecondsTimePoint.now()); + } catch (InvalidDateException e1) { + return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not parse the 'to' time.").type(MediaType.TEXT_PLAIN).build(); + } + + TrackedRaceJsonSerializer serializer = new TrackedRaceJsonSerializer(new DefaultWindTrackJsonSerializer()); + serializer.setWindSource(windSource); + serializer.setFromTime(from); + serializer.setToTime(to); + + JSONObject jsonWindTracks = serializer.serialize(trackedRace); + byte[] json = jsonWindTracks.toJSONString().getBytes(); + return Response.ok(json).build(); + } + } + return response; + } + + @GET + @Produces("application/json;charset=UTF-8") + @Path("{regattaname}/races/{racename}/competitors/legs") + public Response getCompetitorRanks(@PathParam("regattaname") String regattaName, @PathParam("racename") String raceName) { + Response response; + Regatta regatta = findRegattaByName(regattaName); + if (regatta == null) { + response = Response.status(Status.NOT_FOUND).entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN).build(); + } else { + RaceDefinition race = findRaceByName(regatta, raceName); + if (race == null) { + response = Response.status(Status.NOT_FOUND).entity("Could not find a race with name '" + raceName + "'.").type(MediaType.TEXT_PLAIN).build(); + } else { + TrackedRace trackedRace = findTrackedRace(regattaName, raceName); + TimePoint timePoint = trackedRace.getTimePointOfNewestEvent() == null ? MillisecondsTimePoint.now() + : trackedRace.getTimePointOfNewestEvent(); + + JSONObject jsonRaceResults = new JSONObject(); + jsonRaceResults.put("name", trackedRace.getRace().getName()); + jsonRaceResults.put("regatta", regatta.getName()); + + JSONArray jsonLegs = new JSONArray(); + for (TrackedLeg leg : trackedRace.getTrackedLegs()) { + JSONObject jsonLeg = new JSONObject(); + jsonLeg.put("from", leg.getLeg().getFrom().getName()); + jsonLeg.put("fromWaypointId", leg.getLeg().getFrom().getId()); + jsonLeg.put("to", leg.getLeg().getTo().getName()); + jsonLeg.put("toWaypointId", leg.getLeg().getTo().getId()); + try { + jsonLeg.put("upOrDownwindLeg", leg.isUpOrDownwindLeg(timePoint)); + } catch (NoWindException e) { + // no wind, then it's simply no upwind or downwind leg + jsonLeg.put("upOrDownwindLeg", "false"); + } + JSONArray jsonCompetitors = new JSONArray(); + Map ranks = leg.getRanks(timePoint); + for (Competitor competitor : trackedRace.getRace().getCompetitors()) { + JSONObject jsonCompetitorInLeg = new JSONObject(); + TrackedLegOfCompetitor trackedLegOfCompetitor = leg.getTrackedLeg(competitor); + if (trackedLegOfCompetitor != null) { + jsonCompetitorInLeg.put("id", competitor.getId() != null ? competitor.getId().toString() : null); + jsonCompetitorInLeg.put("name", competitor.getName()); + jsonCompetitorInLeg.put("sailNumber", competitor.getBoat().getSailID()); + + Distance distanceTraveled = trackedLegOfCompetitor.getDistanceTraveled(timePoint); + if (distanceTraveled != null) { + jsonCompetitorInLeg.put("distanceTraveled-m", UnitSerializationUtil.distanceDecimalFormatter.format(distanceTraveled.getMeters())); + } + try { + Integer rank = ranks.get(competitor); + jsonCompetitorInLeg.put("rank", rank); + } catch (RuntimeException re) { + if (re.getCause() != null && re.getCause() instanceof NoWindException) { + // well, we don't know the wind direction, so we can't compute a ranking + } else { + throw re; + } + } + try { + jsonCompetitorInLeg.put("gapToLeader-s", + trackedLegOfCompetitor.getGapToLeaderInSeconds(timePoint)); + } catch (NoWindException e1) { + // well, we don't know the wind direction... then no gap to leader will be shown... + } + jsonCompetitorInLeg.put("started", trackedLegOfCompetitor.hasStartedLeg(timePoint)); + jsonCompetitorInLeg.put("finished", trackedLegOfCompetitor.hasFinishedLeg(timePoint)); + jsonCompetitors.add(jsonCompetitorInLeg); + } + } + jsonLeg.put("competitors", jsonCompetitors); + jsonLegs.add(jsonLeg); + } + jsonRaceResults.put("legs", jsonLegs); + + byte[] json = jsonRaceResults.toJSONString().getBytes(); + return Response.ok(json).build(); + } + } + return response; + } + +} + \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java new file mode 100644 index 00000000000..a9e069c0797 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RestApiApplication.java @@ -0,0 +1,20 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.core.Application; + + +public class RestApiApplication extends Application { + public Set> getClasses() { + HashSet> classes = new HashSet<>(); + classes.add(LeaderboardGroupsResource.class); + classes.add(EventsResource.class); + classes.add(RegattasResource.class); + classes.add(LeaderboardsResource.class); + // classes.add(WindResource.class); + + return classes; + } +} diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedRaceJsonSerializer.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedRaceJsonSerializer.java new file mode 100644 index 00000000000..eeb32c420f1 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedRaceJsonSerializer.java @@ -0,0 +1,85 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import java.util.ArrayList; +import java.util.List; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.WindSource; +import com.sap.sailing.domain.common.WindSourceType; +import com.sap.sailing.domain.common.impl.WindSourceImpl; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.domain.tracking.WindTrack; +import com.sap.sailing.server.gateway.serialization.JsonSerializer; + +public class TrackedRaceJsonSerializer implements JsonSerializer { + public static final String FIELD_ID = "id"; + public static final String FIELD_NAME = "name"; + public static final String FIELD_REGATTA = "regatta"; + public static final String FIELD_WINDSOURCES = "windSources"; + + public static final String ALL_WINDSOURCES = "ALL"; + + private String windSourceToSerialize; + private TimePoint fromTime; + private TimePoint toTime; + private final WindTrackJsonSerializer windTrackSerializer; + + public TrackedRaceJsonSerializer(WindTrackJsonSerializer windTrackSerializer) { + this.windTrackSerializer = windTrackSerializer; + windSourceToSerialize = WindSourceType.COMBINED.name(); + } + + public JSONObject serialize(TrackedRace trackedRace) { + JSONObject jsonRace = new JSONObject(); + + jsonRace.put(FIELD_NAME, trackedRace.getRace().getName()); + jsonRace.put(FIELD_REGATTA, trackedRace.getRaceIdentifier().getRegattaName()); + + if(windTrackSerializer != null) { + JSONArray windTracks = new JSONArray(); + + List windSources = getAvailableWindSources(trackedRace); + for (WindSource windSource : windSources) { + if (ALL_WINDSOURCES.equals(windSourceToSerialize) || windSource.getType().name().equalsIgnoreCase(windSourceToSerialize)) { + windTrackSerializer.setFromTime(fromTime); + windTrackSerializer.setToTime(toTime); + windTrackSerializer.setWindSource(windSource); + + WindTrack windTrack = trackedRace.getOrCreateWindTrack(windSource); + JSONObject jsonWindTrack = windTrackSerializer.serialize(windTrack); + windTracks.add(jsonWindTrack); + } + } + jsonRace.put(FIELD_WINDSOURCES, windTracks); + } + + return jsonRace; + } + + public void setWindSource(String windSourceToSerialize) { + this.windSourceToSerialize = windSourceToSerialize; + } + + public void setFromTime(TimePoint fromTime) { + this.fromTime = fromTime; + } + + public void setToTime(TimePoint toTime) { + this.toTime = toTime; + } + + private List getAvailableWindSources(TrackedRace trackedRace) { + List windSources = new ArrayList(); + for (WindSource windSource : trackedRace.getWindSources()) { + windSources.add(windSource); + } + for (WindSource windSourceToExclude : trackedRace.getWindSourcesToExclude()) { + windSources.remove(windSourceToExclude); + } + windSources.add(new WindSourceImpl(WindSourceType.COMBINED)); + return windSources; + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/WindTrackJsonSerializer.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/WindTrackJsonSerializer.java new file mode 100644 index 00000000000..d61c2f7cc68 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/WindTrackJsonSerializer.java @@ -0,0 +1,12 @@ +package com.sap.sailing.server.gateway.jaxrs.api; + +import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.WindSource; +import com.sap.sailing.domain.tracking.WindTrack; +import com.sap.sailing.server.gateway.serialization.JsonSerializer; + +public interface WindTrackJsonSerializer extends JsonSerializer { + void setFromTime(TimePoint fromTime); + void setToTime(TimePoint toTime); + void setWindSource(WindSource windSource); +} diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/LeaderboardGroupsStructureResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/LeaderboardGroupsStructureResource.java new file mode 100644 index 00000000000..3d2aaca2677 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/LeaderboardGroupsStructureResource.java @@ -0,0 +1,45 @@ +package com.sap.sailing.server.gateway.jaxrs.spi; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; + +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; +import com.sap.sailing.server.gateway.serialization.masterdata.impl.TopLevelMasterDataSerializer; + +@Path("/v1/leaderboardgroups/structure") +public class LeaderboardGroupsStructureResource extends AbstractSailingServerResource { + + @GET + @Produces("application/json;charset=UTF-8") + public Response getStructureOfLeaderboardGroups(@QueryParam("names") List leaderboardGroupNames) { + Map leaderboardGroups = getService().getLeaderboardGroups(); + Set requestedLeaderboardGroupNames = new HashSet(); + + if (leaderboardGroupNames != null && !leaderboardGroupNames.isEmpty()) { + requestedLeaderboardGroupNames.addAll(leaderboardGroupNames); + } else { + // No range supplied. Export all for now + requestedLeaderboardGroupNames.addAll(leaderboardGroups.keySet()); + } + + TopLevelMasterDataSerializer masterSerializer = new TopLevelMasterDataSerializer(leaderboardGroups, + getService().getAllEvents(), getService().getPersistentRegattasForRaceIDs(), getService().getAllMediaTracks()); + + JSONObject masterData = masterSerializer.serialize(requestedLeaderboardGroupNames); + + byte[] json = masterData.toJSONString().getBytes(); + return Response.ok(json).build(); + } +} + \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/RestSpiApplication.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/RestSpiApplication.java new file mode 100644 index 00000000000..c84e93abd84 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/spi/RestSpiApplication.java @@ -0,0 +1,16 @@ +package com.sap.sailing.server.gateway.jaxrs.spi; + +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.core.Application; + + +public class RestSpiApplication extends Application { + public Set> getClasses() { + HashSet> classes = new HashSet<>(); + classes.add(LeaderboardGroupsStructureResource.class); + + return classes; + } +} diff --git a/java/com.sap.sailing.server.gateway/webservices/eventsExportDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/eventsExportDoc.html similarity index 72% rename from java/com.sap.sailing.server.gateway/webservices/eventsExportDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/eventsExportDoc.html index 824cb23e59a..eee5368fbcb 100644 --- a/java/com.sap.sailing.server.gateway/webservices/eventsExportDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/eventsExportDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/eventsExportSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/eventsExportSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/eventsExportSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/eventsExportSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/api/deprecated/index.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/index.html new file mode 100644 index 00000000000..c6fb70b603c --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/index.html @@ -0,0 +1,110 @@ + + + + + + + + Deprecated Web Services API + + +

SAP Sailing Analytics Deprecated Web Services API - Overview

+ +

+The best entry point to navigating the contents of a server is usually the leaderboardgroups service, +listing the leaderboard groups offered by the server. For example, +http://www.sapsailing.com/sailingserver/leaderboardgroups +lists the names of the leaderboard groups that the server instance knows. The names returned in the list can then be used +as parameter for the leaderboardgroup service, e.g., as follows: +http://www.sapsailing.com/sailingserver/leaderboardgroup?leaderboardGroupName=Star%20IDM%202013. +Note, of course, that the name needs to be URL-encoded with special characters and white spaces correctly +translated into URL format. +

+
+

+The leaderboard group service list the leaderboards in the group. There are essentially two types of leaderboard: +flexible leaderboards and regatta leaderboards. For flexible leaderboards, the service tells the list of races +in the leaderboard, and for each race in particular the regatta name and the tracked race name. These two attributes +can, in turn, be used as parameters for further services to identify the race for which information shall be retrieved and +to fetch information about the regatta with its structure such as series and fleets. +Again, note that those names need to be URL-encoded accordingly when used as parameter to a service call. +

+
+

+When a service takes a time point as a parameter, there are usually two ways of specifying it: either as an +ISO time stamp, e.g., 2013-05-08T10:12:59Z or as Unix time stamp (milliseconds since 1970-01-01T00:00:00Z). The parameters +in the latter format are usually called ...asmillis. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Web ServiceDescriptionSupported formats
/eventsGets all eventsJson
/regattasGets all regattasJson
/regattaGets a regattaJson
/leaderboardgroupsGets all leaderboard groupsJson
/leaderboardgroupGets a group of leaderboardsJson
/leaderboardsGets all leaderboardsJson
/leaderboardGets a leaderboardJson
/windGets wind data for a raceJson
+
+Back to Web Services Home + + \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/webservices/leaderboardExportDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardExportDoc.html similarity index 77% rename from java/com.sap.sailing.server.gateway/webservices/leaderboardExportDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardExportDoc.html index 7c8bf97d641..4d5913755c3 100644 --- a/java/com.sap.sailing.server.gateway/webservices/leaderboardExportDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardExportDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/leaderboardExportSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardExportSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/leaderboardExportSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardExportSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/leaderboardGroupExportDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardGroupExportDoc.html similarity index 75% rename from java/com.sap.sailing.server.gateway/webservices/leaderboardGroupExportDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardGroupExportDoc.html index 5fac5000b9e..57e20e9f245 100644 --- a/java/com.sap.sailing.server.gateway/webservices/leaderboardGroupExportDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardGroupExportDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/leaderboardGroupExportSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardGroupExportSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/leaderboardGroupExportSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardGroupExportSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/leaderboardGroupsExportDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardGroupsExportDoc.html similarity index 72% rename from java/com.sap.sailing.server.gateway/webservices/leaderboardGroupsExportDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardGroupsExportDoc.html index fca3e68621d..f96607f824b 100644 --- a/java/com.sap.sailing.server.gateway/webservices/leaderboardGroupsExportDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardGroupsExportDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/leaderboardGroupsExportSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardGroupsExportSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/leaderboardGroupsExportSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardGroupsExportSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/leaderboardsExportDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardsExportDoc.html similarity index 72% rename from java/com.sap.sailing.server.gateway/webservices/leaderboardsExportDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardsExportDoc.html index d010dcdeb97..b422945c14c 100644 --- a/java/com.sap.sailing.server.gateway/webservices/leaderboardsExportDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardsExportDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/leaderboardsExportSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardsExportSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/leaderboardsExportSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/leaderboardsExportSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/regattaExportDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/regattaExportDoc.html similarity index 76% rename from java/com.sap.sailing.server.gateway/webservices/regattaExportDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/regattaExportDoc.html index 0c9cc590020..e37747d6125 100644 --- a/java/com.sap.sailing.server.gateway/webservices/regattaExportDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/regattaExportDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/regattaExportSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/regattaExportSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/regattaExportSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/regattaExportSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/regattasExportDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/regattasExportDoc.html similarity index 71% rename from java/com.sap.sailing.server.gateway/webservices/regattasExportDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/regattasExportDoc.html index 2888824893c..7171c12b148 100644 --- a/java/com.sap.sailing.server.gateway/webservices/regattasExportDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/regattasExportDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/regattasExportSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/regattasExportSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/regattasExportSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/regattasExportSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/showboatpositionsDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/showboatpositionsDoc.html similarity index 82% rename from java/com.sap.sailing.server.gateway/webservices/showboatpositionsDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/showboatpositionsDoc.html index 8300c605337..587a386894d 100755 --- a/java/com.sap.sailing.server.gateway/webservices/showboatpositionsDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/showboatpositionsDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/showboatpositionsSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/showboatpositionsSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/showboatpositionsSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/showboatpositionsSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/showraceDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/showraceDoc.html similarity index 81% rename from java/com.sap.sailing.server.gateway/webservices/showraceDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/showraceDoc.html index 3850e988156..f2c10dbe19f 100755 --- a/java/com.sap.sailing.server.gateway/webservices/showraceDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/showraceDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/showraceSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/showraceSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/showraceSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/showraceSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/showwaypointsDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/showwaypointsDoc.html similarity index 80% rename from java/com.sap.sailing.server.gateway/webservices/showwaypointsDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/showwaypointsDoc.html index 7989ebd9aab..a54c71c24c0 100755 --- a/java/com.sap.sailing.server.gateway/webservices/showwaypointsDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/showwaypointsDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/showwaypointsSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/showwaypointsSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/showwaypointsSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/showwaypointsSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/windExportDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/windExportDoc.html similarity index 76% rename from java/com.sap.sailing.server.gateway/webservices/windExportDoc.html rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/windExportDoc.html index 876e7342956..98fc03556e0 100644 --- a/java/com.sap.sailing.server.gateway/webservices/windExportDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/windExportDoc.html @@ -2,10 +2,10 @@ - - - - Gateway services + + + + Deprecated Web Services API

SAP Sailing Analytics - Web Services

diff --git a/java/com.sap.sailing.server.gateway/webservices/windExportSample.json b/java/com.sap.sailing.server.gateway/webservices/api/deprecated/windExportSample.json similarity index 100% rename from java/com.sap.sailing.server.gateway/webservices/windExportSample.json rename to java/com.sap.sailing.server.gateway/webservices/api/deprecated/windExportSample.json diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/eventsGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/eventsGetDoc.html new file mode 100644 index 00000000000..93b834abf0c --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/eventsGetDoc.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/events

+ +Description: +

The service gets all existing events with their venues and course areas

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/events
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/index.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/index.html new file mode 100644 index 00000000000..bfea3dfe064 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/index.html @@ -0,0 +1,88 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta - Overview

+ +

+A number of web services are available to query the state of a SAP Sailing Analytics server instance. +Note that different server instances exist, and not all servers hold the same data. Usually, events get +their own URL which is then made sure to point to a server instance holding the data for that event. +We use an Apache reverse proxy to map URLs (and in particular the sub-domain) to a particular server instance. +So, www.sapsailing.com may end up on a different server instance than +tw2013.sapsailing.com +or ess40-2013.sapsailing.com. Usually, we hand out a per-event +or per-series URL, such as the ones above (except www.sapsailing.com which is the general landing page), +and you would only fetch the content for the event you're interested in, even if the server instance has more. +In all subsequent explanations, you may replace the "www.sapsailing.com" hostname by an according per-event host +name to make sure you get to the event you're interested in. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice URLDescription
/api/v1/eventsGets all events
/api/v1/regattasGets all regattas
/api/v1/regattas/{name}Gets the details of a regatta
/api/v1/regattas/{regattaname}/races/{racename}/competitors/positionsGets all GPS positions of the competitors of a race
/api/v1/regattas/{regattaname}/races/{racename}/competitors/legsGets some leg information (e.g. rank, distance traveled) for all competitors of a race
/api/v1/regattas/{regattaname}/races/{racename}/marks/positionsGets all GPS positions of the course marks of a race
/api/v1/regattas/{regattaname}/races/{racename}/courseGets the course of a race
/api/v1/regattas/{regattaname}/races/{racename}/windGets all GPS positions and data values for the wind of a race
/api/v1/leaderboardgroupsGets all leaderboard groups
/api/v1/leaderboardgroups/{name}Gets the details of a group of leaderboards
/api/v1/leaderboardsGets all leaderboards
/api/v1/leaderboards/{name}Gets the details of a leaderboard
+
+Back to Web Services Home + + \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardGetDoc.html new file mode 100644 index 00000000000..aac2459e435 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardGetDoc.html @@ -0,0 +1,50 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/leaderboards/{name}

+ +Description: +

The service gets the details of a leaderboard

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:resultState [Live = Default, Preliminary, Final]
 maxCompetitorsCount [1000 = Default]
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/leaderboards/505 Worlds 2013
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardgroupGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardgroupGetDoc.html new file mode 100644 index 00000000000..17100d714fc --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardgroupGetDoc.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/leaderboardgroups/{name}

+ +Description: +

The service gets the details of a group of leaderboards

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/leaderboardgroups/505 Worlds 2013
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardgroupsGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardgroupsGetDoc.html new file mode 100644 index 00000000000..f24dcf896f2 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardgroupsGetDoc.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/leaderboardgroups

+ +Description: +

The service gets the names of all existing leaderboard groups

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/leaderboardgroups
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardsGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardsGetDoc.html new file mode 100644 index 00000000000..8506d47f1c2 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/leaderboardsGetDoc.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/leaderboards

+ +Description: +

The service gets the names of all existing leaderboards

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/leaderboards
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCompetitorLegsGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCompetitorLegsGetDoc.html new file mode 100644 index 00000000000..49623342cd1 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCompetitorLegsGetDoc.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/regattas/{regattaname}/races/{racename}/competitors/legs

+ +Description: +

Gets some leg information (e.g. rank, distance traveled) for all competitors of a race

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/regattas/{regattaname}/races/{racename}/competitors/legs
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCompetitorPositionsGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCompetitorPositionsGetDoc.html new file mode 100644 index 00000000000..10d6ea90eb2 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCompetitorPositionsGetDoc.html @@ -0,0 +1,51 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/regattas/{regattaname}/races/{racename}/competitors/positions

+ +Description: +

Gets all GPS positions of the competitors of a race

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters: +
from
+
fromasmillis
+
to
+
toasmillis
+
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/regattas/{regattaname}/races/{racename}/competitors/positions
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCourseGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCourseGetDoc.html new file mode 100644 index 00000000000..3584347292c --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCourseGetDoc.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/regattas/{regattaname}/races/{racename}/course

+ +Description: +

Gets the course of a race

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/regattas/{regattaname}/races/{racename}/course
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceMarkPositionsGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceMarkPositionsGetDoc.html new file mode 100644 index 00000000000..b1adbbc6a87 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceMarkPositionsGetDoc.html @@ -0,0 +1,51 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/regattas/{regattaname}/races/{racename}/marks/positions

+ +Description: +

Gets all GPS positions of the course marks of a race

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters: +
from
+
fromasmillis
+
to
+
toasmillis
+
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/regattas/{regattaname}/races/{racename}/marks/positions
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceWindGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceWindGetDoc.html new file mode 100644 index 00000000000..19cdfdd995c --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceWindGetDoc.html @@ -0,0 +1,55 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/regattas/{regattaname}/races/{racename}/wind

+ +Description: +

Gets all GPS positions and data values for the wind of a race

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters: +
regattaname
+
racename
+
Optional parameters: +
windsource [COMBINED = Default, WEB, EXPEDITION, TRACK_BASED_ESTIMATION, COURSE_BASED, RACECOMMITTEE]
+
fromtime
+
fromtimeasmillis
+
totime
+
totimeasmillis
+
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/regattas/{regattaname}/races/{racename}/wind
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/regattaGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/regattaGetDoc.html new file mode 100644 index 00000000000..0671ea6e291 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/regattaGetDoc.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/regattas/{name}

+ +Description: +

The service gets the details of a regatta

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/regatta/Kieler Woche (5o5)
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/regattasGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/regattasGetDoc.html new file mode 100644 index 00000000000..8b4b163cdfe --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/regattasGetDoc.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /api/v1/regattas

+ +Description: +

The service gets the names of all existing regattas

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:None
Request method:GET
Example:http://www.sapsailing.com/sailingserver/api/v1/regattas
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.gateway/webservices/index.html b/java/com.sap.sailing.server.gateway/webservices/index.html index 5e35611d086..7a3f9cd65c4 100644 --- a/java/com.sap.sailing.server.gateway/webservices/index.html +++ b/java/com.sap.sailing.server.gateway/webservices/index.html @@ -23,97 +23,16 @@ and you would only fetch the content for the event you're interested in, even if In all subsequent explanations, you may replace the "www.sapsailing.com" hostname by an according per-event host name to make sure you get to the event you're interested in.

- -

-The best entry point to navigating the contents of a server is usually the leaderboardgroups service, -listing the leaderboard groups offered by the server. For example, -http://www.sapsailing.com/sailingserver/leaderboardgroups -lists the names of the leaderboard groups that the server instance knows. The names returned in the list can then be used -as parameter for the leaderboardgroup service, e.g., as follows: -http://www.sapsailing.com/sailingserver/leaderboardgroup?leaderboardGroupName=Star%20IDM%202013. -Note, of course, that the name needs to be URL-encoded with special characters and white spaces correctly -translated into URL format. +

+

+Attention: +We are going to introduce a new and more managed WebServices API. The old API is marked as deprecated but will continue to work for some time.

- -

-The leaderboard group service list the leaderboards in the group. There are essentially two types of leaderboard: -flexible leaderboards and regatta leaderboards. For flexible leaderboards, the service tells the list of races -in the leaderboard, and for each race in particular the regatta name and the tracked race name. These two attributes -can, in turn, be used as parameters for further services to identify the race for which information shall be retrieved and -to fetch information about the regatta with its structure such as series and fleets. -Again, note that those names need to be URL-encoded accordingly when used as parameter to a service call. -

- -

-When a service takes a time point as a parameter, there are usually two ways of specifying it: either as an -ISO time stamp, e.g., 2013-05-08T10:12:59Z or as Unix time stamp (milliseconds since 1970-01-01T00:00:00Z). The parameters -in the latter format are usually called ...asmillis. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Web ServiceDescriptionSupported formats
eventsGets all eventsJson
regattasGets all regattasJson
regattaGets a regattaJson
leaderboardgroupsGets all leaderboard groupsJson
leaderboardgroupGets a group of leaderboardsJson
leaderboardsGets all leaderboardsJson
leaderboardGets a leaderboardJson
windGets wind data for a raceJson
showraceGets general time-dependent data for a race and the competitorsJson
showwaypointsGets course and waypoint data for a raceJson
showboatpositionsGets boat GPS data for a raceJson
+
+Webservices API-Documention:
+ \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/webservices/spi/v1/index.html b/java/com.sap.sailing.server.gateway/webservices/spi/v1/index.html new file mode 100644 index 00000000000..f461dd1ee8b --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/spi/v1/index.html @@ -0,0 +1,30 @@ + + + + + + + + SAP-Sailing Analytics Webservices SPI Version 1.0 + + +

SAP-Sailing Analytics Webservices SPI Version 1.0 - Overview

+ + + + + + + + + + + + + + +
Webservice URLDescription
/spi/v1/leaderboardgroups/structureGets the internal structure of a list of leaderboard groups
+
+Back to Web Service Home + + \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/webservices/spi/v1/leaderboardgroupsStructureGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/spi/v1/leaderboardgroupsStructureGetDoc.html new file mode 100644 index 00000000000..375744f6f38 --- /dev/null +++ b/java/com.sap.sailing.server.gateway/webservices/spi/v1/leaderboardgroupsStructureGetDoc.html @@ -0,0 +1,46 @@ + + + + + + + + SAP Sailing Analytics Webservices API Version 1.0 Beta + + +

SAP Sailing Analytics Webservices API Version 1.0 Beta

+

URL: /spi/v1/leaderboardgroups/structure

+ +Description: +

The service gets the wind data of a race

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Webservice Type:REST
Output format:Json
Mandatory parameters:None
Optional parameters:names
Request method:GET
Example:http://www.sapsailing.com/sailingserver/spi/v1/leaderboardgroups/structure
+
+Back to Web Service Overview + + diff --git a/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF index dbf7938bac6..1d08244f5d9 100644 --- a/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF @@ -6,9 +6,7 @@ Bundle-Version: 1.0.0.qualifier Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Fragment-Host: com.sap.sailing.server.replication -Import-Package: com.rabbitmq.client;version="2.8.4", - junit.framework;version="4.8.1", - org.junit;version="4.8.1" +Import-Package: com.rabbitmq.client;version="2.8.4" Require-Bundle: com.sap.sailing.server, com.sap.sailing.domain.common, com.sap.sailing.domain, @@ -21,4 +19,5 @@ Require-Bundle: com.sap.sailing.server, com.sap.sailing.expeditionconnector, com.sap.sailing.domain.swisstimingadapter, org.json.simple;bundle-version="1.1.0", + org.junit4;bundle-version="4.8.2", org.hamcrest;bundle-version="1.1.0" diff --git a/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF index 79db93d1930..7a646cd8493 100755 --- a/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF @@ -15,10 +15,9 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sailing.mongodb, com.tractrac.clientmodule;bundle-version="2.0.0", com.mongodb.driver;bundle-version="2.6.2", + org.junit4;bundle-version="4.8.2", com.sap.sailing.domain.test, org.hamcrest;bundle-version="1.1.0", com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0" -Import-Package: junit.framework;version="4.8.1", - org.junit;version="4.8.1", - org.json.simple +Import-Package: org.json.simple Export-Package: com.sap.sailing.server.impl diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java index a3915c15166..b6076ad97a8 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java @@ -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> positionedCompetitors = new ArrayList>(); + positionedCompetitors.add(new Triple(competitor.getId(), competitor.getName(), MaxPointsReason.BFD)); + positionedCompetitors.add(new Triple(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()); + UUID courseAreaUUID = UUID.randomUUID(); + CourseArea courseArea = new CourseAreaImpl("testArea", courseAreaUUID); + event.getVenue().addCourseArea(courseArea); + + List raceColumnNames = new ArrayList(); + String raceColumnName = "T1"; + raceColumnNames.add(raceColumnName); + raceColumnNames.add("T2"); + final List emptyRaceColumnNamesList = Collections.emptyList(); + + List series = new ArrayList(); + List fleets = new ArrayList(); + 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 leaderboardNames = new ArrayList(); + leaderboardNames.add(leaderboard.getName()); + sourceService.addLeaderboardGroup(TEST_GROUP_NAME, "testGroupDesc", false, leaderboardNames, null, null); + + // Set tracked Race with competitors + Set competitors = new HashSet(); + UUID competitorUUID = UUID.randomUUID(); + Set sailors = new HashSet(); + 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 sailors2 = new HashSet(); + 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> positionedCompetitors = new ArrayList>(); + positionedCompetitors.add(new Triple(competitor.getId(), competitor.getName(), MaxPointsReason.DNS)); + positionedCompetitors.add(new Triple(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 names = new HashSet(); + 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 competitorsCreatedOnTarget = new HashSet(); + competitorsCreatedOnTarget.add(competitorOnTarget); + + TrackedRace trackedRaceForTarget = new DummyTrackedRace(competitorsCreatedOnTarget, regattaOnTarget); + Fleet fleet1OnTarget = raceColumnOnTarget.getFleetByName(testFleet1.getName()); + raceColumnOnTarget.setTrackedRace(fleet1OnTarget, trackedRaceForTarget); + + Iterable competitorsOnTarget = leaderboardOnTarget.getAllCompetitors(); + Iterator 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 diff --git a/java/com.sap.sailing.server.trackfiles.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.trackfiles.test/META-INF/MANIFEST.MF index 8d26e6b0091..fcaa64fa64a 100644 --- a/java/com.sap.sailing.server.trackfiles.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server.trackfiles.test/META-INF/MANIFEST.MF @@ -5,15 +5,14 @@ Bundle-SymbolicName: com.sap.sailing.server.trackfiles.test Bundle-Version: 1.0.0.qualifier Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.7 -Require-Bundle: com.sap.sailing.server.trackfiles, - com.tractrac.clientmodule;bundle-version="2.0.0", +Fragment-Host: com.sap.sailing.server.trackfiles +Require-Bundle: com.tractrac.clientmodule;bundle-version="2.0.0", com.sap.sailing.domain.tractracadapter, com.googlecode.java-diff-utils;bundle-version="1.3.0", com.sap.sailing.domain.common, com.sap.sailing.domain.test;bundle-version="1.0.0", com.sap.sailing.domain;bundle-version="1.0.0", - com.sap.sailing.server;bundle-version="1.0.0" -Import-Package: junit.framework;version="4.8.1", - org.json.simple, - org.json.simple.parser, - org.junit;version="4.8.1" + com.sap.sailing.server;bundle-version="1.0.0", + org.junit4;bundle-version="4.8.2" +Import-Package: org.json.simple, + org.json.simple.parser diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy).launch b/java/com.sap.sailing.server/SailingServer (No Proxy).launch index a57a4653d7d..ffa53ac74e2 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy).launch @@ -18,7 +18,7 @@ - + @@ -28,9 +28,9 @@ - + - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch index dd8c852aef2..77e917122fc 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch @@ -22,7 +22,7 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Monitoring).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Monitoring).launch index d6bdfccc2ef..871a4c361dc 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Monitoring).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Monitoring).launch @@ -22,7 +22,7 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, No Tests).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, No Tests).launch index daff9dc0887..74b58322c07 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, No Tests).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, No Tests).launch @@ -21,7 +21,7 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch index f61bf2f668c..0e310c59ce8 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch @@ -21,7 +21,7 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (Proxy).launch b/java/com.sap.sailing.server/SailingServer (Proxy).launch index 4bfb820d4d5..fd283c15bd2 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy).launch @@ -22,10 +22,10 @@ - + - + diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch index 865a19b1987..69d27d3bf3b 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch @@ -22,7 +22,7 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch b/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch index d33bd740031..5939146639d 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch @@ -22,7 +22,7 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch b/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch index db41c6b0869..4b7a4e1035d 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy, SwissTiming Live Simulation).launch @@ -21,7 +21,7 @@ - + diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/ExtenderBundleTracker.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/ExtenderBundleTracker.java index 1ac74048c85..b7672874a0b 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/ExtenderBundleTracker.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/ExtenderBundleTracker.java @@ -36,16 +36,14 @@ public class ExtenderBundleTracker extends BundleTracker { public void modifiedBundle(Bundle bundle, BundleEvent event, Bundle object) { String symbolicName = bundle.getSymbolicName(); logger.info(symbolicName + " " + getBundleStateAsText(event)); - - if(event != null && event.getType() == BundleEvent.STOPPING) { + if (event != null && event.getType() == BundleEvent.STOPPING) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); StringBuffer b = new StringBuffer(); - for(StackTraceElement traceElement: stackTrace) { + for (StackTraceElement traceElement : stackTrace) { b.append(traceElement.toString() + "\n"); } - logger.info(b.toString()); + logger.fine(b.toString()); } - String trackManifestEntry = (String) bundle.getHeaders().get("TrackLifecycle"); if (trackManifestEntry != null) { trackLifecycle(bundle, event); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java index ec40af24cc7..21386648ecc 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java @@ -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 positionedCompetitor : positioningList) { - Competitor competitor = DomainFactory.INSTANCE.getExistingCompetitorById(positionedCompetitor.getA()); + Competitor competitor = service.getBaseDomainFactory().getExistingCompetitorById(positionedCompetitor.getA()); if (positionedCompetitor.getC().equals(MaxPointsReason.NONE)) { try { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 9eac80d239e..8c16475a91d 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -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) { @@ -582,11 +580,13 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen @Override public void removeLeaderboard(String leaderboardName) { Leaderboard leaderboard = removeLeaderboardFromLeaderboardsByName(leaderboardName); - leaderboard.removeRaceColumnListener(raceLogReplicator); - leaderboard.removeRaceColumnListener(raceLogScoringReplicator); - mongoObjectFactory.removeLeaderboard(leaderboardName); - syncGroupsAfterLeaderboardRemove(leaderboardName, true); - leaderboard.destroy(); + if (leaderboard != null) { + leaderboard.removeRaceColumnListener(raceLogReplicator); + leaderboard.removeRaceColumnListener(raceLogScoringReplicator); + mongoObjectFactory.removeLeaderboard(leaderboardName); + syncGroupsAfterLeaderboardRemove(leaderboardName, true); + leaderboard.destroy(); + } } private Leaderboard removeLeaderboardFromLeaderboardsByName(String leaderboardName) { @@ -771,9 +771,13 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen SailMasterConnector swissTimingConnector = swissTimingFactory.getOrCreateSailMasterConnector(hostname, port, swissTimingAdapterPersistence, canSendRequests); for (Race race : swissTimingConnector.getRaces()) { - TimePoint startTime = swissTimingConnector.getStartTime(race.getRaceID()); - result.add(new com.sap.sailing.domain.swisstimingadapter.RaceRecord(race.getRaceID(), - race.getDescription(), startTime == null ? null : startTime.asDate())); + String raceID = race.getRaceID(); + TimePoint startTime = swissTimingConnector.getStartTime(raceID); + boolean hasCourse = swissTimingConnector.hasCourse(raceID); + boolean hasStartlist = swissTimingConnector.hasStartlist(raceID); + result.add(new com.sap.sailing.domain.swisstimingadapter.RaceRecord(raceID, + race.getDescription(), startTime == null ? null : startTime.asDate(), + hasCourse, hasStartlist)); } return result; } @@ -1158,7 +1162,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen stopTrackingWind(regatta, race); } } - raceTracker.stop(); // this also removes the TrackedRace from trackedRegatta + raceTracker.stop(); raceTrackersByID.remove(raceTracker.getID()); } raceTrackersByRegatta.remove(regatta); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java index 5b71da06724..a7bfcfd31f2 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java @@ -170,7 +170,7 @@ public class ImportMasterDataOperation extends List logEvents = fleetEntry.getValue(); RaceLog raceLog = raceColumn.getRaceLog(fleet); for (RaceLogEvent singleEvent : logEvents) { - raceLog.add(singleEvent); + raceLog.load(singleEvent); } } } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateLeaderboardMaxPointsReason.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateLeaderboardMaxPointsReason.java index d6c5673e81c..2a1cce83097 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateLeaderboardMaxPointsReason.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateLeaderboardMaxPointsReason.java @@ -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(updatedEntry.getNetPoints(), updatedEntry.getTotalPoints(), isScoreCorrected); } else { throw new IllegalArgumentException("Didn't find competitor with ID "+competitorIdAsString+" in leaderboard "+getLeaderboardName()); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateLeaderboardScoreCorrection.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateLeaderboardScoreCorrection.java index 7319800c250..31c073f27e0 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateLeaderboardScoreCorrection.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateLeaderboardScoreCorrection.java @@ -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()); } diff --git a/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-ide-local.target b/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-ide-local.target index 7f9be4428d6..be869928137 100644 --- a/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-ide-local.target +++ b/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-ide-local.target @@ -1,19 +1,13 @@ - + - - - - - - @@ -22,10 +16,14 @@ - - - - + + + + + + + + @@ -37,5 +35,18 @@ + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-ide-p2admin.target b/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-ide-p2admin.target index 5dac40b7a79..2065dd2ae87 100644 --- a/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-ide-p2admin.target +++ b/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-ide-p2admin.target @@ -8,8 +8,17 @@ - - + + + + + + + + + + + @@ -20,10 +29,12 @@ - - - - + + + + + + diff --git a/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-maven-central.target b/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-maven-central.target index 82b884f1808..41f740bdedd 100644 --- a/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-maven-central.target +++ b/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-maven-central.target @@ -10,14 +10,21 @@ - - - - + + + + + + + + + + + @@ -28,10 +35,12 @@ - - - - + + + + + + diff --git a/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-maven-local.target b/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-maven-local.target index acc7c5dc7a9..b56910ea88f 100644 --- a/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-maven-local.target +++ b/java/com.sap.sailing.targetplatform/definitions/race-analysis-p2-maven-local.target @@ -7,8 +7,6 @@ - - @@ -16,8 +14,17 @@ - - + + + + + + + + + + + @@ -28,10 +35,12 @@ - - - - + + + + + + diff --git a/java/com.sap.sailing.www.events/ess40/mobile.html b/java/com.sap.sailing.www.events/ess40/mobile.html index aec15c0dfd7..7c4b627b278 100644 --- a/java/com.sap.sailing.www.events/ess40/mobile.html +++ b/java/com.sap.sailing.www.events/ess40/mobile.html @@ -20,18 +20,11 @@

Extreme Sailing Series 2013

Next Event

- Act 6 - Cardiff, England -

-

- August 22th - 25th -

-