mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-04 10:09:42 +00:00
Merge branch 'master' into ubilabs--buoy_positioning_app--develop
Conflicts: java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT sdm.launch java/com.sap.sailing.gwt.ui/SailingGWT Remote Profiling (Run-Mode only).launch java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch java/com.sap.sailing.gwt.ui/SailingGWT.launch java/com.sap.sse.gwt.theme/SSETheme_GWT sdm.launch java/com.sap.sse.gwt.theme/SSETheme_GWT.launch
This commit is contained in:
commit
ca254c72e3
335 files changed
+6696
-3400
No files matched your search
@@ -24,9 +24,14 @@ if __name__ == '__main__':
|
||||
# using options like re.IGNORECASE will render the search almost unusable
|
||||
prefix_pattern = re.compile('^%s' % prefix)
|
||||
for fix in wind_tracks.find({'REGATTA_NAME' : prefix_pattern}):
|
||||
data = (fix['REGATTA_NAME'], str(fix['WIND']['LAT_DEG']),
|
||||
str(fix['WIND']['LNG_DEG']), str(fix['WIND']['TIME_AS_MILLIS']), str(fix['WIND']['KNOT_SPEED']),
|
||||
str(fix['WIND']['DEGREE_BEARING']))
|
||||
data = {}
|
||||
try:
|
||||
data = (fix['REGATTA_NAME'], str(fix['WIND']['LAT_DEG']),
|
||||
str(fix['WIND']['LNG_DEG']), str(fix['WIND']['TIME_AS_MILLIS']), str(fix['WIND']['KNOT_SPEED']),
|
||||
str(fix['WIND']['DEGREE_BEARING']))
|
||||
except:
|
||||
print 'Exception for dataset %s' % data
|
||||
continue
|
||||
wind_source_id = fix['WIND_SOURCE_NAME']
|
||||
if hasattr(fix, 'WIND_SOURCE_ID'):
|
||||
wind_source_id += '-'+fix['WIND_SOURCE_ID']
|
||||
@@ -37,24 +42,24 @@ if __name__ == '__main__':
|
||||
data_container.append(data)
|
||||
if counter % 1000 == 0:
|
||||
sys.stdout.write('.')
|
||||
sys.stdout.flush()
|
||||
if counter % 100000 == 0:
|
||||
sys.stdout.write(str(counter))
|
||||
sys.stdout.flush()
|
||||
|
||||
print '\nSorting %s fixes in memory for regattas %s' % (len(data_container), regattas)
|
||||
sorted_fixes = sorted(data_container, key=lambda windfix: windfix[3], reverse=True)
|
||||
counter = 0; last_timepoint = {}
|
||||
print 'Starting export of %s wind fixes in interval %sms to %s' % (len(sorted_fixes), long(interval), exportfile)
|
||||
for cached_fix in sorted_fixes:
|
||||
if last_timepoint.get(cached_fix[0])==None or ((long(last_timepoint.get(cached_fix[0]))-long(cached_fix[3])) >= long(interval)):
|
||||
counter += 1
|
||||
csv.write(';'.join(cached_fix))
|
||||
csv.write('\n')
|
||||
last_timepoint[cached_fix[0]] = cached_fix[3]
|
||||
if counter % 1000 == 0:
|
||||
sys.stdout.write('#')
|
||||
sys.stdout.flush()
|
||||
print '\nFlushing to store, sorting %s fixes in memory for regattas %s' % (len(data_container), regattas)
|
||||
sorted_fixes = sorted(data_container, key=lambda windfix: windfix[3], reverse=True)
|
||||
counter = 0; last_timepoint = {}
|
||||
print 'Starting export of %s wind fixes in interval %sms to %s' % (len(sorted_fixes), long(interval), exportfile)
|
||||
for cached_fix in sorted_fixes:
|
||||
if last_timepoint.get(cached_fix[0])==None or ((long(last_timepoint.get(cached_fix[0]))-long(cached_fix[3])) >= long(interval)):
|
||||
counter += 1
|
||||
csv.write(';'.join(cached_fix))
|
||||
csv.write('\n')
|
||||
last_timepoint[cached_fix[0]] = cached_fix[3]
|
||||
if counter % 1000 == 0:
|
||||
sys.stdout.write('#')
|
||||
sys.stdout.flush()
|
||||
# free memory
|
||||
data_container = []
|
||||
|
||||
print '\nExported %s fix(es) that have a minimum time distance of %s milliseconds' % (counter, interval)
|
||||
csv.close()
|
||||
print 'Exported the following prefix-matching regattas: %s' % last_timepoint.keys()
|
||||
@@ -20,7 +20,7 @@ start_tmux() {
|
||||
|
||||
start_servers() {
|
||||
NUMBER_OF_INSTANCES=`echo "$JAVA_START_INSTANCES" | wc -w`
|
||||
MEMORY_PER_INSTANCE_IN_MB=`cat /proc/meminfo | grep MemTotal | awk '{printf("%i\n", ($2 / 1024 - 1500) / '$NUMBER_OF_INSTANCES' );}'`
|
||||
MEMORY_PER_INSTANCE_IN_MB=`cat /proc/meminfo | grep MemTotal | awk '{printf("%i\n", ($2 / 1024 * 0.75 - 1500) / '$NUMBER_OF_INSTANCES' );}'`
|
||||
echo "Using ${MEMORY_PER_INSTANCE_IN_MB}MB as default heap size per instance."
|
||||
for conf in $JAVA_START_INSTANCES; do
|
||||
echo "Checking for amazon update..."
|
||||
|
||||
@@ -70,22 +70,11 @@
|
||||
line-height: 0pt;
|
||||
}
|
||||
|
||||
.competitorEditButton {
|
||||
.eventLogo {
|
||||
position: absolute;
|
||||
height: 23.5pt;
|
||||
width: 23.5pt;
|
||||
right: 10pt;
|
||||
top: 17.5pt;
|
||||
right: 12.5px;
|
||||
bottom: 10px;
|
||||
height: 22.5pt;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.competitorLabel{
|
||||
position: absolute;
|
||||
width: 200pt;
|
||||
height: 23.5pt;
|
||||
margin-top: 17.5pt;
|
||||
right: 43.5pt;
|
||||
font-size: 12pt;
|
||||
font-color: black;
|
||||
text-align: right;
|
||||
line-height: 23.5pt;
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
<!doctype html>
|
||||
<!-- The DOCTYPE declaration above will set the -->
|
||||
<!-- browser's rendering engine into -->
|
||||
<!-- "Standards Mode". Replacing this declaration -->
|
||||
<!-- with a "Quirks Mode" doctype may lead to some -->
|
||||
<!-- differences in layout. -->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<meta http-equiv="REFRESH" content="0; url=http://www.sapsailing.com/browser-info.html">
|
||||
<![endif]-->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<link href='src/main/resources/images/dashboardicon.png'
|
||||
rel='apple-touch-startup-image'>
|
||||
<link href='src/main/resources/images/dashboardicon.png' rel='apple-touch-icon'>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="src/main/resources/images/dashboardicon.png" />
|
||||
|
||||
<link href='images/dashboardicon.png' rel='apple-touch-icon'>
|
||||
|
||||
<title>ESS Dashboard</title>
|
||||
|
||||
@@ -19,7 +21,7 @@
|
||||
<script type="text/javascript"
|
||||
src="com.sap.sailing.dashboards.gwt.RibDashboard/com.sap.sailing.dashboards.gwt.RibDashboard.nocache.js"></script>
|
||||
|
||||
<!-- Disables vertical scrolling whole website over edge on apple browsers -->
|
||||
<!-- Disables scrolling whole website vertically over edge on apple browsers -->
|
||||
<script type="text/javascript">
|
||||
document.ontouchmove = function(event){
|
||||
event.preventDefault();
|
||||
|
||||
Regular → Executable
+9
-3
@@ -4,7 +4,10 @@
|
||||
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
||||
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="false"/>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT" value="9998"/>
|
||||
<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.dashboards.gwt.RibDashboard"/>
|
||||
</listAttribute>
|
||||
<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/dashboards/RibDashboard.html"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/com.sap.sailing.dashboards.gwt"/>
|
||||
@@ -19,6 +22,8 @@
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
|
||||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" path="1" type="4"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/java" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.dashboards.gwt/src/main/java" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.dashboards.gwt/src/main/resources" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain/src" path="3" type="2"/> "/>
|
||||
@@ -29,13 +34,14 @@
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.google.gwt.osgi/lib/gwt-servlet.jar" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.google.gwt.osgi/lib/gwt-user.jar" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.domain.common/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sailing.gwt.ui/src/main/java" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/org.moxieapps.gwt.highcharts/src" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.gwt.adminconsole/src" path="3" type="2"/> "/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
||||
<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="-nosuperDevMode -incremental -war "${project_loc:com.sap.sailing.dashboards.gwt}" -startupUrl /dashboards/RibDashboard.html -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort auto com.sap.sailing.dashboards.gwt.RibDashboard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -war "${project_loc:com.sap.sailing.dashboards.gwt}" -startupUrl /dashboards/RibDashboard.html -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9998 com.sap.sailing.dashboards.gwt.RibDashboard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.dashboards.gwt"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XstartOnFirstThread -Xmx2048m"/>
|
||||
</launchConfiguration>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
+57
@@ -0,0 +1,57 @@
|
||||
package com.sap.sailing.dashboards.gwt.client;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||
import com.google.gwt.dom.client.Style.Visibility;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
|
||||
public class EventLogo extends Image {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RibDashboardPanel.class.getName());
|
||||
|
||||
protected EventLogo() {
|
||||
super();
|
||||
this.getElement().addClassName("eventLogo");
|
||||
}
|
||||
|
||||
public static EventLogo getEventLogoFromEventId(SailingServiceAsync sailingServiceAsync, String eventId) {
|
||||
final EventLogo eventLogo = new EventLogo();
|
||||
eventLogo.getElement().setAttribute("src", "someURL");
|
||||
try {
|
||||
final UUID eventUUID = UUID.fromString(eventId);
|
||||
sailingServiceAsync.getEventById(eventUUID, true, new AsyncCallback<EventDTO>() {
|
||||
@Override
|
||||
public void onSuccess(final EventDTO event) {
|
||||
logger.log(Level.INFO, "GOT EVENT: ");
|
||||
final String logoUrl = event.getLogoImageURL();
|
||||
// Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
//
|
||||
// @Override
|
||||
// public void execute() {
|
||||
if (logoUrl != null) {
|
||||
eventLogo.getElement().setAttribute("src", logoUrl);
|
||||
} else {
|
||||
eventLogo.getElement().getStyle().setVisibility(Visibility.HIDDEN);
|
||||
}
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
eventLogo.getElement().getStyle().setVisibility(Visibility.HIDDEN);
|
||||
}
|
||||
});
|
||||
} catch (IllegalArgumentException e) {
|
||||
eventLogo.getElement().getStyle().setVisibility(Visibility.HIDDEN);
|
||||
}
|
||||
return eventLogo;
|
||||
}
|
||||
}
|
||||
+5
-161
@@ -5,26 +5,10 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.dom.client.Document;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.user.client.Cookies;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.FocusPanel;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.RootPanel;
|
||||
import com.sap.sailing.dashboards.gwt.client.actions.GetRibDashboardRaceInfoAction;
|
||||
import com.sap.sailing.dashboards.gwt.client.bottomnotification.BottomNotification;
|
||||
import com.sap.sailing.dashboards.gwt.client.device.Location;
|
||||
import com.sap.sailing.dashboards.gwt.client.popups.RacingNotYetStartedPopup;
|
||||
import com.sap.sailing.dashboards.gwt.client.popups.RacingNotYetStartedPopupListener;
|
||||
import com.sap.sailing.dashboards.gwt.client.popups.competitorselection.CompetitorSelectionPopup;
|
||||
import com.sap.sailing.dashboards.gwt.client.popups.competitorselection.CompetitorSelectionPopupListener;
|
||||
import com.sap.sailing.dashboards.gwt.client.startanalysis.NewStartAnalysisListener;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
||||
@@ -39,126 +23,48 @@ import com.sap.sse.gwt.client.player.TimeListener;
|
||||
* @author Alexander Ries
|
||||
*
|
||||
*/
|
||||
public class RibDashboardDataRetriever implements RacingNotYetStartedPopupListener, CompetitorSelectionPopupListener,
|
||||
TimeListener, RaceSelectionProvider {
|
||||
public class RibDashboardDataRetriever implements TimeListener, RaceSelectionProvider {
|
||||
|
||||
private int numberOfCachedStartAnalysisDTOs;
|
||||
private String leaderboardName;
|
||||
private ArrayList<RibDashboardDataRetrieverListener> dataRetrieverListener;
|
||||
private ArrayList<NewStartAnalysisListener> newStartAnalysisListeners;
|
||||
private ArrayList<RaceSelectionChangeListener> raceSelectionChangeListener;
|
||||
|
||||
private String selectedCompetitorName;
|
||||
|
||||
private CompetitorSelectionPopup competitorSelectionPopup;
|
||||
private RacingNotYetStartedPopup popupRacingNotYetStarted;
|
||||
private BottomNotification bottomNotification;
|
||||
private FocusPanel competitorEditButton;
|
||||
private Label competitorLabel;
|
||||
private boolean shouldReloadStartAnalysis;
|
||||
|
||||
private AsyncActionsExecutor asyncActionsExecutor;
|
||||
|
||||
private final RibDashboardServiceAsync ribDashboardService;
|
||||
|
||||
private final Object MUTEX;
|
||||
|
||||
private static RibDashboardDataRetriever INSTANCE = null;
|
||||
|
||||
private static final String PARAM_LEADERBOARD_NAME = "leaderboardName";
|
||||
private static final String KEY_SLECTED_TEAM_COOKIE = "selectedTeam";
|
||||
private static final int SLECTED_TEAM_COOKIE_EXPIRE_TIME_IN_MILLIS = 60 * 1000 * 60 * 5;
|
||||
|
||||
public RibDashboardDataRetriever(RibDashboardServiceAsync ribDashboardService) {
|
||||
initNonFinalMemberVariablesWithNoArgumentConstructor();
|
||||
initRacingNotYetStartedPopup();
|
||||
MUTEX = new Object();
|
||||
this.ribDashboardService = ribDashboardService;
|
||||
this.leaderboardName = Window.Location.getParameter(PARAM_LEADERBOARD_NAME);
|
||||
numberOfCachedStartAnalysisDTOs = 0;
|
||||
competitorSelectionPopup = new CompetitorSelectionPopup();
|
||||
selectedCompetitorName = Cookies.getCookie(KEY_SLECTED_TEAM_COOKIE);
|
||||
asyncActionsExecutor = new AsyncActionsExecutor();
|
||||
initCompetitorLabelAndAddToRootPanel();
|
||||
initBottomNotification();
|
||||
}
|
||||
|
||||
public static RibDashboardDataRetriever getInstance(RibDashboardServiceAsync ribDashboardService) {
|
||||
synchronized (Location.class) {
|
||||
if (INSTANCE == null) {
|
||||
if (ribDashboardService == null) {
|
||||
throw new RuntimeException("Can not initialize data retriever without reference to ribdashboard service");
|
||||
}
|
||||
INSTANCE = new RibDashboardDataRetriever(ribDashboardService);
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private void initRacingNotYetStartedPopup() {
|
||||
popupRacingNotYetStarted = new RacingNotYetStartedPopup();
|
||||
popupRacingNotYetStarted.addListener(this);
|
||||
}
|
||||
|
||||
private void initBottomNotification() {
|
||||
bottomNotification = new BottomNotification();
|
||||
RootPanel.get().add(bottomNotification);
|
||||
}
|
||||
|
||||
private void initNonFinalMemberVariablesWithNoArgumentConstructor() {
|
||||
dataRetrieverListener = new ArrayList<RibDashboardDataRetrieverListener>();
|
||||
newStartAnalysisListeners = new ArrayList<NewStartAnalysisListener>();
|
||||
raceSelectionChangeListener = new ArrayList<RaceSelectionChangeListener>();
|
||||
}
|
||||
|
||||
private void loadLiveRaceInfoFromRibDashboadService() {
|
||||
GetRibDashboardRaceInfoAction getRibDashboardRaceInfoAction = new GetRibDashboardRaceInfoAction(ribDashboardService, leaderboardName, selectedCompetitorName);
|
||||
|
||||
GetRibDashboardRaceInfoAction getRibDashboardRaceInfoAction = new GetRibDashboardRaceInfoAction(ribDashboardService, leaderboardName);
|
||||
|
||||
asyncActionsExecutor.execute(getRibDashboardRaceInfoAction, new AsyncCallback<RibDashboardRaceInfoDTO>() {
|
||||
@Override
|
||||
public void onSuccess(RibDashboardRaceInfoDTO result) {
|
||||
switch (result.responseMessage) {
|
||||
case OK:
|
||||
popupRacingNotYetStarted.hide(/* remove blur effect */true);
|
||||
case RACE_LIVE:
|
||||
List<RegattaAndRaceIdentifier> singletonList = Collections
|
||||
.singletonList(result.idOfLastTrackedRace);
|
||||
setSelection(singletonList);
|
||||
if (result.startAnalysisDTOList != null) {
|
||||
int numberOfReceivedStartAnalysisDTOs = result.startAnalysisDTOList.size();
|
||||
if (numberOfCachedStartAnalysisDTOs != numberOfReceivedStartAnalysisDTOs || shouldReloadStartAnalysis == true) {
|
||||
shouldReloadStartAnalysis = false;
|
||||
numberOfCachedStartAnalysisDTOs = numberOfReceivedStartAnalysisDTOs;
|
||||
notifyNewStartAnalysisListener(result.startAnalysisDTOList, selectedCompetitorName);
|
||||
}
|
||||
}
|
||||
if(competitorEditButton == null){
|
||||
initCompetitorChangeButtonAndAddToRootPanel();
|
||||
setCompetitorLabelText(selectedCompetitorName);
|
||||
}
|
||||
if (result.competitorNamesFromLastTrackedRace != null
|
||||
&& result.competitorNamesFromLastTrackedRace.size() > 0
|
||||
&& !competitorSelectionPopup.isShown()) {
|
||||
competitorSelectionPopup.setCompetitorList(result.competitorNamesFromLastTrackedRace);
|
||||
competitorSelectionPopup.addListener(RibDashboardDataRetriever.this);
|
||||
}
|
||||
notifyDataObservers(result);
|
||||
break;
|
||||
case NO_COMPETITOR_SELECTED:
|
||||
popupRacingNotYetStarted.hide(true);
|
||||
if (result.competitorNamesFromLastTrackedRace != null
|
||||
&& result.competitorNamesFromLastTrackedRace.size() > 0
|
||||
&& !competitorSelectionPopup.isShown()) {
|
||||
competitorSelectionPopup.setCompetitorList(result.competitorNamesFromLastTrackedRace);
|
||||
competitorSelectionPopup.addListener(RibDashboardDataRetriever.this);
|
||||
competitorSelectionPopup.show();
|
||||
}
|
||||
break;
|
||||
case NO_RACE_LIVE:
|
||||
if (numberOfCachedStartAnalysisDTOs == 0) {
|
||||
popupRacingNotYetStarted.showWithMessageAndImageAndButtonText("Racing not yet started",
|
||||
RibDashboardImageResources.INSTANCE.watch(), "Retry");
|
||||
} else {
|
||||
setSelection(null);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -195,68 +101,6 @@ public class RibDashboardDataRetriever implements RacingNotYetStartedPopupListen
|
||||
}
|
||||
}
|
||||
|
||||
public void addNewStartAnalysisListener(NewStartAnalysisListener o) {
|
||||
synchronized (MUTEX) {
|
||||
if (o != null && !newStartAnalysisListeners.contains(o)) {
|
||||
this.newStartAnalysisListeners.add(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeNewStartAnalysisListener(NewStartAnalysisListener o) {
|
||||
synchronized (MUTEX) {
|
||||
this.newStartAnalysisListeners.remove(o);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyNewStartAnalysisListener(List<StartAnalysisDTO> startAnalysisDTOs, String selectedCompetitor) {
|
||||
synchronized (MUTEX) {
|
||||
for (NewStartAnalysisListener newStartAnalysisListener : newStartAnalysisListeners) {
|
||||
newStartAnalysisListener.addNewStartAnalysisCardForCompetitor(startAnalysisDTOs, selectedCompetitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initCompetitorChangeButtonAndAddToRootPanel() {
|
||||
if (competitorEditButton == null) {
|
||||
competitorEditButton = new FocusPanel();
|
||||
competitorEditButton.addStyleName("competitorEditButton");
|
||||
Image settingsImage = new Image();
|
||||
settingsImage.setResource(RibDashboardImageResources.INSTANCE.settings());
|
||||
competitorEditButton.add(settingsImage);
|
||||
competitorEditButton.addDomHandler(new ClickHandler() {
|
||||
public void onClick(ClickEvent event) {
|
||||
competitorSelectionPopup.show();
|
||||
}
|
||||
}, ClickEvent.getType());
|
||||
RootPanel.get().add(competitorEditButton);
|
||||
}
|
||||
}
|
||||
|
||||
private void initCompetitorLabelAndAddToRootPanel() {
|
||||
competitorLabel = new Label();
|
||||
competitorLabel.addStyleName("competitorLabel");
|
||||
Document.get().getBody().appendChild(competitorLabel.getElement());
|
||||
}
|
||||
|
||||
private void setCompetitorLabelText(String slectedCompetitor) {
|
||||
competitorLabel.setText(slectedCompetitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popupButtonClicked() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didClickedOKWithCompetitorName(String competitorName) {
|
||||
this.selectedCompetitorName = competitorName;
|
||||
Cookies.setCookie(KEY_SLECTED_TEAM_COOKIE, competitorName, new Date(new Date().getTime()
|
||||
+ SLECTED_TEAM_COOKIE_EXPIRE_TIME_IN_MILLIS));
|
||||
initCompetitorChangeButtonAndAddToRootPanel();
|
||||
setCompetitorLabelText(competitorName);
|
||||
shouldReloadStartAnalysis = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
loadLiveRaceInfoFromRibDashboadService();
|
||||
|
||||
+2
-2
@@ -33,10 +33,10 @@ public class RibDashboardEntryPoint extends AbstractEntryPoint<StringMessages> {
|
||||
RibDashboardServiceAsync ribdashboardService = GWT.create(RibDashboardService.class);
|
||||
EntryPointHelper.registerASyncService((ServiceDefTarget) ribdashboardService, RemoteServiceMappingConstants.WEB_CONTEXT_PATH, RemoteServiceMappingConstants.ribdashboardServiceRemotePath);
|
||||
|
||||
RibDashboardDataRetriever dataRetriever = RibDashboardDataRetriever.getInstance(ribdashboardService);
|
||||
RibDashboardDataRetriever dataRetriever = new RibDashboardDataRetriever(ribdashboardService);
|
||||
|
||||
applyMGWTSettings();
|
||||
RibDashboardPanel ribDashboardPanel = new RibDashboardPanel(ribdashboardService);
|
||||
RibDashboardPanel ribDashboardPanel = new RibDashboardPanel(ribdashboardService, sailingService, dataRetriever);
|
||||
RootLayoutPanel.get().add(ribDashboardPanel);
|
||||
WindBotDataRetriever windBotDataRetriever = new WindBotDataRetriever(sailingService);
|
||||
windBotDataRetriever.addNumberOfWindBotsChangeListeners(ribDashboardPanel);
|
||||
|
||||
-3
@@ -33,9 +33,6 @@ public interface RibDashboardImageResources extends ClientBundle {
|
||||
@Source("images/rightarrow_disabled.png")
|
||||
ImageResource rightdisabled();
|
||||
|
||||
@Source("images/windarrow.png")
|
||||
ImageResource windarrow();
|
||||
|
||||
@Source("images/compass.png")
|
||||
ImageResource compass();
|
||||
|
||||
|
||||
+26
-20
@@ -10,18 +10,19 @@ import com.google.gwt.dom.client.DivElement;
|
||||
import com.google.gwt.dom.client.Document;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.LayoutPanel;
|
||||
import com.google.gwt.user.client.ui.RootPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.googlecode.mgwt.ui.client.widget.carousel.Carousel;
|
||||
import com.sap.sailing.dashboards.gwt.client.bottomnotification.BottomNotification;
|
||||
import com.sap.sailing.dashboards.gwt.client.startanalysis.StartlineAnalysisComponent;
|
||||
import com.sap.sailing.dashboards.gwt.client.startlineadvantage.StartLineAdvantageComponent;
|
||||
import com.sap.sailing.dashboards.gwt.client.windchart.WindBotComponent;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
/**
|
||||
* This class contains all components of the Dashboard and the basic UI Elements of the Dashboard, like top and bottom
|
||||
@@ -57,7 +58,7 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr
|
||||
@UiField
|
||||
HTMLPanel rightwindbotcontainer;
|
||||
|
||||
@UiField
|
||||
@UiField(provided = true)
|
||||
public StartLineAdvantageComponent startLineCAComponent;
|
||||
|
||||
@UiField
|
||||
@@ -69,19 +70,34 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr
|
||||
@UiField
|
||||
public HTMLPanel bottombar;
|
||||
|
||||
@UiField
|
||||
public HTMLPanel windcharthint;
|
||||
|
||||
@UiField(provided = true)
|
||||
public StartlineAnalysisComponent startanalysisComponent;
|
||||
|
||||
private BottomNotification bottomNotification;
|
||||
private List<WindBotComponent> windBotComponents;
|
||||
private StringMessages stringConstants;
|
||||
private final String EVENT_ID_PARAMETER = "eventId";
|
||||
|
||||
public RibDashboardPanel(RibDashboardServiceAsync ribDashboardService) {
|
||||
public RibDashboardPanel(RibDashboardServiceAsync ribDashboardService, SailingServiceAsync sailingServiceAsync, RibDashboardDataRetriever ribDashboardDataRetriever) {
|
||||
windBotComponents = new ArrayList<WindBotComponent>();
|
||||
RibDashboardDataRetriever.getInstance(ribDashboardService).addDataObserver(this);
|
||||
initBottomNotification();
|
||||
startanalysisComponent = new StartlineAnalysisComponent(bottomNotification, ribDashboardService);
|
||||
ribDashboardDataRetriever.addDataObserver(this);
|
||||
startanalysisComponent = new StartlineAnalysisComponent(ribDashboardService, sailingServiceAsync);
|
||||
startLineCAComponent = new StartLineAdvantageComponent(ribDashboardDataRetriever);
|
||||
stringConstants = StringMessages.INSTANCE;
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
initLogos();
|
||||
windcharthint.getElement().setInnerText(stringConstants.dashboardWindChartHint());
|
||||
windloadinghintleft.setInnerText(stringConstants.dashboardWindBotLoading());
|
||||
windloadinghintright.setInnerText(stringConstants.dashboardWindBotLoading());
|
||||
|
||||
String eventId = Window.Location.getParameter(EVENT_ID_PARAMETER);
|
||||
EventLogo eventLogo = EventLogo.getEventLogoFromEventId(sailingServiceAsync, eventId);
|
||||
if(eventLogo != null){
|
||||
Document.get().getBody().appendChild(eventLogo.getElement());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initLogos() {
|
||||
@@ -89,16 +105,6 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr
|
||||
logo.setResource(RibDashboardImageResources.INSTANCE.logo_sap());
|
||||
logo.getElement().addClassName(style.logo());
|
||||
Document.get().getBody().appendChild(logo.getElement());
|
||||
|
||||
Image esslogo = new Image();
|
||||
esslogo.setResource(RibDashboardImageResources.INSTANCE.logoess());
|
||||
esslogo.getElement().addClassName(style.extremelogo());
|
||||
Document.get().getBody().appendChild(esslogo.getElement());
|
||||
}
|
||||
|
||||
private void initBottomNotification() {
|
||||
bottomNotification = new BottomNotification();
|
||||
RootPanel.get().add(bottomNotification);
|
||||
}
|
||||
|
||||
private void initWindBotComponents(List<String> windBotIDs,
|
||||
@@ -122,8 +128,8 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr
|
||||
windBotAddedCounterTOConsiderForPanels++;
|
||||
if (windloadinghintleft.getStyle().getOpacity() != "0.0"
|
||||
|| windloadinghintright.getStyle().getOpacity() != "0.0") {
|
||||
windloadinghintleft.setInnerHTML("Wind bot not available.");
|
||||
windloadinghintright.setInnerHTML("Wind bot not available.");
|
||||
windloadinghintleft.setInnerHTML(stringConstants.dashboardWindBotNotAvailable());
|
||||
windloadinghintright.setInnerHTML(stringConstants.dashboardWindBotNotAvailable());
|
||||
}
|
||||
}
|
||||
addWindBotComponentsAsDataRetrieverListener(windBotDataRetrieverProvider);
|
||||
|
||||
+3
-3
@@ -18,13 +18,13 @@
|
||||
<mgwtcarousel:Carousel ui:field="carousel">
|
||||
<mgwtpanel:Panel styleName="{style.page}">
|
||||
<g:HTMLPanel ui:field="leftwindbotcontainer" styleName="{style.collumn} {style.left}">
|
||||
<div class="{style.windloadinghint}"><div ui:field="windloadinghintleft" class="{style.windloadinghinttext}">Loading Wind Bot Data...</div></div>
|
||||
<div class="{style.windloadinghint}"><div ui:field="windloadinghintleft" class="{style.windloadinghinttext}"></div></div>
|
||||
</g:HTMLPanel>
|
||||
<g:HTMLPanel ui:field="rightwindbotcontainer"
|
||||
styleName="{style.collumn} {style.right}">
|
||||
<div class="{style.windloadinghint}"><div ui:field="windloadinghintright" class="{style.windloadinghinttext}">Loading Wind Bot Data...</div></div>
|
||||
<div class="{style.windloadinghint}"><div ui:field="windloadinghintright" class="{style.windloadinghinttext}"></div></div>
|
||||
</g:HTMLPanel>
|
||||
<g:HTMLPanel styleName="{style.windcharthint}">Tap on chart to change interval.</g:HTMLPanel>
|
||||
<g:HTMLPanel ui:field="windcharthint" styleName="{style.windcharthint}"></g:HTMLPanel>
|
||||
</mgwtpanel:Panel>
|
||||
<mgwtpanel:Panel styleName="{style.page}">
|
||||
<g:HTMLPanel styleName="{style.collumn} {style.startanalysiscollumn}">
|
||||
|
||||
-1
@@ -4,6 +4,5 @@ import com.google.gwt.resources.client.CssResource;
|
||||
|
||||
public interface RibDashboardPanelStyle extends CssResource {
|
||||
String logo();
|
||||
String extremelogo();
|
||||
String start();
|
||||
}
|
||||
+9
-1
@@ -1,9 +1,17 @@
|
||||
package com.sap.sailing.dashboards.gwt.client;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.rpc.RemoteService;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
|
||||
public interface RibDashboardService extends RemoteService {
|
||||
RibDashboardRaceInfoDTO getLiveRaceInfo(String leaderboardName, String competitorName) throws NoWindException;
|
||||
RibDashboardRaceInfoDTO getLiveRaceInfo(String leaderboardName) throws NoWindException;
|
||||
|
||||
List<StartAnalysisDTO> getStartAnalysisListForCompetitorIDAndLeaderboardName(String competitorIdAsString, String leaderboardName);
|
||||
|
||||
List<CompetitorDTO> getCompetitorsInLeaderboard(String leaderboardName);
|
||||
}
|
||||
+9
-1
@@ -1,10 +1,18 @@
|
||||
package com.sap.sailing.dashboards.gwt.client;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
|
||||
public interface RibDashboardServiceAsync {
|
||||
|
||||
void getLiveRaceInfo(String leaderboardName, String competitorName, AsyncCallback<RibDashboardRaceInfoDTO> callback);
|
||||
void getLiveRaceInfo(String leaderboardName, AsyncCallback<RibDashboardRaceInfoDTO> callback);
|
||||
|
||||
void getStartAnalysisListForCompetitorIDAndLeaderboardName(String competitorIdAsString, String leaderboardName, AsyncCallback<List<StartAnalysisDTO>> callback);
|
||||
|
||||
void getCompetitorsInLeaderboard(String leaderboardName, AsyncCallback<List<CompetitorDTO>> callback);
|
||||
|
||||
}
|
||||
+26
-37
@@ -34,17 +34,6 @@
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.extremelogo {
|
||||
position: absolute;
|
||||
left: 100%;
|
||||
top: 100%;
|
||||
width: 90pt;
|
||||
height: 22.5pt;
|
||||
margin-top: -31pt;
|
||||
margin-left: -100pt;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.collumn {
|
||||
position: absolute;
|
||||
top: 5pt;
|
||||
@@ -161,32 +150,6 @@
|
||||
bottom: 0pt;
|
||||
}
|
||||
|
||||
.windloadinghint {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
opacity: 0.4;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.windloadinghinttext {
|
||||
position: absolute;
|
||||
bottom: 0pt;
|
||||
height: 15pt;
|
||||
line-height: 15pt;
|
||||
margin-top: 0pt;
|
||||
vertical-align: middle;
|
||||
font-size: 12pt;
|
||||
font-family: "Arial";
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
top: 50%;
|
||||
margin-top: -7pt;
|
||||
}
|
||||
|
||||
.leaderboardpanel {
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
@@ -329,3 +292,29 @@ windchartcontainer {
|
||||
left: 260%;
|
||||
background-color: #0DBFFF;
|
||||
}
|
||||
|
||||
.windloadinghint {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
opacity: 0.4;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.windloadinghinttext {
|
||||
position: absolute;
|
||||
bottom: 0pt;
|
||||
height: 15pt;
|
||||
line-height: 15pt;
|
||||
margin-top: 0pt;
|
||||
vertical-align: middle;
|
||||
font-size: 12pt;
|
||||
font-family: "Arial";
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
top: 50%;
|
||||
margin-top: -7pt;
|
||||
}
|
||||
+2
-4
@@ -9,16 +9,14 @@ public class GetRibDashboardRaceInfoAction implements AsyncAction<RibDashboardRa
|
||||
|
||||
private final RibDashboardServiceAsync ribDashboardService;
|
||||
private final String leaderboardName;
|
||||
private final String competitorName;
|
||||
|
||||
public GetRibDashboardRaceInfoAction(RibDashboardServiceAsync ribDashboardService, String leaderboardName, String competitorName) {
|
||||
public GetRibDashboardRaceInfoAction(RibDashboardServiceAsync ribDashboardService, String leaderboardName) {
|
||||
this.ribDashboardService = ribDashboardService;
|
||||
this.leaderboardName = leaderboardName;
|
||||
this.competitorName = competitorName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(AsyncCallback<RibDashboardRaceInfoDTO> callback) {
|
||||
ribDashboardService.getLiveRaceInfo(leaderboardName, competitorName, callback);
|
||||
ribDashboardService.getLiveRaceInfo(leaderboardName, callback);
|
||||
}
|
||||
}
|
||||
+5
-9
@@ -39,18 +39,14 @@ public class BottomNotification extends FocusPanel {
|
||||
bottomNotificationClickListeners = new ArrayList<BottomNotificationClickListener>();
|
||||
}
|
||||
|
||||
public void initClickHander() {
|
||||
|
||||
}
|
||||
|
||||
public void show(String message, String backgroundColorAsHex, String textcolorAsHex, boolean dismissAfter20Seconds) {
|
||||
public void show(BottomNotificationType bottomNotificationType) {
|
||||
shown = true;
|
||||
this.removeStyleName("bottomnotificationhidden");
|
||||
this.addStyleName("bottomnotificationshow");
|
||||
this.getElement().setInnerHTML(message);
|
||||
this.getElement().getStyle().setBackgroundColor(backgroundColorAsHex);
|
||||
this.getElement().getStyle().setColor(textcolorAsHex);
|
||||
if (dismissAfter20Seconds) {
|
||||
this.getElement().setInnerHTML(bottomNotificationType.getMessage());
|
||||
this.getElement().getStyle().setBackgroundColor(bottomNotificationType.getBackgroundColorAsHex());
|
||||
this.getElement().getStyle().setColor(bottomNotificationType.getTextColorAsHex());
|
||||
if (bottomNotificationType.isShouldDisappearAfter20Seconds()) {
|
||||
Timer timer = new Timer() {
|
||||
public void run() {
|
||||
hide();
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.bottomnotification;
|
||||
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public enum BottomNotificationType {
|
||||
|
||||
NEW_STARTANALYSIS_AVAILABLE(StringMessages.INSTANCE.dashboardNewStartAnalysisAvailable(), "#F0AB00", "#000000", true);
|
||||
|
||||
private String message;
|
||||
private String backgroundColorAsHex;
|
||||
private String textColorAsHex;
|
||||
private boolean shouldDisappearAfter20Seconds;
|
||||
|
||||
private BottomNotificationType(String message, String backgroundColorAsHex, String textColorAsHex, boolean shouldDisappearAfter20Seconds) {
|
||||
this.message = message;
|
||||
this.backgroundColorAsHex = backgroundColorAsHex;
|
||||
this.textColorAsHex = textColorAsHex;
|
||||
this.shouldDisappearAfter20Seconds = shouldDisappearAfter20Seconds;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getBackgroundColorAsHex() {
|
||||
return backgroundColorAsHex;
|
||||
}
|
||||
|
||||
public String getTextColorAsHex() {
|
||||
return textColorAsHex;
|
||||
}
|
||||
|
||||
public boolean isShouldDisappearAfter20Seconds() {
|
||||
return shouldDisappearAfter20Seconds;
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.popups.competitorselection;
|
||||
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
|
||||
public interface CompetitorSelectionListener {
|
||||
|
||||
public void didClickOKWithSelectedCompetitor(CompetitorDTO competitor);
|
||||
}
|
||||
+16
-18
@@ -17,6 +17,7 @@ import com.google.gwt.user.client.ui.HasWidgets;
|
||||
import com.google.gwt.user.client.ui.RootLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.RootPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
|
||||
public class CompetitorSelectionPopup extends Composite implements HasWidgets, CompetitorTableRowSelectionListener {
|
||||
|
||||
@@ -44,10 +45,10 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
|
||||
@UiField
|
||||
Button button;
|
||||
|
||||
private String currentCompetitorSelected;
|
||||
private CompetitorDTO currentCompetitorSelected;
|
||||
private boolean isVisible;
|
||||
|
||||
private List<CompetitorSelectionPopupListener> competitorSelectionPopupListener;
|
||||
private List<CompetitorSelectionListener> competitorSelectionPopupListener;
|
||||
|
||||
private static CompetitorSelectionPopupUiBinder uiBinder = GWT.create(CompetitorSelectionPopupUiBinder.class);
|
||||
|
||||
@@ -55,17 +56,14 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
|
||||
}
|
||||
|
||||
public CompetitorSelectionPopup() {
|
||||
competitorSelectionPopupListener = new ArrayList<CompetitorSelectionPopupListener>();
|
||||
competitorSelectionPopupListener = new ArrayList<CompetitorSelectionListener>();
|
||||
competitortable = new CompetitorTable(this);
|
||||
isVisible = false;
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
}
|
||||
|
||||
public void setCompetitorList(List<String> competitorList){
|
||||
public void show(List<CompetitorDTO> competitorList) {
|
||||
competitortable.setTableContent(competitorList);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
RootPanel.get().add(this);
|
||||
this.button.setText("OK");
|
||||
this.getElement().addClassName(style.popupshow());
|
||||
@@ -84,19 +82,19 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
|
||||
isVisible = false;
|
||||
}
|
||||
|
||||
public void addListener(CompetitorSelectionPopupListener o) {
|
||||
public void addListener(CompetitorSelectionListener o) {
|
||||
if (o != null && !competitorSelectionPopupListener.contains(o)) {
|
||||
this.competitorSelectionPopupListener.add(o);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(CompetitorSelectionPopupListener o) {
|
||||
public void removeListener(CompetitorSelectionListener o) {
|
||||
this.competitorSelectionPopupListener.remove(o);
|
||||
}
|
||||
|
||||
public void notifyListenerAboutOKButtonClickedWithSelectedCompetitorName(String competitorName) {
|
||||
for (CompetitorSelectionPopupListener newStartAnalysisListener : competitorSelectionPopupListener) {
|
||||
newStartAnalysisListener.didClickedOKWithCompetitorName(competitorName);
|
||||
public void notifyListenerAboutOKButtonClickedWithSelectedCompetitorName(CompetitorDTO competitor) {
|
||||
for (CompetitorSelectionListener newStartAnalysisListener : competitorSelectionPopupListener) {
|
||||
newStartAnalysisListener.didClickOKWithSelectedCompetitor(competitor);
|
||||
}
|
||||
hide();
|
||||
}
|
||||
@@ -113,6 +111,12 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didSelectedRowWithCompetitorName(CompetitorDTO competitor) {
|
||||
button.getElement().addClassName(style.buttonshow());
|
||||
currentCompetitorSelected = competitor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void add(Widget w) {
|
||||
@@ -133,10 +137,4 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
|
||||
public boolean remove(Widget w) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didSelectedRowWithCompetitorName(String competitorName) {
|
||||
button.getElement().addClassName(style.buttonshow());
|
||||
currentCompetitorSelected = competitorName;
|
||||
}
|
||||
}
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.popups.competitorselection;
|
||||
|
||||
public interface CompetitorSelectionPopupListener {
|
||||
|
||||
public void didClickedOKWithCompetitorName(String competitorName);
|
||||
}
|
||||
+10
-9
@@ -10,45 +10,46 @@ import com.google.gwt.user.cellview.client.TextColumn;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.google.gwt.view.client.SingleSelectionModel;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
|
||||
public class CompetitorTable extends AbsolutePanel {
|
||||
|
||||
private CellTable<String> table;
|
||||
private CellTable<CompetitorDTO> table;
|
||||
private CompetitorTableRowSelectionListener competitorTableRowSelectionListener;
|
||||
|
||||
public CompetitorTable(CompetitorTableRowSelectionListener competitorTableRowSelectionListener) {
|
||||
this.competitorTableRowSelectionListener = competitorTableRowSelectionListener;
|
||||
}
|
||||
|
||||
public void setTableContent(List<String> competitorNames) {
|
||||
public void setTableContent(List<CompetitorDTO> competitorNames) {
|
||||
if (table == null) {
|
||||
initTable(competitorNames);
|
||||
}
|
||||
}
|
||||
|
||||
private void initTable(List<String> competitorNames) {
|
||||
private void initTable(List<CompetitorDTO> competitorNames) {
|
||||
CellTable.Resources tableRes = GWT.create(CompetitorTableStyleResource.class);
|
||||
|
||||
table = new CellTable<String>(15, tableRes);
|
||||
table = new CellTable<CompetitorDTO>(15, tableRes);
|
||||
table.getElement().getStyle().setWidth(100, Unit.PCT);
|
||||
table.setSkipRowHoverStyleUpdate(true);
|
||||
table.setSkipRowHoverCheck(true);
|
||||
table.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.DISABLED);
|
||||
final SingleSelectionModel<String> selectionModel = new SingleSelectionModel<String>();
|
||||
final SingleSelectionModel<CompetitorDTO> selectionModel = new SingleSelectionModel<CompetitorDTO>();
|
||||
table.setSelectionModel(selectionModel);
|
||||
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
String selected = selectionModel.getSelectedObject();
|
||||
CompetitorDTO selected = selectionModel.getSelectedObject();
|
||||
if (selected != null) {
|
||||
competitorTableRowSelectionListener.didSelectedRowWithCompetitorName(selected);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
TextColumn<String> competitorNameCollumn = new TextColumn<String>() {
|
||||
TextColumn<CompetitorDTO> competitorNameCollumn = new TextColumn<CompetitorDTO>() {
|
||||
@Override
|
||||
public String getValue(String competitorName) {
|
||||
return competitorName;
|
||||
public String getValue(CompetitorDTO competitor) {
|
||||
return competitor.getName();
|
||||
}
|
||||
};
|
||||
table.addColumn(competitorNameCollumn, "");
|
||||
|
||||
+3
-1
@@ -1,6 +1,8 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.popups.competitorselection;
|
||||
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
|
||||
public interface CompetitorTableRowSelectionListener {
|
||||
|
||||
public void didSelectedRowWithCompetitorName(String competitorName);
|
||||
public void didSelectedRowWithCompetitorName(CompetitorDTO competitor);
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
@CHARSET "UTF-8";
|
||||
|
||||
.settings_button {
|
||||
position: absolute !important;
|
||||
height: 23.5pt;
|
||||
width: 23.5pt;
|
||||
right: 10pt;
|
||||
top: 17.5pt;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.settings_button_image {
|
||||
position: absolute;
|
||||
height: 23.5pt;
|
||||
width: 23.5pt;
|
||||
right: 10pt;
|
||||
top: 17.5pt;
|
||||
}
|
||||
|
||||
.settings_indication_label {
|
||||
position: absolute;
|
||||
width: 200pt;
|
||||
height: 23.5pt;
|
||||
margin-top: 17.5pt;
|
||||
right: 43.5pt;
|
||||
font-size: 12pt;
|
||||
font-color: black;
|
||||
text-align: right;
|
||||
line-height: 23.5pt;
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.popups.competitorselection;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
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;
|
||||
import com.google.gwt.user.client.ui.FocusPanel;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.dashboards.gwt.client.RibDashboardImageResources;
|
||||
|
||||
public class SettingsButtonWithSelectionIndicationLabel extends Composite {
|
||||
|
||||
private static SettingsButtonWithSelectionIndicationLabelUiBinder uiBinder = GWT
|
||||
.create(SettingsButtonWithSelectionIndicationLabelUiBinder.class);
|
||||
|
||||
interface SettingsButtonWithSelectionIndicationLabelUiBinder extends
|
||||
UiBinder<Widget, SettingsButtonWithSelectionIndicationLabel> {
|
||||
}
|
||||
|
||||
interface SettingsButtonWithSelectionIndicationLabelStyle extends CssResource {
|
||||
}
|
||||
|
||||
@UiField
|
||||
SettingsButtonWithSelectionIndicationLabelStyle style;
|
||||
|
||||
@UiField
|
||||
FocusPanel settingsButton;
|
||||
|
||||
@UiField
|
||||
Image settingsButtonImage;
|
||||
|
||||
@UiField
|
||||
Label settingsIndicationLabel;
|
||||
|
||||
public SettingsButtonWithSelectionIndicationLabel() {
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
settingsButtonImage.setResource(RibDashboardImageResources.INSTANCE.settings());
|
||||
}
|
||||
|
||||
public void addClickHandlerToSettingsButton(ClickHandler clickHandler){
|
||||
settingsButton.addClickHandler(clickHandler);
|
||||
}
|
||||
|
||||
public void setSelectionIndicationTextOnLabel(String selectionIndicationText) {
|
||||
settingsIndicationLabel.setText(selectionIndicationText);
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
|
||||
xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
||||
<ui:style
|
||||
type='com.sap.sailing.dashboards.gwt.client.popups.competitorselection.SettingsButtonWithSelectionIndicationLabel.SettingsButtonWithSelectionIndicationLabelStyle'
|
||||
src='SettingsButtonWithSelectionIndicationLabel.css'></ui:style>
|
||||
<g:HTMLPanel>
|
||||
<g:FocusPanel ui:field="settingsButton" styleName="{style.settings_button}"></g:FocusPanel>
|
||||
<g:Image ui:field="settingsButtonImage" styleName="{style.settings_button_image}"></g:Image>
|
||||
<g:Label ui:field="settingsIndicationLabel" styleName="{style.settings_indication_label}"></g:Label>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.startanalysis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
|
||||
/**
|
||||
* classes implementing this interface get usually notified, if there is a new {@link StartAnalysisDTO}
|
||||
* in {@link RibDashboardRaceInfoDTO} variable <code>startAnalysisDTOList</code>.
|
||||
*
|
||||
* @author Alexander Ries (D062114)
|
||||
*
|
||||
*/
|
||||
public interface NewStartAnalysisListener {
|
||||
|
||||
public void addNewStartAnalysisCardForCompetitor(List<StartAnalysisDTO> startAnalysisDTOs, String selectedCompetitor);
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
@CHARSET "UTF-8";
|
||||
|
||||
.combinedWindPanel {
|
||||
margin-top: 10pt;
|
||||
margin-left: 10pt;
|
||||
right: 0pt;
|
||||
width: 45pt;
|
||||
height: 45pt;
|
||||
border-radius: 22.5pt;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.combinedWindPanelTextLabel {
|
||||
margin-top: 15pt;
|
||||
width: 45pt;
|
||||
height: 25pt;
|
||||
background-color: white;
|
||||
line-height: 25pt;
|
||||
vertical-align: middle;
|
||||
font-size: 11pt;
|
||||
font-family: "Arial";
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.combinedWindPanelCanvas{
|
||||
width: 35pt;
|
||||
height: 35pt;
|
||||
margin-top: 5pt;
|
||||
margin-left: 5pt;
|
||||
}
|
||||
+3
-1
@@ -1,7 +1,9 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.startanalysis;
|
||||
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
|
||||
public interface StartAnalysisPageChangeListener {
|
||||
|
||||
public void loadMapAndContent(int newPageIndex, String someDataDTO);
|
||||
public void startAnalysisComponentPageChangedToIndexAndStartAnalysis(int newPageIndex, StartAnalysisDTO startAnalysisDTO);
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.startanalysis;
|
||||
|
||||
import com.google.gwt.resources.client.ClientBundle;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.CombinedWindPanelStyle;
|
||||
|
||||
interface StartAnalysisResources extends ClientBundle {
|
||||
|
||||
@Source("com/sap/sailing/dashboards/gwt/client/images/windarrow.png")
|
||||
ImageResource combinedWindIcon();
|
||||
|
||||
@Source("StartAnalysisCombinedWindPanel.css")
|
||||
CombinedWindPanelStyle combinedWindPanelStyle();
|
||||
}
|
||||
-326
@@ -1,326 +0,0 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.startanalysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.dom.client.Style.Position;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.maps.client.LoadApi;
|
||||
import com.google.gwt.maps.client.LoadApi.LoadLibrary;
|
||||
import com.google.gwt.maps.client.MapOptions;
|
||||
import com.google.gwt.maps.client.MapWidget;
|
||||
import com.google.gwt.maps.client.base.LatLng;
|
||||
import com.google.gwt.maps.client.base.LatLngBounds;
|
||||
import com.google.gwt.maps.client.controls.ControlPosition;
|
||||
import com.google.gwt.maps.client.controls.MapTypeStyle;
|
||||
import com.google.gwt.maps.client.controls.ScaleControlOptions;
|
||||
import com.google.gwt.maps.client.maptypes.MapTypeStyleFeatureType;
|
||||
import com.google.gwt.maps.client.mvc.MVCArray;
|
||||
import com.google.gwt.maps.client.overlays.Polyline;
|
||||
import com.google.gwt.maps.client.overlays.PolylineOptions;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisCompetitorDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.BoatOverlay;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.CourseMarkOverlay;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapOverlaysZIndexes;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.TailFactory;
|
||||
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.MarkDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.GoogleMapStyleHelper;
|
||||
import com.sap.sse.common.impl.RGBColor;
|
||||
|
||||
public class StartAnalysisSimpleMap extends AbsolutePanel implements TailFactory {
|
||||
|
||||
private MapWidget map;
|
||||
private StartAnalysisDTO startAnalysisDTO;
|
||||
|
||||
public StartAnalysisSimpleMap(int containerID, StartAnalysisDTO startAnalysisDTO) {
|
||||
|
||||
this.startAnalysisDTO = startAnalysisDTO;
|
||||
|
||||
this.getElement().getStyle().setPosition(Position.ABSOLUTE);
|
||||
this.getElement().getStyle().setWidth(100, Unit.PCT);
|
||||
this.getElement().getStyle().setHeight(100, Unit.PCT);
|
||||
loadMapsAPIV3();
|
||||
}
|
||||
|
||||
private void loadMapsAPIV3() {
|
||||
boolean sensor = true;
|
||||
// load all the libs for use in the maps
|
||||
ArrayList<LoadLibrary> loadLibraries = new ArrayList<LoadApi.LoadLibrary>();
|
||||
loadLibraries.add(LoadLibrary.DRAWING);
|
||||
loadLibraries.add(LoadLibrary.GEOMETRY);
|
||||
|
||||
Runnable onLoad = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MapOptions mapOptions = MapOptions.newInstance();
|
||||
mapOptions.setScrollWheel(true);
|
||||
mapOptions.setMapTypeControl(false);
|
||||
mapOptions.setPanControl(false);
|
||||
mapOptions.setZoomControl(false);
|
||||
mapOptions.setScaleControl(true);
|
||||
mapOptions.setDraggable(false);
|
||||
mapOptions.setPanControl(false);
|
||||
MapTypeStyle[] mapTypeStyles = new MapTypeStyle[4];
|
||||
|
||||
// hide all transit lines including ferry lines
|
||||
mapTypeStyles[0] = GoogleMapStyleHelper.createHiddenStyle(MapTypeStyleFeatureType.TRANSIT);
|
||||
// hide points of interest
|
||||
mapTypeStyles[1] = GoogleMapStyleHelper.createHiddenStyle(MapTypeStyleFeatureType.POI);
|
||||
// simplify road display
|
||||
mapTypeStyles[2] = GoogleMapStyleHelper.createSimplifiedStyle(MapTypeStyleFeatureType.ROAD);
|
||||
// set water color
|
||||
mapTypeStyles[3] = GoogleMapStyleHelper.createColorStyle(MapTypeStyleFeatureType.WATER, new RGBColor(0,
|
||||
136, 255), -35, -34);
|
||||
|
||||
mapOptions.setMapTypeStyles(mapTypeStyles);
|
||||
ScaleControlOptions scaleControlOptions = ScaleControlOptions.newInstance();
|
||||
scaleControlOptions.setPosition(ControlPosition.BOTTOM_RIGHT);
|
||||
mapOptions.setScaleControlOptions(scaleControlOptions);
|
||||
mapOptions.setStreetViewControl(false);
|
||||
map = new MapWidget(mapOptions);
|
||||
StartAnalysisSimpleMap.this.add(map, 0, 0);
|
||||
map.setSize("100%", "100%");
|
||||
map.getElement().getStyle().setBackgroundColor("#4293DB");
|
||||
map.triggerResize();
|
||||
drawStartLine(startAnalysisDTO.startLineMarks);
|
||||
drawLinesFromStartLineToFirstMark(startAnalysisDTO.startLineMarks, startAnalysisDTO.firstMark);
|
||||
drawStartlineMarks(startAnalysisDTO.startLineMarks);
|
||||
drawFirstMark(startAnalysisDTO.firstMark);
|
||||
drawTails(createGPSFixesForCompetitors(startAnalysisDTO));
|
||||
drawBoats(createGPSPositionForCompetitors(startAnalysisDTO));
|
||||
zoomMapToNewBounds(calculateNewBounds(startAnalysisDTO.startLineMarkPositions));
|
||||
}
|
||||
};
|
||||
LoadApi.go(onLoad, loadLibraries, sensor);
|
||||
}
|
||||
|
||||
private Map<CompetitorDTO, List<GPSFixDTO>> createGPSFixesForCompetitors(StartAnalysisDTO startAnalysisDTO) {
|
||||
|
||||
Map<CompetitorDTO, List<GPSFixDTO>> gpsFixesForCompetitors = new HashMap<CompetitorDTO, List<GPSFixDTO>>();
|
||||
for (StartAnalysisCompetitorDTO startAnalysisCompetitorDTO : startAnalysisDTO.startAnalysisCompetitorDTOs) {
|
||||
gpsFixesForCompetitors.put(startAnalysisCompetitorDTO.competitorDTO,
|
||||
startAnalysisCompetitorDTO.gpsFixDTOs);
|
||||
}
|
||||
return gpsFixesForCompetitors;
|
||||
}
|
||||
|
||||
private Map<CompetitorDTO, GPSFixDTO> createGPSPositionForCompetitors(StartAnalysisDTO startAnalysisDTO) {
|
||||
Map<CompetitorDTO, GPSFixDTO> gpsPositionForCompetitors = new HashMap<CompetitorDTO, GPSFixDTO>();
|
||||
for (StartAnalysisCompetitorDTO startAnalysisCompetitorDTO : startAnalysisDTO.startAnalysisCompetitorDTOs) {
|
||||
gpsPositionForCompetitors.put(startAnalysisCompetitorDTO.competitorDTO,
|
||||
startAnalysisCompetitorDTO.gpsFixDTOs.get(startAnalysisCompetitorDTO.gpsFixDTOs.size()-1));
|
||||
}
|
||||
return gpsPositionForCompetitors;
|
||||
}
|
||||
|
||||
private void drawStartLine(List<MarkDTO> startlineMarks) {
|
||||
if (map != null && startlineMarks != null) {
|
||||
|
||||
if (startlineMarks.size() == 2) {
|
||||
LatLng startLinePoint1 = LatLng.newInstance(startlineMarks.get(0).position.latDeg,
|
||||
startlineMarks.get(0).position.lngDeg);
|
||||
LatLng startLinePoint2 = LatLng.newInstance(startlineMarks.get(1).position.latDeg,
|
||||
startlineMarks.get(1).position.lngDeg);
|
||||
|
||||
PolylineOptions options = PolylineOptions.newInstance();
|
||||
options.setGeodesic(true);
|
||||
options.setStrokeColor("#FFFFFF");
|
||||
options.setStrokeWeight(2);
|
||||
options.setStrokeOpacity(1.0);
|
||||
|
||||
MVCArray<LatLng> pointsAsArray = MVCArray.newInstance();
|
||||
pointsAsArray.insertAt(0, startLinePoint1);
|
||||
pointsAsArray.insertAt(1, startLinePoint2);
|
||||
|
||||
Polyline startLine = Polyline.newInstance(options);
|
||||
startLine.setPath(pointsAsArray);
|
||||
|
||||
startLine.setMap(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawLinesFromStartLineToFirstMark(List<MarkDTO> startlineMarks, MarkDTO firstMark){
|
||||
if (map != null && startlineMarks != null && firstMark != null) {
|
||||
if (startlineMarks.size() == 2) {
|
||||
LatLng startLinePoint1 = LatLng.newInstance(startlineMarks.get(0).position.latDeg,
|
||||
startlineMarks.get(0).position.lngDeg);
|
||||
LatLng startLinePoint2 = LatLng.newInstance(startlineMarks.get(1).position.latDeg,
|
||||
startlineMarks.get(1).position.lngDeg);
|
||||
LatLng firstMarkPoint = LatLng.newInstance(firstMark.position.latDeg,
|
||||
firstMark.position.lngDeg);
|
||||
|
||||
PolylineOptions options = PolylineOptions.newInstance();
|
||||
options.setGeodesic(true);
|
||||
options.setStrokeColor("#A3A3A3");
|
||||
options.setStrokeWeight(2);
|
||||
options.setStrokeOpacity(1.0);
|
||||
|
||||
MVCArray<LatLng> pointsAsArray1 = MVCArray.newInstance();
|
||||
pointsAsArray1.insertAt(0, startLinePoint1);
|
||||
pointsAsArray1.insertAt(1, firstMarkPoint);
|
||||
|
||||
MVCArray<LatLng> pointsAsArray2 = MVCArray.newInstance();
|
||||
pointsAsArray2.insertAt(0, startLinePoint2);
|
||||
pointsAsArray2.insertAt(1, firstMarkPoint);
|
||||
|
||||
Polyline startMarkFirstMark1 = Polyline.newInstance(options);
|
||||
Polyline startMarkFirstMark2 = Polyline.newInstance(options);
|
||||
|
||||
startMarkFirstMark1.setPath(pointsAsArray1);
|
||||
startMarkFirstMark2.setPath(pointsAsArray2);
|
||||
|
||||
startMarkFirstMark1.setMap(map);
|
||||
startMarkFirstMark2.setMap(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawStartlineMarks(List<MarkDTO> startlineMarks) {
|
||||
if (map != null) {
|
||||
for (MarkDTO markDTO : startlineMarks) {
|
||||
CourseMarkOverlay courseMarkOverlay = createCourseMarkOverlay(
|
||||
RaceMapOverlaysZIndexes.COURSEMARK_ZINDEX, markDTO);
|
||||
courseMarkOverlay.addToMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawFirstMark(MarkDTO firstMark){
|
||||
CourseMarkOverlay courseMarkOverlay = createCourseMarkOverlay(
|
||||
RaceMapOverlaysZIndexes.COURSEMARK_ZINDEX, firstMark);
|
||||
courseMarkOverlay.addToMap();
|
||||
}
|
||||
|
||||
private CourseMarkOverlay createCourseMarkOverlay(int zIndex, final MarkDTO markDTO) {
|
||||
markDTO.position.latDeg = markDTO.position.latDeg;
|
||||
final CourseMarkOverlay courseMarkOverlay = new CourseMarkOverlay(map, zIndex, markDTO);
|
||||
return courseMarkOverlay;
|
||||
}
|
||||
|
||||
private LatLngBounds calculateNewBounds(List<PositionDTO> startLinePositions) {
|
||||
LatLngBounds newBounds = null;
|
||||
List<PositionDTO> newStartLinePositionDTOs = new ArrayList<PositionDTO>(startLinePositions);
|
||||
Iterable<PositionDTO> positionsToZoom = newStartLinePositionDTOs;
|
||||
|
||||
if (positionsToZoom != null) {
|
||||
for (PositionDTO position : positionsToZoom) {
|
||||
PositionDTO positionMoovedToNorth = position;
|
||||
positionMoovedToNorth.latDeg = positionMoovedToNorth.latDeg - 0.0009;
|
||||
|
||||
LatLng markLatLng = LatLng.newInstance(positionMoovedToNorth.latDeg, positionMoovedToNorth.lngDeg);
|
||||
LatLngBounds bounds = LatLngBounds.newInstance(markLatLng, markLatLng);
|
||||
if (newBounds == null) {
|
||||
newBounds = bounds;
|
||||
} else {
|
||||
newBounds.extend(markLatLng);
|
||||
}
|
||||
markLatLng = null;
|
||||
position = null;
|
||||
positionMoovedToNorth.latDeg = positionMoovedToNorth.latDeg + 0.0009;
|
||||
}
|
||||
}
|
||||
// }
|
||||
positionsToZoom = null;
|
||||
return newBounds;
|
||||
}
|
||||
|
||||
private void zoomMapToNewBounds(LatLngBounds newBounds) {
|
||||
if (newBounds != null) {
|
||||
map.setCenter(newBounds.getCenter());
|
||||
map.setZoom(17);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawBoats(Map<CompetitorDTO, GPSFixDTO> competitorAndLastFix) {
|
||||
|
||||
Set<CompetitorDTO> competitors = competitorAndLastFix.keySet();
|
||||
|
||||
for (CompetitorDTO competitorDTO : competitors) {
|
||||
BoatOverlay boatOverlay = createBoatOverlay(RaceMapOverlaysZIndexes.BOATS_ZINDEX, competitorDTO, false);
|
||||
boatOverlay.setSelected(false);
|
||||
boatOverlay.setBoatFix(competitorAndLastFix.get(competitorDTO), 10);
|
||||
boatOverlay.addToMap();
|
||||
}
|
||||
}
|
||||
|
||||
private BoatOverlay createBoatOverlay(int zIndex, final CompetitorDTO competitorDTO, boolean highlighted) {
|
||||
final BoatOverlay boatCanvas = new BoatOverlay(map, zIndex, competitorDTO, competitorDTO.getColor());
|
||||
boatCanvas.setSelected(false);
|
||||
return boatCanvas;
|
||||
}
|
||||
|
||||
private void drawTails(Map<CompetitorDTO, List<GPSFixDTO>> competitorFixes) {
|
||||
|
||||
Set<CompetitorDTO> competitors = competitorFixes.keySet();
|
||||
for (CompetitorDTO competitor : competitors) {
|
||||
Polyline competitorPolyline = createPolylineFromGPSFixDTOs(competitor, competitorFixes.get(competitor));
|
||||
competitorPolyline.setMap(map);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Polyline createPolylineFromGPSFixDTOs(CompetitorDTO competitorDTO, List<GPSFixDTO> fixes) {
|
||||
List<LatLng> points = new ArrayList<LatLng>();
|
||||
int indexOfFirst = -1;
|
||||
int indexOfLast = -1;
|
||||
int i = 0;
|
||||
for (Iterator<GPSFixDTO> fixIter = fixes.iterator(); fixIter.hasNext() && indexOfLast == -1;) {
|
||||
GPSFixDTO fix = fixIter.next();
|
||||
if (!fix.timepoint.before(fixes.get(fixes.size() - 1).timepoint)) {
|
||||
indexOfLast = i - 1;
|
||||
} else {
|
||||
LatLng point = null;
|
||||
if (indexOfFirst == -1) {
|
||||
if (!fix.timepoint.before(fixes.get(0).timepoint)) {
|
||||
indexOfFirst = i;
|
||||
point = LatLng.newInstance(fix.position.latDeg, fix.position.lngDeg);
|
||||
}
|
||||
} else {
|
||||
point = LatLng.newInstance(fix.position.latDeg, fix.position.lngDeg);
|
||||
}
|
||||
if (point != null) {
|
||||
points.add(point);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (indexOfLast == -1) {
|
||||
indexOfLast = i - 1;
|
||||
}
|
||||
Polyline result = createTail(competitorDTO, points);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Polyline createTail(CompetitorDTO competitor, List<LatLng> points) {
|
||||
PolylineOptions options = createTailStyle(competitor, false);
|
||||
Polyline result = Polyline.newInstance(options);
|
||||
|
||||
MVCArray<LatLng> pointsAsArray = MVCArray.newInstance(points.toArray(new LatLng[0]));
|
||||
result.setPath(pointsAsArray);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolylineOptions createTailStyle(CompetitorDTO competitor, boolean isHighlighted) {
|
||||
PolylineOptions options = PolylineOptions.newInstance();
|
||||
options.setClickable(true);
|
||||
options.setGeodesic(true);
|
||||
options.setStrokeOpacity(1.0);
|
||||
options.setStrokeColor(competitor.getColor().getAsHtml());
|
||||
options.setStrokeWeight(1);
|
||||
options.setZindex(RaceMapOverlaysZIndexes.BOATTAILS_ZINDEX);
|
||||
return options;
|
||||
}
|
||||
}
|
||||
+3
-42
@@ -56,19 +56,12 @@
|
||||
display: inline;
|
||||
width: 80%;
|
||||
height: 100%;
|
||||
background-color: #4293DB;
|
||||
margin-top: 1px; /*Zeigt sonst Linie am oberen Rand*/
|
||||
/*#4293DB old water color*/
|
||||
background-color: #004384;
|
||||
margin-top: 1px; /*Shows otherwise small line at top edge*/
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.startanalysis_google_map {
|
||||
position: absolute;
|
||||
bottom: -20pt;
|
||||
right: -20pt;
|
||||
left: -20pt;
|
||||
top: -20pt;
|
||||
}
|
||||
|
||||
.startanalysis_card_table {
|
||||
position: absolute;
|
||||
bottom: 10pt;
|
||||
@@ -87,30 +80,6 @@
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.startanalysis_card_wind_direction_image {
|
||||
position: absolute;
|
||||
top: 0pt;
|
||||
right: 0pt;
|
||||
width: 45pt;
|
||||
height: 45pt;
|
||||
border-radius: 22.5pt;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.startanalysis_card_wind_arrow {
|
||||
width: 25pt;
|
||||
height: 25pt;
|
||||
margin-top: 10pt;
|
||||
margin-left: 10pt;
|
||||
}
|
||||
|
||||
.startanalysis_card_wind_canvas {
|
||||
width: 25pt;
|
||||
height: 25pt;
|
||||
margin-top: 10pt;
|
||||
margin-left: 10pt;
|
||||
}
|
||||
|
||||
.startanalysis_card_data {
|
||||
position: absolute;
|
||||
right: 0pt;
|
||||
@@ -124,14 +93,6 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.startanalysis_card_wind_data_direction {
|
||||
top: 55pt;
|
||||
}
|
||||
|
||||
.startanalysis_card_wind_data_speed {
|
||||
top: 85pt;
|
||||
}
|
||||
|
||||
.startanalysis_card_line_advantage {
|
||||
top: 0pt;
|
||||
left: 55pt;
|
||||
|
||||
+115
-72
@@ -1,37 +1,45 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.startanalysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.gwt.canvas.client.Canvas;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||
import com.google.gwt.dom.client.DivElement;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.i18n.client.NumberFormat;
|
||||
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.Timer;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.HasWidgets;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.dashboards.gwt.client.RibDashboardImageResources;
|
||||
import com.sap.sailing.dashboards.gwt.client.startanalysis.rankingtable.StartAnalysisStartRankTable;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings.HelpLineTypes;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings.ZoomTypes;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.player.Timer.PlayModes;
|
||||
|
||||
public class StartlineAnalysisCard extends Composite implements HasWidgets, StartAnalysisPageChangeListener {
|
||||
|
||||
private StartAnalysisSimpleMap simpleMap;
|
||||
|
||||
private static StartlineAnalysisCardUiBinder uiBinder = GWT.create(StartlineAnalysisCardUiBinder.class);
|
||||
|
||||
interface StartlineAnalysisCardUiBinder extends UiBinder<Widget, StartlineAnalysisCard> {
|
||||
}
|
||||
|
||||
interface StartlineAnalysis extends CssResource {
|
||||
public String startanalysis_card_wind_canvas();
|
||||
public String startanalysis_card_wind_arrow();
|
||||
}
|
||||
|
||||
@UiField
|
||||
@@ -40,100 +48,135 @@ public class StartlineAnalysisCard extends Composite implements HasWidgets, Star
|
||||
@UiField
|
||||
HTMLPanel startanalysis_card;
|
||||
|
||||
@UiField
|
||||
HTMLPanel winddirection;
|
||||
|
||||
@UiField
|
||||
HTMLPanel startanalysis_card_table;
|
||||
|
||||
@UiField
|
||||
DivElement startanalysis_card_wind_data_direction;
|
||||
|
||||
@UiField
|
||||
DivElement startanalysis_card_wind_data_speed;
|
||||
|
||||
@UiField
|
||||
DivElement startanalysis_card_line_advantage;
|
||||
|
||||
Canvas winddirectionContainer;
|
||||
Image windarrow;
|
||||
|
||||
private int cardid;
|
||||
private boolean containsMap = false;
|
||||
private StartAnalysisDTO startAnalysisDTO;
|
||||
private RaceMap raceMap;
|
||||
|
||||
public StartlineAnalysisCard(double leftCSSProperty, int cardID, StartAnalysisDTO startAnalysisDTO) {
|
||||
private SailingServiceAsync sailingServiceAsync;
|
||||
private StringMessages stringMessages;
|
||||
private final CompetitorSelectionModel competitorSelectionModel;
|
||||
|
||||
private final double WIND_LINE_ADVANTAGE_DIV_WIDTH_IN_PT = 185;
|
||||
private final double GEOMETRIC_LINE_ADVANTAGE_DIV_WIDTH_IN_PT = 210;
|
||||
private final int TAIL_LENGHT_IN_MILLISECONDS = 900000;
|
||||
|
||||
|
||||
private static StartAnalysisResources resources = GWT.create(StartAnalysisResources.class);
|
||||
public StartlineAnalysisCard(double leftCSSProperty, int cardId, StartAnalysisDTO startAnalysisDTO,
|
||||
SailingServiceAsync sailingServiceAsync) {
|
||||
stringMessages = StringMessages.INSTANCE;
|
||||
resources.combinedWindPanelStyle().ensureInjected();
|
||||
this.sailingServiceAsync = sailingServiceAsync;
|
||||
competitorSelectionModel = new CompetitorSelectionModel(/* hasMultiSelection */true);
|
||||
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
startanalysis_card.getElement().getStyle().setLeft(leftCSSProperty, Unit.PCT);
|
||||
|
||||
winddirectionContainer = Canvas.createIfSupported();
|
||||
this.startAnalysisDTO = startAnalysisDTO;
|
||||
|
||||
winddirectionContainer.setStyleName(style.startanalysis_card_wind_canvas());
|
||||
|
||||
windarrow = new Image();
|
||||
windarrow.setResource(RibDashboardImageResources.INSTANCE.windarrow());
|
||||
windarrow.setStyleName(style.startanalysis_card_wind_arrow());
|
||||
winddirection.add(windarrow);
|
||||
|
||||
cardid = cardID;
|
||||
|
||||
if (cardID == 0) {
|
||||
addMap(cardID);
|
||||
}
|
||||
|
||||
this.cardid = cardId;
|
||||
startanalysis_card_table.add(new StartAnalysisStartRankTable(startAnalysisDTO.startAnalysisCompetitorDTOs));
|
||||
fillWindAndStartLineData(this.startAnalysisDTO);
|
||||
|
||||
this.onLoad();
|
||||
}
|
||||
|
||||
private void fillWindAndStartLineData(StartAnalysisDTO startAnalysisDTO) {
|
||||
|
||||
if (startAnalysisDTO.startAnalysisWindLineInfoDTO != null) {
|
||||
String winddirectionformatted = NumberFormat.getFormat("#0").format(
|
||||
startAnalysisDTO.startAnalysisWindLineInfoDTO.windDirectionInDegrees-90);
|
||||
windarrow.getElement().getStyle()
|
||||
.setProperty("transform", "rotate(" + winddirectionformatted + "deg)");
|
||||
windarrow.getElement().getStyle().setProperty("webkitTransform", "rotate(" + winddirectionformatted + "deg)");
|
||||
startanalysis_card_wind_data_direction
|
||||
.setInnerHTML(NumberFormat.getFormat("#0.0").format(startAnalysisDTO.startAnalysisWindLineInfoDTO.windDirectionInDegrees) + "°");
|
||||
startanalysis_card_wind_data_speed
|
||||
.setInnerHTML(NumberFormat.getFormat("#0.0").format(startAnalysisDTO.startAnalysisWindLineInfoDTO.windSpeedInKnots) + " kts");
|
||||
startanalysis_card_line_advantage.setInnerHTML(startAnalysisDTO.startAnalysisWindLineInfoDTO.startLineAdvantage.startLineAdvatageType.getDisplayName()+": "+NumberFormat.getFormat("#0.0").format(startAnalysisDTO.startAnalysisWindLineInfoDTO.startLineAdvantage.startLineAdvantage)+" m");
|
||||
setLineAdvantageDivWidth(startAnalysisDTO.startAnalysisWindLineInfoDTO.startLineAdvantage.startLineAdvatageType);
|
||||
String startLineAdvantageType;
|
||||
if (startAnalysisDTO.startAnalysisWindLineInfoDTO.startLineAdvantage.startLineAdvatageType
|
||||
.equals(StartlineAdvantageType.GEOMETRIC)) {
|
||||
startLineAdvantageType = stringMessages.dashboardStartlineAdvantageByGeometry();
|
||||
}else{
|
||||
startLineAdvantageType = stringMessages.dashboardStartlineAdvantageByWind();
|
||||
}
|
||||
startanalysis_card_line_advantage
|
||||
.setInnerHTML(startLineAdvantageType
|
||||
+ ": "
|
||||
+ NumberFormat
|
||||
.getFormat("#0.0")
|
||||
.format(startAnalysisDTO.startAnalysisWindLineInfoDTO.startLineAdvantage.startLineAdvantage)
|
||||
+ " m");
|
||||
}
|
||||
}
|
||||
|
||||
private void addMap(final int cardID) {
|
||||
Timer timer = new Timer()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
simpleMap = new StartAnalysisSimpleMap(cardID, startAnalysisDTO);
|
||||
startanalysis_card.add(simpleMap);
|
||||
}
|
||||
};
|
||||
private void setLineAdvantageDivWidth(StartlineAdvantageType startlineAdvantageType) {
|
||||
if (startAnalysisDTO.startAnalysisWindLineInfoDTO.startLineAdvantage.startLineAdvatageType
|
||||
.equals(StartlineAdvantageType.GEOMETRIC)) {
|
||||
startanalysis_card_line_advantage.getStyle().setWidth(GEOMETRIC_LINE_ADVANTAGE_DIV_WIDTH_IN_PT, Unit.PT);
|
||||
} else {
|
||||
startanalysis_card_line_advantage.getStyle().setWidth(WIND_LINE_ADVANTAGE_DIV_WIDTH_IN_PT, Unit.PT);
|
||||
}
|
||||
}
|
||||
|
||||
timer.schedule(800);
|
||||
containsMap = true;
|
||||
private void addMap(final int cardID, final StartAnalysisDTO startAnalysisDTO) {
|
||||
AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
|
||||
com.sap.sse.gwt.client.player.Timer timer = new com.sap.sse.gwt.client.player.Timer(PlayModes.Live, 1000l);
|
||||
timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds);
|
||||
timer.pause();
|
||||
|
||||
RaceTimesInfoProvider raceTimesInfoProvider = new RaceTimesInfoProvider(sailingServiceAsync,
|
||||
asyncActionsExecutor, null, Collections.singletonList(startAnalysisDTO.regattaAndRaceIdentifier), 5000l /* requestInterval */);
|
||||
|
||||
raceMap = new RaceMap(sailingServiceAsync, asyncActionsExecutor, null, timer, competitorSelectionModel,
|
||||
StringMessages.INSTANCE, false, false, false, startAnalysisDTO.regattaAndRaceIdentifier,
|
||||
resources.combinedWindPanelStyle());
|
||||
competitorSelectionModel.setCompetitors(startAnalysisDTO.getCompetitorDTOsFromStartAnaylsisCompetitorDTOs(),
|
||||
raceMap);
|
||||
raceMap.onRaceSelectionChange(Collections.singletonList(startAnalysisDTO.regattaAndRaceIdentifier));
|
||||
ArrayList<ZoomTypes> zoomTypes = new ArrayList<ZoomTypes>();
|
||||
zoomTypes.add(ZoomTypes.TAILS);
|
||||
raceMap.getSettings().setZoomSettings(new RaceMapZoomSettings(zoomTypes, false));
|
||||
raceMap.getSettings().setHelpLinesSettings(getHelpLineSettings());
|
||||
raceMap.getSettings().setTailLengthInMilliseconds(TAIL_LENGHT_IN_MILLISECONDS);
|
||||
raceTimesInfoProvider.addRaceTimesInfoProviderListener(raceMap);
|
||||
startanalysis_card.add(raceMap);
|
||||
/**
|
||||
* Executes onResize() after the reflow of the DOM. Otherwise it has no effect.
|
||||
* Needs to resize the map because google maps are not shown loaded fully when they are hidden.
|
||||
* */
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
raceMap.onResize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private RaceMapHelpLinesSettings getHelpLineSettings() {
|
||||
HashSet<HelpLineTypes> visibleHelpLines = new HashSet<HelpLineTypes>();
|
||||
visibleHelpLines.add(HelpLineTypes.STARTLINE);
|
||||
visibleHelpLines.add(HelpLineTypes.BOATTAILS);
|
||||
visibleHelpLines.add(HelpLineTypes.STARTLINETOFIRSTMARKTRIANGLE);
|
||||
return new RaceMapHelpLinesSettings(visibleHelpLines);
|
||||
}
|
||||
|
||||
private void removeMap() {
|
||||
if(simpleMap.isAttached()){
|
||||
startanalysis_card.remove(simpleMap);
|
||||
containsMap = false;
|
||||
if (raceMap != null && raceMap.isAttached() == true) {
|
||||
startanalysis_card.remove(raceMap);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMapAndContent(int newPageIndex, String someDataDTO) {
|
||||
if (cardid == newPageIndex && containsMap == false) {
|
||||
addMap(newPageIndex);
|
||||
} else if (containsMap == true) {
|
||||
removeMap();
|
||||
public void startAnalysisComponentPageChangedToIndexAndStartAnalysis(final int newPageIndex,
|
||||
final StartAnalysisDTO startAnalysisDTO) {
|
||||
removeMap();
|
||||
if (cardid == newPageIndex) {
|
||||
/**
|
||||
* Prevents UI to animate startanalysis card animation with small interruptions.
|
||||
* The map gets added just after the DOM manipulation was executed.
|
||||
* */
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
addMap(newPageIndex, startAnalysisDTO);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-8
@@ -7,15 +7,7 @@
|
||||
src='StartlineAnalysis.css'></ui:style>
|
||||
|
||||
<g:HTMLPanel ui:field="startanalysis_card" styleName="{style.startanalysis_card}">
|
||||
<!-- <maps:MapWidget></maps:MapWidget> -->
|
||||
<div class="{style.startanalysis_card_wind_line_data_container}">
|
||||
<g:HTMLPanel ui:field="winddirection"
|
||||
styleName="{style.startanalysis_card_wind_direction_image}">
|
||||
</g:HTMLPanel>
|
||||
<div ui:field="startanalysis_card_wind_data_direction"
|
||||
class="{style.startanalysis_card_data} {style.startanalysis_card_wind_data_direction}"></div>
|
||||
<div ui:field="startanalysis_card_wind_data_speed"
|
||||
class="{style.startanalysis_card_data} {style.startanalysis_card_wind_data_speed}"></div>
|
||||
<div ui:field="startanalysis_card_line_advantage"
|
||||
class="{style.startanalysis_card_data} {style.startanalysis_card_line_advantage}"></div>
|
||||
</div>
|
||||
|
||||
+192
-34
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.dashboards.gwt.client.startanalysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@@ -11,18 +12,30 @@ import com.google.gwt.event.dom.client.ClickHandler;
|
||||
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.Cookies;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FocusPanel;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.HasWidgets;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.RootPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.dashboards.gwt.client.RibDashboardDataRetriever;
|
||||
import com.sap.sailing.dashboards.gwt.client.RibDashboardImageResources;
|
||||
import com.sap.sailing.dashboards.gwt.client.RibDashboardServiceAsync;
|
||||
import com.sap.sailing.dashboards.gwt.client.bottomnotification.BottomNotification;
|
||||
import com.sap.sailing.dashboards.gwt.client.bottomnotification.BottomNotificationClickListener;
|
||||
import com.sap.sailing.dashboards.gwt.client.bottomnotification.BottomNotificationType;
|
||||
import com.sap.sailing.dashboards.gwt.client.popups.competitorselection.CompetitorSelectionListener;
|
||||
import com.sap.sailing.dashboards.gwt.client.popups.competitorselection.CompetitorSelectionPopup;
|
||||
import com.sap.sailing.dashboards.gwt.client.popups.competitorselection.SettingsButtonWithSelectionIndicationLabel;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sse.gwt.client.player.TimeListener;
|
||||
import com.sap.sse.gwt.client.player.Timer;
|
||||
import com.sap.sse.gwt.client.player.Timer.PlayModes;
|
||||
|
||||
/**
|
||||
* The class contains an collection of {@link StartlineAnalysisCard}s that are displayed in horizontal aligned pages. It
|
||||
@@ -34,8 +47,7 @@ import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
* @author Alexander Ries (D062114)
|
||||
*
|
||||
*/
|
||||
public class StartlineAnalysisComponent extends Composite implements HasWidgets, NewStartAnalysisListener,
|
||||
BottomNotificationClickListener {
|
||||
public class StartlineAnalysisComponent extends Composite implements HasWidgets {
|
||||
|
||||
private static StartlineAnalysisComponentUiBinder uiBinder = GWT.create(StartlineAnalysisComponentUiBinder.class);
|
||||
|
||||
@@ -71,7 +83,7 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets,
|
||||
HTMLPanel startanalysis_card_container;
|
||||
|
||||
/**
|
||||
* The left property from the {@link #startanalysis_card_container}.
|
||||
* The CSS "left" property from the {@link #startanalysis_card_container}.
|
||||
* */
|
||||
private double currentScrollPosition = 0;
|
||||
|
||||
@@ -87,22 +99,42 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets,
|
||||
|
||||
private boolean displaysCards;
|
||||
private List<StartAnalysisDTO> starts;
|
||||
private List<StartAnalysisPageChangeListener> pageChangeListener;
|
||||
private List<StartlineAnalysisCard> pageChangeListener;
|
||||
private BottomNotification bottomNotification;
|
||||
private String selectedCompetitor;
|
||||
private Timer timer;
|
||||
private RibDashboardServiceAsync ribDashboardServiceAsync;
|
||||
private SailingServiceAsync sailingServiceAsync;
|
||||
|
||||
private static final int RERFRESH_INTERVAL = 10000;
|
||||
|
||||
private CompetitorSelectionPopup competitorSelectionPopup;
|
||||
private SettingsButtonWithSelectionIndicationLabel settingsButtonWithSelectionIndicationLabel;
|
||||
|
||||
private String leaderboardName;
|
||||
|
||||
private static final String PARAM_LEADERBOARD_NAME = "leaderboardName";
|
||||
private static final String SELECTED_COMPETITOR_ID_COOKIE_KEY = "selectedCompetitorId";
|
||||
private static final int SELECTED_COMPETITOR_ID_COOKIE_KEY_EXPIRE_TIME_IN_MILLIS = 60 * 1000 * 60 * 5;
|
||||
private static final int SCROLL_OFFSET_STARTANALYSIS_CARDS = 83;
|
||||
|
||||
/**
|
||||
* The class requires a {@link BottomNotification} to inform the user when a new {@link StartlineAnalysisCard} gets
|
||||
* added.
|
||||
* Component that contains handles, displays and loads startanalysis cards.
|
||||
* */
|
||||
public StartlineAnalysisComponent(BottomNotification bottomNotification, RibDashboardServiceAsync ribDashboardService) {
|
||||
this.bottomNotification = bottomNotification;
|
||||
pageChangeListener = new ArrayList<StartAnalysisPageChangeListener>();
|
||||
bottomNotification.addBottomNotificationClickListener(this);
|
||||
RibDashboardDataRetriever.getInstance(ribDashboardService).addNewStartAnalysisListener(this);
|
||||
public StartlineAnalysisComponent(RibDashboardServiceAsync ribDashboardServiceAsync, SailingServiceAsync sailingServiceAsync) {
|
||||
this.ribDashboardServiceAsync = ribDashboardServiceAsync;
|
||||
this.sailingServiceAsync = sailingServiceAsync;
|
||||
pageChangeListener = new ArrayList<StartlineAnalysisCard>();
|
||||
starts = new ArrayList<StartAnalysisDTO>();
|
||||
this.leaderboardName = Window.Location.getParameter(PARAM_LEADERBOARD_NAME);
|
||||
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
initCompetitorSelectionPopupAndAddCompetitorSelectionListener();
|
||||
initLeftRightButtons();
|
||||
initTimer();
|
||||
initAndAddBottomNotification();
|
||||
getCachedSelectedCompetitorOrAskForWithPopup();
|
||||
initAndAddSettingsButtonWithSelectionIndicationLabel();
|
||||
}
|
||||
|
||||
private void initLeftRightButtons() {
|
||||
@@ -122,6 +154,114 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets,
|
||||
});
|
||||
}
|
||||
|
||||
private void initTimer() {
|
||||
timer = new Timer(PlayModes.Live);
|
||||
timer.setRefreshInterval(RERFRESH_INTERVAL);
|
||||
timer.addTimeListener(new TimeListener() {
|
||||
|
||||
@Override
|
||||
public void timeChanged(Date newTime, Date oldTime) {
|
||||
String selectedCompetitorId = Cookies.getCookie(SELECTED_COMPETITOR_ID_COOKIE_KEY);
|
||||
if (selectedCompetitorId != null) {
|
||||
loadStartAnalysisDTOsForCompetitorID(selectedCompetitorId);
|
||||
} else {
|
||||
loadCompetitorsAndShowCompetitorSelectionPopup();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadStartAnalysisDTOsForCompetitorID(String competitorIdAsString){
|
||||
ribDashboardServiceAsync.getStartAnalysisListForCompetitorIDAndLeaderboardName(
|
||||
competitorIdAsString, leaderboardName, new AsyncCallback<List<StartAnalysisDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(List<StartAnalysisDTO> result) {
|
||||
if (!result.isEmpty()) {
|
||||
|
||||
if (displayedStartAnalysisCompetitorDifferentToRequestedOne()) {
|
||||
removeAllStartAnalysisCards();
|
||||
}
|
||||
|
||||
if (result.size() != starts.size()) {
|
||||
showNotificationForNewStartAnalysis();
|
||||
}
|
||||
addNewStartAnalysisCards(result);
|
||||
settingsButtonWithSelectionIndicationLabel
|
||||
.setSelectionIndicationTextOnLabel(result.get(0).competitor.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initAndAddBottomNotification() {
|
||||
bottomNotification = new BottomNotification();
|
||||
bottomNotification.addBottomNotificationClickListener(new BottomNotificationClickListener() {
|
||||
|
||||
@Override
|
||||
public void bottomNotificationClicked() {
|
||||
scrollToLast();
|
||||
}
|
||||
});
|
||||
RootPanel.get().add(bottomNotification);
|
||||
}
|
||||
|
||||
private void initCompetitorSelectionPopupAndAddCompetitorSelectionListener() {
|
||||
competitorSelectionPopup = new CompetitorSelectionPopup();
|
||||
competitorSelectionPopup.addListener(new CompetitorSelectionListener() {
|
||||
|
||||
@Override
|
||||
public void didClickOKWithSelectedCompetitor(CompetitorDTO competitor) {
|
||||
if (competitor != null) {
|
||||
Cookies.removeCookie(SELECTED_COMPETITOR_ID_COOKIE_KEY);
|
||||
Cookies.setCookie(SELECTED_COMPETITOR_ID_COOKIE_KEY, competitor.getIdAsString(), new Date(
|
||||
new Date().getTime() + SELECTED_COMPETITOR_ID_COOKIE_KEY_EXPIRE_TIME_IN_MILLIS));
|
||||
if (settingsButtonWithSelectionIndicationLabel != null) {
|
||||
settingsButtonWithSelectionIndicationLabel.setSelectionIndicationTextOnLabel(competitor
|
||||
.getName());
|
||||
}
|
||||
loadStartAnalysisDTOsForCompetitorID(competitor.getIdAsString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void getCachedSelectedCompetitorOrAskForWithPopup() {
|
||||
String selectedCompetitorIdFromCookie = Cookies.getCookie(SELECTED_COMPETITOR_ID_COOKIE_KEY);
|
||||
if (selectedCompetitorIdFromCookie == null) {
|
||||
loadCompetitorsAndShowCompetitorSelectionPopup();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadCompetitorsAndShowCompetitorSelectionPopup() {
|
||||
ribDashboardServiceAsync.getCompetitorsInLeaderboard(leaderboardName, new AsyncCallback<List<CompetitorDTO>>() {
|
||||
@Override
|
||||
public void onSuccess(List<CompetitorDTO> result) {
|
||||
if (!competitorSelectionPopup.isShown())
|
||||
competitorSelectionPopup.show(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initAndAddSettingsButtonWithSelectionIndicationLabel() {
|
||||
settingsButtonWithSelectionIndicationLabel = new SettingsButtonWithSelectionIndicationLabel();
|
||||
settingsButtonWithSelectionIndicationLabel.addClickHandlerToSettingsButton(new ClickHandler() {
|
||||
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
loadCompetitorsAndShowCompetitorSelectionPopup();
|
||||
}
|
||||
});
|
||||
RootPanel.get().add(settingsButtonWithSelectionIndicationLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* <param>clickedLeft</param> if clicked left is true, the left arrow button was pressed, a false represent the
|
||||
* right button. The buttons are represented by the member variables {@link #left_focus_panel} and
|
||||
@@ -131,7 +271,7 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets,
|
||||
if (displaysCards == true) {
|
||||
if (clickedLeft) {
|
||||
if (page != 0) {
|
||||
currentScrollPosition = currentScrollPosition + 83;
|
||||
currentScrollPosition = currentScrollPosition + SCROLL_OFFSET_STARTANALYSIS_CARDS;
|
||||
page--;
|
||||
startanalysis_card_container.getElement().getStyle().setLeft(currentScrollPosition, Unit.PCT);
|
||||
notifyStartAnalysisPageChangeListener(page);
|
||||
@@ -148,7 +288,7 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets,
|
||||
}
|
||||
} else {
|
||||
if (page != numberOfStartAnalysisCards - 1) {
|
||||
currentScrollPosition -= 83;
|
||||
currentScrollPosition -= SCROLL_OFFSET_STARTANALYSIS_CARDS;
|
||||
page++;
|
||||
startanalysis_card_container.getElement().getStyle().setLeft(currentScrollPosition, Unit.PCT);
|
||||
notifyStartAnalysisPageChangeListener(page);
|
||||
@@ -169,7 +309,8 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets,
|
||||
|
||||
private void scrollToLast() {
|
||||
if (numberOfStartAnalysisCards > 1) {
|
||||
currentScrollPosition = currentScrollPosition - (numberOfStartAnalysisCards - page - 1) * 83;
|
||||
currentScrollPosition = currentScrollPosition - (numberOfStartAnalysisCards - page - 1)
|
||||
* SCROLL_OFFSET_STARTANALYSIS_CARDS;
|
||||
page = numberOfStartAnalysisCards - 1;
|
||||
startanalysis_card_container.getElement().getStyle().setLeft(currentScrollPosition, Unit.PCT);
|
||||
header.getElement().setInnerHTML("Start " + starts.get(page).raceName);
|
||||
@@ -181,7 +322,7 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets,
|
||||
}
|
||||
}
|
||||
|
||||
private void addStartAnalysisCard(StartAnalysisDTO startAnalysisDTO) {
|
||||
private void addStartAnalysisCard(final StartAnalysisDTO startAnalysisDTO) {
|
||||
|
||||
if (displaysCards == false) {
|
||||
displaysCards = true;
|
||||
@@ -190,20 +331,26 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets,
|
||||
if (numberOfStartAnalysisCards > 0) {
|
||||
rightButton.setResource(RibDashboardImageResources.INSTANCE.right());
|
||||
}
|
||||
StartlineAnalysisCard sac = new StartlineAnalysisCard(numberOfStartAnalysisCards * 83 + 10,
|
||||
numberOfStartAnalysisCards, startAnalysisDTO);
|
||||
startanalysis_card_container.add(sac);
|
||||
registerPageChangeListener(sac);
|
||||
final StartlineAnalysisCard startlineAnalysisCard = new StartlineAnalysisCard(numberOfStartAnalysisCards
|
||||
* SCROLL_OFFSET_STARTANALYSIS_CARDS + 10, numberOfStartAnalysisCards, startAnalysisDTO,
|
||||
sailingServiceAsync);
|
||||
startanalysis_card_container.add(startlineAnalysisCard);
|
||||
startlineAnalysisCard.startAnalysisComponentPageChangedToIndexAndStartAnalysis(page, startAnalysisDTO);
|
||||
registerPageChangeListener(startlineAnalysisCard);
|
||||
numberOfStartAnalysisCards++;
|
||||
|
||||
}
|
||||
|
||||
private void removeAllStartAnalysisCards() {
|
||||
startanalysis_card_container.clear();
|
||||
numberOfStartAnalysisCards = 0;
|
||||
starts.clear();
|
||||
}
|
||||
|
||||
public void registerPageChangeListener(StartAnalysisPageChangeListener s) {
|
||||
private void showNotificationForNewStartAnalysis() {
|
||||
this.bottomNotification.show(BottomNotificationType.NEW_STARTANALYSIS_AVAILABLE);
|
||||
}
|
||||
|
||||
public void registerPageChangeListener(StartlineAnalysisCard s) {
|
||||
pageChangeListener.add(s);
|
||||
}
|
||||
|
||||
@@ -213,26 +360,37 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets,
|
||||
|
||||
public void notifyStartAnalysisPageChangeListener(int newPageIndex) {
|
||||
for (StartAnalysisPageChangeListener sO : pageChangeListener) {
|
||||
sO.loadMapAndContent(newPageIndex, "someData");
|
||||
if(starts.get(newPageIndex) != null)
|
||||
sO.startAnalysisComponentPageChangedToIndexAndStartAnalysis(newPageIndex, starts.get(newPageIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNewStartAnalysisCardForCompetitor(List<StartAnalysisDTO> startAnalysisDTOs, String selectedCompetitor) {
|
||||
this.bottomNotification.show("New Start Analysis available.", "#F0AB00", "#000000", true);
|
||||
if (!selectedCompetitor.equals(this.selectedCompetitor)) {
|
||||
removeAllStartAnalysisCards();
|
||||
}
|
||||
private void addNewStartAnalysisCards(List<StartAnalysisDTO> startAnalysisDTOs) {
|
||||
for (int i = numberOfStartAnalysisCards; i <= startAnalysisDTOs.size() - 1; i++) {
|
||||
addStartAnalysisCard(startAnalysisDTOs.get(i));
|
||||
starts.add(startAnalysisDTOs.get(i));
|
||||
}
|
||||
this.selectedCompetitor = selectedCompetitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bottomNotificationClicked() {
|
||||
scrollToLast();
|
||||
private String getCompetitorIdAsStringFromDisplayedStartAnalysisDTOs() {
|
||||
String result = "";
|
||||
if (starts != null && starts.size() > 0) {
|
||||
CompetitorDTO competitor = starts.get(0).competitor;
|
||||
if (competitor != null)
|
||||
result = starts.get(0).competitor.getIdAsString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean displayedStartAnalysisCompetitorDifferentToRequestedOne() {
|
||||
String competitorIDFromDispalyedStartAnalysisDTOs = getCompetitorIdAsStringFromDisplayedStartAnalysisDTOs();
|
||||
if (competitorIDFromDispalyedStartAnalysisDTOs != null
|
||||
&& !(competitorIDFromDispalyedStartAnalysisDTOs.equals(Cookies
|
||||
.getCookie(SELECTED_COMPETITOR_ID_COOKIE_KEY)))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-6
@@ -10,14 +10,16 @@ import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSe
|
||||
import com.google.gwt.user.cellview.client.TextColumn;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisCompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class StartAnalysisStartRankTable extends AbsolutePanel {
|
||||
|
||||
CellTable<StartAnalysisCompetitorDTO> table;
|
||||
private CellTable<StartAnalysisCompetitorDTO> table;
|
||||
private StringMessages stringConstants;
|
||||
|
||||
public StartAnalysisStartRankTable(List<StartAnalysisCompetitorDTO> saCompetitors) {
|
||||
|
||||
stringConstants = StringMessages.INSTANCE;
|
||||
initTable(saCompetitors);
|
||||
}
|
||||
|
||||
@@ -59,13 +61,13 @@ public class StartAnalysisStartRankTable extends AbsolutePanel {
|
||||
}
|
||||
};
|
||||
|
||||
table.addColumn(rankColumn, "Rank at first mark");
|
||||
table.addColumn(rankColumn, stringConstants.dashboardRankAtFirstMark());
|
||||
table.setColumnWidth(rankColumn, 18.0, Unit.PCT);
|
||||
table.addColumn(teamColumn, "Team");
|
||||
table.addColumn(teamColumn, stringConstants.dashboardTeam());
|
||||
table.setColumnWidth(teamColumn, 42.0, Unit.PCT);
|
||||
table.addColumn(speedColumn, "Speed in kts");
|
||||
table.addColumn(speedColumn, stringConstants.dashboardSpeedInKts());
|
||||
table.setColumnWidth(speedColumn, 15.0, Unit.PCT);
|
||||
table.addColumn(distanceColumn, "Distance to line in m");
|
||||
table.addColumn(distanceColumn, stringConstants.dashboardDistanceToLineInM());
|
||||
table.setColumnWidth(distanceColumn, 25.0, Unit.PCT);
|
||||
|
||||
table.setRowCount(4, true);
|
||||
|
||||
+7
-11
@@ -9,7 +9,6 @@ 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.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiConstructor;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
@@ -17,6 +16,7 @@ import com.google.gwt.user.client.ui.HasWidgets;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.dashboards.gwt.client.windchart.VerticalWindChartClickListener;
|
||||
import com.sap.sailing.dashboards.gwt.client.windchart.WindBotComponent;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
/**
|
||||
* The purpose of the class is to display a live and an average value of a continuously updating data source.
|
||||
@@ -66,8 +66,7 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti
|
||||
@UiField
|
||||
HTMLPanel averagePanel;
|
||||
|
||||
int sizeForUnit;
|
||||
|
||||
private StringMessages stringConstants;
|
||||
public LiveAverageComponent() {
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
}
|
||||
@@ -79,7 +78,8 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti
|
||||
* sets a special size
|
||||
*
|
||||
* */
|
||||
public @UiConstructor LiveAverageComponent(String header, String unit) {
|
||||
public LiveAverageComponent(String header, String unit) {
|
||||
stringConstants = StringMessages.INSTANCE;
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
liveAveragePanel.getElement().getStyle().setProperty("backgroundColor", "white");
|
||||
this.header.setInnerText(header);
|
||||
@@ -94,8 +94,8 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti
|
||||
this.liveUnit.getStyle().setPosition(Position.ABSOLUTE);
|
||||
this.averageUnit.getStyle().setPosition(Position.ABSOLUTE);
|
||||
}
|
||||
this.liveLabel.setInnerHTML("live");
|
||||
this.averageLabel.setInnerHTML("average<br>(15 minutes)");
|
||||
this.liveLabel.setInnerHTML(stringConstants.dashboardLiveWind());
|
||||
this.averageLabel.setInnerHTML(stringConstants.dashboardAverageWind()+"<br>"+stringConstants.dashboardAverageWindMinutes(15));
|
||||
}
|
||||
|
||||
public void updateValues(String liveValue, String averageValue) {
|
||||
@@ -125,10 +125,6 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti
|
||||
|
||||
@Override
|
||||
public void clickedWindChartWithNewIntervalChangeInMillis(int windChartIntervallInMillis) {
|
||||
if(windChartIntervallInMillis > 15){
|
||||
this.averageLabel.setInnerHTML("average<br>(1 hour)");
|
||||
}else{
|
||||
this.averageLabel.setInnerHTML("average<br>(15 minutes)");
|
||||
}
|
||||
this.averageLabel.setInnerHTML(stringConstants.dashboardAverageWind()+"<br>"+stringConstants.dashboardAverageWindMinutes(windChartIntervallInMillis));
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -5,6 +5,7 @@ import com.sap.sailing.dashboards.gwt.client.RibDashboardDataRetriever;
|
||||
import com.sap.sailing.dashboards.gwt.client.RibDashboardDataRetrieverListener;
|
||||
import com.sap.sailing.dashboards.gwt.client.startanalysis.StartlineAdvantageType;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
/**
|
||||
* The purpose of the class is to display the live and average start line advantage either by wind or by geometry. There
|
||||
@@ -21,15 +22,14 @@ public class StartLineAdvantageComponent extends LiveAverageComponent implements
|
||||
private StartLineAdvantageComponentState startLineAdvantageComponentState;
|
||||
private StartLineAdvantageComponentStateShowsAdvantageByWind startLineAdvantageComponentStateShowsAdvantageByWind;
|
||||
private StartLineAdvantageComponentStateShowsAdvantageByGeometry startLineAdvantageComponentStateShowsAdvantageByGeometry;
|
||||
private StringMessages stringConstants;
|
||||
|
||||
private static final String HEADER_ADVANTAGE_BY_WIND = "Startline advantage by wind";
|
||||
private static final String HEADER_ADVANTAGE_BY_GEOMETRY = "Startline advantage by geometry";
|
||||
|
||||
public StartLineAdvantageComponent() {
|
||||
public StartLineAdvantageComponent(RibDashboardDataRetriever ribDashboardDataRetriever) {
|
||||
super();
|
||||
stringConstants = StringMessages.INSTANCE;
|
||||
initAndSetStartLineAdvantageStates();
|
||||
StartLineAdvantageComponentRessources.INSTANCE.css().ensureInjected();
|
||||
this.header.setInnerText(HEADER_ADVANTAGE_BY_WIND);
|
||||
this.header.setInnerText(stringConstants.dashboardStartlineAdvantageByWind());
|
||||
this.header.addClassName(StartLineAdvantageComponentRessources.INSTANCE.css()
|
||||
.startLineAdvantageComponent_header());
|
||||
liveAveragePanel.getElement().addClassName(
|
||||
@@ -40,9 +40,9 @@ public class StartLineAdvantageComponent extends LiveAverageComponent implements
|
||||
StartLineAdvantageComponentRessources.INSTANCE.css().startLineAdvantageComponent_middleLine());
|
||||
averagePanel.getElement().addClassName(
|
||||
StartLineAdvantageComponentRessources.INSTANCE.css().startLineAdvantageComponent_averagePanel());
|
||||
this.liveLabel.setInnerHTML("live");
|
||||
this.averageLabel.setInnerHTML("average<br>(1 hour)");
|
||||
RibDashboardDataRetriever.getInstance(null).addDataObserver(this);
|
||||
this.liveLabel.setInnerHTML(stringConstants.dashboardLiveWind());
|
||||
this.averageLabel.setInnerHTML(stringConstants.dashboardAverageWind()+"<br>"+stringConstants.dashboardAverageWindMinutes(60));
|
||||
ribDashboardDataRetriever.addDataObserver(this);
|
||||
}
|
||||
|
||||
private void initAndSetStartLineAdvantageStates() {
|
||||
@@ -116,7 +116,7 @@ public class StartLineAdvantageComponent extends LiveAverageComponent implements
|
||||
@Override
|
||||
public void changeStartLineAdvatageComponentsStateToOtherState(
|
||||
StartLineAdvantageComponent startLineAdvantageComponent) {
|
||||
startLineAdvantageComponent.header.setInnerText(HEADER_ADVANTAGE_BY_GEOMETRY);
|
||||
startLineAdvantageComponent.header.setInnerText(stringConstants.dashboardStartlineAdvantageByWind());
|
||||
startLineAdvantageComponent.startLineAdvantageComponentState = startLineAdvantageComponent.startLineAdvantageComponentStateShowsAdvantageByGeometry;
|
||||
startLineAdvantageComponent.liveNumber
|
||||
.setInnerText(startLineAdvantageComponent.startLineAdvantageComponentStateShowsAdvantageByGeometry
|
||||
@@ -149,7 +149,7 @@ public class StartLineAdvantageComponent extends LiveAverageComponent implements
|
||||
@Override
|
||||
public void changeStartLineAdvatageComponentsStateToOtherState(
|
||||
StartLineAdvantageComponent startLineAdvantageComponent) {
|
||||
startLineAdvantageComponent.header.setInnerText(HEADER_ADVANTAGE_BY_WIND);
|
||||
startLineAdvantageComponent.header.setInnerText(stringConstants.dashboardStartlineAdvantageByGeometry());
|
||||
startLineAdvantageComponent.startLineAdvantageComponentState = startLineAdvantageComponent.startLineAdvantageComponentStateShowsAdvantageByWind;
|
||||
startLineAdvantageComponent.liveNumber
|
||||
.setInnerText(startLineAdvantageComponent.startLineAdvantageComponentStateShowsAdvantageByWind
|
||||
|
||||
-6
@@ -3,8 +3,6 @@ package com.sap.sailing.dashboards.gwt.client.windchart;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.moxieapps.gwt.highcharts.client.Axis.Type;
|
||||
import org.moxieapps.gwt.highcharts.client.Chart;
|
||||
@@ -38,7 +36,6 @@ import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FocusPanel;
|
||||
import com.google.gwt.user.client.ui.HasWidgets;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.dashboards.gwt.client.RibDashboardEntryPoint;
|
||||
|
||||
/**
|
||||
* The class represents a wind chart that is displayed vertically. Because it is meant to be used to display wind fixes,
|
||||
@@ -71,8 +68,6 @@ public class VerticalWindChart extends Composite implements HasWidgets {
|
||||
|
||||
private static final int MAX_SERIES_POINTS = 100000000;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RibDashboardEntryPoint.class.getName());
|
||||
|
||||
private static VerticalWindChartUiBinder uiBinder = GWT.create(VerticalWindChartUiBinder.class);
|
||||
|
||||
interface VerticalWindChartUiBinder extends UiBinder<Widget, VerticalWindChart> {
|
||||
@@ -246,7 +241,6 @@ public class VerticalWindChart extends Composite implements HasWidgets {
|
||||
} else {
|
||||
pointRangeInMilliseconds = 0;
|
||||
}
|
||||
logger.log(Level.INFO, "Points Range " + pointRangeInMilliseconds);
|
||||
return pointRangeInMilliseconds;
|
||||
}
|
||||
|
||||
|
||||
+26
@@ -34,6 +34,32 @@
|
||||
color: black;
|
||||
}
|
||||
|
||||
.windloadinghint {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
opacity: 0.4;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.windloadinghinttext {
|
||||
position: absolute;
|
||||
bottom: 0pt;
|
||||
height: 15pt;
|
||||
line-height: 15pt;
|
||||
margin-top: 0pt;
|
||||
vertical-align: middle;
|
||||
font-size: 12pt;
|
||||
font-family: "Arial";
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
top: 50%;
|
||||
margin-top: -7pt;
|
||||
}
|
||||
|
||||
.clickHintMinutesSpan{
|
||||
font-weight: bolder;
|
||||
}
|
||||
+11
-3
@@ -24,6 +24,7 @@ import com.sap.sailing.dashboards.gwt.shared.SinWave;
|
||||
import com.sap.sailing.dashboards.gwt.shared.WindType;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.ChartPointRecalculator;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
|
||||
@@ -57,6 +58,9 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa
|
||||
interface WindBotComponentStyle extends CssResource {
|
||||
}
|
||||
|
||||
@UiField
|
||||
public HTMLPanel windBotComponent;
|
||||
|
||||
/**
|
||||
* The header of the widget displaying the name of the wind bot.
|
||||
* */
|
||||
@@ -67,14 +71,14 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa
|
||||
* One of two {@link LiveAverageComponent}s that display in big font the live and the average value of the measured
|
||||
* wind speed.
|
||||
* */
|
||||
@UiField
|
||||
@UiField(provided = true)
|
||||
public LiveAverageComponent trueWindSpeedLiveAverageComponent;
|
||||
|
||||
/**
|
||||
* One of two {@link LiveAverageComponent}s that display in big font the live and the average value of the measured
|
||||
* wind direction.
|
||||
* */
|
||||
@UiField
|
||||
@UiField(provided = true)
|
||||
public LiveAverageComponent trueWindDirectionLiveAverageComponent;
|
||||
|
||||
/**
|
||||
@@ -99,9 +103,11 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa
|
||||
public LocationPointerCompass locationPointerCompass;
|
||||
|
||||
private String windBotId;
|
||||
private StringMessages stringConstants;
|
||||
|
||||
public WindBotComponent(String windBotId) {
|
||||
this.windBotId = windBotId;
|
||||
stringConstants = StringMessages.INSTANCE;
|
||||
String inSimulationModeParameter = Window.Location.getParameter(IN_SIMULATION_MODE);
|
||||
if (inSimulationModeParameter != null && inSimulationModeParameter.equals("true")) {
|
||||
inSimulationMode = true;
|
||||
@@ -112,8 +118,10 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa
|
||||
}
|
||||
movingAverageSpeed = new MovingAverage(500);
|
||||
movingAverageDirection = new MovingAverage(500);
|
||||
trueWindSpeedLiveAverageComponent = new LiveAverageComponent(stringConstants.dashboardTrueWindSpeed(), stringConstants.dashboardTrueWindSpeedUnit());
|
||||
trueWindDirectionLiveAverageComponent = new LiveAverageComponent(stringConstants.dashboardTrueWindDirection(), stringConstants.dashboardTrueWindDirectionUnit());
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
windBotNamePanel.getElement().setInnerText("Wind Bot " + windBotId);
|
||||
windBotNamePanel.getElement().setInnerText(stringConstants.dashboardWindBot()+" "+ windBotId);
|
||||
trueWindSpeedVerticalWindChart.addVerticalWindChartClickListener(trueWindSpeedLiveAverageComponent);
|
||||
trueWindDirectionVerticalWindChart.addVerticalWindChartClickListener(trueWindDirectionLiveAverageComponent);
|
||||
}
|
||||
|
||||
+4
-4
@@ -8,17 +8,17 @@
|
||||
<ui:style type='com.sap.sailing.dashboards.gwt.client.windchart.WindBotComponent.WindBotComponentStyle'
|
||||
src='WindBotComponentStyle.css'></ui:style>
|
||||
|
||||
<g:HTMLPanel styleName="windBotComponent">
|
||||
<g:HTMLPanel ui:field="windBotNamePanel" styleName="{style.windBotNamePanel}">Wind Bot</g:HTMLPanel>
|
||||
<g:HTMLPanel ui:field="windBotComponent" styleName="windBotComponent">
|
||||
<g:HTMLPanel ui:field="windBotNamePanel" styleName="{style.windBotNamePanel}"></g:HTMLPanel>
|
||||
<g:HTMLPanel
|
||||
styleName="{style.wind_bot_component_live_average_container} {style.wind_bot_component_left}">
|
||||
<startlineadvantage:LiveAverageComponent
|
||||
ui:field="trueWindSpeedLiveAverageComponent" header="TWS" unit="kts"></startlineadvantage:LiveAverageComponent>
|
||||
ui:field="trueWindSpeedLiveAverageComponent"></startlineadvantage:LiveAverageComponent>
|
||||
</g:HTMLPanel>
|
||||
<g:HTMLPanel
|
||||
styleName="{style.wind_bot_component_live_average_container} {style.wind_bot_component_right}">
|
||||
<startlineadvantage:LiveAverageComponent
|
||||
ui:field="trueWindDirectionLiveAverageComponent" header="TWD" unit="°"></startlineadvantage:LiveAverageComponent>
|
||||
ui:field="trueWindDirectionLiveAverageComponent"></startlineadvantage:LiveAverageComponent>
|
||||
</g:HTMLPanel>
|
||||
<g:HTMLPanel
|
||||
styleName="{style.wind_bot_component_windchart_container} {style.wind_bot_component_left}">
|
||||
|
||||
+59
-51
@@ -3,9 +3,7 @@ package com.sap.sailing.dashboards.gwt.server;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -15,6 +13,7 @@ import org.osgi.util.tracker.ServiceTracker;
|
||||
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
|
||||
import com.sap.sailing.dashboards.gwt.client.RibDashboardService;
|
||||
import com.sap.sailing.dashboards.gwt.client.startanalysis.StartlineAdvantageType;
|
||||
import com.sap.sailing.dashboards.gwt.server.startanalysis.StartAnalysisCreationController;
|
||||
import com.sap.sailing.dashboards.gwt.shared.MovingAverage;
|
||||
import com.sap.sailing.dashboards.gwt.shared.ResponseMessage;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
|
||||
@@ -25,7 +24,7 @@ import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
@@ -39,10 +38,14 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
* @author Alexander Ries (D062114)
|
||||
*
|
||||
*/
|
||||
public class RibDashboardServiceImpl extends RemoteServiceServlet implements RibDashboardService,
|
||||
StartAnalysisRacesStoreListener {
|
||||
public class RibDashboardServiceImpl extends RemoteServiceServlet implements RibDashboardService {
|
||||
|
||||
private static final long serialVersionUID = 7710545186662632126L;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private StartAnalysisCreationController startAnalysisCreationController;
|
||||
|
||||
/**
|
||||
* Variable contains last {@link TrackedRace} that is or was live
|
||||
@@ -63,30 +66,18 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib
|
||||
* */
|
||||
private MovingAverage averageStartLineAdvantageByGeometry;
|
||||
|
||||
/**
|
||||
* The map values contain a Pair, whose first value is a {@link MovingAverage} for the true wind speed and the
|
||||
* second one contains an average for the true wind direction for a wind bot.
|
||||
* */
|
||||
|
||||
private Map<String, List<StartAnalysisDTO>> startAnalysisDTOsForCompetitor;
|
||||
private StartAnalysisRacesStore startAnalysisRacesStore;
|
||||
|
||||
private final ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
|
||||
private final com.sap.sailing.domain.base.DomainFactory baseDomainFactory;
|
||||
private final BundleContext context;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RibDashboardServiceImpl.class.getName());
|
||||
|
||||
|
||||
public RibDashboardServiceImpl() {
|
||||
context = Activator.getDefault();
|
||||
racingEventServiceTracker = createAndOpenRacingEventServiceTracker(context);
|
||||
baseDomainFactory = getRacingEventService().getBaseDomainFactory();
|
||||
startAnalysisCreationController = new StartAnalysisCreationController(getRacingEventService());
|
||||
|
||||
startAnalysisRacesStore = new StartAnalysisRacesStore(getRacingEventService());
|
||||
startAnalysisRacesStore.addStartAnalyisisRacesStoreListener(this);
|
||||
|
||||
startAnalysisDTOsForCompetitor = new HashMap<String, List<StartAnalysisDTO>>();
|
||||
averageStartLineAdvantageByWind = new MovingAverage(400);
|
||||
averageStartLineAdvantageByGeometry = new MovingAverage(400);
|
||||
}
|
||||
@@ -105,36 +96,26 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib
|
||||
|
||||
/**
|
||||
* <param>leaderboardName</param> is used to retrieve the live running race with the method
|
||||
* {@link #getLiveRaceFromLeaderboardName(String)}. <param>competitorName</param> If competitorName is null, the
|
||||
* response contains only a list of competitors in the live race. Otherwise the parameter is used to return the
|
||||
* right startanalysis for a specific competitor with in the returned {@link RibDashboardRaceInfoDTO}.
|
||||
* {@link #getLiveRaceFromLeaderboardName(String)}.
|
||||
*
|
||||
* @throws NoWindException
|
||||
* */
|
||||
@Override
|
||||
public RibDashboardRaceInfoDTO getLiveRaceInfo(String leaderboardName, String competitorName) throws NoWindException {
|
||||
public RibDashboardRaceInfoDTO getLiveRaceInfo(String leaderboardName) throws NoWindException {
|
||||
RibDashboardRaceInfoDTO lRInfo = new RibDashboardRaceInfoDTO();
|
||||
if (leaderboardName != null) {
|
||||
TimePoint timePointOfRequest = MillisecondsTimePoint.now();
|
||||
if (checkIfRaceIsStillRunning(timePointOfRequest, leaderboardName)) {
|
||||
if (competitorName == null) {
|
||||
fillLiveRaceInfoDTOWithRaceData(lRInfo, timePointOfRequest);
|
||||
logger.log(Level.INFO, "No Competitor selected");
|
||||
lRInfo.responseMessage = ResponseMessage.NO_COMPETITOR_SELECTED;
|
||||
return lRInfo;
|
||||
} else {
|
||||
fillLiveRaceInfoDTOWithRaceData(lRInfo, timePointOfRequest);
|
||||
fillLiveRaceInfoDTOWithStartLineAdavantageData(lRInfo, timePointOfRequest);
|
||||
fillLiveRaceInfoDTOWithStartAnalysisData(lRInfo, competitorName);
|
||||
lRInfo.responseMessage = ResponseMessage.OK;
|
||||
}
|
||||
fillLiveRaceInfoDTOWithRaceData(lRInfo, timePointOfRequest);
|
||||
fillLiveRaceInfoDTOWithStartLineAdavantageData(lRInfo, timePointOfRequest);
|
||||
lRInfo.responseMessage = ResponseMessage.RACE_LIVE;
|
||||
} else {
|
||||
lRInfo.responseMessage = ResponseMessage.NO_RACE_LIVE;
|
||||
}
|
||||
return lRInfo;
|
||||
} else {
|
||||
lRInfo.responseMessage = ResponseMessage.NO_RACE_LIVE;
|
||||
return lRInfo;
|
||||
}
|
||||
return lRInfo;
|
||||
}
|
||||
|
||||
private void fillLiveRaceInfoDTOWithRaceData(RibDashboardRaceInfoDTO lRInfo, TimePoint now) {
|
||||
@@ -150,10 +131,6 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib
|
||||
}
|
||||
}
|
||||
|
||||
private void fillLiveRaceInfoDTOWithStartAnalysisData(RibDashboardRaceInfoDTO lRInfo, String competiorName) {
|
||||
lRInfo.startAnalysisDTOList = startAnalysisDTOsForCompetitor.get(competiorName);
|
||||
}
|
||||
|
||||
// returns true if race is still live
|
||||
private boolean checkIfRaceIsStillRunning(TimePoint now, String leaderboardName) {
|
||||
if (runningRace == null || !(runningRace.isLive(now))) {
|
||||
@@ -161,7 +138,6 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib
|
||||
if (runningRace == null) {
|
||||
return false;
|
||||
} else {
|
||||
startAnalysisRacesStore.addAsListener(runningRace);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@@ -185,17 +161,34 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib
|
||||
return result;
|
||||
}
|
||||
|
||||
private void fillLiveRaceInfoDTOWithStartLineAdavantageData(RibDashboardRaceInfoDTO lRInfo, TimePoint timePoint) throws NoWindException {
|
||||
private List<TrackedRace> getTrackedRacesFromLeaderboard(String leaderboardName) {
|
||||
List<TrackedRace> result = new ArrayList<TrackedRace>();
|
||||
Leaderboard lb = getRacingEventService().getLeaderboardByName(leaderboardName);
|
||||
if (lb != null) {
|
||||
for (RaceColumn column : lb.getRaceColumns()) {
|
||||
for (Fleet fleet : column.getFleets()) {
|
||||
TrackedRace race = column.getTrackedRace(fleet);
|
||||
if (race != null) {
|
||||
result.add(race);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void fillLiveRaceInfoDTOWithStartLineAdavantageData(RibDashboardRaceInfoDTO lRInfo, TimePoint timePoint)
|
||||
throws NoWindException {
|
||||
if (runningRace != null && timePoint != null) {
|
||||
StartLineAdvantageDTO startLineAdvantageDTO = new StartLineAdvantageDTO();
|
||||
StartlineAdvantageType startlineAdvantageType = getStartlineAdvantageType(runningRace, timePoint);
|
||||
if(startlineAdvantageType == null || startlineAdvantageType == StartlineAdvantageType.WIND){
|
||||
if (startlineAdvantageType == null || startlineAdvantageType == StartlineAdvantageType.WIND) {
|
||||
startLineAdvantageDTO.startLineAdvatageType = StartlineAdvantageType.WIND;
|
||||
double startlineAdvantage = runningRace.getStartLine(timePoint).getAdvantage().getMeters();
|
||||
startLineAdvantageDTO.startLineAdvantage = startlineAdvantage;
|
||||
averageStartLineAdvantageByWind.add(startlineAdvantage);
|
||||
startLineAdvantageDTO.startlineAdvantageAverage = averageStartLineAdvantageByWind.getAverage();
|
||||
}else if(startlineAdvantageType == StartlineAdvantageType.GEOMETRIC){
|
||||
} else if (startlineAdvantageType == StartlineAdvantageType.GEOMETRIC) {
|
||||
startLineAdvantageDTO.startLineAdvatageType = StartlineAdvantageType.GEOMETRIC;
|
||||
double startlineAdvantage = runningRace.getStartLine(timePoint).getAdvantage().getMeters();
|
||||
startLineAdvantageDTO.startLineAdvantage = startlineAdvantage;
|
||||
@@ -224,12 +217,13 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib
|
||||
}
|
||||
}
|
||||
|
||||
private LegType getFirstLegTypeOfTrackedRaceAtTimePoint(TrackedRace trackedRace, TimePoint timePoint) throws NoWindException{
|
||||
private LegType getFirstLegTypeOfTrackedRaceAtTimePoint(TrackedRace trackedRace, TimePoint timePoint)
|
||||
throws NoWindException {
|
||||
Iterable<TrackedLeg> trackedLegs = trackedRace.getTrackedLegs();
|
||||
if(trackedLegs != null && trackedLegs.iterator().hasNext()){
|
||||
if (trackedLegs != null && trackedLegs.iterator().hasNext()) {
|
||||
TrackedLeg firstLegInTrackedRace = trackedLegs.iterator().next();
|
||||
return firstLegInTrackedRace.getLegType(timePoint);
|
||||
}else{
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -238,12 +232,26 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib
|
||||
return baseDomainFactory;
|
||||
}
|
||||
|
||||
public TrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier regattaNameAndRaceName) {
|
||||
return null;
|
||||
@Override
|
||||
public List<StartAnalysisDTO> getStartAnalysisListForCompetitorIDAndLeaderboardName(String competitorIdAsString,
|
||||
String leaderboardName) {
|
||||
List<StartAnalysisDTO> startAnalysisDTOs = new ArrayList<StartAnalysisDTO>();
|
||||
Competitor competitor = baseDomainFactory.getCompetitorStore().getExistingCompetitorByIdAsString(
|
||||
competitorIdAsString);
|
||||
List<TrackedRace> trackedRacesForLeaderBoardName = getTrackedRacesFromLeaderboard(leaderboardName);
|
||||
for (TrackedRace trackedRace : trackedRacesForLeaderBoardName) {
|
||||
StartAnalysisDTO startAnalysisDTO = startAnalysisCreationController.checkStartAnalysisForCompetitorInTrackedRace(competitor, trackedRace);
|
||||
if (startAnalysisDTO != null)
|
||||
startAnalysisDTOs.add(startAnalysisDTO);
|
||||
}
|
||||
return startAnalysisDTOs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAnalyisisRacesChanged(Map<String, List<StartAnalysisDTO>> startAnalysisDTOCompetitorMap) {
|
||||
startAnalysisDTOsForCompetitor = startAnalysisDTOCompetitorMap;
|
||||
public List<CompetitorDTO> getCompetitorsInLeaderboard(String leaderboardName) {
|
||||
logger.log(Level.INFO, "getCompetitorsInLeaderboard(...) Request.");
|
||||
Leaderboard lb = getRacingEventService().getLeaderboardByName(leaderboardName);
|
||||
return baseDomainFactory.getCompetitorDTOList(lb.getCompetitorsFromBestToWorst(new MillisecondsTimePoint(
|
||||
new Date())));
|
||||
}
|
||||
}
|
||||
-484
@@ -1,484 +0,0 @@
|
||||
package com.sap.sailing.dashboards.gwt.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.dashboards.gwt.client.RibDashboardEntryPoint;
|
||||
import com.sap.sailing.dashboards.gwt.client.startanalysis.StartlineAdvantageType;
|
||||
import com.sap.sailing.dashboards.gwt.client.startanalysis.rankingtable.StartAnalysisStartRankTable;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisCompetitorDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisRankingTableEntryDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.WindAndAdvantagesInfoForStartLineDTO;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.LineDetails;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
|
||||
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.MarkDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.SpeedWithBearingDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.WindDTO;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
/**
|
||||
* The task of StartAnalyisisRacesStore is to cache StartAnalysisDTOs for Competitors at one day. At initialization it
|
||||
* generates StartAnalysisDTOs for Competitors from races started before initialization time and generates
|
||||
* StartAnalysisDTOs for Competitors from races that are starting when the server is running. It achieves this basically
|
||||
* by registering as RaceChangeListener and receiving so markRoundings for competitors.
|
||||
*/
|
||||
public class StartAnalysisRacesStore {
|
||||
|
||||
private final com.sap.sailing.domain.base.DomainFactory baseDomainFactory;
|
||||
|
||||
/**
|
||||
* {@link StartAnalyisisRacesStoreListener} get notified at after initialization and after the change of
|
||||
* {@link #startAnalysisDTOListForCompetitorName}
|
||||
* */
|
||||
private List<StartAnalysisRacesStoreListener> listeners;
|
||||
|
||||
/**
|
||||
* Caches a list of chronologically sorted {@link StartAnalysisDTO} for names from Competitors. After any change of
|
||||
* this field {@link #notifyListernersAboutStartAnalysisDTOsChanges()} get called.
|
||||
* */
|
||||
private Map<String, List<StartAnalysisDTO>> startAnalysisDTOListForCompetitorName;
|
||||
|
||||
/**
|
||||
* Contains a ranking list of competitor at mark one for every race
|
||||
* */
|
||||
private Map<TrackedRace, List<Competitor>> rankingListAtMarkOneForTrackedRace;
|
||||
|
||||
/**
|
||||
* Like {@link startAnalysisCompetitorDTOsForCompetitorNameForTrackedRace} gpsFixesForCompetitorNameForTracedRace
|
||||
* contains the list of gps fixes for a competitor name at from 6 seconds at the start. Caching
|
||||
* {@link gpsFixesForCompetitorNameForTracedRace}s brings the advantage of faster code at creating finished
|
||||
* {@link #startAnalysisDTOListForCompetitorName}.
|
||||
* */
|
||||
private Map<TrackedRace, Map<String, List<GPSFixDTO>>> gpsFixesPathBeforeStartForCompetitor;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RibDashboardEntryPoint.class.getName());
|
||||
/**
|
||||
* Minimum number of competitors in {@link StartAnalysisStartRankTable}
|
||||
* */
|
||||
private final int MINIMUM_NUMBER_OF_COMPETITORS_IN_STARTANALYSISRANKINGTABLE = 3;
|
||||
private final int TAILLENGHT_IN_MILLISECONDS = 200000;
|
||||
|
||||
/**
|
||||
* Calls {@link #generateStartAnalysisDTOsForCompetitorNamesFromRacesStartedBeforeClassInitialization()} to create
|
||||
* startanalysisDTO for races that started before class initialization.
|
||||
*/
|
||||
public StartAnalysisRacesStore(RacingEventService racingEventService) {
|
||||
|
||||
baseDomainFactory = racingEventService.getBaseDomainFactory();
|
||||
this.listeners = new ArrayList<StartAnalysisRacesStoreListener>();
|
||||
|
||||
startAnalysisDTOListForCompetitorName = new HashMap<String, List<StartAnalysisDTO>>();
|
||||
rankingListAtMarkOneForTrackedRace = new HashMap<TrackedRace, List<Competitor>>();
|
||||
gpsFixesPathBeforeStartForCompetitor = new HashMap<TrackedRace, Map<String, List<GPSFixDTO>>>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Index of the Mark in the Race. Is used in
|
||||
* {@link #markPassingReceived(Competitor, Map, Iterable, TrackedRace)} to identify just markpassings at mark one,
|
||||
* because the position of a boat at mark one defines the performance/startingrank of the race
|
||||
*/
|
||||
private int getIndexOfMarkPassingMark(Iterable<MarkPassing> markPassings, TrackedRace trackedRace) {
|
||||
List<MarkPassing> markPassingsList = listFromIterator(markPassings.iterator());
|
||||
return trackedRace.getRace().getCourse()
|
||||
.getIndexOfWaypoint(markPassingsList.get(markPassingsList.size() - 1).getWaypoint());
|
||||
}
|
||||
|
||||
private List<Competitor> getOrCreateAndAddRankingListAtMarkOneForTrackedRace(TrackedRace trackedRace) {
|
||||
if (!rankingListAtMarkOneForTrackedRace.containsKey(trackedRace)) {
|
||||
List<Competitor> rankingListAtMarkOneForRace = new ArrayList<Competitor>();
|
||||
rankingListAtMarkOneForTrackedRace.put(trackedRace, rankingListAtMarkOneForRace);
|
||||
}
|
||||
return rankingListAtMarkOneForTrackedRace.get(trackedRace);
|
||||
}
|
||||
|
||||
private List<StartAnalysisDTO> getOrCreateAndAddStartAnalysisDTOListForCompetitorName(String competitorName) {
|
||||
if (!startAnalysisDTOListForCompetitorName.containsKey(competitorName)) {
|
||||
List<StartAnalysisDTO> startAnalysisDTOList = new ArrayList<StartAnalysisDTO>();
|
||||
startAnalysisDTOListForCompetitorName.put(competitorName, startAnalysisDTOList);
|
||||
}
|
||||
return startAnalysisDTOListForCompetitorName.get(competitorName);
|
||||
}
|
||||
|
||||
private StartAnalysisDTO createStartAnalysisDTOForCompetitor(Competitor competitor, TrackedRace trackedRace) {
|
||||
StartAnalysisDTO startAnalysisDTO = createStartAnalysisDTOWithOnlyStaticData(trackedRace);
|
||||
List<StartAnalysisCompetitorDTO> competitors = new ArrayList<StartAnalysisCompetitorDTO>();
|
||||
List<Competitor> rankingList = getOrCreateAndAddRankingListAtMarkOneForTrackedRace(trackedRace);
|
||||
|
||||
boolean isCompetitorBetweenFirstThree = false;
|
||||
for (int i = 0; i < MINIMUM_NUMBER_OF_COMPETITORS_IN_STARTANALYSISRANKINGTABLE; i++) {
|
||||
competitors.add(createStartAnalysisCompetitorDTO(trackedRace, i + 1,
|
||||
getOrCreateAndAddRankingListAtMarkOneForTrackedRace(trackedRace).get(i)));
|
||||
if (rankingList.get(i).equals(competitor)) {
|
||||
isCompetitorBetweenFirstThree = true;
|
||||
}
|
||||
}
|
||||
if (!isCompetitorBetweenFirstThree) {
|
||||
competitors.add(createStartAnalysisCompetitorDTO(trackedRace,
|
||||
getOrCreateAndAddRankingListAtMarkOneForTrackedRace(trackedRace).size(), competitor));
|
||||
}
|
||||
startAnalysisDTO.startAnalysisCompetitorDTOs = competitors;
|
||||
return startAnalysisDTO;
|
||||
}
|
||||
|
||||
private List<MarkPassing> listFromIterator(Iterator<MarkPassing> iterator) {
|
||||
List<MarkPassing> result = new ArrayList<MarkPassing>();
|
||||
while (iterator.hasNext()) {
|
||||
result.add(iterator.next());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private StartAnalysisDTO createStartAnalysisDTOWithOnlyStaticData(TrackedRace trackedRace) {
|
||||
StartAnalysisDTO startAnalysisDTO = new StartAnalysisDTO();
|
||||
startAnalysisDTO.raceName = trackedRace.getRace().getName();
|
||||
startAnalysisDTO.startLineMarkPositions = getStartLineBoyPositions(trackedRace);
|
||||
startAnalysisDTO.firstMark = getMarksOfWayPoint(trackedRace, getFirstMarkWayPoint(trackedRace)).get(0);
|
||||
startAnalysisDTO.startAnalysisWindLineInfoDTO = createStartAnalysisWindAndLineData(trackedRace);
|
||||
startAnalysisDTO.startLineMarks = getMarksOfWayPoint(trackedRace,
|
||||
trackedRace.getStartLine(trackedRace.getStartTimeReceived()).getWaypoint());
|
||||
return startAnalysisDTO;
|
||||
}
|
||||
|
||||
private Map<String, Date> createPerCompetitorIdAsString(TrackedRace currentRace, Date fiveSecondsBeforeStart) {
|
||||
Map<String, Date> fromPerCompetitorIdAsString = new HashMap<String, Date>();
|
||||
for (Competitor competitor : currentRace.getCompetitorsFromBestToWorst(new MillisecondsTimePoint(new Date()
|
||||
.getTime()))) {
|
||||
fromPerCompetitorIdAsString.put(competitor.getId().toString(), fiveSecondsBeforeStart);
|
||||
}
|
||||
return fromPerCompetitorIdAsString;
|
||||
}
|
||||
|
||||
private StartAnalysisRankingTableEntryDTO createRankTableEntry(TrackedRace trackedRace, int rank,
|
||||
Competitor competitor) {
|
||||
StartAnalysisRankingTableEntryDTO startAnalysisRankTableEntryDTO = createStartAnalysisRankTableEntryDTOWithRankAndStartTimepoint(
|
||||
competitor, rank, trackedRace);
|
||||
return startAnalysisRankTableEntryDTO;
|
||||
}
|
||||
|
||||
private StartAnalysisRankingTableEntryDTO createStartAnalysisRankTableEntryDTOWithRankAndStartTimepoint(
|
||||
Competitor competitor, int rank, TrackedRace trackedRace) {
|
||||
StartAnalysisRankingTableEntryDTO tableentry = new StartAnalysisRankingTableEntryDTO();
|
||||
tableentry.rankAtFirstMark = rank;
|
||||
tableentry.teamName = competitor.getName();
|
||||
tableentry.speedAtStartTime = trackedRace.getSpeed(competitor, 1).getKnots();
|
||||
tableentry.distanceToLineAtStartTime = trackedRace.getDistanceToStartLine(competitor, 1).getMeters();
|
||||
tableentry.tailColor = competitor.getColor().getAsHtml();
|
||||
return tableentry;
|
||||
}
|
||||
|
||||
private List<PositionDTO> getStartLineBoyPositions(TrackedRace trackedRace) {
|
||||
return getMarkPositionDTOs(trackedRace.getStartTimeReceived(), trackedRace, trackedRace.getRace().getCourse()
|
||||
.getFirstWaypoint());
|
||||
}
|
||||
|
||||
private Waypoint getFirstMarkWayPoint(TrackedRace trackedRace) {
|
||||
Waypoint firstMarkWayPoint = null;
|
||||
Iterator<Waypoint> waypoints = trackedRace.getRace().getCourse().getWaypoints().iterator();
|
||||
int wayPointCounter = 0;
|
||||
while (waypoints.hasNext()) {
|
||||
Waypoint wayPoint = waypoints.next();
|
||||
if (wayPointCounter == 1) {
|
||||
return wayPoint;
|
||||
}
|
||||
wayPointCounter++;
|
||||
}
|
||||
return firstMarkWayPoint;
|
||||
}
|
||||
|
||||
private List<PositionDTO> getMarkPositionDTOs(TimePoint timePoint, TrackedRace trackedRace, Waypoint waypoint) {
|
||||
|
||||
List<PositionDTO> markPositionDTOs = new ArrayList<PositionDTO>();
|
||||
for (Mark startMark : waypoint.getMarks()) {
|
||||
final Position estimatedMarkPosition = trackedRace.getOrCreateTrack(startMark).getEstimatedPosition(
|
||||
timePoint, /* extrapolate */false);
|
||||
if (estimatedMarkPosition != null) {
|
||||
markPositionDTOs.add(new PositionDTO(estimatedMarkPosition.getLatDeg(), estimatedMarkPosition
|
||||
.getLngDeg()));
|
||||
}
|
||||
}
|
||||
return markPositionDTOs;
|
||||
}
|
||||
|
||||
private List<MarkDTO> getMarksOfWayPoint(TrackedRace trackedRace, Waypoint wayPoint) {
|
||||
List<MarkDTO> startLineMarks = new ArrayList<MarkDTO>();
|
||||
for (Mark startMark : wayPoint.getMarks()) {
|
||||
final Position estimatedMarkPosition = trackedRace.getOrCreateTrack(startMark).getEstimatedPosition(
|
||||
trackedRace.getStartTimeReceived(), /* extrapolate */false);
|
||||
if (estimatedMarkPosition != null) {
|
||||
startLineMarks.add(convertToMarkDTO(startMark, estimatedMarkPosition));
|
||||
}
|
||||
}
|
||||
return startLineMarks;
|
||||
}
|
||||
|
||||
private MarkDTO convertToMarkDTO(Mark mark, Position position) {
|
||||
MarkDTO markDTO;
|
||||
if (position != null) {
|
||||
markDTO = new MarkDTO(mark.getId().toString(), mark.getName(), position.getLatDeg(), position.getLngDeg());
|
||||
} else {
|
||||
markDTO = new MarkDTO(mark.getId().toString(), mark.getName());
|
||||
}
|
||||
markDTO.color = mark.getColor();
|
||||
markDTO.shape = mark.getShape();
|
||||
markDTO.pattern = mark.getPattern();
|
||||
markDTO.type = mark.getType();
|
||||
|
||||
return markDTO;
|
||||
}
|
||||
|
||||
public void addStartAnalyisisRacesStoreListener(StartAnalysisRacesStoreListener startAnalyisisRacesStoreListener) {
|
||||
listeners.add(startAnalyisisRacesStoreListener);
|
||||
}
|
||||
|
||||
private WindAndAdvantagesInfoForStartLineDTO createStartAnalysisWindAndLineData(TrackedRace trackedRace) {
|
||||
WindAndAdvantagesInfoForStartLineDTO startAnalysisWindLineInfoDTO = new WindAndAdvantagesInfoForStartLineDTO();
|
||||
LineDetails startline = trackedRace.getStartLine(trackedRace.getStartTimeReceived());
|
||||
StartLineAdvantageDTO startLineAdvantageDTO = new StartLineAdvantageDTO();
|
||||
startLineAdvantageDTO.startLineAdvatageType = getStartlineAdvantageType(trackedRace, new MillisecondsTimePoint(new Date()));
|
||||
startLineAdvantageDTO.startLineAdvantage = startline.getAdvantage().getMeters();
|
||||
startAnalysisWindLineInfoDTO.startLineAdvantage = startLineAdvantageDTO;
|
||||
Position portMarkPosition = trackedRace.getOrCreateTrack(
|
||||
trackedRace.getStartLine(trackedRace.getStartTimeReceived()).getStarboardMarkWhileApproachingLine())
|
||||
.getEstimatedPosition(trackedRace.getStartTimeReceived(), /* extrapolate */
|
||||
false);
|
||||
Wind windAtStart = trackedRace.getWind(portMarkPosition, trackedRace.getStartTimeReceived());
|
||||
startAnalysisWindLineInfoDTO.windDirectionInDegrees = windAtStart.getBearing().getDegrees();
|
||||
startAnalysisWindLineInfoDTO.windSpeedInKnots = windAtStart.getKnots();
|
||||
return startAnalysisWindLineInfoDTO;
|
||||
}
|
||||
|
||||
private StartlineAdvantageType getStartlineAdvantageType(TrackedRace trackedRace, TimePoint timePoint) {
|
||||
try {
|
||||
LegType typeOfFirstLeg;
|
||||
typeOfFirstLeg = getFirstLegTypeOfTrackedRaceAtTimePoint(trackedRace, timePoint);
|
||||
switch (typeOfFirstLeg) {
|
||||
case UPWIND:
|
||||
return StartlineAdvantageType.WIND;
|
||||
case REACHING:
|
||||
return StartlineAdvantageType.GEOMETRIC;
|
||||
default:
|
||||
return StartlineAdvantageType.WIND;
|
||||
}
|
||||
} catch (NoWindException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyListernersAboutStartAnalysisDTOChange() {
|
||||
for (StartAnalysisRacesStoreListener startAnalyisisRacesStoreListener : listeners) {
|
||||
startAnalyisisRacesStoreListener.startAnalyisisRacesChanged(startAnalysisDTOListForCompetitorName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a List of GPSFixDTOs for every competitor name in tracked race
|
||||
* */
|
||||
private Map<String, List<GPSFixDTO>> getGPSFixDTOListForCompetitorName(TrackedRace trackedRace,
|
||||
Map<String, Date> fromPerCompetitorIdAsString, Map<String, Date> toPerCompetitorIdAsString,
|
||||
boolean extrapolate) throws NoWindException {
|
||||
Map<String, List<GPSFixDTO>> result = new HashMap<String, List<GPSFixDTO>>();
|
||||
if (trackedRace != null) {
|
||||
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
|
||||
if (fromPerCompetitorIdAsString.containsKey(competitor.getId().toString())) {
|
||||
CompetitorDTO competitorDTO = baseDomainFactory.convertToCompetitorDTO(competitor);
|
||||
List<GPSFixDTO> fixesForCompetitor = new ArrayList<GPSFixDTO>();
|
||||
result.put(competitorDTO.getName(), fixesForCompetitor);
|
||||
GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
|
||||
TimePoint fromTimePoint = new MillisecondsTimePoint(fromPerCompetitorIdAsString.get(competitorDTO
|
||||
.getIdAsString()));
|
||||
TimePoint toTimePoint = new MillisecondsTimePoint(toPerCompetitorIdAsString.get(competitorDTO
|
||||
.getIdAsString()));
|
||||
// copy the fixes into a list while holding the monitor;
|
||||
// then release the monitor to avoid deadlocks
|
||||
// during wind estimations required for tack determination
|
||||
List<GPSFixMoving> fixes = new ArrayList<GPSFixMoving>();
|
||||
track.lockForRead();
|
||||
try {
|
||||
Iterator<GPSFixMoving> fixIter = track.getFixesIterator(fromTimePoint, /* inclusive */
|
||||
true);
|
||||
while (fixIter.hasNext()) {
|
||||
GPSFixMoving fix = fixIter.next();
|
||||
if (fix.getTimePoint().after(fromTimePoint) && fix.getTimePoint().before(toTimePoint)) {
|
||||
fixes.add(fix);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
|
||||
Iterator<GPSFixMoving> fixIter = fixes.iterator();
|
||||
while (fixIter.hasNext()) {
|
||||
GPSFixMoving fix = fixIter.next();
|
||||
Wind wind = trackedRace.getWind(fix.getPosition(), toTimePoint);
|
||||
final SpeedWithBearing estimatedSpeed = track.getEstimatedSpeed(fix.getTimePoint());
|
||||
Tack tack = wind == null ? null : trackedRace.getTack(estimatedSpeed, wind, fix.getTimePoint());
|
||||
LegType legType = null;
|
||||
WindDTO windDTO = wind == null ? null : createWindDTOFromAlreadyAveraged(wind, toTimePoint);
|
||||
GPSFixDTO fixDTO = createGPSFixDTO(fix, estimatedSpeed, windDTO, tack, legType, /* extrapolate */
|
||||
false);
|
||||
fixesForCompetitor.add(fixDTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected WindDTO createWindDTOFromAlreadyAveraged(Wind wind, TimePoint requestTimepoint) {
|
||||
WindDTO windDTO = new WindDTO();
|
||||
windDTO.requestTimepoint = requestTimepoint.asMillis();
|
||||
windDTO.trueWindBearingDeg = wind.getBearing().getDegrees();
|
||||
windDTO.trueWindFromDeg = wind.getBearing().reverse().getDegrees();
|
||||
windDTO.trueWindSpeedInKnots = wind.getKnots();
|
||||
windDTO.trueWindSpeedInMetersPerSecond = wind.getMetersPerSecond();
|
||||
windDTO.dampenedTrueWindBearingDeg = wind.getBearing().getDegrees();
|
||||
windDTO.dampenedTrueWindFromDeg = wind.getBearing().reverse().getDegrees();
|
||||
windDTO.dampenedTrueWindSpeedInKnots = wind.getKnots();
|
||||
windDTO.dampenedTrueWindSpeedInMetersPerSecond = wind.getMetersPerSecond();
|
||||
if (wind.getPosition() != null) {
|
||||
windDTO.position = new PositionDTO(wind.getPosition().getLatDeg(), wind.getPosition().getLngDeg());
|
||||
}
|
||||
if (wind.getTimePoint() != null) {
|
||||
windDTO.measureTimepoint = wind.getTimePoint().asMillis();
|
||||
}
|
||||
return windDTO;
|
||||
}
|
||||
|
||||
private SpeedWithBearingDTO createSpeedWithBearingDTO(SpeedWithBearing speedWithBearing) {
|
||||
return new SpeedWithBearingDTO(speedWithBearing.getKnots(), speedWithBearing.getBearing().getDegrees());
|
||||
}
|
||||
|
||||
private GPSFixDTO createGPSFixDTO(GPSFix fix, SpeedWithBearing speedWithBearing, WindDTO windDTO, Tack tack,
|
||||
LegType legType, boolean extrapolated) {
|
||||
return new GPSFixDTO(fix.getTimePoint().asDate(), fix.getPosition() == null ? null : new PositionDTO(fix
|
||||
.getPosition().getLatDeg(), fix.getPosition().getLngDeg()), speedWithBearing == null ? null
|
||||
: createSpeedWithBearingDTO(speedWithBearing), windDTO, tack, legType, extrapolated);
|
||||
}
|
||||
|
||||
private LegType getFirstLegTypeOfTrackedRaceAtTimePoint(TrackedRace trackedRace, TimePoint timePoint)
|
||||
throws NoWindException {
|
||||
Iterable<TrackedLeg> trackedLegs = trackedRace.getTrackedLegs();
|
||||
if (trackedLegs != null && trackedLegs.iterator().hasNext()) {
|
||||
TrackedLeg firstLegInTrackedRace = trackedLegs.iterator().next();
|
||||
return firstLegInTrackedRace.getLegType(timePoint);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private StartAnalysisCompetitorDTO createStartAnalysisCompetitorDTO(TrackedRace trackedRace, int rank,
|
||||
Competitor competitor) {
|
||||
StartAnalysisCompetitorDTO startAnalysisCompetitorDTOsForRace = new StartAnalysisCompetitorDTO();
|
||||
startAnalysisCompetitorDTOsForRace.competitorDTO = baseDomainFactory.convertToCompetitorDTO(competitor);
|
||||
startAnalysisCompetitorDTOsForRace.rankingTableEntryDTO = createRankTableEntry(trackedRace, rank, competitor);
|
||||
List<GPSFixDTO> boatPositions = getOrCreateGPSFixDTOsForCompetitorForTrackedRace(trackedRace).get(
|
||||
competitor.getName());
|
||||
startAnalysisCompetitorDTOsForRace.gpsFixDTOs = boatPositions;
|
||||
return startAnalysisCompetitorDTOsForRace;
|
||||
}
|
||||
|
||||
private Map<String, List<GPSFixDTO>> getOrCreateGPSFixDTOsForCompetitorForTrackedRace(TrackedRace trackedRace) {
|
||||
try {
|
||||
if (!gpsFixesPathBeforeStartForCompetitor.containsKey(trackedRace)) {
|
||||
gpsFixesPathBeforeStartForCompetitor.put(
|
||||
trackedRace,
|
||||
getGPSFixDTOListForCompetitorName(
|
||||
trackedRace,
|
||||
createPerCompetitorIdAsString(trackedRace, new Date(trackedRace.getStartTimeReceived()
|
||||
.asMillis() - TAILLENGHT_IN_MILLISECONDS)),
|
||||
createPerCompetitorIdAsString(trackedRace, new Date(trackedRace.getStartTimeReceived()
|
||||
.asMillis())), true));
|
||||
}
|
||||
} catch (NoWindException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return gpsFixesPathBeforeStartForCompetitor.get(trackedRace);
|
||||
}
|
||||
|
||||
public static List<StartAnalysisDTO> cloneList(List<StartAnalysisDTO> list) {
|
||||
List<StartAnalysisDTO> clone = new ArrayList<StartAnalysisDTO>(list.size());
|
||||
for (StartAnalysisDTO item : list)
|
||||
clone.add(item);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public void addAsListener(TrackedRace trackedRace) {
|
||||
trackedRace.addListener(new Listener(trackedRace));
|
||||
}
|
||||
|
||||
private class Listener extends AbstractRaceChangeListener {
|
||||
private final TrackedRace trackedRace;
|
||||
|
||||
protected Listener(TrackedRace trackedRace) {
|
||||
this.trackedRace = trackedRace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markPassingReceived(Competitor competitor, Map<Waypoint, MarkPassing> oldMarkPassings,
|
||||
Iterable<MarkPassing> markPassings) {
|
||||
logger.log(Level.INFO, "Received Mark Passing " + competitor.getName());
|
||||
if (markPassings.iterator().hasNext()) {
|
||||
if (getIndexOfMarkPassingMark(markPassings, trackedRace) == 1) {
|
||||
logger.log(Level.INFO, "Received Mark Passing " + competitor.getName() + " Mark 1");
|
||||
if (!getOrCreateAndAddRankingListAtMarkOneForTrackedRace(trackedRace).contains(competitor)) {
|
||||
getOrCreateAndAddRankingListAtMarkOneForTrackedRace(trackedRace).add(competitor);
|
||||
logger.log(Level.INFO, "Received Mark Passing " + competitor.getName() + " RankingList Size"
|
||||
+ getOrCreateAndAddRankingListAtMarkOneForTrackedRace(trackedRace).size());
|
||||
if (getOrCreateAndAddRankingListAtMarkOneForTrackedRace(trackedRace).size() == MINIMUM_NUMBER_OF_COMPETITORS_IN_STARTANALYSISRANKINGTABLE) {
|
||||
for (Competitor competitorInRankingList : getOrCreateAndAddRankingListAtMarkOneForTrackedRace(trackedRace)) {
|
||||
getOrCreateAndAddStartAnalysisDTOListForCompetitorName(
|
||||
competitorInRankingList.getName()).add(
|
||||
createStartAnalysisDTOForCompetitor(competitorInRankingList, trackedRace));
|
||||
}
|
||||
logger.log(Level.INFO, "Received Mark Passing "
|
||||
+ competitor.getName()
|
||||
+ " StartAnalysisDTOlist for competitor size: "
|
||||
+ getOrCreateAndAddStartAnalysisDTOListForCompetitorName(competitor.getName())
|
||||
.size());
|
||||
notifyListernersAboutStartAnalysisDTOChange();
|
||||
} else if (getOrCreateAndAddRankingListAtMarkOneForTrackedRace(trackedRace).size() > MINIMUM_NUMBER_OF_COMPETITORS_IN_STARTANALYSISRANKINGTABLE) {
|
||||
getOrCreateAndAddStartAnalysisDTOListForCompetitorName(competitor.getName()).add(
|
||||
createStartAnalysisDTOForCompetitor(competitor, trackedRace));
|
||||
logger.log(Level.INFO, "Received Mark Passing "
|
||||
+ competitor.getName()
|
||||
+ " StartAnalysisDTOlist for competitor size: "
|
||||
+ getOrCreateAndAddStartAnalysisDTOListForCompetitorName(competitor.getName())
|
||||
.size());
|
||||
notifyListernersAboutStartAnalysisDTOChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package com.sap.sailing.dashboards.gwt.server;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
|
||||
|
||||
public interface StartAnalysisRacesStoreListener {
|
||||
|
||||
public void startAnalyisisRacesChanged(Map<String , List<StartAnalysisDTO>> startAnalysisDTOs);
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.sap.sailing.dashboards.gwt.server.startanalysis;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
public abstract class AbstractStartAnalysisCreationValidator {
|
||||
|
||||
private static int MINIMUM_NUMBER_COMPETITORS_FOR_STARTANALYSIS = 3;
|
||||
|
||||
protected boolean threeCompetitorsPassedSecondWayPoint(TrackedRace trackedRace){
|
||||
Waypoint secondWaypoint = trackedRace.getRace().getCourse().getFirstLeg().getTo();
|
||||
Iterator<MarkPassing> markPassingsInOrder = trackedRace.getMarkPassingsInOrder(secondWaypoint).iterator();
|
||||
int counter = 0;
|
||||
while (markPassingsInOrder.hasNext()) {
|
||||
markPassingsInOrder.next();
|
||||
counter ++;
|
||||
}
|
||||
return counter >= MINIMUM_NUMBER_COMPETITORS_FOR_STARTANALYSIS ? true : false;
|
||||
}
|
||||
|
||||
protected boolean competitorPassedSecondWayPoint(Competitor competitor, TrackedRace trackedRace){
|
||||
Waypoint secondWaypoint = trackedRace.getRace().getCourse().getFirstLeg().getTo();
|
||||
return trackedRace.getMarkPassing(competitor, secondWaypoint) == null ? false : true;
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.sap.sailing.dashboards.gwt.server.startanalysis;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public class StartAnalysisCreationController extends AbstractStartAnalysisCreationValidator {
|
||||
|
||||
private StartAnalysisDTOFactory startAnalysisDTOFactory;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(StartAnalysisCreationController.class.getName());
|
||||
|
||||
public StartAnalysisCreationController(RacingEventService racingEventService) {
|
||||
startAnalysisDTOFactory = new StartAnalysisDTOFactory(racingEventService);
|
||||
}
|
||||
|
||||
public StartAnalysisDTO checkStartAnalysisForCompetitorInTrackedRace(Competitor competitor, TrackedRace trackedRace) {
|
||||
StartAnalysisDTO startAnalysisDTO;
|
||||
if (threeCompetitorsPassedSecondWayPoint(trackedRace) &&
|
||||
competitorPassedSecondWayPoint(competitor, trackedRace))
|
||||
{
|
||||
logger.log(Level.INFO, "Trigger StartAnalysisDTO creation");
|
||||
startAnalysisDTO = startAnalysisDTOFactory.createStartAnalysisForCompetitorAndTrackedRace(competitor, trackedRace);
|
||||
return startAnalysisDTO;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
package com.sap.sailing.dashboards.gwt.server.startanalysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.dashboards.gwt.client.startanalysis.StartlineAdvantageType;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisCompetitorDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisRankingTableEntryDTO;
|
||||
import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.WindAndAdvantagesInfoForStartLineDTO;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.tracking.LineDetails;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValidator{
|
||||
|
||||
private final com.sap.sailing.domain.base.DomainFactory baseDomainFactory;
|
||||
|
||||
private static int MINIMUM_NUMBER_COMPETITORS_FOR_STARTANALYSIS = 3;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(StartAnalysisDTOFactory.class.getName());
|
||||
|
||||
public StartAnalysisDTOFactory(RacingEventService racingEventService){
|
||||
baseDomainFactory = racingEventService.getBaseDomainFactory();
|
||||
}
|
||||
|
||||
public StartAnalysisDTO createStartAnalysisForCompetitorAndTrackedRace(Competitor competitor, TrackedRace trackedRace) {
|
||||
StartAnalysisDTO startAnalysisDTO = new StartAnalysisDTO();
|
||||
addStaticDataToStartAnalysisDTOFrom(startAnalysisDTO, trackedRace);
|
||||
List<StartAnalysisCompetitorDTO> competitors = new ArrayList<StartAnalysisCompetitorDTO>();
|
||||
Waypoint secondWaypoint = trackedRace.getRace().getCourse().getFirstLeg().getTo();
|
||||
List<MarkPassing> markPassingsInOrder = convertMarkpPassingsIteratorToList(trackedRace.getMarkPassingsInOrder(secondWaypoint).iterator());
|
||||
|
||||
boolean isCompetitorOneOfFirstThree = false;
|
||||
for (int i = 0; i < MINIMUM_NUMBER_COMPETITORS_FOR_STARTANALYSIS; i++) {
|
||||
competitors.add(createStartAnalysisCompetitorDTO(trackedRace, i + 1,
|
||||
markPassingsInOrder.get(i).getCompetitor()));
|
||||
if (markPassingsInOrder.get(i).getCompetitor().equals(competitor)) {
|
||||
isCompetitorOneOfFirstThree = true;
|
||||
}
|
||||
}
|
||||
if (!isCompetitorOneOfFirstThree) {
|
||||
int rankOfCompetitorWhilePassingSecondWaypoint = getRankOfCompetitorWhilePassingSecondWaypoint(competitor, trackedRace);
|
||||
competitors.add(createStartAnalysisCompetitorDTO(trackedRace, rankOfCompetitorWhilePassingSecondWaypoint, competitor));
|
||||
}
|
||||
startAnalysisDTO.competitor = baseDomainFactory.getCompetitorStore().convertToCompetitorDTO(competitor);
|
||||
startAnalysisDTO.startAnalysisCompetitorDTOs = competitors;
|
||||
startAnalysisDTO.timeOfStartInMilliSeconds = trackedRace.getStartOfRace().asMillis();
|
||||
startAnalysisDTO.regattaAndRaceIdentifier = trackedRace.getRaceIdentifier();
|
||||
logger.log(Level.INFO, "Created StartAnalysis For Competitor "+competitor.getName()+" and "+trackedRace.getRace().getName());
|
||||
return startAnalysisDTO;
|
||||
}
|
||||
|
||||
private List<MarkPassing> convertMarkpPassingsIteratorToList(Iterator<MarkPassing> iterator){
|
||||
List<MarkPassing> list = new ArrayList<MarkPassing>();
|
||||
while(iterator.hasNext()){
|
||||
list.add(iterator.next());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private int getRankOfCompetitorWhilePassingSecondWaypoint(Competitor competitor, TrackedRace trackedRace){
|
||||
Waypoint secondWaypoint = trackedRace.getRace().getCourse().getFirstLeg().getTo();
|
||||
Iterator<MarkPassing> markPassings = trackedRace.getMarkPassingsInOrder(secondWaypoint).iterator();
|
||||
int counter = 0;
|
||||
while(markPassings.hasNext()){
|
||||
counter ++;
|
||||
if(markPassings.next().getCompetitor().getId().equals(competitor.getId()))
|
||||
return counter;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private StartAnalysisDTO addStaticDataToStartAnalysisDTOFrom(StartAnalysisDTO startAnalysisDTO,TrackedRace trackedRace) {
|
||||
startAnalysisDTO.raceName = trackedRace.getRace().getName();
|
||||
startAnalysisDTO.startAnalysisWindLineInfoDTO = createStartAnalysisWindAndLineData(trackedRace);
|
||||
return startAnalysisDTO;
|
||||
}
|
||||
|
||||
|
||||
private StartAnalysisRankingTableEntryDTO createRankTableEntry(TrackedRace trackedRace, int rank,
|
||||
Competitor competitor) {
|
||||
StartAnalysisRankingTableEntryDTO startAnalysisRankTableEntryDTO = createStartAnalysisRankTableEntryDTOWithRankAndStartTimepoint(
|
||||
competitor, rank, trackedRace);
|
||||
return startAnalysisRankTableEntryDTO;
|
||||
}
|
||||
|
||||
private StartAnalysisRankingTableEntryDTO createStartAnalysisRankTableEntryDTOWithRankAndStartTimepoint(
|
||||
Competitor competitor, int rank, TrackedRace trackedRace) {
|
||||
StartAnalysisRankingTableEntryDTO tableentry = new StartAnalysisRankingTableEntryDTO();
|
||||
tableentry.rankAtFirstMark = rank;
|
||||
tableentry.teamName = competitor.getName();
|
||||
tableentry.speedAtStartTime = trackedRace.getSpeed(competitor, 1).getKnots();
|
||||
tableentry.distanceToLineAtStartTime = trackedRace.getDistanceToStartLine(competitor, 1).getMeters();
|
||||
tableentry.tailColor = competitor.getColor().getAsHtml();
|
||||
return tableentry;
|
||||
}
|
||||
|
||||
private WindAndAdvantagesInfoForStartLineDTO createStartAnalysisWindAndLineData(TrackedRace trackedRace) {
|
||||
WindAndAdvantagesInfoForStartLineDTO startAnalysisWindLineInfoDTO = new WindAndAdvantagesInfoForStartLineDTO();
|
||||
LineDetails startline = trackedRace.getStartLine(trackedRace.getStartTimeReceived());
|
||||
StartLineAdvantageDTO startLineAdvantageDTO = new StartLineAdvantageDTO();
|
||||
startLineAdvantageDTO.startLineAdvatageType = getStartlineAdvantageType(trackedRace, new MillisecondsTimePoint(new Date()));
|
||||
startLineAdvantageDTO.startLineAdvantage = startline.getAdvantage().getMeters();
|
||||
startAnalysisWindLineInfoDTO.startLineAdvantage = startLineAdvantageDTO;
|
||||
Position portMarkPosition = trackedRace.getOrCreateTrack(
|
||||
trackedRace.getStartLine(trackedRace.getStartTimeReceived()).getStarboardMarkWhileApproachingLine())
|
||||
.getEstimatedPosition(trackedRace.getStartTimeReceived(), /* extrapolate */
|
||||
false);
|
||||
Wind windAtStart = trackedRace.getWind(portMarkPosition, trackedRace.getStartTimeReceived());
|
||||
startAnalysisWindLineInfoDTO.windDirectionInDegrees = windAtStart.getBearing().getDegrees();
|
||||
startAnalysisWindLineInfoDTO.windSpeedInKnots = windAtStart.getKnots();
|
||||
return startAnalysisWindLineInfoDTO;
|
||||
}
|
||||
|
||||
private StartlineAdvantageType getStartlineAdvantageType(TrackedRace trackedRace, TimePoint timePoint) {
|
||||
try {
|
||||
LegType typeOfFirstLeg;
|
||||
typeOfFirstLeg = getFirstLegTypeOfTrackedRaceAtTimePoint(trackedRace, timePoint);
|
||||
switch (typeOfFirstLeg) {
|
||||
case UPWIND:
|
||||
return StartlineAdvantageType.WIND;
|
||||
case REACHING:
|
||||
return StartlineAdvantageType.GEOMETRIC;
|
||||
default:
|
||||
return StartlineAdvantageType.WIND;
|
||||
}
|
||||
} catch (NoWindException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private LegType getFirstLegTypeOfTrackedRaceAtTimePoint(TrackedRace trackedRace, TimePoint timePoint)
|
||||
throws NoWindException {
|
||||
Iterable<TrackedLeg> trackedLegs = trackedRace.getTrackedLegs();
|
||||
if (trackedLegs != null && trackedLegs.iterator().hasNext()) {
|
||||
TrackedLeg firstLegInTrackedRace = trackedLegs.iterator().next();
|
||||
return firstLegInTrackedRace.getLegType(timePoint);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private StartAnalysisCompetitorDTO createStartAnalysisCompetitorDTO(TrackedRace trackedRace, int rank,
|
||||
Competitor competitor) {
|
||||
StartAnalysisCompetitorDTO startAnalysisCompetitorDTOsForRace = new StartAnalysisCompetitorDTO();
|
||||
startAnalysisCompetitorDTOsForRace.competitorDTO = baseDomainFactory.getCompetitorStore().convertToCompetitorDTO(competitor);
|
||||
startAnalysisCompetitorDTOsForRace.rankingTableEntryDTO = createRankTableEntry(trackedRace, rank, competitor);
|
||||
return startAnalysisCompetitorDTOsForRace;
|
||||
}
|
||||
}
|
||||
+2
-4
@@ -9,9 +9,7 @@ package com.sap.sailing.dashboards.gwt.shared;
|
||||
*/
|
||||
public enum ResponseMessage
|
||||
{
|
||||
OK,
|
||||
BETWEEN_RACES,
|
||||
NO_RACE_LIVE,
|
||||
NO_COMPETITOR_SELECTED
|
||||
RACE_LIVE,
|
||||
NO_RACE_LIVE
|
||||
}
|
||||
|
||||
-3
@@ -1,10 +1,8 @@
|
||||
package com.sap.sailing.dashboards.gwt.shared.dto.startanalysis;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
|
||||
|
||||
public class StartAnalysisCompetitorDTO implements Serializable{
|
||||
|
||||
@@ -12,5 +10,4 @@ public class StartAnalysisCompetitorDTO implements Serializable{
|
||||
|
||||
public CompetitorDTO competitorDTO;
|
||||
public StartAnalysisRankingTableEntryDTO rankingTableEntryDTO;
|
||||
public List<GPSFixDTO> gpsFixDTOs;
|
||||
}
|
||||
+17
-8
@@ -1,27 +1,36 @@
|
||||
package com.sap.sailing.dashboards.gwt.shared.dto.startanalysis;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.dto.PositionDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.MarkDTO;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
|
||||
public class StartAnalysisDTO implements Serializable, Comparable<StartAnalysisDTO>{
|
||||
public class StartAnalysisDTO implements Serializable, Comparable<StartAnalysisDTO> {
|
||||
|
||||
private static final long serialVersionUID = -1325150193180234561L;
|
||||
|
||||
public String raceName;
|
||||
public List<PositionDTO> startLineMarkPositions;
|
||||
public List<MarkDTO> startLineMarks;
|
||||
public MarkDTO firstMark;
|
||||
public CompetitorDTO competitor;
|
||||
public WindAndAdvantagesInfoForStartLineDTO startAnalysisWindLineInfoDTO;
|
||||
public List<StartAnalysisCompetitorDTO> startAnalysisCompetitorDTOs;
|
||||
public long timeOfStartInMilliSeconds;
|
||||
public RegattaAndRaceIdentifier regattaAndRaceIdentifier;
|
||||
|
||||
|
||||
public StartAnalysisDTO(){}
|
||||
public StartAnalysisDTO() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(StartAnalysisDTO o) {
|
||||
return raceName.compareTo(o.raceName);
|
||||
}
|
||||
|
||||
public List<CompetitorDTO> getCompetitorDTOsFromStartAnaylsisCompetitorDTOs() {
|
||||
List<CompetitorDTO> competitorDTOs = new ArrayList<CompetitorDTO>();
|
||||
for (StartAnalysisCompetitorDTO startAnalysisCompetitorDTO : startAnalysisCompetitorDTOs) {
|
||||
competitorDTOs.add(startAnalysisCompetitorDTO.competitorDTO);
|
||||
}
|
||||
return competitorDTOs;
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB |
+7
-6
@@ -15,6 +15,7 @@ import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
|
||||
import com.sap.sailing.datamining.test.util.ConcurrencyTestsUtil;
|
||||
import com.sap.sailing.datamining.test.util.NullProcessor;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
@@ -26,7 +27,7 @@ import com.sap.sse.datamining.components.Processor;
|
||||
public class TestLeaderboardGroupRetrievalProcessor {
|
||||
|
||||
private RacingEventService service;
|
||||
private Processor<RacingEventService, LeaderboardGroup> retriever;
|
||||
private Processor<RacingEventService, LeaderboardGroupWithContext> retriever;
|
||||
|
||||
private Collection<LeaderboardGroup> retrievedGroups;
|
||||
|
||||
@@ -36,16 +37,16 @@ public class TestLeaderboardGroupRetrievalProcessor {
|
||||
stub(service.getLeaderboardGroups()).toReturn(getGroupsInService());
|
||||
|
||||
retrievedGroups = new HashSet<>();
|
||||
Processor<LeaderboardGroup, Void> receiver = new NullProcessor<LeaderboardGroup, Void>(LeaderboardGroup.class, Void.class) {
|
||||
Processor<LeaderboardGroupWithContext, Void> receiver = new NullProcessor<LeaderboardGroupWithContext, Void>(LeaderboardGroupWithContext.class, Void.class) {
|
||||
@Override
|
||||
public void processElement(LeaderboardGroup element) {
|
||||
retrievedGroups.add(element);
|
||||
public void processElement(LeaderboardGroupWithContext element) {
|
||||
retrievedGroups.add(element.getLeaderboardGroup());
|
||||
}
|
||||
};
|
||||
|
||||
Collection<Processor<LeaderboardGroup, ?>> resultReceivers = new ArrayList<>();
|
||||
Collection<Processor<LeaderboardGroupWithContext, ?>> resultReceivers = new ArrayList<>();
|
||||
resultReceivers.add(receiver);
|
||||
retriever = new LeaderboardGroupRetrievalProcessor(ConcurrencyTestsUtil.getExecutor(), resultReceivers);
|
||||
retriever = new LeaderboardGroupRetrievalProcessor(ConcurrencyTestsUtil.getExecutor(), resultReceivers, 0);
|
||||
}
|
||||
|
||||
private Map<String, LeaderboardGroup> getGroupsInService() {
|
||||
|
||||
+4
-12
@@ -2,28 +2,20 @@ package com.sap.sailing.datamining.test.util;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.DataMiningExecutorService;
|
||||
|
||||
public class ConcurrencyTestsUtil {
|
||||
|
||||
private static final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
|
||||
private static ThreadPoolExecutor executor = createExecutor();
|
||||
private static final ExecutorService executor = new DataMiningExecutorService(THREAD_POOL_SIZE);
|
||||
|
||||
public static ThreadPoolExecutor getExecutor() {
|
||||
if (executor.isShutdown()) {
|
||||
executor = createExecutor();
|
||||
}
|
||||
public static ExecutorService getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
private static ThreadPoolExecutor createExecutor() {
|
||||
return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
}
|
||||
|
||||
public static void sleepFor(long milliseconds) {
|
||||
try {
|
||||
Thread.sleep(milliseconds);
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ public class NullProcessor<InputType, ResultType> extends AbstractProcessor<Inpu
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable failure) {
|
||||
|
||||
throw new RuntimeException("An error occured during the processing", failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sse.datamining.shared,
|
||||
com.sap.sse,
|
||||
com.sap.sse.common,
|
||||
org.eclipse.osgi
|
||||
org.eclipse.osgi,
|
||||
com.sap.sailing.polars
|
||||
Bundle-ClassPath: .
|
||||
Bundle-Activator: com.sap.sailing.datamining.Activator
|
||||
Bundle-ActivationPolicy: lazy
|
||||
+1
-1
@@ -43,5 +43,5 @@ Bft9=Sturm
|
||||
Bft10=schwerer Sturm
|
||||
Bft11=orkanartiger Sturm
|
||||
Bft12=Orkan
|
||||
RelativeRankInRace=Relativer Rang im Rennen
|
||||
RelativeScoreInRace=Relative Wertung im Rennen (0 am besten; 1 am schlechtesten)
|
||||
WindSpeedInBeaufort=Windgeschwindigkeit in Bft.
|
||||
+1
-1
@@ -43,5 +43,5 @@ Bft9=Strong gale
|
||||
Bft10=Storm
|
||||
Bft11=Violent storm
|
||||
Bft12=Hurricane
|
||||
RelativeRankInRace=Relative rank in race
|
||||
RelativeScoreInRace=Relative score in race (0 best; 1 worst)
|
||||
WindSpeedInBeaufort=Wind speed in Bft
|
||||
+3
-3
@@ -3,10 +3,10 @@ package com.sap.sailing.datamining;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasRaceResultOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasGPSFixContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.datamining.data.HasMarkPassingContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceResultOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
@@ -18,7 +18,7 @@ import com.sap.sailing.datamining.impl.components.MarkPassingRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.TrackedLegOfCompetitorRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.TrackedLegRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.TrackedRaceRetrievalProcessor;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.datamining.DataRetrieverChainDefinition;
|
||||
import com.sap.sse.datamining.impl.SimpleDataRetrieverChainDefinition;
|
||||
@@ -32,7 +32,7 @@ public class SailingDataRetrievalChainDefinitions {
|
||||
|
||||
final DataRetrieverChainDefinition<RacingEventService, HasLeaderboardContext> leaderboardRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
|
||||
RacingEventService.class, HasLeaderboardContext.class, "LeaderboardSailingDomainRetrieverChain");
|
||||
leaderboardRetrieverChainDefinition.startWith(LeaderboardGroupRetrievalProcessor.class, LeaderboardGroup.class, "LeaderboardGroup");
|
||||
leaderboardRetrieverChainDefinition.startWith(LeaderboardGroupRetrievalProcessor.class, LeaderboardGroupWithContext.class, "LeaderboardGroup");
|
||||
leaderboardRetrieverChainDefinition.endWith(LeaderboardGroupRetrievalProcessor.class, LeaderboardRetrievalProcessor.class,
|
||||
HasLeaderboardContext.class, "Leaderboard");
|
||||
|
||||
|
||||
+4
-1
@@ -1,9 +1,12 @@
|
||||
package com.sap.sailing.datamining.data;
|
||||
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
|
||||
public interface HasLeaderboardContext {
|
||||
|
||||
public Leaderboard getLeaderboard();
|
||||
Leaderboard getLeaderboard();
|
||||
|
||||
PolarDataService getPolarDataService();
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.sap.sailing.datamining.data;
|
||||
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
|
||||
public interface HasLeaderboardGroupContext {
|
||||
|
||||
LeaderboardGroup getLeaderboardGroup();
|
||||
|
||||
PolarDataService getPolarDataService();
|
||||
|
||||
}
|
||||
+3
-1
@@ -16,10 +16,12 @@ public interface HasRaceResultOfCompetitorContext {
|
||||
/**
|
||||
* 0 means the competitor won the race, 1 means the competitor ranked last
|
||||
*/
|
||||
@Statistic(messageKey="RelativeRankInRace", ordinal=3)
|
||||
@Statistic(messageKey="RelativeScoreInRace", ordinal=3, resultDecimals=2)
|
||||
public double getRelativeRank();
|
||||
|
||||
@Dimension(messageKey="WindSpeedInBeaufort")
|
||||
int getAverageWindSpeedInRoundedBeaufort();
|
||||
|
||||
@Dimension(messageKey="Regatta")
|
||||
String getRegattaName();
|
||||
}
|
||||
+4
-3
@@ -16,8 +16,8 @@ public class CompetitorOfRaceInLeaderboardRetrievalProcessor extends
|
||||
AbstractSimpleRetrievalProcessor<HasLeaderboardContext, HasRaceResultOfCompetitorContext> {
|
||||
|
||||
public CompetitorOfRaceInLeaderboardRetrievalProcessor(ExecutorService executor,
|
||||
Collection<Processor<HasRaceResultOfCompetitorContext, ?>> resultReceivers) {
|
||||
super(HasLeaderboardContext.class, HasRaceResultOfCompetitorContext.class, executor, resultReceivers);
|
||||
Collection<Processor<HasRaceResultOfCompetitorContext, ?>> resultReceivers, int retrievalLevel) {
|
||||
super(HasLeaderboardContext.class, HasRaceResultOfCompetitorContext.class, executor, resultReceivers, retrievalLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -25,7 +25,8 @@ public class CompetitorOfRaceInLeaderboardRetrievalProcessor extends
|
||||
Collection<HasRaceResultOfCompetitorContext> raceResultsOfCompetitor = new ArrayList<>();
|
||||
for (RaceColumn raceColumn : element.getLeaderboard().getRaceColumns()) {
|
||||
for (Competitor competitor : element.getLeaderboard().getCompetitors()) {
|
||||
HasRaceResultOfCompetitorContext raceResultOfCompetitorContext = new RaceResultOfCompetitorWithContext(element, raceColumn, competitor);
|
||||
HasRaceResultOfCompetitorContext raceResultOfCompetitorContext = new RaceResultOfCompetitorWithContext(element, raceColumn, competitor,
|
||||
element.getPolarDataService());
|
||||
raceResultsOfCompetitor.add(raceResultOfCompetitorContext);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -16,8 +16,8 @@ import com.sap.sse.datamining.impl.components.AbstractSimpleRetrievalProcessor;
|
||||
|
||||
public class GPSFixRetrievalProcessor extends AbstractSimpleRetrievalProcessor<HasTrackedLegOfCompetitorContext, HasGPSFixContext> {
|
||||
|
||||
public GPSFixRetrievalProcessor(ExecutorService executor, Collection<Processor<HasGPSFixContext, ?>> resultReceivers) {
|
||||
super(HasTrackedLegOfCompetitorContext.class, HasGPSFixContext.class, executor, resultReceivers);
|
||||
public GPSFixRetrievalProcessor(ExecutorService executor, Collection<Processor<HasGPSFixContext, ?>> resultReceivers, int retrievalLevel) {
|
||||
super(HasTrackedLegOfCompetitorContext.class, HasGPSFixContext.class, executor, resultReceivers, retrievalLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+13
-6
@@ -2,23 +2,30 @@ package com.sap.sailing.datamining.impl.components;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractSimpleRetrievalProcessor;
|
||||
|
||||
public class LeaderboardGroupRetrievalProcessor extends
|
||||
AbstractSimpleRetrievalProcessor<RacingEventService, LeaderboardGroup> {
|
||||
AbstractSimpleRetrievalProcessor<RacingEventService, LeaderboardGroupWithContext> {
|
||||
|
||||
public LeaderboardGroupRetrievalProcessor(ExecutorService executor,
|
||||
Collection<Processor<LeaderboardGroup, ?>> resultReceivers) {
|
||||
super(RacingEventService.class, LeaderboardGroup.class, executor, resultReceivers);
|
||||
Collection<Processor<LeaderboardGroupWithContext, ?>> resultReceivers, int retrievalLevel) {
|
||||
super(RacingEventService.class, LeaderboardGroupWithContext.class, executor, resultReceivers, retrievalLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<LeaderboardGroup> retrieveData(RacingEventService element) {
|
||||
return element.getLeaderboardGroups().values();
|
||||
protected Iterable<LeaderboardGroupWithContext> retrieveData(RacingEventService element) {
|
||||
final PolarDataService polarDataService = element.getPolarDataService();
|
||||
return element.getLeaderboardGroups()
|
||||
.values()
|
||||
.stream()
|
||||
.map(lg -> new LeaderboardGroupWithContext(lg, polarDataService))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
}
|
||||
+7
-7
@@ -5,25 +5,25 @@ import java.util.Collection;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
|
||||
import com.sap.sailing.datamining.impl.data.LeaderboardWithContext;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.impl.components.AbstractSimpleRetrievalProcessor;
|
||||
|
||||
public class LeaderboardRetrievalProcessor extends
|
||||
AbstractSimpleRetrievalProcessor<LeaderboardGroup, HasLeaderboardContext> {
|
||||
AbstractSimpleRetrievalProcessor<LeaderboardGroupWithContext, HasLeaderboardContext> {
|
||||
|
||||
public LeaderboardRetrievalProcessor(ExecutorService executor,
|
||||
Collection<Processor<HasLeaderboardContext, ?>> resultReceivers) {
|
||||
super(LeaderboardGroup.class, HasLeaderboardContext.class, executor, resultReceivers);
|
||||
Collection<Processor<HasLeaderboardContext, ?>> resultReceivers, int retrievalLevel) {
|
||||
super(LeaderboardGroupWithContext.class, HasLeaderboardContext.class, executor, resultReceivers, retrievalLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<HasLeaderboardContext> retrieveData(LeaderboardGroup element) {
|
||||
protected Iterable<HasLeaderboardContext> retrieveData(LeaderboardGroupWithContext element) {
|
||||
Collection<HasLeaderboardContext> leaderboardsWithContext = new ArrayList<>();
|
||||
for (Leaderboard leaderboard : element.getLeaderboards()) {
|
||||
leaderboardsWithContext.add(new LeaderboardWithContext(leaderboard));
|
||||
for (Leaderboard leaderboard : element.getLeaderboardGroup().getLeaderboards()) {
|
||||
leaderboardsWithContext.add(new LeaderboardWithContext(leaderboard, element.getPolarDataService()));
|
||||
}
|
||||
return leaderboardsWithContext;
|
||||
}
|
||||
|
||||
+2
-2
@@ -19,8 +19,8 @@ public class MarkPassingRetrievalProcessor extends
|
||||
AbstractSimpleRetrievalProcessor<HasTrackedRaceContext, HasMarkPassingContext> {
|
||||
|
||||
public MarkPassingRetrievalProcessor(ExecutorService executor,
|
||||
Collection<Processor<HasMarkPassingContext, ?>> resultReceivers) {
|
||||
super(HasTrackedRaceContext.class, HasMarkPassingContext.class, executor, resultReceivers);
|
||||
Collection<Processor<HasMarkPassingContext, ?>> resultReceivers, int retrievalLevel) {
|
||||
super(HasTrackedRaceContext.class, HasMarkPassingContext.class, executor, resultReceivers, retrievalLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -15,8 +15,8 @@ public class TrackedLegOfCompetitorRetrievalProcessor extends
|
||||
AbstractSimpleRetrievalProcessor<HasTrackedLegContext, HasTrackedLegOfCompetitorContext> {
|
||||
|
||||
public TrackedLegOfCompetitorRetrievalProcessor(ExecutorService executor,
|
||||
Collection<Processor<HasTrackedLegOfCompetitorContext, ?>> resultReceivers) {
|
||||
super(HasTrackedLegContext.class, HasTrackedLegOfCompetitorContext.class, executor, resultReceivers);
|
||||
Collection<Processor<HasTrackedLegOfCompetitorContext, ?>> resultReceivers, int retrievalLevel) {
|
||||
super(HasTrackedLegContext.class, HasTrackedLegOfCompetitorContext.class, executor, resultReceivers, retrievalLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -15,8 +15,8 @@ public class TrackedLegRetrievalProcessor extends
|
||||
AbstractSimpleRetrievalProcessor<HasTrackedRaceContext, HasTrackedLegContext> {
|
||||
|
||||
public TrackedLegRetrievalProcessor(ExecutorService executor,
|
||||
Collection<Processor<HasTrackedLegContext, ?>> resultReceivers) {
|
||||
super(HasTrackedRaceContext.class, HasTrackedLegContext.class, executor, resultReceivers);
|
||||
Collection<Processor<HasTrackedLegContext, ?>> resultReceivers, int retrievalLevel) {
|
||||
super(HasTrackedRaceContext.class, HasTrackedLegContext.class, executor, resultReceivers, retrievalLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ public class TrackedRaceRetrievalProcessor extends
|
||||
AbstractSimpleRetrievalProcessor<HasLeaderboardContext, HasTrackedRaceContext> {
|
||||
|
||||
public TrackedRaceRetrievalProcessor(ExecutorService executor,
|
||||
Collection<Processor<HasTrackedRaceContext, ?>> resultReceivers) {
|
||||
super(HasLeaderboardContext.class, HasTrackedRaceContext.class, executor, resultReceivers);
|
||||
Collection<Processor<HasTrackedRaceContext, ?>> resultReceivers, int retrievalLevel) {
|
||||
super(HasLeaderboardContext.class, HasTrackedRaceContext.class, executor, resultReceivers, retrievalLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
|
||||
public class LeaderboardGroupWithContext implements HasLeaderboardGroupContext {
|
||||
|
||||
private final LeaderboardGroup leaderboardGroup;
|
||||
private final PolarDataService polarDataService;
|
||||
|
||||
public LeaderboardGroupWithContext(LeaderboardGroup leaderboardGroup, PolarDataService polarDataService) {
|
||||
this.leaderboardGroup = leaderboardGroup;
|
||||
this.polarDataService = polarDataService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeaderboardGroup getLeaderboardGroup() {
|
||||
return leaderboardGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarDataService getPolarDataService() {
|
||||
return polarDataService;
|
||||
}
|
||||
|
||||
}
|
||||
+9
-1
@@ -2,13 +2,16 @@ package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
|
||||
public class LeaderboardWithContext implements HasLeaderboardContext {
|
||||
|
||||
private final Leaderboard leaderboard;
|
||||
private final PolarDataService polarDataService;
|
||||
|
||||
public LeaderboardWithContext(Leaderboard leaderboard) {
|
||||
public LeaderboardWithContext(Leaderboard leaderboard, PolarDataService polarDataService) {
|
||||
this.leaderboard = leaderboard;
|
||||
this.polarDataService = polarDataService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -16,4 +19,9 @@ public class LeaderboardWithContext implements HasLeaderboardContext {
|
||||
return leaderboard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolarDataService getPolarDataService() {
|
||||
return polarDataService;
|
||||
}
|
||||
|
||||
}
|
||||
+72
-16
@@ -1,35 +1,50 @@
|
||||
package com.sap.sailing.datamining.impl.data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceResultOfCompetitorContext;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableSpeed;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindWithConfidence;
|
||||
import com.sap.sailing.polars.PolarDataService;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompetitorContext {
|
||||
private final static Logger logger = Logger.getLogger(RaceResultOfCompetitorWithContext.class.getName());
|
||||
|
||||
private final HasLeaderboardContext leaderboardWithContext;
|
||||
private final RaceColumn raceColumn;
|
||||
private final Competitor competitor;
|
||||
private final PolarDataService polarDataService;
|
||||
|
||||
public RaceResultOfCompetitorWithContext(HasLeaderboardContext leaderboardWithContext, RaceColumn raceColumn, Competitor competitor) {
|
||||
public RaceResultOfCompetitorWithContext(HasLeaderboardContext leaderboardWithContext, RaceColumn raceColumn,
|
||||
Competitor competitor, PolarDataService polarDataService) {
|
||||
this.leaderboardWithContext = leaderboardWithContext;
|
||||
this.raceColumn = raceColumn;
|
||||
this.competitor = competitor;
|
||||
this.polarDataService = polarDataService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,20 +62,23 @@ public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompeti
|
||||
Leaderboard leaderboard = getLeaderboardContext().getLeaderboard();
|
||||
final MillisecondsTimePoint now = MillisecondsTimePoint.now();
|
||||
double competitorCount = Util.size(leaderboard.getCompetitors());
|
||||
double rank = leaderboard.getNetPoints(competitor, raceColumn, now);
|
||||
final double result = rank / competitorCount;
|
||||
double points = leaderboard.getNetPoints(competitor, raceColumn, now);
|
||||
double relativeLowPoints = leaderboard.getScoringScheme().isHigherBetter() ?
|
||||
competitorCount - points : points;
|
||||
final double result = relativeLowPoints / competitorCount;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAverageWindSpeedInRoundedBeaufort() {
|
||||
Speed exactResult = getAverageWindSpeed();
|
||||
return (int) exactResult.getBeaufort();
|
||||
return (int) Math.round(exactResult.getBeaufort());
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is no tracked race for the competitor or the race has no wind data, <code>null</code> is returned. Otherwise,
|
||||
* the average wind speed for the competitor is sampled in a one-minute interval throughout the race duration.
|
||||
* If there is no tracked race for the competitor or the race has no wind data, <code>null</code> is returned.
|
||||
* Otherwise, the average wind speed for the competitor is sampled in a one-minute interval throughout the race
|
||||
* duration.
|
||||
*/
|
||||
private Speed getAverageWindSpeed() {
|
||||
final Speed result;
|
||||
@@ -68,14 +86,15 @@ public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompeti
|
||||
if (trackedRace == null) {
|
||||
result = null;
|
||||
} else {
|
||||
ScalableSpeed windSpeedSum = new ScalableSpeed(Speed.NULL);
|
||||
long count = 0;
|
||||
final ScalableSpeed[] windSpeedSum = new ScalableSpeed[1];
|
||||
windSpeedSum[0] = new ScalableSpeed(Speed.NULL);
|
||||
final long[] count = new long[1];
|
||||
final List<Leg> legs = trackedRace.getRace().getCourse().getLegs();
|
||||
if (legs.isEmpty()) {
|
||||
result = null;
|
||||
} else {
|
||||
final Leg firstLeg = legs.get(0);
|
||||
final Leg lastLeg = legs.get(legs.size()-1);
|
||||
final Leg lastLeg = legs.get(legs.size() - 1);
|
||||
GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(getCompetitor());
|
||||
TimePoint started = trackedRace.getTrackedLeg(getCompetitor(), firstLeg).getStartTime();
|
||||
TimePoint finished = trackedRace.getTrackedLeg(getCompetitor(), lastLeg).getFinishTime();
|
||||
@@ -84,18 +103,47 @@ public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompeti
|
||||
for (TimePoint timePoint = from; !timePoint.after(to); timePoint = timePoint.plus(Duration.ONE_MINUTE)) {
|
||||
final Position position;
|
||||
if (track != null) {
|
||||
position = track.getEstimatedPosition(timePoint, /* extrapolate */ false);
|
||||
position = track.getEstimatedPosition(timePoint, /* extrapolate */false);
|
||||
} else {
|
||||
position = trackedRace.getCenterOfCourse(timePoint);
|
||||
}
|
||||
final Wind wind = trackedRace.getWind(position, timePoint);
|
||||
final WindWithConfidence<Pair<Position, TimePoint>> wind = trackedRace.getWindWithConfidence(
|
||||
position, timePoint);
|
||||
if (wind != null) {
|
||||
windSpeedSum = windSpeedSum.add(new ScalableSpeed(wind));
|
||||
count++;
|
||||
if (wind.useSpeed()) {
|
||||
windSpeedSum[0] = windSpeedSum[0].add(new ScalableSpeed(wind.getObject()));
|
||||
count[0]++;
|
||||
} else {
|
||||
if (!track.hasDirectionChange(timePoint, /* minimumDegreeDifference */10)) {
|
||||
// TODO try to estimate wind speed using polar data service, wind direction and COG/SOG
|
||||
SpeedWithBearing cog = track.getEstimatedSpeed(timePoint);
|
||||
final TrackedLegOfCompetitor currentLeg = trackedRace.getCurrentLeg(competitor, timePoint);
|
||||
if (currentLeg != null) {
|
||||
LegType legType;
|
||||
try {
|
||||
legType = trackedRace.getTrackedLeg(currentLeg.getLeg()).getLegType(timePoint);
|
||||
final Tack tack = trackedRace.getTack(competitor, timePoint);
|
||||
if (tack != null) {
|
||||
Set<SpeedWithBearingWithConfidence<Void>> estimatedWindSpeeds = polarDataService
|
||||
.getAverageTrueWindSpeedAndAngleCandidates(trackedRace.getRace()
|
||||
.getBoatClass(), cog, legType, tack);
|
||||
if (!estimatedWindSpeeds.isEmpty()) {
|
||||
estimatedWindSpeeds.stream().max((a,b)->(int) Math.signum(a.getConfidence()-b.getConfidence())).ifPresent(swbwc-> {
|
||||
windSpeedSum[0] = windSpeedSum[0].add(new ScalableSpeed(swbwc.getObject()));
|
||||
count[0]++;
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (NoWindException e) {
|
||||
logger.log(Level.FINEST, "Can't determine wind direction, so no tack nor leg type known", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
result = windSpeedSum.divide(count);
|
||||
if (count[0] > 0) {
|
||||
result = windSpeedSum[0].divide(count[0]);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
@@ -103,4 +151,12 @@ public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompeti
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRegattaName() {
|
||||
Leaderboard leaderboard = getLeaderboardContext().getLeaderboard();;
|
||||
final String result = leaderboard.getName();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+7
@@ -1,7 +1,9 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsDurationImpl;
|
||||
|
||||
public abstract class AbstractSpeedImpl implements Speed {
|
||||
|
||||
@@ -17,6 +19,11 @@ public abstract class AbstractSpeedImpl implements Speed {
|
||||
return new NauticalMileDistance((t2.asMillis() - t1.asMillis()) / 1000. / 3600. * getKnots());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getDuration(Distance distance) {
|
||||
return new MillisecondsDurationImpl((long) (1000 * distance.getMeters() / getMetersPerSecond()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMetersPerSecond() {
|
||||
return getKnots() * Mile.METERS_PER_SEA_MILE / 3600;
|
||||
|
||||
+4
-2
@@ -15,12 +15,14 @@ import java.io.Serializable;
|
||||
*
|
||||
*/
|
||||
public enum DetailType implements Serializable {
|
||||
DISTANCE_TRAVELED(0, ASCENDING), AVERAGE_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING), RACE_RANK(0, ASCENDING), REGATTA_RANK(0, ASCENDING), OVERALL_RANK(0, ASCENDING),
|
||||
DISTANCE_TRAVELED(0, ASCENDING), DISTANCE_TRAVELED_INCLUDING_GATE_START(0, ASCENDING),
|
||||
AVERAGE_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING), RACE_RANK(0, ASCENDING), REGATTA_RANK(0, ASCENDING), OVERALL_RANK(0, ASCENDING),
|
||||
RANK_GAIN(0, ASCENDING), NUMBER_OF_MANEUVERS(0, ASCENDING), CURRENT_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING),
|
||||
ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS(1, ASCENDING), VELOCITY_MADE_GOOD_IN_KNOTS(2, DESCENDING),
|
||||
GAP_TO_LEADER_IN_SECONDS(0, ASCENDING), GAP_CHANGE_SINCE_LEG_START_IN_SECONDS(0, ASCENDING),
|
||||
SIDE_TO_WHICH_MARK_AT_LEG_START_WAS_ROUNDED(0, ASCENDING), WINDWARD_DISTANCE_TO_GO_IN_METERS(0, ASCENDING),
|
||||
AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS(0, ASCENDING), AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS(0, ASCENDING), RACE_DISTANCE_TRAVELED(0, ASCENDING),
|
||||
RACE_DISTANCE_TRAVELED_INCLUDING_GATE_START(0, ASCENDING),
|
||||
RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING), RACE_GAP_TO_LEADER_IN_SECONDS(0, ASCENDING),
|
||||
RACE_DISTANCE_TO_LEADER_IN_METERS(0, ASCENDING), RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS(0, ASCENDING),
|
||||
RACE_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS(0, ASCENDING),
|
||||
@@ -41,7 +43,7 @@ public enum DetailType implements Serializable {
|
||||
RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL(1, ASCENDING), RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START(1, ASCENDING),
|
||||
RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START(2, DESCENDING),
|
||||
RACE_TIME_TRAVELED(0, ASCENDING), RACE_TIME_TRAVELED_UPWIND(0, ASCENDING), RACE_TIME_TRAVELED_DOWNWIND(0, ASCENDING), RACE_TIME_TRAVELED_REACHING(0, ASCENDING),
|
||||
DISTANCE_TO_START_LINE(0, ASCENDING), BEAT_ANGLE(0, ASCENDING);
|
||||
DISTANCE_TO_START_LINE(0, ASCENDING), BEAT_ANGLE(0, ASCENDING), COURSE_OVER_GROUND_TRUE_DEGREES(0, ASCENDING);
|
||||
|
||||
private int precision;
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
public class DoubleTriple {
|
||||
private final double a;
|
||||
private final double b;
|
||||
private final double c;
|
||||
|
||||
public DoubleTriple(double a, double b, double c) {
|
||||
super();
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
public double getA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
public double getB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
public double getC() {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -40,7 +40,9 @@ public enum MaxPointsReason {
|
||||
/** Discretionary Penalty Imposed by the race committee */
|
||||
DPI(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ false),
|
||||
/** Retired */
|
||||
RET(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ true);
|
||||
RET(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ true),
|
||||
/** Uniform Flag Disqualification */
|
||||
UFD(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ true);
|
||||
|
||||
private final boolean discardable;
|
||||
|
||||
|
||||
+1
-1
@@ -32,6 +32,6 @@ public interface PolarSheetGenerationSettings extends Serializable {
|
||||
|
||||
boolean areDefault();
|
||||
|
||||
int getNumberOfLeadingCompetitorsToInclude();
|
||||
double getPctOfLeadingCompetitorsToInclude();
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.datamining.shared.Unit;
|
||||
import com.sap.sse.datamining.shared.annotations.Statistic;
|
||||
@@ -46,6 +47,11 @@ public interface Speed extends Comparable<Speed>, Serializable {
|
||||
return Distance.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getDuration(Distance distance) {
|
||||
throw new ArithmeticException("Cannot determine duration for any distance with zero speed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "0kn";
|
||||
@@ -68,4 +74,10 @@ public interface Speed extends Comparable<Speed>, Serializable {
|
||||
*/
|
||||
Distance travel(TimePoint from, TimePoint to);
|
||||
|
||||
/**
|
||||
* The duration it takes to travel the <code>distance</code> specified on a great circle (the "straight
|
||||
* line" on a sphere) with this speed.
|
||||
*/
|
||||
Duration getDuration(Distance distance);
|
||||
|
||||
}
|
||||
+7
@@ -19,6 +19,7 @@ public class LegEntryDTO implements Serializable {
|
||||
private static final long serialVersionUID = -1236734337344886025L;
|
||||
public LegType legType;
|
||||
public Double distanceTraveledInMeters;
|
||||
public Double distanceTraveledIncludingGateStartInMeters;
|
||||
public Double averageSpeedOverGroundInKnots;
|
||||
public int rank;
|
||||
public Double gapToLeaderInSeconds;
|
||||
@@ -62,6 +63,7 @@ public class LegEntryDTO implements Serializable {
|
||||
result = prime * result
|
||||
+ ((currentSpeedOverGroundInKnots == null) ? 0 : currentSpeedOverGroundInKnots.hashCode());
|
||||
result = prime * result + ((distanceTraveledInMeters == null) ? 0 : distanceTraveledInMeters.hashCode());
|
||||
result = prime * result + ((distanceTraveledIncludingGateStartInMeters == null) ? 0 : distanceTraveledIncludingGateStartInMeters.hashCode());
|
||||
result = prime
|
||||
* result
|
||||
+ ((estimatedTimeToNextWaypointInSeconds == null) ? 0 : estimatedTimeToNextWaypointInSeconds.hashCode());
|
||||
@@ -120,6 +122,11 @@ public class LegEntryDTO implements Serializable {
|
||||
return false;
|
||||
} else if (!distanceTraveledInMeters.equals(other.distanceTraveledInMeters))
|
||||
return false;
|
||||
if (distanceTraveledIncludingGateStartInMeters == null) {
|
||||
if (other.distanceTraveledIncludingGateStartInMeters != null)
|
||||
return false;
|
||||
} else if (!distanceTraveledIncludingGateStartInMeters.equals(other.distanceTraveledIncludingGateStartInMeters))
|
||||
return false;
|
||||
if (estimatedTimeToNextWaypointInSeconds == null) {
|
||||
if (other.estimatedTimeToNextWaypointInSeconds != null)
|
||||
return false;
|
||||
|
||||
+15
-35
@@ -12,7 +12,6 @@ import java.util.Set;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.TimingConstants;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class RaceColumnDTO extends NamedDTO implements Serializable {
|
||||
@@ -25,6 +24,8 @@ public class RaceColumnDTO extends NamedDTO implements Serializable {
|
||||
private double effectiveFactor;
|
||||
private Map<FleetDTO, RaceLogTrackingInfoDTO> raceLogTrackingInfos;
|
||||
|
||||
public enum RaceColumnLiveState { NOT_TRACKED, TRACKED, TRACKED_AND_LIVE };
|
||||
|
||||
public RaceColumnDTO() {
|
||||
trackedRaceIdentifiersPerFleet = new HashMap<FleetDTO, RegattaAndRaceIdentifier>();
|
||||
raceLogTrackingInfos = new HashMap<FleetDTO, RaceLogTrackingInfoDTO>();
|
||||
@@ -32,6 +33,16 @@ public class RaceColumnDTO extends NamedDTO implements Serializable {
|
||||
fleets = new ArrayList<FleetDTO>();
|
||||
}
|
||||
|
||||
public RaceColumnLiveState getLiveState(long serverTimePointAsMillis) {
|
||||
RaceColumnLiveState result = RaceColumnLiveState.NOT_TRACKED;
|
||||
if (hasLiveRaces(serverTimePointAsMillis) && hasGPSData() && hasWindData()) {
|
||||
result = RaceColumnLiveState.TRACKED_AND_LIVE;
|
||||
} else if (hasTrackedRaces()) {
|
||||
result = RaceColumnLiveState.TRACKED;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getRaceColumnName() {
|
||||
return getName();
|
||||
}
|
||||
@@ -144,42 +155,11 @@ public class RaceColumnDTO extends NamedDTO implements Serializable {
|
||||
* point of the "live" interval as defined above.
|
||||
*/
|
||||
public boolean isLive(FleetDTO fleet, long serverTimePointAsMillis) {
|
||||
final Date startOfLivePeriod;
|
||||
final Date endOfLivePeriod;
|
||||
boolean result = false;
|
||||
final RaceDTO raceDTO = racesPerFleet.get(fleet);
|
||||
if (raceDTO == null || raceDTO.trackedRace == null || !raceDTO.trackedRace.hasGPSData || !raceDTO.trackedRace.hasWindData) {
|
||||
startOfLivePeriod = null;
|
||||
endOfLivePeriod = null;
|
||||
} else {
|
||||
if (raceDTO.startOfRace == null) {
|
||||
startOfLivePeriod = raceDTO.trackedRace.startOfTracking;
|
||||
} else {
|
||||
startOfLivePeriod = new Date(raceDTO.startOfRace.getTime() - TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS);
|
||||
}
|
||||
if (raceDTO.endOfRace == null) {
|
||||
if (raceDTO.trackedRace.timePointOfNewestEvent != null) {
|
||||
endOfLivePeriod = new Date(raceDTO.trackedRace.timePointOfNewestEvent.getTime()
|
||||
+ TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
|
||||
} else {
|
||||
endOfLivePeriod = null;
|
||||
}
|
||||
} else {
|
||||
endOfLivePeriod = new Date(raceDTO.endOfRace.getTime() + TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
|
||||
}
|
||||
if(raceDTO != null) {
|
||||
result = raceDTO.isLive(serverTimePointAsMillis);
|
||||
}
|
||||
|
||||
// if an empty timepoint is given then take the start of the race
|
||||
if (serverTimePointAsMillis == 0) {
|
||||
serverTimePointAsMillis = startOfLivePeriod.getTime()+1;
|
||||
}
|
||||
|
||||
// whenLastTrackedRaceWasLive is null if there is no tracked race for fleet, or the tracked race hasn't started yet at the server time
|
||||
// when this DTO was assembled, or there were no GPS or wind data
|
||||
final boolean result =
|
||||
startOfLivePeriod != null &&
|
||||
endOfLivePeriod != null &&
|
||||
startOfLivePeriod.getTime() <= serverTimePointAsMillis &&
|
||||
serverTimePointAsMillis <= endOfLivePeriod.getTime();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.Date;
|
||||
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.TimingConstants;
|
||||
|
||||
/**
|
||||
* Master data about a single race that is to be transferred to the client.<p>
|
||||
@@ -14,6 +15,8 @@ import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
public class RaceDTO extends NamedDTO {
|
||||
private static final long serialVersionUID = 2613189982608149975L;
|
||||
|
||||
public enum RaceLiveState { NOT_TRACKED, TRACKED, TRACKED_AND_LIVE, TRACKED_BUT_NOT_SCHEDULED };
|
||||
|
||||
/**
|
||||
* Tells if this race is currently being tracked, meaning that a {@link RaceTracker} is
|
||||
* listening for incoming GPS fixes, mark passings etc., to update a {@link TrackedRace} object
|
||||
@@ -46,6 +49,20 @@ public class RaceDTO extends NamedDTO {
|
||||
this.isTracked = isCurrentlyTracked;
|
||||
}
|
||||
|
||||
public RaceLiveState getLiveState(long serverTimePointAsMillis) {
|
||||
RaceLiveState result = RaceLiveState.NOT_TRACKED;
|
||||
if(trackedRace != null && trackedRace.hasGPSData && trackedRace.hasWindData) {
|
||||
result = RaceLiveState.TRACKED;
|
||||
if(isLive(serverTimePointAsMillis)) {
|
||||
result = RaceLiveState.TRACKED_AND_LIVE;
|
||||
if(startOfRace == null) {
|
||||
result = RaceLiveState.TRACKED_BUT_NOT_SCHEDULED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public RegattaAndRaceIdentifier getRaceIdentifier() {
|
||||
return new RegattaNameAndRaceName(regattaName, getName());
|
||||
}
|
||||
@@ -54,6 +71,52 @@ public class RaceDTO extends NamedDTO {
|
||||
return regattaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see {@link TrackedRace#isLive} for further explanation.
|
||||
* @param serverTimePointAsMillis
|
||||
* the time point (in server clock time) at which to determine whether the race is/was live
|
||||
* @return <code>true</code> if <code>serverTimePointAsMillis</code> is between (inclusively) the start and end time
|
||||
* point of the "live" interval as defined above.
|
||||
*/
|
||||
public boolean isLive(long serverTimePointAsMillis) {
|
||||
final Date startOfLivePeriod;
|
||||
final Date endOfLivePeriod;
|
||||
if (trackedRace == null || !trackedRace.hasGPSData || !trackedRace.hasWindData) {
|
||||
startOfLivePeriod = null;
|
||||
endOfLivePeriod = null;
|
||||
} else {
|
||||
if (startOfRace == null) {
|
||||
startOfLivePeriod = trackedRace.startOfTracking;
|
||||
} else {
|
||||
startOfLivePeriod = new Date(startOfRace.getTime() - TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS);
|
||||
}
|
||||
if (endOfRace == null) {
|
||||
if (trackedRace.timePointOfNewestEvent != null) {
|
||||
endOfLivePeriod = new Date(trackedRace.timePointOfNewestEvent.getTime()
|
||||
+ TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
|
||||
} else {
|
||||
endOfLivePeriod = null;
|
||||
}
|
||||
} else {
|
||||
endOfLivePeriod = new Date(endOfRace.getTime() + TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
// if an empty timepoint is given then take the start of the race
|
||||
if (serverTimePointAsMillis == 0) {
|
||||
serverTimePointAsMillis = startOfLivePeriod.getTime()+1;
|
||||
}
|
||||
|
||||
// whenLastTrackedRaceWasLive is null if there is no tracked race for fleet, or the tracked race hasn't started yet at the server time
|
||||
// when this DTO was assembled, or there were no GPS or wind data
|
||||
final boolean result =
|
||||
startOfLivePeriod != null &&
|
||||
endOfLivePeriod != null &&
|
||||
startOfLivePeriod.getTime() <= serverTimePointAsMillis &&
|
||||
serverTimePointAsMillis <= endOfLivePeriod.getTime();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
||||
+7
-7
@@ -11,7 +11,7 @@ public class PolarSheetGenerationSettingsImpl implements PolarSheetGenerationSet
|
||||
double[] levels = { 4., 6., 8., 10., 12., 14., 16., 20., 25., 30. };
|
||||
WindSpeedSteppingWithMaxDistance windStepping = new WindSpeedSteppingWithMaxDistance(levels, 2.5);
|
||||
return new PolarSheetGenerationSettingsImpl(50, 0.1, 20, 20, 0.1, true, true, 2, 0.05, true, windStepping,
|
||||
false, 0);
|
||||
false, 1);
|
||||
}
|
||||
|
||||
public static PolarSheetGenerationSettings createBackendPolarSettings() {
|
||||
@@ -26,7 +26,7 @@ public class PolarSheetGenerationSettingsImpl implements PolarSheetGenerationSet
|
||||
}
|
||||
WindSpeedSteppingWithMaxDistance windStepping = new WindSpeedSteppingWithMaxDistance(levels, 0.5);
|
||||
return new PolarSheetGenerationSettingsImpl(50, 0.1, 20, 20, 0.1, true, true, 2, 0.05, true, windStepping,
|
||||
false, 1);
|
||||
false, 0.1);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 2731616509404813790L;
|
||||
@@ -42,7 +42,7 @@ public class PolarSheetGenerationSettingsImpl implements PolarSheetGenerationSet
|
||||
private boolean useOnlyEstimationForWindDirection;
|
||||
private WindSpeedSteppingWithMaxDistance windStepping;
|
||||
private boolean splitByWindGauges;
|
||||
private int numberOfLeadingCompetitorsToInclude;
|
||||
private double pctOfLeadingCompetitorsToInclude;
|
||||
|
||||
//GWT
|
||||
PolarSheetGenerationSettingsImpl() {};
|
||||
@@ -52,7 +52,7 @@ public class PolarSheetGenerationSettingsImpl implements PolarSheetGenerationSet
|
||||
boolean useOnlyWindGaugesForWindSpeed, boolean shouldRemoveOutliers,
|
||||
double outlierDetectionNeighboorhoodRadius, double outlierMinimumNeighboorhoodPct,
|
||||
boolean useOnlyEstimationForWindDirection, WindSpeedSteppingWithMaxDistance windStepping,
|
||||
boolean splitByWindGauges, int numberOfLeadingCompetitorsToInclude) {
|
||||
boolean splitByWindGauges, double pctOfLeadingCompetitorsToInclude) {
|
||||
this.minimumDataCountPerGraph = minimumDataCountPerGraph;
|
||||
this.minimumWindConfidence = minimumWindConfidence;
|
||||
this.minimumDataCountPerAngle = minimumDataCountPerAngle;
|
||||
@@ -65,7 +65,7 @@ public class PolarSheetGenerationSettingsImpl implements PolarSheetGenerationSet
|
||||
this.useOnlyEstimationForWindDirection = useOnlyEstimationForWindDirection;
|
||||
this.windStepping = windStepping;
|
||||
this.splitByWindGauges = splitByWindGauges;
|
||||
this.numberOfLeadingCompetitorsToInclude = numberOfLeadingCompetitorsToInclude;
|
||||
this.pctOfLeadingCompetitorsToInclude = pctOfLeadingCompetitorsToInclude;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -209,8 +209,8 @@ public class PolarSheetGenerationSettingsImpl implements PolarSheetGenerationSet
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfLeadingCompetitorsToInclude() {
|
||||
return numberOfLeadingCompetitorsToInclude;
|
||||
public double getPctOfLeadingCompetitorsToInclude() {
|
||||
return pctOfLeadingCompetitorsToInclude;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ package com.sap.sailing.domain.common.racelog;
|
||||
*/
|
||||
public interface RaceLogServletConstants {
|
||||
static final String PARAMS_LEADERBOARD_NAME = "leaderboard";
|
||||
static final String PARAMS_RACE_COLUMN_NAME = "raceColumn";
|
||||
static final String PARAMS_RACE_COLUMN_NAME = "race_column";
|
||||
static final String PARAMS_RACE_FLEET_NAME = "fleet";
|
||||
static final String PARAMS_CLIENT_UUID = "clientuuid";
|
||||
static final String PARAM_COURSE_AREA_FILTER = "courseArea";
|
||||
|
||||
+8
-2
@@ -21,7 +21,8 @@ public class DeviceMappingConstants {
|
||||
// schema and host are case insensitive.
|
||||
// But to adhere to best practices, and due to the deficiencies of some web servers and clients,
|
||||
// all URL components should be treated as case insensitive, preferring _underscores_ to CamelCase.
|
||||
public static final String URL_BASE = "/tracking/checkin";
|
||||
public static final String TRACKING_URL_BASE = "/tracking/checkin";
|
||||
public static final String BUOY_TENDER_URL_BASE = "/buoy-tender/checkin";
|
||||
public static final String URL_EVENT_ID = "event_id";
|
||||
public static final String URL_LEADERBOARD_NAME = "leaderboard_name";
|
||||
public static final String URL_COMPETITOR_ID_AS_STRING = "competitor_id";
|
||||
@@ -43,11 +44,16 @@ public class DeviceMappingConstants {
|
||||
|
||||
public static String getDeviceMappingForRegattaLogUrl(String serverUrlWithoutTrailingSlash, String eventId,
|
||||
String leaderboardName, String mappedItemType, String mappedItemId, UrlHelper helper) {
|
||||
return helper.encodeUrl(serverUrlWithoutTrailingSlash + URL_BASE + "?" + URL_EVENT_ID + "=" + eventId + "&"
|
||||
return helper.encodeUrl(serverUrlWithoutTrailingSlash + TRACKING_URL_BASE + "?" + URL_EVENT_ID + "=" + eventId + "&"
|
||||
+ URL_LEADERBOARD_NAME + "=" + leaderboardName + "&" + mappedItemType + "="
|
||||
+ mappedItemId);
|
||||
}
|
||||
|
||||
public static String getBuoyTenderInvitationUrl(String serverUrlWithoutTrailingSlash,
|
||||
String leaderboardName, UrlHelper helper) {
|
||||
return helper.encodeUrl(serverUrlWithoutTrailingSlash + BUOY_TENDER_URL_BASE + "?" + URL_LEADERBOARD_NAME + "=" + leaderboardName);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getDeviceMappingForRaceLogUrl(String serverUrlWithoutTrailingSlash, String leaderboardName,
|
||||
String raceColumnName, String fleetName, String mappedItemType, String mappedItemId, long fromMillis,
|
||||
|
||||
+19
-14
@@ -1,12 +1,12 @@
|
||||
package com.sap.sailing.domain.common.scalablevalue.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.DoubleTriple;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.RadianBearingImpl;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
|
||||
/**
|
||||
@@ -14,42 +14,47 @@ import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
* bearing is scaled separately, and the speed is scaled as a scalar value independently of the bearing. This is
|
||||
* particularly useful for {@link Wind} scaling where it makes more sense to average the wind speed independently of the
|
||||
* wind direction / bearing than adding up the "wind vectors" and averaging, which would reduce the resulting wind speed
|
||||
* for constant wind speeds across all fixes with different directions.
|
||||
* for constant wind speeds across all fixes with different directions.<p>
|
||||
*
|
||||
* The triple used for scaling uses the speed in knots as the first component, the sine as the second and the
|
||||
* cosine as the third value.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class ScalableSpeedWithBearing implements ScalableValue<Util.Triple<Speed, Double, Double>, SpeedWithBearing> {
|
||||
private final Speed speed;
|
||||
public class ScalableSpeedWithBearing implements ScalableValue<DoubleTriple, SpeedWithBearing> {
|
||||
private final double speedInKnots;
|
||||
private final double sin;
|
||||
private final double cos;
|
||||
|
||||
public ScalableSpeedWithBearing(SpeedWithBearing speedWithBearing) {
|
||||
this(new KnotSpeedImpl(speedWithBearing.getKnots()), Math.sin(speedWithBearing.getBearing()
|
||||
this(speedWithBearing.getKnots(), Math.sin(speedWithBearing.getBearing()
|
||||
.getRadians()), Math.cos(speedWithBearing.getBearing().getRadians()));
|
||||
}
|
||||
|
||||
public ScalableSpeedWithBearing(Speed speed, double sin, double cos) {
|
||||
this.speed = speed;
|
||||
this(speed.getKnots(), sin, cos);
|
||||
}
|
||||
|
||||
private ScalableSpeedWithBearing(double speedInKnots, double sin, double cos) {
|
||||
this.speedInKnots = speedInKnots;
|
||||
this.sin = sin;
|
||||
this.cos = cos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalableSpeedWithBearing multiply(double factor) {
|
||||
Speed newSpeed = new KnotSpeedImpl(factor*speed.getKnots());
|
||||
return new ScalableSpeedWithBearing(newSpeed, factor*sin, factor*cos);
|
||||
return new ScalableSpeedWithBearing(factor*speedInKnots, factor*sin, factor*cos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalableSpeedWithBearing add(ScalableValue<Util.Triple<Speed, Double, Double>, SpeedWithBearing> t) {
|
||||
Speed newSpeed = new KnotSpeedImpl(speed.getKnots() + t.getValue().getA().getKnots());
|
||||
return new ScalableSpeedWithBearing(newSpeed, sin+t.getValue().getB(), cos+t.getValue().getC());
|
||||
public ScalableSpeedWithBearing add(ScalableValue<DoubleTriple, SpeedWithBearing> t) {
|
||||
return new ScalableSpeedWithBearing(speedInKnots + t.getValue().getA(), sin+t.getValue().getB(), cos+t.getValue().getC());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing divide(double divisor) {
|
||||
Speed newSpeed = new KnotSpeedImpl(speed.getKnots() / divisor);
|
||||
Speed newSpeed = new KnotSpeedImpl(speedInKnots / divisor);
|
||||
double angle;
|
||||
if (cos == 0) {
|
||||
angle = sin >= 0 ? Math.PI / 2 : -Math.PI / 2;
|
||||
@@ -61,8 +66,8 @@ public class ScalableSpeedWithBearing implements ScalableValue<Util.Triple<Speed
|
||||
}
|
||||
|
||||
@Override
|
||||
public Util.Triple<Speed, Double, Double> getValue() {
|
||||
return new Util.Triple<Speed, Double, Double>(speed, sin, cos);
|
||||
public DoubleTriple getValue() {
|
||||
return new DoubleTriple(speedInKnots, sin, cos);
|
||||
}
|
||||
|
||||
}
|
||||
-1
@@ -120,7 +120,6 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
|
||||
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, AbstractLog<?, ?> log, Mark mark)
|
||||
throws NoCorrespondingServiceRegisteredException, TransformationException{
|
||||
List<DeviceMapping<Mark>> mappings = new DeviceMarkMappingFinder<>(log).analyze().get(mark);
|
||||
|
||||
if (mappings != null) {
|
||||
for (DeviceMapping<Mark> mapping : mappings) {
|
||||
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/);
|
||||
|
||||
+1
@@ -2,3 +2,4 @@ trackingInvitationFor=Einladung zum Tracken für
|
||||
scanQRCodeOrVisitUrlToRegisterAs=Scanne den QRCode oder klicke den Link mit deinem Smartphone an um dich zu registrieren als
|
||||
welcomeTo=Willkommen zu
|
||||
alternativelyVisitThisLink=Alternativ kannst du diesen Link anklicken
|
||||
buoyTender=Bojenleger
|
||||
+1
@@ -2,3 +2,4 @@ trackingInvitationFor=Tracking Invitation for
|
||||
scanQRCodeOrVisitUrlToRegisterAs=Scan the following QRCode or click the link using your smartphone to register as
|
||||
welcomeTo=Welcome to
|
||||
alternativelyVisitThisLink=Alternatively, you can click this Link
|
||||
buoyTender=buoy tender
|
||||
Regular → Executable
+16
-3
@@ -21,9 +21,9 @@ import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTracki
|
||||
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.RaceLogRaceTracker;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.RaceHandle;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.common.mail.MailException;
|
||||
@@ -40,7 +40,7 @@ public interface RaceLogTrackingAdapter {
|
||||
* <li>Is a {@link RaceLogStartTrackingEvent} present in the racelog? If not, add one</li>
|
||||
* </ul>
|
||||
*/
|
||||
void startTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet)
|
||||
RaceHandle startTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet)
|
||||
throws NotDenotedForRaceLogTrackingException, Exception;
|
||||
|
||||
RaceLogTrackingState getRaceLogTrackingState(RacingEventService service, RaceColumn raceColumn, Fleet fleet);
|
||||
@@ -76,10 +76,15 @@ public interface RaceLogTrackingAdapter {
|
||||
throws NotDenotableForRaceLogTrackingException;
|
||||
|
||||
/**
|
||||
* Add a fix to the {@link GPSFixStore}, and create a mapping with a virtual device for exactly that timepoint.
|
||||
* @see #pingMark(RaceLog, Mark, GPSFix, RacingEventService) using a random {@link PingDeviceIdentifier}
|
||||
*/
|
||||
void pingMark(RaceLog raceLogToAddTo, Mark mark, GPSFix gpsFix, RacingEventService service);
|
||||
|
||||
/**
|
||||
* @see #pingMark(RaceLog, Mark, GPSFix, RacingEventService)
|
||||
*/
|
||||
void pingMark(RegattaLog regattaLogToAddTo, Mark mark, GPSFix gpsFix, RacingEventService service);
|
||||
|
||||
/**
|
||||
* Duplicate the course and competitor registrations in the newest {@link RaceLogCourseDesignChangedEvent} in
|
||||
* {@code from} race log to the {@code to} race logs. The {@link Mark}s and {@link ControlPoint}s are duplicated and
|
||||
@@ -102,7 +107,15 @@ public interface RaceLogTrackingAdapter {
|
||||
|
||||
/**
|
||||
* Invite competitors for tracking via the Tracking App by sending out emails.
|
||||
* @throws MailException
|
||||
*/
|
||||
void inviteCompetitorsForTrackingViaEmail(Event event, Leaderboard leaderboard,
|
||||
String serverUrlWithoutTrailingSlash, Set<Competitor> competitors, Locale locale) throws MailException;
|
||||
|
||||
/**
|
||||
* Invite buoy tenders for buoy pinging via the Buoy Tender App by sending out emails.
|
||||
* @throws MailException
|
||||
*/
|
||||
void inviteBuoyTenderViaEmail(Event event, Leaderboard leaderboard, String serverUrlWithoutTrailingSlash,
|
||||
String emails, Locale locale) throws MailException;
|
||||
}
|
||||
+5
@@ -18,6 +18,7 @@ import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory;
|
||||
import com.sap.sailing.domain.racelogtracking.SmartphoneUUIDIdentifier;
|
||||
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.server.MasterDataImportClassLoaderService;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.GPSFixJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.GPSFixMovingJsonDeserializer;
|
||||
@@ -78,6 +79,10 @@ public class Activator implements BundleActivator {
|
||||
registerGPSFixJsonService(context, new GPSFixMovingNmeaDTOJsonDeserializer(), new GPSFixMovingNmeaDTOJsonSerializer(), GPSFixMovingNmeaDTOJsonDeserializer.TYPE);
|
||||
|
||||
registrations.add(context.registerService(RaceLogTrackingAdapterFactory.class, RaceLogTrackingAdapterFactory.INSTANCE, null));
|
||||
|
||||
registrations.add(context.registerService(MasterDataImportClassLoaderService.class,
|
||||
new MasterDataImportClassLoaderServiceImpl(), null));
|
||||
|
||||
logger.log(Level.INFO, "Started "+context.getBundle().getSymbolicName());
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import com.sap.sailing.server.MasterDataImportClassLoaderService;
|
||||
|
||||
public class MasterDataImportClassLoaderServiceImpl implements MasterDataImportClassLoaderService {
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return this.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
}
|
||||
+150
-130
@@ -2,11 +2,9 @@ package com.sap.sailing.domain.racelogtracking.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
@@ -38,12 +36,12 @@ import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTracking
|
||||
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.shared.analyzing.RegisteredCompetitorsAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.shared.events.RegisterCompetitorEvent;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.ControlPoint;
|
||||
import com.sap.sailing.domain.base.CourseBase;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
@@ -54,7 +52,6 @@ import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.SharedDomainFactory;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.CourseDataImpl;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants;
|
||||
@@ -94,36 +91,39 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet)
|
||||
public RaceHandle startTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet)
|
||||
throws NotDenotedForRaceLogTrackingException, Exception {
|
||||
RaceLog raceLog = raceColumn.getRaceLog(fleet);
|
||||
RaceLogTrackingState raceLogTrackingState = new RaceLogTrackingStateAnalyzer(raceLog).analyze();
|
||||
if (! raceLogTrackingState.isForTracking()) {
|
||||
if (!raceLogTrackingState.isForTracking()) {
|
||||
throw new NotDenotedForRaceLogTrackingException();
|
||||
}
|
||||
RegattaIdentifier regatta = ((RegattaLeaderboard) leaderboard).getRegatta().getRegattaIdentifier();
|
||||
|
||||
if (raceLogTrackingState != RaceLogTrackingState.TRACKING) {
|
||||
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createStartTrackingEvent(MillisecondsTimePoint.now(),
|
||||
service.getServerAuthor(), raceLog.getCurrentPassId());
|
||||
raceLog.add(event);
|
||||
}
|
||||
|
||||
if (! isRaceLogRaceTrackerAttached(service, raceLog)) {
|
||||
addTracker(service, regatta, leaderboard, raceColumn, fleet, -1);
|
||||
final RaceHandle result;
|
||||
if (!isRaceLogRaceTrackerAttached(service, raceLog)) {
|
||||
result = addTracker(service, regatta, leaderboard, raceColumn, fleet, -1);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link RaceLogRaceTracker}. If a {@link RaceLogStartTrackingEvent} is already present in the {@code RaceLog}
|
||||
* linked to the {@code raceColumn} and {@code fleet}, a {@code TrackedRace} is created immediately and tracking begins.
|
||||
* Otherwise, the {@code RaceLogRaceTracker} waits until a {@code StartTrackingEvent} is added to perform these actions.
|
||||
* The race first has to be denoted for racelog tracking.
|
||||
* Adds a {@link RaceLogRaceTracker}. If a {@link RaceLogStartTrackingEvent} is already present in the
|
||||
* {@code RaceLog} linked to the {@code raceColumn} and {@code fleet}, a {@code TrackedRace} is created immediately
|
||||
* and tracking begins. Otherwise, the {@code RaceLogRaceTracker} waits until a {@code StartTrackingEvent} is added
|
||||
* to perform these actions. The race first has to be denoted for racelog tracking.
|
||||
*/
|
||||
private RaceHandle addTracker(RacingEventService service, RegattaIdentifier regattaToAddTo, Leaderboard leaderboard,
|
||||
RaceColumn raceColumn, Fleet fleet, long timeoutInMilliseconds) throws RaceLogRaceTrackerExistsException, Exception {
|
||||
private RaceHandle addTracker(RacingEventService service, RegattaIdentifier regattaToAddTo,
|
||||
Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, long timeoutInMilliseconds)
|
||||
throws RaceLogRaceTrackerExistsException, Exception {
|
||||
RaceLog raceLog = raceColumn.getRaceLog(fleet);
|
||||
assert ! isRaceLogRaceTrackerAttached(service, raceLog) : new RaceLogRaceTrackerExistsException(
|
||||
assert !isRaceLogRaceTrackerAttached(service, raceLog) : new RaceLogRaceTrackerExistsException(
|
||||
leaderboard.getName() + " - " + raceColumn.getName() + " - " + fleet.getName());
|
||||
|
||||
Regatta regatta = regattaToAddTo == null ? null : service.getRegatta(regattaToAddTo);
|
||||
@@ -133,15 +133,16 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void denoteRaceForRaceLogTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn,
|
||||
Fleet fleet, String raceName) throws NotDenotableForRaceLogTrackingException {
|
||||
public void denoteRaceForRaceLogTracking(RacingEventService service, Leaderboard leaderboard,
|
||||
RaceColumn raceColumn, Fleet fleet, String raceName) throws NotDenotableForRaceLogTrackingException {
|
||||
|
||||
BoatClass boatClass = null;
|
||||
if (leaderboard instanceof RegattaLeaderboard) {
|
||||
RegattaLeaderboard rLeaderboard = (RegattaLeaderboard) leaderboard;
|
||||
boatClass = rLeaderboard.getRegatta().getBoatClass();
|
||||
} else {
|
||||
throw new NotDenotableForRaceLogTrackingException("Can only denote races in RegattaLeaderboards for RaceLog-tracking");
|
||||
throw new NotDenotableForRaceLogTrackingException(
|
||||
"Can only denote races in RegattaLeaderboards for RaceLog-tracking");
|
||||
}
|
||||
|
||||
if (raceName == null) {
|
||||
@@ -170,7 +171,8 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
for (Fleet fleet : column.getFleets()) {
|
||||
try {
|
||||
denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, null);
|
||||
} catch (NotDenotableForRaceLogTrackingException e) {}
|
||||
} catch (NotDenotableForRaceLogTrackingException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,46 +187,9 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
return new RaceLogTrackingStateAnalyzer(raceColumn.getRaceLog(fleet)).analyze();
|
||||
}
|
||||
|
||||
private Waypoint duplicateWaypoint(Waypoint waypoint, Map<ControlPoint, ControlPoint> controlPointDuplicationCache,
|
||||
Map<Mark, Mark> markDuplicationCache, SharedDomainFactory baseDomainFactory) {
|
||||
ControlPoint oldCP = waypoint.getControlPoint();
|
||||
ControlPoint newCP = null;
|
||||
PassingInstruction pi = waypoint.getPassingInstructions();
|
||||
if (controlPointDuplicationCache.get(oldCP) != null) {
|
||||
newCP = controlPointDuplicationCache.get(oldCP);
|
||||
} else {
|
||||
Mark[] newMarks = new Mark[Util.size(oldCP.getMarks())];
|
||||
int i = 0;
|
||||
for (Mark oldMark : oldCP.getMarks()) {
|
||||
newMarks[i] = null;
|
||||
if (markDuplicationCache.get(oldMark) != null) {
|
||||
newMarks[i] = markDuplicationCache.get(oldMark);
|
||||
} else {
|
||||
newMarks[i] = baseDomainFactory.getOrCreateMark(UUID.randomUUID(), oldMark.getName(), oldMark.getType(),
|
||||
oldMark.getColor(), oldMark.getShape(), oldMark.getPattern());
|
||||
markDuplicationCache.put(oldMark, newMarks[i]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
switch (newMarks.length) {
|
||||
case 1:
|
||||
newCP = newMarks[0];
|
||||
break;
|
||||
case 2:
|
||||
newCP = baseDomainFactory.createControlPointWithTwoMarks(newMarks[0], newMarks[1], oldCP.getName());
|
||||
break;
|
||||
default:
|
||||
logger.log(Level.WARNING, "Don't know how to duplicate CP with more than 2 marks");
|
||||
throw new RuntimeException("Don't know how to duplicate CP with more than 2 marks");
|
||||
}
|
||||
controlPointDuplicationCache.put(oldCP, newCP);
|
||||
}
|
||||
|
||||
return baseDomainFactory.createWaypoint(newCP, pi);
|
||||
}
|
||||
|
||||
private void revokeAlreadyDefinedMarks(RaceLog raceLog, AbstractLogEventAuthor author) {
|
||||
List<RaceLogEvent> markEvents = new AllEventsOfTypeFinder<>(raceLog, true, RaceLogDefineMarkEvent.class).analyze();
|
||||
List<RaceLogEvent> markEvents = new AllEventsOfTypeFinder<>(raceLog, /* only unrevoked */ true, RaceLogDefineMarkEvent.class)
|
||||
.analyze();
|
||||
for (RaceLogEvent event : markEvents) {
|
||||
try {
|
||||
raceLog.revokeEvent(author, event, "removing mark that was already defined");
|
||||
@@ -235,71 +200,91 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyCourseAndCompetitors(RaceLog fromRaceLog, Set<RaceLog> toRaceLogs, SharedDomainFactory baseDomainFactory,
|
||||
RacingEventService service) {
|
||||
public void copyCourseAndCompetitors(RaceLog fromRaceLog, Set<RaceLog> toRaceLogs,
|
||||
SharedDomainFactory baseDomainFactory, RacingEventService service) {
|
||||
CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog).analyze();
|
||||
final Set<Mark> marks = new HashSet<>();
|
||||
course.getWaypoints().forEach(wp->Util.addAll(wp.getMarks(), marks));
|
||||
Set<Competitor> competitors = new RegisteredCompetitorsAnalyzer<>(fromRaceLog).analyze();
|
||||
|
||||
for (RaceLog toRaceLog : toRaceLogs) {
|
||||
if (course == null || ! new RaceLogTrackingStateAnalyzer(toRaceLog).analyze().isForTracking()) {
|
||||
if (course == null || !new RaceLogTrackingStateAnalyzer(toRaceLog).analyze().isForTracking()) {
|
||||
continue;
|
||||
}
|
||||
CourseBase to = new CourseDataImpl("Copy of \"" + course.getName());
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
int i = 0;
|
||||
Map<ControlPoint, ControlPoint> controlPointDuplicationCache = new HashMap<ControlPoint, ControlPoint>();
|
||||
revokeAlreadyDefinedMarks(toRaceLog, service.getServerAuthor());
|
||||
Map<Mark, Mark> markDuplicationCache = new HashMap<Mark, Mark>();
|
||||
for (Waypoint oldWaypoint : course.getWaypoints()) {
|
||||
to.addWaypoint(i++, duplicateWaypoint(oldWaypoint, controlPointDuplicationCache, markDuplicationCache, baseDomainFactory));
|
||||
to.addWaypoint(i++, oldWaypoint);
|
||||
}
|
||||
|
||||
for (Mark mark : markDuplicationCache.values()) {
|
||||
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createDefineMarkEvent(now, service.getServerAuthor(),
|
||||
toRaceLog.getCurrentPassId(), mark);
|
||||
for (Mark mark : marks) {
|
||||
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createDefineMarkEvent(now,
|
||||
service.getServerAuthor(), toRaceLog.getCurrentPassId(), mark);
|
||||
toRaceLog.add(event);
|
||||
}
|
||||
|
||||
int passId = toRaceLog.getCurrentPassId();
|
||||
|
||||
RaceLogEvent newCourseEvent = RaceLogEventFactory.INSTANCE.createCourseDesignChangedEvent(
|
||||
now, service.getServerAuthor(), passId, to);
|
||||
RaceLogEvent newCourseEvent = RaceLogEventFactory.INSTANCE.createCourseDesignChangedEvent(now,
|
||||
service.getServerAuthor(), passId, to);
|
||||
toRaceLog.add(newCourseEvent);
|
||||
|
||||
registerCompetitors(service, toRaceLog, competitors);
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private static interface DeviceMarkMappingEventFactory<VisitorT, EventT extends AbstractLogEvent<VisitorT>> {
|
||||
EventT createDeviceMarkMapping(DeviceIdentifier device, TimePoint timePoint);
|
||||
}
|
||||
|
||||
private <VisitorT, EventT extends AbstractLogEvent<VisitorT>, LogT extends AbstractLog<EventT, VisitorT>> void pingMark(
|
||||
LogT log, Mark mark, GPSFix gpsFix, RacingEventService service,
|
||||
DeviceMarkMappingEventFactory<VisitorT, EventT> factory, DeviceIdentifier device) {
|
||||
TimePoint time = gpsFix.getTimePoint();
|
||||
EventT mapping = factory.createDeviceMarkMapping(device, time);
|
||||
log.add(mapping);
|
||||
try {
|
||||
service.getGPSFixStore().storeFix(device, gpsFix);
|
||||
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
|
||||
logger.log(Level.WARNING, "Could not ping mark " + mark);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pingMark(RaceLog raceLog, Mark mark, GPSFix gpsFix, RacingEventService service) {
|
||||
DeviceIdentifier device = new PingDeviceIdentifierImpl();
|
||||
TimePoint time = gpsFix.getTimePoint();
|
||||
pingMark(raceLog, mark, gpsFix, service,
|
||||
(DeviceIdentifier dev, TimePoint timePoint) -> RaceLogEventFactory.INSTANCE
|
||||
.createDeviceMarkMappingEvent(timePoint, service.getServerAuthor(), dev, mark,
|
||||
raceLog.getCurrentPassId(), timePoint, timePoint), new PingDeviceIdentifierImpl());
|
||||
}
|
||||
|
||||
RaceLogEvent mapping = RaceLogEventFactory.INSTANCE.createDeviceMarkMappingEvent(time,
|
||||
service.getServerAuthor(), device, mark, raceLog.getCurrentPassId(), time, time);
|
||||
raceLog.add(mapping);
|
||||
try {
|
||||
service.getGPSFixStore().storeFix(device, gpsFix);
|
||||
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
|
||||
logger.log(Level.WARNING, "Could not pint mark " + mark);
|
||||
}
|
||||
@Override
|
||||
public void pingMark(RegattaLog regattaLog, Mark mark, GPSFix gpsFix, RacingEventService service) {
|
||||
pingMark(
|
||||
regattaLog,
|
||||
mark,
|
||||
gpsFix,
|
||||
service,
|
||||
(DeviceIdentifier dev, TimePoint timePoint) -> new RegattaLogDeviceMarkMappingEventImpl(timePoint, service
|
||||
.getServerAuthor(), timePoint, UUID.randomUUID(), mark, dev, timePoint, timePoint), new PingDeviceIdentifierImpl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDenotationForRaceLogTracking(RacingEventService service, RaceLog raceLog) {
|
||||
RaceLogEvent denoteForTrackingEvent = new LastEventOfTypeFinder<>(raceLog, true, RaceLogDenoteForTrackingEvent.class).analyze();
|
||||
RaceLogEvent startTrackingEvent = new LastEventOfTypeFinder<>(raceLog, true, RaceLogStartTrackingEvent.class).analyze();
|
||||
RaceLogEvent denoteForTrackingEvent = new LastEventOfTypeFinder<>(raceLog, true,
|
||||
RaceLogDenoteForTrackingEvent.class).analyze();
|
||||
RaceLogEvent startTrackingEvent = new LastEventOfTypeFinder<>(raceLog, true, RaceLogStartTrackingEvent.class)
|
||||
.analyze();
|
||||
try {
|
||||
raceLog.revokeEvent(service.getServerAuthor(), denoteForTrackingEvent, "remove denotation");
|
||||
raceLog.revokeEvent(service.getServerAuthor(), startTrackingEvent, "reset start time upon removing denotation");
|
||||
raceLog.revokeEvent(service.getServerAuthor(), startTrackingEvent,
|
||||
"reset start time upon removing denotation");
|
||||
} catch (NotRevokableException e) {
|
||||
logger.log(Level.WARNING, "could not remove denotation by adding RevokeEvents", e);
|
||||
}
|
||||
}
|
||||
|
||||
private <LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT>
|
||||
void registerCompetitors(AbstractLogEventAuthor author, LogT log, Set<Competitor> competitors,
|
||||
Function<Competitor, EventT> registerEventFactory) {
|
||||
private <LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT> void registerCompetitors(
|
||||
AbstractLogEventAuthor author, LogT log, Set<Competitor> competitors,
|
||||
Function<Competitor, EventT> registerEventFactory) {
|
||||
Set<Competitor> alreadyRegistered = new HashSet<Competitor>(new RegisteredCompetitorsAnalyzer<>(log).analyze());
|
||||
Set<Competitor> toBeRegistered = new HashSet<Competitor>();
|
||||
|
||||
@@ -311,19 +296,19 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
toBeRemoved.removeAll(toBeRegistered);
|
||||
toBeRegistered.removeAll(alreadyRegistered);
|
||||
|
||||
//register
|
||||
// register
|
||||
for (Competitor c : toBeRegistered) {
|
||||
log.add(registerEventFactory.apply(c));
|
||||
}
|
||||
|
||||
//unregister
|
||||
// unregister
|
||||
for (EventT event : log.getUnrevokedEventsDescending()) {
|
||||
if (event instanceof RegisterCompetitorEvent) {
|
||||
RegisterCompetitorEvent<?> registerEvent = (RegisterCompetitorEvent<?>) event;
|
||||
if (toBeRemoved.contains(registerEvent.getCompetitor())) {
|
||||
try {
|
||||
log.revokeEvent(author, event,
|
||||
"unregistering competitor because no longer selected for registration");
|
||||
"unregistering competitor because no longer selected for registration");
|
||||
} catch (NotRevokableException e) {
|
||||
logger.log(Level.WARNING, "could not unregister competitor by adding RevokeEvent", e);
|
||||
}
|
||||
@@ -334,9 +319,12 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
|
||||
@Override
|
||||
public void registerCompetitors(RacingEventService service, RaceLog raceLog, Set<Competitor> competitors) {
|
||||
registerCompetitors(service.getServerAuthor(), raceLog, competitors,
|
||||
registerCompetitors(
|
||||
service.getServerAuthor(),
|
||||
raceLog,
|
||||
competitors,
|
||||
c -> RaceLogEventFactory.INSTANCE.createRegisterCompetitorEvent(MillisecondsTimePoint.now(),
|
||||
service.getServerAuthor(), raceLog.getCurrentPassId(), c));
|
||||
service.getServerAuthor(), raceLog.getCurrentPassId(), c));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -347,8 +335,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
}
|
||||
|
||||
private MailService getMailService() {
|
||||
ServiceReference<MailService> ref = Activator.getContext()
|
||||
.getServiceReference(MailService.class);
|
||||
ServiceReference<MailService> ref = Activator.getContext().getServiceReference(MailService.class);
|
||||
if (ref == null) {
|
||||
logger.warning("No file storage management service registered");
|
||||
return null;
|
||||
@@ -361,7 +348,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
String serverUrlWithoutTrailingSlash, Set<Competitor> competitors, Locale locale) throws MailException {
|
||||
StringBuilder occuredExceptions = new StringBuilder();
|
||||
|
||||
for (Competitor competitor : competitors){
|
||||
for (Competitor competitor : competitors) {
|
||||
final String toAddress = competitor.getEmail();
|
||||
if (toAddress != null) {
|
||||
String leaderboardName = leaderboard.getName();
|
||||
@@ -370,40 +357,73 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
String url = DeviceMappingConstants.getDeviceMappingForRegattaLogUrl(serverUrlWithoutTrailingSlash,
|
||||
event.getId().toString(), leaderboardName, DeviceMappingConstants.URL_COMPETITOR_ID_AS_STRING,
|
||||
competitor.getId().toString(), NonGwtUrlHelper.INSTANCE);
|
||||
String subject = String.format("%s %s",
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "trackingInvitationFor"), competitorName);
|
||||
|
||||
// taken from http://www.tutorialspoint.com/javamail_api/javamail_api_send_inlineimage_in_email.htm
|
||||
BodyPart messageTextPart = new MimeBodyPart();
|
||||
String htmlText = String.format("<h1>%s %s</h1>" + "<p>%s <b>%s</b></p>"
|
||||
+ "<img src=\"cid:image\" title=\"%s\"><br/>"
|
||||
+ "<a href=\"%s\">%s</a>",
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "welcomeTo"), leaderboardName,
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "scanQRCodeOrVisitUrlToRegisterAs"), competitorName,
|
||||
url, url, RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "alternativelyVisitThisLink"));
|
||||
|
||||
try {
|
||||
messageTextPart.setContent(htmlText, "text/html");
|
||||
|
||||
BodyPart messageImagePart = new MimeBodyPart();
|
||||
InputStream imageIs = QRCodeGenerationUtil.create(url, 250);
|
||||
DataSource imageDs = new ByteArrayDataSource(imageIs, "image/png");
|
||||
messageImagePart.setDataHandler(new DataHandler(imageDs));
|
||||
messageImagePart.setHeader("Content-ID", "<image>");
|
||||
|
||||
MimeMultipart multipart = new MimeMultipart();
|
||||
multipart.addBodyPart(messageTextPart);
|
||||
multipart.addBodyPart(messageImagePart);
|
||||
|
||||
getMailService().sendMail(toAddress, subject, multipart);
|
||||
} catch (MessagingException | MailException | WriterException | IOException e) {
|
||||
logger.log(Level.SEVERE, "Error trying to send mail to " + competitor.getName()
|
||||
+ " with e-mail address " + toAddress, e);
|
||||
occuredExceptions.append(e.getMessage()+"\r\n");
|
||||
sendInvitationEmail(locale, toAddress, leaderboardName, competitorName, url);
|
||||
} catch (MailException e) {
|
||||
occuredExceptions.append(e.getMessage() + "\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(occuredExceptions.length() == 0)){
|
||||
if (!(occuredExceptions.length() == 0)) {
|
||||
throw new MailException(occuredExceptions.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void sendInvitationEmail(Locale locale, final String toAddress, String leaderboardName, String invitee,
|
||||
String url) throws MailException {
|
||||
String subject = String.format("%s %s",
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "trackingInvitationFor"), invitee);
|
||||
|
||||
// taken from http://www.tutorialspoint.com/javamail_api/javamail_api_send_inlineimage_in_email.htm
|
||||
BodyPart messageTextPart = new MimeBodyPart();
|
||||
String htmlText = String.format("<h1>%s %s</h1>" + "<p>%s <b>%s</b></p>"
|
||||
+ "<img src=\"cid:image\" title=\"%s\"><br/>" + "<a href=\"%s\">%s</a>",
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "welcomeTo"), leaderboardName,
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "scanQRCodeOrVisitUrlToRegisterAs"), invitee, url, url,
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "alternativelyVisitThisLink"));
|
||||
|
||||
try {
|
||||
messageTextPart.setContent(htmlText, "text/html");
|
||||
|
||||
BodyPart messageImagePart = new MimeBodyPart();
|
||||
InputStream imageIs = QRCodeGenerationUtil.create(url, 250);
|
||||
DataSource imageDs = new ByteArrayDataSource(imageIs, "image/png");
|
||||
messageImagePart.setDataHandler(new DataHandler(imageDs));
|
||||
messageImagePart.setHeader("Content-ID", "<image>");
|
||||
|
||||
MimeMultipart multipart = new MimeMultipart();
|
||||
multipart.addBodyPart(messageTextPart);
|
||||
multipart.addBodyPart(messageImagePart);
|
||||
|
||||
getMailService().sendMail(toAddress, subject, multipart);
|
||||
} catch (MessagingException | MailException | WriterException | IOException e) {
|
||||
logger.log(Level.SEVERE, "Error trying to send mail to " + invitee + " with e-mail address " + toAddress, e);
|
||||
throw new MailException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inviteBuoyTenderViaEmail(Event event, Leaderboard leaderboard, String serverUrlWithoutTrailingSlash,
|
||||
String emails, Locale locale) throws MailException {
|
||||
|
||||
StringBuilder occuredExceptions = new StringBuilder();
|
||||
|
||||
String[] emailArray = emails.split(",");
|
||||
String leaderboardName = leaderboard.getName();
|
||||
|
||||
// http://<host>/buoy-tender/checkin&leaderboard_name=<leaderboard-name>
|
||||
String url = DeviceMappingConstants.getBuoyTenderInvitationUrl(serverUrlWithoutTrailingSlash, leaderboardName,
|
||||
NonGwtUrlHelper.INSTANCE);
|
||||
for (String toAddress : emailArray) {
|
||||
try {
|
||||
sendInvitationEmail(locale, toAddress, leaderboardName,
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "buoyTender"), url);
|
||||
} catch (MailException e) {
|
||||
occuredExceptions.append(e.getMessage() + "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!(occuredExceptions.length() == 0)) {
|
||||
throw new MailException(occuredExceptions.toString());
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -133,7 +133,8 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
|
||||
this.cachedRacingProcedureType = determineInitialProcedureType();
|
||||
this.cachedRaceStatus = RaceLogRaceStatus.UNKNOWN;
|
||||
this.cachedPassId = raceLog.getCurrentPassId();
|
||||
// TODO bug 2083: make sure the listener registration is "weak" in the sense that it is removed when this race state is no longer strongly referenced
|
||||
// see resolved bug 2083: make sure the listener registration is "weak" in the sense that it is removed when
|
||||
// this race state is no longer strongly referenced
|
||||
this.raceLog.addListener(new WeakRaceLogChangedVisitor(this.raceLog, this));
|
||||
// We known that recreateRacingProcedure calls update() when done, therefore this RaceState
|
||||
// will be fully initialized after this line
|
||||
|
||||
+1
@@ -6,6 +6,7 @@ import com.sap.sailing.domain.base.Mark;
|
||||
|
||||
/**
|
||||
* Defines a mark, that can then be used to build a course.
|
||||
*
|
||||
* @author Fredrik Teschke
|
||||
*
|
||||
*/
|
||||
|
||||
+2
-3
@@ -1,7 +1,6 @@
|
||||
package com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
@@ -10,13 +9,13 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
|
||||
public class DefinedMarkFinder extends RaceLogAnalyzer<Collection<Mark>> {
|
||||
public class DefinedMarkFinder extends RaceLogAnalyzer<Iterable<Mark>> {
|
||||
public DefinedMarkFinder(RaceLog raceLog) {
|
||||
super(raceLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Mark> performAnalysis() {
|
||||
protected Iterable<Mark> performAnalysis() {
|
||||
List< Mark> result = new ArrayList<Mark>();
|
||||
for (RaceLogEvent event : getLog().getUnrevokedEvents()) {
|
||||
if (event instanceof RaceLogDefineMarkEvent) {
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ public class RaceLogDefineMarkEventImpl extends RaceLogEventImpl implements Race
|
||||
public RaceLogDefineMarkEventImpl(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint,
|
||||
Serializable pId, int pPassId, Mark mark) {
|
||||
super(createdAt, author, logicalTimePoint, pId, Collections.<Competitor>emptyList(), pPassId);
|
||||
this.mark = mark;
|
||||
this.mark = mark;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+31
@@ -985,6 +985,37 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
assertEquals(29 /* two wins, one second */, leaderboardGroup.getOverallLeaderboard().getTotalPoints(c[3], later), 0.000000001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverallLeaderboardWithESSHighPointScoringWithTwoCompetitorsHavingWonTheSameNumberOfRegattas() throws NoWindException {
|
||||
Competitor[] c = createCompetitors(4).toArray(new Competitor[0]);
|
||||
Competitor[] f1 = new Competitor[] { c[2], c[0], c[1], c[3] };
|
||||
Competitor[] f2 = new Competitor[] { c[0], c[2], c[1], c[3] };
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
|
||||
FlexibleLeaderboard leaderboard1 = new FlexibleLeaderboardImpl("Regatta 1", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]),
|
||||
new HighPointFirstGets10Or8AndLastBreaksTie(), null);
|
||||
leaderboard1.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(f1)), "R1", /* medalRace */
|
||||
false);
|
||||
assertTrue(leaderboard1.getTotalPoints(c[2], later) > leaderboard1.getTotalPoints(c[0], later)); // c2 better than c[0]
|
||||
assertEquals(10.0, leaderboard1.getTotalPoints(c[2], later), 0.1);
|
||||
assertEquals(9.0, leaderboard1.getTotalPoints(c[0], later), 0.1);
|
||||
FlexibleLeaderboard leaderboard2 = new FlexibleLeaderboardImpl("Regatta 2", new ThresholdBasedResultDiscardingRuleImpl(/* discarding thresholds */ new int[0]),
|
||||
new HighPointFirstGets10Or8AndLastBreaksTie(), null);
|
||||
leaderboard2.addRace(new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(f2)), "R1", /* medalRace */
|
||||
false);
|
||||
LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl("Leaderboard Group", "Leaderboard Group", /* displayName */ null, false, Arrays.asList(leaderboard1,
|
||||
leaderboard2));
|
||||
leaderboardGroup.setOverallLeaderboard(new LeaderboardGroupMetaLeaderboard(leaderboardGroup, new HighPointExtremeSailingSeriesOverall(),
|
||||
new ThresholdBasedResultDiscardingRuleImpl(new int[0])));
|
||||
List<Competitor> rankedCompetitors = leaderboardGroup.getOverallLeaderboard().getCompetitorsFromBestToWorst(later);
|
||||
assertEquals(4, rankedCompetitors.size());
|
||||
assertEquals(19, leaderboardGroup.getOverallLeaderboard().getTotalPoints(c[0], later), 0.000000001);
|
||||
assertEquals(19, leaderboardGroup.getOverallLeaderboard().getTotalPoints(c[2], later), 0.000000001);
|
||||
assertEquals(16, leaderboardGroup.getOverallLeaderboard().getTotalPoints(c[1], later), 0.000000001);
|
||||
assertEquals(14, leaderboardGroup.getOverallLeaderboard().getTotalPoints(c[3], later), 0.000000001);
|
||||
assertEquals(c[0], rankedCompetitors.get(0));
|
||||
assertEquals(c[2], rankedCompetitors.get(1));
|
||||
}
|
||||
@Test
|
||||
public void testHighPointScoringEightWithInterpolationWhenFleetNotComplete() throws NoWindException {
|
||||
int competitorsCount = 21;
|
||||
|
||||
+126
@@ -8,12 +8,18 @@ import static org.junit.Assert.assertTrue;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sse.util.SmartFutureCache;
|
||||
import com.sap.sse.util.SmartFutureCache.CacheUpdater;
|
||||
import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
|
||||
import com.sap.sse.util.SmartFutureCache.UpdateInterval;
|
||||
|
||||
@@ -247,4 +253,124 @@ public class SmartFutureCacheTest {
|
||||
System.out.println("Tasks re-used: "+sfc.getSmartFutureCacheTaskReuseCounter());
|
||||
assertEquals(updatesTriggeredFor.size(), updateWasCalled.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfNoNewFuturesAreRunForTheSameKeyWhileCurrentTaskIsSleeping() throws InterruptedException, BrokenBarrierException {
|
||||
final AtomicInteger callCounter = new AtomicInteger(0);
|
||||
CyclicBarrier barrier = new CyclicBarrier(2);
|
||||
CacheUpdater<Integer, Integer, EmptyUpdateInterval> cacheUpdater = new CacheUpdater<Integer, Integer, SmartFutureCache.EmptyUpdateInterval>() {
|
||||
|
||||
@Override
|
||||
public Integer computeCacheUpdate(Integer key, EmptyUpdateInterval updateInterval) throws Exception {
|
||||
synchronized (callCounter) {
|
||||
if (key == 1) {
|
||||
callCounter.incrementAndGet();
|
||||
}
|
||||
}
|
||||
barrier.await();
|
||||
barrier.await();
|
||||
barrier.await();
|
||||
//For this test case value will be same as key, when updated.
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer provideNewCacheValue(Integer key, Integer oldCacheValue, Integer computedCacheUpdate,
|
||||
EmptyUpdateInterval updateInterval) {
|
||||
return computedCacheUpdate;
|
||||
}
|
||||
};
|
||||
SmartFutureCache<Integer, Integer, EmptyUpdateInterval> testCache = new SmartFutureCache<Integer, Integer, SmartFutureCache.EmptyUpdateInterval>(
|
||||
cacheUpdater, "SmartFutureTestCacheLock");
|
||||
testCache.triggerUpdate(1, null);
|
||||
barrier.await();
|
||||
assertEquals(1, callCounter.get());
|
||||
testCache.triggerUpdate(1, null);
|
||||
barrier.await();
|
||||
// Counter should still be one here, since first future is still sleeping at this point
|
||||
assertEquals(1, callCounter.get());
|
||||
barrier.await();
|
||||
|
||||
// Now the first future should be done, and the second update should have been called, so the counter should be 2
|
||||
barrier.await();
|
||||
assertEquals(2, callCounter.get());
|
||||
barrier.await();
|
||||
barrier.await();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTriggerAndGetWithWaitForLatestWithRunningFutureOnSuspendedCache() throws InterruptedException, BrokenBarrierException {
|
||||
final AtomicInteger callCounter = new AtomicInteger(0);
|
||||
CyclicBarrier barrier = new CyclicBarrier(2);
|
||||
CacheUpdater<Integer, Integer, EmptyUpdateInterval> cacheUpdater = new CacheUpdater<Integer, Integer, SmartFutureCache.EmptyUpdateInterval>() {
|
||||
|
||||
@Override
|
||||
public Integer computeCacheUpdate(Integer key, EmptyUpdateInterval updateInterval) throws Exception {
|
||||
synchronized (callCounter) {
|
||||
if (key == 1) {
|
||||
callCounter.incrementAndGet();
|
||||
}
|
||||
}
|
||||
barrier.await();
|
||||
barrier.await();
|
||||
barrier.await();
|
||||
return callCounter.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer provideNewCacheValue(Integer key, Integer oldCacheValue, Integer computedCacheUpdate,
|
||||
EmptyUpdateInterval updateInterval) {
|
||||
return computedCacheUpdate;
|
||||
}
|
||||
};
|
||||
SmartFutureCache<Integer, Integer, EmptyUpdateInterval> testCache = new SmartFutureCache<Integer, Integer, SmartFutureCache.EmptyUpdateInterval>(
|
||||
cacheUpdater, "SmartFutureTestCacheLock");
|
||||
testCache.triggerUpdate(1, null);
|
||||
barrier.await();
|
||||
assertEquals(1, callCounter.get());
|
||||
testCache.triggerUpdate(1, null);
|
||||
testCache.suspend();
|
||||
|
||||
CyclicBarrier getResultBarrier = new CyclicBarrier(2);
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//FIXME find a way to guarantee that get is called, while the first computeUpdate Future is still running
|
||||
int result = testCache.get(1, true);
|
||||
assertEquals(2, result);
|
||||
try {
|
||||
getResultBarrier.await();
|
||||
} catch (InterruptedException | BrokenBarrierException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
barrier.await();
|
||||
|
||||
barrier.await();
|
||||
|
||||
barrier.await();
|
||||
assertEquals(2, callCounter.get());
|
||||
//Trigger again. This update should not retrigger add another future, since cache is disabled and no
|
||||
// get with waitForLatest is called afterwards
|
||||
testCache.triggerUpdate(1, null);
|
||||
barrier.await();
|
||||
barrier.await();
|
||||
//Wait for get Thread to finish with getting and asserting
|
||||
getResultBarrier.await();
|
||||
assertEquals(2, callCounter.get());
|
||||
//Check if no compute Thread is waiting at barrier.
|
||||
boolean timeOut = false;
|
||||
try {
|
||||
barrier.await(10, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
timeOut = true;
|
||||
}
|
||||
assertTrue(timeOut);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Loaded 100 of 335 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user