mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-10 06:10:56 +00:00
Merge remote-tracking branch 'origin/master' into design2015
This commit is contained in:
commit
4941775fb6
64 files changed
+1076
-360
No files matched your search
@@ -22,7 +22,7 @@
|
||||
}
|
||||
|
||||
.highcharts-container {
|
||||
position: absulute;
|
||||
position: absolute;
|
||||
top: 0pt;
|
||||
bottom: 0pt;
|
||||
left: 0pt;
|
||||
@@ -38,11 +38,10 @@
|
||||
width: 100%;
|
||||
bottom: 0pt;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 15pt;
|
||||
line-height: 30pt;
|
||||
color: black;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@@ -134,5 +133,5 @@
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
color: grey;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
}
|
||||
@@ -10,10 +10,12 @@
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
|
||||
<link href='images/dashboardicon.png' rel='apple-touch-icon'>
|
||||
|
||||
<title>ESS Dashboard</title>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/dashboardicon.png" />
|
||||
<link href='images/dashboardicon.png' rel='apple-touch-icon'>
|
||||
<link rel="stylesheet" type="text/css" href="/sailing-fontface-1.0.cache.css">
|
||||
|
||||
<title>Dashboard</title>
|
||||
|
||||
<script type="text/javascript" src="js/jquery-1.5.2.min.js"></script>
|
||||
<script type="text/javascript" src="highcharts/js/highcharts.js"></script>
|
||||
|
||||
@@ -12,6 +12,6 @@ bin.includes = META-INF/,\
|
||||
js/,\
|
||||
WEB-INF/lib/gwt-ajaxloader.jar,\
|
||||
fonts/,\
|
||||
fontface.css
|
||||
images/
|
||||
output.. = WEB-INF/classes/
|
||||
bin.excludes = WEB-INF/lib/
|
||||
@@ -1,115 +0,0 @@
|
||||
/* Generated by Font Squirrel (http://www.fontsquirrel.com) on October 17, 2012 06:01:42 AM America/New_York */
|
||||
|
||||
|
||||
/* @font-face { */
|
||||
/* font-family: 'OpenSansLightItalic'; */
|
||||
/* src: url('fonts/OpenSans-LightItalic-webfont.eot'); */
|
||||
/* src: url('fonts/OpenSans-LightItalic-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/OpenSans-LightItalic-webfont.woff') format('woff'), url('fonts/OpenSans-LightItalic-webfont.ttf') format('truetype'), url('fonts/OpenSans-LightItalic-webfont.svg#OpenSansLightItalic') format('svg'); */
|
||||
/* font-weight: normal; */
|
||||
/* font-style: normal; */
|
||||
|
||||
/* } */
|
||||
|
||||
@font-face {
|
||||
font-family: 'OpenSansRegular';
|
||||
src: url('fonts/OpenSans-Regular-webfont.eot');
|
||||
src: url('fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/OpenSans-Regular-webfont.woff') format('woff'), url('fonts/OpenSans-Regular-webfont.ttf') format('truetype'), url('fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* @font-face { */
|
||||
/* font-family: 'OpenSansItalic'; */
|
||||
/* src: url('fonts/OpenSans-Italic-webfont.eot'); */
|
||||
/* src: url('fonts/OpenSans-Italic-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/OpenSans-Italic-webfont.woff') format('woff'), url('fonts/OpenSans-Italic-webfont.ttf') format('truetype'), url('fonts/OpenSans-Italic-webfont.svg#OpenSansItalic') format('svg'); */
|
||||
/* font-weight: normal; */
|
||||
/* font-style: normal; */
|
||||
|
||||
/* } */
|
||||
|
||||
/* @font-face { */
|
||||
/* font-family: 'OpenSansSemibold'; */
|
||||
/* src: url('fonts/OpenSans-Semibold-webfont.eot'); */
|
||||
/* src: url('fonts/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/OpenSans-Semibold-webfont.woff') format('woff'), url('fonts/OpenSans-Semibold-webfont.ttf') format('truetype'), url('fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg'); */
|
||||
/* font-weight: normal; */
|
||||
/* font-style: normal; */
|
||||
|
||||
/* } */
|
||||
|
||||
/* @font-face { */
|
||||
/* font-family: 'OpenSansSemiboldItalic'; */
|
||||
/* src: url('fonts/OpenSans-SemiboldItalic-webfont.eot'); */
|
||||
/* src: url('fonts/OpenSans-SemiboldItalic-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/OpenSans-SemiboldItalic-webfont.woff') format('woff'), url('fonts/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'), url('fonts/OpenSans-SemiboldItalic-webfont.svg#OpenSansSemiboldItalic') format('svg'); */
|
||||
/* font-weight: normal; */
|
||||
/* font-style: normal; */
|
||||
|
||||
/* } */
|
||||
|
||||
@font-face {
|
||||
font-family: 'OpenSansBold';
|
||||
src: url('fonts/OpenSans-Bold-webfont.eot');
|
||||
src: url('fonts/OpenSans-Bold-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/OpenSans-Bold-webfont.woff') format('woff'), url('fonts/OpenSans-Bold-webfont.ttf') format('truetype'), url('fonts/OpenSans-Bold-webfont.svg#OpenSansBold') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
|
||||
}
|
||||
|
||||
/* @font-face { */
|
||||
/* font-family: 'OpenSansBoldItalic'; */
|
||||
/* src: url('fonts/OpenSans-BoldItalic-webfont.eot'); */
|
||||
/* src: url('fonts/OpenSans-BoldItalic-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/OpenSans-BoldItalic-webfont.woff') format('woff'), url('fonts/OpenSans-BoldItalic-webfont.ttf') format('truetype'), url('fonts/OpenSans-BoldItalic-webfont.svg#OpenSansBoldItalic') format('svg'); */
|
||||
/* font-weight: normal; */
|
||||
/* font-style: normal; */
|
||||
|
||||
/* } */
|
||||
|
||||
/* @font-face { */
|
||||
/* font-family: 'OpenSansExtrabold'; */
|
||||
/* src: url('fonts/OpenSans-ExtraBold-webfont.eot'); */
|
||||
/* src: url('fonts/OpenSans-ExtraBold-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/OpenSans-ExtraBold-webfont.woff') format('woff'), url('fonts/OpenSans-ExtraBold-webfont.ttf') format('truetype'), url('fonts/OpenSans-ExtraBold-webfont.svg#OpenSansExtrabold') format('svg'); */
|
||||
/* font-weight: normal; */
|
||||
/* font-style: normal; */
|
||||
|
||||
/* } */
|
||||
|
||||
/* @font-face { */
|
||||
/* font-family: 'OpenSansExtraboldItalic'; */
|
||||
/* src: url('fonts/OpenSans-ExtraBoldItalic-webfont.eot'); */
|
||||
/* src: url('fonts/OpenSans-ExtraBoldItalic-webfont.eot?#iefix') format('embedded-opentype'), url('fonts/OpenSans-ExtraBoldItalic-webfont.woff') format('woff'), url('fonts/OpenSans-ExtraBoldItalic-webfont.ttf') format('truetype'), url('fonts/OpenSans-ExtraBoldItalic-webfont.svg#OpenSansExtraboldItalic') format('svg'); */
|
||||
/* font-weight: normal; */
|
||||
/* font-style: normal; */
|
||||
|
||||
/* } */
|
||||
|
||||
/* @font-face { */
|
||||
/* font-family: 'OpenSansCondensedLight'; */
|
||||
/* src: url('fonts/OpenSans-CondLight-webfont.eot'); */
|
||||
/* src: url('fonts/OpenSans-CondLight-webfont.eot?#iefix') format('embedded-opentype'), */
|
||||
/* url('fonts/OpenSans-CondLight-webfont.woff') format('woff'), */
|
||||
/* url('fonts/OpenSans-CondLight-webfont.ttf') format('truetype'); */
|
||||
/* font-weight: normal; */
|
||||
/* font-style: normal; */
|
||||
|
||||
/* } */
|
||||
|
||||
/* @font-face { */
|
||||
/* font-family: 'OpenSansCondensedLightItalic'; */
|
||||
/* src: url('fonts/OpenSans-CondLightItalic-webfont.eot'); */
|
||||
/* src: url('fonts/OpenSans-CondLightItalic-webfont.eot?#iefix') format('embedded-opentype'), */
|
||||
/* url('fonts/OpenSans-CondLightItalic-webfont.woff') format('woff'), */
|
||||
/* url('fonts/OpenSans-CondLightItalic-webfont.ttf') format('truetype'); */
|
||||
/* font-weight: normal; */
|
||||
/* font-style: normal; */
|
||||
|
||||
/* } */
|
||||
|
||||
/* @font-face { */
|
||||
/* font-family: 'OpenSansCondensedBold'; */
|
||||
/* src: url('fonts/OpenSans-CondBold-webfont.eot'); */
|
||||
/* src: url('fonts/OpenSans-CondBold-webfont.eot?#iefix') format('embedded-opentype'), */
|
||||
/* url('fonts/OpenSans-CondBold-webfont.woff') format('woff'), */
|
||||
/* url('fonts/OpenSans-CondBold-webfont.ttf') format('truetype'); */
|
||||
/* font-weight: normal; */
|
||||
/* font-style: normal; */
|
||||
|
||||
/* } */
|
||||
+5
-6
@@ -1,4 +1,3 @@
|
||||
@import url(fontface.css);
|
||||
|
||||
.bar {
|
||||
height: 100%;
|
||||
@@ -6,7 +5,7 @@
|
||||
line-height: 15pt;
|
||||
vertical-align: middle;
|
||||
font-size: 15pt;
|
||||
font-family: 'OpenSansRegular', Arial, Verdana, sans-serif;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
@@ -67,7 +66,7 @@
|
||||
line-height: 25pt;
|
||||
vertical-align: middle;
|
||||
font-size: 15pt;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
@@ -165,7 +164,7 @@
|
||||
margin-top: 0pt;
|
||||
vertical-align: middle;
|
||||
font-size: 12pt;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -178,7 +177,7 @@
|
||||
margin-top: 0pt;
|
||||
vertical-align: middle;
|
||||
font-size: 12pt;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -312,7 +311,7 @@ windchartcontainer {
|
||||
margin-top: 0pt;
|
||||
vertical-align: middle;
|
||||
font-size: 12pt;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
top: 50%;
|
||||
|
||||
+12
-6
@@ -3,6 +3,7 @@ package com.sap.sailing.dashboards.gwt.client.eventlogo;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.dom.client.Style.Visibility;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
@@ -23,12 +24,17 @@ public class EventLogo extends Image {
|
||||
sailingServiceAsync.getEventById(eventUUID, true, new AsyncCallback<EventDTO>() {
|
||||
@Override
|
||||
public void onSuccess(final EventDTO event) {
|
||||
final ImageDTO logo = event.getLogoImage();
|
||||
if (logo != null) {
|
||||
eventLogo.getElement().setAttribute("src", logo.getSourceRef());
|
||||
} else {
|
||||
eventLogo.getElement().getStyle().setVisibility(Visibility.HIDDEN);
|
||||
}
|
||||
if (event != null) {
|
||||
final ImageDTO logo = event.getLogoImage();
|
||||
if (logo != null) {
|
||||
eventLogo.getElement().setAttribute("src", logo.getSourceRef());
|
||||
} else {
|
||||
eventLogo.getElement().getStyle().setVisibility(Visibility.HIDDEN);
|
||||
}
|
||||
if (event.getName() != null) {
|
||||
Window.setTitle(event.getName() + " Dashboard");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-1
@@ -61,6 +61,7 @@
|
||||
padding: 0px;
|
||||
margin-top: 5pt;
|
||||
margin-left: 0px;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
.popup_button:active {
|
||||
@@ -76,7 +77,7 @@
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
color: grey;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
.blurred {
|
||||
|
||||
+3
-3
@@ -16,7 +16,7 @@
|
||||
line-height: 30pt;
|
||||
vertical-align: middle;
|
||||
font-size: 15pt;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
@@ -91,7 +91,7 @@
|
||||
line-height: 25pt;
|
||||
vertical-align: middle;
|
||||
font-size: 11pt;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
color: white;
|
||||
line-height: 25pt;
|
||||
font-size: 11pt;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ public class StartlineAnalysisCard extends Composite implements HasWidgets, Star
|
||||
zoomTypes.add(ZoomTypes.BUOYS);
|
||||
} else {
|
||||
timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds);
|
||||
zoomTypes.add(ZoomTypes.TAILS);
|
||||
zoomTypes.add(ZoomTypes.BOATS);
|
||||
}
|
||||
AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
|
||||
RaceTimesInfoProvider raceTimesInfoProvider = new RaceTimesInfoProvider(sailingServiceAsync,
|
||||
|
||||
+11
-3
@@ -21,7 +21,7 @@
|
||||
line-height: 15pt;
|
||||
vertical-align: middle;
|
||||
font-size: 12.5pt;
|
||||
font-family: "Arial;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
overflow: visible;
|
||||
@@ -55,19 +55,27 @@
|
||||
}
|
||||
|
||||
.liveAverageCompoment_panel_value_number {
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
font-size: 27pt;
|
||||
}
|
||||
|
||||
.liveAverageCompoment_panel_value_unit {
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
.liveAverageCompoment_panel_value_unit_degrees {
|
||||
position: absolute;
|
||||
font-size: 20pt;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
.liveAverageCompoment_value_panel {
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
text-align: center;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
@@ -78,7 +86,7 @@
|
||||
text-align: center;
|
||||
font-size: 12pt;
|
||||
color: grey;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
.liveAverageCompoment_liveLabelContainer {
|
||||
|
||||
+11
-9
@@ -5,9 +5,7 @@ import java.util.Iterator;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.DivElement;
|
||||
import com.google.gwt.dom.client.SpanElement;
|
||||
import com.google.gwt.dom.client.Style;
|
||||
import com.google.gwt.dom.client.Style.Position;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.resources.client.CssResource;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
@@ -32,6 +30,11 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti
|
||||
|
||||
interface LiveAverageComponentUiBinder extends UiBinder<Widget, LiveAverageComponent> {
|
||||
}
|
||||
|
||||
interface LiveAverageComponentStyle extends CssResource {
|
||||
|
||||
String liveAverageCompoment_panel_value_unit_degrees();
|
||||
}
|
||||
|
||||
@UiField
|
||||
HTMLPanel liveAveragePanel;
|
||||
@@ -65,6 +68,9 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti
|
||||
|
||||
@UiField
|
||||
HTMLPanel averagePanel;
|
||||
|
||||
@UiField
|
||||
LiveAverageComponentStyle style;
|
||||
|
||||
private StringMessages stringConstants;
|
||||
public LiveAverageComponent() {
|
||||
@@ -87,12 +93,8 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti
|
||||
this.averageUnit.setInnerText(unit);
|
||||
// Lifts the degrees unit string "°". Otherwise it would be too small.
|
||||
if (unit.equals("°")) {
|
||||
this.liveUnit.getStyle().setFontSize(15, Unit.PT);
|
||||
this.averageUnit.getStyle().setFontSize(15, Unit.PT);
|
||||
this.liveUnit.getStyle().setFontWeight(Style.FontWeight.LIGHTER);
|
||||
this.averageUnit.getStyle().setFontWeight(Style.FontWeight.LIGHTER);
|
||||
this.liveUnit.getStyle().setPosition(Position.ABSOLUTE);
|
||||
this.averageUnit.getStyle().setPosition(Position.ABSOLUTE);
|
||||
this.liveUnit.addClassName(style.liveAverageCompoment_panel_value_unit_degrees());
|
||||
this.averageUnit.setClassName(style.liveAverageCompoment_panel_value_unit_degrees());
|
||||
}
|
||||
this.liveLabel.setInnerHTML(stringConstants.dashboardLiveWind());
|
||||
this.averageLabel.setInnerHTML(stringConstants.dashboardAverageWind()+"<br>"+stringConstants.dashboardAverageWindMinutes(15));
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
|
||||
xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
||||
|
||||
<ui:style src="LiveAverageComponent.css" />
|
||||
<ui:style type='com.sap.sailing.dashboards.gwt.client.startlineadvantage.LiveAverageComponent.LiveAverageComponentStyle' src='LiveAverageComponent.css'></ui:style>
|
||||
|
||||
<g:HTMLPanel ui:field="liveAveragePanel" styleName="{style.liveAverageCompoment_panel}">
|
||||
|
||||
|
||||
+2
-4
@@ -22,14 +22,12 @@ public class StartLineAdvantageComponent extends LiveAverageComponent implements
|
||||
private StartLineAdvantageComponentState startLineAdvantageComponentState;
|
||||
private StartLineAdvantageComponentStateShowsAdvantageByWind startLineAdvantageComponentStateShowsAdvantageByWind;
|
||||
private StartLineAdvantageComponentStateShowsAdvantageByGeometry startLineAdvantageComponentStateShowsAdvantageByGeometry;
|
||||
private StringMessages stringConstants;
|
||||
private static StringMessages stringConstants = StringMessages.INSTANCE;
|
||||
|
||||
public StartLineAdvantageComponent(RibDashboardDataRetriever ribDashboardDataRetriever) {
|
||||
super();
|
||||
stringConstants = StringMessages.INSTANCE;
|
||||
super(stringConstants.dashboardStartlineAdvantageByWind(), "m");
|
||||
initAndSetStartLineAdvantageStates();
|
||||
StartLineAdvantageComponentRessources.INSTANCE.css().ensureInjected();
|
||||
this.header.setInnerText(stringConstants.dashboardStartlineAdvantageByWind());
|
||||
this.header.addClassName(StartLineAdvantageComponentRessources.INSTANCE.css()
|
||||
.startLineAdvantageComponent_header());
|
||||
liveAveragePanel.getElement().addClassName(
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@
|
||||
line-height: 35px;
|
||||
vertical-align: middle;
|
||||
font-size: 12px;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
text-align: center;
|
||||
color: black;
|
||||
}
|
||||
@@ -53,7 +53,7 @@
|
||||
margin-top: 0pt;
|
||||
vertical-align: middle;
|
||||
font-size: 12pt;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
top: 50%;
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
line-height: 45pt;
|
||||
vertical-align: middle;
|
||||
font-size: 15pt;
|
||||
font-family: "Arial";
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
|
||||
+2
@@ -22,6 +22,7 @@
|
||||
top: -5pt;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
font-size: 9pt;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
@@ -34,6 +35,7 @@
|
||||
bottom: -17pt;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-family: 'Open Sans', Arial, Verdana, sans-serif;
|
||||
line-height: 10pt;
|
||||
font-weight: bold;
|
||||
font-size: 9pt;
|
||||
|
||||
+7
-1
@@ -59,7 +59,13 @@ public enum BoatClassMasterdata {
|
||||
FLYING_DUTCHMAN ("Flying Dutchman", true, 6.10, 1.80, BoatHullType.MONOHULL, true),
|
||||
DYAS("Dyas", true, 7.15, 1.95, BoatHullType.MONOHULL, true),
|
||||
INTERNATIONAL_14("International 14", true, 4.27, 1.83, BoatHullType.MONOHULL, true, "I14"),
|
||||
OPEN_BIC("O'pen BIC", true, 2.75, 1.14, BoatHullType.MONOHULL, false, "OpenBIC");
|
||||
OPEN_BIC("O'pen BIC", true, 2.75, 1.14, BoatHullType.MONOHULL, false, "OpenBIC"),
|
||||
|
||||
// multi-class "boat classes"; to be replaced at some later point in time by something like a RegattaClass
|
||||
ORC ("ORC", true, 13.83, 3.91, BoatHullType.MONOHULL, true),
|
||||
ORC_CLUB ("ORC Club", true, 13.83, 3.91, BoatHullType.MONOHULL, true),
|
||||
ORC_INTERNATIONAL ("ORC International", true, 13.83, 3.91, BoatHullType.MONOHULL, true, "ORC Int.");
|
||||
|
||||
|
||||
private final String displayName;
|
||||
private final String[] alternativeNames;
|
||||
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
package com.sap.sailing.domain.test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceColumnInSeries;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.base.impl.BoatClassImpl;
|
||||
import com.sap.sailing.domain.base.impl.FleetImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.SeriesImpl;
|
||||
import com.sap.sailing.domain.base.impl.TrackedRaces;
|
||||
import com.sap.sailing.domain.common.TimingConstants;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
/**
|
||||
* Covers the linking and unlinking between {@link RaceColumn}s and {@link TrackedRaces}s
|
||||
* and tests whether {@link RaceExecutionOrderProvider}s get correctly attached and detached. Also tests
|
||||
* late attaching and detaching of {@link RaceExecutionOrderProvider}s in case the {@link RaceExecutionOrderProvider}
|
||||
* was <code>null</code> when {@link RaceColumn} was linked to {@link TrackedRace}.
|
||||
*
|
||||
* @author Alexander Ries (D062114)
|
||||
*
|
||||
*/
|
||||
public class RaceExecutionOrderProvdiderAttachDetachTest extends TrackBasedTest {
|
||||
private FlexibleLeaderboard flexibleLeaderboard;
|
||||
private RaceColumnInSeries raceColumnInSeries;
|
||||
private Fleet fleet;
|
||||
private TrackedRaceImpl trackedRace;
|
||||
private Regatta regatta;
|
||||
private Series series;
|
||||
|
||||
private final String REGATTA = "TestRegatta";
|
||||
private final String RACE = "TestRace";
|
||||
private final String FLEET = "TestFleet";
|
||||
private final String BOATCLASS = "TestClass";
|
||||
private final String SERIES = "TestSeries";
|
||||
private final String FLEXIBLELEADERBOARD = "TestFlexibleLeaderboard";
|
||||
private final String RACECOLUMN_SERIES = "TestSeriesRaceColumn";
|
||||
private final String RACECOLUMN_FLEXIBLELEADERBOARD = "TestFlexibleLeaderboardRaceColumn";
|
||||
|
||||
@Test
|
||||
public void testRaceExecutionOrderProviderAttachDetachWithRaceCollumn() {
|
||||
trackedRace = createTestTrackedRace(REGATTA, RACE, BOATCLASS, Collections.<Competitor> emptyList(),
|
||||
MillisecondsTimePoint.now());
|
||||
flexibleLeaderboard = new FlexibleLeaderboardImpl(FLEXIBLELEADERBOARD,
|
||||
new ThresholdBasedResultDiscardingRuleImpl(new int[] { 3, 6 }), new LowPoint(), null);
|
||||
flexibleLeaderboard.addRace(trackedRace, RACECOLUMN_FLEXIBLELEADERBOARD, false);
|
||||
assertTrue(trackedRace.hasRaceExecutionOrderProvidersAttached());
|
||||
flexibleLeaderboard.removeRaceColumn(RACECOLUMN_FLEXIBLELEADERBOARD);
|
||||
assertFalse(trackedRace.hasRaceExecutionOrderProvidersAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindInRegularIntervalWithPreviousRaceStillTracking() {
|
||||
final TimePoint startOfFirstRace = MillisecondsTimePoint.now();
|
||||
final TimePoint startOfSecondRace = startOfFirstRace.plus(Duration.ONE_MINUTE.times(5));
|
||||
DynamicTrackedRaceImpl previousTrackedRace = createTestTrackedRace(REGATTA, RACE, BOATCLASS, Collections.<Competitor> emptyList(), startOfFirstRace);
|
||||
previousTrackedRace.setStartOfTrackingReceived(startOfFirstRace);
|
||||
trackedRace = createTestTrackedRace(REGATTA, "TestRace2", BOATCLASS, Collections.<Competitor> emptyList(), startOfSecondRace);
|
||||
flexibleLeaderboard = new FlexibleLeaderboardImpl(FLEXIBLELEADERBOARD,
|
||||
new ThresholdBasedResultDiscardingRuleImpl(new int[] { 3, 6 }), new LowPoint(), null);
|
||||
flexibleLeaderboard.addRace(previousTrackedRace, RACECOLUMN_FLEXIBLELEADERBOARD+"1", false);
|
||||
flexibleLeaderboard.addRace(trackedRace, RACECOLUMN_FLEXIBLELEADERBOARD+"2", false);
|
||||
Wind wind = new WindImpl(new DegreePosition(12, 13), startOfSecondRace.plus(Duration.ONE_MINUTE), new KnotSpeedWithBearingImpl(
|
||||
/* speedInKnots */18, new DegreeBearingImpl(185)));
|
||||
assertTrue(previousTrackedRace.takesWindFix(wind)); // previous race has tracking still open and takes the fix
|
||||
assertTrue(trackedRace.takesWindFix(wind)); // tracked race also needs to take the fix as it falls into the regular tracking interval
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindInExtendedLeadIntervalWithPreviousRaceStillTracking() {
|
||||
final TimePoint startOfFirstRace = MillisecondsTimePoint.now();
|
||||
final TimePoint endOfFirstRace = startOfFirstRace.plus(Duration.ONE_SECOND);
|
||||
final TimePoint startOfSecondRace = startOfFirstRace.plus(Duration.ONE_HOUR);
|
||||
DynamicTrackedRaceImpl previousTrackedRace = createTestTrackedRace(REGATTA, RACE, BOATCLASS, Collections.<Competitor> emptyList(), startOfFirstRace);
|
||||
previousTrackedRace.setStartOfTrackingReceived(startOfFirstRace);
|
||||
previousTrackedRace.setEndOfTrackingReceived(endOfFirstRace); // a very short race...
|
||||
trackedRace = createTestTrackedRace(REGATTA, "TestRace2", BOATCLASS, Collections.<Competitor> emptyList(), startOfSecondRace);
|
||||
flexibleLeaderboard = new FlexibleLeaderboardImpl(FLEXIBLELEADERBOARD,
|
||||
new ThresholdBasedResultDiscardingRuleImpl(new int[] { 3, 6 }), new LowPoint(), null);
|
||||
flexibleLeaderboard.addRace(previousTrackedRace, RACECOLUMN_FLEXIBLELEADERBOARD+"1", false);
|
||||
flexibleLeaderboard.addRace(trackedRace, RACECOLUMN_FLEXIBLELEADERBOARD+"2", false);
|
||||
// the wind fix is after the grace period of the first race's end, so won't be accepted by it, but within the extended
|
||||
// time range before the second race, so shall be accepted by it.
|
||||
Wind wind = new WindImpl(new DegreePosition(12, 13),
|
||||
endOfFirstRace.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).plus(Duration.ONE_MINUTE), // fix is after the grace period
|
||||
new KnotSpeedWithBearingImpl(/* speedInKnots */18, new DegreeBearingImpl(185)));
|
||||
assertFalse(previousTrackedRace.takesWindFix(wind)); // previous race has tracking closed one second after it started and doesn't accept the fix
|
||||
assertTrue(trackedRace.takesWindFix(wind)); // tracked race also needs to take the fix as it falls into the regular tracking interval
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindInExtendedLeadIntervalWithNoPreviousRace() {
|
||||
final TimePoint startOfFirstRace = MillisecondsTimePoint.now();
|
||||
final TimePoint endOfFirstRace = startOfFirstRace.plus(Duration.ONE_SECOND);
|
||||
final TimePoint startOfSecondRace = startOfFirstRace.plus(Duration.ONE_HOUR);
|
||||
trackedRace = createTestTrackedRace(REGATTA, "TestRace2", BOATCLASS, Collections.<Competitor> emptyList(), startOfSecondRace);
|
||||
flexibleLeaderboard = new FlexibleLeaderboardImpl(FLEXIBLELEADERBOARD,
|
||||
new ThresholdBasedResultDiscardingRuleImpl(new int[] { 3, 6 }), new LowPoint(), null);
|
||||
flexibleLeaderboard.addRace(trackedRace, RACECOLUMN_FLEXIBLELEADERBOARD, false);
|
||||
// the wind fix is within the extended time range before the second race, and there is no previous race, so shall be accepted by it
|
||||
Wind wind = new WindImpl(new DegreePosition(12, 13),
|
||||
endOfFirstRace.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).plus(Duration.ONE_MINUTE), // fix is after the grace period
|
||||
new KnotSpeedWithBearingImpl(/* speedInKnots */18, new DegreeBearingImpl(185)));
|
||||
assertTrue(trackedRace.takesWindFix(wind));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindInExtendedLeadIntervalWithPreviousRaceLongAgo() {
|
||||
final TimePoint startOfFirstRace = MillisecondsTimePoint.now();
|
||||
final TimePoint endOfFirstRace = startOfFirstRace.plus(Duration.ONE_SECOND);
|
||||
final TimePoint startOfSecondRace = startOfFirstRace.plus(TrackedRaceImpl.EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS.times(2));
|
||||
DynamicTrackedRaceImpl previousTrackedRace = createTestTrackedRace(REGATTA, RACE, BOATCLASS, Collections.<Competitor> emptyList(), startOfFirstRace);
|
||||
previousTrackedRace.setStartOfTrackingReceived(startOfFirstRace);
|
||||
previousTrackedRace.setEndOfTrackingReceived(endOfFirstRace); // a very short race...
|
||||
trackedRace = createTestTrackedRace(REGATTA, "TestRace2", BOATCLASS, Collections.<Competitor> emptyList(), startOfSecondRace);
|
||||
flexibleLeaderboard = new FlexibleLeaderboardImpl(FLEXIBLELEADERBOARD,
|
||||
new ThresholdBasedResultDiscardingRuleImpl(new int[] { 3, 6 }), new LowPoint(), null);
|
||||
flexibleLeaderboard.addRace(previousTrackedRace, RACECOLUMN_FLEXIBLELEADERBOARD+"1", false);
|
||||
flexibleLeaderboard.addRace(trackedRace, RACECOLUMN_FLEXIBLELEADERBOARD+"2", false);
|
||||
// the wind fix is outside the extended time range before the second race, and the previous race doesn't accept it; shall not be accepted
|
||||
Wind wind = new WindImpl(new DegreePosition(12, 13),
|
||||
endOfFirstRace.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).plus(Duration.ONE_MINUTE), // fix is after the grace period
|
||||
new KnotSpeedWithBearingImpl(/* speedInKnots */18, new DegreeBearingImpl(185)));
|
||||
assertFalse(previousTrackedRace.takesWindFix(wind)); // fix is after first race's end plus grace period
|
||||
assertFalse(trackedRace.takesWindFix(wind));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindInExtendedLeadIntervalButStillRecordedByPreviousRace() {
|
||||
final TimePoint startOfFirstRace = MillisecondsTimePoint.now();
|
||||
final TimePoint endOfFirstRace = startOfFirstRace.plus(Duration.ONE_SECOND);
|
||||
final TimePoint startOfSecondRace = startOfFirstRace.plus(TrackedRaceImpl.EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS.divide(2));
|
||||
DynamicTrackedRaceImpl previousTrackedRace = createTestTrackedRace(REGATTA, RACE, BOATCLASS, Collections.<Competitor> emptyList(), startOfFirstRace);
|
||||
previousTrackedRace.setStartOfTrackingReceived(startOfFirstRace);
|
||||
previousTrackedRace.setEndOfTrackingReceived(endOfFirstRace); // a very short race...
|
||||
trackedRace = createTestTrackedRace(REGATTA, "TestRace2", BOATCLASS, Collections.<Competitor> emptyList(), startOfSecondRace);
|
||||
flexibleLeaderboard = new FlexibleLeaderboardImpl(FLEXIBLELEADERBOARD,
|
||||
new ThresholdBasedResultDiscardingRuleImpl(new int[] { 3, 6 }), new LowPoint(), null);
|
||||
flexibleLeaderboard.addRace(previousTrackedRace, RACECOLUMN_FLEXIBLELEADERBOARD+"1", false);
|
||||
flexibleLeaderboard.addRace(trackedRace, RACECOLUMN_FLEXIBLELEADERBOARD+"2", false);
|
||||
// the wind fix is inside the extended time range before the second race, but the previous race still accepts it; shall not be accepted
|
||||
Wind wind = new WindImpl(new DegreePosition(12, 13),
|
||||
startOfFirstRace.plus(Duration.ONE_SECOND), // fix is recorded by previous race
|
||||
new KnotSpeedWithBearingImpl(/* speedInKnots */18, new DegreeBearingImpl(185)));
|
||||
assertTrue(previousTrackedRace.takesWindFix(wind)); // fix is after first race's end plus grace period
|
||||
assertFalse(trackedRace.takesWindFix(wind));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRaceExecutionOrderProviderAttachDetachWithRaceCollumnInSeries() {
|
||||
createTestSetupWithRegattaAndSeries(/* linkSeriesToRegatta */true);
|
||||
raceColumnInSeries.setTrackedRace(fleet, trackedRace);
|
||||
assertTrue(trackedRace.hasRaceExecutionOrderProvidersAttached());
|
||||
raceColumnInSeries.releaseTrackedRace(fleet);
|
||||
assertFalse(trackedRace.hasRaceExecutionOrderProvidersAttached());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRaceExecutionOrderProviderAttachDetachWhenSeriesRegattaIsSetAndRemovedAfterTrackedRaceHaveBeenSetToRaceColumns() {
|
||||
createTestSetupWithRegattaAndSeries(/* linkSeriesToRegatta */false);
|
||||
raceColumnInSeries.setTrackedRace(fleet, trackedRace);
|
||||
assertFalse(trackedRace.hasRaceExecutionOrderProvidersAttached());
|
||||
series.setRegatta(regatta);
|
||||
assertTrue(trackedRace.hasRaceExecutionOrderProvidersAttached());
|
||||
series.setRegatta(null);
|
||||
assertFalse(trackedRace.hasRaceExecutionOrderProvidersAttached());
|
||||
}
|
||||
|
||||
private void createTestSetupWithRegattaAndSeries(boolean linkSeriesToRegatta) {
|
||||
trackedRace = createTestTrackedRace(REGATTA, RACE, BOATCLASS, Collections.<Competitor> emptyList(),
|
||||
MillisecondsTimePoint.now());
|
||||
fleet = new FleetImpl(FLEET);
|
||||
Set<Fleet> fleets = new HashSet<>();
|
||||
fleets.add(fleet);
|
||||
series = new SeriesImpl(SERIES, false, fleets, new HashSet<String>(), null);
|
||||
Set<Series> seriesSet = new HashSet<>();
|
||||
if (linkSeriesToRegatta) {
|
||||
seriesSet.add(series);
|
||||
}
|
||||
BoatClass boatClass = new BoatClassImpl(BOATCLASS, true);
|
||||
raceColumnInSeries = series.addRaceColumn(RACECOLUMN_SERIES, null);
|
||||
ScoringScheme scoringScheme = new LowPoint();
|
||||
regatta = new RegattaImpl(RegattaImpl.getDefaultName(REGATTA, boatClass.getName()), boatClass,
|
||||
/* startDate */null, /* endDate */null, seriesSet, false, scoringScheme, UUID.randomUUID(), null,
|
||||
OneDesignRankingMetric::new);
|
||||
}
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
package com.sap.sailing.domain.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
|
||||
/**
|
||||
* This test verifies the algorithm used to escape and unescape SimpleRaceIdentifier components as used in
|
||||
* <code>FleetIfentifierImpl</code>.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class SimpleRaceIdentifierEscapingTest {
|
||||
@Test
|
||||
public void testUnescapingSimpleRaceIdentifier() {
|
||||
test("Leaderboard with trailing backslash and dot\\.", "raceColumn", "fleet");
|
||||
test("Leaderboard\\.with\\.two dots", "raceColumn", "fleet");
|
||||
test("Leaderboard with double backslash\\\\", "raceColumn", "fleet");
|
||||
test("Leaderboard with double backslash and dot\\\\.", "raceColumn", "fleet");
|
||||
test("\\Leaderboard with leading backslash", "raceColumn", "fleet");
|
||||
test("\\.Leaderboard with leading backslash and dot", "raceColumn", "fleet");
|
||||
test("\\\\.Leaderboard with leading double backslash and dot", "raceColumn", "fleet");
|
||||
test("\\\\.Leaderboard with leading double backslash and two dots", "raceColumn", "fleet");
|
||||
}
|
||||
|
||||
private void test(String leaderboardName, String raceColumnName, String fleetName) {
|
||||
final String marshalled = build(leaderboardName, raceColumnName, fleetName);
|
||||
final Triple<String, String, String> parsed = parse(marshalled);
|
||||
assertEquals(leaderboardName, parsed.getA());
|
||||
assertEquals(raceColumnName, parsed.getB());
|
||||
assertEquals(fleetName, parsed.getC());
|
||||
}
|
||||
|
||||
private Triple<String, String, String> parse(String s) {
|
||||
int arrayIndex = 0;
|
||||
StringBuilder[] split = new StringBuilder[3];
|
||||
for (int i=0; i<split.length; i++) {
|
||||
split[i] = new StringBuilder();
|
||||
}
|
||||
boolean escaped = false;
|
||||
for (int i=0; i<s.length(); i++) {
|
||||
if (escaped) {
|
||||
split[arrayIndex].append(s.charAt(i));
|
||||
escaped = false;
|
||||
} else if (s.charAt(i) == '\\') {
|
||||
escaped = true; // next character is escaped
|
||||
} else if (s.charAt(i) == '.') {
|
||||
// an unescaped dot
|
||||
arrayIndex++;
|
||||
} else {
|
||||
// unescaped non-escape, non-dot character
|
||||
split[arrayIndex].append(s.charAt(i));
|
||||
}
|
||||
}
|
||||
String leaderboardName = split[0].toString();
|
||||
String raceColumnName = split[1].toString();
|
||||
String fleetName = split[2].toString();
|
||||
return new Triple<>(leaderboardName, raceColumnName, fleetName);
|
||||
}
|
||||
|
||||
private String build(String leaderboardName, String raceColumnName, String fleetName) {
|
||||
return String.format("%s.%s.%s",
|
||||
escape(leaderboardName),
|
||||
escape(raceColumnName),
|
||||
escape(fleetName));
|
||||
}
|
||||
|
||||
private String escape(String s) {
|
||||
return s.replace("\\", "\\\\").replace(".", "\\.");
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -122,7 +122,8 @@ public abstract class TrackBasedTest {
|
||||
OneDesignRankingMetric::new);
|
||||
// in this simplified artificial course, the top mark is exactly north of the right leeward gate
|
||||
DegreePosition topPosition = new DegreePosition(54.48, 10.24);
|
||||
TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix time
|
||||
TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix timed
|
||||
trackedRace.setStartOfTrackingReceived(timePointForFixes);
|
||||
trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(new DegreePosition(54.4680424, 10.234451), new MillisecondsTimePoint(0)));
|
||||
trackedRace.getOrCreateTrack(right).addGPSFix(new GPSFixImpl(new DegreePosition(54.4680424, 10.24), new MillisecondsTimePoint(0)));
|
||||
trackedRace.getOrCreateTrack(windwardMark).addGPSFix(new GPSFixImpl(topPosition, new MillisecondsTimePoint(0)));
|
||||
|
||||
+14
-6
@@ -59,6 +59,7 @@ import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceAbortedListener;
|
||||
import com.sap.sailing.domain.tracking.RaceChangeListener;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.RaceListener;
|
||||
import com.sap.sailing.domain.tracking.StartTimeChangedListener;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
@@ -442,6 +443,11 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
public void adjustEventToRegattaAssociation(EventFetcher eventFetcher) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceExecutionOrderProvider getRaceExecutionOrderProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RankingMetricConstructor getRankingMetricConstructor() {
|
||||
return null;
|
||||
@@ -783,10 +789,6 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachAllRaceLogs() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateStartTime() {
|
||||
}
|
||||
@@ -898,7 +900,6 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
|
||||
@Override
|
||||
public boolean isUsingMarkPassingCalculator() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -947,10 +948,17 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
@Override
|
||||
public Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException,
|
||||
NoWindException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachRaceExecutionProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint,
|
||||
WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) {
|
||||
|
||||
+8
-5
@@ -43,6 +43,7 @@ import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceAbortedListener;
|
||||
import com.sap.sailing.domain.tracking.RaceChangeListener;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.StartTimeChangedListener;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
@@ -470,10 +471,6 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachAllRaceLogs() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLive(TimePoint at) {
|
||||
return false;
|
||||
@@ -639,8 +636,14 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
@Override
|
||||
public Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException,
|
||||
NoWindException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachRaceExecutionProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import com.sap.sailing.domain.leaderboard.MetaLeaderboard;
|
||||
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.util.impl.RaceColumnListeners;
|
||||
import com.sap.sse.common.Named;
|
||||
@@ -224,4 +225,6 @@ public interface RaceColumn extends Named {
|
||||
boolean hasSplitFleetContiguousScoring();
|
||||
|
||||
boolean hasSplitFleets();
|
||||
|
||||
RaceExecutionOrderProvider getRaceExecutionOrderProvider();
|
||||
}
|
||||
@@ -20,7 +20,9 @@ public interface RaceColumnListener extends Serializable {
|
||||
|
||||
void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring);
|
||||
|
||||
boolean canAddRaceColumnToContainer(RaceColumn raceColumn);
|
||||
default boolean canAddRaceColumnToContainer(RaceColumn raceColumn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void raceColumnAddedToContainer(RaceColumn raceColumn);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.ranking.RankingMetricConstructor;
|
||||
import com.sap.sailing.domain.ranking.RankingMetricsFactory;
|
||||
import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sse.common.Named;
|
||||
@@ -187,6 +188,8 @@ public interface Regatta extends Named, WithID, IsRegattaLike {
|
||||
* opposite end of the association needs to be maintained on the event's side.
|
||||
*/
|
||||
void adjustEventToRegattaAssociation(EventFetcher eventFetcher);
|
||||
|
||||
RaceExecutionOrderProvider getRaceExecutionOrderProvider();
|
||||
|
||||
default RankingMetrics getRankingMetricType() {
|
||||
return RankingMetricsFactory.getForClass(getRankingMetricConstructor().apply(/* trackedRace */ null).getClass());
|
||||
|
||||
+2
-1
@@ -74,6 +74,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
|
||||
}
|
||||
if (trackedRace != null) {
|
||||
trackedRace.attachRaceLog(getRaceLog(fleet));
|
||||
trackedRace.attachRaceExecutionProvider(getRaceExecutionOrderProvider());
|
||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceLinked(this, fleet, trackedRace);
|
||||
}
|
||||
}
|
||||
@@ -98,6 +99,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
|
||||
if (previouslyLinkedRace != null && regattaLikeParent != null) {
|
||||
RaceLogIdentifier identifier = getRaceLogIdentifier(fleet);
|
||||
previouslyLinkedRace.detachRaceLog(identifier.getIdentifier());
|
||||
previouslyLinkedRace.detachRaceExecutionOrderProvider(getRaceExecutionOrderProvider());
|
||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(this, fleet, previouslyLinkedRace);
|
||||
}
|
||||
}
|
||||
@@ -197,5 +199,4 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
|
||||
public void setMasterDataExportOngoingThreadFlag(boolean flagValue) {
|
||||
trackedRaces.setMasterDataExportOngoingThreadFlag(flagValue);
|
||||
}
|
||||
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package com.sap.sailing.domain.base.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.util.SmartFutureCache;
|
||||
import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
|
||||
|
||||
public abstract class AbstractRaceExecutionOrderProvider implements RaceExecutionOrderProvider, RaceColumnListenerWithDefaultAction {
|
||||
private static final long serialVersionUID = 4795731834688229568L;
|
||||
private transient SmartFutureCache<String, Map<TrackedRace, Set<TrackedRace>>, EmptyUpdateInterval> previousRacesByRaceCache;
|
||||
private final String RACES_ORDER_LIST_CACHE_KEY = "racesOrderCacheKey";
|
||||
private final String RACES_ORDER_LIST_LOCKS_NAME = getClass().getName();
|
||||
|
||||
public AbstractRaceExecutionOrderProvider() {
|
||||
previousRacesByRaceCache = createRacesOrderCache();
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultAction() {
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerUpdate() {
|
||||
previousRacesByRaceCache.triggerUpdate(RACES_ORDER_LIST_CACHE_KEY, /* update interval */null);
|
||||
}
|
||||
|
||||
private Map<TrackedRace, Set<TrackedRace>> getPreviousRacesByRace() {
|
||||
return previousRacesByRaceCache.get(RACES_ORDER_LIST_CACHE_KEY, /* waitForLatest */true);
|
||||
}
|
||||
|
||||
protected abstract Map<Fleet, Iterable<? extends RaceColumn>> getRaceColumnsOfSeries();
|
||||
|
||||
private Map<TrackedRace, Set<TrackedRace>> reloadAndGetPreviousRacesByRace() {
|
||||
final Map<TrackedRace, Set<TrackedRace>> previousRacesByRace = new HashMap<>();
|
||||
for (Entry<Fleet, Iterable<? extends RaceColumn>> raceColumnsInSeries : getRaceColumnsOfSeries().entrySet()) {
|
||||
addPreviousRaces(previousRacesByRace, raceColumnsInSeries.getKey(), raceColumnsInSeries.getValue());
|
||||
}
|
||||
return previousRacesByRace;
|
||||
}
|
||||
|
||||
private void addPreviousRaces(final Map<TrackedRace, Set<TrackedRace>> previousRacesByRace, Fleet fleet,
|
||||
final Iterable<? extends RaceColumn> raceColumns) {
|
||||
TrackedRace previousRace = null;
|
||||
for (RaceColumn currentRaceColumn : raceColumns) {
|
||||
final TrackedRace trackedRaceInColumnForFleet = currentRaceColumn.getTrackedRace(fleet);
|
||||
if (trackedRaceInColumnForFleet != null) {
|
||||
Set<TrackedRace> previousRaces = previousRacesByRace.get(trackedRaceInColumnForFleet);
|
||||
if (previousRaces == null) {
|
||||
previousRaces = new HashSet<>();
|
||||
previousRacesByRace.put(trackedRaceInColumnForFleet, previousRaces);
|
||||
}
|
||||
if (previousRace != null) {
|
||||
previousRaces.add(previousRace);
|
||||
}
|
||||
previousRace = trackedRaceInColumnForFleet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SmartFutureCache<String, Map<TrackedRace, Set<TrackedRace>>, EmptyUpdateInterval> createRacesOrderCache() {
|
||||
return new SmartFutureCache<String, Map<TrackedRace, Set<TrackedRace>>, SmartFutureCache.EmptyUpdateInterval>(
|
||||
new SmartFutureCache.AbstractCacheUpdater<String, Map<TrackedRace, Set<TrackedRace>>, SmartFutureCache.EmptyUpdateInterval>() {
|
||||
@Override
|
||||
public Map<TrackedRace, Set<TrackedRace>> computeCacheUpdate(String key,
|
||||
EmptyUpdateInterval updateInterval) throws Exception {
|
||||
if (key.equals(RACES_ORDER_LIST_CACHE_KEY)) {
|
||||
return reloadAndGetPreviousRacesByRace();
|
||||
} else {
|
||||
final Map<TrackedRace, Set<TrackedRace>> emptyMap = Collections.emptyMap();
|
||||
return emptyMap;
|
||||
}
|
||||
}
|
||||
}, RACES_ORDER_LIST_LOCKS_NAME);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
ois.defaultReadObject();
|
||||
this.previousRacesByRaceCache = createRacesOrderCache();
|
||||
// don't call triggerUpdate() as of now because the cache's owner may not yet be fully initialized,
|
||||
// so the getRaceColumnsOfSeries() method may not yet be able to do its work. The owner must call
|
||||
// triggerUpdate when fully initialized.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TrackedRace> getPreviousRacesInExecutionOrder(TrackedRace race) {
|
||||
Set<TrackedRace> result = Collections.emptySet();
|
||||
final Map<TrackedRace, Set<TrackedRace>> previousRacesByRace = getPreviousRacesByRace();
|
||||
if (previousRacesByRace != null) {
|
||||
result = previousRacesByRace.get(race);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+12
-2
@@ -8,6 +8,7 @@ import com.sap.sailing.domain.base.RaceColumnInSeries;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
@@ -119,6 +120,15 @@ public class RaceColumnInSeriesImpl extends AbstractRaceColumn implements RaceCo
|
||||
public boolean hasSplitFleetContiguousScoring() {
|
||||
return getSeries().hasSplitFleetContiguousScoring();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public RaceExecutionOrderProvider getRaceExecutionOrderProvider() {
|
||||
final RaceExecutionOrderProvider result;
|
||||
if (getRegatta() != null) {
|
||||
result = getRegatta().getRaceExecutionOrderProvider();
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
package com.sap.sailing.domain.base.impl;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceColumnListener;
|
||||
import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
|
||||
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* Delegates all listener operations to a default action which is implemented here to do nothing. This way, subclasses
|
||||
* can easily provide a default action to be executed for all callback methods except for maybe a few which then need to
|
||||
* be explicitly overridden. If not most methods need to perform the same action then instead of implementing a default
|
||||
* action subclasses should rather override the {@link RaceColumnListener} operations individually.
|
||||
*
|
||||
* @author Alexander Ries (D062114)
|
||||
*
|
||||
*/
|
||||
public interface RaceColumnListenerWithDefaultAction extends RaceColumnListener {
|
||||
/**
|
||||
* This implementation of the default action to which all other operations delegate does nothing. Subclasses can
|
||||
* choose to override this method to provide this as the default behavior for all other methods and then still
|
||||
* override individual {@link RaceColumnListener} methods, or they can leave the default action empty and just
|
||||
* override {@link RaceColumnListener} methods.
|
||||
*/
|
||||
void defaultAction();
|
||||
|
||||
@Override
|
||||
default void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void isMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void isStartsWithZeroScoreChanged(RaceColumn raceColumn, boolean newIsStartsWithZeroScore) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn,
|
||||
boolean firstColumnIsNonDiscardableCarryForward) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void raceColumnAddedToContainer(RaceColumn raceColumn) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void raceColumnRemovedFromContainer(RaceColumn raceColumn) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void raceColumnMoved(RaceColumn raceColumn, int newIndex) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void competitorDisplayNameChanged(Competitor competitor, String oldDisplayName, String displayName) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule,
|
||||
ResultDiscardingRule newDiscardingRule) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) {
|
||||
defaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isTransient() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,14 @@ package com.sap.sailing.domain.base.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -46,6 +49,7 @@ import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeListener;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
@@ -88,7 +92,8 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
|
||||
private CourseArea defaultCourseArea;
|
||||
private RegattaConfiguration configuration;
|
||||
|
||||
private RaceExecutionOrderCache raceExecutionOrderCache;
|
||||
|
||||
/**
|
||||
* Regattas may be constructed as implicit default regattas in which case they won't need to be stored
|
||||
* durably and don't contain valuable information worth being preserved; or they are constructed explicitly
|
||||
@@ -192,6 +197,7 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
this.defaultCourseArea = courseArea;
|
||||
this.configuration = null;
|
||||
this.regattaLikeHelper = new BaseRegattaLikeImpl(new RegattaAsRegattaLikeIdentifier(this), regattaLogStore);
|
||||
this.raceExecutionOrderCache = new RaceExecutionOrderCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -242,6 +248,11 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
}
|
||||
}
|
||||
|
||||
protected Object readResolve() throws ObjectStreamException {
|
||||
raceExecutionOrderCache.triggerUpdate(); // now we're fully initialized and the cache can do its job
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link RaceColumnListeners} may not be de-serialized (yet) when the regatta
|
||||
* is de-serialized. Do avoid re-registering empty objects most probably leading
|
||||
@@ -263,7 +274,13 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
|
||||
@Override
|
||||
public Iterable<? extends Series> getSeries() {
|
||||
return Collections.unmodifiableCollection(series);
|
||||
final Iterable<? extends Series> result;
|
||||
if (series != null) {
|
||||
result = Collections.unmodifiableCollection(series);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -628,4 +645,36 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceExecutionOrderProvider getRaceExecutionOrderProvider() {
|
||||
return raceExecutionOrderCache;
|
||||
}
|
||||
|
||||
private class RaceExecutionOrderCache extends AbstractRaceExecutionOrderProvider {
|
||||
private static final long serialVersionUID = 1658153438012186894L;
|
||||
|
||||
public RaceExecutionOrderCache() {
|
||||
super();
|
||||
addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Fleet, Iterable<? extends RaceColumn>> getRaceColumnsOfSeries() {
|
||||
final Map<Fleet, Iterable<? extends RaceColumn>> result = new HashMap<>();
|
||||
final Iterable<? extends Series> mySeries = getSeries();
|
||||
if (mySeries != null) {
|
||||
for (Series currentSeries : mySeries) {
|
||||
if (currentSeries.getFleets() != null) {
|
||||
for (Fleet fleet : currentSeries.getFleets()) {
|
||||
if (currentSeries.getRaceColumns() != null) {
|
||||
result.put(fleet, currentSeries.getRaceColumns());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,11 @@ import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.util.impl.RaceColumnListeners;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/**
|
||||
* A series listens on its columns; however, a veto for column addition isn't done here but in a {@link RegattaLeaderboard}.
|
||||
*
|
||||
* @see #addRaceColumn(String, TrackedRegattaRegistry)
|
||||
*/
|
||||
public class SeriesImpl extends RenamableImpl implements Series, RaceColumnListener {
|
||||
private static final long serialVersionUID = -1640404303144907381L;
|
||||
private final Map<String, Fleet> fleetsByName;
|
||||
@@ -79,8 +84,7 @@ public class SeriesImpl extends RenamableImpl implements Series, RaceColumnListe
|
||||
fleetsInAscendingOrder = new ArrayList<Fleet>();
|
||||
Util.addAll(fleets, fleetsInAscendingOrder);
|
||||
Collections.sort(fleetsInAscendingOrder);
|
||||
List<RaceColumnInSeries> myRaceColumns = new ArrayList<RaceColumnInSeries>();
|
||||
this.raceColumns = myRaceColumns;
|
||||
this.raceColumns = new ArrayList<RaceColumnInSeries>();
|
||||
this.isMedal = isMedal;
|
||||
this.raceColumnListeners = new RaceColumnListeners();
|
||||
for (String raceColumnName : raceColumnNames) {
|
||||
@@ -105,7 +109,15 @@ public class SeriesImpl extends RenamableImpl implements Series, RaceColumnListe
|
||||
|
||||
@Override
|
||||
public void setRegatta(Regatta regatta) {
|
||||
if (this.regatta != null) {
|
||||
detachRaceExecutionOrderProviderFromTrackedRacesInRaceColumns();
|
||||
}
|
||||
this.regatta = regatta;
|
||||
if (this.regatta != null) {
|
||||
attachRaceExecutionOrderProviderToTrackedRacesInRaceColumns();
|
||||
} else {
|
||||
detachRaceExecutionOrderProviderFromTrackedRacesInRaceColumns();
|
||||
}
|
||||
}
|
||||
|
||||
public Iterable<? extends Fleet> getFleets() {
|
||||
@@ -162,6 +174,28 @@ public class SeriesImpl extends RenamableImpl implements Series, RaceColumnListe
|
||||
this,
|
||||
trackedRegattaRegistry);
|
||||
}
|
||||
|
||||
private void attachRaceExecutionOrderProviderToTrackedRacesInRaceColumns() {
|
||||
for (RaceColumnInSeries raceColumnInSeries : raceColumns) {
|
||||
for (Fleet fleet : raceColumnInSeries.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumnInSeries.getTrackedRace(fleet);
|
||||
if (trackedRace != null && regatta != null) {
|
||||
trackedRace.attachRaceExecutionProvider(regatta.getRaceExecutionOrderProvider());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void detachRaceExecutionOrderProviderFromTrackedRacesInRaceColumns() {
|
||||
for (RaceColumnInSeries raceColumnInSeries : raceColumns) {
|
||||
for (Fleet fleet : raceColumnInSeries.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumnInSeries.getTrackedRace(fleet);
|
||||
if (trackedRace != null && regatta != null && regatta.getRaceExecutionOrderProvider() != null) {
|
||||
trackedRace.detachRaceExecutionOrderProvider(regatta.getRaceExecutionOrderProvider());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRaceColumnUp(String raceColumnName) {
|
||||
@@ -280,16 +314,6 @@ public class SeriesImpl extends RenamableImpl implements Series, RaceColumnListe
|
||||
raceColumnListeners.notifyListenersAboutIsFirstColumnIsNonDiscardableCarryForwardChanged(raceColumn, firstColumnIsNonDiscardableCarryForward);
|
||||
}
|
||||
|
||||
/**
|
||||
* A series listens on its columns; individual columns, however, don't ask whether they can be added; the series itself does.
|
||||
*
|
||||
* @see #addRaceColumn(String, TrackedRegattaRegistry)
|
||||
*/
|
||||
@Override
|
||||
public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceColumnAddedToContainer(RaceColumn raceColumn) {
|
||||
raceColumnListeners.notifyListenersAboutRaceColumnAddedToContainer(raceColumn);
|
||||
|
||||
-5
@@ -305,11 +305,6 @@ public class LeaderboardCacheManager {
|
||||
removeFromCache(leaderboard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceColumnAddedToContainer(RaceColumn raceColumn) {
|
||||
removeFromCache(leaderboard);
|
||||
|
||||
+40
-3
@@ -3,11 +3,14 @@ package com.sap.sailing.domain.leaderboard.impl;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -18,6 +21,7 @@ import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceColumnListener;
|
||||
import com.sap.sailing.domain.base.impl.AbstractRaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
@@ -31,6 +35,7 @@ import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeListener;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
@@ -54,6 +59,7 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
private String name;
|
||||
private transient RaceLogStore raceLogStore;
|
||||
private CourseArea courseArea;
|
||||
private RaceExecutionOrderProvider raceExecutionOrderProvider;
|
||||
|
||||
/**
|
||||
* @see RegattaLog for the reason why the leaderboard manages a {@code RegattaLog}
|
||||
@@ -75,10 +81,11 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
}
|
||||
this.name = name;
|
||||
this.races = new ArrayList<FlexibleRaceColumn>();
|
||||
this.races = new ArrayList<>();
|
||||
this.raceLogStore = raceLogStore;
|
||||
this.courseArea = courseArea;
|
||||
this.regattaLikeHelper = new BaseRegattaLikeImpl(new FlexibleLeaderboardAsRegattaLikeIdentifier(this), regattaLogStore);
|
||||
this.raceExecutionOrderProvider = new RaceExecutionOrderCache();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,6 +101,11 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
column.setRaceLogInformation(raceLogStore, new FlexibleLeaderboardAsRegattaLikeIdentifier(this));
|
||||
}
|
||||
}
|
||||
|
||||
protected Object readResolve() throws ObjectStreamException {
|
||||
raceExecutionOrderProvider.triggerUpdate();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -160,6 +172,9 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
if (raceColumn != null) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
raceLogStore.removeRaceLog(raceColumn.getRaceLogIdentifier(fleet));
|
||||
if (raceColumn.getTrackedRace(fleet) != null) {
|
||||
raceColumn.getTrackedRace(fleet).detachRaceExecutionOrderProvider(raceExecutionOrderProvider);
|
||||
}
|
||||
}
|
||||
races.remove(raceColumn);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(raceColumn);
|
||||
@@ -169,11 +184,17 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumn> getRaceColumns() {
|
||||
return Collections.unmodifiableCollection(new ArrayList<RaceColumn>(races));
|
||||
final Iterable<RaceColumn> result;
|
||||
if (races != null) {
|
||||
result = Collections.unmodifiableCollection(new ArrayList<RaceColumn>(races));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected RaceColumnImpl createRaceColumn(String column, boolean medalRace) {
|
||||
return new RaceColumnImpl(column, medalRace);
|
||||
return new RaceColumnImpl(column, medalRace, raceExecutionOrderProvider);
|
||||
}
|
||||
|
||||
protected Iterable<Fleet> turnNullOrEmptyFleetsIntoDefaultFleet(Fleet... fleets) {
|
||||
@@ -302,4 +323,20 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
result.addAll(viaLog);
|
||||
return result;
|
||||
}
|
||||
|
||||
private class RaceExecutionOrderCache extends AbstractRaceExecutionOrderProvider {
|
||||
private static final long serialVersionUID = 652833386555762661L;
|
||||
|
||||
public RaceExecutionOrderCache() {
|
||||
super();
|
||||
addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Fleet, Iterable<? extends RaceColumn>> getRaceColumnsOfSeries() {
|
||||
final Map<Fleet, Iterable<? extends RaceColumn>> result = new HashMap<>();
|
||||
result.put(FlexibleLeaderboardImpl.defaultFleet, getRaceColumns());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-1
@@ -5,17 +5,20 @@ import java.util.Collections;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.impl.AbstractRaceColumn;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
|
||||
public class RaceColumnImpl extends AbstractRaceColumn implements FlexibleRaceColumn {
|
||||
private static final long serialVersionUID = -7801617988982540470L;
|
||||
private String name;
|
||||
|
||||
private boolean medalRace;
|
||||
private final RaceExecutionOrderProvider raceExecutionOrderProvider;
|
||||
|
||||
public RaceColumnImpl(String name, boolean medalRace) {
|
||||
public RaceColumnImpl(String name, boolean medalRace, RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.medalRace = medalRace;
|
||||
this.raceExecutionOrderProvider = raceExecutionOrderProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,4 +47,8 @@ public class RaceColumnImpl extends AbstractRaceColumn implements FlexibleRaceCo
|
||||
return Collections.singleton(FlexibleLeaderboardImpl.defaultFleet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceExecutionOrderProvider getRaceExecutionOrderProvider() {
|
||||
return raceExecutionOrderProvider;
|
||||
}
|
||||
}
|
||||
+6
@@ -15,6 +15,7 @@ import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
|
||||
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
@@ -197,4 +198,9 @@ public class MetaLeaderboardColumn extends SimpleAbstractRaceColumn implements R
|
||||
@Override
|
||||
public void reloadRaceLog(Fleet fleet) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceExecutionOrderProvider getRaceExecutionOrderProvider() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.sap.sailing.domain.tracking;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
|
||||
/**
|
||||
* Sometimes {@link TrackedRace}s want to know which {@link DynamicTrackedRace} is in front of them in the execution order
|
||||
* of a {@link Regatta}. This is i.e interesting to know in the {@link DynamicTrackedRace #recordWind(com.sap.sailing.domain.common.Wind, com.sap.sailing.domain.common.WindSource)}
|
||||
* method, when the race has to decide whether to record the wind. If a previous {@link TrackedRace}
|
||||
* is <code>null</code>, the current {@link TrackedRace} would save the wind fixes earlier.
|
||||
*
|
||||
* @author Alexander Ries (D062114)
|
||||
*
|
||||
*/
|
||||
public interface RaceExecutionOrderProvider {
|
||||
|
||||
/**
|
||||
* Parameter <code>race</code> is a {@link TrackedRace} from which the method returns the previous
|
||||
* {@link TrackedRace}s in the execution order of a {@link Regatta}. This expresses the fact that the races returned
|
||||
* by this method must all have been finished before <code>race</code> can start.
|
||||
*/
|
||||
Set<TrackedRace> getPreviousRacesInExecutionOrder(TrackedRace race);
|
||||
|
||||
/**
|
||||
* When the owner of this cache-like provider has initialized all its structures that this cache requires
|
||||
* it shall call this method. This applies in particular after de-serializing the owner because during de-serialization,
|
||||
* even during the <code>readObject</code> method, the owner's fields may not all be initialized. The
|
||||
* <code>readResolve()</code> method is usually a good place to do so.
|
||||
*/
|
||||
void triggerUpdate();
|
||||
}
|
||||
@@ -275,6 +275,27 @@ public interface TrackedRace extends Serializable {
|
||||
* is returned. Otherwise, the center of gravity between the mark positions is computed and returned.
|
||||
*/
|
||||
Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* Checks whether the {@link Wind#getTimePoint()} is in range of start and end {@link TimePoint}s plus extra time
|
||||
* for wind recording. If, based on a {@link RaceExecutionOrderProvider}, there is no previous race that takes the
|
||||
* wind fix, an extended time range lead (see
|
||||
* {@link TrackedRaceImpl#EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS}) is used to record wind even a long
|
||||
* time before the race start.
|
||||
* <p>
|
||||
*
|
||||
* A race does not record wind when both, {@link #getStartOfTracking()} and {@link #getStartOfRace()} are
|
||||
* <code>null</code>. Wind is not recorded when it is after the later of {@link #getEndOfRace()} and
|
||||
* {@link #getEndOfTracking()} and one of the two is not <code>null</code>.
|
||||
* <p>
|
||||
*
|
||||
* This default implementation returns true which may be useful for tests and mocked implementations; however, real
|
||||
* implementations shall override this and provide a meaningful implementation according to the specification given
|
||||
* above.
|
||||
*/
|
||||
default boolean takesWindFix(Wind wind) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #getWind(Position, TimePoint, Set) getWind(p, at, Collections.emptyList())}
|
||||
@@ -652,9 +673,9 @@ public interface TrackedRace extends Serializable {
|
||||
void detachRaceLog(Serializable identifier);
|
||||
|
||||
/**
|
||||
* Detaches all {@link RaceLog} instances from this race
|
||||
* Detaches the link {@link RaceExecutionOrderProvider}
|
||||
*/
|
||||
void detachAllRaceLogs();
|
||||
void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider);
|
||||
|
||||
/**
|
||||
* Attaches the passed race log with this {@link TrackedRace}.
|
||||
@@ -674,6 +695,12 @@ public interface TrackedRace extends Serializable {
|
||||
*/
|
||||
void attachRegattaLog(RegattaLog regattaLog);
|
||||
|
||||
/**
|
||||
* Attaches a {@link RaceExecutionOrderProvider} to make a {@link TrackedRace} aware
|
||||
* which races are scheduled around it in the execution order of a {@link Regatta}.
|
||||
* */
|
||||
void attachRaceExecutionProvider(RaceExecutionOrderProvider raceExecutionOrderProvider);
|
||||
|
||||
/**
|
||||
* Returns the attached race log event track for this race if any.
|
||||
* Otherwise <code>null</code>.
|
||||
@@ -823,4 +850,5 @@ public interface TrackedRace extends Serializable {
|
||||
Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException, NoWindException;
|
||||
|
||||
void setPolarDataService(PolarDataService polarDataService);
|
||||
|
||||
}
|
||||
+3
-13
@@ -24,7 +24,6 @@ import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Sideline;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.TimingConstants;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
@@ -658,17 +657,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
||||
@Override
|
||||
public boolean recordWind(Wind wind, WindSource windSource) {
|
||||
final boolean result;
|
||||
// TODO check what a good filter is; remember that start/end of tracking may change over time; what if we have discarded valuable wind fixes?
|
||||
TimePoint startOfRace = getStartOfRace();
|
||||
TimePoint startOfTracking = getStartOfTracking();
|
||||
TimePoint endOfRace = getEndOfRace();
|
||||
TimePoint endOfTracking = getEndOfTracking();
|
||||
if ((startOfTracking == null || !startOfTracking.minus(TrackedRaceImpl.TIME_BEFORE_START_TO_TRACK_WIND_MILLIS).after(wind.getTimePoint()) ||
|
||||
(startOfRace != null && !startOfRace.minus(TrackedRaceImpl.TIME_BEFORE_START_TO_TRACK_WIND_MILLIS).after(wind.getTimePoint())))
|
||||
&&
|
||||
// Caution: don't add to endOfTracking; it may be the end of time, leading to a wrap-around / overflow
|
||||
(endOfTracking == null || endOfTracking.after(wind.getTimePoint().minus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS)) ||
|
||||
(endOfRace != null && endOfRace.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).after(wind.getTimePoint())))) {
|
||||
if (takesWindFix(wind)) {
|
||||
result = getOrCreateWindTrack(windSource).add(wind);
|
||||
updated(/* time point */null); // wind events shouldn't advance race time
|
||||
triggerManeuverCacheRecalculationForAllCompetitors();
|
||||
@@ -759,7 +748,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
||||
}
|
||||
super.detachRaceLog(identifier);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addCourseDesignChangedListener(CourseDesignChangedListener listener) {
|
||||
this.courseDesignChangedListeners.add(listener);
|
||||
@@ -818,4 +807,5 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
|
||||
public DynamicGPSFixTrack<Mark, GPSFix> getTrack(Mark mark) {
|
||||
return (DynamicGPSFixTrack<Mark, GPSFix>) super.getTrack(mark);
|
||||
}
|
||||
|
||||
}
|
||||
+92
-6
@@ -116,6 +116,7 @@ import com.sap.sailing.domain.tracking.GPSTrackListener;
|
||||
import com.sap.sailing.domain.tracking.LineDetails;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.RaceListener;
|
||||
import com.sap.sailing.domain.tracking.Track;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
@@ -156,7 +157,9 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
// TODO make this variable
|
||||
private static final long DELAY_FOR_CACHE_CLEARING_IN_MILLISECONDS = 7500;
|
||||
|
||||
public static final long TIME_BEFORE_START_TO_TRACK_WIND_MILLIS = 4 * 60 * 1000l; // let wind start four minutes before race
|
||||
public static final Duration TIME_BEFORE_START_TO_TRACK_WIND_MILLIS = Duration.ONE_MINUTE.times(4); // let wind start four minutes before race
|
||||
|
||||
public static final Duration EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS = Duration.ONE_HOUR;
|
||||
|
||||
private TrackedRaceStatus status;
|
||||
|
||||
@@ -283,6 +286,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
* Keys are the {@link RegattaLog#getId() IDs} of the regatta logs that are stored as values.
|
||||
*/
|
||||
protected transient ConcurrentHashMap<Serializable, RegattaLog> attachedRegattaLogs;
|
||||
|
||||
private transient ConcurrentHashMap<RaceExecutionOrderProvider, RaceExecutionOrderProvider> attachedRaceExecutionOrderProviders;
|
||||
|
||||
/**
|
||||
* The time delay to the current point in time in milliseconds.
|
||||
@@ -376,6 +381,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
locksForMarkPassings = new IdentityHashMap<>();
|
||||
attachedRaceLogs = new ConcurrentHashMap<>();
|
||||
attachedRegattaLogs = new ConcurrentHashMap<>();
|
||||
attachedRaceExecutionOrderProviders = new ConcurrentHashMap<>();
|
||||
this.status = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.PREPARED, 0.0);
|
||||
this.statusNotifier = new Object[0];
|
||||
this.loadingFromWindStoreLock = new NamedReentrantReadWriteLock("Loading from wind store lock for tracked race "
|
||||
@@ -573,6 +579,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
ois.defaultReadObject();
|
||||
raceStates = new WeakHashMap<>();
|
||||
attachedRaceLogs = new ConcurrentHashMap<>();
|
||||
attachedRaceExecutionOrderProviders = new ConcurrentHashMap<>();
|
||||
markPassingsTimes = new ArrayList<com.sap.sse.common.Util.Pair<Waypoint, com.sap.sse.common.Util.Pair<TimePoint, TimePoint>>>();
|
||||
// The short time wind cache needs to be there before operations such as maneuver recalculation try to access it
|
||||
shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2);
|
||||
@@ -1491,6 +1498,62 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the {@link Wind#getTimePoint()} is in range of start and end {@link TimePoint}s plus extra time
|
||||
* for wind recording. If, based on a {@link RaceExecutionOrderProvider}, there is no previous race that takes the
|
||||
* wind fix, an extended time range lead (see {@link TrackedRaceImpl#EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS})
|
||||
* is used to record wind even a long time before the race start.<p>
|
||||
*
|
||||
* A race does not record wind when both, {@link #getStartOfTracking()} and {@link #getStartOfRace()} are <code>null</code>.
|
||||
* Wind is not recorded when it is after the later of {@link #getEndOfRace()} and {@link #getEndOfTracking()} and one of the
|
||||
* two is not <code>null</code>.
|
||||
*/
|
||||
@Override
|
||||
public boolean takesWindFix(Wind wind) {
|
||||
final boolean result;
|
||||
final TimePoint earliestStartTimePoint = Util.getEarliestOfTimePoints(getStartOfRace(), getStartOfTracking());
|
||||
final TimePoint latestEndTimePoint = Util.getLatestOfTimePoints(getEndOfRace(), getEndOfTracking());
|
||||
if (earliestStartTimePoint != null) {
|
||||
// first check if the fix meets the criteria set by the latestEndTimePoint: either the latestEndTimePoint is null, meaning an
|
||||
// open interval which will continue to accept late wind fixes, or the fix time point is before the latestEndTimePoint plus a grace
|
||||
// interval:
|
||||
if (latestEndTimePoint == null || wind.getTimePoint().minus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).before(latestEndTimePoint)) {
|
||||
// then check, if fix is accepted anyway because it's after earliestStartTimePoint.minus(TIME_BEFORE_START_TO_TRACK_WIND_MILLIS)
|
||||
// and before latestEndTimePoint.plus(IS_LIVE_GRACE_PERIOD_IN_MILLIS) or latestEndTimePoint is null. In this case, no expensive
|
||||
// recursive check whether previous races take the fix are required.
|
||||
if (wind.getTimePoint().plus(TIME_BEFORE_START_TO_TRACK_WIND_MILLIS).after(earliestStartTimePoint)) {
|
||||
result = true;
|
||||
} else {
|
||||
// if the fix is older than even the extended lead interval would accept, don't accept the fix:
|
||||
if (wind.getTimePoint().plus(EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS).before(earliestStartTimePoint)) {
|
||||
result = false;
|
||||
} else {
|
||||
// the fix is in the critical interval between EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS and
|
||||
// TIME_BEFORE_START_TO_TRACK_WIND_MILLIS before the earliestStartTimePoint; the fix shall only be accepted
|
||||
// if no previous race exists that accepts it
|
||||
result = noPreviousRaceTakesWind(wind);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = false; // don't accept the fix if it's after the latest end time point plus some grace interval
|
||||
}
|
||||
} else {
|
||||
result = false; // don't accept a fix if we don't have any start time information about the race
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean noPreviousRaceTakesWind(Wind wind) {
|
||||
final boolean result;
|
||||
Set<TrackedRace> previousRacesInExecutionOrder = getPreviousRacesFromAttachedRaceExecutionOrderProviders();
|
||||
if (previousRacesInExecutionOrder == null || !previousRacesInExecutionOrder.stream().filter(tr -> tr.takesWindFix(wind) == true).findAny().isPresent()) {
|
||||
result = true;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wind getWind(Position p, TimePoint at) {
|
||||
@@ -3041,7 +3104,35 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
public void attachRaceLog(final RaceLog raceLog) {
|
||||
loadFixesForLog(raceLog, attachedRaceLogs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachRaceExecutionProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
if (raceExecutionOrderProvider != null && !attachedRaceExecutionOrderProviders.containsKey(raceExecutionOrderProvider)) {
|
||||
attachedRaceExecutionOrderProviders.put(raceExecutionOrderProvider, raceExecutionOrderProvider);
|
||||
}
|
||||
}
|
||||
|
||||
protected Set<TrackedRace> getPreviousRacesFromAttachedRaceExecutionOrderProviders() {
|
||||
final Set<TrackedRace> result;
|
||||
if (attachedRaceExecutionOrderProviders != null) {
|
||||
result = attachedRaceExecutionOrderProviders.values().stream().map(reop->reop.getPreviousRacesInExecutionOrder(this)).collect(HashSet::new, (r, e)->r.addAll(e), (r, e)->r.addAll(e));
|
||||
} else {
|
||||
result = Collections.emptySet();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
if (raceExecutionOrderProvider != null) {
|
||||
attachedRaceExecutionOrderProviders.remove(raceExecutionOrderProvider);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasRaceExecutionOrderProvidersAttached(){
|
||||
return !attachedRaceExecutionOrderProviders.isEmpty();
|
||||
}
|
||||
|
||||
private ReadonlyRaceState getRaceState(RaceLog raceLog) {
|
||||
ReadonlyRaceState result;
|
||||
synchronized (raceStates) {
|
||||
@@ -3064,11 +3155,6 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
|
||||
public void detachRaceLog(Serializable identifier) {
|
||||
this.attachedRaceLogs.remove(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachAllRaceLogs() {
|
||||
this.attachedRaceLogs.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceLog getRaceLog(Serializable identifier) {
|
||||
|
||||
+3
-1
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.tracking.impl;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
@@ -94,11 +95,12 @@ public class TrackedRegattaImpl implements TrackedRegatta {
|
||||
unlockTrackedRacesAfterRead();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolving replaces this de-serialized object (which has a <code>null</code> {@link #raceListeners} collection) by
|
||||
* a new one into which all other collection contents are copied.
|
||||
*/
|
||||
private Object readResolve() {
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
TrackedRegattaImpl result = new TrackedRegattaImpl(this.regatta);
|
||||
result.trackedRaces.putAll(this.trackedRaces);
|
||||
result.trackedRacesByBoatClass.putAll(this.trackedRacesByBoatClass);
|
||||
|
||||
+9
-4
@@ -49,6 +49,7 @@ import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceAbortedListener;
|
||||
import com.sap.sailing.domain.tracking.RaceChangeListener;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.RaceListener;
|
||||
import com.sap.sailing.domain.tracking.StartTimeChangedListener;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
@@ -590,10 +591,6 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachAllRaceLogs() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateStartTime() {
|
||||
}
|
||||
@@ -779,4 +776,12 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
public RankingMetric getRankingMetric() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachRaceExecutionProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,9 @@
|
||||
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
||||
<booleanAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT_AUTO" value="true"/>
|
||||
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
|
||||
<listEntry value="com.sap.sailing.gwt.regattaoverview.RegattaOverview"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.RaceBoard"/>
|
||||
<listEntry value="com.sap.sailing.gwt.Home"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.DataMining"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.LeaderboardEditing"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.Spectator"/>
|
||||
<listEntry value="com.sap.sailing.gwt.regattaoverview.RegattaOverview"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
|
||||
@@ -18,8 +15,12 @@
|
||||
<listEntry value="com.sap.sailing.gwt.ui.Simulator"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.YoutubePopup"/>
|
||||
<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
|
||||
<listEntry value="com.sap.sailing.gwt.home.Mobile"/>
|
||||
<listEntry value="com.sap.sailing.gwt.home.Desktop"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.LOG_LEVEL" value="INFO"/>
|
||||
<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
@@ -72,7 +73,7 @@
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.Home com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.regattaoverview.RegattaOverview"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Mobile -startupUrl /gwt/HomeDesktop.html com.sap.sailing.gwt.home.Desktop -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Desktop com.sap.sailing.gwt.home.Mobile com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
|
||||
</launchConfiguration>
|
||||
+5
@@ -18,6 +18,11 @@ public class BoatClassImageResolver {
|
||||
|
||||
static {
|
||||
boatClassIconsMap = new HashMap<String, ImageResource>();
|
||||
|
||||
// handicap sailing icons
|
||||
boatClassIconsMap.put(BoatClassMasterdata.ORC.getDisplayName(), imageResources.ORCIcon());
|
||||
boatClassIconsMap.put(BoatClassMasterdata.ORC_CLUB.getDisplayName(), imageResources.ORCIcon());
|
||||
boatClassIconsMap.put(BoatClassMasterdata.ORC_INTERNATIONAL.getDisplayName(), imageResources.ORCIcon());
|
||||
|
||||
boatClassIconsMap.put(BoatClassMasterdata._12M.getDisplayName(), imageResources._12mRIcon());
|
||||
boatClassIconsMap.put(BoatClassMasterdata._2_4M.getDisplayName(), imageResources._2_4mIcon());
|
||||
|
||||
+4
@@ -153,4 +153,8 @@ public interface BoatClassImageResources extends ClientBundle {
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/RS800.png")
|
||||
ImageResource RS800Icon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/ORC.png")
|
||||
ImageResource ORCIcon();
|
||||
|
||||
}
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
+2
-2
@@ -106,10 +106,10 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
|
||||
JSONArray jsonLeaderboards = new JSONArray();
|
||||
Map<String, Leaderboard> leaderboards = getService().getLeaderboards();
|
||||
for (String leaderboardName : leaderboards.keySet()) {
|
||||
if (!leaderboardName.equals(LeaderboardNameConstants.DEFAULT_LEADERBOARD_NAME))
|
||||
if (!leaderboardName.equals(LeaderboardNameConstants.DEFAULT_LEADERBOARD_NAME)) {
|
||||
jsonLeaderboards.add(leaderboardName);
|
||||
}
|
||||
}
|
||||
|
||||
String json = jsonLeaderboards.toJSONString();
|
||||
return Response.ok(json, MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
|
||||
+2
-2
@@ -889,8 +889,8 @@ public class RegattasResource extends AbstractSailingServerResource {
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
jsonCompetitorInLeg.put("gapToLeader-s",
|
||||
trackedLegOfCompetitor.getGapToLeader(timePoint, rankingInfo, WindPositionMode.LEG_MIDDLE));
|
||||
Duration gapToLeaderDuration = trackedLegOfCompetitor.getGapToLeader(timePoint, rankingInfo, WindPositionMode.LEG_MIDDLE);
|
||||
jsonCompetitorInLeg.put("gapToLeader-s", gapToLeaderDuration != null ? gapToLeaderDuration.asSeconds() : 0.0);
|
||||
jsonCompetitorInLeg.put("started", trackedLegOfCompetitor.hasStartedLeg(timePoint));
|
||||
jsonCompetitorInLeg.put("finished", trackedLegOfCompetitor.hasFinishedLeg(timePoint));
|
||||
jsonCompetitors.add(jsonCompetitorInLeg);
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ public class InitialLoadReplicationObjectIdentityTest extends AbstractServerRepl
|
||||
DynamicTrackedRace masterTrackedRace = master.createTrackedRace(new RegattaNameAndRaceName(masterRegatta.getName(), masterRace.getName()),
|
||||
master.getWindStore(), master.getGPSFixStore(), /* delayToLiveInMillis */ 3000,
|
||||
/* millisecondsOverWhichToAverageWind */ 15000, /* millisecondsOverWhichToAverageSpeed */ 10000, /*ignoreTracTracMarkPassings*/ false);
|
||||
|
||||
masterTrackedRace.setStartOfTrackingReceived(MillisecondsTimePoint.now());
|
||||
/* Leaderboard */
|
||||
final String leaderboardName = "Great Leaderboard";
|
||||
final int[] discardThresholds = new int[] { 17, 23 };
|
||||
|
||||
+7
-2
@@ -55,6 +55,7 @@ import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
|
||||
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
|
||||
import com.sap.sailing.server.operationaltransformation.TrackRegatta;
|
||||
import com.sap.sse.common.Color;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
@@ -142,7 +143,9 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
|
||||
|
||||
@Test
|
||||
public void testWindAdditionReplication() throws InterruptedException {
|
||||
final Wind wind = new WindImpl(new DegreePosition(2, 3), new MillisecondsTimePoint(3456),
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
trackedRace.setStartOfTrackingReceived(now);
|
||||
final Wind wind = new WindImpl(new DegreePosition(2, 3), new MillisecondsTimePoint(now.asMillis()+1234),
|
||||
new KnotSpeedWithBearingImpl(13, new DegreeBearingImpl(234)));
|
||||
WindSource webWindSource = new WindSourceImpl(WindSourceType.WEB);
|
||||
trackedRace.recordWind(wind, webWindSource);
|
||||
@@ -190,12 +193,14 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
|
||||
|
||||
@Test
|
||||
public void testReplicationOfLoadingOfStoredWindTrack() throws UnknownHostException, MongoException, InterruptedException {
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
trackedRace.setStartOfTrackingReceived(now);
|
||||
MongoWindStore windStore = MongoWindStoreFactory.INSTANCE.getMongoWindStore(PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(),
|
||||
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory());
|
||||
WindSource webWindSource = new WindSourceImpl(WindSourceType.WEB);
|
||||
WindTrack windTrack = windStore.getWindTrack(trackedRegatta.getRegatta().getName(), trackedRace, webWindSource, /* millisecondsOverWhichToAverage */ 10000,
|
||||
/* delayForWindEstimationCacheInvalidation */ 10000);
|
||||
final Wind wind = new WindImpl(new DegreePosition(2, 3), new MillisecondsTimePoint(3456),
|
||||
final Wind wind = new WindImpl(new DegreePosition(2, 3), new MillisecondsTimePoint(now.asMillis()+1234),
|
||||
new KnotSpeedWithBearingImpl(13, new DegreeBearingImpl(234)));
|
||||
windTrack.add(wind);
|
||||
Thread.sleep(1000); // give MongoDB time to read its own writes in a separate session
|
||||
|
||||
+1
@@ -101,6 +101,7 @@ public class WindByRaceLogTest {
|
||||
service.apply(new TrackRegatta(raceIdentifier));
|
||||
trackedRace = (DynamicTrackedRace) service.apply(new CreateTrackedRace(raceIdentifier, EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,/* delayToLiveInMillis */ 5000,
|
||||
/* millisecondsOverWhichToAverageWind */ 10000, /* millisecondsOverWhichToAverageSpeed */10000));
|
||||
trackedRace.setStartOfTrackingReceived(MillisecondsTimePoint.now());
|
||||
defaultFleet = Util.get(raceColumn.getFleets(), 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,11 +90,6 @@ public class RaceLogReplicator implements RaceColumnListener {
|
||||
public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceColumnAddedToContainer(RaceColumn raceColumn) {
|
||||
}
|
||||
|
||||
-5
@@ -62,11 +62,6 @@ public class RaceLogScoringReplicator implements RaceColumnListener {
|
||||
public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, boolean firstColumnIsNonDiscardableCarryForward) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceColumnAddedToContainer(RaceColumn raceColumn) {
|
||||
}
|
||||
|
||||
+9
-4
@@ -42,6 +42,7 @@ import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceAbortedListener;
|
||||
import com.sap.sailing.domain.tracking.RaceChangeListener;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.StartTimeChangedListener;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
@@ -438,10 +439,6 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
|
||||
public void detachRaceLog(Serializable identifier) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachAllRaceLogs() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachRaceLog(RaceLog raceLog) {
|
||||
}
|
||||
@@ -616,4 +613,12 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
|
||||
public RankingMetric getRankingMetric() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachRaceExecutionProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
|
||||
}
|
||||
}
|
||||
@@ -362,4 +362,46 @@ public class Util {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the earlier {@link TimePoint} of a and b. If one of them is <code>null</code> and the other
|
||||
* <code>!null</code>, the TimePoint that is not <code>!null</code> gets returned. If both are <code>null</code>,
|
||||
* <code>null</code> is the result.
|
||||
*/
|
||||
public static TimePoint getEarliestOfTimePoints(TimePoint a, TimePoint b) {
|
||||
TimePoint result = null;
|
||||
if (a != null && b != null) {
|
||||
result = a.before(b) ? a : b;
|
||||
} else {
|
||||
result = (a != null && b == null) ? a : (a == null && b != null) ? b : null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latest {@link TimePoint} of a and b. If one of them is <code>null</code> and the other
|
||||
* <code>!null</code>, the TimePoint that is not <code>!null</code> gets returned. If both are <code>null</code>,
|
||||
* <code>null</code> is the result.
|
||||
*/
|
||||
public static TimePoint getLatestOfTimePoints(TimePoint a, TimePoint b) {
|
||||
TimePoint result = null;
|
||||
if (a != null && b != null) {
|
||||
result = a.after(b) ? a : b;
|
||||
} else {
|
||||
result = (a != null && b == null) ? a : (a == null && b != null) ? b : null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if <code>timePoint</code> is after <code>a</code> an before <code>b</code>.
|
||||
* If one of the parameters is <code>null</code> the method returns <code>false</code>.
|
||||
*/
|
||||
public static boolean isTimePointInRangeOfTimePointsAandB(TimePoint timePoint, TimePoint a, TimePoint b) {
|
||||
boolean result = false;
|
||||
if (timePoint != null && a != null && b != null) {
|
||||
result = timePoint.after(a) && timePoint.before(b);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user