diff --git a/doc/SAPSailingAnalytics_Administrator_Training.pptx b/doc/SAPSailingAnalytics_Administrator_Training.pptx
index 73acb57142a..417c356472f 100644
Binary files a/doc/SAPSailingAnalytics_Administrator_Training.pptx and b/doc/SAPSailingAnalytics_Administrator_Training.pptx differ
diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/DashboardClientFactoryImpl.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/DashboardClientFactoryImpl.java
index 9ca74a9fbdf..57e263299b0 100644
--- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/DashboardClientFactoryImpl.java
+++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/DashboardClientFactoryImpl.java
@@ -1,12 +1,9 @@
package com.sap.sailing.dashboards.gwt.client;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchSystem;
import com.sap.sailing.dashboards.gwt.shared.dispatch.impl.DashboardDispatchSystemImpl;
-import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
-import com.sap.sse.gwt.client.EntryPointHelper;
+import com.sap.sailing.gwt.ui.client.SailingServiceHelper;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
@@ -24,8 +21,7 @@ public class DashboardClientFactoryImpl implements DashboardClientFactory{
public DashboardClientFactoryImpl() {
dispatch = new DashboardDispatchSystemImpl();
- sailingService = GWT.create(SailingService.class);
- EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService, RemoteServiceMappingConstants.WEB_CONTEXT_PATH, RemoteServiceMappingConstants.sailingServiceRemotePath);
+ sailingService = SailingServiceHelper.createSailingServiceInstance(false);
dashboardFiveSecondsTimer = new Timer(PlayModes.Live);
dashboardFiveSecondsTimer.setRefreshInterval(DASHBOARD_RERFRESH_INTERVAL);
diff --git a/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF
index 98840fcc156..366d8cd72b9 100644
--- a/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF
@@ -17,6 +17,7 @@ Export-Package: com.sap.sailing.domain.common,
com.sap.sailing.domain.common.quadtree,
com.sap.sailing.domain.common.quadtree.impl;x-friends:="com.sap.sailing.domain.test",
com.sap.sailing.domain.common.racelog,
+ com.sap.sailing.domain.common.sharding,
com.sap.sailing.domain.common.racelog.tracking,
com.sap.sailing.domain.common.racelog.utils,
com.sap.sailing.domain.common.scalablevalue.impl,
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java
index 79b6493febb..211470e68cf 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java
@@ -31,6 +31,7 @@ public enum BoatClassMasterdata {
CANOE_TAIFUN ("Canoe Taifun", true, 5.20, 1.32, BoatHullType.MONOHULL, false, "Taifun", "Taifun Kanu", "Kanu Taifun"),
CONTENDER ("Contender", true, 4.88, 1.42, BoatHullType.MONOHULL, false),
CC_30 ("C&C 30", true, 9.12, 3.25, BoatHullType.MONOHULL, true),
+ CLUB_SWAN_50 ("Club Swan 50", true, 16.74, 4.20, BoatHullType.MONOHULL, true, "ClubSwan50"),
D_ONE ("D-One", true, 4.23, 2.31, BoatHullType.MONOHULL, true, "Devoti D-One", "DOne", "D_One"),
DRAGON_INT ("Dragon Int.", true, 8.89, 1.96, BoatHullType.MONOHULL, true, "Drachen", "Dragon"),
DELPHIA_24 ("Delphia 24", true, 7.70, 2.50, BoatHullType.MONOHULL, true, "Delphia 24 One Design", "Delphia 24 OD"),
@@ -44,6 +45,7 @@ public enum BoatClassMasterdata {
FARR_280 ("Farr 280", true, 8.72, 2.87, BoatHullType.MONOHULL, true, "F280", "F-280", "Farr-280"),
FINN ("Finn", true, 4.50, 1.51, BoatHullType.MONOHULL, false),
FLYING_DUTCHMAN ("Flying Dutchman", true, 6.10, 1.80, BoatHullType.MONOHULL, true, "FD"),
+ FLYING_JUNIOR ("Flying Junior", true, 4.03, 1.50, BoatHullType.MONOHULL, true, "FJ"),
FLYING_PHANTOM ("Flying Phantom", true, 5.52, 3.00, BoatHullType.CATAMARAN, true),
FOLKBOAT ("Folkboat", true, 7.68, 2.20, BoatHullType.MONOHULL, false, "Folke", "Folkeboot"),
FUN ("FUN", true, 7.20, 2.45, BoatHullType.MONOHULL, true, "FUN O.D.", "FUN OD", "Open FUN"),
@@ -115,6 +117,7 @@ public enum BoatClassMasterdata {
TOM_28_MAX ("Tom 28 MAX", true, 8.48, 2.48, BoatHullType.MONOHULL, true, "Tom 28"),
TRIAS ("Trias", true, 9.20, 2.12, BoatHullType.MONOHULL, true),
TP52 ("TP52", true, 15.85, 4.35, BoatHullType.MONOHULL, true, "TP 52", "Transpac 52", "Transpac52"),
+ VAURIEN ("Vaurien", true, 4.08, 1.47, BoatHullType.MONOHULL, true),
VENT_D_OUEST ("Vent d'Ouest", true, 5.85, 1.75, BoatHullType.MONOHULL, true, "VENTDOUEST", "VENTD'OUEST"),
VIPER_640 ("Viper 640", true, 6.43, 2.49, BoatHullType.MONOHULL, true),
VO60 ("VO60", true, 19.5, 5.25, BoatHullType.MONOHULL, true, "Volvo Ocean 60", "VolvoOcean60", "W60", "Whitbread60", "Whitbread 60"),
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java
index 5c727f3a542..b9d0717a096 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DetailType.java
@@ -5,10 +5,9 @@ import static com.sap.sailing.domain.common.SortingOrder.DESCENDING;
import static com.sap.sailing.domain.common.SortingOrder.NONE;
import java.io.Serializable;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.List;
+import java.util.LinkedHashSet;
/**
* Identifies details that can be requested from the racing service. Optionally, the details can specify a precision as
@@ -244,11 +243,11 @@ public enum DetailType implements Serializable {
}
/**
- * Special List of DetailTypes, that allows operators to select for example the RideHeight, that is usually only
- * selectable, if it already has data.
+ * Special collection of {@link DetailType}s, that allows operators to select for example the RideHeight, that is
+ * usually only selectable, if it already has data.
*/
- public static List getAutoplayDetailTypesForChart() {
- List availableDetailsTypes = new ArrayList<>();
+ public static Collection getAutoplayDetailTypesForChart() {
+ final Collection availableDetailsTypes = new LinkedHashSet<>();
availableDetailsTypes.add(DetailType.CHART_WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD);
availableDetailsTypes.add(DetailType.LEG_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
availableDetailsTypes.add(DetailType.LEG_DISTANCE_TRAVELED);
@@ -266,8 +265,8 @@ public enum DetailType implements Serializable {
return availableDetailsTypes;
}
- public static List getRaceExpeditionDetailTypes() {
- ArrayList allowed = new ArrayList<>();
+ public static Collection getRaceExpeditionDetailTypes() {
+ final Collection allowed = new LinkedHashSet<>();
allowed.add(EXPEDITION_RACE_AWA);
allowed.add(EXPEDITION_RACE_AWS);
allowed.add(EXPEDITION_RACE_TWA);
@@ -310,15 +309,8 @@ public enum DetailType implements Serializable {
return allowed;
}
- public static List getLegExtendedBravoDetailTypes() {
- ArrayList allowed = new ArrayList<>();
- allowed.add(DetailType.BRAVOEXTENDED_LEG_CURRENT_DISTANCE_FOILED_IN_METERS);
- allowed.add(DetailType.BRAVOEXTENDED_LEG_CURRENT_DURATION_FOILED_IN_SECONDS);
- return allowed;
- }
-
- public static List getRaceExtendedBravoDetailTypes() {
- ArrayList allowed = new ArrayList<>();
+ public static Collection getRaceExtendedBravoDetailTypes() {
+ final Collection allowed = new LinkedHashSet<>();
allowed.add(DetailType.BRAVOEXTENDED_RACE_CURRENT_PORT_DAGGERBOARD_RAKE);
allowed.add(DetailType.BRAVOEXTENDED_RACE_CURRENT_STBD_DAGGERBOARD_RAKE);
allowed.add(DetailType.BRAVOEXTENDED_RACE_CURRENT_PORT_RUDDER_RAKE);
@@ -340,24 +332,28 @@ public enum DetailType implements Serializable {
return allowed;
}
- public static List getRaceBravoDetailTypes() {
- ArrayList allowed = new ArrayList<>();
+ public static Collection getRaceBravoDetailTypes() {
+ final Collection allowed = new LinkedHashSet<>();
allowed.add(DetailType.BRAVO_RACE_HEEL_IN_DEGREES);
allowed.add(DetailType.BRAVO_RACE_PITCH_IN_DEGREES);
allowed.add(DetailType.BRAVO_RACE_CURRENT_RIDE_HEIGHT_IN_METERS);
+ allowed.add(DetailType.RACE_CURRENT_DISTANCE_FOILED_IN_METERS);
+ allowed.add(DetailType.RACE_CURRENT_DURATION_FOILED_IN_SECONDS);
return allowed;
}
- public static List getLegBravoDetailTypes() {
- ArrayList allowed = new ArrayList<>();
+ public static Collection getLegBravoDetailTypes() {
+ final Collection allowed = new LinkedHashSet<>();
allowed.add(DetailType.BRAVO_LEG_CURRENT_HEEL_IN_DEGREES);
allowed.add(DetailType.BRAVO_LEG_CURRENT_PITCH_IN_DEGREES);
allowed.add(DetailType.BRAVO_LEG_CURRENT_RIDE_HEIGHT_IN_METERS);
+ allowed.add(DetailType.BRAVOEXTENDED_LEG_CURRENT_DISTANCE_FOILED_IN_METERS);
+ allowed.add(DetailType.BRAVOEXTENDED_LEG_CURRENT_DURATION_FOILED_IN_SECONDS);
return allowed;
}
- public static List getAllRaceDetailTypes() {
- ArrayList allowed = new ArrayList<>();
+ public static Collection getAllRaceDetailTypes() {
+ final Collection allowed = new LinkedHashSet<>();
allowed.add(RACE_GAP_TO_LEADER_IN_SECONDS);
allowed.add(RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(RACE_DISTANCE_TRAVELED);
@@ -366,7 +362,6 @@ public enum DetailType implements Serializable {
allowed.add(RACE_CALCULATED_TIME_TRAVELED);
allowed.add(RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD);
allowed.add(RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
- allowed.add(BRAVO_RACE_CURRENT_RIDE_HEIGHT_IN_METERS);
allowed.add(RACE_CURRENT_DISTANCE_FOILED_IN_METERS);
allowed.add(RACE_CURRENT_DURATION_FOILED_IN_SECONDS);
allowed.add(RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS);
@@ -388,7 +383,7 @@ public enum DetailType implements Serializable {
* @return
*/
public static Collection getAllNonRestrictedDetailTypes() {
- List all = new ArrayList<>(Arrays.asList(values()));
+ final Collection all = new LinkedHashSet<>(Arrays.asList(values()));
all.removeAll(getRaceBravoDetailTypes());
all.removeAll(getLegBravoDetailTypes());
all.removeAll(getRaceExtendedBravoDetailTypes());
@@ -398,83 +393,150 @@ public enum DetailType implements Serializable {
return all;
}
- public static List getAvailableOverallDetailColumnTypes() {
- return Arrays.asList(new DetailType[] { DetailType.REGATTA_RANK, DetailType.OVERALL_TOTAL_DISTANCE_TRAVELED,
- DetailType.OVERALL_TOTAL_AVERAGE_SPEED_OVER_GROUND, DetailType.OVERALL_TOTAL_TIME_SAILED_IN_SECONDS,
- DetailType.OVERALL_MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS, DetailType.OVERALL_TIME_ON_TIME_FACTOR,
- DetailType.OVERALL_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE,
- DetailType.OVERALL_TOTAL_SCORED_RACE_COUNT, TOTAL_TIME_SAILED_UPWIND_IN_SECONDS,
- TOTAL_TIME_SAILED_REACHING_IN_SECONDS, TOTAL_TIME_SAILED_DOWNWIND_IN_SECONDS });
+ public static Collection getAvailableOverallDetailColumnTypes() {
+ final Collection allowed = new LinkedHashSet<>();
+ allowed.add(REGATTA_RANK);
+ allowed.add(OVERALL_TOTAL_DISTANCE_TRAVELED);
+ allowed.add(OVERALL_TOTAL_AVERAGE_SPEED_OVER_GROUND);
+ allowed.add(OVERALL_TOTAL_TIME_SAILED_IN_SECONDS);
+ allowed.add(OVERALL_MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS);
+ allowed.add(OVERALL_TIME_ON_TIME_FACTOR);
+ allowed.add(OVERALL_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE);
+ allowed.add(OVERALL_TOTAL_SCORED_RACE_COUNT);
+ allowed.add(TOTAL_TIME_SAILED_UPWIND_IN_SECONDS);
+ allowed.add(TOTAL_TIME_SAILED_REACHING_IN_SECONDS);
+ allowed.add(TOTAL_TIME_SAILED_DOWNWIND_IN_SECONDS);
+ return allowed;
}
- public static List getOverallBravoDetailTypes() {
- return Arrays.asList(new DetailType[] { DetailType.OVERALL_TOTAL_DISTANCE_FOILED_IN_METERS,
- OVERALL_TOTAL_DURATION_FOILED_IN_SECONDS });
+ public static Collection getOverallBravoDetailTypes() {
+ final Collection allowed = new LinkedHashSet<>();
+ allowed.add(OVERALL_TOTAL_DISTANCE_FOILED_IN_METERS);
+ allowed.add(OVERALL_TOTAL_DURATION_FOILED_IN_SECONDS);
+ return allowed;
}
- public static List getLegDetailColumnTypes() {
- return Arrays.asList(new DetailType[] { DetailType.LEG_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS,
- DetailType.LEG_DISTANCE_TRAVELED, DetailType.LEG_DISTANCE_TRAVELED_INCLUDING_GATE_START,
- DetailType.LEG_GAP_TO_LEADER_IN_SECONDS, DetailType.LEG_GAP_CHANGE_SINCE_LEG_START_IN_SECONDS,
- DetailType.LEG_SIDE_TO_WHICH_MARK_AT_LEG_START_WAS_ROUNDED,
- DetailType.LEG_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, DetailType.LEG_WINDWARD_DISTANCE_TO_GO_IN_METERS,
- DetailType.NUMBER_OF_MANEUVERS, DetailType.LEG_ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS,
- DetailType.LEG_VELOCITY_MADE_GOOD_IN_KNOTS, DetailType.LEG_TIME_TRAVELED,
- DetailType.LEG_CORRECTED_TIME_TRAVELED, DetailType.LEG_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS,
- DetailType.LEG_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS, DetailType.LEG_RANK_GAIN });
+ public static Collection getLegDetailColumnTypes() {
+ final Collection allowed = new LinkedHashSet<>();
+ allowed.add(LEG_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS);
+ allowed.add(LEG_DISTANCE_TRAVELED);
+ allowed.add(LEG_DISTANCE_TRAVELED_INCLUDING_GATE_START);
+ allowed.add(LEG_GAP_TO_LEADER_IN_SECONDS);
+ allowed.add(LEG_GAP_CHANGE_SINCE_LEG_START_IN_SECONDS);
+ allowed.add(LEG_SIDE_TO_WHICH_MARK_AT_LEG_START_WAS_ROUNDED);
+ allowed.add(LEG_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
+ allowed.add(LEG_WINDWARD_DISTANCE_TO_GO_IN_METERS);
+ allowed.add(NUMBER_OF_MANEUVERS);
+ allowed.add(LEG_ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS);
+ allowed.add(LEG_VELOCITY_MADE_GOOD_IN_KNOTS);
+ allowed.add(LEG_TIME_TRAVELED);
+ allowed.add(LEG_CORRECTED_TIME_TRAVELED);
+ allowed.add(LEG_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS);
+ allowed.add(LEG_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS);
+ allowed.add(LEG_RANK_GAIN);
+ return allowed;
}
- public static List getRaceStartAnalysisColumnTypes() {
- return Arrays.asList(new DetailType[] { DetailType.RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START,
- DetailType.RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START, DetailType.DISTANCE_TO_START_AT_RACE_START,
- DetailType.TIME_BETWEEN_RACE_START_AND_COMPETITOR_START, DetailType.SPEED_OVER_GROUND_AT_RACE_START,
- DetailType.SPEED_OVER_GROUND_WHEN_PASSING_START,
- DetailType.DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_PASSING_START_IN_METERS,
- DetailType.START_TACK });
+ public static Collection getRaceStartAnalysisColumnTypes() {
+ final Collection allowed = new LinkedHashSet<>();
+ allowed.add(RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START);
+ allowed.add(RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START);
+ allowed.add(DISTANCE_TO_START_AT_RACE_START);
+ allowed.add(TIME_BETWEEN_RACE_START_AND_COMPETITOR_START);
+ allowed.add(SPEED_OVER_GROUND_AT_RACE_START);
+ allowed.add(SPEED_OVER_GROUND_WHEN_PASSING_START);
+ allowed.add(DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_PASSING_START_IN_METERS);
+ allowed.add(START_TACK);
+ return allowed;
}
- public static List getLegExpeditionDetailColumnTypes() {
- return Arrays.asList(new DetailType[] { EXPEDITION_LEG_AWA, EXPEDITION_LEG_AWS, EXPEDITION_LEG_TWA,
- EXPEDITION_LEG_TWS, EXPEDITION_LEG_TWD, EXPEDITION_LEG_TARG_TWA, EXPEDITION_LEG_BOAT_SPEED,
- EXPEDITION_LEG_TARG_BOAT_SPEED, EXPEDITION_LEG_SOG, EXPEDITION_LEG_COG, EXPEDITION_LEG_FORESTAY_LOAD,
- EXPEDITION_LEG_RAKE, EXPEDITION_LEG_COURSE, EXPEDITION_LEG_HEADING, EXPEDITION_LEG_VMG,
- EXPEDITION_LEG_VMG_TARG_VMG_DELTA, EXPEDITION_LEG_RATE_OF_TURN, EXPEDITION_LEG_RUDDER_ANGLE,
- EXPEDITION_LEG_TARGET_HEEL, EXPEDITION_LEG_TIME_TO_PORT_LAYLINE,
- EXPEDITION_LEG_TIME_TO_STB_LAYLINE, EXPEDITION_LEG_DIST_TO_PORT_LAYLINE,
- EXPEDITION_LEG_DIST_TO_STB_LAYLINE, EXPEDITION_LEG_TIME_TO_GUN, EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT,
- EXPEDITION_LEG_TIME_TO_PIN, EXPEDITION_LEG_TIME_TO_BURN_TO_LINE,
- EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT, EXPEDITION_LEG_TIME_TO_BURN_TO_PIN,
- EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT, EXPEDITION_LEG_DISTANCE_TO_PIN,
- EXPEDITION_LEG_DISTANCE_BELOW_LINE, EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION, EXPEDITION_LEG_BARO,
- EXPEDITION_LEG_LOAD_S, EXPEDITION_LEG_LOAD_P, EXPEDITION_LEG_JIB_CAR_PORT, EXPEDITION_LEG_JIB_CAR_STBD,
- EXPEDITION_LEG_MAST_BUTT });
+ public static Collection getLegExpeditionDetailColumnTypes() {
+ final Collection allowed = new LinkedHashSet<>();
+ allowed.add(EXPEDITION_LEG_AWA);
+ allowed.add(EXPEDITION_LEG_AWS);
+ allowed.add(EXPEDITION_LEG_TWA);
+ allowed.add(EXPEDITION_LEG_TWS);
+ allowed.add(EXPEDITION_LEG_TWD);
+ allowed.add(EXPEDITION_LEG_TARG_TWA);
+ allowed.add(EXPEDITION_LEG_BOAT_SPEED);
+ allowed.add(EXPEDITION_LEG_TARG_BOAT_SPEED);
+ allowed.add(EXPEDITION_LEG_SOG);
+ allowed.add(EXPEDITION_LEG_COG);
+ allowed.add(EXPEDITION_LEG_FORESTAY_LOAD);
+ allowed.add(EXPEDITION_LEG_RAKE);
+ allowed.add(EXPEDITION_LEG_COURSE);
+ allowed.add(EXPEDITION_LEG_HEADING);
+ allowed.add(EXPEDITION_LEG_VMG);
+ allowed.add(EXPEDITION_LEG_VMG_TARG_VMG_DELTA);
+ allowed.add(EXPEDITION_LEG_RATE_OF_TURN);
+ allowed.add(EXPEDITION_LEG_RUDDER_ANGLE);
+ allowed.add(EXPEDITION_LEG_TARGET_HEEL);
+ allowed.add(EXPEDITION_LEG_TIME_TO_PORT_LAYLINE);
+ allowed.add(EXPEDITION_LEG_TIME_TO_STB_LAYLINE);
+ allowed.add(EXPEDITION_LEG_DIST_TO_PORT_LAYLINE);
+ allowed.add(EXPEDITION_LEG_DIST_TO_STB_LAYLINE);
+ allowed.add(EXPEDITION_LEG_TIME_TO_GUN);
+ allowed.add(EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT);
+ allowed.add(EXPEDITION_LEG_TIME_TO_PIN);
+ allowed.add(EXPEDITION_LEG_TIME_TO_BURN_TO_LINE);
+ allowed.add(EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT);
+ allowed.add(EXPEDITION_LEG_TIME_TO_BURN_TO_PIN);
+ allowed.add(EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT);
+ allowed.add(EXPEDITION_LEG_DISTANCE_TO_PIN);
+ allowed.add(EXPEDITION_LEG_DISTANCE_BELOW_LINE);
+ allowed.add(EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION);
+ allowed.add(EXPEDITION_LEG_BARO);
+ allowed.add(EXPEDITION_LEG_LOAD_S);
+ allowed.add(EXPEDITION_LEG_LOAD_P);
+ allowed.add(EXPEDITION_LEG_JIB_CAR_PORT);
+ allowed.add(EXPEDITION_LEG_JIB_CAR_STBD);
+ allowed.add(EXPEDITION_LEG_MAST_BUTT);
+ return allowed;
}
/**
* Not yet implemented types can be added here, they will be hidden from any user under all circumstances
*/
- public static List getDisabledDetailColumTypes() {
- return Arrays.asList(new DetailType[] { EXPEDITION_LEG_TARG_TWA, EXPEDITION_LEG_VMG,
- EXPEDITION_LEG_VMG_TARG_VMG_DELTA, EXPEDITION_LEG_RATE_OF_TURN, EXPEDITION_LEG_RUDDER_ANGLE,
- EXPEDITION_LEG_TIME_TO_PORT_LAYLINE, EXPEDITION_LEG_TIME_TO_STB_LAYLINE,
- EXPEDITION_LEG_DIST_TO_PORT_LAYLINE, EXPEDITION_LEG_DIST_TO_STB_LAYLINE,
- EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT, EXPEDITION_LEG_TIME_TO_PIN, EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT,
- EXPEDITION_LEG_TIME_TO_BURN_TO_PIN, EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT,
- EXPEDITION_LEG_DISTANCE_TO_PIN, EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION, EXPEDITION_RACE_TARG_TWA,
- EXPEDITION_RACE_VMG, EXPEDITION_RACE_VMG_TARG_VMG_DELTA,
- EXPEDITION_RACE_RUDDER_ANGLE, EXPEDITION_RACE_TIME_TO_PORT_LAYLINE, EXPEDITION_RACE_TIME_TO_STB_LAYLINE,
- EXPEDITION_RACE_DIST_TO_PORT_LAYLINE, EXPEDITION_RACE_DIST_TO_STB_LAYLINE,
- EXPEDITION_RACE_TIME_TO_COMMITTEE_BOAT, EXPEDITION_RACE_TIME_TO_PIN,
- EXPEDITION_RACE_TIME_TO_BURN_TO_PIN, EXPEDITION_RACE_TIME_TO_BURN_TO_COMMITTEE_BOAT,
- EXPEDITION_RACE_DISTANCE_TO_COMMITTEE_BOAT, EXPEDITION_RACE_DISTANCE_TO_PIN,
- EXPEDITION_RACE_LINE_SQUARE_FOR_WIND_DIRECTION });
+ public static Collection getDisabledDetailColumTypes() {
+ final Collection disabled = new LinkedHashSet<>();
+ disabled.add(EXPEDITION_LEG_TARG_TWA);
+ disabled.add(EXPEDITION_LEG_VMG);
+ disabled.add(EXPEDITION_LEG_VMG_TARG_VMG_DELTA);
+ disabled.add(EXPEDITION_LEG_RATE_OF_TURN);
+ disabled.add(EXPEDITION_LEG_RUDDER_ANGLE);
+ disabled.add(EXPEDITION_LEG_TIME_TO_PORT_LAYLINE);
+ disabled.add(EXPEDITION_LEG_TIME_TO_STB_LAYLINE);
+ disabled.add(EXPEDITION_LEG_DIST_TO_PORT_LAYLINE);
+ disabled.add(EXPEDITION_LEG_DIST_TO_STB_LAYLINE);
+ disabled.add(EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT);
+ disabled.add(EXPEDITION_LEG_TIME_TO_PIN);
+ disabled.add(EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT);
+ disabled.add(EXPEDITION_LEG_TIME_TO_BURN_TO_PIN);
+ disabled.add(EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT);
+ disabled.add(EXPEDITION_LEG_DISTANCE_TO_PIN);
+ disabled.add(EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION);
+ disabled.add(EXPEDITION_RACE_TARG_TWA);
+ disabled.add(EXPEDITION_RACE_VMG);
+ disabled.add(EXPEDITION_RACE_VMG_TARG_VMG_DELTA);
+ disabled.add(EXPEDITION_RACE_RUDDER_ANGLE);
+ disabled.add(EXPEDITION_RACE_TIME_TO_PORT_LAYLINE);
+ disabled.add(EXPEDITION_RACE_TIME_TO_STB_LAYLINE);
+ disabled.add(EXPEDITION_RACE_DIST_TO_PORT_LAYLINE);
+ disabled.add(EXPEDITION_RACE_DIST_TO_STB_LAYLINE);
+ disabled.add(EXPEDITION_RACE_TIME_TO_COMMITTEE_BOAT);
+ disabled.add(EXPEDITION_RACE_TIME_TO_PIN);
+ disabled.add(EXPEDITION_RACE_TIME_TO_BURN_TO_PIN);
+ disabled.add(EXPEDITION_RACE_TIME_TO_BURN_TO_COMMITTEE_BOAT);
+ disabled.add(EXPEDITION_RACE_DISTANCE_TO_COMMITTEE_BOAT);
+ disabled.add(EXPEDITION_RACE_DISTANCE_TO_PIN);
+ disabled.add(EXPEDITION_RACE_LINE_SQUARE_FOR_WIND_DIRECTION);
+ return disabled;
}
- public static List getAllLegDetailColumnTypes() {
- ArrayList all = new ArrayList<>();
+ public static Collection getAllLegDetailColumnTypes() {
+ final Collection all = new LinkedHashSet<>();
all.addAll(getLegDetailColumnTypes());
all.addAll(getLegBravoDetailTypes());
- all.addAll(getLegExtendedBravoDetailTypes());
all.addAll(getLegExpeditionDetailColumnTypes());
return all;
}
@@ -498,11 +560,10 @@ public enum DetailType implements Serializable {
return t;
}
}
-
}
}
}
throw new IllegalArgumentException("Could not restore " + value + " to an DetailType enum");
}
-}
\ No newline at end of file
+}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sharding/ShardingType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sharding/ShardingType.java
new file mode 100644
index 00000000000..1ed04cadfaa
--- /dev/null
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sharding/ShardingType.java
@@ -0,0 +1,61 @@
+package com.sap.sailing.domain.common.sharding;
+
+/**
+ * Enum that defines all sharding types known by the system.
+ *
+ * For a sharding to work, we need both client and backend properly identifying a shard.
+ *
+ * While the client has to properly deliver sharding information on each request, the server side
+ * infrastructure must be able to identify the information and properly route the requests.
+ *
+ * The current implementation uses a SUFFIX appended the GWT RPC URLs (allowing path based routing), so that each call to the server
+ * propagates the sharding information through the url.
+ *
+ * A load balancer can be used to properly route each request to the corresponding server node. The first
+ * sharding implemented is the sharding by leaderboard name.
+ *
+ * The suffix appended to the request URL consists of two parts: a prefix that is used to identify the type of shard
+ * and a payload that will be used to identify the shard.
+ *
+ *
+ */
+public enum ShardingType {
+ LEADERBOARDNAME("/leaderboard/");
+
+ private String prefix;
+
+ private ShardingType(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public String encodeIfNeeded(String shardingInfo) {
+ if (shardingInfo.startsWith(prefix)) {
+ return shardingInfo;
+ }
+ return new StringBuilder().append(prefix)
+ .append(normalize(shardingInfo))
+ .toString();
+ }
+
+ private String normalize(String replace) {
+ char[] chars = replace.toCharArray();
+ StringBuilder answer = new StringBuilder();
+ for(int i = 0;i 47 && c < 58) { // digits
+ answer.append(c);
+ } else if (c > 64 && c < 91) { // uppercase letters
+ answer.append(c);
+ } else if (c > 69 && c < 123) { // lowercase letters
+ answer.append(c);
+ } else {
+ answer.append("_");
+ }
+ }
+ return answer.toString();
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+}
\ No newline at end of file
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/RegattaConfiguration.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/RegattaConfiguration.java
index 1828d8c0ef1..2819e8ee4e3 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/RegattaConfiguration.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/RegattaConfiguration.java
@@ -10,6 +10,7 @@ import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration;
import com.sap.sailing.domain.base.configuration.procedures.SWCStartConfiguration;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
+import com.sap.sse.common.Duration;
/**
* Interface holding configuration options for a Regatta, including configurations for
@@ -26,6 +27,12 @@ public interface RegattaConfiguration extends Serializable, Cloneable {
* Gets the default {@link RacingProcedureType} for races configured.
*/
RacingProcedureType getDefaultRacingProcedureType();
+
+ /**
+ * Gets the default protest time duration. May be {@code null} in case no default is set for the
+ * regatta.
+ */
+ Duration getDefaultProtestTimeDuration();
/**
* Gets the configuration for RRS26 races.
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/EmptyRegattaConfiguration.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/EmptyRegattaConfiguration.java
index 4b39cbeed7f..0363327b55b 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/EmptyRegattaConfiguration.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/EmptyRegattaConfiguration.java
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.configuration.ConfigurationLoader;
import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
+import com.sap.sse.common.Duration;
/**
* Is empty, does nothing on store and load.
@@ -17,6 +18,7 @@ public class EmptyRegattaConfiguration extends RegattaConfigurationImpl implemen
public RegattaConfiguration load() {
setDefaultRacingProcedureType(RacingProcedureType.UNKNOWN);
setDefaultCourseDesignerMode(CourseDesignerMode.UNKNOWN);
+ setDefaultProtestTimeDuration(Duration.ONE_MINUTE.times(90));
setRRS26Configuration(new RRS26ConfigurationImpl());
setSWCStartConfiguration(new SWCStartConfigurationImpl());
setGateStartConfiguration(new GateStartConfigurationImpl());
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/RegattaConfigurationImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/RegattaConfigurationImpl.java
index 5810aa96e41..55c1f89b320 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/RegattaConfigurationImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/RegattaConfigurationImpl.java
@@ -9,6 +9,7 @@ import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration;
import com.sap.sailing.domain.base.configuration.procedures.SWCStartConfiguration;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
+import com.sap.sse.common.Duration;
public class RegattaConfigurationImpl implements RegattaConfiguration {
@@ -16,6 +17,7 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
private RacingProcedureType defaultRacingProcedureType;
private CourseDesignerMode defaultCourseDesignerMode;
+ private Duration defaultProtestTimeDuration;
private RRS26Configuration rrs26Configuration;
private SWCStartConfiguration swcStartConfiguration;
@@ -42,6 +44,15 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
defaultCourseDesignerMode = mode;
}
+ @Override
+ public Duration getDefaultProtestTimeDuration() {
+ return defaultProtestTimeDuration;
+ }
+
+ public void setDefaultProtestTimeDuration(Duration defaultProtestTimeDuration) {
+ this.defaultProtestTimeDuration = defaultProtestTimeDuration;
+ }
+
@Override
public RRS26Configuration getRRS26Configuration() {
return rrs26Configuration;
@@ -101,6 +112,7 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
RegattaConfigurationImpl copy = new RegattaConfigurationImpl();
copy.setDefaultRacingProcedureType(defaultRacingProcedureType);
copy.setDefaultCourseDesignerMode(defaultCourseDesignerMode);
+ copy.setDefaultProtestTimeDuration(defaultProtestTimeDuration);
copy.setRRS26Configuration(rrs26Configuration);
copy.setSWCStartConfiguration(swcStartConfiguration);
copy.setGateStartConfiguration(gateStartConfiguration);
@@ -120,6 +132,9 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
if (update.getDefaultRacingProcedureType() != null) {
target.setDefaultRacingProcedureType(update.getDefaultRacingProcedureType());
}
+ if (update.getDefaultProtestTimeDuration() != null) {
+ target.setDefaultProtestTimeDuration(update.getDefaultProtestTimeDuration());
+ }
if (update.getRRS26Configuration() != null) {
target.setRRS26Configuration(
(RRS26Configuration) target.getRRS26Configuration().merge(update.getRRS26Configuration()));
diff --git a/java/com.sap.sailing.domain/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain/META-INF/MANIFEST.MF
index 5567e3bc181..6f6d9a68bbe 100755
--- a/java/com.sap.sailing.domain/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.domain/META-INF/MANIFEST.MF
@@ -31,6 +31,7 @@ Export-Package: com.sap.sailing.domain.base,
com.sap.sailing.domain.trackimport,
com.sap.sailing.domain.tracking,
com.sap.sailing.domain.tracking.impl,
+ com.sap.sailing.domain.sharding,
com.sap.sailing.domain.windfinder,
com.sap.sailing.util,
com.sap.sailing.util.impl;x-friends:="com.sap.sailing.server.replication,com.sap.sailing.domain.test"
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java
index ed3880b105b..ec56da0c10f 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java
@@ -12,7 +12,9 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
+import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.leaderboard.Leaderboard;
+import com.sap.sailing.domain.sharding.ShardingContext;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -274,6 +276,7 @@ public class LiveLeaderboardUpdater implements Runnable {
public void run() {
assert running;
try {
+ ShardingContext.setShardingConstraint(ShardingType.LEADERBOARDNAME, leaderboard.getName());
logger.info("Starting " + LiveLeaderboardUpdater.class.getSimpleName() + " thread for leaderboard "
+ leaderboard.getName());
// interrupt the current thread if not producing a single result within the overall timeout
@@ -326,6 +329,8 @@ public class LiveLeaderboardUpdater implements Runnable {
notifyAll();
}
logger.log(Level.SEVERE, "exception updating live leaderboard "+leaderboard.getName(), e);
+ } finally {
+ ShardingContext.clearShardingConstraint(ShardingType.LEADERBOARDNAME);
}
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java
index e3bd3246dff..bf8bbf41983 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java
@@ -55,6 +55,7 @@ import com.sap.sailing.domain.common.dto.LegEntryDTO;
import com.sap.sailing.domain.common.dto.MetaLeaderboardRaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceDTO;
+import com.sap.sailing.domain.common.sharding.ShardingType;
import com.sap.sailing.domain.common.tracking.BravoExtendedFix;
import com.sap.sailing.domain.common.tracking.BravoFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
@@ -68,6 +69,7 @@ import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.ranking.RankingMetric.CompetitorRankingInfo;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
+import com.sap.sailing.domain.sharding.ShardingContext;
import com.sap.sailing.domain.tracking.BravoFixTrack;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.Maneuver;
@@ -355,6 +357,7 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard {
final boolean waitForLatestAnalyses, TrackedRegattaRegistry trackedRegattaRegistry, final DomainFactory baseDomainFactory,
final boolean fillTotalPointsUncorrected)
throws NoWindException {
+ ShardingContext.checkConstraint(ShardingType.LEADERBOARDNAME, getName());
long startOfRequestHandling = System.currentTimeMillis();
final LeaderboardDTOCalculationReuseCache cache = new LeaderboardDTOCalculationReuseCache(timePoint);
final BoatClass boatClass = getBoatClass();
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 808d4bca7b5..d9577814e88 100644
--- 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
@@ -52,16 +52,17 @@ import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
/**
* Base implementation for various types of leaderboards. The {@link RaceColumnListener} implementation forwards events
- * received to all {@link RaceColumnListener} subscribed with this leaderboard. To which objects this leaderboard subscribes
- * as {@link RaceColumnListener} is left to the concrete subclasses to implement, but the race columns seem like useful
- * candidates.
+ * received to all {@link RaceColumnListener} subscribed with this leaderboard. To which objects this leaderboard
+ * subscribes as {@link RaceColumnListener} is left to the concrete subclasses to implement, but the race columns seem
+ * like useful candidates.
*
* @author Axel Uhl (d043530)
*
*/
-public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardWithCache implements Leaderboard, RaceColumnListener {
+public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardWithCache
+ implements Leaderboard, RaceColumnListener {
private static final long serialVersionUID = 330156778603279333L;
-
+
static final Double DOUBLE_0 = new Double(0);
private final SettableScoreCorrection scoreCorrection;
@@ -75,15 +76,15 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
private final Map displayNames;
/**
- * Backs the {@link #getCarriedPoints(Competitor)} API with data. Can be used to prime this leaderboard
- * with aggregated results of races not tracked / displayed by this leaderboard in detail. The points
- * provided by this map are considered by {@link #getNetPoints(Competitor, TimePoint)}.
+ * Backs the {@link #getCarriedPoints(Competitor)} API with data. Can be used to prime this leaderboard with
+ * aggregated results of races not tracked / displayed by this leaderboard in detail. The points provided by this
+ * map are considered by {@link #getNetPoints(Competitor, TimePoint)}.
*/
private final Map carriedPoints;
/**
- * A set that manages the difference between {@link #getCompetitors()} and {@link #getAllCompetitors()}. Access
- * is controlled by the {@link #suppressedCompetitorsLock} lock.
+ * A set that manages the difference between {@link #getCompetitors()} and {@link #getAllCompetitors()}. Access is
+ * controlled by the {@link #suppressedCompetitorsLock} lock.
*/
private final Set suppressedCompetitors;
private final NamedReentrantReadWriteLock suppressedCompetitorsLock;
@@ -107,8 +108,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
private final Fleet fleet;
private EntryImpl(Callable trackedRankProvider, Double totalPoints,
- Callable totalPointsUncorrectedProvider, boolean isTotalPointsCorrected,
- Double netPoints, MaxPointsReason maxPointsReason, boolean discarded, Fleet fleet) {
+ Callable totalPointsUncorrectedProvider, boolean isTotalPointsCorrected, Double netPoints,
+ MaxPointsReason maxPointsReason, boolean discarded, Fleet fleet) {
super();
this.trackedRankProvider = trackedRankProvider;
this.totalPoints = totalPoints;
@@ -119,6 +120,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
this.discarded = discarded;
this.fleet = fleet;
}
+
@Override
public int getTrackedRank() {
try {
@@ -127,30 +129,37 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
throw new RuntimeException(e);
}
}
+
@Override
public Double getTotalPoints() {
return totalPoints;
}
+
@Override
public boolean isTotalPointsCorrected() {
return isTotalPointsCorrected;
}
+
@Override
public Double getNetPoints() {
return netPoints;
}
+
@Override
public MaxPointsReason getMaxPointsReason() {
return maxPointsReason;
}
+
@Override
public boolean isDiscarded() {
return discarded;
}
+
@Override
public Fleet getFleet() {
return fleet;
}
+
@Override
public Double getTotalPointsUncorrected() {
try {
@@ -160,7 +169,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
}
}
-
+
/**
* Computing the competitors can be a bit expensive, particularly if the fleet is large and there may be suppressed
* competitors, and the leaderboard may be a meta-leaderboard that refers to other leaderboards which each have
@@ -171,10 +180,10 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
*
* As it turns out, one of the most frequent uses of the {@link AbstractSimpleLeaderboardImpl#getCompetitors}
* competitors list is to determine their number which in turn is only required for high-point scoring systems and
- * for computing the default score for penalties. Again, the most frequently used low-point family of scoring schemes
- * does not require this number. Yet, the scoring scheme requires an argument for polymorphic use by those that
- * need it. Instead of computing it for each call, this interface lets us defer the actual calculation until the
- * point when it's really needed. Once asked, this object will cache the result. Therefore, a new one should be
+ * for computing the default score for penalties. Again, the most frequently used low-point family of scoring
+ * schemes does not require this number. Yet, the scoring scheme requires an argument for polymorphic use by those
+ * that need it. Instead of computing it for each call, this interface lets us defer the actual calculation until
+ * the point when it's really needed. Once asked, this object will cache the result. Therefore, a new one should be
* constructed each time the number shall be computed.
*
* @author Axel Uhl (D043530)
@@ -183,7 +192,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public class NumberOfCompetitorsFetcherImpl implements NumberOfCompetitorsInLeaderboardFetcher {
private int numberOfCompetitors = -1;
private int numberOfCompetitorsWithoutMaxPointReason = -1;
-
+
@Override
public int getNumberOfCompetitorsInLeaderboard() {
if (numberOfCompetitors == -1) {
@@ -191,7 +200,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
return numberOfCompetitors;
}
-
+
@Override
public int getNumberOfCompetitorsWithoutMaxPointReason(RaceColumn column, TimePoint timePoint) {
if (numberOfCompetitorsWithoutMaxPointReason == -1) {
@@ -215,17 +224,17 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
this.suppressedCompetitors = new HashSet();
this.suppressedCompetitorsLock = new NamedReentrantReadWriteLock("suppressedCompetitorsLock", /* fair */ false);
}
-
+
protected RaceColumnListeners getRaceColumnListeners() {
return raceColumnListeners;
}
-
+
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
super.trackedRaceUnlinked(raceColumn, fleet, trackedRace);
}
-
+
@Override
public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
getRaceColumnListeners().notifyListenersAboutTrackedRaceLinked(raceColumn, fleet, trackedRace);
@@ -235,10 +244,11 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public void isMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) {
getRaceColumnListeners().notifyListenersAboutIsMedalRaceChanged(raceColumn, newIsMedalRace);
}
-
+
@Override
public void isFleetsCanRunInParallelChanged(RaceColumn raceColumn, boolean newIsFleetsCanRunInParallel) {
- getRaceColumnListeners().notifyListenersAboutIsFleetsCanRunInParallelChanged(raceColumn, newIsFleetsCanRunInParallel);
+ getRaceColumnListeners().notifyListenersAboutIsFleetsCanRunInParallelChanged(raceColumn,
+ newIsFleetsCanRunInParallel);
}
@Override
@@ -247,13 +257,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
- public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) {
- getRaceColumnListeners().notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn, firstColumnIsNonDiscardableCarryForward);
+ public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn,
+ boolean firstColumnIsNonDiscardableCarryForward) {
+ getRaceColumnListeners().notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn,
+ firstColumnIsNonDiscardableCarryForward);
}
@Override
public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) {
- getRaceColumnListeners().notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn, hasSplitFleetContiguousScoring);
+ getRaceColumnListeners().notifyListenersAboutHasSplitFleetContiguousScoringChanged(raceColumn,
+ hasSplitFleetContiguousScoring);
}
@Override
@@ -283,11 +296,13 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
@Override
public void competitorDisplayNameChanged(Competitor competitor, String oldDisplayName, String displayName) {
- getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName, displayName);
+ getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName,
+ displayName);
}
@Override
- public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule, ResultDiscardingRule newDiscardingRule) {
+ public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule,
+ ResultDiscardingRule newDiscardingRule) {
getRaceColumnListeners().notifyListenersAboutResultDiscardingRuleChanged(oldDiscardingRule, newDiscardingRule);
}
@@ -304,7 +319,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
protected SettableScoreCorrection createScoreCorrection() {
return new ScoreCorrectionImpl(this);
}
-
+
@Override
public SettableScoreCorrection getScoreCorrection() {
return scoreCorrection;
@@ -372,7 +387,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
String oldDisplayName = displayNames.get(competitor);
displayNames.put(competitor, displayName);
if (!Util.equalsWithNull(oldDisplayName, displayName)) {
- getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName, displayName);
+ getRaceColumnListeners().notifyListenersAboutCompetitorDisplayNameChanged(competitor, oldDisplayName,
+ displayName);
}
}
@@ -385,9 +401,9 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
@Override
public Double getTotalPoints(final Competitor competitor, final RaceColumn raceColumn, final TimePoint timePoint) {
- return getScoreCorrection().getCorrectedScore(
- ()->getTrackedRank(competitor, raceColumn, timePoint), competitor,
- raceColumn, this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme()).getCorrectedScore();
+ return getScoreCorrection().getCorrectedScore(() -> getTrackedRank(competitor, raceColumn, timePoint),
+ competitor, raceColumn, this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme())
+ .getCorrectedScore();
}
@Override
@@ -399,19 +415,19 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public boolean isDiscarded(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
return isDiscarded(competitor, raceColumn, getRaceColumns(), timePoint);
}
-
+
private boolean isDiscarded(Competitor competitor, RaceColumn raceColumn,
Iterable raceColumnsToConsider, TimePoint timePoint) {
- final Set discardedRaceColumns = getResultDiscardingRule()
- .getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint);
+ final Set discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
+ raceColumnsToConsider, timePoint);
return isDiscarded(competitor, raceColumn, timePoint, discardedRaceColumns);
}
/**
* Same as {@link #isDiscarded(Competitor, RaceColumn, TimePoint)}, only that the set of discarded race columns can
- * be specified which is useful when net points are to be computed for more than one column for the same
- * competitor because then the calculation of discards (which requires looking at all columns) only needs to be done
- * once and not again for each column (which would lead to quadratic effort).
+ * be specified which is useful when net points are to be computed for more than one column for the same competitor
+ * because then the calculation of discards (which requires looking at all columns) only needs to be done once and
+ * not again for each column (which would lead to quadratic effort).
*
* @param discardedRaceColumns
* expected to be the result of what we would get if we called {@link #getResultDiscardingRule()}.
@@ -420,8 +436,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
*/
private boolean isDiscarded(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint,
final Set discardedRaceColumns) {
- return !raceColumn.isMedalRace()
- && getMaxPointsReason(competitor, raceColumn, timePoint).isDiscardable()
+ return !raceColumn.isMedalRace() && getMaxPointsReason(competitor, raceColumn, timePoint).isDiscardable()
&& discardedRaceColumns.contains(raceColumn);
}
@@ -431,16 +446,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
- public Double getNetPoints(Competitor competitor, RaceColumn raceColumn,
- Iterable raceColumnsToConsider, TimePoint timePoint) {
- final Set discardedRaceColumns = getResultDiscardingRule()
- .getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint);
+ public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, Iterable raceColumnsToConsider,
+ TimePoint timePoint) {
+ final Set discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
+ raceColumnsToConsider, timePoint);
return getNetPoints(competitor, raceColumn, timePoint, discardedRaceColumns);
}
/**
- * Same as {@link #getNetPoints(Competitor, RaceColumn, Iterable, TimePoint)}, only that the set of discarded race columns can
- * be specified which is useful when net points are to be computed for more than one column for the same
+ * Same as {@link #getNetPoints(Competitor, RaceColumn, Iterable, TimePoint)}, only that the set of discarded race
+ * columns can be specified which is useful when net points are to be computed for more than one column for the same
* competitor because then the calculation of discards (which requires looking at all columns) only needs to be done
* once and not again for each column (which would lead to quadratic effort).
*
@@ -450,7 +465,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
* getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint)}.
*/
@Override
- public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint, Set discardedRaceColumns) {
+ public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint,
+ Set discardedRaceColumns) {
Double result;
if (isDiscarded(competitor, raceColumn, timePoint, discardedRaceColumns)) {
result = 0.0;
@@ -473,11 +489,12 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
@Override
public Double getNetPoints(Competitor competitor, final Iterable raceColumnsToConsider,
TimePoint timePoint) {
- // when a column with isStartsWithZeroScore() is found, only reset score if the competitor scored in any race from there on
+ // when a column with isStartsWithZeroScore() is found, only reset score if the competitor scored in any race
+ // from there on
boolean needToResetScoreUponNextNonEmptyEntry = false;
double result = getCarriedPoints(competitor);
- final Set discardedRaceColumns = getResultDiscardingRule()
- .getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint);
+ final Set discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
+ raceColumnsToConsider, timePoint);
for (RaceColumn raceColumn : raceColumnsToConsider) {
if (raceColumn.isStartsWithZeroScore()) {
needToResetScoreUponNextNonEmptyEntry = true;
@@ -497,16 +514,19 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
/**
- * All competitors with non-null total points are added to the result which is then sorted by total points in ascending
- * order. The fleet, if ordered, is the primary ordering criterion, followed by the total points.
+ * All competitors with non-null total points are added to the result which is then sorted by total
+ * points in ascending order. The fleet, if ordered, is the primary ordering criterion, followed by the total
+ * points.
*/
@Override
- public List getCompetitorsFromBestToWorst(final RaceColumn raceColumn, TimePoint timePoint) throws NoWindException {
+ public List getCompetitorsFromBestToWorst(final RaceColumn raceColumn, TimePoint timePoint)
+ throws NoWindException {
final Map> totalPointsAndFleet = new HashMap>();
for (Competitor competitor : getCompetitors()) {
Double totalPoints = getTotalPoints(competitor, raceColumn, timePoint);
if (totalPoints != null) {
- totalPointsAndFleet.put(competitor, new com.sap.sse.common.Util.Pair(totalPoints, raceColumn.getFleetOfCompetitor(competitor)));
+ totalPointsAndFleet.put(competitor, new com.sap.sse.common.Util.Pair(totalPoints,
+ raceColumn.getFleetOfCompetitor(competitor)));
}
}
List result = new ArrayList(totalPointsAndFleet.keySet());
@@ -518,7 +538,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
comparisonResult = 0;
} else {
if (raceColumn.hasSplitFleets() && !raceColumn.hasSplitFleetContiguousScoring()) {
- // only check fleets if there are more than one and the column is not to be contiguously scored even in case
+ // only check fleets if there are more than one and the column is not to be contiguously scored
+ // even in case
// of split fleets
final Fleet o1Fleet = totalPointsAndFleet.get(o1).getB();
final Fleet o2Fleet = totalPointsAndFleet.get(o2).getB();
@@ -537,13 +558,14 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
}
} else {
- // either there are no split fleets or the split isn't relevant for scoring as for ordered fleets
+ // either there are no split fleets or the split isn't relevant for scoring as for ordered
+ // fleets
// the scoring runs contiguously from top to bottom
comparisonResult = 0;
}
if (comparisonResult == 0) {
- comparisonResult = getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false).compare(
- totalPointsAndFleet.get(o1).getA(), totalPointsAndFleet.get(o2).getA());
+ comparisonResult = getScoringScheme().getScoreComparator(/* nullScoresAreBetter */ false)
+ .compare(totalPointsAndFleet.get(o1).getA(), totalPointsAndFleet.get(o2).getA());
}
}
return comparisonResult;
@@ -559,11 +581,12 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public List getCompetitorsFromBestToWorst(TimePoint timePoint) {
return getCompetitorsFromBestToWorst(getRaceColumns(), timePoint);
}
-
+
/**
* suppressed competitors are removed from the result
*/
- private List getCompetitorsFromBestToWorst(Iterable raceColumnsToConsider, TimePoint timePoint) {
+ private List getCompetitorsFromBestToWorst(Iterable raceColumnsToConsider,
+ TimePoint timePoint) {
List result = new ArrayList();
for (Competitor competitor : getCompetitors()) {
result.add(competitor);
@@ -571,9 +594,11 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
Collections.sort(result, getTotalRankComparator(raceColumnsToConsider, timePoint));
return result;
}
-
- protected Comparator super Competitor> getTotalRankComparator(Iterable raceColumnsToConsider, TimePoint timePoint) {
- return new LeaderboardTotalRankComparator(this, timePoint, getScoringScheme(), /* nullScoresAreBetter */ false, raceColumnsToConsider);
+
+ protected Comparator super Competitor> getTotalRankComparator(Iterable raceColumnsToConsider,
+ TimePoint timePoint) {
+ return new LeaderboardTotalRankComparator(this, timePoint, getScoringScheme(), /* nullScoresAreBetter */ false,
+ raceColumnsToConsider);
}
@Override
@@ -599,15 +624,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
- public boolean countRaceForComparisonWithDiscardingThresholds(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
+ public boolean countRaceForComparisonWithDiscardingThresholds(Competitor competitor, RaceColumn raceColumn,
+ TimePoint timePoint) {
TrackedRace trackedRaceForCompetitorInColumn;
- return getScoringScheme().isValidInNetScore(this, raceColumn, competitor, timePoint) &&
- (getScoreCorrection().isScoreCorrected(competitor, raceColumn, timePoint) ||
- ((trackedRaceForCompetitorInColumn=raceColumn.getTrackedRace(competitor)) != null &&
- trackedRaceForCompetitorInColumn.hasStarted(timePoint) &&
- trackedRaceForCompetitorInColumn.getRank(competitor, timePoint) != 0));
+ return getScoringScheme().isValidInNetScore(this, raceColumn, competitor, timePoint)
+ && (getScoreCorrection().isScoreCorrected(competitor, raceColumn, timePoint)
+ || ((trackedRaceForCompetitorInColumn = raceColumn.getTrackedRace(competitor)) != null
+ && trackedRaceForCompetitorInColumn.hasStarted(timePoint)
+ && trackedRaceForCompetitorInColumn.getRank(competitor, timePoint) != 0));
}
-
+
@Override
public void addRaceColumnListener(RaceColumnListener listener) {
getRaceColumnListeners().addRaceColumnListener(listener);
@@ -619,27 +645,31 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
- public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint) throws NoWindException {
- final Set discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this, getRaceColumns(), timePoint);
+ public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint)
+ throws NoWindException {
+ final Set discardedRaceColumns = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
+ getRaceColumns(), timePoint);
return getEntry(competitor, race, timePoint, discardedRaceColumns);
}
-
+
@Override
public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint,
Set discardedRaceColumns) throws NoWindException {
- Callable trackedRankProvider = ()->getTrackedRank(competitor, race, timePoint);
+ Callable trackedRankProvider = () -> getTrackedRank(competitor, race, timePoint);
final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor, race,
this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
boolean discarded = isDiscarded(competitor, race, timePoint, discardedRaceColumns);
final Double correctedScore = correctedResults.getCorrectedScore();
- return new EntryImpl(trackedRankProvider, correctedScore, ()->correctedResults.getUncorrectedScore(),
- correctedResults.isCorrected(), discarded ? DOUBLE_0 : correctedScore == null ? null
- : Double.valueOf(correctedScore * race.getFactor()), correctedResults.getMaxPointsReason(), discarded,
- race.getFleetOfCompetitor(competitor));
+ return new EntryImpl(trackedRankProvider, correctedScore, () -> correctedResults.getUncorrectedScore(),
+ correctedResults.isCorrected(),
+ discarded ? DOUBLE_0
+ : correctedScore == null ? null : Double.valueOf(correctedScore * race.getFactor()),
+ correctedResults.getMaxPointsReason(), discarded, race.getFleetOfCompetitor(competitor));
}
@Override
- public Map> getRankedCompetitorsFromBestToWorstAfterEachRaceColumn(TimePoint timePoint) throws NoWindException {
+ public Map> getRankedCompetitorsFromBestToWorstAfterEachRaceColumn(TimePoint timePoint)
+ throws NoWindException {
Map> result = new LinkedHashMap<>();
List raceColumnsToConsider = new ArrayList<>();
for (RaceColumn raceColumn : getRaceColumns()) {
@@ -663,7 +693,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public Map call() {
Map netPointsSumPerCompetitorInColumn = new HashMap<>();
for (Competitor competitor : getCompetitors()) {
- netPointsSumPerCompetitorInColumn.put(competitor, getNetPoints(competitor, finalRaceColumnsToConsider, timePoint));
+ netPointsSumPerCompetitorInColumn.put(competitor,
+ getNetPoints(competitor, finalRaceColumnsToConsider, timePoint));
}
synchronized (result) {
return netPointsSumPerCompetitorInColumn;
@@ -686,27 +717,29 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
@Override
- public Map, Entry> getContent(final TimePoint timePoint) throws NoWindException {
+ public Map, Entry> getContent(final TimePoint timePoint)
+ throws NoWindException {
Map, Entry> result = new HashMap, Entry>();
Map> discardedRaces = new HashMap>();
for (final RaceColumn raceColumn : getRaceColumns()) {
for (final Competitor competitor : getCompetitors()) {
- Callable trackedRankProvider = ()->getTrackedRank(competitor, raceColumn, timePoint);
- final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor, raceColumn,
- this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
+ Callable trackedRankProvider = () -> getTrackedRank(competitor, raceColumn, timePoint);
+ final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor,
+ raceColumn, this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
Set discardedRacesForCompetitor = discardedRaces.get(competitor);
if (discardedRacesForCompetitor == null) {
- discardedRacesForCompetitor = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this, getRaceColumns(), timePoint);
+ discardedRacesForCompetitor = getResultDiscardingRule().getDiscardedRaceColumns(competitor, this,
+ getRaceColumns(), timePoint);
discardedRaces.put(competitor, discardedRacesForCompetitor);
}
boolean discarded = discardedRacesForCompetitor.contains(raceColumn);
final Double correctedScore = correctedResults.getCorrectedScore();
Entry entry = new EntryImpl(trackedRankProvider, correctedScore,
- ()->correctedResults.getUncorrectedScore(),
- correctedResults.isCorrected(),
- discarded ? DOUBLE_0 : (correctedScore==null?null:
- Double.valueOf((correctedScore * raceColumn.getFactor()))), correctedResults.getMaxPointsReason(),
- discarded, raceColumn.getFleetOfCompetitor(competitor));
+ () -> correctedResults.getUncorrectedScore(), correctedResults.isCorrected(),
+ discarded ? DOUBLE_0
+ : (correctedScore == null ? null
+ : Double.valueOf((correctedScore * raceColumn.getFactor()))),
+ correctedResults.getMaxPointsReason(), discarded, raceColumn.getFleetOfCompetitor(competitor));
result.put(new com.sap.sse.common.Util.Pair(competitor, raceColumn), entry);
}
}
@@ -714,7 +747,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
/**
- * A leaderboard will only accept the addition of a race column if the column's name is unique across the leaderboard.
+ * A leaderboard will only accept the addition of a race column if the column's name is unique across the
+ * leaderboard.
*/
@Override
public boolean canAddRaceColumnToContainer(RaceColumn newRaceColumn) {
@@ -731,17 +765,18 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
/**
* Finds out the time point when any of the {@link Leaderboard#getTrackedRaces() tracked races currently attached to
* the leaderboard} and the {@link Leaderboard#getScoreCorrection() score corrections} have last been
- * modified. If no tracked race is attached and no time-stamped score corrections have been applied to the leaderboard,
- * null is returned. The time point computed this way is a good choice for normalizing queries for later time
- * points in an attempt to achieve more cache hits.
+ * modified. If no tracked race is attached and no time-stamped score corrections have been applied to the
+ * leaderboard, null is returned. The time point computed this way is a good choice for normalizing
+ * queries for later time points in an attempt to achieve more cache hits.
+ *
*
- * Note, however, that the result does not tell about structural changes to the leaderboard and therefore cannot be used
- * to determine the need for cache invalidation. For example, if a column is added to a leaderboard after the time point
- * returned by this method but that column's attached tracked race has finished before the time point returned by this method,
- * the result of this method won't change. Still, the contents of the leaderboard will change by a change in column structure.
- * A different means to determine the possibility of changes that happened to this leaderboard must be used for cache
- * management. Such a facility has to listen for score correction changes, tracked races being attached or detached and
- * the column structure changing.
+ * Note, however, that the result does not tell about structural changes to the leaderboard and therefore cannot be
+ * used to determine the need for cache invalidation. For example, if a column is added to a leaderboard after the
+ * time point returned by this method but that column's attached tracked race has finished before the time point
+ * returned by this method, the result of this method won't change. Still, the contents of the leaderboard will
+ * change by a change in column structure. A different means to determine the possibility of changes that happened
+ * to this leaderboard must be used for cache management. Such a facility has to listen for score correction
+ * changes, tracked races being attached or detached and the column structure changing.
*
* @see TrackedRace#getTimePointOfNewestEvent()
* @see SettableScoreCorrection#getTimePointOfLastCorrectionsValidity()
@@ -750,19 +785,22 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
public TimePoint getTimePointOfLatestModification() {
TimePoint result = null;
for (TrackedRace trackedRace : getTrackedRaces()) {
- if (result == null || (trackedRace.getTimePointOfNewestEvent() != null && trackedRace.getTimePointOfNewestEvent().after(result))) {
+ if (result == null || (trackedRace.getTimePointOfNewestEvent() != null
+ && trackedRace.getTimePointOfNewestEvent().after(result))) {
result = trackedRace.getTimePointOfNewestEvent();
}
}
TimePoint timePointOfLastScoreCorrection = getScoreCorrection().getTimePointOfLastCorrectionsValidity();
- if (timePointOfLastScoreCorrection != null && (result == null || timePointOfLastScoreCorrection.after(result))) {
+ if (timePointOfLastScoreCorrection != null
+ && (result == null || timePointOfLastScoreCorrection.after(result))) {
result = timePointOfLastScoreCorrection;
}
return result;
}
@Override
- public com.sap.sse.common.Util.Pair getMaximumSpeedOverGround(Competitor competitor, TimePoint timePoint) {
+ public com.sap.sse.common.Util.Pair getMaximumSpeedOverGround(Competitor competitor,
+ TimePoint timePoint) {
com.sap.sse.common.Util.Pair result = null;
// TODO should we ensure that competitor participated in all race columns?
for (TrackedRace trackedRace : getTrackedRaces()) {
@@ -771,16 +809,17 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
if (!markPassings.isEmpty()) {
TimePoint from = markPassings.first().getTimePoint();
TimePoint to;
- if (timePoint.after(markPassings.last().getTimePoint()) &&
- markPassings.last().getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint()) {
+ if (timePoint.after(markPassings.last().getTimePoint()) && markPassings.last()
+ .getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint()) {
// stop counting when competitor finished the race
to = markPassings.last().getTimePoint();
} else {
to = timePoint;
}
- com.sap.sse.common.Util.Pair maxSpeed = trackedRace.getTrack(competitor).getMaximumSpeedOverGround(from, to);
- if (result == null || result.getB() == null ||
- (maxSpeed != null && maxSpeed.getB() != null && maxSpeed.getB().compareTo(result.getB()) > 0)) {
+ com.sap.sse.common.Util.Pair maxSpeed = trackedRace.getTrack(competitor)
+ .getMaximumSpeedOverGround(from, to);
+ if (result == null || result.getB() == null || (maxSpeed != null && maxSpeed.getB() != null
+ && maxSpeed.getB().compareTo(result.getB()) > 0)) {
result = maxSpeed;
}
}
@@ -799,7 +838,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
return result;
}
-
+
@Override
public Iterable getCompetitors() {
final Iterable result;
@@ -815,10 +854,11 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
return result;
}
-
+
@Override
public Iterable getCompetitors(RaceColumn raceColumn, Fleet fleet) {
- return getCompetitorIterableSkippingSuppressed(getAllCompetitors(raceColumn, fleet), getSuppressedCompetitors());
+ return getCompetitorIterableSkippingSuppressed(getAllCompetitors(raceColumn, fleet),
+ getSuppressedCompetitors());
}
/**
@@ -838,7 +878,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
LockUtil.unlockAfterRead(suppressedCompetitorsLock);
}
}
-
+
@Override
public boolean isSuppressed(Competitor competitor) {
LockUtil.lockForRead(suppressedCompetitorsLock);
@@ -848,12 +888,12 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
LockUtil.unlockAfterRead(suppressedCompetitorsLock);
}
}
-
+
@Override
public void setSuppressed(Competitor competitor, boolean suppressed) {
- if (competitor == null) {
- throw new IllegalArgumentException("Cannot change suppression for a null competitor");
- }
+ if (competitor == null) {
+ throw new IllegalArgumentException("Cannot change suppression for a null competitor");
+ }
LockUtil.lockForWrite(suppressedCompetitorsLock);
try {
if (suppressed) {
@@ -874,7 +914,7 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
TimePoint timePoint = delayToLiveInMillis == null ? now : now.minus(delayToLiveInMillis);
return timePoint;
}
-
+
@Override
public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) {
getRaceColumnListeners().notifyListenersAboutRaceLogEventAdded(raceColumn, raceLogIdentifier, event);
@@ -887,14 +927,16 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
}
public String toString() {
- return getName() + " " + (getDefaultCourseArea() != null ? getDefaultCourseArea().getName() : "") + " " + (getScoringScheme() != null ? getScoringScheme().getType().name() : "");
+ return getName() + " "
+ + (getDefaultCourseArea() != null ? getDefaultCourseArea().getName() : "") + " "
+ + (getScoringScheme() != null ? getScoringScheme().getType().name() : "");
}
@Override
public NumberOfCompetitorsInLeaderboardFetcher getNumberOfCompetitorsInLeaderboardFetcher() {
return new NumberOfCompetitorsFetcherImpl();
}
-
+
@Override
public Pair getRaceColumnAndFleet(TrackedRace trackedRace) {
for (final RaceColumn raceColumn : getRaceColumns()) {
@@ -914,8 +956,8 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
Map competitorsAndTheirBoats = raceColumn.getAllCompetitorsAndTheirBoats();
allBoats.addAll(competitorsAndTheirBoats.values());
}
- return Util.getDominantObject(StreamSupport.stream(allBoats.spliterator(), /* parallel */ false).
- map(b->b.getBoatClass()).collect(Collectors.toList()));
+ return Util.getDominantObject(StreamSupport.stream(allBoats.spliterator(), /* parallel */ false)
+ .map(b -> b.getBoatClass()).collect(Collectors.toList()));
}
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/impl/GPSFixStoreImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/impl/GPSFixStoreImpl.java
deleted file mode 100755
index c16c669fe70..00000000000
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/impl/GPSFixStoreImpl.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package com.sap.sailing.domain.racelog.impl;
-
-import java.util.List;
-import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-
-import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
-import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder;
-import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMarkMappingFinder;
-import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.base.Mark;
-import com.sap.sailing.domain.common.DeviceIdentifier;
-import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
-import com.sap.sailing.domain.common.tracking.GPSFix;
-import com.sap.sailing.domain.common.tracking.GPSFixMoving;
-import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
-import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
-import com.sap.sailing.domain.racelogtracking.DeviceMapping;
-import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
-import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
-import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
-import com.sap.sse.common.TimePoint;
-import com.sap.sse.common.Util;
-
-/**
- * At the moment, the timerange covered by the fixes for a device, and the number of fixes for a device are stored in a
- * metadata collection. Should be changed, see bug 1982.
- *
- * @author Fredrik Teschke
- */
-public class GPSFixStoreImpl implements GPSFixStore {
- private final SensorFixStore sensorFixStore;
-
- public GPSFixStoreImpl(SensorFixStore sensorFixStore) {
- this.sensorFixStore = sensorFixStore;
- }
-
- private void loadTrack(DynamicGPSFixTrack, FixT> track, DeviceIdentifier device,
- TimePoint from, TimePoint to, boolean toIsInclusive)
- throws NoCorrespondingServiceRegisteredException, TransformationException {
- loadTrack(track, device, from, to, toIsInclusive, () -> {
- return false;
- }, (c) -> {
- });
- }
-
- private void loadTrack(DynamicGPSFixTrack, FixT> track, DeviceIdentifier device,
- TimePoint from, TimePoint to, boolean toIsInclusive, BooleanSupplier isPreemptiveStopped,
- Consumer progress)
- throws NoCorrespondingServiceRegisteredException, TransformationException {
- sensorFixStore. loadFixes(fix -> track.add(fix, /* replace */ true), device, from, to, toIsInclusive,
- isPreemptiveStopped, progress);
- }
-
- @Override
- public void loadCompetitorTrack(DynamicGPSFixTrack track, RegattaLog log,
- Competitor competitor) throws NoCorrespondingServiceRegisteredException, TransformationException {
- List> mappings = new RegattaLogDeviceCompetitorMappingFinder(log)
- .analyze().get(competitor);
- if (mappings != null) {
- for (DeviceMapping mapping : mappings) {
- loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(),
- false /* toIsInclusive */);
- }
- }
- }
-
- @Override
- public void loadMarkTrack(DynamicGPSFixTrack track, RegattaLog log, Mark mark)
- throws NoCorrespondingServiceRegisteredException, TransformationException {
- List> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze()
- .get(mark);
- if (mappings != null) {
- for (DeviceMapping mapping : mappings) {
- loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(),
- false /* toIsInclusive */);
- }
- }
- }
-
- @Override
- public void storeFix(DeviceIdentifier device, GPSFix fix) {
- sensorFixStore.storeFix(device, fix);
- }
-
- @Override
- public void loadCompetitorTrack(DynamicGPSFixTrack track,
- DeviceMapping mapping, TimePoint start, TimePoint end, BooleanSupplier isPreemptiveStopped,
- Consumer progressReporter)
- throws TransformationException, NoCorrespondingServiceRegisteredException {
-
- // loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true
- // /*inclusive*/);
- final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
- final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to());
- loadTrack(track, mapping.getDevice(), from, to, true /* inclusive */, isPreemptiveStopped, progressReporter);
- }
-
- @Override
- public void loadMarkTrack(DynamicGPSFixTrack track, DeviceMapping mapping, TimePoint start,
- TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer progressReport)
- throws TransformationException, NoCorrespondingServiceRegisteredException {
- final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
- final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to());
- loadTrack(track, mapping.getDevice(), from, to, true /* inclusive */, isPreemptiveStopped, progressReport);
- }
-
- @Override
- public void loadMarkTrack(DynamicGPSFixTrack track, RegattaLog log, Mark mark, TimePoint start,
- TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException {
- List> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze()
- .get(mark);
- if (mappings != null) {
- for (DeviceMapping mapping : mappings) {
- final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
- final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to());
- loadTrack(track, mapping.getDevice(), from, to, false /* toIsInclusive */);
- }
- }
- }
-}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java
deleted file mode 100644
index 58a500bbcb1..00000000000
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.sap.sailing.domain.racelog.tracking;
-
-import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-
-import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
-import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.base.Mark;
-import com.sap.sailing.domain.common.DeviceIdentifier;
-import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
-import com.sap.sailing.domain.common.tracking.GPSFix;
-import com.sap.sailing.domain.common.tracking.GPSFixMoving;
-import com.sap.sailing.domain.racelogtracking.DeviceMapping;
-import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
-import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
-import com.sap.sse.common.TimePoint;
-
-public enum EmptyGPSFixStore implements GPSFixStore {
- INSTANCE;
-
- @Override
- public void storeFix(DeviceIdentifier device, GPSFix fix) {
- }
-
- @Override
- public void loadCompetitorTrack(DynamicGPSFixTrack track,
- RegattaLog log, Competitor competitor) {
- }
-
- @Override
- public void loadMarkTrack(DynamicGPSFixTrack track,
- RegattaLog log, Mark mark) {
- }
-
- @Override
- public void loadMarkTrack(DynamicGPSFixTrack track, RegattaLog log, Mark mark,
- TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException {
- }
-
- @Override
- public void loadCompetitorTrack(DynamicGPSFixTrack track,
- DeviceMapping mapping, TimePoint start, TimePoint end, BooleanSupplier isPreemptiveStopped,
- Consumer progressReporter)
- throws TransformationException, NoCorrespondingServiceRegisteredException {
-
- }
-
- @Override
- public void loadMarkTrack(DynamicGPSFixTrack track, DeviceMapping mapping, TimePoint start,
- TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer progressReporter)
- throws TransformationException, NoCorrespondingServiceRegisteredException {
-
- }
-}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java
deleted file mode 100644
index b83eabef87f..00000000000
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.sap.sailing.domain.racelog.tracking;
-
-import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-
-import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
-import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
-import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
-import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.base.Mark;
-import com.sap.sailing.domain.common.DeviceIdentifier;
-import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
-import com.sap.sailing.domain.common.tracking.GPSFix;
-import com.sap.sailing.domain.common.tracking.GPSFixMoving;
-import com.sap.sailing.domain.racelogtracking.DeviceMapping;
-import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
-import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
-import com.sap.sse.common.TimePoint;
-
-
-public interface GPSFixStore {
- /**
- * Load all fixes that correspond to the {@link RegattaLogDeviceCompetitorMappingEvent}s found in the {@code raceLog}.
- */
- void loadCompetitorTrack(DynamicGPSFixTrack track, RegattaLog log,
- Competitor competitor) throws TransformationException;
-
- /**
- * Load all fixes that correspond to the {@link RegattaLogDeviceMarkMappingEvent}s found in the {@code raceLog}.
- */
- void loadMarkTrack(DynamicGPSFixTrack track, RegattaLog log, Mark mark) throws TransformationException,
- NoCorrespondingServiceRegisteredException;
-
- /**
- * Load all fixes within the start and end time point (inclusive) that correspond to the
- * {@link RegattaLogDeviceMarkMappingEvent}s found in the {@code raceLog}.
- *
- * @param start
- * if null, the start of the time range for which to load fixes is only constrained by the
- * device mapping intervals
- * @param end
- * if null, the end of the time range for which to load fixes is only constrained by the
- * device mapping intervals
- */
- void loadMarkTrack(DynamicGPSFixTrack track, RegattaLog log, Mark mark, TimePoint start,
- TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException;
-
- void loadCompetitorTrack(DynamicGPSFixTrack track, DeviceMapping mapping,
- TimePoint start, TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer progressReporter)
- throws TransformationException, NoCorrespondingServiceRegisteredException;
-
- /**
- * Load all fixes that correspond to the {@code mapping}.
- */
- void loadMarkTrack(DynamicGPSFixTrack track, DeviceMapping mapping, TimePoint start,
- TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer progressReport)
- throws TransformationException,
- NoCorrespondingServiceRegisteredException;
-
- void storeFix(DeviceIdentifier device, GPSFix fix) throws TransformationException, NoCorrespondingServiceRegisteredException;
-}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/sharding/ShardingContext.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/sharding/ShardingContext.java
new file mode 100644
index 00000000000..221d4ec164c
--- /dev/null
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/sharding/ShardingContext.java
@@ -0,0 +1,121 @@
+package com.sap.sailing.domain.sharding;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.sap.sailing.domain.common.sharding.ShardingType;
+import com.sap.sailing.domain.leaderboard.caching.LiveLeaderboardUpdater;
+
+/**
+ * The sharding context is used to store and verify contraints for a thread.
+ *
+ * This is currently used to verify if a given thread, that is explicitly expected to only
+ * trigger the calculation of a given leaderboard, does trigger the calculation of further/ other
+ * leaderboards.
+ *
+ * It is also used to log warnings if a leaderboard is calculated without predefining the thread constraint.
+ *
+ * The enum {@link ShardingType} lists the known sharding types. Each sharding type defines a prefix that will
+ * be used to identify the sharding type from the request, as implemented in {@link #identifyAndSetShardingConstraint(String)}.
+ *
+ * By calling {@link #setShardingConstraint(ShardingType, String)} it is possible to directly set a thread constraint.
+ * This is useful in background computing code, as in {@link LiveLeaderboardUpdater}
+ *
+ */
+public class ShardingContext {
+ private static final Logger logger = Logger.getLogger(ShardingContext.class.getName());
+
+ private static final ConcurrentMap> shardingMap = new ConcurrentHashMap<>();
+
+ /**
+ * Sets the sharding context. The type of sharding will be identified by the prefix.
+ *
+ * @param shardingInfo
+ */
+ public static ShardingType identifyAndSetShardingConstraint(String shardingInfo) {
+ if (shardingInfo == null || shardingInfo.isEmpty()) {
+ logger.warning("Empty sharding constraint");
+ return null;
+ }
+ ThreadLocal identifiedShardingHolder = null;
+ for (ShardingType shardingType : ShardingType.values()) {
+ if (shardingInfo.startsWith(shardingType.getPrefix())) {
+ identifiedShardingHolder = shardingMap.computeIfAbsent(shardingType, t -> new ThreadLocal<>());
+ checkAndSetShardingInfo(shardingType, shardingInfo, identifiedShardingHolder);
+ return shardingType;
+ }
+ }
+ if (identifiedShardingHolder == null) {
+ logger.warning("Could not identify sharding type for: " + shardingInfo);
+ }
+ return null;
+ }
+
+ /**
+ * Provide sharding constraint for given sharding type.
+ *
+ * @param shardingType
+ * @param shardingInfo
+ */
+ public static void setShardingConstraint(ShardingType shardingType, String shardingInfo) {
+ final String encodedShardingInfo = shardingType.encodeIfNeeded(shardingInfo);
+ ThreadLocal shardingHolder = shardingMap.computeIfAbsent(shardingType, t -> new ThreadLocal<>());
+ checkAndSetShardingInfo(shardingType, encodedShardingInfo, shardingHolder);
+ }
+
+ /**
+ * Check if provided sharding information name equals shard constraint.
+ *
+ * If the information is null or empty, we log a warning.
+ * If shard does not have a constraint, we log a warning. If
+ * the information provided does not match information previously stored in shard,
+ * we make a severe log entry.
+ *
+ * @param shardingInfo
+ */
+ public static void checkConstraint(final ShardingType type, final String shardingInfo) {
+ if (shardingInfo == null || shardingInfo.isEmpty()) {
+ logger.warning("Empty sharding constraint");
+ return;
+ }
+ final ThreadLocal shardingHolder = shardingMap.get(type);
+ if (shardingHolder == null) {
+ logger.log(Level.WARNING, "No current sharding context set for " + type.name(), new RuntimeException());
+ return;
+ }
+ String currentShardingInfo = shardingHolder.get();
+ if (currentShardingInfo == null || currentShardingInfo.isEmpty()) {
+ logger.warning("No current sharding constraint for " + type.name());
+ return;
+ }
+ final String encodedShardingInfo = type.encodeIfNeeded(shardingInfo);
+ if (!encodedShardingInfo.equals(currentShardingInfo)) {
+ logger.log(Level.SEVERE, "Current sharding constraint vialation for " + type.name() + ". Got "
+ + shardingInfo + ", shard requires " + currentShardingInfo, new RuntimeException());
+ return;
+ }
+ }
+
+ public static void clearShardingConstraint(ShardingType type) {
+ ThreadLocal shardingHolder = shardingMap.get(type);
+ if (shardingHolder != null) {
+ shardingHolder.remove();
+ }
+ }
+
+ private static void checkAndSetShardingInfo(ShardingType shardingType, String encodedShardingInfo,
+ ThreadLocal shardingHolder) {
+ if (encodedShardingInfo == null || encodedShardingInfo.isEmpty()) {
+ logger.log(Level.SEVERE, "Cannot set empty sharding information for " + shardingType.name(),
+ new RuntimeException());
+ }
+ String currentShardingInfo = shardingHolder.get();
+ if (currentShardingInfo == null) {
+ shardingHolder.set(encodedShardingInfo);
+ } else if (!encodedShardingInfo.equals(currentShardingInfo)) {
+ logger.log(Level.SEVERE, "Switching shard constraint for " + shardingType.name()+". Got <<" + encodedShardingInfo +">>, expeted <<"+ currentShardingInfo+">>", new RuntimeException());
+ }
+ }
+}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
index 6120df5646a..c598d23b01d 100644
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
@@ -49,7 +49,7 @@ import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuse
import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
-import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
+import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.ranking.RankingMetric;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sailing.domain.tracking.impl.NonCachingMarkPositionAtTimePointCache;
@@ -773,7 +773,7 @@ public interface TrackedRace extends Serializable, IsManagedByCache
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 ed917794a7e..06fcd8d9c08 100644
--- a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF
@@ -77,6 +77,7 @@ TrackLifecycle: true
Export-Package: com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.confidence.impl,
com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.impl,
com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl,
+ com.sap.sailing.gwt.common.communication.routing,
com.sap.sailing.gwt.home.communication,
com.sap.sailing.gwt.home.server,
com.sap.sailing.gwt.server,
diff --git a/java/com.sap.sailing.gwt.ui/WEB-INF/web.xml b/java/com.sap.sailing.gwt.ui/WEB-INF/web.xml
index 8538c7b0804..7f9c9641021 100755
--- a/java/com.sap.sailing.gwt.ui/WEB-INF/web.xml
+++ b/java/com.sap.sailing.gwt.ui/WEB-INF/web.xml
@@ -70,6 +70,7 @@
SailingService/service/sailing
+ /service/sailing/*
@@ -90,6 +91,7 @@
sailingDispatch/service/dispatch
+ /service/dispatch/*
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/app/AutoPlayClientFactoryBase.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/app/AutoPlayClientFactoryBase.java
index 0c865358e6e..242ea7d5c6a 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/app/AutoPlayClientFactoryBase.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/app/AutoPlayClientFactoryBase.java
@@ -1,16 +1,20 @@
package com.sap.sailing.gwt.autoplay.client.app;
+import java.util.HashMap;
+import java.util.Map;
+
import com.google.gwt.core.client.GWT;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sailing.gwt.autoplay.client.places.autoplaystart.AutoPlayStartPlace;
+import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.ui.client.MediaService;
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
-import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
+import com.sap.sailing.gwt.ui.client.SailingServiceHelper;
import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sse.security.ui.client.SecureClientFactoryImpl;
@@ -20,11 +24,13 @@ public abstract class AutoPlayClientFactoryBase
private final MediaServiceAsync mediaService;
private final AutoPlayPlaceNavigator navigator;
+ private final Map services = new HashMap<>();
+
public AutoPlayClientFactoryBase(ApplicationTopLevelView root, EventBus eventBus, PlaceController placeController,
AutoPlayPlaceNavigator navigator) {
super(root, eventBus, placeController);
this.navigator = navigator;
- sailingService = GWT.create(SailingService.class);
+ sailingService = SailingServiceHelper.createSailingServiceInstance();
mediaService = GWT.create(MediaService.class);
EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService,
RemoteServiceMappingConstants.sailingServiceRemotePath);
@@ -39,8 +45,25 @@ public abstract class AutoPlayClientFactoryBase
@Override
public SailingServiceAsync getSailingService() {
+ if (isConfigured()) {
+ return getSailingService(() -> getAutoPlayCtxSignalError().getContextDefinition().getLeaderboardName());
+ }
return sailingService;
}
+
+ @Override
+ public SailingServiceAsync getSailingService(ProvidesLeaderboardRouting routingProvider) {
+ if (routingProvider == null) {
+ return sailingService;
+ } else {
+ SailingServiceAsync sailingServiceAsync = services.get(routingProvider.routingSuffixPath());
+ if (sailingServiceAsync == null) {
+ sailingServiceAsync = SailingServiceHelper.createSailingServiceInstance(routingProvider);
+ services.put(routingProvider.routingSuffixPath(), sailingServiceAsync);
+ }
+ return sailingServiceAsync;
+ }
+ }
@Override
public MediaServiceAsync getMediaService() {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/AutoPlayConfiguration.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/AutoPlayConfiguration.java
index e3c631638db..349d9ba9ac7 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/AutoPlayConfiguration.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/AutoPlayConfiguration.java
@@ -1,10 +1,13 @@
package com.sap.sailing.gwt.autoplay.client.configs;
+import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.user.client.Window;
import com.sap.sailing.gwt.autoplay.client.app.AutoPlayClientFactory;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
+import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
+import com.sap.sse.gwt.settings.UrlBuilderUtil;
import com.sap.sse.security.ui.client.UserService;
public abstract class AutoPlayConfiguration {
@@ -19,20 +22,28 @@ public abstract class AutoPlayConfiguration {
OnSettingsCallback holder, PerspectiveCompositeSettings> settings, AutoPlayContextDefinition apcd,
UserService userService) {
Window.alert("This configuration does not have settings");
-
}
/**
* This method should be pure/standalone, it is not allowed to make any guesses on fields written by startRootNode,
* as it can be called before that
*/
- public void loadSettingsDefault(EventDTO selectedEvent, StrippedLeaderboardDTO leaderboard, UserService userService,
- OnSettingsCallback holder) {
- holder.newSettings(null);
+ public void loadSettingsDefault(EventDTO selectedEvent, AutoPlayContextDefinition apcd,
+ StrippedLeaderboardDTO leaderboard, UserService userService, OnSettingsCallback holder) {
+ holder.newSettings(null, getUrlWithSettings(apcd, null));
+ }
+
+ private String getUrlWithSettings(AutoPlayContextDefinition apcd, PerspectiveCompositeSettings> settings) {
+ UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters();
+ SettingsToUrlSerializer urlSerializer = new SettingsToUrlSerializer();
+ if (settings != null) {
+ urlSerializer.serializeSettingsMapToUrlBuilder(settings, urlBuilder);
+ }
+ urlSerializer.serializeToUrlBuilder(apcd, urlBuilder);
+ return urlBuilder.buildString();
}
public interface OnSettingsCallback {
- void newSettings(PerspectiveCompositeSettings> newSettings);
+ void newSettings(PerspectiveCompositeSettings> newSettings, String urlWithSettings);
}
-
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/impl/AutoPlayClassicConfiguration.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/impl/AutoPlayClassicConfiguration.java
index bc1cd20e127..ec9dade106a 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/impl/AutoPlayClassicConfiguration.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/impl/AutoPlayClassicConfiguration.java
@@ -26,58 +26,81 @@ import com.sap.sse.security.ui.client.UserService;
public class AutoPlayClassicConfiguration extends AutoPlayConfiguration {
private static final Logger logger = Logger.getLogger(AutoPlayClassicConfiguration.class.getName());
-
+
@Override
public void startRootNode(AutoPlayClientFactory cf, AutoPlayContextDefinition context,
PerspectiveCompositeSettings> settings, EventDTO initialEventData) {
- cf.getSailingService().getAvailableDetailTypesForLeaderboard(context.getLeaderboardName(), new AsyncCallback>() {
- @Override
- public void onFailure(Throwable caught) {
- logger.log(Level.WARNING, "Could not load detailtypes for leaderboard", caught);
- }
+ cf.getSailingService().getAvailableDetailTypesForLeaderboard(context.getLeaderboardName(),
+ null, new AsyncCallback>() {
+ @Override
+ public void onFailure(Throwable caught) {
+ logger.log(Level.WARNING, "Could not load detailtypes for leaderboard", caught);
+ }
- @SuppressWarnings("unchecked")
- @Override
- public void onSuccess(Iterable result) {
- StrippedLeaderboardDTO leaderBoardDTO = AutoplayHelper.getSelectedLeaderboard(initialEventData,
- context.getLeaderboardName());
- AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderBoardDTO, cf.getUserService(), result);
- cf.setAutoPlayContext(new AutoPlayContextImpl(autoplayLifecycle,
- (PerspectiveCompositeSettings) settings,
- AutoPlayClassicConfiguration.this, context, initialEventData));
- // start sixty inch slide loop nodes...
- RootNodeClassic root = new RootNodeClassic(cf);
- root.start(cf.getEventBus());
- }
- });
+ @SuppressWarnings("unchecked")
+ @Override
+ public void onSuccess(Iterable result) {
+ StrippedLeaderboardDTO leaderBoardDTO = AutoplayHelper.getSelectedLeaderboard(initialEventData,
+ context.getLeaderboardName());
+ AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(
+ leaderBoardDTO, cf.getUserService(), result);
+ cf.setAutoPlayContext(new AutoPlayContextImpl(autoplayLifecycle,
+ (PerspectiveCompositeSettings) settings,
+ AutoPlayClassicConfiguration.this, context, initialEventData));
+ // start sixty inch slide loop nodes...
+ RootNodeClassic root = new RootNodeClassic(cf);
+ root.start(cf.getEventBus());
+ }
+ });
}
@Override
public void openSettingsDialog(EventDTO selectedEvent, StrippedLeaderboardDTO leaderboard,
- OnSettingsCallback settingsCallback, PerspectiveCompositeSettings> settings, AutoPlayContextDefinition apcd, UserService userService) {
+ OnSettingsCallback settingsCallback, PerspectiveCompositeSettings> settings,
+ AutoPlayContextDefinition apcd, UserService userService) {
DialogCallback> callback = new DialogCallback>() {
@Override
public void ok(PerspectiveCompositeSettings editedObject) {
- settingsCallback.newSettings(editedObject);
+ settingsCallback.newSettings(editedObject,
+ getUrlWithSettings(apcd, editedObject, leaderboard, userService));
}
@Override
public void cancel() {
}
};
- AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService, Arrays.asList(DetailType.values()));
- PerspectiveCompositeSettings autoplayPerspectiveSettings = autoplayLifecycle
- .createDefaultSettings();
- LinkWithSettingsGenerator> settingsGenerator = new LinkWithSettingsGenerator<>(Window.Location.getPath(), autoplayLifecycle::createDefaultSettings, apcd);
- new SettingsDialogForLinkSharing>(settingsGenerator,
- autoplayLifecycle, autoplayPerspectiveSettings, StringMessages.INSTANCE, true, callback).show();
+ AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService,
+ Arrays.asList(DetailType.values()));
+ @SuppressWarnings("unchecked")
+ PerspectiveCompositeSettings autoplayPerspectiveSettings = settings != null
+ ? (PerspectiveCompositeSettings) settings
+ : autoplayLifecycle.createDefaultSettings();
+ LinkWithSettingsGenerator> settingsGenerator = new LinkWithSettingsGenerator<>(
+ Window.Location.getPath(), autoplayLifecycle::createDefaultSettings, apcd);
+ new SettingsDialogForLinkSharing>(
+ settingsGenerator, autoplayLifecycle, autoplayPerspectiveSettings, StringMessages.INSTANCE, true,
+ callback).show();
}
@Override
- public void loadSettingsDefault(EventDTO selectedEvent, StrippedLeaderboardDTO leaderboard,
- UserService userService, OnSettingsCallback settingsCallback) {
- AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService, Arrays.asList(DetailType.values()));
- settingsCallback.newSettings(autoplayLifecycle.createDefaultSettings());
+ public void loadSettingsDefault(EventDTO selectedEvent, AutoPlayContextDefinition apcd,
+ StrippedLeaderboardDTO leaderboard, UserService userService, OnSettingsCallback settingsCallback) {
+ AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService,
+ Arrays.asList(DetailType.values()));
+ PerspectiveCompositeSettings defaultSettings = autoplayLifecycle
+ .createDefaultSettings();
+ settingsCallback.newSettings(defaultSettings,
+ getUrlWithSettings(apcd, defaultSettings, leaderboard, userService));
}
+ private String getUrlWithSettings(AutoPlayContextDefinition apcd,
+ PerspectiveCompositeSettings settings, StrippedLeaderboardDTO leaderboard,
+ UserService userService) {
+ AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService,
+ Arrays.asList(DetailType.values()));
+ LinkWithSettingsGenerator> settingsGenerator = new LinkWithSettingsGenerator<>(
+ Window.Location.getPath(), autoplayLifecycle::createDefaultSettings, apcd);
+
+ return settingsGenerator.createUrl(settings);
+ }
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/IdleRaceLeaderboard.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/IdleRaceLeaderboard.java
index 0ea917d7fd1..f73c2f82b74 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/IdleRaceLeaderboard.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/IdleRaceLeaderboard.java
@@ -17,6 +17,7 @@ import com.sap.sailing.gwt.autoplay.client.utils.AutoplayHelper;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint;
+import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
@@ -35,6 +36,7 @@ public class IdleRaceLeaderboard extends FiresPlaceNode {
}
public void onStart() {
+ leaderboardTimer.setTime(MillisecondsTimePoint.now().asMillis());
leaderboardTimer.play();
PerspectiveCompositeSettings settings = cf.getAutoPlayCtxSignalError()
.getAutoplaySettings();
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/IdleSixtyInchLeaderboardNode.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/IdleSixtyInchLeaderboardNode.java
index 2b2231c106a..ee1361b1c53 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/IdleSixtyInchLeaderboardNode.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/IdleSixtyInchLeaderboardNode.java
@@ -93,11 +93,11 @@ public class IdleSixtyInchLeaderboardNode extends FiresPlaceNode {
private void startWithLeaderbaord(final MultiRaceLeaderboardSettings leaderboardSettings,
CompetitorSelectionProvider provider, String leaderboardName) {
- MultiRaceLeaderboardPanel leaderboardPanel = new MultiRaceLeaderboardPanel(null, null, cf.getSailingService(),
- new AsyncActionsExecutor(), leaderboardSettings, false, provider, timer, null, leaderboardName,
- cf.getErrorReporter(), StringMessages.INSTANCE, false, null, false, null, false, true, false, false,
- false, new SixtyInchLeaderboardStyle(true), FlagImageResolverImpl.get(),
- Arrays.asList(DetailType.values()));
+ MultiRaceLeaderboardPanel leaderboardPanel = new MultiRaceLeaderboardPanel(null, null,
+ cf.getSailingService(() -> leaderboardName), new AsyncActionsExecutor(), leaderboardSettings, false,
+ provider, timer, null, leaderboardName, cf.getErrorReporter(), StringMessages.INSTANCE, false, null,
+ false, null, false, true, false, false, false, new SixtyInchLeaderboardStyle(true),
+ FlagImageResolverImpl.get(), Arrays.asList(DetailType.values()));
IdleSixtyInchLeaderboardPlace place = new IdleSixtyInchLeaderboardPlace(leaderboardPanel, provider,
durationConsumer);
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/LiveRaceBoardNode.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/LiveRaceBoardNode.java
index c7e5493dc6b..b5bd0f557bd 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/LiveRaceBoardNode.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/LiveRaceBoardNode.java
@@ -24,6 +24,7 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.raceboard.RaceBoardPanel;
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
import com.sap.sailing.gwt.ui.shared.RaceboardDataDTO;
+import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
@@ -54,6 +55,8 @@ public class LiveRaceBoardNode extends FiresPlaceNode implements RaceTimesInfoPr
}
public void onStart() {
+ raceboardTimer.setTime(MillisecondsTimePoint.now().asMillis());
+ raceboardTimer.play();
raceTimesInfoProvider.addRaceIdentifier(cf.getAutoPlayCtxSignalError().getLifeOrPreLiveRace(), true);
PerspectiveCompositeSettings settings = cf.getAutoPlayCtxSignalError().getAutoplaySettings();
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/autoplaystart/AutoPlayStartPresenterImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/autoplaystart/AutoPlayStartPresenterImpl.java
index 69d1a6a2e36..879c748387c 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/autoplaystart/AutoPlayStartPresenterImpl.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/autoplaystart/AutoPlayStartPresenterImpl.java
@@ -55,10 +55,10 @@ public class AutoPlayStartPresenterImpl extends AbstractActivity implements Auto
StrippedLeaderboardDTO leaderBoard = AutoplayHelper.getSelectedLeaderboard(event,
apcd.getLeaderboardName());
- apcd.getType().getConfig().loadSettingsDefault(event, leaderBoard, clientFactory.getUserService(), new OnSettingsCallback() {
+ apcd.getType().getConfig().loadSettingsDefault(event, apcd, leaderBoard, clientFactory.getUserService(), new OnSettingsCallback() {
@Override
- public void newSettings(PerspectiveCompositeSettings> newSettings) {
+ public void newSettings(PerspectiveCompositeSettings> newSettings, String urlWithSettings) {
if (newSettings != null) {
serializer.deserializeSettingsMapFromCurrentLocation(newSettings);
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/autoplaystart/AutoPlayStartViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/autoplaystart/AutoPlayStartViewImpl.java
index ce8f0b88f03..2e21e7d8da2 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/autoplaystart/AutoPlayStartViewImpl.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/autoplaystart/AutoPlayStartViewImpl.java
@@ -8,7 +8,6 @@ import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
@@ -30,8 +29,6 @@ import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.common.Util;
import com.sap.sse.gwt.client.GWTLocaleUtil;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
-import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
-import com.sap.sse.gwt.settings.UrlBuilderUtil;
public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartView {
private static StartPageViewUiBinder uiBinder = GWT.create(StartPageViewUiBinder.class);
@@ -151,9 +148,9 @@ public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartVie
selectedAutoPlayType.getConfig().openSettingsDialog(selectedEvent, selectedLeaderboard,
new OnSettingsCallback() {
@Override
- public void newSettings(PerspectiveCompositeSettings> newSettings) {
+ public void newSettings(PerspectiveCompositeSettings> newSettings, String urlWithSettings) {
settings = newSettings;
- updateURL();
+ updateURL(urlWithSettings);
}
}, settings, apcd, currentPresenter.getUserService());
}
@@ -197,12 +194,12 @@ public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartVie
settingsButton.removeStyleName(SharedResources.INSTANCE.mainCss().buttoninactive());
startAutoPlayButton.removeStyleName(SharedResources.INSTANCE.mainCss().buttoninactive());
apcd = new AutoPlayContextDefinitionImpl(selectedAutoPlayType, selectedEvent.id, selectedLeaderboardName);
- apcd.getType().getConfig().loadSettingsDefault(selectedEvent, selectedLeaderboard, currentPresenter.getUserService(),
+ apcd.getType().getConfig().loadSettingsDefault(selectedEvent, apcd, selectedLeaderboard, currentPresenter.getUserService(),
new OnSettingsCallback() {
@Override
- public void newSettings(PerspectiveCompositeSettings> newSettings) {
+ public void newSettings(PerspectiveCompositeSettings> newSettings, String urlWithSettings) {
settings = newSettings;
- updateURL();
+ updateURL(urlWithSettings);
}
});
}
@@ -210,16 +207,10 @@ public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartVie
return readyToGo;
}
- private void updateURL() {
- UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters();
- SettingsToUrlSerializer urlSerializer = new SettingsToUrlSerializer();
- if (settings != null) {
- urlSerializer.serializeSettingsMapToUrlBuilder(settings, urlBuilder);
- }
- urlSerializer.serializeToUrlBuilder(apcd, urlBuilder);
- configuratedUrl = urlBuilder.buildString();
- configStarter.setText(configuratedUrl);
- configStarter.setHref(configuratedUrl);
+ private void updateURL(String urlWithSettings) {
+ configuratedUrl = urlWithSettings;
+ configStarter.setText(urlWithSettings);
+ configStarter.setHref(urlWithSettings);
}
@UiHandler("localeSelectionBox")
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/SourceCommon.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/SourceCommon.gwt.xml
index a20e68ee3dd..f1e0f650ecf 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/SourceCommon.gwt.xml
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/SourceCommon.gwt.xml
@@ -6,6 +6,8 @@
+
+
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/BoatClassImageResolver.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/BoatClassImageResolver.java
index c4f83ff28d1..b7ca2ca21a3 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/BoatClassImageResolver.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/BoatClassImageResolver.java
@@ -45,6 +45,7 @@ public class BoatClassImageResolver {
boatClassIconsMap.put(BoatClassMasterdata.CANOE_TAIFUN.getDisplayName(), imageResources.CanoeTaifunIcon());
boatClassIconsMap.put(BoatClassMasterdata.CONTENDER.getDisplayName(), imageResources.ContenderIcon());
boatClassIconsMap.put(BoatClassMasterdata.CC_30.getDisplayName(), imageResources.CC30Icon());
+ boatClassIconsMap.put(BoatClassMasterdata.CLUB_SWAN_50.getDisplayName(), imageResources.CLUBSWAN50Icon());
boatClassIconsMap.put(BoatClassMasterdata.DELPHIA_24.getDisplayName(), imageResources.Delphia24Icon());
boatClassIconsMap.put(BoatClassMasterdata.DRAGON_INT.getDisplayName(), imageResources.DragonIcon());
boatClassIconsMap.put(BoatClassMasterdata.DYAS.getDisplayName(), imageResources.DyasIcon());
@@ -58,6 +59,7 @@ public class BoatClassImageResolver {
boatClassIconsMap.put(BoatClassMasterdata.FARR_280.getDisplayName(), imageResources.Farr280Icon());
boatClassIconsMap.put(BoatClassMasterdata.FINN.getDisplayName(), imageResources.FinnIcon());
boatClassIconsMap.put(BoatClassMasterdata.FLYING_DUTCHMAN.getDisplayName(), imageResources.FlyingDutchmanIcon());
+ boatClassIconsMap.put(BoatClassMasterdata.FLYING_JUNIOR.getDisplayName(), imageResources.FlyingJuniorIcon());
boatClassIconsMap.put(BoatClassMasterdata.FOLKBOAT.getDisplayName(), imageResources.FolkBoatIcon());
boatClassIconsMap.put(BoatClassMasterdata.FUN.getDisplayName(), imageResources.FUNIcon());
boatClassIconsMap.put(BoatClassMasterdata.GC_32.getDisplayName(), imageResources.GC32Icon());
@@ -126,6 +128,7 @@ public class BoatClassImageResolver {
boatClassIconsMap.put(BoatClassMasterdata.TOM_28_MAX.getDisplayName(), imageResources.Tom28MaxIcon());
boatClassIconsMap.put(BoatClassMasterdata.TP52.getDisplayName(), imageResources.TP52Icon());
boatClassIconsMap.put(BoatClassMasterdata.TRIAS.getDisplayName(), imageResources.TriasIcon());
+ boatClassIconsMap.put(BoatClassMasterdata.VAURIEN.getDisplayName(), imageResources.VaurienIcon());
boatClassIconsMap.put(BoatClassMasterdata.VENT_D_OUEST.getDisplayName(), imageResources.VentdOuestIcon());
boatClassIconsMap.put(BoatClassMasterdata.VIPER_640.getDisplayName(), imageResources.Viper640Icon());
boatClassIconsMap.put(BoatClassMasterdata.VX_ONE.getDisplayName(), imageResources.VXOneIcon());
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/BoatClassImageResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/BoatClassImageResources.java
index 2855dbbf8db..0270a334a1f 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/BoatClassImageResources.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/BoatClassImageResources.java
@@ -132,6 +132,10 @@ public interface BoatClassImageResources extends ClientBundle {
@ImageOptions(preventInlining = true)
ImageResource FinnIcon();
+ @Source("com/sap/sailing/gwt/ui/client/images/boatclass/FLYING_JUNIOR.png")
+ @ImageOptions(preventInlining = true)
+ ImageResource FlyingJuniorIcon();
+
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/FLYING_DUTCHMAN.png")
@ImageOptions(preventInlining = true)
ImageResource FlyingDutchmanIcon();
@@ -396,6 +400,10 @@ public interface BoatClassImageResources extends ClientBundle {
@ImageOptions(preventInlining = true)
ImageResource CC30Icon();
+ @Source("com/sap/sailing/gwt/ui/client/images/boatclass/CLUBSWAN50.png")
+ @ImageOptions(preventInlining = true)
+ ImageResource CLUBSWAN50Icon();
+
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/GP_26.png")
@ImageOptions(preventInlining = true)
ImageResource GP26Icon();
@@ -431,4 +439,8 @@ public interface BoatClassImageResources extends ClientBundle {
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/RUNNING.png")
@ImageOptions(preventInlining = true)
ImageResource RunningIcon();
+
+ @Source("com/sap/sailing/gwt/ui/client/images/boatclass/VAURIEN.png")
+ @ImageOptions(preventInlining = true)
+ ImageResource VaurienIcon();
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/controls/tabbar/TabPanel.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/controls/tabbar/TabPanel.ui.xml
index 15379e2d27b..89523c3b333 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/controls/tabbar/TabPanel.ui.xml
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/controls/tabbar/TabPanel.ui.xml
@@ -25,6 +25,7 @@
.tabExtension {
float: right;
+ margin-top: .5em;
}
.tabExtension > * {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/communication/routing/ProvidesLeaderboardRouting.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/communication/routing/ProvidesLeaderboardRouting.java
new file mode 100644
index 00000000000..3c224cd0998
--- /dev/null
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/communication/routing/ProvidesLeaderboardRouting.java
@@ -0,0 +1,16 @@
+package com.sap.sailing.gwt.common.communication.routing;
+
+import com.sap.sailing.domain.common.sharding.ShardingType;
+import com.sap.sse.gwt.client.ServiceRoutingProvider;
+
+/**
+ * Interface used to provide leaderboard specific routing, see {@link ServiceRoutingProvider}
+ */
+public interface ProvidesLeaderboardRouting extends ServiceRoutingProvider {
+
+ String getLeaderboardName();
+
+ default String routingSuffixPath() {
+ return ShardingType.LEADERBOARDNAME.encodeIfNeeded(getLeaderboardName());
+ }
+}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/GetCompetitionFormatRacesAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/GetCompetitionFormatRacesAction.java
index 7479b838571..479278ed257 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/GetCompetitionFormatRacesAction.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/GetCompetitionFormatRacesAction.java
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.communication.event;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
+import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
@@ -26,7 +27,7 @@ import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
*
*/
public class GetFinishedRacesAction implements SailingAction>>,
- IsClientCacheable {
+ IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -59,4 +60,9 @@ public class GetFinishedRacesAction implements SailingAction
*/
public class GetLiveRacesForRegattaAction implements SailingAction>>,
- IsClientCacheable {
+ IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaName;
@@ -66,4 +67,10 @@ public class GetLiveRacesForRegattaAction implements SailingAction5 minutes.
*
*/
-public class GetRegattaStatisticsAction implements SailingAction>, IsClientCacheable {
+public class GetRegattaStatisticsAction implements SailingAction>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -53,4 +54,9 @@ public class GetRegattaStatisticsAction implements SailingAction5 minutes for currently running events.
*
*/
-public class GetRegattaWithProgressAction implements SailingAction>, IsClientCacheable {
+public class GetRegattaWithProgressAction implements SailingAction>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String regattaId;
@@ -55,4 +56,9 @@ public class GetRegattaWithProgressAction implements SailingAction
*/
-public class GetMiniLeaderbordAction implements SailingAction>, IsClientCacheable {
+public class GetMiniLeaderbordAction implements SailingAction>, IsClientCacheable, ProvidesLeaderboardRouting {
private UUID eventId;
private String leaderboardName;
private int limit = 0;
@@ -74,4 +75,9 @@ public class GetMiniLeaderbordAction implements SailingAction
*/
-public class GetSixtyInchStatisticAction implements SailingAction {
+public class GetSixtyInchStatisticAction implements SailingAction, ProvidesLeaderboardRouting {
private static final Logger LOGGER = Logger.getLogger(GetSixtyInchStatisticAction.class.getName());
// transfer as string, to avoid transfering incompatible types
private String racename;
@@ -95,4 +96,9 @@ public class GetSixtyInchStatisticAction implements SailingAction seriesNavigation, EventListEventSeriesDTO eventSeries) {
eventImage.appendChild(new EventTeaserSeriesInfoCorner(seriesNavigation, eventSeries).getElement());
+ eventName.setInnerSafeHtml(LongNamesUtil.breakLongName(eventSeries.getDisplayName()));
+ venue.setInnerText(StringMessages.INSTANCE.lastEvent(event.getLocationOrVenue()));
+ eventImage.setTitle(StringMessages.INSTANCE.teaserOverallLinkToolTip());
}
public void hideImage(boolean hide) {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/sailorinfo/SailorInfo.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/sailorinfo/SailorInfo.java
index e8f8256c259..734bbc937e8 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/sailorinfo/SailorInfo.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/sailorinfo/SailorInfo.java
@@ -20,12 +20,12 @@ public class SailorInfo extends Composite {
FlowPanel panel = new FlowPanel();
Style panelStyle = panel.getElement().getStyle();
panelStyle.setDisplay(Display.INLINE_BLOCK);
+ panelStyle.setVerticalAlign(VerticalAlign.BOTTOM);
Label sailorInfoLabel = new Label();
sailorInfoLabel.getElement().setInnerHTML(i18n.sailorInfoLongText().replace("\n", " "));
Style labelStyle = sailorInfoLabel.getElement().getStyle();
labelStyle.setDisplay(Display.INLINE_BLOCK);
- sailorInfoLabel.getElement().getStyle().setMarginTop(0.5, Unit.EM);
sailorInfoLabel.getElement().getStyle().setMarginRight(0.5, Unit.EM);
panel.add(sailorInfoLabel);
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/AbstractEventActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/AbstractEventActivity.java
index aa8ca601d0f..eaeb6c02a20 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/AbstractEventActivity.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/AbstractEventActivity.java
@@ -37,7 +37,6 @@ import com.sap.sailing.gwt.settings.client.raceboard.RaceBoardPerspectiveOwnSett
import com.sap.sailing.gwt.settings.client.raceboard.RaceboardContextDefinition;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewContextDefinition;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings;
-import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapLifecycle;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapSettings;
@@ -83,10 +82,6 @@ public abstract class AbstractEventActivity ex
this.timerForClientServerOffset = new Timer(PlayModes.Replay);
this.clientFactory = clientFactory;
}
-
- public SailingServiceAsync getSailingService() {
- return clientFactory.getSailingService();
- }
public SailingDispatchSystem getDispatch() {
return clientFactory.getDispatch();
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/EventView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/EventView.java
index 67df7061b24..130a9419a8a 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/EventView.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/EventView.java
@@ -21,7 +21,6 @@ import com.sap.sailing.gwt.home.shared.places.event.EventDefaultPlace;
import com.sap.sailing.gwt.home.shared.places.events.EventsPlace;
import com.sap.sailing.gwt.home.shared.places.fakeseries.SeriesDefaultPlace;
import com.sap.sailing.gwt.home.shared.places.start.StartPlace;
-import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
import com.sap.sse.gwt.client.player.Timer;
@@ -37,7 +36,6 @@ public interface EventView> asyncCallback) {
+ clientFactory.getSailingService(()-> leaderboardName).getAvailableDetailTypesForLeaderboard(leaderboardName, raceOrNull, asyncCallback);
+ }
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/EventRegattaView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/EventRegattaView.java
index 3ba25f59503..4b6ba6e5061 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/EventRegattaView.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/EventRegattaView.java
@@ -1,5 +1,8 @@
package com.sap.sailing.gwt.home.desktop.places.event.regatta;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.sap.sailing.domain.common.DetailType;
+import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.gwt.home.desktop.places.event.EventView;
import com.sap.sailing.gwt.home.desktop.places.event.regatta.overviewtab.RegattaOverviewPlace;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
@@ -15,5 +18,8 @@ public interface EventRegattaView extends EventView> asyncCallback);
}
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/RegattaAnalyticsDataManager.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/RegattaAnalyticsDataManager.java
index cd2674c4483..c68b0705aba 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/RegattaAnalyticsDataManager.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/RegattaAnalyticsDataManager.java
@@ -6,6 +6,7 @@ import com.sap.sailing.gwt.settings.client.leaderboard.MultiRaceLeaderboardSetti
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.DebugIdHelper;
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
+import com.sap.sailing.gwt.ui.client.SailingClientFactory;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.charts.MultiCompetitorLeaderboardChart;
@@ -31,16 +32,16 @@ public class RegattaAnalyticsDataManager {
private final CompetitorSelectionModel competitorSelectionProvider;
private final AsyncActionsExecutor asyncActionsExecutor;
private final ErrorReporter errorReporter;
- private final SailingServiceAsync sailingService;
+ private final SailingClientFactory sailingCF;
private final Timer timer;
private final FlagImageResolver flagImageResolver;
- public RegattaAnalyticsDataManager(final SailingServiceAsync sailingService,
+ public RegattaAnalyticsDataManager(final SailingClientFactory sailingCF,
AsyncActionsExecutor asyncActionsExecutor, Timer timer, ErrorReporter errorReporter,
FlagImageResolver flagImageResolver) {
this.flagImageResolver = flagImageResolver;
this.competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */true);
- this.sailingService = sailingService;
+ this.sailingCF = sailingCF;
this.asyncActionsExecutor = asyncActionsExecutor;
this.timer = timer;
this.errorReporter = errorReporter;
@@ -53,6 +54,7 @@ public class RegattaAnalyticsDataManager {
final String leaderboardGroupName, String leaderboardName, boolean showRaceDetails,
boolean autoExpandLastRaceColumn, Iterable availableDetailTypes) {
if (leaderboardPanel == null) {
+ SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
leaderboardPanel = new MultiRaceLeaderboardPanel(parent, context, sailingService,
asyncActionsExecutor,
leaderboardSettings,
@@ -68,6 +70,7 @@ public class RegattaAnalyticsDataManager {
public MultiCompetitorLeaderboardChart createMultiCompetitorChart(String leaderboardName, DetailType chartDetailType) {
if(multiCompetitorChart == null) {
+ SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
multiCompetitorChart = new MultiCompetitorLeaderboardChart(null, null, sailingService, asyncActionsExecutor,
leaderboardName, chartDetailType,
competitorSelectionProvider, timer, StringMessages.INSTANCE, false, errorReporter);
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/TabletAndDesktopRegattaEventView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/TabletAndDesktopRegattaEventView.java
index 2e738b85c8d..3a01b27d22c 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/TabletAndDesktopRegattaEventView.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/TabletAndDesktopRegattaEventView.java
@@ -2,6 +2,7 @@ package com.sap.sailing.gwt.home.desktop.places.event.regatta;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.TextTransform;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -65,7 +66,12 @@ public class TabletAndDesktopRegattaEventView extends Composite implements Event
racesTabUi = new RegattaRacesTabView(flagImageResolver);
regattaOverviewTabUi = new RegattaOverviewTabView(flagImageResolver);
initWidget(uiBinder.createAndBindUi(this));
-
+
+ String sailorsInfoURL = currentPresenter.getEventDTO().getSailorsInfoWebsiteURL();
+ if (sailorsInfoURL != null && !sailorsInfoURL.isEmpty()) {
+ tabPanelUi.addTabExtension(new SailorInfo(sailorsInfoURL));
+ }
+
if(currentPresenter.getEventDTO().getType() == EventType.SERIES) {
final PlaceNavigation currentEventSeriesNavigation = currentPresenter.getCurrentEventSeriesNavigation();
Anchor seriesAnchor = new Anchor(i18n.overallLeaderboardSelection());
@@ -82,14 +88,10 @@ public class TabletAndDesktopRegattaEventView extends Composite implements Event
seriesAnchor.setStyleName(SharedResources.INSTANCE.mainCss().button());
seriesAnchor.addStyleName(SharedResources.INSTANCE.mainCss().buttonprimary());
Style style = seriesAnchor.getElement().getStyle();
- style.setFontSize(16, Unit.PX);
- style.setPadding(0.75, Unit.EM);
+ style.setPaddingLeft(0.75, Unit.EM);
+ style.setPaddingRight(0.75, Unit.EM);
+ style.setTextTransform(TextTransform.UPPERCASE);
tabPanelUi.addTabExtension(seriesAnchor);
- } else {
- String sailorsInfoURL = currentPresenter.getEventDTO().getSailorsInfoWebsiteURL();
- if(sailorsInfoURL != null && ! sailorsInfoURL.isEmpty()) {
- tabPanelUi.addTabExtension(new SailorInfo(sailorsInfoURL));
- }
}
final Iterable spots = currentPresenter.getEventDTO().getAllWindFinderSpotIdsUsedByEvent();
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/analyticstab/RegattaCompetitorAnalyticsTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/analyticstab/RegattaCompetitorAnalyticsTabView.java
index 327906f426a..54b514a9f7c 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/analyticstab/RegattaCompetitorAnalyticsTabView.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/analyticstab/RegattaCompetitorAnalyticsTabView.java
@@ -99,8 +99,8 @@ public class RegattaCompetitorAnalyticsTabView extends SharedLeaderboardRegattaT
}
};
if (regattaAnalyticsManager.getLeaderboardPanel() == null) {
- currentPresenter.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
- new AsyncCallback>() {
+ currentPresenter.getAvailableDetailTypesForLeaderboard(leaderboardName,
+ null, new AsyncCallback>() {
@Override
public void onSuccess(Iterable result) {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/leaderboardtab/RegattaLeaderboardTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/leaderboardtab/RegattaLeaderboardTabView.java
index 2b3d471ba91..588316451ce 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/leaderboardtab/RegattaLeaderboardTabView.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/leaderboardtab/RegattaLeaderboardTabView.java
@@ -147,8 +147,8 @@ public class RegattaLeaderboardTabView extends SharedLeaderboardRegattaTabView> callback) {
- currentPresenter.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
- new AsyncCallback>() {
+ currentPresenter.getAvailableDetailTypesForLeaderboard(leaderboardName,
+ null, new AsyncCallback>() {
@Override
public void onSuccess(Iterable result) {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/EventSeriesAnalyticsDataManager.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/EventSeriesAnalyticsDataManager.java
index d2356ebb303..0ffae739c78 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/EventSeriesAnalyticsDataManager.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/EventSeriesAnalyticsDataManager.java
@@ -3,8 +3,11 @@ package com.sap.sailing.gwt.home.desktop.places.fakeseries;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.function.Function;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.DetailType;
+import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.settings.client.leaderboard.MultiCompetitorLeaderboardChartSettings;
import com.sap.sailing.gwt.settings.client.leaderboard.MultiRaceLeaderboardSettings;
@@ -12,6 +15,7 @@ import com.sap.sailing.gwt.ui.client.CompetitorSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.DebugIdHelper;
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
+import com.sap.sailing.gwt.ui.client.SailingClientFactory;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.charts.MultiCompetitorLeaderboardChart;
@@ -42,33 +46,32 @@ public class EventSeriesAnalyticsDataManager {
private final CompetitorSelectionModel competitorSelectionProvider;
private final AsyncActionsExecutor asyncActionsExecutor;
private final ErrorReporter errorReporter;
- private final SailingServiceAsync sailingService;
+ private final SailingClientFactory sailingCF;
private final Timer timer;
private final int MAX_COMPETITORS_IN_CHART = 30;
private final FlagImageResolver flagImageResolver;
- public EventSeriesAnalyticsDataManager(final SailingServiceAsync sailingService,
+ public EventSeriesAnalyticsDataManager(final SailingClientFactory sailingCF,
AsyncActionsExecutor asyncActionsExecutor, Timer timer, ErrorReporter errorReporter,
FlagImageResolver flagImageResolver) {
this.flagImageResolver = flagImageResolver;
this.competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */true);
- this.sailingService = sailingService;
+ this.sailingCF = sailingCF;
this.asyncActionsExecutor = asyncActionsExecutor;
this.timer = timer;
this.errorReporter = errorReporter;
this.overallLeaderboardPanel = null;
this.multiCompetitorChart = null;
}
-
- public SailingServiceAsync getSailingService() {
- return sailingService;
- }
public MultiRaceLeaderboardPanel createMultiRaceOverallLeaderboardPanel(Component> parent, ComponentContext> context,
final MultiRaceLeaderboardSettings leaderboardSettings,
final String leaderboardGroupName, String leaderboardName, boolean showRaceDetails,
boolean autoExpandLastRaceColumn, Iterable availableDetailTypes) {
+
+
if(overallLeaderboardPanel == null) {
+ SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
overallLeaderboardPanel = new MultiRaceLeaderboardPanel(parent, context, sailingService, asyncActionsExecutor,
leaderboardSettings, true,
competitorSelectionProvider, timer, leaderboardGroupName, leaderboardName, errorReporter,
@@ -84,7 +87,10 @@ public class EventSeriesAnalyticsDataManager {
public MultiCompetitorLeaderboardChart createMultiCompetitorChart(Component> parent,
ComponentContext> context, String leaderboardName,
DetailType chartDetailType) {
+
if(multiCompetitorChart == null) {
+ SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
+
multiCompetitorChart = new MultiCompetitorLeaderboardChart(parent, context, sailingService,
asyncActionsExecutor,
leaderboardName, chartDetailType,
@@ -98,8 +104,10 @@ public class EventSeriesAnalyticsDataManager {
MultiRaceLeaderboardSettings leaderboardSettings,
String preselectedLeaderboardName, String leaderboardGroupName,
String metaLeaderboardName, boolean showRaceDetails, boolean autoExpandLastRaceColumn, Iterable availableDetailTypes) {
- if(multiLeaderboardPanel == null) {
- multiLeaderboardPanel = new MultiLeaderboardProxyPanel(parent, context, sailingService, metaLeaderboardName,
+ if (multiLeaderboardPanel == null) {
+ final Function sailingServiceFactory = leaderBoardName -> sailingCF
+ .getSailingService(() -> leaderBoardName);
+ multiLeaderboardPanel = new MultiLeaderboardProxyPanel(parent, context, sailingServiceFactory, metaLeaderboardName,
asyncActionsExecutor, timer, true /* isEmbedded */,
preselectedLeaderboardName, errorReporter, StringMessages.INSTANCE,
showRaceDetails, autoExpandLastRaceColumn, leaderboardSettings, flagImageResolver, availableDetailTypes);
@@ -179,4 +187,10 @@ public class EventSeriesAnalyticsDataManager {
public Timer getTimer() {
return timer;
}
+
+ public void getAvailableDetailTypesForLeaderboard(String leaderboardName, RegattaAndRaceIdentifier raceOrNull,
+ AsyncCallback> asyncCallback) {
+ SailingServiceAsync sailingService = sailingCF.getSailingService(()-> leaderboardName);
+ sailingService.getAvailableDetailTypesForLeaderboard(leaderboardName, raceOrNull, asyncCallback);
+ }
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/SeriesActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/SeriesActivity.java
index 3e615dad84c..260c47542b9 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/SeriesActivity.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/SeriesActivity.java
@@ -59,7 +59,7 @@ public class SeriesActivity extends AbstractActivity implements SeriesView.Prese
if (this.ctx.getAnalyticsManager() == null) {
ctx.withAnalyticsManager(new EventSeriesAnalyticsDataManager( //
- clientFactory.getSailingService(), //
+ clientFactory, //
asyncActionsExecutor, //
new Timer(PlayModes.Live, PlayStates.Paused, delayBetweenAutoAdvancesInMilliseconds), //
clientFactory.getErrorReporter(), flagImageResolver));
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/analyticstab/EventSeriesCompetitorAnalyticsTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/analyticstab/EventSeriesCompetitorAnalyticsTabView.java
index a2c71c335ec..e838a90f357 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/analyticstab/EventSeriesCompetitorAnalyticsTabView.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/analyticstab/EventSeriesCompetitorAnalyticsTabView.java
@@ -78,8 +78,8 @@ public class EventSeriesCompetitorAnalyticsTabView extends SharedLeaderboardEven
}
};
if (eventSeriesAnalyticsManager.getLeaderboardPanel() == null) {
- eventSeriesAnalyticsManager.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
- new AsyncCallback>() {
+ eventSeriesAnalyticsManager.getAvailableDetailTypesForLeaderboard(leaderboardName,
+ null, new AsyncCallback>() {
@Override
public void onSuccess(Iterable result) {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/leaderboardstab/EventSeriesLeaderboardsTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/leaderboardstab/EventSeriesLeaderboardsTabView.java
index 3a6df7f843b..0ad163958f8 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/leaderboardstab/EventSeriesLeaderboardsTabView.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/leaderboardstab/EventSeriesLeaderboardsTabView.java
@@ -77,8 +77,8 @@ public class EventSeriesLeaderboardsTabView extends Composite implements SeriesT
final EventSeriesAnalyticsDataManager regattaAnalyticsManager = currentPresenter.getCtx()
.getAnalyticsManager();
- regattaAnalyticsManager.getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName,
- new AsyncCallback>() {
+ regattaAnalyticsManager.getAvailableDetailTypesForLeaderboard(leaderboardName,
+ null, new AsyncCallback>() {
@Override
public void onSuccess(Iterable result) {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/overallleaderboardtab/EventSeriesOverallLeaderboardTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/overallleaderboardtab/EventSeriesOverallLeaderboardTabView.java
index 5f924bdb3c3..b34f29b1291 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/overallleaderboardtab/EventSeriesOverallLeaderboardTabView.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/fakeseries/overallleaderboardtab/EventSeriesOverallLeaderboardTabView.java
@@ -64,7 +64,7 @@ public class EventSeriesOverallLeaderboardTabView extends SharedLeaderboardEvent
contentArea.setWidget(currentPresenter.getErrorAndBusyClientFactory().createBusyView());
String leaderboardName = currentPresenter.getSeriesDTO().getLeaderboardId();
if (leaderboardName != null && !leaderboardName.isEmpty()) {
- currentPresenter.getCtx().getAnalyticsManager().getSailingService().getAvailableDetailTypesForLeaderboard(leaderboardName, new AsyncCallback>() {
+ currentPresenter.getCtx().getAnalyticsManager().getAvailableDetailTypesForLeaderboard(leaderboardName, null, new AsyncCallback>() {
@Override
public void onSuccess(Iterable result) {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/RaceCommitteeAppNotes.html b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/RaceCommitteeAppNotes.html
index bc21c9b9ca2..f1d5075a2e4 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/RaceCommitteeAppNotes.html
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/RaceCommitteeAppNotes.html
@@ -4,6 +4,14 @@
What's New - SAP Sailing Race Manager
+
February 2018
+
+
The protest time is now configurable in the backend. An empty value means, the RCApp
+ will take 90 minutes as default. If no time is set in the backend, the RCApp will save a
+ custom duration as new default. A server side duration (device or regatta specific) will always
+ be the default.
+
+
August 2017
The result list can now be edited without a finish time.
@@ -22,6 +30,11 @@
for the competitor is cleared, the rank is set to 0 and the penalty is
set to "NONE" then the competitor will remain in the list, and this
"empty" result will be sent to the server, clearing any previous score
+ corrections that were sent to the server. This is the only way to
+ "reset" an erroneous score correction entirely from the app, because
+ swiping and thus removing the competitor from the list would leave the
+ previous score correction unchanged on the server upon the next result
+ publication.
When entering and publishing partial results, updates will only be applied
for those competitors for which a result has been entered. In particular,
@@ -30,12 +43,6 @@
partial results entered on one device will not unnecessarily remove changes
applied on another device.
- corrections that were sent to the server. This is the only way to
- "reset" an erroneous score correction entirely from the app, because
- swiping and thus removing the competitor from the list would leave the
- previous score correction unchanged on the server upon the next result
- publication.
-
Selecting a filter dimension adds a table containing the available values of the selected dimension. The order of
the value tables is equal to the order of the dimensions list.
-
Note that the selection of the filter dimensions follows the table with checkbox column pattern. So simply clicking on a
- dimension will result in deselecting all previously selected dimensions, removing possible filter values. Clicking on the
- checkbox column or using ctrl+click is advised.
-
Each filter value table now has its own scroll-bar.
+
The grouping dimensions are now ordered alphabetically.