mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-14 22:43:57 +00:00
Merge branch 'master' into bug4656
This commit is contained in:
commit
9b6669a446
131 files changed
+1392
-741
No files matched your search
@@ -26,10 +26,10 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.googlecode.mgwt;bundle-version="2.0.0";resolution:=optional,
|
||||
com.sap.sse.gwt.adminconsole,
|
||||
org.apache.commons.math;bundle-version="2.1.0",
|
||||
com.sap.sse.security.ui
|
||||
com.sap.sse.security.ui,
|
||||
com.sap.sse
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Import-Package: com.sap.sse.util,
|
||||
javax.servlet;version="3.1.0",
|
||||
Import-Package: javax.servlet;version="3.1.0",
|
||||
javax.servlet.descriptor;version="3.1.0",
|
||||
javax.servlet.http;version="3.1.0",
|
||||
org.apache.commons.io,
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ public class RibDashboardEntryPoint extends AbstractEntryPoint<StringMessages> {
|
||||
public void doOnModuleLoad() {
|
||||
applyMGWTSettings();
|
||||
DashboardClientFactory dashboardClientFactory = new DashboardClientFactoryImpl();
|
||||
DashboardPanel rootPanel = new DashboardPanel(dashboardClientFactory);
|
||||
DashboardPanel rootPanel = new DashboardPanel(dashboardClientFactory, this);
|
||||
RootLayoutPanel.get().add(rootPanel);
|
||||
WindBotDataRetriever windBotDataRetriever = new WindBotDataRetriever(dashboardClientFactory);
|
||||
windBotDataRetriever.addNumberOfWindBotsChangeListeners(rootPanel);
|
||||
|
||||
+3
-2
@@ -36,6 +36,7 @@ import com.sap.sailing.dashboards.gwt.shared.dto.RaceIdDTO;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.media.ImageDTO;
|
||||
|
||||
/**
|
||||
@@ -88,12 +89,12 @@ public class DashboardPanel extends Composite implements NumberOfWindBotsChangeL
|
||||
DashboardClientFactory dashboardClientFactory;
|
||||
private static final Logger logger = Logger.getLogger(DashboardPanel.class.getName());
|
||||
|
||||
public DashboardPanel(DashboardClientFactory dashboardClientFactory) {
|
||||
public DashboardPanel(DashboardClientFactory dashboardClientFactory, ErrorReporter errorReporter) {
|
||||
DashboardPanelResources.INSTANCE.style().ensureInjected();
|
||||
this.dashboardClientFactory = dashboardClientFactory;
|
||||
leftWindBotWidget = new WindBotWidget(dashboardClientFactory);
|
||||
rightWindBotWidget = new WindBotWidget(dashboardClientFactory);
|
||||
startanalysisComponent = new StartAnalysisWidget(this.dashboardClientFactory);
|
||||
startanalysisComponent = new StartAnalysisWidget(this.dashboardClientFactory, errorReporter);
|
||||
startlineAdvantagesByWindComponent = new StartlineAdvantagesByWindWidget(this.dashboardClientFactory);
|
||||
startlineAdvantageByGeometryWidget = new StartlineAdvantageByGeometryWidget(this.dashboardClientFactory);
|
||||
stringConstants = StringMessages.INSTANCE;
|
||||
|
||||
+8
-5
@@ -43,6 +43,7 @@ import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapResources;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
|
||||
/**
|
||||
* The class contains an collection of {@link StartAnalysisCard}s that are displayed in horizontal aligned pages. It
|
||||
@@ -112,11 +113,12 @@ public class StartAnalysisWidget extends Composite implements HasWidgets, PollsL
|
||||
* */
|
||||
private int numberOfStartAnalysisCards = 0;
|
||||
private boolean displaysCards;
|
||||
private List<StartAnalysisDTO> starts;
|
||||
private List<StartAnalysisCard> pageChangeListener;
|
||||
private final List<StartAnalysisDTO> starts;
|
||||
private final List<StartAnalysisCard> pageChangeListener;
|
||||
private BottomNotification bottomNotification;
|
||||
private CompetitorSelectionPopup competitorSelectionPopup;
|
||||
private DashboardClientFactory dashboardClientFactory;
|
||||
private final DashboardClientFactory dashboardClientFactory;
|
||||
private final ErrorReporter errorReporter;
|
||||
|
||||
private final String cookieKeyForSelectedCompetitorInLeaderboard;
|
||||
|
||||
@@ -131,8 +133,9 @@ public class StartAnalysisWidget extends Composite implements HasWidgets, PollsL
|
||||
/**
|
||||
* Component that contains handles, displays and loads startanalysis cards.
|
||||
* */
|
||||
public StartAnalysisWidget(DashboardClientFactory dashboardClientFactory) {
|
||||
public StartAnalysisWidget(DashboardClientFactory dashboardClientFactory, ErrorReporter errorReporter) {
|
||||
StartAnalysisWidgetResources.INSTANCE.gss().ensureInjected();
|
||||
this.errorReporter = errorReporter;
|
||||
dashboardWidgetHeaderAndNoDataMessage = new DashboardWidgetHeaderAndNoDataMessage();
|
||||
selectedCompetitorWithSettingsButton = new SettingsButtonWithSelectionIndicationLabel();
|
||||
selectedCompetitorWithSettingsButton.disable();
|
||||
@@ -378,7 +381,7 @@ public class StartAnalysisWidget extends Composite implements HasWidgets, PollsL
|
||||
}
|
||||
final StartAnalysisCard startlineAnalysisCard = new StartAnalysisCard(numberOfStartAnalysisCards
|
||||
* SCROLL_OFFSET_STARTANALYSIS_CARDS + MARGIN_LEFT_STARTANALYSIS_CARD, numberOfStartAnalysisCards,
|
||||
startAnalysisDTO, dashboardClientFactory.getSailingService(), raceMapResources);
|
||||
startAnalysisDTO, dashboardClientFactory.getSailingService(), errorReporter, raceMapResources);
|
||||
startanalysis_card_container.add(startlineAnalysisCard);
|
||||
startlineAnalysisCard.startAnalysisComponentPageChangedToIndexAndStartAnalysis(page, startAnalysisDTO);
|
||||
registerPageChangeListener(startlineAnalysisCard);
|
||||
|
||||
+10
-5
@@ -38,6 +38,7 @@ import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapResources;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapSettings;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings.ZoomTypes;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.player.Timer.PlayModes;
|
||||
|
||||
@@ -70,8 +71,9 @@ public class StartAnalysisCard extends Composite implements HasWidgets, StartAna
|
||||
private StartAnalysisDTO startAnalysisDTO;
|
||||
private RaceMap raceMap;
|
||||
|
||||
private SailingServiceAsync sailingServiceAsync;
|
||||
private StringMessages stringMessages;
|
||||
private final SailingServiceAsync sailingServiceAsync;
|
||||
private final ErrorReporter errorReporter;
|
||||
private final StringMessages stringMessages;
|
||||
private final RaceCompetitorSelectionModel competitorSelectionModel;
|
||||
|
||||
private final double WIND_LINE_ADVANTAGE_DIV_WIDTH_IN_PT = 185;
|
||||
@@ -80,9 +82,11 @@ public class StartAnalysisCard extends Composite implements HasWidgets, StartAna
|
||||
|
||||
private RaceMapResources raceMapResources;
|
||||
|
||||
public StartAnalysisCard(double leftCSSProperty, int cardId, StartAnalysisDTO startAnalysisDTO, SailingServiceAsync sailingServiceAsync, RaceMapResources raceMapResources) {
|
||||
public StartAnalysisCard(double leftCSSProperty, int cardId, StartAnalysisDTO startAnalysisDTO,
|
||||
SailingServiceAsync sailingServiceAsync, ErrorReporter errorReporter, RaceMapResources raceMapResources) {
|
||||
stringMessages = StringMessages.INSTANCE;
|
||||
this.sailingServiceAsync = sailingServiceAsync;
|
||||
this.errorReporter = errorReporter;
|
||||
this.raceMapResources = raceMapResources;
|
||||
competitorSelectionModel = new RaceCompetitorSelectionModel(/* hasMultiSelection */true);
|
||||
competitorSelectionModel.setCompetitors(startAnalysisDTO.getCompetitorDTOsFromStartAnaylsisCompetitorDTOs(), raceMap);
|
||||
@@ -167,10 +171,11 @@ public class StartAnalysisCard extends Composite implements HasWidgets, StartAna
|
||||
|
||||
|
||||
RaceTimesInfoProvider raceTimesInfoProvider = new RaceTimesInfoProvider(sailingServiceAsync,
|
||||
asyncActionsExecutor, null, Collections.singletonList(startAnalysisDTO.regattaAndRaceIdentifier), 5000l /* requestInterval */);
|
||||
asyncActionsExecutor, errorReporter,
|
||||
Collections.singletonList(startAnalysisDTO.regattaAndRaceIdentifier), 5000l /* requestInterval */);
|
||||
raceMap = new RaceMap(null, null, new RaceMapLifecycle(StringMessages.INSTANCE), raceMapSettings,
|
||||
sailingServiceAsync,
|
||||
asyncActionsExecutor, null, timer, competitorSelectionModel,
|
||||
asyncActionsExecutor, errorReporter, timer, competitorSelectionModel,
|
||||
new RaceCompetitorSet(competitorSelectionModel), StringMessages.INSTANCE,
|
||||
startAnalysisDTO.regattaAndRaceIdentifier, raceMapResources, /* showHeaderPanel */ true, new DefaultQuickRanksDTOProvider());
|
||||
raceTimesInfoProvider.addRaceTimesInfoProviderListener(raceMap);
|
||||
|
||||
+2
-1
@@ -188,7 +188,7 @@ AbsRelativeBearingToNextMarkAfterManeuver=Rumbo relativo absoluto a la siguiente
|
||||
RatioBetweenDistanceSailedWithAndWithoutManeuver=Ratio entre distancia navegada con y sin maniobra
|
||||
RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver=Ratio entre distancia navegada hacia la proyección del ángulo medio con y sin maniobra
|
||||
DurationLostByManeuver=Tiempo perdido por maniobra
|
||||
DurationLostByManeuverTowardMiddleAngleProjection=tiempo perdido por maniobra hacia la proyección del ángulo medio
|
||||
DurationLostByManeuverTowardMiddleAngleProjection=Tiempo perdido por maniobra hacia la proyección del ángulo medio
|
||||
JibingCount=Recuento de trasluchadas
|
||||
TackingCount=Recuento de viradas
|
||||
AbsTwaAtMaxTurningRate=TWA absoluto en velocidad máxima de giro
|
||||
@@ -199,3 +199,4 @@ PercentageOfMainCurveProgressUntilHighestSpeed=Porcentaje de progreso de curva p
|
||||
PercentageOfMainCurveProgressUntilMaxTurningRate=Porcentaje de progreso de curva principal hasta velocidad máxima de giro
|
||||
AbsTwaAtManeuverMiddle=TWA absoluto en mitad de maniobra
|
||||
GpsSamplingRate=Velocidad de muestreo de GPS
|
||||
RaceDuration=Duración de carrera
|
||||
+1
@@ -199,3 +199,4 @@ PercentageOfMainCurveProgressUntilHighestSpeed=Pourcentage de progression de la
|
||||
PercentageOfMainCurveProgressUntilMaxTurningRate=Pourcentage de progression de la courbe principale jusqu''à la vitesse angulaire max.
|
||||
AbsTwaAtManeuverMiddle=TWA absolu au milieu de la manœuvre
|
||||
GpsSamplingRate=Fréquence d''échantillonage GPS
|
||||
RaceDuration=Durée de la course
|
||||
+1
@@ -199,3 +199,4 @@ PercentageOfMainCurveProgressUntilHighestSpeed=最高速度までの主曲線進
|
||||
PercentageOfMainCurveProgressUntilMaxTurningRate=回転率最大速度までの主曲線進行の比率 (%)
|
||||
AbsTwaAtManeuverMiddle=マニューバー中間での絶対 TWA
|
||||
GpsSamplingRate=GPS サンプリング率
|
||||
RaceDuration=レース持続時間
|
||||
+2
-1
@@ -188,7 +188,7 @@ AbsRelativeBearingToNextMarkAfterManeuver=Rumo relativo absoluto até a marca se
|
||||
RatioBetweenDistanceSailedWithAndWithoutManeuver=Proporção entre distância navegada com e sem manobra
|
||||
RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver=Proporção entre distância navegada em direção à projeção do ângulo médio com e sem manobra
|
||||
DurationLostByManeuver=Duração perdida por manobra
|
||||
DurationLostByManeuverTowardMiddleAngleProjection=duração perdida por manobra em direção à projeção do ângulo médio
|
||||
DurationLostByManeuverTowardMiddleAngleProjection=Duração perdida por manobra em direção à projeção do ângulo médio
|
||||
JibingCount=Contagem de jaibe
|
||||
TackingCount=Contagem de cambada
|
||||
AbsTwaAtMaxTurningRate=TWA absoluto na taxa de viragem máxima
|
||||
@@ -199,3 +199,4 @@ PercentageOfMainCurveProgressUntilHighestSpeed=Porcentagem de progresso da curva
|
||||
PercentageOfMainCurveProgressUntilMaxTurningRate=Porcentagem de progresso da curva principal até velocidade de taxa de viragem máxima
|
||||
AbsTwaAtManeuverMiddle=TWA absoluto no meio da manobra
|
||||
GpsSamplingRate=Taxa de amostra de GPS
|
||||
RaceDuration=Duração da corrida
|
||||
+2
-1
@@ -188,7 +188,7 @@ AbsRelativeBearingToNextMarkAfterManeuver=Абс. относительное н
|
||||
RatioBetweenDistanceSailedWithAndWithoutManeuver=Соотношение пройденного расстояния с маневром и без
|
||||
RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver=Соотношение пройденного расстояния на срединную угловую проекцию с маневром и без
|
||||
DurationLostByManeuver=Потеря длительности за счет маневра
|
||||
DurationLostByManeuverTowardMiddleAngleProjection=потеря длительности за счет маневра на срединную угловую проекцию
|
||||
DurationLostByManeuverTowardMiddleAngleProjection=Потеря длительности за счет маневра на срединную угловую проекцию
|
||||
JibingCount=Поворотов фордевинд
|
||||
TackingCount=Поворотов оверштаг
|
||||
AbsTwaAtMaxTurningRate=Абс. TWA при макс. скорости поворота
|
||||
@@ -199,3 +199,4 @@ PercentageOfMainCurveProgressUntilHighestSpeed=Процент прохожден
|
||||
PercentageOfMainCurveProgressUntilMaxTurningRate=Процент прохождения основной кривой до макс. скорости поворота
|
||||
AbsTwaAtManeuverMiddle=Абс. TWA в середине маневра
|
||||
GpsSamplingRate=Частота дискретизации GPS
|
||||
RaceDuration=Длительность гонки
|
||||
+1
@@ -199,3 +199,4 @@ PercentageOfMainCurveProgressUntilHighestSpeed=最高速度前主要曲线进度
|
||||
PercentageOfMainCurveProgressUntilMaxTurningRate=最大回转率速度前主要曲线进度的百分比
|
||||
AbsTwaAtManeuverMiddle=操作中间的绝对实际风向角
|
||||
GpsSamplingRate=GPS 采样率
|
||||
RaceDuration=比赛轮次持续时间
|
||||
+1
-1
@@ -17,7 +17,7 @@ public enum BoatClassMasterdata {
|
||||
_49ER ("49er", true, 4.88, 1.93, BoatHullType.MONOHULL, true),
|
||||
_49ERFX ("49erFX", true, 4.88, 1.93, BoatHullType.MONOHULL, true, "49FX"),
|
||||
_420 ("420", true, 4.20, 1.65, BoatHullType.MONOHULL, true, "420er", "420M", "420W"),
|
||||
_470 ("470", true, 4.70, 1.68, BoatHullType.MONOHULL, true, "470er", "470M", "470W", "470 - M", "470 - W"),
|
||||
_470 ("470", true, 4.70, 1.68, BoatHullType.MONOHULL, true, "470er", "470M", "470W", "470 - M", "470 - W", "470 Men", "470 Women"),
|
||||
_5O5 ("5O5", true, 5.03, 1.88, BoatHullType.MONOHULL, true, "505", "5o5", "505er", "5o5er"),
|
||||
_5_5MR ("5.5mR", true, 9.50, 1.92, BoatHullType.MONOHULL, true, "5.5 Meter", "5.5 Metre", "5.5", "5.5M", "5.5-metre", "5.5 metre"),
|
||||
_6MR ("6mR", true, 11, 2.2, BoatHullType.MONOHULL, true, "6 Meter", "6 Metre", "6", "6M", "6-metre", "6 metre"),
|
||||
|
||||
+5
-1
@@ -46,7 +46,11 @@ public enum MaxPointsReason {
|
||||
/** Time limit Expired */
|
||||
TLE(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ true, /* appliesAtStartOfRace */ false),
|
||||
/** Standard Penalty by Race Committee; gives a certain number of penalty points on top of rank-inferred score */
|
||||
STP(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ false, /* appliesAtStartOfRace */ true);
|
||||
STP(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ false, /* appliesAtStartOfRace */ true),
|
||||
/** Disqualified after causing a tangle in an incident */
|
||||
DCT(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ true, /* appliesAtStartOfRace */ false),
|
||||
/** Retired after causing a tangle */
|
||||
RCT(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ true, /* appliesAtStartOfRace */ false);
|
||||
|
||||
private final boolean discardable;
|
||||
|
||||
|
||||
+1
@@ -18,6 +18,7 @@ public class BasicRaceDTO extends NamedDTO {
|
||||
|
||||
public Date startOfRace;
|
||||
public Date endOfRace;
|
||||
public Date raceFinishedTime;
|
||||
public TrackedRaceDTO trackedRace;
|
||||
|
||||
public BasicRaceDTO() {} // for GWT serialization only
|
||||
|
||||
-2
@@ -67,10 +67,8 @@ public abstract class PassAwareRaceLogAnalyzerTest<AnalyzerType extends RaceLogA
|
||||
RaceLogEvent minorEvent = createEvent(RaceLogEvent.class, 0, 0, UUID.randomUUID(), author);
|
||||
TargetPair pair = getTargetEventsAndResultForPassAwareTests(1, author);
|
||||
ResultType expectedResult = pair.getB();
|
||||
|
||||
pair.addAll(raceLog);
|
||||
raceLog.add(minorEvent);
|
||||
|
||||
assertEquals(expectedResult, analyzer.analyze());
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -30,7 +30,8 @@ public abstract class RaceLogAnalyzerTest<AnalyzerType extends RaceLogAnalyzer<?
|
||||
protected abstract AnalyzerType createAnalyzer(RaceLog raceLog);
|
||||
|
||||
protected static <T extends RaceLogEvent> T createEvent(Class<T> type, long milliseconds) {
|
||||
return createEvent(/* priority */ 0, type, milliseconds);
|
||||
final T result = createEvent(/* priority */ 0, type, milliseconds);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected static <T extends RaceLogEvent> T createEvent(int priority, Class<T> type, long milliseconds) {
|
||||
|
||||
+83
-28
@@ -7,6 +7,7 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
@@ -18,21 +19,36 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceStatusAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceStatusAnalyzer.Clock;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartProcedureChangedEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.SimpleRaceLogIdentifierImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.ReadonlyRacingProcedureFactory;
|
||||
import com.sap.sailing.domain.base.configuration.impl.EmptyRegattaConfiguration;
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
|
||||
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class RaceStatusAnalyzerTest extends PassAwareRaceLogAnalyzerTest<RaceStatusAnalyzer, RaceLogRaceStatus> {
|
||||
public class RaceStatusAnalyzerTest extends PassAwareRaceLogAnalyzerTest<RaceStatusAnalyzer, Pair<RaceLogRaceStatus, TimePoint>> {
|
||||
|
||||
private RacingProcedure racingProcedure = mock(RacingProcedure.class);
|
||||
private TimePoint now = MillisecondsTimePoint.now();
|
||||
private Clock constantTimeClock = ()->now;
|
||||
|
||||
@Override
|
||||
protected RaceStatusAnalyzer createAnalyzer(RaceLog raceLog) {
|
||||
return new RaceStatusAnalyzer(mock(RaceLogResolver.class), raceLog, racingProcedure);
|
||||
return new RaceStatusAnalyzer(mock(RaceLogResolver.class), raceLog, constantTimeClock, racingProcedure);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -40,7 +56,7 @@ public class RaceStatusAnalyzerTest extends PassAwareRaceLogAnalyzerTest<RaceSta
|
||||
RaceLogRaceStatusEvent event = createEvent(RaceLogRaceStatusEvent.class, 1, passId, author);
|
||||
when(event.getNextStatus()).thenReturn(RaceLogRaceStatus.RUNNING);
|
||||
doAnswer(new StatusVisitorAnswer()).when(event).accept(any(RaceLogEventVisitor.class));
|
||||
return new TargetPair(Arrays.asList(event), event.getNextStatus());
|
||||
return new TargetPair(Arrays.asList(event), new Pair<>(event.getNextStatus(), now));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,38 +65,46 @@ public class RaceStatusAnalyzerTest extends PassAwareRaceLogAnalyzerTest<RaceSta
|
||||
RaceLogRaceStatusEvent event = createEvent(RaceLogRaceStatusEvent.class, 1, passId, author);
|
||||
when(event.getNextStatus()).thenReturn(RaceLogRaceStatus.FINISHING);
|
||||
doAnswer(new StatusVisitorAnswer()).when(event).accept(any(RaceLogEventVisitor.class));
|
||||
return new TargetPair(Arrays.asList(event), event.getNextStatus());
|
||||
return new TargetPair(Arrays.asList(event), new Pair<>(event.getNextStatus(), now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnscheduldedForNone() {
|
||||
RaceLogEvent event1 = createEvent(RaceLogEvent.class, 1);
|
||||
raceLog.add(event1);
|
||||
assertEquals(RaceLogRaceStatus.UNSCHEDULED, analyzer.analyze());
|
||||
assertEquals(RaceLogRaceStatus.UNSCHEDULED, analyzer.analyze().getA());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMostRecent() {
|
||||
RaceLogRaceStatusEvent event1 = createEvent(RaceLogRaceStatusEvent.class, 1);
|
||||
when(event1.getNextStatus()).thenReturn(RaceLogRaceStatus.FINISHING);
|
||||
RaceLogRaceStatusEvent event2 = createEvent(RaceLogRaceStatusEvent.class, 2);
|
||||
when(event2.getNextStatus()).thenReturn(RaceLogRaceStatus.FINISHED);
|
||||
doAnswer(new StatusVisitorAnswer()).when(event2).accept(any(RaceLogEventVisitor.class));
|
||||
|
||||
LogEventAuthorImpl author = new LogEventAuthorImpl("author", 0);
|
||||
RaceLogRaceStatusEvent event1 = new RaceLogRaceStatusEventImpl(
|
||||
new MillisecondsTimePoint(1), author, /* passId */ 1, RaceLogRaceStatus.FINISHING);
|
||||
RaceLogRaceStatusEvent event2 = new RaceLogRaceStatusEventImpl(
|
||||
new MillisecondsTimePoint(2), author, /* passId */ 1, RaceLogRaceStatus.FINISHED);
|
||||
raceLog.add(event1);
|
||||
raceLog.add(event2);
|
||||
|
||||
assertEquals(event2.getNextStatus(), analyzer.analyze());
|
||||
assertEquals(event2.getNextStatus(), analyzer.analyze().getA());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinishingWithFinishedInFuture() {
|
||||
now = new MillisecondsTimePoint(2);
|
||||
LogEventAuthorImpl author = new LogEventAuthorImpl("author", 0);
|
||||
RaceLogRaceStatusEvent event1 = new RaceLogRaceStatusEventImpl(
|
||||
new MillisecondsTimePoint(1), author, /* passId */ 1, RaceLogRaceStatus.FINISHING);
|
||||
RaceLogRaceStatusEvent event2 = new RaceLogRaceStatusEventImpl(
|
||||
new MillisecondsTimePoint(3), author, /* passId */ 1, RaceLogRaceStatus.FINISHED);
|
||||
raceLog.add(event1);
|
||||
raceLog.add(event2);
|
||||
assertEquals(event1.getNextStatus(), analyzer.analyze().getA());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartphaseNotYetActive() {
|
||||
when(racingProcedure.isStartphaseActive(any(TimePoint.class), any(TimePoint.class))).thenReturn(false);
|
||||
|
||||
RaceLogStartTimeEvent event = createStartTimeEvent(MillisecondsTimePoint.now().plus(20000).asMillis(), true);
|
||||
raceLog.add(event);
|
||||
|
||||
assertEquals(RaceLogRaceStatus.SCHEDULED, analyzer.analyze());
|
||||
assertEquals(RaceLogRaceStatus.SCHEDULED, analyzer.analyze().getA());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -90,7 +114,7 @@ public class RaceStatusAnalyzerTest extends PassAwareRaceLogAnalyzerTest<RaceSta
|
||||
RaceLogStartTimeEvent event = createStartTimeEvent(MillisecondsTimePoint.now().plus(20000).asMillis(), true);
|
||||
raceLog.add(event);
|
||||
|
||||
assertEquals(RaceLogRaceStatus.STARTPHASE, analyzer.analyze());
|
||||
assertEquals(RaceLogRaceStatus.STARTPHASE, analyzer.analyze().getA());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,7 +124,7 @@ public class RaceStatusAnalyzerTest extends PassAwareRaceLogAnalyzerTest<RaceSta
|
||||
RaceLogStartTimeEvent event = createStartTimeEvent(0, false);
|
||||
raceLog.add(event);
|
||||
|
||||
assertEquals(RaceLogRaceStatus.RUNNING, analyzer.analyze());
|
||||
assertEquals(RaceLogRaceStatus.RUNNING, analyzer.analyze().getA());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -112,13 +136,47 @@ public class RaceStatusAnalyzerTest extends PassAwareRaceLogAnalyzerTest<RaceSta
|
||||
return startTime.minus(1);
|
||||
}
|
||||
}, racingProcedure);
|
||||
|
||||
when(racingProcedure.isStartphaseActive(any(TimePoint.class), any(TimePoint.class))).thenReturn(false);
|
||||
|
||||
RaceLogStartTimeEvent event = createStartTimeEvent(startTime);
|
||||
raceLog.add(event);
|
||||
|
||||
assertEquals(RaceLogRaceStatus.SCHEDULED, analyzer.analyze());
|
||||
assertEquals(RaceLogRaceStatus.SCHEDULED, analyzer.analyze().getA());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRaceStateStatusUpdateWithoutNewRaceLogEvent() throws InterruptedException {
|
||||
final TimePoint[] timeForClock = { MillisecondsTimePoint.now() };
|
||||
final RaceStatusAnalyzer.Clock clock = new RaceStatusAnalyzer.Clock() {
|
||||
@Override
|
||||
public TimePoint now() {
|
||||
return timeForClock[0];
|
||||
}
|
||||
};
|
||||
final int analyzeAndUpdateCachedRaceStatusCalls[] = new int[1];
|
||||
ReadonlyRaceState raceState = new ReadonlyRaceStateImpl(mock(RaceLogResolver.class), raceLog,
|
||||
new SimpleRaceLogIdentifierImpl("regatta", "column", "fleet"), clock, new ReadonlyRacingProcedureFactory(
|
||||
new EmptyRegattaConfiguration()), Collections.emptyMap()) {
|
||||
@Override
|
||||
protected void analyzeAndUpdateCachedRaceStatus() {
|
||||
analyzeAndUpdateCachedRaceStatusCalls[0]++;
|
||||
super.analyzeAndUpdateCachedRaceStatus();
|
||||
}
|
||||
};
|
||||
RaceLogStartProcedureChangedEvent startProcedureEvent = new RaceLogStartProcedureChangedEventImpl(
|
||||
timeForClock[0], mock(AbstractLogEventAuthor.class), /* passId */ 0, RacingProcedureType.RRS26);
|
||||
raceLog.add(startProcedureEvent);
|
||||
final TimePoint startTime = timeForClock[0].plus(Duration.ONE_MINUTE.times(10));
|
||||
RaceLogStartTimeEvent event = createStartTimeEvent(startTime);
|
||||
raceLog.add(event);
|
||||
assertEquals(startTime, raceState.getStartTime());
|
||||
assertEquals(RaceLogRaceStatus.SCHEDULED, raceState.getStatus());
|
||||
timeForClock[0] = timeForClock[0].plus(Duration.ONE_MINUTE.times(9)); // one minute before start; we should be in STARTPHASE
|
||||
assertEquals(RaceLogRaceStatus.STARTPHASE, raceState.getStatus());
|
||||
timeForClock[0] = timeForClock[0].plus(Duration.ONE_MINUTE.times(2)); // one minute after start; we should be RUNNING
|
||||
assertEquals(RaceLogRaceStatus.RUNNING, raceState.getStatus());
|
||||
timeForClock[0] = timeForClock[0].plus(Duration.ONE_MINUTE.times(2)); // three minutes after start; we should still be RUNNING, without recalculating
|
||||
final int analyzeAndUpdateCachedRaceStatusCallsBefore = analyzeAndUpdateCachedRaceStatusCalls[0];
|
||||
assertEquals(RaceLogRaceStatus.RUNNING, raceState.getStatus());
|
||||
assertEquals(analyzeAndUpdateCachedRaceStatusCalls[0], analyzeAndUpdateCachedRaceStatusCallsBefore);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -141,7 +199,7 @@ public class RaceStatusAnalyzerTest extends PassAwareRaceLogAnalyzerTest<RaceSta
|
||||
raceLog.add(event1);
|
||||
raceLog.add(event2);
|
||||
|
||||
assertEquals(event2.getNextStatus(), analyzer.analyze());
|
||||
assertEquals(event2.getNextStatus(), analyzer.analyze().getA());
|
||||
}
|
||||
|
||||
private static RaceLogStartTimeEvent createStartTimeEvent(long startTimeAsMillis, boolean isGreater) {
|
||||
@@ -155,10 +213,7 @@ public class RaceStatusAnalyzerTest extends PassAwareRaceLogAnalyzerTest<RaceSta
|
||||
}
|
||||
|
||||
private static RaceLogStartTimeEvent createStartTimeEvent(TimePoint startTime) {
|
||||
RaceLogStartTimeEvent event = createEvent(RaceLogStartTimeEvent.class, 1);
|
||||
when(event.getStartTime()).thenReturn(startTime);
|
||||
doAnswer(new StartTimeVisitorAnswer()).when(event).accept(any(RaceLogEventVisitor.class));
|
||||
return event;
|
||||
return new RaceLogStartTimeEventImpl(startTime, new LogEventAuthorImpl("Author", /* priority */ 0), /* pass */ 0, startTime);
|
||||
}
|
||||
|
||||
private static class StartTimeVisitorAnswer implements Answer<Void> {
|
||||
|
||||
+3
-12
@@ -140,33 +140,27 @@ public class RaceStateTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdvancePass() {
|
||||
public void testAdvancePass() throws InterruptedException {
|
||||
state.addChangedListener(listener);
|
||||
int oldPassId = raceLog.getCurrentPassId();
|
||||
|
||||
state.setAdvancePass(mock(TimePoint.class));
|
||||
|
||||
assertEquals(oldPassId + 1, raceLog.getCurrentPassId());
|
||||
verify(listener).onAdvancePass(state);
|
||||
verifyNoMoreInteractions(listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbort() {
|
||||
public void testAbort() throws InterruptedException {
|
||||
state.addChangedListener(listener);
|
||||
|
||||
state.setAborted(mock(TimePoint.class), false, Flags.NONE);
|
||||
|
||||
// TODO: change test when interface is complete
|
||||
verifyNoMoreInteractions(listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeneralRecall() {
|
||||
public void testGeneralRecall() throws InterruptedException {
|
||||
state.addChangedListener(listener);
|
||||
|
||||
state.setGeneralRecall(mock(TimePoint.class));
|
||||
|
||||
// TODO: change test when interface is complete
|
||||
verifyNoMoreInteractions(listener);
|
||||
}
|
||||
@@ -174,14 +168,11 @@ public class RaceStateTest {
|
||||
@Test
|
||||
public void testInvalidateAfterAdvancePass() throws InterruptedException {
|
||||
state.addChangedListener(listener);
|
||||
|
||||
state.forceNewStartTime(nowMock, new MillisecondsTimePoint(1));
|
||||
Thread.sleep(100);
|
||||
state.setFinishedTime(new MillisecondsTimePoint(10));
|
||||
state.setCourseDesign(nowMock, mock(CourseBase.class), CourseDesignerMode.ADMIN_CONSOLE);
|
||||
|
||||
state.setAdvancePass(mock(TimePoint.class));
|
||||
|
||||
assertNull(state.getStartTime());
|
||||
assertEquals(RaceLogRaceStatus.UNSCHEDULED, state.getStatus());
|
||||
verify(listener, times(1)).onAdvancePass(state);
|
||||
|
||||
+50
-17
@@ -1,5 +1,9 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogDependentStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
@@ -10,11 +14,19 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventCompar
|
||||
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRacingProcedure;
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.util.impl.ArrayListNavigableSet;
|
||||
|
||||
public class RaceStatusAnalyzer extends RaceLogAnalyzer<RaceLogRaceStatus> {
|
||||
|
||||
/**
|
||||
* Returns the status and the clock {@link TimePoint} at which it was calculated. That time point is obtained
|
||||
* from the {@link Clock} passed to this analyzer at construction time. It is queried at the time the analysis
|
||||
* takes place ({@link #performAnalysis()}.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class RaceStatusAnalyzer extends RaceLogAnalyzer<Pair<RaceLogRaceStatus, TimePoint>> {
|
||||
public interface Clock {
|
||||
TimePoint now();
|
||||
}
|
||||
@@ -24,26 +36,27 @@ public class RaceStatusAnalyzer extends RaceLogAnalyzer<RaceLogRaceStatus> {
|
||||
public TimePoint now() {
|
||||
return MillisecondsTimePoint.now();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private RaceLogResolver resolver;
|
||||
private final RaceLogResolver resolver;
|
||||
private final Clock clock;
|
||||
private final ReadonlyRacingProcedure racingProcedure;
|
||||
|
||||
public RaceStatusAnalyzer(RaceLogResolver resolver, RaceLog raceLog, ReadonlyRacingProcedure racingProcedure) {
|
||||
super(raceLog);
|
||||
this.eventDispatcher = new EventDispatcher(new StandardClock(), racingProcedure);
|
||||
this.resolver = resolver;
|
||||
this(resolver, raceLog, new StandardClock(), racingProcedure);
|
||||
}
|
||||
|
||||
public RaceStatusAnalyzer(RaceLogResolver resolver, RaceLog raceLog, Clock clock, ReadonlyRacingProcedure racingProcedure) {
|
||||
super(raceLog);
|
||||
this.eventDispatcher = new EventDispatcher(clock, racingProcedure);
|
||||
this.resolver = resolver;
|
||||
this.clock = clock;
|
||||
this.racingProcedure = racingProcedure;
|
||||
}
|
||||
|
||||
private static final Set<RaceLogRaceStatus> statusTypesToIgnoreIfEventNotValidYet = new HashSet<>(Arrays.asList(
|
||||
new RaceLogRaceStatus[] { RaceLogRaceStatus.FINISHED, RaceLogRaceStatus.FINISHING }));
|
||||
@Override
|
||||
protected RaceLogRaceStatus performAnalysis() {
|
||||
protected Pair<RaceLogRaceStatus, TimePoint> performAnalysis() {
|
||||
ArrayListNavigableSet<RaceLogRaceStatusEvent> statusEvents = new ArrayListNavigableSet<>(
|
||||
RaceLogRaceStatusEventComparator.INSTANCE);
|
||||
for (RaceLogEvent event : getPassEvents()) {
|
||||
@@ -51,21 +64,42 @@ public class RaceStatusAnalyzer extends RaceLogAnalyzer<RaceLogRaceStatus> {
|
||||
statusEvents.add((RaceLogRaceStatusEvent) event);
|
||||
}
|
||||
}
|
||||
final TimePoint now = clock.now();
|
||||
final EventDispatcher eventDispatcher = new EventDispatcher(now, racingProcedure);
|
||||
Set<RaceLogRaceStatus> statusesToIgnore = new HashSet<>();
|
||||
RaceLogRaceStatus result = RaceLogRaceStatus.UNSCHEDULED;
|
||||
for (RaceLogRaceStatusEvent event : statusEvents.descendingSet()) {
|
||||
event.accept(eventDispatcher);
|
||||
return eventDispatcher.nextStatus;
|
||||
// We need to read across a not yet valid FINISHED event and record that other FINISHED
|
||||
// events need to be ignored; if we find a not yet valid FINISHING event, ignore further FINISHING
|
||||
// events; but dispatch all other events (particularly start-related events) to the dispatcher:
|
||||
final boolean dispatch;
|
||||
if (statusTypesToIgnoreIfEventNotValidYet.contains(event.getNextStatus())) {
|
||||
if (event.getLogicalTimePoint().after(now)) { // event not valid yet
|
||||
statusesToIgnore.add(event.getNextStatus()); // but ignore events of same status with lesser relevance
|
||||
dispatch = false;
|
||||
} else {
|
||||
dispatch = true;
|
||||
}
|
||||
} else {
|
||||
dispatch = true;
|
||||
}
|
||||
if (dispatch) {
|
||||
event.accept(eventDispatcher);
|
||||
result = eventDispatcher.nextStatus;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return RaceLogRaceStatus.UNSCHEDULED;
|
||||
return new Pair<>(result, now);
|
||||
}
|
||||
|
||||
private class EventDispatcher extends BaseRaceLogEventVisitor {
|
||||
|
||||
private final Clock clock;
|
||||
private final TimePoint now;
|
||||
private final ReadonlyRacingProcedure racingProcedure;
|
||||
public RaceLogRaceStatus nextStatus;
|
||||
|
||||
public EventDispatcher(Clock clock, ReadonlyRacingProcedure racingProcedure) {
|
||||
this.clock = clock;
|
||||
public EventDispatcher(TimePoint now, ReadonlyRacingProcedure racingProcedure) {
|
||||
this.now = now;
|
||||
this.racingProcedure = racingProcedure;
|
||||
this.nextStatus = RaceLogRaceStatus.UNKNOWN;
|
||||
}
|
||||
@@ -80,7 +114,6 @@ public class RaceStatusAnalyzer extends RaceLogAnalyzer<RaceLogRaceStatus> {
|
||||
if (startTime == null) {
|
||||
nextStatus = RaceLogRaceStatus.PRESCHEDULED;
|
||||
} else {
|
||||
TimePoint now = clock.now();
|
||||
if (racingProcedure.isStartphaseActive(startTime, now)) {
|
||||
nextStatus = RaceLogRaceStatus.STARTPHASE;
|
||||
} else if (now.before(startTime)) {
|
||||
|
||||
+1
-3
@@ -1,12 +1,10 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.state;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEvents;
|
||||
|
||||
public interface RaceStateEventScheduler {
|
||||
|
||||
void scheduleStateEvents(Collection<RaceStateEvent> stateEvents);
|
||||
void scheduleStateEvents(Iterable<RaceStateEvent> stateEvents);
|
||||
|
||||
void unscheduleStateEvent(RaceStateEvents stateEventName);
|
||||
|
||||
|
||||
+1
-5
@@ -55,10 +55,6 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState {
|
||||
|
||||
private final AbstractLogEventAuthor author;
|
||||
|
||||
public static ReadonlyRaceState create(RaceLogResolver raceLogResolver, RaceLog raceLog) {
|
||||
return create(raceLogResolver, raceLog, /* forRaceLogIdentifier */ null, Collections.<SimpleRaceLogIdentifier, ReadonlyRaceState>emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link RaceState} with the initial racing procedure type set to a fallback value and an empty configuration.
|
||||
*/
|
||||
@@ -82,7 +78,7 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState {
|
||||
private RaceStateImpl(RaceLogResolver raceLogResolver, RaceLog raceLog, AbstractLogEventAuthor author, RaceStatusAnalyzer.Clock analyzersClock,
|
||||
RacingProcedureFactory procedureFactory) {
|
||||
super(raceLogResolver, raceLog, /* forRaceLogIdentifier */ null, analyzersClock, procedureFactory,
|
||||
Collections.<SimpleRaceLogIdentifier, ReadonlyRaceState>emptyMap(), /* update */ true);
|
||||
Collections.<SimpleRaceLogIdentifier, ReadonlyRaceState>emptyMap());
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
|
||||
+128
-27
@@ -2,6 +2,8 @@ package com.sap.sailing.domain.abstractlog.race.state.impl;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
|
||||
@@ -44,6 +46,9 @@ import com.sap.sailing.domain.common.racelog.RacingProcedureType;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.TimeRangeImpl;
|
||||
import com.sap.sse.util.WeakIdentityHashMap;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ReadonlyRaceState}. Use the static factory methods to instantiate your race state.
|
||||
@@ -55,11 +60,48 @@ import com.sap.sse.common.Util;
|
||||
* See {@link ReadonlyRaceStateImpl#update()} for the core of the algorithm.
|
||||
*/
|
||||
public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedListener {
|
||||
|
||||
public static ReadonlyRaceState create(RaceLogResolver raceLogResolver, RaceLog raceLog) {
|
||||
return create(raceLogResolver, raceLog, /* forRaceLogIdentifier */null,
|
||||
private static final WeakIdentityHashMap<RaceLog, WeakIdentityHashMap<RaceLogResolver, ReadonlyRaceState>> raceStateCache =
|
||||
new WeakIdentityHashMap<>();
|
||||
|
||||
/**
|
||||
* Obtains a race state for the combination of {@code raceLog} and {@code raceLogResolver}. The result is
|
||||
* cache using weak references to the race log and the race log resolver for quick retrieval upon equal
|
||||
* requests, saving memory, saving listeners and thereby avoiding more synchronization issues.
|
||||
*
|
||||
* See also bug4704.
|
||||
*/
|
||||
public static ReadonlyRaceState getOrCreate(RaceLogResolver raceLogResolver, RaceLog raceLog) {
|
||||
return getOrCreate(raceLogResolver, raceLog, /* forRaceLogIdentifier */null,
|
||||
Collections.<SimpleRaceLogIdentifier, ReadonlyRaceState> emptyMap());
|
||||
}
|
||||
|
||||
public static ReadonlyRaceState getOrCreate(RaceLogResolver raceLogResolver, RaceLog raceLog,
|
||||
SimpleRaceLogIdentifier forRaceLogIdentifier,
|
||||
Map<SimpleRaceLogIdentifier, ReadonlyRaceState> dependentRaceStates) {
|
||||
WeakIdentityHashMap<RaceLogResolver, ReadonlyRaceState> raceStatesForRaceLog;
|
||||
ReadonlyRaceState result = null;
|
||||
synchronized (raceStateCache) {
|
||||
raceStatesForRaceLog = raceStateCache.get(raceLog);
|
||||
if (raceStatesForRaceLog == null) {
|
||||
raceStatesForRaceLog = new WeakIdentityHashMap<>();
|
||||
raceStateCache.put(raceLog, raceStatesForRaceLog);
|
||||
} else {
|
||||
result = raceStatesForRaceLog.get(raceLogResolver);
|
||||
}
|
||||
if (result == null) {
|
||||
result = createInternal(raceLogResolver, raceLog, forRaceLogIdentifier, dependentRaceStates);
|
||||
raceStatesForRaceLog.put(raceLogResolver, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static final ReadonlyRaceState createInternal(RaceLogResolver raceLogResolver, RaceLog raceLog,
|
||||
SimpleRaceLogIdentifier forRaceLogIdentifier,
|
||||
Map<SimpleRaceLogIdentifier, ReadonlyRaceState> dependentRaceStates) {
|
||||
return create(raceLogResolver, raceLog, forRaceLogIdentifier, dependentRaceStates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ReadonlyRaceState}.
|
||||
@@ -109,7 +151,8 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
private RaceStateEventScheduler scheduler;
|
||||
|
||||
/**
|
||||
* We need one for each change in {@link RacingProcedureType}.
|
||||
* We need one for each change in {@link RacingProcedureType}. The analyzer uses the {@link #statusAnalyzerClock}
|
||||
* as its time source.
|
||||
*/
|
||||
private RaceStatusAnalyzer statusAnalyzer;
|
||||
private final RacingProcedureTypeAnalyzer racingProcedureAnalyzer;
|
||||
@@ -138,6 +181,22 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
private RacingProcedureType cachedRacingProcedureTypeNoFallback;
|
||||
|
||||
private RaceLogRaceStatus cachedRaceStatus;
|
||||
|
||||
/**
|
||||
* The time taken from {@link #statusAnalyzerClock} when the race status was last updated. Set to a valid
|
||||
* value whenever {@link #cachedRaceStatus} is set.
|
||||
*/
|
||||
private TimePoint clockTimePointWhenCachedRaceStatusWasSet;
|
||||
|
||||
/**
|
||||
* Time points determined during {@link #updateCachedRaceStatusAndValidity(RaceLogRaceStatus)} at which
|
||||
* the race status may change. If the time range between {@link #clockTimePointWhenCachedRaceStatusWasSet} and
|
||||
* the current {@link #statusAnalyzerClock clock} time point spans any of these, the {@link #cachedRaceStatus}
|
||||
* is to be considered invalid and needs to be re-calculated. Set to a valid but possibly empty iterable
|
||||
* whenever {@link #cachedRaceStatus} is set.
|
||||
*/
|
||||
private Iterable<TimePoint> timePointsWhenRaceStatusMayChange;
|
||||
|
||||
private int cachedPassId;
|
||||
private StartTimeFinderResult cachedStartTimeFinderResult;
|
||||
private TimePoint cachedFinishingTime;
|
||||
@@ -157,7 +216,7 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
SimpleRaceLogIdentifier forRaceLogIdentifier, RacingProcedureFactory procedureFactory,
|
||||
Map<SimpleRaceLogIdentifier, ReadonlyRaceState> dependentRaceStates) {
|
||||
this(raceLogResolver, raceLog, forRaceLogIdentifier, new RaceStatusAnalyzer.StandardClock(),
|
||||
procedureFactory, dependentRaceStates, /* update */true);
|
||||
procedureFactory, dependentRaceStates);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,14 +225,11 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
* new race state. This can help avoid endless recursions because this race state can be passed along
|
||||
* together with the identifier so that when again along a dependent call chain a race state is required
|
||||
* for that race log identifier, this one can be used.
|
||||
* @param update
|
||||
* if <code>true</code>, the race state will be updated whenever the underlying <code>raceLog</code>
|
||||
* changes.
|
||||
*/
|
||||
protected ReadonlyRaceStateImpl(RaceLogResolver raceLogResolver, RaceLog raceLog,
|
||||
SimpleRaceLogIdentifier forRaceLogIdentifier, Clock analyzersClock,
|
||||
RacingProcedureFactory procedureFactory,
|
||||
final Map<SimpleRaceLogIdentifier, ReadonlyRaceState> dependentRaceStates, boolean update) {
|
||||
final Map<SimpleRaceLogIdentifier, ReadonlyRaceState> dependentRaceStates) {
|
||||
this.raceLog = raceLog;
|
||||
this.raceLogResolver = raceLogResolver;
|
||||
this.procedureFactory = procedureFactory;
|
||||
@@ -295,9 +351,30 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
|
||||
@Override
|
||||
public RaceLogRaceStatus getStatus() {
|
||||
final TimePoint timePointForAnalysis = statusAnalyzerClock.now();
|
||||
final TimeRange timeRangeSinceLastStatusUpdate = new TimeRangeImpl(clockTimePointWhenCachedRaceStatusWasSet, timePointForAnalysis);
|
||||
if (overlapsTimePointForPotentialStatusChange(timeRangeSinceLastStatusUpdate)) {
|
||||
analyzeAndUpdateCachedRaceStatus();
|
||||
}
|
||||
return cachedRaceStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds out whether any of the time points in {@link #timePointsWhenRaceStatusMayChange} falls into the time range
|
||||
* provided. In this case we assume that a race status update may have happened between the time point when the
|
||||
* {@link #cachedRaceStatus} was updated last and the current request time point, forming the time range provided
|
||||
* as parameter here.
|
||||
*/
|
||||
private boolean overlapsTimePointForPotentialStatusChange(TimeRange timeRangeSinceLastStatusUpdate) {
|
||||
for (final TimePoint e : timePointsWhenRaceStatusMayChange) {
|
||||
if (timeRangeSinceLastStatusUpdate.includes(e)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TimePoint getStartTime() {
|
||||
return cachedStartTimeFinderResult.getStartTime();
|
||||
@@ -404,7 +481,7 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
} else {
|
||||
RaceLog resolvedRaceLog = raceLogResolver.resolve(dependentOnRaceIdentifier);
|
||||
if (resolvedRaceLog != null) {
|
||||
raceStateToObserve = ReadonlyRaceStateImpl.create(raceLogResolver, resolvedRaceLog,
|
||||
raceStateToObserve = ReadonlyRaceStateImpl.getOrCreate(raceLogResolver, resolvedRaceLog,
|
||||
dependentOnRaceIdentifier, dependentRaceStates);
|
||||
raceStateToObserve.addChangedListener(raceStateToObserveListener);
|
||||
}
|
||||
@@ -433,13 +510,6 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
recreateRacingProcedure(dependentRaceStates);
|
||||
changedListeners.onRacingProcedureChanged(this);
|
||||
}
|
||||
|
||||
RaceLogRaceStatus status = statusAnalyzer.analyze();
|
||||
if (!Util.equalsWithNull(cachedRaceStatus, status)) {
|
||||
cachedRaceStatus = status;
|
||||
changedListeners.onStatusChanged(this);
|
||||
}
|
||||
|
||||
int passId = raceLog.getCurrentPassId();
|
||||
if (cachedPassId != passId) {
|
||||
cachedPassId = passId;
|
||||
@@ -448,38 +518,33 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
cachedRacingProcedureType = null;
|
||||
cachedRacingProcedureTypeNoFallback = null;
|
||||
}
|
||||
|
||||
StartTimeFinderResult startTimeFinderResult = startTimeAnalyzer.analyze();
|
||||
if (!Util.equalsWithNull(cachedStartTimeFinderResult, startTimeFinderResult)) {
|
||||
cachedStartTimeFinderResult = startTimeFinderResult;
|
||||
changedListeners.onStartTimeChanged(this);
|
||||
}
|
||||
adjustObserverForRelativeStartTime(startTimeFinderResult, dependentRaceStates);
|
||||
|
||||
TimePoint finishingTime = finishingTimeAnalyzer.analyze();
|
||||
if (!Util.equalsWithNull(cachedFinishingTime, finishingTime)) {
|
||||
cachedFinishingTime = finishingTime;
|
||||
changedListeners.onFinishingTimeChanged(this);
|
||||
}
|
||||
|
||||
TimePoint finishedTime = finishedTimeAnalyzer.analyze();
|
||||
if (!Util.equalsWithNull(cachedFinishedTime, finishedTime)) {
|
||||
cachedFinishedTime = finishedTime;
|
||||
changedListeners.onFinishedTimeChanged(this);
|
||||
}
|
||||
|
||||
analyzeAndUpdateCachedRaceStatus(); // do this after start and finishing times have been updated
|
||||
TimeRange protest = protestTimeAnalyzer.analyze();
|
||||
if (!Util.equalsWithNull(cachedProtest, protest)) {
|
||||
cachedProtest = protest;
|
||||
changedListeners.onProtestTimeChanged(this);
|
||||
}
|
||||
|
||||
CompetitorResults positionedCompetitors = finishPositioningListAnalyzer.analyze();
|
||||
if (!Util.equalsWithNull(cachedPositionedCompetitors, positionedCompetitors)) {
|
||||
cachedPositionedCompetitors = positionedCompetitors;
|
||||
changedListeners.onFinishingPositioningsChanged(this);
|
||||
}
|
||||
|
||||
CompetitorResults confirmedPositionedCompetitors = confirmedFinishPositioningListAnalyzer.analyze();
|
||||
if (!Util.equalsWithNull(cachedConfirmedPositionedCompetitors, confirmedPositionedCompetitors)) {
|
||||
cachedConfirmedPositionedCompetitors = confirmedPositionedCompetitors;
|
||||
@@ -487,13 +552,11 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
changedListeners.onFinishingPositionsConfirmed(this);
|
||||
}
|
||||
}
|
||||
|
||||
CourseBase courseDesign = courseDesignerAnalyzer.analyze();
|
||||
if (!Util.equalsWithNull(cachedCourseDesign, courseDesign)) {
|
||||
cachedCourseDesign = courseDesign;
|
||||
changedListeners.onCourseDesignChanged(this);
|
||||
}
|
||||
|
||||
Wind windFix = lastWindFixAnalyzer.analyze();
|
||||
if (!Util.equalsWithNull(cachedWindFix, windFix)) {
|
||||
cachedWindFix = windFix;
|
||||
@@ -501,6 +564,46 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method has protected visibility (and not private) to allow instrumenting by test cases
|
||||
*/
|
||||
protected void analyzeAndUpdateCachedRaceStatus() {
|
||||
Pair<RaceLogRaceStatus, TimePoint> statusAndTimePoint = statusAnalyzer.analyze();
|
||||
if (!Util.equalsWithNull(cachedRaceStatus, statusAndTimePoint)) {
|
||||
updateCachedRaceStatusAndValidity(statusAndTimePoint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the {@link #cachedRaceStatus} and calculates and remembers its validity, based on
|
||||
* {@link ReadonlyRacingProcedure#createStartStateEvents(TimePoint)} and which of those have already
|
||||
* passed at the current clock time and which ones are still lying ahead.
|
||||
*/
|
||||
private void updateCachedRaceStatusAndValidity(Pair<RaceLogRaceStatus, TimePoint> statusAndTimePoint) {
|
||||
final RaceLogRaceStatus oldRaceStatus = cachedRaceStatus;
|
||||
cachedRaceStatus = statusAndTimePoint.getA();
|
||||
clockTimePointWhenCachedRaceStatusWasSet = statusAndTimePoint.getB();
|
||||
if (getStartTimeFinderResult() == null || getStartTime() == null) {
|
||||
timePointsWhenRaceStatusMayChange = Collections.emptyList();
|
||||
} else {
|
||||
final TimePoint startTime = getStartTime();
|
||||
List<TimePoint> newTimePointsWhenRaceStatusMayChange = new LinkedList<>();
|
||||
for (final RaceStateEvent e : racingProcedure.createStartStateEvents(startTime)) {
|
||||
newTimePointsWhenRaceStatusMayChange.add(e.getTimePoint());
|
||||
}
|
||||
if (getFinishingTime() != null) {
|
||||
newTimePointsWhenRaceStatusMayChange.add(getFinishingTime());
|
||||
}
|
||||
if (getFinishedTime() != null) {
|
||||
newTimePointsWhenRaceStatusMayChange.add(getFinishedTime());
|
||||
}
|
||||
timePointsWhenRaceStatusMayChange = newTimePointsWhenRaceStatusMayChange;
|
||||
}
|
||||
if (!Util.equalsWithNull(oldRaceStatus, cachedRaceStatus)) {
|
||||
changedListeners.onStatusChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void recreateRacingProcedure(Map<SimpleRaceLogIdentifier, ReadonlyRaceState> dependentRaceStates) {
|
||||
if (racingProcedure != null) {
|
||||
removeChangedListener(racingProcedure);
|
||||
@@ -509,10 +612,8 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
racingProcedure = procedureFactory.createRacingProcedure(cachedRacingProcedureType, raceLog, raceLogResolver);
|
||||
racingProcedure.setStateEventScheduler(scheduler);
|
||||
addChangedListener(racingProcedure);
|
||||
|
||||
statusAnalyzer = new RaceStatusAnalyzer(raceLogResolver, raceLog, statusAnalyzerClock, racingProcedure);
|
||||
// let's do an update because status might have changed with new procedure
|
||||
update(dependentRaceStates);
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.RaceState;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.RaceStateChangedListener;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.RaceStateEventProcessor;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.RaceStateEventScheduler;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
|
||||
@@ -122,6 +123,13 @@ public interface ReadonlyRacingProcedure extends RaceStateEventProcessor, RaceSt
|
||||
RacingProcedurePrerequisite checkPrerequisitesForStart(TimePoint now, TimePoint startTime,
|
||||
RacingProcedurePrerequisite.FulfillmentFunction function);
|
||||
|
||||
|
||||
/**
|
||||
* Delivers the time points and types of the events around the start, each optionally
|
||||
* leading to a change in race status.
|
||||
*/
|
||||
Iterable<RaceStateEvent> createStartStateEvents(TimePoint startTime);
|
||||
|
||||
/**
|
||||
* This method is called by the framework. You don't need to call it.
|
||||
*/
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.basic.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
@@ -66,7 +65,7 @@ public class BasicRacingProcedureImpl extends BaseRacingProcedure {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
public Iterable<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
return Arrays.<RaceStateEvent>asList(new RaceStateEventImpl(startTime, RaceStateEvents.START));
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ess.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
@@ -64,7 +63,7 @@ public class ESSRacingProcedureImpl extends BaseRacingProcedure implements ESSRa
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
public Iterable<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
return Arrays.<RaceStateEvent> asList(new RaceStateEventImpl(startTime.minus(startPhaseAPDownInterval),
|
||||
RaceStateEvents.ESS_AP_DOWN), new RaceStateEventImpl(startTime.minus(startPhaseESSThreeUpInterval),
|
||||
RaceStateEvents.ESS_THREE_UP), new RaceStateEventImpl(startTime.minus(startPhaseESSTwoUpInterval),
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.gate.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
@@ -119,7 +118,7 @@ public class GateStartRacingProcedureImpl extends BaseRacingProcedure implements
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
public Iterable<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
return Arrays.<RaceStateEvent> asList(
|
||||
new RaceStateEventImpl(startTime.minus(startPhaseClassOverGolfUpInterval),
|
||||
RaceStateEvents.GATE_CLASS_OVER_GOLF_UP),
|
||||
|
||||
-2
@@ -276,8 +276,6 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
|
||||
return configuration;
|
||||
}
|
||||
|
||||
protected abstract Collection<RaceStateEvent> createStartStateEvents(TimePoint startTime);
|
||||
|
||||
@Override
|
||||
public void onStartTimeChanged(ReadonlyRaceState state) {
|
||||
getChangedListeners().onActiveFlagsChanged(this);
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
@@ -81,7 +80,7 @@ public class LeagueRacingProcedureImpl extends BaseRacingProcedure implements Le
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
public Iterable<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
// Remark: We are reusing here CLASS_UP, STARTMODE_UP and STARTMODE_DOWN from the RRS26 procedure
|
||||
// The question is why there are no generic CLASS_UP, STARTMODE_UP and STARTMODE_DOWN events
|
||||
return Arrays.<RaceStateEvent> asList(
|
||||
|
||||
-3
@@ -28,17 +28,14 @@ public abstract class ConfigurableStartModeFlagRacingProcedureImpl extends BaseR
|
||||
public ConfigurableStartModeFlagRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author,
|
||||
ConfigurableStartModeFlagRacingProcedureConfiguration configuration, RaceLogResolver raceLogResolver) {
|
||||
super(raceLog, author, configuration, raceLogResolver);
|
||||
|
||||
RacingProcedureTypeAnalyzer procedureAnalyzer = new RacingProcedureTypeAnalyzer(raceLog);
|
||||
if (configuration.getStartModeFlags() != null) {
|
||||
this.startModeFlagAnalyzer = new StartModeFlagFinder(procedureAnalyzer, raceLog, configuration.getStartModeFlags());
|
||||
} else {
|
||||
this.startModeFlagAnalyzer = new StartModeFlagFinder(procedureAnalyzer, raceLog, getDefaultStartModeFlags());
|
||||
}
|
||||
|
||||
this.cachedStartmodeFlag = getDefaultStartMode();
|
||||
this.startmodeFlagHasBeenSet = false;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.line.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -64,7 +63,7 @@ public class RRS26RacingProcedureImpl extends ConfigurableStartModeFlagRacingPro
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
public Iterable<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
return Arrays.<RaceStateEvent> asList(
|
||||
new RaceStateEventImpl(startTime.minus(startPhaseClassUpInterval), RaceStateEvents.RRS26_CLASS_UP),
|
||||
new RaceStateEventImpl(startTime.minus(startPhaseStartModeUpInterval), RaceStateEvents.RRS26_STARTMODE_UP),
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.line.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -69,7 +68,7 @@ public class SWCRacingProcedureImpl extends ConfigurableStartModeFlagRacingProce
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
public Iterable<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
|
||||
return Arrays.<RaceStateEvent> asList(
|
||||
new RaceStateEventImpl(startTime.minus(CLASS_AND_STARTMODE_UP_INTERVAL), RaceStateEvents.SWC_CLASS_AND_STARTMODE_UP),
|
||||
new RaceStateEventImpl(startTime.minus(FIVE_MINUTES_FLAG_UP_INTERVAL), RaceStateEvents.SWC_FIVE_UP),
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@ package com.sap.sailing.domain.swisstimingadapter.persistence.impl;
|
||||
|
||||
public enum FieldNames {
|
||||
// SwissTiming configuration parameters:
|
||||
ST_CONFIG_NAME, ST_CONFIG_HOSTNAME, ST_CONFIG_PORT, ST_CONFIG_JSON_URL, ST_ARCHIVE_JSON_URL,
|
||||
ST_CONFIG_NAME, ST_CONFIG_HOSTNAME, ST_CONFIG_PORT, ST_CONFIG_JSON_URL, ST_CONFIG_UPDATE_URL,
|
||||
ST_CONFIG_UPDATE_USERNAME, ST_CONFIG_UPDATE_PASSWORD, ST_ARCHIVE_JSON_URL,
|
||||
|
||||
// last message count field:
|
||||
LAST_MESSAGE_COUNT,
|
||||
|
||||
+9
-4
@@ -37,8 +37,8 @@ public class SwissTimingAdapterPersistenceImpl implements SwissTimingAdapterPers
|
||||
DBCollection stConfigs = database.getCollection(CollectionNames.SWISSTIMING_CONFIGURATIONS.name());
|
||||
for (DBObject o : stConfigs.find()) {
|
||||
SwissTimingConfiguration stConfig = loadSwissTimingConfiguration(o);
|
||||
// the old swisstiming config was not based on a json URL -> ignore such configs
|
||||
if(stConfig.getJsonURL() != null) {
|
||||
// the old SwissTiming configuration was not based on a JSON URL -> ignore such configurations
|
||||
if (stConfig.getJsonURL() != null) {
|
||||
result.add(stConfig);
|
||||
}
|
||||
}
|
||||
@@ -57,8 +57,10 @@ public class SwissTimingAdapterPersistenceImpl implements SwissTimingAdapterPers
|
||||
String jsonURL = (String) object.get(FieldNames.ST_CONFIG_JSON_URL.name());
|
||||
String hostname = (String) object.get(FieldNames.ST_CONFIG_HOSTNAME.name());
|
||||
Integer port = (Integer) object.get(FieldNames.ST_CONFIG_PORT.name());
|
||||
|
||||
return swissTimingFactory.createSwissTimingConfiguration(name, jsonURL, hostname, port);
|
||||
String updateURL = (String) object.get(FieldNames.ST_CONFIG_UPDATE_URL.name());
|
||||
String updateUsername = (String) object.get(FieldNames.ST_CONFIG_UPDATE_USERNAME.name());
|
||||
String updatePassword = (String) object.get(FieldNames.ST_CONFIG_UPDATE_PASSWORD.name());
|
||||
return swissTimingFactory.createSwissTimingConfiguration(name, jsonURL, hostname, port, updateURL, updateUsername, updatePassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,6 +98,9 @@ public class SwissTimingAdapterPersistenceImpl implements SwissTimingAdapterPers
|
||||
result.put(FieldNames.ST_CONFIG_JSON_URL.name(), swissTimingConfiguration.getJsonURL());
|
||||
result.put(FieldNames.ST_CONFIG_HOSTNAME.name(), swissTimingConfiguration.getHostname());
|
||||
result.put(FieldNames.ST_CONFIG_PORT.name(), swissTimingConfiguration.getPort());
|
||||
result.put(FieldNames.ST_CONFIG_UPDATE_URL.name(), swissTimingConfiguration.getUpdateURL());
|
||||
result.put(FieldNames.ST_CONFIG_UPDATE_USERNAME.name(), swissTimingConfiguration.getUpdateUsername());
|
||||
result.put(FieldNames.ST_CONFIG_UPDATE_PASSWORD.name(), swissTimingConfiguration.getUpdatePassword());
|
||||
|
||||
stConfigCollection.insert(result);
|
||||
}
|
||||
|
||||
+10
-1
@@ -54,6 +54,9 @@ public class SwissTimingConnectivityParamsHandler extends AbstractRaceTrackingCo
|
||||
private static final String PORT = "port";
|
||||
private static final String BOAT_CLASS_NAME = "boatClassName";
|
||||
private static final String HOSTNAME = "hostname";
|
||||
private static final String UPDATE_URL = "updateURL";
|
||||
private static final String UPDATE_USERNAME = "updateUsername";
|
||||
private static final String UPDATE_PASSWORD = "updatePassword";
|
||||
private final RaceLogStore raceLogStore;
|
||||
private final RegattaLogStore regattaLogStore;
|
||||
private final DomainFactory domainFactory;
|
||||
@@ -78,6 +81,9 @@ public class SwissTimingConnectivityParamsHandler extends AbstractRaceTrackingCo
|
||||
result.put(START_LIST, createStartListDBObject(stParams));
|
||||
result.put(DELAY_TO_LIVE_IN_MILLIS, stParams.getDelayToLiveInMillis());
|
||||
result.put(USE_INTERNAL_MARK_PASSING_ALGORITHM, stParams.isUseInternalMarkPassingAlgorithm());
|
||||
result.put(UPDATE_URL, stParams.getUpdateURL());
|
||||
result.put(UPDATE_USERNAME, stParams.getUpdateUsername());
|
||||
result.put(UPDATE_PASSWORD, stParams.getUpdatePassword());
|
||||
addWindTrackingParameters(stParams, result);
|
||||
return result;
|
||||
}
|
||||
@@ -175,7 +181,10 @@ public class SwissTimingConnectivityParamsHandler extends AbstractRaceTrackingCo
|
||||
map.get(START_LIST) == null ? null : createStartListFromDBObject((String) map.get(RACE_ID), (BasicDBList) map.get(START_LIST)),
|
||||
((Number) map.get(DELAY_TO_LIVE_IN_MILLIS)).longValue(),
|
||||
swissTimingFactory, domainFactory, raceLogStore, regattaLogStore,
|
||||
(boolean) map.get(USE_INTERNAL_MARK_PASSING_ALGORITHM), isTrackWind(map), isCorrectWindDirectionByMagneticDeclination(map));
|
||||
(boolean) map.get(USE_INTERNAL_MARK_PASSING_ALGORITHM), isTrackWind(map), isCorrectWindDirectionByMagneticDeclination(map),
|
||||
(String) map.get(UPDATE_URL),
|
||||
(String) map.get(UPDATE_USERNAME),
|
||||
(String) map.get(UPDATE_PASSWORD));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+10
-1
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -18,6 +19,7 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.DomainFactoryImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
@@ -70,10 +72,17 @@ public interface DomainFactory {
|
||||
RaceTrackingConnectivityParameters createTrackingConnectivityParameters(String hostname, int port, String raceID,
|
||||
String raceName, String raceDescription, BoatClass boatClass, StartList startList,
|
||||
long delayToLiveInMillis, SwissTimingFactory swissTimingFactory, DomainFactory domainFactory,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination);
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, String updateURL, String updateUsername, String updatePassword);
|
||||
|
||||
ControlPoint getOrCreateControlPoint(String description, Iterable<Serializable> deviceIds, MarkType markType);
|
||||
|
||||
RaceDefinition createRaceDefinition(Regatta regatta, String swissTimingRaceID, Map<Competitor, Boat> competitorsAndBoats,
|
||||
List<ControlPoint> courseDefinition, String raceName, String raceIdForRaceDefinition);
|
||||
|
||||
/**
|
||||
* Adds update handlers that forward events about a race, such as start time changes, course changes
|
||||
* or postponents, to an update URL using specific REST requests.
|
||||
*/
|
||||
void addUpdateHandlers(String updateURL, String username, String password, Serializable eventId,
|
||||
RaceDefinition raceDefinition, DynamicTrackedRace trackedRace) throws URISyntaxException;
|
||||
}
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@@ -16,9 +17,9 @@ public interface SailMasterListener {
|
||||
|
||||
void receivedClockAtMark(String raceID, List<Util.Triple<Integer, TimePoint, String>> markIndicesTimePointsAndBoatIDs);
|
||||
|
||||
void receivedStartList(String raceID, StartList startList);
|
||||
void receivedStartList(String raceID, StartList startList) throws URISyntaxException;
|
||||
|
||||
void receivedCourseConfiguration(String raceID, Course course);
|
||||
void receivedCourseConfiguration(String raceID, Course course) throws URISyntaxException;
|
||||
|
||||
void receivedAvailableRaces(Iterable<Race> races);
|
||||
|
||||
|
||||
+1
-3
@@ -26,12 +26,10 @@ public interface SwissTimingAdapter {
|
||||
* is specified, a regatta lookup is performed with that identifier; if the regatta is found, it is used
|
||||
* to add the races to. Otherwise, a default regatta as described above will be created and used.
|
||||
* @param useInternalMarkPassingAlgorithm use our own instead of the SwissTiming-provided mark passing / split times
|
||||
* @param trackWind TODO
|
||||
* @param correctWindDirectionByMagneticDeclination TODO
|
||||
*/
|
||||
RaceHandle addSwissTimingRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, String raceID,
|
||||
String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
|
||||
StartList startList, RaceLogStore logStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination)
|
||||
StartList startList, RaceLogStore logStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, String updateURL, String updateUsername, String updatePassword)
|
||||
throws InterruptedException, UnknownHostException, IOException, ParseException, Exception;
|
||||
|
||||
StartList readStartListForRace(String raceId, RegattaResults regattaResults);
|
||||
|
||||
+6
@@ -14,4 +14,10 @@ public interface SwissTimingConfiguration {
|
||||
String getHostname();
|
||||
|
||||
Integer getPort();
|
||||
|
||||
String getUpdateURL();
|
||||
|
||||
String getUpdateUsername();
|
||||
|
||||
String getUpdatePassword();
|
||||
}
|
||||
+6
-12
@@ -49,20 +49,14 @@ public interface SwissTimingFactory {
|
||||
|
||||
SailMasterTransceiver createSailMasterTransceiver();
|
||||
|
||||
SwissTimingConfiguration createSwissTimingConfiguration(String name, String jsonURL, String hostname, Integer port);
|
||||
SwissTimingConfiguration createSwissTimingConfiguration(String name, String jsonURL, String hostname, Integer port, String updateURL, String updateUsername, String updatePassword);
|
||||
|
||||
SwissTimingRaceTracker createRaceTracker(String raceID, String raceName, String raceDescription,
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore,
|
||||
boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, SwissTimingTrackingConnectivityParameters connectivityParams) throws InterruptedException, UnknownHostException,
|
||||
IOException, ParseException;
|
||||
SwissTimingRaceTracker createRaceTracker(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore,
|
||||
DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
throws InterruptedException, UnknownHostException, IOException, ParseException;
|
||||
|
||||
RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription,
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
|
||||
WindStore windStore, boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
RaceTracker createRaceTracker(Regatta regatta, WindStore windStore, DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
RaceLogResolver raceLogResolver, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
throws UnknownHostException, InterruptedException, IOException, ParseException;
|
||||
|
||||
Race createRace(String raceId, String raceName, String description, BoatClass boatClass);
|
||||
|
||||
+29
-2
@@ -1,6 +1,8 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
@@ -50,9 +52,14 @@ import com.sap.sailing.domain.swisstimingadapter.RaceType;
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceType.OlympicRaceCode;
|
||||
import com.sap.sailing.domain.swisstimingadapter.StartList;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.impl.CourseDesignUpdateHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.FinishTimeUpdateHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.RaceAbortedHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.StartTimeUpdateHandler;
|
||||
import com.sap.sse.common.Named;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
@@ -402,9 +409,29 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
String raceID, String raceName, String raceDescription, BoatClass boatClass, StartList startList,
|
||||
long delayToLiveInMillis, SwissTimingFactory swissTimingFactory, DomainFactory domainFactory,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm,
|
||||
boolean trackWind, boolean correctWindDirectionByMagneticDeclination) {
|
||||
boolean trackWind, boolean correctWindDirectionByMagneticDeclination, String updateURL,
|
||||
String updateUsername, String updatePassword) {
|
||||
return new SwissTimingTrackingConnectivityParameters(hostname, port, raceID, raceName, raceDescription,
|
||||
boatClass, startList, delayToLiveInMillis, swissTimingFactory, domainFactory, raceLogStore,
|
||||
regattaLogStore, useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination);
|
||||
regattaLogStore, useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination,
|
||||
updateURL, updateUsername, updatePassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUpdateHandlers(String updateURL, String username, String password, Serializable eventId,
|
||||
RaceDefinition raceDefinition, DynamicTrackedRace trackedRace) throws URISyntaxException {
|
||||
final URI updateURI = new URI(updateURL);
|
||||
CourseDesignUpdateHandler courseDesignHandler = new CourseDesignUpdateHandler(
|
||||
updateURI, username, password, eventId, raceDefinition.getId());
|
||||
StartTimeUpdateHandler startTimeHandler = new StartTimeUpdateHandler(
|
||||
updateURI, username, password, eventId,
|
||||
raceDefinition.getId(), trackedRace.getTrackedRegatta().getRegatta());
|
||||
RaceAbortedHandler raceAbortedHandler = new RaceAbortedHandler(
|
||||
updateURI, username, password, eventId,
|
||||
raceDefinition.getId());
|
||||
final FinishTimeUpdateHandler finishTimeUpdateHandler = new FinishTimeUpdateHandler(updateURI, username, password, eventId,
|
||||
raceDefinition.getId(), trackedRace.getTrackedRegatta().getRegatta());
|
||||
baseDomainFactory.addUpdateHandlers(trackedRace, courseDesignHandler, startTimeHandler, raceAbortedHandler,
|
||||
finishTimeUpdateHandler);
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -69,12 +69,13 @@ public class SwissTimingAdapterImpl implements SwissTimingAdapter {
|
||||
public RaceHandle addSwissTimingRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, String raceID,
|
||||
String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
|
||||
StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds,
|
||||
boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) throws Exception {
|
||||
boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination,
|
||||
String updateURL, String updateUsername, String updatePassword) throws Exception {
|
||||
return trackerManager.addRace(regattaToAddTo,
|
||||
swissTimingDomainFactory.createTrackingConnectivityParameters(hostname, port, raceID, raceName,
|
||||
raceDescription, boatClass, startList, DEFAULT_SWISSTIMING_LIVE_DELAY_IN_MILLISECONDS,
|
||||
swissTimingFactory, swissTimingDomainFactory, raceLogStore, regattaLogStore,
|
||||
useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination),
|
||||
useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination, updateURL, updateUsername, updatePassword),
|
||||
timeoutInMilliseconds);
|
||||
}
|
||||
|
||||
@@ -118,9 +119,9 @@ public class SwissTimingAdapterImpl implements SwissTimingAdapter {
|
||||
Person person = persons.get(crewMember.getPersonID());
|
||||
crew.add(new CrewMemberImpl(
|
||||
person.getGivenName() + " " + person.getFamilyName(),
|
||||
person.getNOC().name(), crewMember.getPosition().name()));
|
||||
(person.getNOC()==null)?null:(person.getNOC().name()), crewMember.getPosition().name()));
|
||||
}
|
||||
String nationality = team.getNOC().name();
|
||||
String nationality = team.getNOC()==null?null:team.getNOC().name();
|
||||
CompetitorWithID competitor = new CompetitorWithID(team.getTeamID(),
|
||||
boat.getSailNumber(), nationality, team.getTeamName(), crew);
|
||||
competitors.add(competitor);
|
||||
|
||||
+18
-1
@@ -7,13 +7,19 @@ public class SwissTimingConfigurationImpl implements SwissTimingConfiguration {
|
||||
private final String jsonURL;
|
||||
private final String hostname;
|
||||
private final Integer port;
|
||||
private final String updateURL;
|
||||
private final String updateUsername;
|
||||
private final String updatePassword;
|
||||
|
||||
public SwissTimingConfigurationImpl(String name, String jsonURL, String hostname, Integer port) {
|
||||
public SwissTimingConfigurationImpl(String name, String jsonURL, String hostname, Integer port, String updateURL, String updateUsername, String updatePassword) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.jsonURL = jsonURL;
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
this.updateURL = updateURL;
|
||||
this.updateUsername = updateUsername;
|
||||
this.updatePassword = updatePassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -36,4 +42,15 @@ public class SwissTimingConfigurationImpl implements SwissTimingConfiguration {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getUpdateURL() {
|
||||
return updateURL;
|
||||
}
|
||||
|
||||
public String getUpdateUsername() {
|
||||
return updateUsername;
|
||||
}
|
||||
|
||||
public String getUpdatePassword() {
|
||||
return updatePassword;
|
||||
}
|
||||
}
|
||||
+11
-17
@@ -17,7 +17,6 @@ import com.sap.sailing.domain.swisstimingadapter.Race;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterConnector;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterMessage;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterTransceiver;
|
||||
import com.sap.sailing.domain.swisstimingadapter.StartList;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingArchiveConfiguration;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingConfiguration;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
@@ -83,32 +82,27 @@ public class SwissTimingFactoryImpl implements SwissTimingFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SwissTimingConfiguration createSwissTimingConfiguration(String name, String jsonURL, String hostname, Integer port) {
|
||||
return new SwissTimingConfigurationImpl(name, jsonURL, hostname, port);
|
||||
public SwissTimingConfiguration createSwissTimingConfiguration(String name, String jsonURL, String hostname,
|
||||
Integer port, String updateURL, String updateUsername, String updatePassword) {
|
||||
return new SwissTimingConfigurationImpl(name, jsonURL, hostname, port, updateURL, updateUsername, updatePassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SwissTimingRaceTracker createRaceTracker(String raceID, String raceName, String raceDescription,
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore,
|
||||
boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
public SwissTimingRaceTracker createRaceTracker(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
WindStore windStore, DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
RaceLogResolver raceLogResolver, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
throws InterruptedException, UnknownHostException, IOException, ParseException {
|
||||
return new SwissTimingRaceTrackerImpl(raceID, raceName, raceDescription, boatClass, hostname, port, startList,
|
||||
raceLogStore, regattaLogStore, windStore, domainFactory, this,
|
||||
trackedRegattaRegistry, raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm, connectivityParams);
|
||||
return new SwissTimingRaceTrackerImpl(raceLogStore, regattaLogStore, windStore, domainFactory, this,
|
||||
trackedRegattaRegistry, raceLogResolver, connectivityParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription,
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
|
||||
WindStore windStore, boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
|
||||
public RaceTracker createRaceTracker(Regatta regatta, WindStore windStore, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
throws UnknownHostException, InterruptedException, IOException, ParseException {
|
||||
return new SwissTimingRaceTrackerImpl(regatta, raceID, raceName, raceDescription, boatClass, hostname, port,
|
||||
startList, windStore, domainFactory, this, trackedRegattaRegistry, raceLogStore, regattaLogStore,
|
||||
raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm, connectivityParams);
|
||||
return new SwissTimingRaceTrackerImpl(regatta, windStore, domainFactory, this, trackedRegattaRegistry,
|
||||
raceLogStore, regattaLogStore, raceLogResolver, connectivityParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+54
-28
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.swisstimingadapter.impl;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Collection;
|
||||
@@ -63,6 +64,7 @@ import com.sap.sailing.domain.tracking.TrackingDataLoader;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.domain.tracking.impl.TrackedRaceStatusImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.UpdateHandler;
|
||||
import com.sap.sse.common.Distance;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
@@ -110,23 +112,30 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
private final TMDMessageQueue tmdMessageQueue;
|
||||
|
||||
private final RaceLogResolver raceLogResolver;
|
||||
|
||||
/**
|
||||
* If set to a non-{@code null}, non-{@link String#isEmpty() empty} value, updates about start time changes, course
|
||||
* changes, etc. will be sent as REST requests to this URL, using the {@link #updateUsername} /
|
||||
* {@link #updatePassword} as credentials.
|
||||
*/
|
||||
private final String updateURL;
|
||||
|
||||
private final String updateUsername;
|
||||
|
||||
private final String updatePassword;
|
||||
|
||||
protected SwissTimingRaceTrackerImpl(String raceID, String raceName, String raceDescription, BoatClass boatClass,
|
||||
String hostname, int port, StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
protected SwissTimingRaceTrackerImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
WindStore windStore, DomainFactory domainFactory, SwissTimingFactory factory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, long delayToLiveInMillis,
|
||||
boolean useInternalMarkPassingAlgorithm, SwissTimingTrackingConnectivityParameters connectivityParams) throws InterruptedException,
|
||||
UnknownHostException, IOException, ParseException {
|
||||
this(/* regatta */ null, raceID, raceName, raceDescription, boatClass, hostname, port, startList, windStore,
|
||||
domainFactory, factory, trackedRegattaRegistry, raceLogStore, regattaLogStore, raceLogResolver,
|
||||
delayToLiveInMillis, useInternalMarkPassingAlgorithm, connectivityParams);
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver,
|
||||
SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
throws InterruptedException, UnknownHostException, IOException, ParseException {
|
||||
this(/* regatta */ null, windStore, domainFactory, factory, trackedRegattaRegistry, raceLogStore, regattaLogStore, raceLogResolver, connectivityParams);
|
||||
}
|
||||
|
||||
protected SwissTimingRaceTrackerImpl(Regatta regatta, String raceID, String raceName, String raceDescription,
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, WindStore windStore,
|
||||
DomainFactory domainFactory, SwissTimingFactory factory, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, RaceLogResolver raceLogResolver,
|
||||
long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
protected SwissTimingRaceTrackerImpl(Regatta regatta, WindStore windStore, DomainFactory domainFactory,
|
||||
SwissTimingFactory factory, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, RaceLogResolver raceLogResolver,
|
||||
SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
throws InterruptedException, UnknownHostException, IOException, ParseException {
|
||||
super(connectivityParams);
|
||||
this.raceLogResolver = raceLogResolver;
|
||||
@@ -134,29 +143,35 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
final Regatta effectiveRegatta;
|
||||
// Try to find a pre-associated event based on the Race ID
|
||||
if (regatta == null) {
|
||||
effectiveRegatta = trackedRegattaRegistry.getRememberedRegattaForRace(raceID);
|
||||
effectiveRegatta = trackedRegattaRegistry.getRememberedRegattaForRace(connectivityParams.getRaceID());
|
||||
} else {
|
||||
effectiveRegatta = regatta;
|
||||
}
|
||||
// if regatta is still null, no previous assignment of any of the races in this TracTrac event to a Regatta was
|
||||
// found; in this case, create a default regatta based on the TracTrac event data
|
||||
this.regatta = effectiveRegatta == null ? domainFactory.getOrCreateDefaultRegatta(raceLogStore, regattaLogStore,
|
||||
raceID, boatClass, trackedRegattaRegistry) : effectiveRegatta;
|
||||
this.connector = factory.getOrCreateSailMasterConnector(hostname, port, raceID, raceName, raceDescription, boatClass);
|
||||
connectivityParams.getRaceID(), connectivityParams.getBoatClass(), trackedRegattaRegistry) : effectiveRegatta;
|
||||
this.connector = factory.getOrCreateSailMasterConnector(connectivityParams.getHostname(), connectivityParams.getPort(),
|
||||
connectivityParams.getRaceID(), connectivityParams.getRaceName(), connectivityParams.getRaceDescription(), connectivityParams.getBoatClass());
|
||||
this.domainFactory = domainFactory;
|
||||
this.raceID = raceID;
|
||||
this.raceName = raceName;
|
||||
this.startList = startList;
|
||||
this.startListFromManage2Sail = startList != null;
|
||||
this.raceDescription = raceDescription;
|
||||
this.boatClass = boatClass;
|
||||
this.raceID = connectivityParams.getRaceID();
|
||||
// start out with an empty course, so we don't depend on receiving the CCG message before the timeout
|
||||
this.course = new CourseImpl(this.raceID, /* start with empty marks list */ Collections.emptyList());
|
||||
this.raceName = connectivityParams.getRaceName();
|
||||
this.startList = connectivityParams.getStartList();
|
||||
this.startListFromManage2Sail = connectivityParams.getStartList() != null;
|
||||
this.raceDescription = connectivityParams.getRaceDescription();
|
||||
this.boatClass = connectivityParams.getBoatClass();
|
||||
this.windStore = windStore;
|
||||
this.id = createID(raceID, hostname, port);
|
||||
this.id = createID(connectivityParams.getRaceID(), connectivityParams.getHostname(), connectivityParams.getPort());
|
||||
connector.addSailMasterListener(this);
|
||||
trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(this.regatta);
|
||||
this.delayToLiveInMillis = delayToLiveInMillis;
|
||||
this.delayToLiveInMillis = connectivityParams.getDelayToLiveInMillis();
|
||||
this.competitorsByBoatId = new HashMap<String, Competitor>();
|
||||
this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
|
||||
this.useInternalMarkPassingAlgorithm = connectivityParams.isUseInternalMarkPassingAlgorithm();
|
||||
this.updateURL = connectivityParams.getUpdateURL();
|
||||
this.updateUsername = connectivityParams.getUpdateUsername();
|
||||
this.updatePassword = connectivityParams.getUpdatePassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -406,7 +421,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receivedStartList(String raceID, StartList startList) {
|
||||
public void receivedStartList(String raceID, StartList startList) throws URISyntaxException {
|
||||
// ignore STL messages if the startlist has been already provided by Manage2Sail
|
||||
if (!startListFromManage2Sail && this.raceID.equals(raceID)) {
|
||||
StartList oldStartList = this.startList;
|
||||
@@ -435,7 +450,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
}
|
||||
}
|
||||
|
||||
private void createRaceDefinition(Course course) {
|
||||
private void createRaceDefinition(Course course) throws URISyntaxException {
|
||||
assert this.raceID.equals(raceID);
|
||||
assert startList != null;
|
||||
assert course != null;
|
||||
@@ -465,9 +480,20 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
}
|
||||
}, useInternalMarkPassingAlgorithm, raceLogResolver,
|
||||
/* Not needed because the RaceTracker is not active on a replica */ Optional.empty());
|
||||
addUpdateHandlers();
|
||||
notifyRaceCreationListeners();
|
||||
logger.info("Created SwissTiming RaceDefinition and TrackedRace for "+race.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* If a non-{@code null}, non-{@link String#isEmpty() empty} {@link #updateURL} is set, adds {@link UpdateHandler}s
|
||||
* to the race that will forward changes to the race such as start time changes or course changes to the URL as REST
|
||||
* requests.
|
||||
*/
|
||||
private void addUpdateHandlers() throws URISyntaxException {
|
||||
getDomainFactory().addUpdateHandlers(updateURL, updateUsername, updatePassword,
|
||||
/* TODO using the regatta ID as the "eventId" for now... */ regatta.getId(), trackedRace.getRace(), trackedRace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if {@link #getRegatta()} still contains the {@link RaceDefinition} obtained when calling
|
||||
@@ -481,7 +507,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receivedCourseConfiguration(String raceID, Course course) {
|
||||
public void receivedCourseConfiguration(String raceID, Course course) throws URISyntaxException {
|
||||
Course oldCourse = this.course;
|
||||
if (trackedRace == null) {
|
||||
if (oldCourse == null && startList != null) {
|
||||
|
||||
+24
-8
@@ -31,11 +31,15 @@ public class SwissTimingTrackingConnectivityParameters extends AbstractRaceTrack
|
||||
private final long delayToLiveInMillis;
|
||||
private final StartList startList;
|
||||
private final boolean useInternalMarkPassingAlgorithm;
|
||||
private final String updateURL;
|
||||
private final String updateUsername;
|
||||
private final String updatePassword;
|
||||
|
||||
public SwissTimingTrackingConnectivityParameters(String hostname, int port, String raceID, String raceName,
|
||||
String raceDescription, BoatClass boatClass, StartList startList, long delayToLiveInMillis,
|
||||
SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) {
|
||||
RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm, boolean trackWind,
|
||||
boolean correctWindDirectionByMagneticDeclination, String updateURL, String updateUsername, String updatePassword) {
|
||||
super(trackWind, correctWindDirectionByMagneticDeclination);
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
@@ -50,6 +54,9 @@ public class SwissTimingTrackingConnectivityParameters extends AbstractRaceTrack
|
||||
this.raceLogStore = raceLogStore;
|
||||
this.regattaLogStore = regattaLogStore;
|
||||
this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
|
||||
this.updateURL = updateURL;
|
||||
this.updateUsername = updateUsername;
|
||||
this.updatePassword = updatePassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,18 +67,15 @@ public class SwissTimingTrackingConnectivityParameters extends AbstractRaceTrack
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
|
||||
RaceLogResolver raceLogResolver, LeaderboardGroupResolver leaderboardGroupResolver, long timeoutInMilliseconds) throws Exception {
|
||||
return swissTimingFactory.createRaceTracker(raceID, raceName, raceDescription, boatClass, hostname, port,
|
||||
startList, delayToLiveInMillis, raceLogStore, regattaLogStore, windStore,
|
||||
useInternalMarkPassingAlgorithm,
|
||||
domainFactory, trackedRegattaRegistry, raceLogResolver, this);
|
||||
return swissTimingFactory.createRaceTracker(raceLogStore, regattaLogStore, windStore, domainFactory, trackedRegattaRegistry, raceLogResolver,
|
||||
this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
WindStore windStore, RaceLogResolver raceLogResolver, LeaderboardGroupResolver leaderboardGroupResolver, long timeoutInMilliseconds) throws Exception {
|
||||
return swissTimingFactory.createRaceTracker(regatta, raceID, raceName, raceDescription, boatClass, hostname,
|
||||
port, startList, delayToLiveInMillis, windStore, useInternalMarkPassingAlgorithm,
|
||||
domainFactory, trackedRegattaRegistry, raceLogResolver, raceLogStore, regattaLogStore, this);
|
||||
return swissTimingFactory.createRaceTracker(regatta, windStore, domainFactory, trackedRegattaRegistry, raceLogResolver, raceLogStore,
|
||||
regattaLogStore, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,6 +96,18 @@ public class SwissTimingTrackingConnectivityParameters extends AbstractRaceTrack
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getUpdateURL() {
|
||||
return updateURL;
|
||||
}
|
||||
|
||||
public String getUpdateUsername() {
|
||||
return updateUsername;
|
||||
}
|
||||
|
||||
public String getUpdatePassword() {
|
||||
return updatePassword;
|
||||
}
|
||||
|
||||
public String getRaceID() {
|
||||
return raceID;
|
||||
}
|
||||
|
||||
+4
@@ -16,6 +16,7 @@ import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogDependentStartTimeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.SimpleRaceLogIdentifierImpl;
|
||||
import com.sap.sailing.domain.base.CompetitorWithBoat;
|
||||
@@ -73,5 +74,8 @@ public class TrackedRaceStartTimeUpdateForDependentStartTimeTest extends TrackBa
|
||||
assertEquals(r1StartTimeToSet, r1StartTime[0]);
|
||||
assertNotNull(r2StartTime[0]);
|
||||
assertEquals(r1StartTimeToSet.plus(startTimeDiff), r2StartTime[0]);
|
||||
// bug 4708: test that r2's start time is reverted to null after r1 loses its start time
|
||||
r1RaceLog.add(new RaceLogPassChangeEventImpl(MillisecondsTimePoint.now(), author, /* pass */ 1));
|
||||
assertNull(r2StartTime[0]);
|
||||
}
|
||||
}
|
||||
+10
-8
@@ -14,8 +14,8 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -73,6 +73,9 @@ import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.domain.tracking.impl.FinishTimeUpdateHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.RaceAbortedHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.StartTimeUpdateHandler;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.JSONService;
|
||||
import com.sap.sailing.domain.tractracadapter.MetadataParser;
|
||||
@@ -677,17 +680,16 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
TracTracCourseDesignUpdateHandler courseDesignHandler = new TracTracCourseDesignUpdateHandler(
|
||||
tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
|
||||
raceDefinition.getId(), tractracRace, this);
|
||||
trackedRace.addCourseDesignChangedListener(courseDesignHandler);
|
||||
TracTracStartTimeUpdateHandler startTimeHandler = new TracTracStartTimeUpdateHandler(
|
||||
StartTimeUpdateHandler startTimeHandler = new StartTimeUpdateHandler(
|
||||
tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
|
||||
raceDefinition.getId(), trackedRace.getTrackedRegatta().getRegatta());
|
||||
trackedRace.addStartTimeChangedListener(startTimeHandler);
|
||||
TracTracRaceAbortedHandler raceAbortedHandler = new TracTracRaceAbortedHandler(
|
||||
RaceAbortedHandler raceAbortedHandler = new RaceAbortedHandler(
|
||||
tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
|
||||
raceDefinition.getId());
|
||||
trackedRace.addRaceAbortedListener(raceAbortedHandler);
|
||||
trackedRace.addListener(new TracTracFinishTimeUpdateHandler(tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
|
||||
raceDefinition.getId(), trackedRace.getTrackedRegatta().getRegatta()).getListener());
|
||||
final FinishTimeUpdateHandler finishTimeUpdateHandler = new FinishTimeUpdateHandler(tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
|
||||
raceDefinition.getId(), trackedRace.getTrackedRegatta().getRegatta());
|
||||
baseDomainFactory.addUpdateHandlers(trackedRace, courseDesignHandler, startTimeHandler, raceAbortedHandler,
|
||||
finishTimeUpdateHandler);
|
||||
}
|
||||
|
||||
private DynamicTrackedRace createTrackedRace(TrackedRegatta trackedRegatta, RaceDefinition race,
|
||||
|
||||
+9
-7
@@ -251,17 +251,19 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<IControlRoute,
|
||||
}
|
||||
}
|
||||
|
||||
private DynamicTrackedRace createTrackedRace(RaceDefinition race, Iterable<Sideline> sidelines, Consumer<DynamicTrackedRace> runAfterCreatingTrackedRace) {
|
||||
DynamicTrackedRace trackedRace = getTrackedRegatta().createTrackedRace(race, sidelines,
|
||||
windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
|
||||
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
|
||||
private DynamicTrackedRace createTrackedRace(RaceDefinition race, Iterable<Sideline> sidelines,
|
||||
Consumer<DynamicTrackedRace> runAfterCreatingTrackedRace) {
|
||||
DynamicTrackedRace trackedRace = getTrackedRegatta().createTrackedRace(race, sidelines, windStore,
|
||||
delayToLiveInMillis, millisecondsOverWhichToAverageWind,
|
||||
/* time over which to average speed: */ race.getBoatClass()
|
||||
.getApproximateManeuverDurationInMilliseconds(),
|
||||
raceDefinitionSetToUpdate, useInternalMarkPassingAlgorithm, raceLogResolver,
|
||||
/* Not needed because the RaceTracker is not active on a replica */ Optional.empty());
|
||||
if (runAfterCreatingTrackedRace != null) {
|
||||
runAfterCreatingTrackedRace.accept(trackedRace);
|
||||
runAfterCreatingTrackedRace.accept(trackedRace);
|
||||
}
|
||||
getDomainFactory().addTracTracUpdateHandlers(tracTracUpdateURI, getTracTracEvent().getId(), tracTracUsername, tracTracPassword, race, trackedRace,
|
||||
tractracRace);
|
||||
getDomainFactory().addTracTracUpdateHandlers(tracTracUpdateURI, getTracTracEvent().getId(), tracTracUsername,
|
||||
tracTracPassword, race, trackedRace, tractracRace);
|
||||
return trackedRace;
|
||||
}
|
||||
|
||||
|
||||
+4
-58
@@ -1,86 +1,32 @@
|
||||
package com.sap.sailing.domain.tractracadapter.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.sap.sailing.domain.base.ControlPoint;
|
||||
import com.sap.sailing.domain.base.CourseBase;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.CourseDataImpl;
|
||||
import com.sap.sailing.domain.tracking.CourseDesignChangedListener;
|
||||
import com.sap.sailing.domain.tracking.impl.CourseDesignUpdateHandler;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.ControlPointJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseBaseJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.GateJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.MarkJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.WaypointJsonSerializer;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.tractrac.model.lib.api.event.IRace;
|
||||
import com.tractrac.model.lib.api.route.IControl;
|
||||
|
||||
public class TracTracCourseDesignUpdateHandler extends UpdateHandler implements CourseDesignChangedListener {
|
||||
|
||||
private final static String ACTION = "update_course";
|
||||
|
||||
private final static Logger logger = Logger.getLogger(TracTracCourseDesignUpdateHandler.class.getName());
|
||||
private final JsonSerializer<CourseBase> courseSerializer;
|
||||
public class TracTracCourseDesignUpdateHandler extends CourseDesignUpdateHandler {
|
||||
private final IRace tractracRace;
|
||||
private final DomainFactory domainFactory;
|
||||
|
||||
public TracTracCourseDesignUpdateHandler(URI updateURI, String tracTracUsername, String tracTracPassword, Serializable tracTracEventId, Serializable raceId, IRace tractracRace, DomainFactory domainFactory) {
|
||||
super(updateURI, ACTION, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
|
||||
super(updateURI, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
|
||||
this.domainFactory = domainFactory;
|
||||
this.tractracRace = tractracRace;
|
||||
this.courseSerializer = new CourseJsonSerializer(
|
||||
new CourseBaseJsonSerializer(
|
||||
new WaypointJsonSerializer(
|
||||
new ControlPointJsonSerializer(
|
||||
new MarkJsonSerializer(),
|
||||
new GateJsonSerializer(new MarkJsonSerializer())))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void courseDesignChanged(final CourseBase newCourseDesign) throws MalformedURLException, IOException {
|
||||
if (!isActive()) {
|
||||
logger.info("Not sending course update to TracTrac because no URL has been provided.");
|
||||
return;
|
||||
}
|
||||
final CourseBase newCourseDesignWithExistingControlPoints = replaceControlPointsByMatchingExistingControlPoints(newCourseDesign);
|
||||
JSONObject serializedCourseDesign = courseSerializer.serialize(newCourseDesignWithExistingControlPoints);
|
||||
String payload = serializedCourseDesign.toJSONString();
|
||||
URL currentCourseDesignURL = buildUpdateURL();
|
||||
logger.info("Using " + currentCourseDesignURL.toString() + " for the course update!");
|
||||
logger.info("Payload is " + payload);
|
||||
HttpURLConnection connection = (HttpURLConnection) currentCourseDesignURL.openConnection();
|
||||
try {
|
||||
setConnectionPropertiesAndSendWithPayload(connection, payload);
|
||||
try {
|
||||
checkAndLogUpdateResponse(connection);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
} else {
|
||||
logger.severe("Connection to TracTrac Course Update URL " + currentCourseDesignURL.toString() + " could not be established");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CourseBase replaceControlPointsByMatchingExistingControlPoints(CourseBase courseDesign) {
|
||||
protected CourseBase replaceControlPointsByMatchingExistingControlPoints(CourseBase courseDesign) {
|
||||
final Iterable<IControl> candidates = domainFactory.getControlsForCourseArea(tractracRace.getEvent(), tractracRace.getCourseArea());
|
||||
final CourseBase result = new CourseDataImpl(courseDesign.getName());
|
||||
int zeroBasedPosition = 0;
|
||||
|
||||
@@ -47,5 +47,12 @@ Require-Bundle: com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||
com.sap.sse.shared.android,
|
||||
org.apache.commons.math,
|
||||
com.sap.sailing.declination,
|
||||
com.sap.sailing.server.gateway.serialization.shared.android,
|
||||
com.sap.sse.datamining.annotations
|
||||
Import-Package: org.apache.http,
|
||||
org.apache.http.client;version="[4.2.5,4.3.0)",
|
||||
org.apache.http.client.entity;version="[4.2.5,4.3.0)",
|
||||
org.apache.http.client.methods;version="[4.2.5,4.3.0)",
|
||||
org.apache.http.impl.client;version="[4.2.5,4.3.0)",
|
||||
org.apache.http.message;version="[4.2.5,4.3.0)"
|
||||
Automatic-Module-Name: com.sap.sailing.domain
|
||||
@@ -21,9 +21,14 @@ import com.sap.sailing.domain.common.dto.TrackedRaceStatisticsDTO;
|
||||
import com.sap.sailing.domain.common.media.MediaTrack;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.impl.CourseDesignUpdateHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.FinishTimeUpdateHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.RaceAbortedHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.StartTimeUpdateHandler;
|
||||
import com.sap.sse.common.IsManagedByCache;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
@@ -101,4 +106,11 @@ public interface DomainFactory extends SharedDomainFactory {
|
||||
*/
|
||||
void updateRaceDTOWithTrackedRaceData(TrackedRace trackedRace, RaceDTO raceDTO);
|
||||
|
||||
/**
|
||||
* Adds update handlers to a {@link TrackedRace} which can send updates to a REST service about race status
|
||||
* changes such as a start time change, a course change, or a postponement.
|
||||
*/
|
||||
void addUpdateHandlers(DynamicTrackedRace trackedRace, CourseDesignUpdateHandler courseDesignHandler,
|
||||
StartTimeUpdateHandler startTimeHandler, RaceAbortedHandler raceAbortedHandler,
|
||||
final FinishTimeUpdateHandler finishTimeUpdateHandler);
|
||||
}
|
||||
+22
-24
@@ -11,6 +11,8 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -60,15 +62,15 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
|
||||
private TrackedRaces trackedRaces;
|
||||
private Map<Fleet, RaceIdentifier> raceIdentifiers;
|
||||
|
||||
private Map<Fleet, RaceLog> raceLogs;
|
||||
|
||||
private ConcurrentMap<Fleet, RaceLog> raceLogs;
|
||||
|
||||
private transient RaceLogStore raceLogStore;
|
||||
private RegattaLikeIdentifier regattaLikeParent;
|
||||
|
||||
public AbstractRaceColumn() {
|
||||
this.trackedRaces = new TrackedRaces();
|
||||
this.raceIdentifiers = new HashMap<Fleet, RaceIdentifier>();
|
||||
this.raceLogs = new HashMap<Fleet, RaceLog>();
|
||||
this.raceLogs = new ConcurrentHashMap<Fleet, RaceLog>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,9 +84,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
|
||||
|
||||
@Override
|
||||
public RaceLog getRaceLog(Fleet fleet) {
|
||||
synchronized (raceLogs) {
|
||||
return raceLogs.get(fleet);
|
||||
}
|
||||
return raceLogs.get(fleet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,25 +197,23 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
|
||||
|
||||
@Override
|
||||
public void reloadRaceLog(Fleet fleet) {
|
||||
synchronized (raceLogs) {
|
||||
RaceLogIdentifier identifier = getRaceLogIdentifier(fleet);
|
||||
RaceLog newOrLoadedRaceLog = raceLogStore.getRaceLog(identifier, /* ignoreCache */true);
|
||||
RaceLog raceLogAvailable = raceLogs.get(fleet);
|
||||
if (raceLogAvailable == null) {
|
||||
RaceColumnRaceLogReplicator listener = new RaceColumnRaceLogReplicator(this, identifier);
|
||||
// FIXME Wouldn't this skip any listener notifications that a merge below would trigger if the race log already existed?
|
||||
// FIXME For example, how about the race log-provided score corrections that need application to the leaderboard and replication?
|
||||
newOrLoadedRaceLog.addListener(listener);
|
||||
raceLogs.put(fleet, newOrLoadedRaceLog);
|
||||
final TrackedRace trackedRace = getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
// need to attach race log
|
||||
trackedRace.attachRaceLog(newOrLoadedRaceLog);
|
||||
}
|
||||
} else {
|
||||
// now add all race log events from newOrLoadedRaceLog that are not already in raceLogAvailable
|
||||
raceLogAvailable.merge(newOrLoadedRaceLog);
|
||||
RaceLogIdentifier identifier = getRaceLogIdentifier(fleet);
|
||||
RaceLog newOrLoadedRaceLog = raceLogStore.getRaceLog(identifier, /* ignoreCache */true);
|
||||
RaceLog raceLogAvailable = raceLogs.get(fleet);
|
||||
if (raceLogAvailable == null) {
|
||||
RaceColumnRaceLogReplicator listener = new RaceColumnRaceLogReplicator(this, identifier);
|
||||
// FIXME Wouldn't this skip any listener notifications that a merge below would trigger if the race log already existed?
|
||||
// FIXME For example, how about the race log-provided score corrections that need application to the leaderboard and replication?
|
||||
newOrLoadedRaceLog.addListener(listener);
|
||||
raceLogs.put(fleet, newOrLoadedRaceLog);
|
||||
final TrackedRace trackedRace = getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
// need to attach race log
|
||||
trackedRace.attachRaceLog(newOrLoadedRaceLog);
|
||||
}
|
||||
} else {
|
||||
// now add all race log events from newOrLoadedRaceLog that are not already in raceLogAvailable
|
||||
raceLogAvailable.merge(newOrLoadedRaceLog);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-1
@@ -64,11 +64,16 @@ import com.sap.sailing.domain.leaderboard.impl.LowPointTieBreakBasedOnLastSeries
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPointWinnerGetsZero;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPointWithAutomaticRDG;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPointWithEliminationsAndRoundsWinnerGets07;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.impl.CourseDesignUpdateHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.FinishTimeUpdateHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.RaceAbortedHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.StartTimeUpdateHandler;
|
||||
import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
|
||||
import com.sap.sailing.geocoding.ReverseGeocoder;
|
||||
import com.sap.sse.common.Distance;
|
||||
@@ -201,11 +206,12 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
|
||||
assert trackedRace != null;
|
||||
raceDTO.startOfRace = trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace().asDate();
|
||||
raceDTO.endOfRace = trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace().asDate();
|
||||
raceDTO.raceFinishedTime = trackedRace.getFinishedTime() == null ? null : trackedRace.getFinishedTime().asDate();
|
||||
raceDTO.status = new RaceStatusDTO();
|
||||
raceDTO.status.status = trackedRace.getStatus() == null ? null : trackedRace.getStatus().getStatus();
|
||||
raceDTO.status.loadingProgress = trackedRace.getStatus() == null ? 0.0 : trackedRace.getStatus().getLoadingProgress();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TrackedRaceDTO createTrackedRaceDTO(TrackedRace trackedRace) {
|
||||
TrackedRaceDTO trackedRaceDTO = new TrackedRaceDTO();
|
||||
@@ -394,6 +400,7 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompetitorAndBoatDTO> getCompetitorDTOList(List<Pair<Competitor, Boat>> competitors) {
|
||||
List<CompetitorAndBoatDTO> result = new ArrayList<>();
|
||||
for (Pair<Competitor, Boat> competitorAndBoat : competitors) {
|
||||
@@ -401,4 +408,14 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUpdateHandlers(DynamicTrackedRace trackedRace, CourseDesignUpdateHandler courseDesignHandler,
|
||||
StartTimeUpdateHandler startTimeHandler, RaceAbortedHandler raceAbortedHandler,
|
||||
final FinishTimeUpdateHandler finishTimeUpdateHandler) {
|
||||
trackedRace.addCourseDesignChangedListener(courseDesignHandler);
|
||||
trackedRace.addStartTimeChangedListener(startTimeHandler);
|
||||
trackedRace.addRaceAbortedListener(raceAbortedHandler);
|
||||
trackedRace.addListener(finishTimeUpdateHandler.getListener());
|
||||
}
|
||||
}
|
||||
+28
-13
@@ -698,8 +698,9 @@ public class ManeuverDetectorImpl extends AbstractManeuverDetectorImpl {
|
||||
} catch (NoWindException e) {
|
||||
tackAfterManeuver = null;
|
||||
}
|
||||
maneuver = new ManeuverWithMainCurveBoundariesImpl(maneuverType, tackAfterManeuver, maneuverPosition, maneuverMainCurveDetails.getTimePoint(),
|
||||
maneuverMainCurveDetails.extractCurveBoundariesOnly(), maneuverUnstableCourseAndSpeedBoundaries,
|
||||
maneuver = new ManeuverWithMainCurveBoundariesImpl(maneuverType, tackAfterManeuver, maneuverPosition,
|
||||
maneuverMainCurveDetails.getTimePoint(), maneuverMainCurveDetails.extractCurveBoundariesOnly(),
|
||||
maneuverUnstableCourseAndSpeedBoundaries,
|
||||
maneuverMainCurveDetails.getMaxTurningRateInDegreesPerSecond(), markPassing, maneuverLoss);
|
||||
}
|
||||
return maneuver;
|
||||
@@ -723,7 +724,8 @@ public class ManeuverDetectorImpl extends AbstractManeuverDetectorImpl {
|
||||
// For upwind/downwind legs, find the mean course between inbound and outbound course and project actual
|
||||
// and
|
||||
// extrapolated positions onto it:
|
||||
Bearing middleManeuverAngle = speedWithBearingWhenSpeedStartedToDrop.getBearing().middle(speedWithBearingAfterManeuver.getBearing());
|
||||
Bearing middleManeuverAngle = speedWithBearingWhenSpeedStartedToDrop.getBearing()
|
||||
.middle(speedWithBearingAfterManeuver.getBearing());
|
||||
// extrapolate maximum speed before maneuver to time point of maximum speed after maneuver and project
|
||||
// resulting position
|
||||
// onto the average maneuver course; compare to the projected position actually reached at the time
|
||||
@@ -731,9 +733,9 @@ public class ManeuverDetectorImpl extends AbstractManeuverDetectorImpl {
|
||||
// maneuver:
|
||||
Position positionWhenSpeedStartedToDrop = track.getEstimatedPosition(timePointWhenSpeedStartedToDrop,
|
||||
/* extrapolate */ false);
|
||||
Position extrapolatedPositionAtTimePointOfMaxSpeedAfterManeuver = speedWithBearingWhenSpeedStartedToDrop.travelTo(
|
||||
positionWhenSpeedStartedToDrop, timePointWhenSpeedStartedToDrop,
|
||||
timePointWhenSpeedLevelledOffAfterManeuver);
|
||||
Position extrapolatedPositionAtTimePointOfMaxSpeedAfterManeuver = speedWithBearingWhenSpeedStartedToDrop
|
||||
.travelTo(positionWhenSpeedStartedToDrop, timePointWhenSpeedStartedToDrop,
|
||||
timePointWhenSpeedLevelledOffAfterManeuver);
|
||||
Position actualPositionAtTimePointOfMaxSpeedAfterManeuver = track
|
||||
.getEstimatedPosition(timePointWhenSpeedLevelledOffAfterManeuver, /* extrapolate */ false);
|
||||
Position projectedExtrapolatedPositionAtTimePointOfMaxSpeedAfterManeuver = extrapolatedPositionAtTimePointOfMaxSpeedAfterManeuver
|
||||
@@ -745,9 +747,8 @@ public class ManeuverDetectorImpl extends AbstractManeuverDetectorImpl {
|
||||
Distance projectedDistanceSailedIfNotManeuvering = positionWhenSpeedStartedToDrop
|
||||
.getDistance(projectedExtrapolatedPositionAtTimePointOfMaxSpeedAfterManeuver);
|
||||
return new ManeuverLoss(projectedDistanceSailed, projectedDistanceSailedIfNotManeuvering,
|
||||
positionWhenSpeedStartedToDrop,
|
||||
actualPositionAtTimePointOfMaxSpeedAfterManeuver, maneuverDuration, speedWithBearingWhenSpeedStartedToDrop,
|
||||
middleManeuverAngle);
|
||||
positionWhenSpeedStartedToDrop, actualPositionAtTimePointOfMaxSpeedAfterManeuver, maneuverDuration,
|
||||
speedWithBearingWhenSpeedStartedToDrop, middleManeuverAngle);
|
||||
}
|
||||
|
||||
protected Duration getDurationForDouglasPeuckerExtensionForMainCurveAnalysis(Duration approximateManeuverDuration) {
|
||||
@@ -938,11 +939,25 @@ public class ManeuverDetectorImpl extends AbstractManeuverDetectorImpl {
|
||||
if (isCourseChangeLimitExceededForCurveExtension(maneuverMainCurveDetails, maneuverStart)) {
|
||||
maneuverStart = null;
|
||||
}
|
||||
// Stable course analysis is considered as not necessary for preparation phase of maneuver because no
|
||||
// oversteering is usually performed before maneuver
|
||||
TimePoint stableBearingAnalysisUntil = maneuverStart == null ? maneuverMainCurveDetails.getTimePointBefore()
|
||||
: maneuverStart.getExtensionTimePoint();
|
||||
Speed lowestSpeed = maneuverStart == null ? null : maneuverStart.getLowestSpeedWithinExtensionArea();
|
||||
double courseChangeSinceManeuverMainCurveInDegrees = maneuverStart == null ? 0
|
||||
: maneuverStart.getCourseChangeInDegreesWithinExtensionArea();
|
||||
stepsToAnalyze = getSpeedWithBearingStepsWithinTimeRange(stepsToAnalyze, earliestTimePointForSpeedTrendAnalysis,
|
||||
stableBearingAnalysisUntil);
|
||||
ManeuverCurveBoundaryExtension stableBearingExtension = findStableBearingWithMaxAbsCourseChangeSpeed(
|
||||
stepsToAnalyze, true, MAX_TURNING_RATE_IN_DEG_PER_SECOND_FOR_STABLE_COURSE_ANALYSIS);
|
||||
if (stableBearingExtension != null
|
||||
&& !isCourseChangeLimitExceededForCurveExtension(maneuverMainCurveDetails, stableBearingExtension)) {
|
||||
maneuverStart = stableBearingExtension;
|
||||
courseChangeSinceManeuverMainCurveInDegrees += stableBearingExtension
|
||||
.getCourseChangeInDegreesWithinExtensionArea();
|
||||
if (lowestSpeed == null
|
||||
|| lowestSpeed.compareTo(stableBearingExtension.getLowestSpeedWithinExtensionArea()) > 0) {
|
||||
lowestSpeed = stableBearingExtension.getLowestSpeedWithinExtensionArea();
|
||||
}
|
||||
}
|
||||
return maneuverStart != null
|
||||
? new ManeuverCurveBoundaryExtension(maneuverStart.getExtensionTimePoint(),
|
||||
maneuverStart.getSpeedWithBearingAtExtensionTimePoint(),
|
||||
@@ -959,8 +974,8 @@ public class ManeuverDetectorImpl extends AbstractManeuverDetectorImpl {
|
||||
if (curveBoundaryExtension == null) {
|
||||
return false;
|
||||
}
|
||||
return Math.abs(curveBoundaryExtension.getCourseChangeInDegreesWithinExtensionArea()) > Math
|
||||
.abs(curveBoundaryExtension.getCourseChangeInDegreesWithinExtensionArea()) / 3.0;
|
||||
return Math.abs(maneuverMainCurveDetails.getDirectionChangeInDegrees()) / 2.0 < Math
|
||||
.abs(curveBoundaryExtension.getCourseChangeInDegreesWithinExtensionArea());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseBase;
|
||||
import com.sap.sailing.domain.tracking.CourseDesignChangedListener;
|
||||
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.ControlPointJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseBaseJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.GateJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.MarkJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.WaypointJsonSerializer;
|
||||
|
||||
public class CourseDesignUpdateHandler extends UpdateHandler implements CourseDesignChangedListener {
|
||||
|
||||
private final static String ACTION = "update_course";
|
||||
|
||||
private final static Logger logger = Logger.getLogger(CourseDesignUpdateHandler.class.getName());
|
||||
private final JsonSerializer<CourseBase> courseSerializer;
|
||||
|
||||
public CourseDesignUpdateHandler(URI updateURI, String username, String password, Serializable eventId, Serializable raceId) {
|
||||
super(updateURI, ACTION, username, password, eventId, raceId);
|
||||
this.courseSerializer = new CourseJsonSerializer(
|
||||
new CourseBaseJsonSerializer(
|
||||
new WaypointJsonSerializer(
|
||||
new ControlPointJsonSerializer(
|
||||
new MarkJsonSerializer(),
|
||||
new GateJsonSerializer(new MarkJsonSerializer())))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void courseDesignChanged(final CourseBase newCourseDesign) throws MalformedURLException, IOException {
|
||||
if (!isActive()) {
|
||||
logger.info("Not sending course update to TracTrac because no URL has been provided.");
|
||||
return;
|
||||
}
|
||||
final CourseBase newCourseDesignWithExistingControlPoints = replaceControlPointsByMatchingExistingControlPoints(newCourseDesign);
|
||||
JSONObject serializedCourseDesign = courseSerializer.serialize(newCourseDesignWithExistingControlPoints);
|
||||
String payload = serializedCourseDesign.toJSONString();
|
||||
URL currentCourseDesignURL = buildUpdateURL();
|
||||
logger.info("Using " + currentCourseDesignURL.toString() + " for the course update!");
|
||||
logger.info("Payload is " + payload);
|
||||
HttpURLConnection connection = (HttpURLConnection) currentCourseDesignURL.openConnection();
|
||||
try {
|
||||
setConnectionPropertiesAndSendWithPayload(connection, payload);
|
||||
try {
|
||||
checkAndLogUpdateResponse(connection);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
} else {
|
||||
logger.severe("Connection to TracTrac Course Update URL " + currentCourseDesignURL.toString() + " could not be established");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This default implementation returns the {@code courseDesign} unchanged. Subclasses have the possibility to
|
||||
* override this method in order to replace individual course marks provided in a detailed course design,
|
||||
* based on the actual course marks available.
|
||||
*/
|
||||
protected CourseBase replaceControlPointsByMatchingExistingControlPoints(CourseBase courseDesign) {
|
||||
return courseDesign;
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -188,8 +188,9 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
||||
public void onStartTimeChanged(ReadonlyRaceState state) {
|
||||
final TimePoint oldStartTime = getStartOfRace();
|
||||
invalidateStartTime();
|
||||
if (!Util.equalsWithNull(oldStartTime, getStartOfRace())) {
|
||||
onStartTimeChangedByRaceCommittee(getStartOfRace());
|
||||
final TimePoint startTimeFromRaceLog = state.getStartTime();
|
||||
if (!Util.equalsWithNull(oldStartTime, startTimeFromRaceLog)) {
|
||||
onStartTimeChangedByRaceCommittee(startTimeFromRaceLog);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor {
|
||||
logger.severe("Trying to add " + this + " as listener to a null race log for tracked race " + trackedRace.getRace());
|
||||
} else {
|
||||
raceLog.addListener(this);
|
||||
final ReadonlyRaceState raceState = ReadonlyRaceStateImpl.create(trackedRace.getRaceLogResolver(), raceLog);
|
||||
final ReadonlyRaceState raceState = ReadonlyRaceStateImpl.getOrCreate(trackedRace.getRaceLogResolver(), raceLog);
|
||||
raceLogs.put(raceLog, raceState);
|
||||
raceState.addChangedListener(new BaseRaceStateChangedListener() {
|
||||
@Override
|
||||
|
||||
+6
-7
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.tractracadapter.impl;
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
@@ -20,12 +20,11 @@ import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.util.LaxRedirectStrategyForAllRedirectResponseCodes;
|
||||
|
||||
public class TracTracFinishTimeUpdateHandler extends UpdateHandler {
|
||||
private final static Logger logger = Logger.getLogger(TracTracFinishTimeUpdateHandler.class.getName());
|
||||
public class FinishTimeUpdateHandler extends UpdateHandler {
|
||||
private final static Logger logger = Logger.getLogger(FinishTimeUpdateHandler.class.getName());
|
||||
|
||||
private final static String ACTION_STOP_TRACKING = "end_tracking";
|
||||
private final static String FIELD_TRACKING_END_TIME = "tracking_end_time";
|
||||
@@ -36,9 +35,9 @@ public class TracTracFinishTimeUpdateHandler extends UpdateHandler {
|
||||
*/
|
||||
private final Regatta regatta;
|
||||
|
||||
public TracTracFinishTimeUpdateHandler(URI updateURI, String tracTracUsername, String tracTracPassword,
|
||||
Serializable tracTracEventId, Serializable raceId, Regatta regatta) {
|
||||
super(updateURI, ACTION_STOP_TRACKING, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
|
||||
public FinishTimeUpdateHandler(URI updateURI, String username, String password,
|
||||
Serializable eventId, Serializable raceId, Regatta regatta) {
|
||||
super(updateURI, ACTION_STOP_TRACKING, username, password, eventId, raceId);
|
||||
this.regatta = regatta;
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.tractracadapter.impl;
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
@@ -15,14 +15,14 @@ import org.json.simple.parser.ParseException;
|
||||
import com.sap.sailing.domain.common.racelog.Flags;
|
||||
import com.sap.sailing.domain.tracking.RaceAbortedListener;
|
||||
|
||||
public class TracTracRaceAbortedHandler extends UpdateHandler implements RaceAbortedListener {
|
||||
public class RaceAbortedHandler extends UpdateHandler implements RaceAbortedListener {
|
||||
|
||||
private final static String ACTION = "update_race_status";
|
||||
|
||||
private final static Logger logger = Logger.getLogger(TracTracRaceAbortedHandler.class.getName());
|
||||
private final static Logger logger = Logger.getLogger(RaceAbortedHandler.class.getName());
|
||||
|
||||
public TracTracRaceAbortedHandler(URI updateURI, String tracTracUsername, String tracTracPassword, Serializable tracTracEventId, Serializable raceId) {
|
||||
super(updateURI, ACTION, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
|
||||
public RaceAbortedHandler(URI updateURI, String username, String password, Serializable eventId, Serializable raceId) {
|
||||
super(updateURI, ACTION, username, password, eventId, raceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.tractracadapter.impl;
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
@@ -13,14 +13,14 @@ import org.json.simple.parser.ParseException;
|
||||
import com.sap.sailing.domain.tracking.StartTimeChangedListener;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
public class TracTracStartTimeResetHandler extends UpdateHandler implements StartTimeChangedListener {
|
||||
public class StartTimeResetHandler extends UpdateHandler implements StartTimeChangedListener {
|
||||
|
||||
private static final String ACTION = "resetStartTime";
|
||||
|
||||
private final static Logger logger = Logger.getLogger(TracTracStartTimeResetHandler.class.getName());
|
||||
private final static Logger logger = Logger.getLogger(StartTimeResetHandler.class.getName());
|
||||
|
||||
public TracTracStartTimeResetHandler(URI updateURI, String tracTracUsername, String tracTracPassword, Serializable tracTracEventId, Serializable raceId) {
|
||||
super(updateURI, ACTION, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
|
||||
public StartTimeResetHandler(URI updateURI, String username, String password, Serializable eventId, Serializable raceId) {
|
||||
super(updateURI, ACTION, username, password, eventId, raceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
+14
-18
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.tractracadapter.impl;
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
@@ -23,13 +23,14 @@ import org.apache.http.message.BasicNameValuePair;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.racelog.Flags;
|
||||
import com.sap.sailing.domain.tracking.StartTimeChangedListener;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.util.LaxRedirectStrategyForAllRedirectResponseCodes;
|
||||
|
||||
public class TracTracStartTimeUpdateHandler extends UpdateHandler implements StartTimeChangedListener {
|
||||
private final static Logger logger = Logger.getLogger(TracTracStartTimeUpdateHandler.class.getName());
|
||||
public class StartTimeUpdateHandler extends UpdateHandler implements StartTimeChangedListener {
|
||||
private final static Logger logger = Logger.getLogger(StartTimeUpdateHandler.class.getName());
|
||||
|
||||
private final static String ACTION = "update_race_start_time";
|
||||
private final static String ACTION_START_TRACKING = "start_tracking";
|
||||
@@ -41,10 +42,13 @@ public class TracTracStartTimeUpdateHandler extends UpdateHandler implements Sta
|
||||
* a new start time is received.
|
||||
*/
|
||||
private final Regatta regatta;
|
||||
|
||||
private final RaceAbortedHandler raceAbortedHandler;
|
||||
|
||||
public TracTracStartTimeUpdateHandler(URI updateURI, String tracTracUsername, String tracTracPassword,
|
||||
public StartTimeUpdateHandler(URI updateURI, String username, String password,
|
||||
Serializable tracTracEventId, Serializable raceId, Regatta regatta) {
|
||||
super(updateURI, ACTION, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
|
||||
super(updateURI, ACTION, username, password, tracTracEventId, raceId);
|
||||
this.raceAbortedHandler = new RaceAbortedHandler(updateURI, username, password, tracTracEventId, raceId);
|
||||
this.regatta = regatta;
|
||||
}
|
||||
|
||||
@@ -52,20 +56,12 @@ public class TracTracStartTimeUpdateHandler extends UpdateHandler implements Sta
|
||||
public void startTimeChanged(TimePoint newStartTime) throws MalformedURLException, IOException, URISyntaxException {
|
||||
if (isActive()) {
|
||||
if (newStartTime == null) {
|
||||
/*
|
||||
* Do not reset start time based on request by Jorge from TracTrac:
|
||||
*
|
||||
* """
|
||||
* We have detected that when you want to update the race start time your
|
||||
* system sends before a message to reset the race start time. When your
|
||||
* system invokes the first service our system changes the race start time
|
||||
* to null and this value causes some secondary effects in our side.
|
||||
*
|
||||
* Can you just send the update_race_start_time without the
|
||||
* reset_race_start_time? The reset_race_start_time service has to be used
|
||||
* if you want to set the value to null.
|
||||
* """
|
||||
/* notify race status as POSTPONED according to Jorge's comment https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4708#c5 :
|
||||
* The method that @frank has commented has to work:
|
||||
* http://em.aws.tractrac.com/update_race_status?eventid=5f2f20f0-6cb2-0136-9eca-60a44ce903c3&raceid=81c082a0-7b1f-0136-166e-028f184941da&username=trac%40sapsailing.com&password=sap0912&race_status=POSTPONED
|
||||
* This method changes the race start time to null.
|
||||
*/
|
||||
raceAbortedHandler.raceAborted(Flags.AP); // will send POSTPONED
|
||||
} else {
|
||||
HashMap<String, String> additionalParameters = new HashMap<String, String>();
|
||||
additionalParameters.put(FIELD_RACE_START_TIME, String.valueOf(newStartTime.asMillis()));
|
||||
+2
-2
@@ -50,7 +50,7 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.TrackingTimesFinde
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogGateLineOpeningTimeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.RaceState;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRacingProcedure;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDefinedMarkAnalyzer;
|
||||
@@ -2975,7 +2975,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
synchronized (raceStates) {
|
||||
result = raceStates.get(raceLog);
|
||||
if (result == null) {
|
||||
result = RaceStateImpl.create(raceLogResolver, raceLog);
|
||||
result = ReadonlyRaceStateImpl.getOrCreate(raceLogResolver, raceLog);
|
||||
raceStates.put(raceLog, result);
|
||||
}
|
||||
}
|
||||
|
||||
+28
-21
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.tractracadapter.impl;
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
@@ -25,21 +25,28 @@ import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.sap.sailing.domain.tractracadapter.UpdateResponse;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.Helpers;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* An update handler can be registered as a listener on a {@link TrackedRace} and can then propagate information to
|
||||
* an external service. This can, e.g., be a tracking partner's system that is interested in receiving race status
|
||||
* updates such as new start times or postponements.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class UpdateHandler {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(UpdateHandler.class.getName());
|
||||
|
||||
private JsonDeserializer<UpdateResponse> updateDeserializer;
|
||||
private final URI baseURI;
|
||||
private final String tracTracUsername;
|
||||
private final String tracTracPassword;
|
||||
private final Serializable tracTracEventId;
|
||||
private final String username;
|
||||
private final String password;
|
||||
private final Serializable eventId;
|
||||
private final Serializable raceId;
|
||||
private final String action;
|
||||
private final boolean active;
|
||||
@@ -53,16 +60,16 @@ public class UpdateHandler {
|
||||
private final static String ResponseCodeForFailure = "FAILURE";
|
||||
private final static String UpdateUrlTemplate = "%s%s?eventid=%s&raceid=%s&username=%s&password=%s";
|
||||
|
||||
public UpdateHandler(URI updateURI, String action, String tracTracUsername, String tracTracPassword, Serializable tracTracEventId, Serializable raceId) {
|
||||
public UpdateHandler(URI updateURI, String action, String username, String password, Serializable eventId, Serializable raceId) {
|
||||
this.baseURI = updateURI;
|
||||
this.action = action;
|
||||
this.tracTracUsername = tracTracUsername;
|
||||
this.tracTracPassword = tracTracPassword;
|
||||
this.tracTracEventId = tracTracEventId;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.eventId = eventId;
|
||||
this.raceId = raceId;
|
||||
this.updateDeserializer = new UpdateResponseDeserializer();
|
||||
if (updateURI != null && !updateURI.toString().equals("")) {
|
||||
logger.info("Activating TracTrac update handler "+this+" for race with ID "+raceId);
|
||||
logger.info("Activating update handler "+this+" for race with ID "+raceId);
|
||||
this.active = true;
|
||||
} else {
|
||||
this.active = false;
|
||||
@@ -87,10 +94,10 @@ public class UpdateHandler {
|
||||
*/
|
||||
protected List<BasicNameValuePair> getDefaultParametersAsNewList() {
|
||||
final List<BasicNameValuePair> result = new ArrayList<>();
|
||||
result.add(new BasicNameValuePair("eventid", tracTracEventId.toString()));
|
||||
result.add(new BasicNameValuePair("eventid", eventId.toString()));
|
||||
result.add(new BasicNameValuePair("raceid", this.raceId.toString()));
|
||||
result.add(new BasicNameValuePair("username", tracTracUsername));
|
||||
result.add(new BasicNameValuePair("password", tracTracPassword));
|
||||
result.add(new BasicNameValuePair("username", username));
|
||||
result.add(new BasicNameValuePair("password", password));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -103,10 +110,10 @@ public class UpdateHandler {
|
||||
String url = String.format(UpdateUrlTemplate,
|
||||
serverUpdateURI.toString(),
|
||||
this.action,
|
||||
URLEncoder.encode(this.tracTracEventId.toString(), EncodingUtf8),
|
||||
URLEncoder.encode(this.eventId.toString(), EncodingUtf8),
|
||||
URLEncoder.encode(this.raceId.toString(), EncodingUtf8),
|
||||
URLEncoder.encode(tracTracUsername, EncodingUtf8),
|
||||
URLEncoder.encode(tracTracPassword, EncodingUtf8));
|
||||
URLEncoder.encode(username, EncodingUtf8),
|
||||
URLEncoder.encode(password, EncodingUtf8));
|
||||
|
||||
for (Entry<String, String> entry : additionalParameters.entrySet()) {
|
||||
url += String.format("&%s=%s",
|
||||
@@ -123,7 +130,7 @@ public class UpdateHandler {
|
||||
protected void checkAndLogUpdateResponse(HttpURLConnection connection) throws IOException, ParseException {
|
||||
connection.setConnectTimeout(10000/*milliseconds*/);
|
||||
connection.connect();
|
||||
BufferedReader reader = getResponseOnUpdateFromTracTrac(connection);
|
||||
BufferedReader reader = getResponseOnUpdateFromProvider(connection);
|
||||
parseAndLogResponse(reader);
|
||||
}
|
||||
|
||||
@@ -133,13 +140,13 @@ public class UpdateHandler {
|
||||
JSONObject responseObject = Helpers.toJSONObjectSafe(responseBody);
|
||||
UpdateResponse updateResponse = updateDeserializer.deserialize(responseObject);
|
||||
if (updateResponse.getStatus().equals(ResponseCodeForFailure)) {
|
||||
logger.severe("Failed to send data to TracTrac, got following response: " + updateResponse.getMessage());
|
||||
logger.severe("Failed to send data to provider, got following response: " + updateResponse.getMessage());
|
||||
} else {
|
||||
logger.info("Successfully sent data to TracTrac with response: " + updateResponse.getMessage());
|
||||
logger.info("Successfully sent data to provider with response: " + updateResponse.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private BufferedReader getResponseOnUpdateFromTracTrac(HttpURLConnection connection) throws IOException {
|
||||
private BufferedReader getResponseOnUpdateFromProvider(HttpURLConnection connection) throws IOException {
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
return reader;
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package com.sap.sailing.domain.tractracadapter;
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
public interface UpdateResponse {
|
||||
|
||||
String getStatus();
|
||||
|
||||
String getMessage();
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
package com.sap.sailing.domain.tractracadapter.impl;
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.tractracadapter.UpdateResponse;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
package com.sap.sailing.domain.tractracadapter.impl;
|
||||
|
||||
import com.sap.sailing.domain.tractracadapter.UpdateResponse;
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
public class UpdateResponseImpl implements UpdateResponse {
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ public class SailingServiceImplMock extends SailingServiceImpl {
|
||||
public RaceHandle addSwissTimingRace(TrackerManager trackerManager,
|
||||
RegattaIdentifier regattaToAddTo, String raceID, String raceName, String raceDescription,
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, RaceLogStore logStore,
|
||||
RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) throws InterruptedException,
|
||||
RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, String updateURL, String updateUsername, String updatePassword) throws InterruptedException,
|
||||
UnknownHostException, IOException, ParseException, Exception {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
|
||||
+35
-6
@@ -12,16 +12,20 @@ import com.google.gwt.i18n.client.NumberFormat;
|
||||
import com.google.gwt.user.client.Timer;
|
||||
import com.google.gwt.user.client.ui.AcceptsOneWidget;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.LeaderboardRowDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.gwt.autoplay.client.app.AnimationPanel;
|
||||
import com.sap.sailing.gwt.autoplay.client.app.AutoPlayClientFactory;
|
||||
import com.sap.sailing.gwt.autoplay.client.app.AutoPlayPresenterConfigured;
|
||||
import com.sap.sailing.gwt.autoplay.client.utils.AutoplayHelper;
|
||||
import com.sap.sailing.gwt.settings.client.leaderboard.SingleRaceLeaderboardSettings;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolverImpl;
|
||||
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateListener;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceCompetitorSet;
|
||||
@@ -152,12 +156,7 @@ public class LiveRaceWithRacemapAndLeaderBoardPresenterImpl
|
||||
view.showErrorNoLive(this, panel, new IllegalStateException("No race is live"));
|
||||
return;
|
||||
}
|
||||
final SingleRaceLeaderboardSettings leaderboardSettings = new SingleRaceLeaderboardSettings(
|
||||
/* maneuverDetailsToShow */ null, /* legDetailsToShow */ null, /* raceDetailsToShow */ null,
|
||||
/* overallDetailsToShow */ null, /* delayBetweenAutoAdvancesInMilliseconds */ null,
|
||||
/* showAddedScores */ false, /* showCompetitorShortNameColumn */ true,
|
||||
/* showCompetitorFullNameColumn */ false, /* isCompetitorNationalityColumnVisible */ false,
|
||||
/* showCompetitorBoatInfoColumn */ false, /* showRaceRankColumn */ true);
|
||||
final SingleRaceLeaderboardSettings leaderboardSettings = getLeaderboardSettings(false);
|
||||
timer = new com.sap.sse.gwt.client.player.Timer(
|
||||
// perform the first request as "live" but don't by default auto-play
|
||||
PlayModes.Live, PlayStates.Playing,
|
||||
@@ -167,12 +166,42 @@ public class LiveRaceWithRacemapAndLeaderBoardPresenterImpl
|
||||
getSlideCtx().getContextDefinition().getLeaderboardName(), errorReporter, StringMessages.INSTANCE,
|
||||
false, null, false, null, false, true, false, false, false, new SixtyInchLeaderboardStyle(true),
|
||||
FlagImageResolverImpl.get(), Arrays.asList(DetailType.values()));
|
||||
|
||||
leaderboardPanel.addLeaderboardUpdateListener(new LeaderboardUpdateListener() {
|
||||
|
||||
@Override
|
||||
public void updatedLeaderboard(LeaderboardDTO leaderboard) {
|
||||
// if this is a changing boat race, enable the boat column
|
||||
if (leaderboardPanel.getLeaderboard() != null) {
|
||||
LeaderboardDTO leaderboardDTO = leaderboardPanel.getLeaderboard();
|
||||
boolean boatsRequired = leaderboardDTO.canBoatsOfCompetitorsChangePerRace;
|
||||
if (leaderboardPanel.getSettings().isShowCompetitorBoatInfoColumn() != boatsRequired) {
|
||||
leaderboardPanel.updateSettings(getLeaderboardSettings(boatsRequired));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void currentRaceSelected(RaceIdentifier raceIdentifier, RaceColumnDTO raceColumn) {
|
||||
}
|
||||
});
|
||||
|
||||
getPlace().getRaceMap().setQuickRanksDTOProvider(new QuickRanksDTOFromLeaderboardDTOProvider(
|
||||
new RaceCompetitorSet(getPlace().getRaceMapSelectionProvider()), liveRace));
|
||||
view.startingWith(this, panel, getPlace().getRaceMap(), leaderboardPanel);
|
||||
selectionTimer.schedule(SWITCH_COMPETITOR_DELAY + AnimationPanel.ANIMATION_DURATION + AnimationPanel.DELAY);
|
||||
}
|
||||
|
||||
private SingleRaceLeaderboardSettings getLeaderboardSettings(boolean showBoatColumn) {
|
||||
final SingleRaceLeaderboardSettings leaderboardSettings = new SingleRaceLeaderboardSettings(
|
||||
/* maneuverDetailsToShow */ null, /* legDetailsToShow */ null, /* raceDetailsToShow */ null,
|
||||
/* overallDetailsToShow */ null, /* delayBetweenAutoAdvancesInMilliseconds */ null,
|
||||
/* showAddedScores */ false, /* showCompetitorShortNameColumn */ true,
|
||||
/* showCompetitorFullNameColumn */ false, showBoatColumn,
|
||||
/* showCompetitorBoatInfoColumn */ false, /* showRaceRankColumn */ true);
|
||||
return leaderboardSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if (timer != null) {
|
||||
|
||||
+3
-4
@@ -137,12 +137,11 @@ public class AutoplayHelper {
|
||||
RaceTimesInfoDTO raceTimes = raceTimesInfos.get(raceIdentifier);
|
||||
boolean notNullInRequiredValues = raceTimes != null && raceTimes.startOfTracking != null
|
||||
&& raceTimes.getStartOfRace() != null;
|
||||
|
||||
boolean raceHasNotEndedOrOnlyRecentlyEnded = raceTimes.endOfRace == null
|
||||
Date endTime = raceTimes.getFinishedTime() != null ? raceTimes.getFinishedTime() : raceTimes.getEndOfRace();
|
||||
boolean raceHasNotEndedOrOnlyRecentlyEnded = endTime == null
|
||||
|| serverTimeDuringRequest.getTime()
|
||||
- raceTimes.delayToLiveInMs < raceTimes.endOfRace.getTime()
|
||||
- raceTimes.delayToLiveInMs < endTime.getTime()
|
||||
+ waitTimeAfterRaceEndInMillis;
|
||||
|
||||
if (notNullInRequiredValues && raceHasNotEndedOrOnlyRecentlyEnded) {
|
||||
long startTimeInMs = raceTimes.getStartOfRace().getTime();
|
||||
long startIn = startTimeInMs - serverTimeDuringRequest.getTime() - raceTimes.delayToLiveInMs;
|
||||
|
||||
+2
-1
@@ -48,10 +48,11 @@ public class MultiRegattaListSteps extends Composite {
|
||||
double parts = Math.pow(seriesProgress.getMaxRacesPerFleet(), 0.4);
|
||||
sumParts += parts;
|
||||
}
|
||||
final boolean showSeriesName = regattaProgress.getSeries().size() > 1;
|
||||
for(RegattaProgressSeriesDTO seriesProgress : regattaProgress.getSeries()) {
|
||||
double parts = Math.pow(seriesProgress.getMaxRacesPerFleet(), 0.4);
|
||||
double percentage = 100.0 * parts / sumParts;
|
||||
MultiRegattaListStepsBody stepsBody = new MultiRegattaListStepsBody(seriesProgress);
|
||||
MultiRegattaListStepsBody stepsBody = new MultiRegattaListStepsBody(seriesProgress, showSeriesName);
|
||||
allMultiregattaSteps.add(stepsBody);
|
||||
stepsBody.getElement().getStyle().setWidth(percentage, Unit.PCT);
|
||||
stepsContainerUi.appendChild(stepsBody.getElement());
|
||||
|
||||
+7
-9
@@ -1,7 +1,5 @@
|
||||
package com.sap.sailing.gwt.home.desktop.partials.multiregattalist;
|
||||
|
||||
import static com.sap.sailing.domain.common.LeaderboardNameConstants.DEFAULT_SERIES_NAME;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -42,17 +40,17 @@ public class MultiRegattaListStepsBody extends UIObject implements RequiresResiz
|
||||
private final String seriesName, seriesNameMedium, seriesNameShort;
|
||||
private int seriesNameLength, seriesNameMediumLength;
|
||||
|
||||
public MultiRegattaListStepsBody(RegattaProgressSeriesDTO seriesProgress) {
|
||||
MultiRegattaListStepsBody(RegattaProgressSeriesDTO seriesProgress, boolean showName) {
|
||||
setElement(uiBinder.createAndBindUi(this));
|
||||
textContainerUi.getStyle().setVisibility(Visibility.HIDDEN);
|
||||
longNameDummyUi.setInnerText(seriesName = caculateSeriesName(seriesProgress));
|
||||
longNameDummyUi.setInnerText(seriesName = caculateSeriesName(seriesProgress, showName));
|
||||
mediumNameDummyUi.setInnerText(seriesNameMedium = caculateSeriesNameMedium());
|
||||
seriesNameShort = caculateSeriesNameShort();
|
||||
if (seriesProgress.isCompleted()) {
|
||||
progressUi.setInnerText(String.valueOf(seriesProgress.getTotalRaceCount()));
|
||||
progressUi.setInnerText(I18N.racesCount(seriesProgress.getTotalRaceCount()));
|
||||
} else {
|
||||
checkUi.getStyle().setDisplay(Display.NONE);
|
||||
progressUi.setInnerText(I18N.currentOfTotal(
|
||||
progressUi.setInnerText(I18N.currentOfTotalRaces(
|
||||
seriesProgress.getProgressRaceCount(), seriesProgress.getTotalRaceCount()));
|
||||
}
|
||||
addFleetProgresses(seriesProgress.getFleetState(), seriesProgress.getMaxRacesPerFleet());
|
||||
@@ -93,9 +91,9 @@ public class MultiRegattaListStepsBody extends UIObject implements RequiresResiz
|
||||
}
|
||||
}
|
||||
|
||||
private String caculateSeriesName(RegattaProgressSeriesDTO seriesProgress) {
|
||||
if (seriesProgress.getName() == null || seriesProgress.getName().isEmpty()
|
||||
|| DEFAULT_SERIES_NAME.equals(seriesProgress.getName())) {
|
||||
private String caculateSeriesName(RegattaProgressSeriesDTO seriesProgress, boolean showName) {
|
||||
if (!showName || seriesProgress.getName() == null || seriesProgress.getName().isEmpty()) {
|
||||
nameUi.getStyle().setDisplay(Display.NONE);
|
||||
return I18N.races();
|
||||
} else {
|
||||
return seriesProgress.getName();
|
||||
|
||||
+17
-2
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.event.regatta.racestab;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.gwt.place.shared.Prefix;
|
||||
import com.sap.sailing.gwt.home.desktop.places.event.regatta.AbstractEventRegattaPlace;
|
||||
import com.sap.sailing.gwt.home.shared.app.HasMobileVersion;
|
||||
@@ -8,24 +10,37 @@ import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.event.EventContext;
|
||||
|
||||
public class RegattaRacesPlace extends AbstractEventRegattaPlace implements HasMobileVersion {
|
||||
|
||||
private final String preferredSeriesName;
|
||||
|
||||
public RegattaRacesPlace(String id, String leaderboardName) {
|
||||
super(id, leaderboardName);
|
||||
this.preferredSeriesName = null;
|
||||
}
|
||||
|
||||
public RegattaRacesPlace(EventContext context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public RegattaRacesPlace(EventContext context, String preferredSeriesName) {
|
||||
super(context);
|
||||
this.preferredSeriesName = preferredSeriesName;
|
||||
}
|
||||
|
||||
public final Optional<String> getPreferredSeriesName() {
|
||||
return Optional.ofNullable(preferredSeriesName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractEventRegattaPlace newInstanceWithContext(EventContext ctx) {
|
||||
return new RegattaRacesPlace(ctx);
|
||||
return new RegattaRacesPlace(ctx, null);
|
||||
}
|
||||
|
||||
@Prefix(PlaceTokenPrefixes.RegattaRaces)
|
||||
public static class Tokenizer extends AbstractEventPlace.Tokenizer<RegattaRacesPlace> {
|
||||
@Override
|
||||
protected RegattaRacesPlace getRealPlace(EventContext context) {
|
||||
return new RegattaRacesPlace(context);
|
||||
return new RegattaRacesPlace(context, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -34,6 +34,7 @@ import com.sap.sailing.gwt.home.shared.places.user.confirmation.ConfirmationPlac
|
||||
import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetActivityProxy;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetPlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
|
||||
import com.sap.sse.gwt.client.DOMUtils;
|
||||
|
||||
public class MobileActivityMapper implements ActivityMapper {
|
||||
private final MobileApplicationClientFactory clientFactory;
|
||||
@@ -52,6 +53,7 @@ public class MobileActivityMapper implements ActivityMapper {
|
||||
SwitchingEntryPoint.reloadApp();
|
||||
return null;
|
||||
}
|
||||
DOMUtils.scrollToTop(clientFactory.getRoot());
|
||||
if (place instanceof ErrorPlace) {
|
||||
return new ErrorActivityProxy((ErrorPlace) place, clientFactory);
|
||||
} else if (place instanceof StartPlace) {
|
||||
|
||||
+5
-1
@@ -21,6 +21,9 @@
|
||||
.eventsteps_phases_phaseinactive {
|
||||
color: #999;
|
||||
}
|
||||
.eventsteps_phases_phase_link {
|
||||
color: #000;
|
||||
}
|
||||
/* .eventsteps_phases_phase:nth-child(2n-1) { */
|
||||
/* padding-right: 0.333333333333333em; */
|
||||
/* } */
|
||||
@@ -35,6 +38,7 @@
|
||||
/* padding: .666666666666667em 0; */
|
||||
display: inline;
|
||||
vertical-align: middle;
|
||||
margin-right: 0.333333333333333rem;
|
||||
}
|
||||
.eventsteps_phases_phase_progressbar {
|
||||
height: 1.266666666666667em;
|
||||
@@ -58,7 +62,7 @@ img.eventsteps_phases_phase_progress_icon {
|
||||
vertical-align: middle;
|
||||
height: 1.133333333333333em;
|
||||
width: 1.133333333333333em;
|
||||
margin: 0 0.333333333333333em;
|
||||
margin-right: 0.333333333333333em;
|
||||
}
|
||||
.eventsteps_phases_phase_progress_text {
|
||||
font-size: 0.866666666666667em;
|
||||
|
||||
+9
-2
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.gwt.home.mobile.partials.eventsteps;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
@@ -11,6 +13,7 @@ import com.sap.sailing.gwt.home.communication.regatta.RegattaProgressSeriesDTO;
|
||||
import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO;
|
||||
import com.sap.sailing.gwt.home.mobile.partials.section.MobileSection;
|
||||
import com.sap.sailing.gwt.home.mobile.partials.sectionHeader.SectionHeaderContent;
|
||||
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
|
||||
import com.sap.sailing.gwt.home.shared.refresh.RefreshableWidget;
|
||||
|
||||
public class EventSteps extends Composite implements RefreshableWidget<RegattaWithProgressDTO> {
|
||||
@@ -22,8 +25,10 @@ public class EventSteps extends Composite implements RefreshableWidget<RegattaWi
|
||||
|
||||
@UiField SectionHeaderContent sectionHeaderUi;
|
||||
private final MobileSection regattaProgessUi;
|
||||
private final Function<String, PlaceNavigation<?>> racesNavigationFactory;
|
||||
|
||||
public EventSteps(RegattaMetadataDTO regatta) {
|
||||
public EventSteps(RegattaMetadataDTO regatta, Function<String, PlaceNavigation<?>> racesNavigationFactory) {
|
||||
this.racesNavigationFactory = racesNavigationFactory;
|
||||
EventStepsResources.INSTANCE.css().ensureInjected();
|
||||
initWidget(regattaProgessUi = uiBinder.createAndBindUi(this));
|
||||
ImageResource boatClassIcon = BoatClassImageResolver.getBoatClassIconResource(regatta.getBoatClass());
|
||||
@@ -36,8 +41,10 @@ public class EventSteps extends Composite implements RefreshableWidget<RegattaWi
|
||||
@Override
|
||||
public void setData(RegattaWithProgressDTO data) {
|
||||
regattaProgessUi.clearContent();
|
||||
final boolean showSeriesName = data.getProgress().getSeries().size() > 1;
|
||||
for (RegattaProgressSeriesDTO seriesProgress : data.getProgress().getSeries()) {
|
||||
regattaProgessUi.addContent(new EventStepsPhase(seriesProgress));
|
||||
final PlaceNavigation<?> navigation = racesNavigationFactory.apply(seriesProgress.getName());
|
||||
regattaProgessUi.addContent(new EventStepsPhase(seriesProgress, navigation, showSeriesName));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-6
@@ -1,11 +1,10 @@
|
||||
package com.sap.sailing.gwt.home.mobile.partials.eventsteps;
|
||||
|
||||
import static com.sap.sailing.domain.common.LeaderboardNameConstants.DEFAULT_SERIES_NAME;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.AnchorElement;
|
||||
import com.google.gwt.dom.client.DivElement;
|
||||
import com.google.gwt.dom.client.ImageElement;
|
||||
import com.google.gwt.dom.client.Style.Display;
|
||||
@@ -16,7 +15,9 @@ import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.home.communication.race.FleetMetadataDTO;
|
||||
import com.sap.sailing.gwt.home.communication.regatta.RegattaProgressFleetDTO;
|
||||
import com.sap.sailing.gwt.home.communication.regatta.RegattaProgressSeriesDTO;
|
||||
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.gwt.client.LinkUtil;
|
||||
|
||||
public class EventStepsPhase extends Composite {
|
||||
|
||||
@@ -26,20 +27,26 @@ public class EventStepsPhase extends Composite {
|
||||
interface EventStepsPhaseUiBinder extends UiBinder<Widget, EventStepsPhase> {
|
||||
}
|
||||
|
||||
@UiField AnchorElement anchorUi;
|
||||
@UiField DivElement nameUi;
|
||||
@UiField ImageElement checkUi;
|
||||
@UiField DivElement progressUi;
|
||||
@UiField DivElement fleetsContainerUi;
|
||||
|
||||
public EventStepsPhase(RegattaProgressSeriesDTO seriesProgress) {
|
||||
EventStepsPhase(RegattaProgressSeriesDTO seriesProgress, PlaceNavigation<?> placeNavigation, boolean showName) {
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
nameUi.setInnerText(DEFAULT_SERIES_NAME.equals(seriesProgress.getName()) ? I18N.races() : seriesProgress.getName());
|
||||
LinkUtil.configureForAction(anchorUi, () -> placeNavigation.goToPlace());
|
||||
if (showName) {
|
||||
nameUi.setInnerText(seriesProgress.getName());
|
||||
} else {
|
||||
nameUi.removeFromParent();
|
||||
}
|
||||
if (seriesProgress.isCompleted()) {
|
||||
progressUi.setInnerText(String.valueOf(seriesProgress.getTotalRaceCount()));
|
||||
progressUi.setInnerText(I18N.racesCount(seriesProgress.getTotalRaceCount()));
|
||||
} else {
|
||||
checkUi.getStyle().setDisplay(Display.NONE);
|
||||
int current = seriesProgress.getProgressRaceCount(), total = seriesProgress.getTotalRaceCount();
|
||||
progressUi.setInnerText(I18N.currentOfTotal(current, total));
|
||||
progressUi.setInnerText(I18N.currentOfTotalRaces(current, total));
|
||||
}
|
||||
if (seriesProgress.getProgressRaceCount() == 0) {
|
||||
addStyleName(EventStepsResources.INSTANCE.css().eventsteps_phases_phaseinactive());
|
||||
|
||||
+8
-6
@@ -6,11 +6,13 @@
|
||||
<ui:with field="local_res" type="com.sap.sailing.gwt.home.mobile.partials.eventsteps.EventStepsResources" />
|
||||
<ui:with field="shr" type="com.sap.sailing.gwt.home.shared.resources.SharedHomeResources" />
|
||||
<g:HTMLPanel addStyleNames="{local_res.css.eventsteps_phases_phase}">
|
||||
<div class="{local_res.css.eventsteps_phases_phase_progress}">
|
||||
<div class="{local_res.css.eventsteps_phases_phase_name}" ui:field="nameUi"></div>
|
||||
<img src="{shr.greenCheck.getSafeUri}" class="{local_res.css.eventsteps_phases_phase_progress_icon}" ui:field="checkUi"></img>
|
||||
<div class="{local_res.css.eventsteps_phases_phase_progress_text}" ui:field="progressUi"></div>
|
||||
</div>
|
||||
<div class="{local_res.css.eventsteps_phases_phase_progressbar}" ui:field="fleetsContainerUi"></div>
|
||||
<a class="{local_res.css.eventsteps_phases_phase_link}" ui:field="anchorUi">
|
||||
<div class="{local_res.css.eventsteps_phases_phase_progress}">
|
||||
<div class="{local_res.css.eventsteps_phases_phase_name}" ui:field="nameUi"></div>
|
||||
<img src="{shr.greenCheck.getSafeUri}" class="{local_res.css.eventsteps_phases_phase_progress_icon}" ui:field="checkUi"></img>
|
||||
<div class="{local_res.css.eventsteps_phases_phase_progress_text}" ui:field="progressUi"></div>
|
||||
</div>
|
||||
<div class="{local_res.css.eventsteps_phases_phase_progressbar}" ui:field="fleetsContainerUi"></div>
|
||||
</a>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
+1
@@ -16,6 +16,7 @@ public interface EventStepsResources extends ClientBundle {
|
||||
String eventsteps_phases();
|
||||
String eventsteps_phases_phase();
|
||||
String eventsteps_phases_phaseinactive();
|
||||
String eventsteps_phases_phase_link();
|
||||
String eventsteps_phases_phase_name();
|
||||
String eventsteps_phases_phase_progressbar();
|
||||
String eventsteps_phases_phase_progressbar_fleet();
|
||||
|
||||
+9
@@ -1,5 +1,8 @@
|
||||
package com.sap.sailing.gwt.home.mobile.partials.regattacompetition;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
@@ -8,6 +11,7 @@ import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.home.communication.event.RaceCompetitionFormatSeriesDTO;
|
||||
import com.sap.sailing.gwt.home.shared.partials.regattacompetition.RegattaCompetitionView;
|
||||
import com.sap.sse.gwt.client.DOMUtils;
|
||||
|
||||
public class RegattaCompetition extends Composite implements RegattaCompetitionView {
|
||||
|
||||
@@ -17,6 +21,7 @@ public class RegattaCompetition extends Composite implements RegattaCompetitionV
|
||||
}
|
||||
|
||||
@UiField FlowPanel regattaSeriesContainerUi;
|
||||
private final Map<String, RegattaCompetitionSeries> seriesNameToUiComponent = new HashMap<>();
|
||||
|
||||
public RegattaCompetition() {
|
||||
RegattaCompetitionResources.INSTANCE.css().ensureInjected();
|
||||
@@ -31,8 +36,12 @@ public class RegattaCompetition extends Composite implements RegattaCompetitionV
|
||||
@Override
|
||||
public RegattaCompetitionSeriesView addSeriesView(RaceCompetitionFormatSeriesDTO series) {
|
||||
RegattaCompetitionSeries seriesView = new RegattaCompetitionSeries(series);
|
||||
seriesNameToUiComponent.put(series.getSeriesName(), seriesView);
|
||||
regattaSeriesContainerUi.add(seriesView);
|
||||
return seriesView;
|
||||
}
|
||||
|
||||
public void scrollToSeries(final String seriesName) {
|
||||
DOMUtils.scrollToTop(seriesNameToUiComponent.get(seriesName));
|
||||
}
|
||||
}
|
||||
+2
@@ -5,4 +5,6 @@ import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
|
||||
public interface RegattaRacesNavigationProvider {
|
||||
|
||||
PlaceNavigation<?> getRegattaRacesNavigation(String regattaId);
|
||||
|
||||
PlaceNavigation<?> getRegattaRacesNavigation(String regattaId, String seriesName);
|
||||
}
|
||||
+6
@@ -247,6 +247,12 @@ public abstract class AbstractEventActivity<PLACE extends AbstractEventPlace> ex
|
||||
EventContext ctx = new EventContext(getCtx()).withRegattaId(regattaId).withRegattaAnalyticsManager(null);
|
||||
return clientFactory.getNavigator().getEventNavigation(new RegattaRacesPlace(ctx), null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlaceNavigation<?> getRegattaRacesNavigation(String regattaId, String prefSeriesName) {
|
||||
EventContext ctx = new EventContext(getCtx()).withRegattaId(regattaId).withRegattaAnalyticsManager(null);
|
||||
return clientFactory.getNavigator().getEventNavigation(new RegattaRacesPlace(ctx, prefSeriesName), null, false);
|
||||
}
|
||||
|
||||
public PlaceNavigation<?> getLatesNewsNavigation() {
|
||||
EventContext ctx = new EventContext(getCtx()).withRegattaId(null).withRegattaAnalyticsManager(null);
|
||||
|
||||
+5
-1
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.mobile.places.event.overview.regatta;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
@@ -19,6 +20,7 @@ import com.sap.sailing.gwt.home.mobile.partials.quickfinder.Quickfinder;
|
||||
import com.sap.sailing.gwt.home.mobile.places.QuickfinderPresenter;
|
||||
import com.sap.sailing.gwt.home.mobile.places.event.EventViewBase;
|
||||
import com.sap.sailing.gwt.home.mobile.places.event.overview.AbstractEventOverview;
|
||||
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
@@ -54,7 +56,9 @@ public class RegattaOverviewImpl extends AbstractEventOverview {
|
||||
}
|
||||
|
||||
private void setupProgress(Panel container) {
|
||||
eventStepsUi = new EventSteps(currentPresenter.getRegatta());
|
||||
final Function<String, PlaceNavigation<?>> racesNavigationFactory = prefSeriesName -> currentPresenter
|
||||
.getRegattaRacesNavigation(getRegattaId(), prefSeriesName);
|
||||
eventStepsUi = new EventSteps(currentPresenter.getRegatta(), racesNavigationFactory);
|
||||
refreshManager.add(eventStepsUi, new GetRegattaWithProgressAction(getEventId(), getRegattaId()));
|
||||
container.add(eventStepsUi);
|
||||
}
|
||||
|
||||
+6
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.gwt.home.mobile.places.event.races;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.sap.sailing.gwt.home.communication.eventview.EventViewDTO;
|
||||
import com.sap.sailing.gwt.home.desktop.places.event.regatta.racestab.RegattaRacesPlace;
|
||||
@@ -32,4 +33,9 @@ public class RacesActivity extends AbstractEventActivity<RegattaRacesPlace> impl
|
||||
initQuickfinder(view, true);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getPreferredSeriesName() {
|
||||
return getPlace().getPreferredSeriesName();
|
||||
}
|
||||
}
|
||||
+4
@@ -1,10 +1,14 @@
|
||||
package com.sap.sailing.gwt.home.mobile.places.event.races;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.sap.sailing.gwt.home.mobile.places.event.EventViewBase;
|
||||
|
||||
public interface RacesView extends EventViewBase {
|
||||
|
||||
public interface Presenter extends EventViewBase.Presenter {
|
||||
|
||||
Optional<String> getPreferredSeriesName();
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -5,13 +5,16 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.home.communication.event.EventReferenceWithStateDTO;
|
||||
import com.sap.sailing.gwt.home.communication.event.GetCompetitionFormatRacesAction;
|
||||
import com.sap.sailing.gwt.home.communication.event.RaceCompetitionFormatSeriesDTO;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO;
|
||||
import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO;
|
||||
import com.sap.sailing.gwt.home.communication.race.SimpleRaceMetadataDTO;
|
||||
@@ -27,6 +30,7 @@ import com.sap.sailing.gwt.home.shared.partials.filter.RacesByCompetitorTextBoxF
|
||||
import com.sap.sailing.gwt.home.shared.partials.placeholder.InfoPlaceholder;
|
||||
import com.sap.sailing.gwt.home.shared.partials.regattacompetition.RegattaCompetitionPresenter;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.gwt.dispatch.shared.commands.ListResult;
|
||||
|
||||
public class RacesViewImpl extends AbstractEventView<RacesView.Presenter> implements RacesView {
|
||||
|
||||
@@ -71,6 +75,13 @@ public class RacesViewImpl extends AbstractEventView<RacesView.Presenter> implem
|
||||
protected String getRaceViewerURL(SimpleRaceMetadataDTO raceMetadata, String mode) {
|
||||
return currentPresenter.getRaceViewerURL(raceMetadata, mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(ListResult<RaceCompetitionFormatSeriesDTO> data) {
|
||||
super.setData(data);
|
||||
final Consumer<? super String> scrollCommand = regattaCompetitionUi::scrollToSeries;
|
||||
Scheduler.get().scheduleDeferred(() -> currentPresenter.getPreferredSeriesName().ifPresent(scrollCommand));
|
||||
}
|
||||
}
|
||||
|
||||
private class RacesViewImplFilterPresenter extends FilterPresenter<SimpleRaceMetadataDTO, SimpleCompetitorDTO> {
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ public class RaceContext {
|
||||
this.fleet = fleet;
|
||||
trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
raceLog = raceColumn.getRaceLog(fleet);
|
||||
state = (raceLog == null) ? null : ReadonlyRaceStateImpl.create(raceLogResolver, raceLog);
|
||||
state = (raceLog == null) ? null : ReadonlyRaceStateImpl.getOrCreate(raceLogResolver, raceLog);
|
||||
}
|
||||
|
||||
private boolean isShowFleetData() {
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ public abstract class LeaderboardPanelLifecycle<T extends LeaderboardSettings>
|
||||
|
||||
protected final Iterable<DetailType> availableDetailTypes;
|
||||
|
||||
public LeaderboardPanelLifecycle(StringMessages stringMessages, Iterable<DetailType> availableDetailTypes) {
|
||||
protected LeaderboardPanelLifecycle(StringMessages stringMessages, Iterable<DetailType> availableDetailTypes) {
|
||||
this.stringMessages = stringMessages;
|
||||
this.availableDetailTypes = availableDetailTypes;
|
||||
}
|
||||
|
||||
+2
-1
@@ -66,7 +66,8 @@ public abstract class LeaderboardSettings extends AbstractGenericSerializableSet
|
||||
showCompetitorBoatInfoColumn = new BooleanSetting("showCompetitorBoatInfoColumn", this, false);
|
||||
}
|
||||
|
||||
public LeaderboardSettings() {
|
||||
public LeaderboardSettings(boolean showCompetitorBoatInfoColumnDefault) {
|
||||
showCompetitorBoatInfoColumn.setDefaultValue(showCompetitorBoatInfoColumnDefault);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -46,7 +46,8 @@ public abstract class LeaderboardSettingsDialogComponent<T extends LeaderboardSe
|
||||
protected T initialSettings;
|
||||
protected Iterable<DetailType> availableDetailTypes;
|
||||
|
||||
public LeaderboardSettingsDialogComponent(T initialSettings, StringMessages stringMessages, Iterable<DetailType> availableDetailTypes, boolean canBoatInfoBeShown) {
|
||||
protected LeaderboardSettingsDialogComponent(T initialSettings, StringMessages stringMessages,
|
||||
Iterable<DetailType> availableDetailTypes, boolean canBoatInfoBeShown) {
|
||||
this.initialSettings = initialSettings;
|
||||
this.stringMessages = stringMessages;
|
||||
this.canBoatInfoBeShown = canBoatInfoBeShown;
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ public class LeaderboardSettingsFactory {
|
||||
}
|
||||
|
||||
public SingleRaceLeaderboardSettings createNewSettingsWithCustomRaceDetails(List<DetailType> raceDetailsToShow) {
|
||||
SingleRaceLeaderboardSettings defaultSettings = new SingleRaceLeaderboardSettings();
|
||||
SingleRaceLeaderboardSettings defaultSettings = new SingleRaceLeaderboardSettings(false);
|
||||
return new SingleRaceLeaderboardSettings(
|
||||
defaultSettings.getManeuverDetailsToShow(),
|
||||
defaultSettings.getLegDetailsToShow(),
|
||||
|
||||
+4
-1
@@ -11,11 +11,13 @@ import com.sap.sse.common.settings.generic.support.SettingsUtil;
|
||||
public class MultiRaceLeaderboardPanelLifecycle extends LeaderboardPanelLifecycle<MultiRaceLeaderboardSettings> {
|
||||
|
||||
protected final List<String> namesOfRaceColumns;
|
||||
private final boolean canBoatInfoBeShown;
|
||||
|
||||
public MultiRaceLeaderboardPanelLifecycle(AbstractLeaderboardDTO leaderboard, StringMessages stringMessages,
|
||||
Iterable<DetailType> availableDetailTypes) {
|
||||
super(stringMessages, availableDetailTypes);
|
||||
this.namesOfRaceColumns = leaderboard != null ? leaderboard.getNamesOfRaceColumns() : new ArrayList<String>();
|
||||
this.canBoatInfoBeShown = leaderboard != null ? !leaderboard.canBoatsOfCompetitorsChangePerRace : false;
|
||||
}
|
||||
@Override
|
||||
public MultiRaceLeaderboardSettings extractUserSettings(MultiRaceLeaderboardSettings currentLeaderboardSettings) {
|
||||
@@ -55,7 +57,8 @@ public class MultiRaceLeaderboardPanelLifecycle extends LeaderboardPanelLifecycl
|
||||
|
||||
@Override
|
||||
public MultiRaceLeaderboardSettingsDialogComponent getSettingsDialogComponent(MultiRaceLeaderboardSettings settings) {
|
||||
return new MultiRaceLeaderboardSettingsDialogComponent(settings, namesOfRaceColumns, stringMessages, availableDetailTypes, false);
|
||||
return new MultiRaceLeaderboardSettingsDialogComponent(settings, namesOfRaceColumns, stringMessages,
|
||||
availableDetailTypes, canBoatInfoBeShown);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-1
@@ -28,7 +28,7 @@ public class MultiRaceLeaderboardSettings extends LeaderboardSettings {
|
||||
|
||||
|
||||
public MultiRaceLeaderboardSettings() {
|
||||
super();
|
||||
super(false);
|
||||
}
|
||||
|
||||
public MultiRaceLeaderboardSettings(Collection<DetailType> maneuverDetailsToShow,
|
||||
@@ -48,6 +48,7 @@ public class MultiRaceLeaderboardSettings extends LeaderboardSettings {
|
||||
}
|
||||
|
||||
public MultiRaceLeaderboardSettings(Iterable<String> namesOfRaceColumnsToShow) {
|
||||
super(false);
|
||||
this.namesOfRaceColumnsToShow.setValues(namesOfRaceColumnsToShow);
|
||||
}
|
||||
|
||||
@@ -63,6 +64,7 @@ public class MultiRaceLeaderboardSettings extends LeaderboardSettings {
|
||||
newSettings.showAddedScores.setValue(this.isShowAddedScores());
|
||||
newSettings.showCompetitorShortNameColumn.setValue(this.isShowCompetitorShortNameColumn());
|
||||
newSettings.showCompetitorFullNameColumn.setValue(this.isShowCompetitorFullNameColumn());
|
||||
newSettings.showCompetitorBoatInfoColumn.setValue(this.isShowCompetitorBoatInfoColumn());
|
||||
newSettings.isShowCompetitorNationality.setValue(this.isShowCompetitorNationality());
|
||||
newSettings.namesOfRaceColumnsToShow.setValues(this.getNamesOfRaceColumnsToShow());
|
||||
newSettings.namesOfRaceColumnsToShow.setDefaultValues(namesOfRaceColumns);
|
||||
|
||||
+4
-2
@@ -9,8 +9,10 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
|
||||
public class OverallLeaderboardSettingsDialogComponent extends MultiRaceLeaderboardSettingsDialogComponent {
|
||||
|
||||
public OverallLeaderboardSettingsDialogComponent(MultiRaceLeaderboardSettings initialSettings, List<String> allRaceColumnNames, StringMessages stringMessages, Iterable<DetailType> availableDetailTypes) {
|
||||
super(initialSettings, allRaceColumnNames, stringMessages, availableDetailTypes, false);
|
||||
public OverallLeaderboardSettingsDialogComponent(MultiRaceLeaderboardSettings initialSettings,
|
||||
List<String> allRaceColumnNames, StringMessages stringMessages, Iterable<DetailType> availableDetailTypes) {
|
||||
super(initialSettings, allRaceColumnNames, stringMessages, availableDetailTypes,
|
||||
/* canBoatInfoBeShown */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-4
@@ -10,15 +10,16 @@ public class SingleRaceLeaderboardSettings extends LeaderboardSettings {
|
||||
|
||||
private BooleanSetting showRaceRankColumn;
|
||||
|
||||
public SingleRaceLeaderboardSettings() {
|
||||
super();
|
||||
public SingleRaceLeaderboardSettings(boolean showCompetitorBoatInfoColumnDefault) {
|
||||
super(showCompetitorBoatInfoColumnDefault);
|
||||
}
|
||||
|
||||
public SingleRaceLeaderboardSettings(Collection<DetailType> maneuverDetailsToShow,
|
||||
Collection<DetailType> legDetailsToShow, Collection<DetailType> raceDetailsToShow,
|
||||
Collection<DetailType> overallDetailsToShow, Long delayBetweenAutoAdvancesInMilliseconds,
|
||||
boolean showAddedScores, boolean showCompetitorShortNameColumn,
|
||||
boolean showCompetitorFullNameColumn, boolean showCompetitorBoatInfoColumn, boolean isCompetitorNationalityColumnVisible,boolean showRaceRankColumn) {
|
||||
boolean showAddedScores, boolean showCompetitorShortNameColumn, boolean showCompetitorFullNameColumn,
|
||||
boolean showCompetitorBoatInfoColumn, boolean isCompetitorNationalityColumnVisible,
|
||||
boolean showRaceRankColumn) {
|
||||
super(maneuverDetailsToShow, legDetailsToShow, raceDetailsToShow, overallDetailsToShow,
|
||||
delayBetweenAutoAdvancesInMilliseconds, showAddedScores, showCompetitorShortNameColumn,
|
||||
showCompetitorFullNameColumn, showCompetitorBoatInfoColumn, isCompetitorNationalityColumnVisible);
|
||||
|
||||
+4
-3
@@ -13,11 +13,11 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog.Validator;
|
||||
public class SingleRaceLeaderboardSettingsDialogComponent
|
||||
extends LeaderboardSettingsDialogComponent<SingleRaceLeaderboardSettings> {
|
||||
|
||||
protected CheckBox showRaceRankColumn;
|
||||
private CheckBox showRaceRankColumn;
|
||||
|
||||
public SingleRaceLeaderboardSettingsDialogComponent(SingleRaceLeaderboardSettings initialSettings,
|
||||
StringMessages stringMessages, Iterable<DetailType> availableDetailTypes) {
|
||||
super(initialSettings, stringMessages, availableDetailTypes, true /*canBoatInfoBeShown*/);
|
||||
super(initialSettings, stringMessages, availableDetailTypes, /* canBoatInfoBeShown */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,7 +33,8 @@ public class SingleRaceLeaderboardSettingsDialogComponent
|
||||
1000l * (delayBetweenAutoAdvancesValue == null ? 0l : delayBetweenAutoAdvancesValue.longValue()),
|
||||
/* showAddedScores */ showAddedScoresCheckBox.getValue().booleanValue(),
|
||||
showCompetitorShortNameColumnCheckBox.getValue(), showCompetitorFullNameColumnCheckBox.getValue(),
|
||||
showCompetitorBoatInfoColumnCheckBox.getValue(), isCompetitorNationalityColumnVisible.getValue(), showRaceRankColumn.getValue());
|
||||
showCompetitorBoatInfoColumnCheckBox.getValue(), isCompetitorNationalityColumnVisible.getValue(),
|
||||
showRaceRankColumn.getValue());
|
||||
return newSettings;
|
||||
}
|
||||
|
||||
|
||||
+45
-22
@@ -25,6 +25,7 @@ import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.IntegerBox;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ListBox;
|
||||
import com.google.gwt.user.client.ui.PasswordTextBox;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.view.client.ListDataProvider;
|
||||
@@ -62,6 +63,9 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
private final ListBox previousConfigurationsComboBox;
|
||||
private final TextBox eventIdBox;
|
||||
private final TextBox jsonUrlBox;
|
||||
private final TextBox updateURLBox;
|
||||
private final TextBox updateUsernameBox;
|
||||
private final PasswordTextBox updatePasswordBox;
|
||||
private final TextBox hostnameTextbox;
|
||||
private final IntegerBox portIntegerbox;
|
||||
private final List<SwissTimingRaceRecordDTO> availableSwissTimingRaces = new ArrayList<SwissTimingRaceRecordDTO>();
|
||||
@@ -75,22 +79,16 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
RegattaRefresher regattaRefresher, StringMessages stringConstants) {
|
||||
super(sailingService, regattaRefresher, errorReporter, true, stringConstants);
|
||||
this.errorReporter = errorReporter;
|
||||
|
||||
VerticalPanel mainPanel = new VerticalPanel();
|
||||
this.setWidget(mainPanel);
|
||||
mainPanel.setWidth("100%");
|
||||
|
||||
CaptionPanel captionPanelConnections = new CaptionPanel(stringConstants.connections());
|
||||
mainPanel.add(captionPanelConnections);
|
||||
|
||||
VerticalPanel verticalPanel = new VerticalPanel();
|
||||
|
||||
captionPanelConnections.setContentWidget(verticalPanel);
|
||||
captionPanelConnections.setStyleName("bold");
|
||||
|
||||
Grid connectionsGrid = new Grid(6, 2);
|
||||
Grid connectionsGrid = new Grid(9, 2);
|
||||
verticalPanel.add(connectionsGrid);
|
||||
|
||||
previousConfigurations = new HashMap<String, SwissTimingConfigurationDTO>();
|
||||
previousConfigurationsComboBox = new ListBox();
|
||||
connectionsGrid.setWidget(0, 1, previousConfigurationsComboBox);
|
||||
@@ -107,10 +105,6 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
}
|
||||
});
|
||||
fillConfigurations();
|
||||
|
||||
jsonUrlBox = new TextBox();
|
||||
jsonUrlBox.getElement().getStyle().setWidth(50, Unit.EM);
|
||||
|
||||
connectionsGrid.setWidget(0, 0, new Label(stringMessages.swissTimingEvents() + ":"));
|
||||
connectionsGrid.setWidget(0, 1, previousConfigurationsComboBox);
|
||||
|
||||
@@ -125,6 +119,8 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
}
|
||||
});
|
||||
|
||||
jsonUrlBox = new TextBox();
|
||||
jsonUrlBox.getElement().getStyle().setWidth(50, Unit.EM);
|
||||
connectionsGrid.setWidget(2, 0, new Label(stringMessages.manage2SailEventURLBox() + ":"));
|
||||
connectionsGrid.setWidget(2, 1, jsonUrlBox);
|
||||
jsonUrlBox.addChangeHandler(event -> {
|
||||
@@ -142,8 +138,23 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
connectionsGrid.setWidget(4, 0, new Label(stringMessages.manage2SailPort() + ":"));
|
||||
connectionsGrid.setWidget(4, 1, portIntegerbox);
|
||||
|
||||
updateURLBox = new TextBox();
|
||||
updateURLBox.getElement().getStyle().setWidth(50, Unit.EM);
|
||||
connectionsGrid.setWidget(5, 0, new Label(stringMessages.swissTimingUpdateURL() + ":"));
|
||||
connectionsGrid.setWidget(5, 1, updateURLBox);
|
||||
|
||||
updateUsernameBox = new TextBox();
|
||||
updateUsernameBox.getElement().getStyle().setWidth(50, Unit.EM);
|
||||
connectionsGrid.setWidget(6, 0, new Label(stringMessages.swissTimingUpdateUsername() + ":"));
|
||||
connectionsGrid.setWidget(6, 1, updateUsernameBox);
|
||||
|
||||
updatePasswordBox = new PasswordTextBox();
|
||||
updatePasswordBox.getElement().getStyle().setWidth(50, Unit.EM);
|
||||
connectionsGrid.setWidget(7, 0, new Label(stringMessages.swissTimingUpdatePassword() + ":"));
|
||||
connectionsGrid.setWidget(7, 1, updatePasswordBox);
|
||||
|
||||
Button btnListRaces = new Button(stringConstants.listRaces());
|
||||
connectionsGrid.setWidget(5, 1, btnListRaces);
|
||||
connectionsGrid.setWidget(8, 1, btnListRaces);
|
||||
btnListRaces.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
@@ -459,6 +470,9 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
|
||||
private void fillRaces(final SailingServiceAsync sailingService) {
|
||||
final String jsonUrl = jsonUrlBox.getValue();
|
||||
final String updateURL = updateURLBox.getValue();
|
||||
final String updateUsername = updateUsernameBox.getValue();
|
||||
final String updatePassword = updatePasswordBox.getValue();
|
||||
sailingService.getRacesOfSwissTimingEvent(jsonUrl, new AsyncCallback<SwissTimingEventRecordDTO>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
@@ -469,21 +483,18 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
@Override
|
||||
public void onSuccess(final SwissTimingEventRecordDTO result) {
|
||||
availableSwissTimingRaces.clear();
|
||||
if (result != null)
|
||||
if (result != null) {
|
||||
availableSwissTimingRaces.addAll(result.races);
|
||||
|
||||
}
|
||||
raceList.getList().clear();
|
||||
raceList.getList().addAll(availableSwissTimingRaces);
|
||||
|
||||
filterablePanelEvents.getTextBox().setText(null);
|
||||
filterablePanelEvents.updateAll(result.races);
|
||||
|
||||
// store a successful configuration in the database for later retrieval
|
||||
final String hostname = result.trackingDataHost;
|
||||
final Integer port = result.trackingDataPort;
|
||||
final String configName = result.eventName;
|
||||
|
||||
sailingService.storeSwissTimingConfiguration(configName, jsonUrl, hostname, port,
|
||||
sailingService.storeSwissTimingConfiguration(configName, jsonUrl, hostname, port, updateURL, updateUsername, updatePassword,
|
||||
new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
@@ -495,10 +506,16 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
public void onSuccess(Void voidResult) {
|
||||
// refresh list of previous configurations
|
||||
SwissTimingConfigurationDTO stConfig = new SwissTimingConfigurationDTO(configName, jsonUrl,
|
||||
hostname, port);
|
||||
hostname, port, updateURL, updateUsername, updatePassword);
|
||||
if (previousConfigurations.put(stConfig.getName(), stConfig) == null) {
|
||||
previousConfigurationsComboBox.addItem(stConfig.getName());
|
||||
}
|
||||
for (int i=0; i<previousConfigurationsComboBox.getItemCount(); i++) {
|
||||
if (previousConfigurationsComboBox.getValue(i).equals(stConfig.getName())) {
|
||||
previousConfigurationsComboBox.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
updatePanelFromSelectedStoredConfiguration();
|
||||
}
|
||||
});
|
||||
@@ -507,8 +524,11 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
}
|
||||
|
||||
private void trackSelectedRaces(boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm) {
|
||||
String hostname = hostnameTextbox.getValue();
|
||||
Integer port = portIntegerbox.getValue();
|
||||
final String hostname = hostnameTextbox.getValue();
|
||||
final Integer port = portIntegerbox.getValue();
|
||||
final String updateURL = updateURLBox.getValue();
|
||||
final String updateUsername = updateUsernameBox.getValue();
|
||||
final String updatePassword = updatePasswordBox.getValue();
|
||||
final List<SwissTimingRaceRecordDTO> selectedRaces = new ArrayList<SwissTimingRaceRecordDTO>();
|
||||
for (final SwissTimingRaceRecordDTO race : this.raceList.getList()) {
|
||||
if (raceTable.getSelectionModel().isSelected(race)) {
|
||||
@@ -526,7 +546,7 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
sailingService.trackWithSwissTiming(
|
||||
/* regattaToAddTo */ regattaIdentifier,
|
||||
selectedRaces, hostname, port, trackWind, correctWindByDeclination,
|
||||
useInternalMarkPassingAlgorithm, new AsyncCallback<Void>() {
|
||||
useInternalMarkPassingAlgorithm, updateURL, updateUsername, updatePassword, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Error trying to register races " + selectedRaces + " for tracking: "
|
||||
@@ -549,6 +569,9 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
|
||||
hostnameTextbox.setValue(stConfig.getHostname());
|
||||
portIntegerbox.setValue(stConfig.getPort());
|
||||
jsonUrlBox.setValue(stConfig.getJsonURL());
|
||||
updateURLBox.setValue(stConfig.getUpdateURL());
|
||||
updateUsernameBox.setValue(stConfig.getUpdateUsername());
|
||||
updatePasswordBox.setValue(stConfig.getUpdatePassword());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -28,6 +28,7 @@ import com.google.gwt.user.client.ui.HTMLTable.ColumnFormatter;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ListBox;
|
||||
import com.google.gwt.user.client.ui.PasswordTextBox;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
@@ -79,7 +80,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
private TextBox jsonURLTextBox;
|
||||
private TextBox tracTracUpdateURITextBox;
|
||||
private TextBox tractracUsernameTextBox;
|
||||
private TextBox tractracPasswordTextBox;
|
||||
private PasswordTextBox tractracPasswordTextBox;
|
||||
private Label loadingMessageLabel;
|
||||
|
||||
private LabeledAbstractFilterablePanel<TracTracRaceRecordDTO> racesFilterablePanel;
|
||||
@@ -199,7 +200,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
grid.setWidget(6, 1, tractracUsernameTextBox);
|
||||
|
||||
// TracTrac Password
|
||||
tractracPasswordTextBox = new TextBox();
|
||||
tractracPasswordTextBox = new PasswordTextBox();
|
||||
tractracPasswordTextBox.ensureDebugId("TracTracPasswordTextBox");
|
||||
tractracPasswordTextBox.setVisibleLength(40);
|
||||
|
||||
@@ -222,10 +223,8 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
}
|
||||
});
|
||||
grid.setWidget(9, 1, listRacesButton);
|
||||
|
||||
loadingMessageLabel = new Label();
|
||||
grid.setWidget(9, 2, loadingMessageLabel);
|
||||
|
||||
return connectionsPanel;
|
||||
}
|
||||
|
||||
|
||||
+22
-15
@@ -61,15 +61,16 @@ public class TrackedRacesManagementPanel extends AbstractRaceManagementPanel {
|
||||
controlsPanel.add(setStartTimeButton);
|
||||
selectedRaceContentPanel.add(controlsPanel);
|
||||
|
||||
raceDataGrid = new Grid(6,2);
|
||||
raceDataGrid = new Grid(7, 2);
|
||||
this.selectedRaceContentPanel.add(raceDataGrid);
|
||||
|
||||
raceDataGrid.setText(0, 0, stringMessages.startTime()+":");
|
||||
raceDataGrid.setText(1, 0, stringMessages.endTime()+":");
|
||||
raceDataGrid.setText(2, 0, stringMessages.duration()+":");
|
||||
raceDataGrid.setText(3, 0, stringMessages.startOfTracking()+":");
|
||||
raceDataGrid.setText(4, 0, stringMessages.endOfTracking()+":");
|
||||
raceDataGrid.setText(5, 0, stringMessages.delayForLiveMode()+" (ms):");
|
||||
raceDataGrid.setText(2, 0, stringMessages.finishingTime()+":");
|
||||
raceDataGrid.setText(3, 0, stringMessages.duration()+":");
|
||||
raceDataGrid.setText(4, 0, stringMessages.startOfTracking()+":");
|
||||
raceDataGrid.setText(5, 0, stringMessages.endOfTracking()+":");
|
||||
raceDataGrid.setText(6, 0, stringMessages.delayForLiveMode()+" (ms):");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,26 +88,32 @@ public class TrackedRacesManagementPanel extends AbstractRaceManagementPanel {
|
||||
} else {
|
||||
raceDataGrid.setText(1, 1, "");
|
||||
}
|
||||
if(selectedRaceDTO.startOfRace != null && selectedRaceDTO.endOfRace != null) {
|
||||
Date duration = new Date(selectedRaceDTO.endOfRace.getTime() - selectedRaceDTO.startOfRace.getTime());
|
||||
raceDataGrid.setText(2, 1, durationFormatter.render(duration));
|
||||
if (selectedRaceDTO.raceFinishedTime != null) {
|
||||
raceDataGrid.setText(2, 1, dateFormatter.render(selectedRaceDTO.raceFinishedTime) + " "
|
||||
+ timeFormatter.render(selectedRaceDTO.raceFinishedTime));
|
||||
} else {
|
||||
raceDataGrid.setText(2, 1, "");
|
||||
}
|
||||
if (selectedRaceDTO.trackedRace != null && selectedRaceDTO.trackedRace.startOfTracking != null) {
|
||||
raceDataGrid.setText(3, 1, dateFormatter.render(selectedRaceDTO.trackedRace.startOfTracking) + " "
|
||||
+ timeFormatter.render(selectedRaceDTO.trackedRace.startOfTracking));
|
||||
if(selectedRaceDTO.startOfRace != null && selectedRaceDTO.endOfRace != null) {
|
||||
Date duration = new Date(selectedRaceDTO.endOfRace.getTime() - selectedRaceDTO.startOfRace.getTime());
|
||||
raceDataGrid.setText(3, 1, durationFormatter.render(duration));
|
||||
} else {
|
||||
raceDataGrid.setText(3, 1, "");
|
||||
}
|
||||
if (selectedRaceDTO.trackedRace != null && selectedRaceDTO.trackedRace.endOfTracking != null) {
|
||||
raceDataGrid.setText(4, 1, dateFormatter.render(selectedRaceDTO.trackedRace.endOfTracking) + " "
|
||||
+ timeFormatter.render(selectedRaceDTO.trackedRace.endOfTracking));
|
||||
if (selectedRaceDTO.trackedRace != null && selectedRaceDTO.trackedRace.startOfTracking != null) {
|
||||
raceDataGrid.setText(4, 1, dateFormatter.render(selectedRaceDTO.trackedRace.startOfTracking) + " "
|
||||
+ timeFormatter.render(selectedRaceDTO.trackedRace.startOfTracking));
|
||||
} else {
|
||||
raceDataGrid.setText(4, 1, "");
|
||||
}
|
||||
if (selectedRaceDTO.trackedRace != null && selectedRaceDTO.trackedRace.endOfTracking != null) {
|
||||
raceDataGrid.setText(5, 1, dateFormatter.render(selectedRaceDTO.trackedRace.endOfTracking) + " "
|
||||
+ timeFormatter.render(selectedRaceDTO.trackedRace.endOfTracking));
|
||||
} else {
|
||||
raceDataGrid.setText(5, 1, "");
|
||||
}
|
||||
if (selectedRaceDTO.trackedRace != null) {
|
||||
raceDataGrid.setText(5, 1, "" + selectedRaceDTO.trackedRace.delayToLiveInMs);
|
||||
raceDataGrid.setText(6, 1, "" + selectedRaceDTO.trackedRace.delayToLiveInMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -146,8 +146,9 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
String storedURI, String courseDesignUpdateURI, boolean trackWind, boolean correctWindByDeclination,
|
||||
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword) throws Exception;
|
||||
|
||||
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable<SwissTimingRaceRecordDTO> rrs, String hostname, int port,
|
||||
boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm) throws Exception;
|
||||
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable<SwissTimingRaceRecordDTO> rrs, String hostname,
|
||||
int port, boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm,
|
||||
String updateURL, String updateUsername, String updatePassword) throws Exception;
|
||||
|
||||
void replaySwissTimingRace(RegattaIdentifier regattaIdentifier, Iterable<SwissTimingReplayRaceDTO> replayRaces,
|
||||
boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm);
|
||||
@@ -286,7 +287,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
|
||||
SwissTimingEventRecordDTO getRacesOfSwissTimingEvent(String eventJsonURL) throws Exception;
|
||||
|
||||
void storeSwissTimingConfiguration(String configName, String jsonURL, String hostname, Integer port);
|
||||
void storeSwissTimingConfiguration(String configName, String jsonURL, String hostname, Integer port, String updateURL, String updateUsername, String updatePassword);
|
||||
|
||||
String[] getCountryCodes();
|
||||
|
||||
|
||||
+2
-2
@@ -163,7 +163,7 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
|
||||
|
||||
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable<SwissTimingRaceRecordDTO> rrs,
|
||||
String hostname, int port, boolean trackWind, boolean correctWindByDeclination,
|
||||
boolean useInternalMarkPassingAlgorithm, AsyncCallback<Void> asyncCallback);
|
||||
boolean useInternalMarkPassingAlgorithm, String updateURL, String updateUsername, String updatePassword, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void replaySwissTimingRace(RegattaIdentifier regattaIdentifier, Iterable<SwissTimingReplayRaceDTO> replayRaces,
|
||||
boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm,
|
||||
@@ -334,7 +334,7 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
|
||||
void getRacesOfSwissTimingEvent(String eventJsonUrl, AsyncCallback<SwissTimingEventRecordDTO> asyncCallback);
|
||||
|
||||
void storeSwissTimingConfiguration(String configName, String jsonURL, String hostname, Integer port,
|
||||
AsyncCallback<Void> asyncCallback);
|
||||
String updateURL, String updateUsername, String updatePassword, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void getCountryCodes(AsyncCallback<String[]> callback);
|
||||
|
||||
|
||||
Loaded 100 of 131 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user