Merge branch 'master' into bug4009

This commit is contained in:
Steffen Schaefer committed 2017-01-26 15:31:34 +01:00
commit 86ae110571
734 files changed
+8349 -37385

No files matched your search

+1 -1
View File
@@ -187,5 +187,5 @@ Export-Package: com.google.gwt.activity.shared,
javaemul.internal.annotations,
jsinterop.annotations
Require-Bundle: javax.servlet;bundle-version="3.1.0",
org.junit4;bundle-version="4.8.2";resolution:=optional,
org.junit;bundle-version="4.8.2";resolution:=optional,
com.google.gwt.dev;bundle-version="2.8.0"
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="output" path="bin"/>
</classpath>
-1
View File
@@ -1 +0,0 @@
bin
-28
View File
@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.sap.sailing.autoload</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
@@ -1,12 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
@@ -1,4 +0,0 @@
#Mon Aug 29 13:20:38 CEST 2011
eclipse.preferences.version=1
pluginProject.extensions=false
resolve.requirebundle=false
@@ -1,23 +0,0 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: AutoLoad Races
Bundle-SymbolicName: com.sap.sailing.autoload
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Export-Package: com.sap.sailing.autoload
Import-Package: org.json.simple,
org.json.simple.parser,
org.osgi.framework;version="1.7.0",
org.osgi.util.tracker;version="1.5.1"
Require-Bundle: com.sap.sailing.gwt.ui,
com.sap.sse.common,
com.sap.sailing.domain.shared.android,
com.sap.sailing.domain.tractracadapter,
com.sap.sailing.server,
com.sap.sailing.domain,
com.sap.sailing.domain.common,
com.sap.sailing.domain.persistence,
com.sap.sse.replication
Bundle-Activator: com.sap.sailing.autoload.Activator
@@ -1,4 +0,0 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.
-12
View File
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>root</artifactId>
<groupId>com.sap.sailing</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>com.sap.sailing.autoload</artifactId>
<packaging>eclipse-plugin</packaging>
</project>
@@ -1,32 +0,0 @@
package com.sap.sailing.autoload;
import java.util.logging.Logger;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.server.RacingEventService;
public class Activator implements BundleActivator {
Logger logger = Logger.getLogger(Activator.class.getName());
@Override
public void start(BundleContext context) throws Exception {
RacingEventService racingEventService = createAndOpenRacingEventServiceTracker(context).getService();
new TracTrac(context, racingEventService);
}
@Override
public void stop(BundleContext context) throws Exception {
}
protected ServiceTracker<RacingEventService, RacingEventService> createAndOpenRacingEventServiceTracker(
BundleContext context) {
ServiceTracker<RacingEventService, RacingEventService> result = new ServiceTracker<RacingEventService, RacingEventService>(
context, RacingEventService.class.getName(), null);
result.open();
return result;
}
}
@@ -1,141 +0,0 @@
package com.sap.sailing.autoload;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory;
import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sailing.domain.tracking.RaceTracker;
import com.sap.sailing.domain.tracking.TrackerManager;
import com.sap.sailing.domain.tractracadapter.RaceRecord;
import com.sap.sailing.domain.tractracadapter.TracTracAdapter;
import com.sap.sailing.domain.tractracadapter.TracTracAdapterFactory;
import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
/**
* Auto load TracTrac races from a parameter called <code>tractrac.autoload.json_urls</code>. This
* parameter contains a list of all event json urls from which you want to load races from. Only
* races in state <code>REPLAY</code> will be loaded.
*
* @author Simon Marcel Pamies
*/
public class TracTrac {
Logger logger = Logger.getLogger(TracTrac.class.getName());
private final TracTracAdapter tracTracAdapter;
private final RacingEventService racingEventService;
public TracTrac(BundleContext context, RacingEventService racingEventService) {
this.racingEventService = racingEventService;
this.tracTracAdapter = createAndOpenTracTracAdapterTracker(context).getService().getOrCreateTracTracAdapter(this.racingEventService.getBaseDomainFactory());
try {
autoLoadTrackTrackRaces();
} catch (Exception e) {
e.printStackTrace();
}
}
private TracTracAdapter getTracTracAdapter() {
return this.tracTracAdapter;
}
private RacingEventService getService() {
return this.racingEventService;
}
private void autoLoadTrackTrackRaces() throws Exception {
String jsonUrls = System.getProperty("tractrac.autoload.json_urls");
if (jsonUrls != null) {
String[] splitJsonUrls = jsonUrls.split(",");
for (String jsonUrl : splitJsonUrls) {
logger.info("Loading races from " + jsonUrl);
Pair<String, List<TracTracRaceRecordDTO>> racesThatCanBeTracked = listTracTracRacesInEvent(jsonUrl, /*listHiddenRaces*/false);
for (TracTracRaceRecordDTO raceRecord : racesThatCanBeTracked.getB()) {
RaceRecord record = getTracTracAdapter().getSingleTracTracRaceRecord(new URL(raceRecord.jsonURL), raceRecord.id, /*loadClientParams*/true);
if (record.getRaceStatus().equals(TracTracConnectionConstants.REPLAY_STATUS) || record.getRaceVisibility().equals(TracTracConnectionConstants.REPLAY_VISIBILITY)) {
RegattaIdentifier regattaForRaceRecord = null;
if (raceRecord.hasRememberedRegatta()) {
Regatta regatta = getService().getRememberedRegattaForRace(raceRecord.id);
if (regatta != null) {
regattaForRaceRecord = regatta.getRegattaIdentifier();
}
}
RaceLogStore raceLogStore = MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore(getService()
.getMongoObjectFactory(), getService().getDomainObjectFactory());
RegattaLogStore regattaLogStore = MongoRegattaLogStoreFactory.INSTANCE.getMongoRegattaLogStore(
getService().getMongoObjectFactory(), getService().getDomainObjectFactory());
getTracTracAdapter().addTracTracRace(
(TrackerManager) getService(),
regattaForRaceRecord,
record.getParamURL(), /* effectiveLiveURI */
null,
record.getStoredURI(),
new URI(""),
new MillisecondsTimePoint(record.getTrackingStartTime().asMillis()),
new MillisecondsTimePoint(record.getTrackingEndTime().asMillis()),
raceLogStore, regattaLogStore,
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, /* offsetToStartTimeOfSimulatedRace */
null, /*useTracTracMarkPassings*/ false,
/* tracTracUsername */"", /* tracTracPassword */"", record.getRaceStatus(),
record.getRaceVisibility());
} else {
logger.info("Ignoring race " + record.getName() + " because it is in status "
+ record.getRaceStatus() + " and visibility " + record.getRaceVisibility());
}
}
}
}
}
public com.sap.sse.common.Util.Pair<String, List<TracTracRaceRecordDTO>> listTracTracRacesInEvent(String eventJsonURL, boolean listHiddenRaces) throws MalformedURLException, IOException, ParseException, org.json.simple.parser.ParseException, URISyntaxException {
com.sap.sse.common.Util.Pair<String,List<RaceRecord>> raceRecords;
raceRecords = getTracTracAdapter().getTracTracRaceRecords(new URL(eventJsonURL), /*loadClientParam*/ false);
List<TracTracRaceRecordDTO> result = new ArrayList<TracTracRaceRecordDTO>();
for (RaceRecord raceRecord : raceRecords.getB()) {
if (listHiddenRaces == false && raceRecord.getRaceVisibility().equals(TracTracConnectionConstants.HIDDEN_VISIBILITY)) {
continue;
}
result.add(new TracTracRaceRecordDTO(raceRecord.getID(), raceRecord.getEventName(), raceRecord.getName(),
raceRecord.getTrackingStartTime().asDate(),
raceRecord
.getTrackingEndTime().asDate(), raceRecord.getRaceStartTime().asDate(),
raceRecord.getBoatClassNames(), raceRecord.getRaceStatus(), raceRecord.getRaceVisibility(), raceRecord.getJsonURL().toString(),
hasRememberedRegatta(raceRecord.getID())));
}
return new com.sap.sse.common.Util.Pair<String, List<TracTracRaceRecordDTO>>(raceRecords.getA(), result);
}
private boolean hasRememberedRegatta(Serializable raceID) {
return racingEventService.getRememberedRegattaForRace(raceID) != null;
}
private ServiceTracker<TracTracAdapterFactory, TracTracAdapterFactory> createAndOpenTracTracAdapterTracker(BundleContext context) {
ServiceTracker<TracTracAdapterFactory, TracTracAdapterFactory> result = new ServiceTracker<TracTracAdapterFactory, TracTracAdapterFactory>(
context, TracTracAdapterFactory.class.getName(), null);
result.open();
result.getService().getOrCreateTracTracAdapter(racingEventService.getBaseDomainFactory());
return result;
}
}
@@ -7,7 +7,7 @@ Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: org.osgi.framework;version="1.3.0"
Bundle-ActivationPolicy: lazy
Require-Bundle: org.junit4;bundle-version="4.8.2",
Require-Bundle: org.junit;bundle-version="4.8.2",
com.sap.sailing.barbados.resultimport,
com.sap.sailing.domain.common,
com.sap.sailing.domain,
@@ -13,9 +13,7 @@ Bundle-ActivationPolicy: lazy
Require-Bundle: com.sap.sailing.server,
com.sap.sailing.domain.common,
com.sap.sailing.domain,
jcl.over.slf4j;bundle-version="1.6.4",
com.sap.sailing.resultimport,
slf4j.api;bundle-version="1.6.4",
com.sap.sse.common,
org.dom4j;bundle-version="1.6.1",
org.apache.xmlbeans;bundle-version="2.3.0",
@@ -15,7 +15,7 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.domain.common,
com.sap.sailing.domain.shared.android,
com.sap.sailing.gwt.ui,
org.moxieapps.gwt.highcharts;bundle-version="1.6.0",
org.moxieapps.gwt.highcharts;bundle-version="1.6.0";resolution:=optional,
com.sap.sse.gwt,
com.sap.sailing.domain.igtimiadapter,
com.sap.sailing.expeditionconnector,
@@ -23,7 +23,7 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.declination,
org.json.simple;bundle-version="1.1.0",
com.sap.sailing.udpconnector,
com.googlecode.mgwt;bundle-version="2.0.0",
com.googlecode.mgwt;bundle-version="2.0.0";resolution:=optional,
com.sap.sse.gwt.adminconsole,
org.apache.commons.math;bundle-version="2.1.0"
Bundle-ActivationPolicy: lazy
@@ -20,7 +20,8 @@ CompetitorSearchTag=Competitor Search Tag
LeaderboardSailingDomainRetrieverChain=Leaderboards
RaceSailingDomainRetrieverChain=Races
LegSailingDomainRetrieverChain=Legs
GPSFixSailingDomainRetrieverChain=GPS-Fixes
GPSFixSailingDomainRetrieverChain=GPS Fixes
WindFixSailingDomainRetrieverChain=Wind Fixes
MarkPassingSailingDomainRetrieverChain=Mark Passings
RaceResultSailingDomainRetrieverChain=Race Results
RaceOfCompetitorSailingDomainRetrieverChain=Races of Competitors
@@ -30,7 +31,8 @@ Leaderboard=Leaderboard
Leg=Leg
MarkPassing=Mark Passing
LegOfCompetitor=Leg of competitor
GpsFix=GPS-Fix
GpsFix=GPS Fix
WindFix=Wind Fix
Maneuver=Maneuver
WindStrengthInBeaufort=Wind Strength in Beaufort
Bft0=Calm
@@ -72,6 +74,8 @@ Tack=Tack
SpeedBefore=Speed Before Maneuver
SpeedAfter=Speed After Maneuver
DirectionChange=Direction Change in Degrees
AbsoluteDirectionChange=Absolute Direction Change in Degrees (Positive)
ToSide=To Side (Port / Starboard)
ManeuverLoss=Maneuver Loss
Waypoint=Waypoint
PassingSide=Passing Side
@@ -82,4 +86,11 @@ WindwardDistanceToAdvantageousEndOfLine=Windward Distance to Advantageous End of
RankAfterHalfOfTheFirstLeg=Rank after the half of the first leg
AdvantageousEndOfLine=Advantageous End of Line
TimeSpentInSeconds=Time Spent in Seconds
MedalRace=Medal Race
MedalRace=Medal Race
WindSourceType=Wind Source Type
WindSourceName=Wind Source Name
windFrom=True Wind Direction (TWD)
windSpeedKnots=True Wind Speed (kts)
speedInKnots=Speed (kts)
bearing=Course over Ground (°T)
WindTrack=Wind Track
@@ -19,6 +19,7 @@ LeaderboardSailingDomainRetrieverChain=Leaderboards
RaceSailingDomainRetrieverChain=Rennen
LegSailingDomainRetrieverChain=Schenkel
GPSFixSailingDomainRetrieverChain=GPS-Fixes
WindFixSailingDomainRetrieverChain=Windmessungen
MarkPassingSailingDomainRetrieverChain=Tonnenrundungen
RaceResultSailingDomainRetrieverChain=Rennergebnisse
RaceOfCompetitorSailingDomainRetrieverChain=Rennen eines Teilnehmers
@@ -29,6 +30,7 @@ Leg=Schenkel
MarkPassing=Tonnenrundung
LegOfCompetitor=Schenkel eines Teilnehmers
GpsFix=GPS-Fix
WindFix=Windmessung
Maneuver=Manöver
Speed=Geschwindigkeit
SpeedTenSecondsBefore=Geschwindigkeit 10s vorher
@@ -72,6 +74,8 @@ Tack=Bug
SpeedBefore=Geschwindigkeit bevor dem Manöver
SpeedAfter=Geschwindigkeit nach dem Manöver
DirectionChange=Richtungsänderung in Grad
AbsoluteDirectionChange=Absolute Richtungsänderung in Grad (positiv)
ToSide=In Richtung (Backbord / Steuerbord)
ManeuverLoss=Manöververlust
Waypoint=Wegpunkt
PassingSide=Passierende Seite
@@ -82,4 +86,11 @@ WindwardDistanceToAdvantageousEndOfLine=Windw
RankAfterHalfOfTheFirstLeg=Platzierung nach der Hälfte des ersten Schenkels
AdvantageousEndOfLine=Bevorteiltes Ende der Startlinie
TimeSpentInSeconds=Benötigte Zeit in Sekunden
MedalRace=Medaillenrennen
MedalRace=Medaillenrennen
WindSourceType=Art der Windmessung
WindSourceName=Name der Windmessreihe
windFrom=Wind aus Richtung (TWD)
windSpeedKnots=Wahre Windgeschwindigkeit (kn)
speedInKnots=Fahrt (kn)
bearing=Kurs über Grund (°)
WindTrack=Windmessreihe
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<file datatype="javapropertyresourcebundle" date="2016-12-21T15:27:50Z" original="/usr/sap/ljs/app/Converter_2566045106627533633/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties" source-language="en" target-language="ja">
<file datatype="javapropertyresourcebundle" date="2017-01-12T14:29:56Z" original="/usr/sap/ljs/app/Converter_2566045106627533633/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties" source-language="en" target-language="ja">
<header>
<skl>
<internal-file crc="f38aaa3e2ebfcee22c5187ca5b77bc00" form="base64">H4sIAAAAAAAAAIVWS28jKRC+8yu4jJQcRopn9qkVKznJ2vHKeci2Ntoj7i53o7TBApys59dvVdEP7Ew8F7rq4wOKetHLHUCpljQKHldgl1A4W4Zr2DgPaU6OroJcMyBuTYjaFrDy+hUaXN0BskPEg96CokHMoVoddqDwK0kQS22a2a2ij3zYb9fgxb+gvaKB2Aljfjv9oKNxVjcmHlQmi3HhnT1sVfsVC6h0jFq1X3Hj9j7A2INWSZQki2un402jQ1AkSRbFpAGIikex0AUoGnCH7Q6iic6rQeQNeK1Ygd4qGjLmEu9R1CtdZUtkAiWieEVdgl877UvygbHVrdtqYxcQvYFX8Dc1aiqjBbboHJnmAznv/I5VENOn5cT8d46GjM9Iwf3utX95Qucg89wCosmWl0xdQNg38UcGy0RLSx43mQd/dFPpNnKgk6EW9kg5b2Xi5P6ferff5Z6WjOSUfJYcTF7MHXN0eyLkF+EkRluLIXemu4DO7ZzcWz6Y92xsuYwebBXrmb0Gvceai4pg2eHSWNnNiOtNvFI3utmSNFJzU9VRauNJ/dKqaw/wDQj5qqZgYwMZ9JO6d3hFHXPwZzXxEOoM+UXh8c5WGfSrusPt5RvaRupvaqobnvi941YtMLpCxPlk40j9Y1yDZsjQY1/U3d57U6AbsI4brPJXWBbUfjpNsiovrrANhfiHHMk3jH28PKbP7BP4Avc+XYcu+3RKpWQ6t4CzlBeO18E1+wgLbV9Up0jSUsCoRb6LFvdNCtUm9j1zHJdRI6NvmdFJRiS2IhZSF36usQ2TSjmWdjomnLbptO3QqxPariBDx3Fi0F+Ur4p02o8RSZBIvfZx0yViUAmh/O2xnrXSxUvOYL2f/dtgiLJZ1vvZJ8D+HQ83xhfNEa2dkO0MWz3F2g2Pfu5CQC7bzZDEpprA4TlydNnUWE35oadToRNDXnyiY+dcU5eDfa40++3EWBPq3DqGZcKz62Cs80uQ+t7ya4hvALaPwNiW7QHfu5K8GLVhkZ//bE+8FLOAz2vxgu/tLMhW7K0Ymg737syg7BVKbX2ItH85JfOZXfdPQefXu1PSE07RVjSkVDz6T2jzru9njI43EXtcIrA8zN8aDwW96dimbQWq12UCqIBuocKeM5hEXhpMIk0868POGaziThDdy4WBVq3MUWfru+Qg+cPCYktP6yqZP5TVqjY+Ht6v4Lh+PVlAfeEN029I2XH5qm3UFbh9+MuWj5u5saA6nsyTN6dK5HLuGuqXVN10yp1uNlibNXCe0WuVCp0tiDXIGgm0jOQN136Dz9n3bfjwuJXZAvrDxlnnKEWQZIzC1aLiHkrd8M8US9xOxf+VN8i0cAoAAA==</internal-file>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<file datatype="javapropertyresourcebundle" date="2016-12-21T15:27:50Z" original="/usr/sap/ljs/app/Converter_2566045106627533633/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties" source-language="en" target-language="ru">
<file datatype="javapropertyresourcebundle" date="2017-01-12T14:31:58Z" original="/usr/sap/ljs/app/Converter_2566045106627533633/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties" source-language="en" target-language="ru">
<header>
<skl>
<internal-file crc="f38aaa3e2ebfcee22c5187ca5b77bc00" form="base64">H4sIAAAAAAAAAIVWS28jKRC+8yu4jJQcRopn9qkVKznJ2vHKeci2Ntoj7i53o7TBApys59dvVdEP7Ew8F7rq4wOKetHLHUCpljQKHldgl1A4W4Zr2DgPaU6OroJcMyBuTYjaFrDy+hUaXN0BskPEg96CokHMoVoddqDwK0kQS22a2a2ij3zYb9fgxb+gvaKB2Aljfjv9oKNxVjcmHlQmi3HhnT1sVfsVC6h0jFq1X3Hj9j7A2INWSZQki2un402jQ1AkSRbFpAGIikex0AUoGnCH7Q6iic6rQeQNeK1Ygd4qGjLmEu9R1CtdZUtkAiWieEVdgl877UvygbHVrdtqYxcQvYFX8Dc1aiqjBbboHJnmAznv/I5VENOn5cT8d46GjM9Iwf3utX95Qucg89wCosmWl0xdQNg38UcGy0RLSx43mQd/dFPpNnKgk6EW9kg5b2Xi5P6ferff5Z6WjOSUfJYcTF7MHXN0eyLkF+EkRluLIXemu4DO7ZzcWz6Y92xsuYwebBXrmb0Gvceai4pg2eHSWNnNiOtNvFI3utmSNFJzU9VRauNJ/dKqaw/wDQj5qqZgYwMZ9JO6d3hFHXPwZzXxEOoM+UXh8c5WGfSrusPt5RvaRupvaqobnvi941YtMLpCxPlk40j9Y1yDZsjQY1/U3d57U6AbsI4brPJXWBbUfjpNsiovrrANhfiHHMk3jH28PKbP7BP4Avc+XYcu+3RKpWQ6t4CzlBeO18E1+wgLbV9Up0jSUsCoRb6LFvdNCtUm9j1zHJdRI6NvmdFJRiS2IhZSF36usQ2TSjmWdjomnLbptO3QqxPariBDx3Fi0F+Ur4p02o8RSZBIvfZx0yViUAmh/O2xnrXSxUvOYL2f/dtgiLJZ1vvZJ8D+HQ83xhfNEa2dkO0MWz3F2g2Pfu5CQC7bzZDEpprA4TlydNnUWE35oadToRNDXnyiY+dcU5eDfa40++3EWBPq3DqGZcKz62Cs80uQ+t7ya4hvALaPwNiW7QHfu5K8GLVhkZ//bE+8FLOAz2vxgu/tLMhW7K0Ymg737syg7BVKbX2ItH85JfOZXfdPQefXu1PSE07RVjSkVDz6T2jzru9njI43EXtcIrA8zN8aDwW96dimbQWq12UCqIBuocKeM5hEXhpMIk0868POGaziThDdy4WBVq3MUWfru+Qg+cPCYktP6yqZP5TVqjY+Ht6v4Lh+PVlAfeEN029I2XH5qm3UFbh9+MuWj5u5saA6nsyTN6dK5HLuGuqXVN10yp1uNlibNXCe0WuVCp0tiDXIGgm0jOQN136Dz9n3bfjwuJXZAvrDxlnnKEWQZIzC1aLiHkrd8M8US9xOxf+VN8i0cAoAAA==</internal-file>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<file datatype="javapropertyresourcebundle" date="2016-12-21T15:27:51Z" original="/usr/sap/ljs/app/Converter_2566045106627533633/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties" source-language="en" target-language="zh-CN">
<file datatype="javapropertyresourcebundle" date="2017-01-12T14:33:45Z" original="/usr/sap/ljs/app/Converter_2566045106627533633/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties" source-language="en" target-language="zh-CN">
<header>
<skl>
<internal-file crc="f38aaa3e2ebfcee22c5187ca5b77bc00" form="base64">H4sIAAAAAAAAAIVWS28jKRC+8yu4jJQcRopn9qkVKznJ2vHKeci2Ntoj7i53o7TBApys59dvVdEP7Ew8F7rq4wOKetHLHUCpljQKHldgl1A4W4Zr2DgPaU6OroJcMyBuTYjaFrDy+hUaXN0BskPEg96CokHMoVoddqDwK0kQS22a2a2ij3zYb9fgxb+gvaKB2Aljfjv9oKNxVjcmHlQmi3HhnT1sVfsVC6h0jFq1X3Hj9j7A2INWSZQki2un402jQ1AkSRbFpAGIikex0AUoGnCH7Q6iic6rQeQNeK1Ygd4qGjLmEu9R1CtdZUtkAiWieEVdgl877UvygbHVrdtqYxcQvYFX8Dc1aiqjBbboHJnmAznv/I5VENOn5cT8d46GjM9Iwf3utX95Qucg89wCosmWl0xdQNg38UcGy0RLSx43mQd/dFPpNnKgk6EW9kg5b2Xi5P6ferff5Z6WjOSUfJYcTF7MHXN0eyLkF+EkRluLIXemu4DO7ZzcWz6Y92xsuYwebBXrmb0Gvceai4pg2eHSWNnNiOtNvFI3utmSNFJzU9VRauNJ/dKqaw/wDQj5qqZgYwMZ9JO6d3hFHXPwZzXxEOoM+UXh8c5WGfSrusPt5RvaRupvaqobnvi941YtMLpCxPlk40j9Y1yDZsjQY1/U3d57U6AbsI4brPJXWBbUfjpNsiovrrANhfiHHMk3jH28PKbP7BP4Avc+XYcu+3RKpWQ6t4CzlBeO18E1+wgLbV9Up0jSUsCoRb6LFvdNCtUm9j1zHJdRI6NvmdFJRiS2IhZSF36usQ2TSjmWdjomnLbptO3QqxPariBDx3Fi0F+Ur4p02o8RSZBIvfZx0yViUAmh/O2xnrXSxUvOYL2f/dtgiLJZ1vvZJ8D+HQ83xhfNEa2dkO0MWz3F2g2Pfu5CQC7bzZDEpprA4TlydNnUWE35oadToRNDXnyiY+dcU5eDfa40++3EWBPq3DqGZcKz62Cs80uQ+t7ya4hvALaPwNiW7QHfu5K8GLVhkZ//bE+8FLOAz2vxgu/tLMhW7K0Ymg737syg7BVKbX2ItH85JfOZXfdPQefXu1PSE07RVjSkVDz6T2jzru9njI43EXtcIrA8zN8aDwW96dimbQWq12UCqIBuocKeM5hEXhpMIk0868POGaziThDdy4WBVq3MUWfru+Qg+cPCYktP6yqZP5TVqjY+Ht6v4Lh+PVlAfeEN029I2XH5qm3UFbh9+MuWj5u5saA6nsyTN6dK5HLuGuqXVN10yp1uNlibNXCe0WuVCp0tiDXIGgm0jOQN136Dz9n3bfjwuJXZAvrDxlnnKEWQZIzC1aLiHkrd8M8US9xOxf+VN8i0cAoAAA==</internal-file>
@@ -17,6 +17,9 @@ 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;
import com.sap.sailing.datamining.data.HasWindFixContext;
import com.sap.sailing.datamining.data.HasWindTrackContext;
import com.sap.sailing.datamining.impl.components.aggregators.ParallelBearingAverageDegreesAggregationProcessor;
import com.sap.sailing.datamining.impl.components.aggregators.ParallelBoolSumAggregationProcessor;
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceAverageAggregationProcessor;
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMaxAggregationProcessor;
@@ -81,6 +84,8 @@ public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries
internalClasses.add(HasTrackedLegContext.class);
internalClasses.add(HasTrackedLegOfCompetitorContext.class);
internalClasses.add(HasGPSFixContext.class);
internalClasses.add(HasWindTrackContext.class);
internalClasses.add(HasWindFixContext.class);
internalClasses.add(HasManeuverContext.class);
internalClasses.add(HasMarkPassingContext.class);
internalClasses.add(HasRaceOfCompetitorContext.class);
@@ -112,6 +117,7 @@ public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries
aggregators.add(ParallelDistanceMaxAggregationProcessor.getDefinition());
aggregators.add(ParallelDistanceMinAggregationProcessor.getDefinition());
aggregators.add(ParallelDistanceMedianAggregationProcessor.getDefinition());
aggregators.add(ParallelBearingAverageDegreesAggregationProcessor.getDefinition());
return aggregators;
}
@@ -133,7 +139,6 @@ public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries
if (INSTANCE == null) {
INSTANCE = new Activator(); // probably non-OSGi case, as in test execution
}
return INSTANCE;
}
@@ -12,6 +12,8 @@ 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;
import com.sap.sailing.datamining.data.HasWindFixContext;
import com.sap.sailing.datamining.data.HasWindTrackContext;
import com.sap.sailing.datamining.impl.components.CompetitorOfRaceInLeaderboardRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.GPSFixRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProcessor;
@@ -22,6 +24,8 @@ import com.sap.sailing.datamining.impl.components.RaceOfCompetitorRetrievalProce
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.datamining.impl.components.WindFixRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.WindTrackRetrievalProcessor;
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.datamining.components.DataRetrieverChainDefinition;
@@ -69,6 +73,13 @@ public class SailingDataRetrievalChainDefinitions {
HasGPSFixContext.class, "GpsFix");
dataRetrieverChainDefinitions.add(gpsFixRetrieverChainDefinition);
final DataRetrieverChainDefinition<RacingEventService, HasWindFixContext> windFixRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
trackedRaceRetrieverChainDefinition, HasWindFixContext.class, "WindFixSailingDomainRetrieverChain");
windFixRetrieverChainDefinition.addAfter(TrackedRaceRetrievalProcessor.class, WindTrackRetrievalProcessor.class, HasWindTrackContext.class, "WindTrack");
windFixRetrieverChainDefinition.endWith(WindTrackRetrievalProcessor.class, WindFixRetrievalProcessor.class,
HasWindFixContext.class, "WindFix");
dataRetrieverChainDefinitions.add(windFixRetrieverChainDefinition);
final DataRetrieverChainDefinition<RacingEventService, HasManeuverContext> maneuverRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
legOfCompetitorRetrieverChainDefinition, HasManeuverContext.class, "ManeuverSailingDomainRetrieverChain");
maneuverRetrieverChainDefinition.endWith(TrackedLegOfCompetitorRetrievalProcessor.class, ManeuverRetrievalProcessor.class,
@@ -1,22 +1,24 @@
package com.sap.sailing.datamining.data;
import java.util.Locale;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
import com.sap.sse.i18n.ResourceBundleStringMessages;
public interface HasGPSFixContext {
public interface HasGPSFixContext extends HasWindOnTrackedLeg {
@Connector(scanForStatistics=false)
public HasTrackedLegOfCompetitorContext getTrackedLegOfCompetitorContext();
@Connector(ordinal=1)
public GPSFixMoving getGPSFix();
@Dimension(messageKey="WindStrengthInBeaufort", ordinal=11)
public ClusterDTO getWindStrengthAsBeaufortCluster(Locale locale, ResourceBundleStringMessages stringMessages);
@Override
default TimePoint getTimePoint() {
return getGPSFix().getTimePoint();
}
@Override
default Position getPosition() {
return getGPSFix().getPosition();
}
}
@@ -0,0 +1,21 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Positioned;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Timed;
public interface HasManeuver extends Positioned, Timed {
Maneuver getManeuver();
@Override
default TimePoint getTimePoint() {
return getManeuver().getTimePoint();
}
@Override
default Position getPosition() {
return getManeuver().getPosition();
}
}
@@ -2,20 +2,17 @@ package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
public interface HasManeuverContext {
public interface HasManeuverContext extends HasWindOnTrackedLeg, HasManeuver, HasTrackedLegOfCompetitor {
@Connector(scanForStatistics=false)
HasTrackedLegOfCompetitorContext getTrackedLegOfCompetitorContext();
Maneuver getManeuver();
//TODO Clean-Up:
// Move Dimensions and Statistics to Maneuver and connect to it
@Dimension(messageKey="ManeuverType", ordinal=12)
@@ -31,6 +28,12 @@ public interface HasManeuverContext {
@Statistic(messageKey="DirectionChange", resultDecimals=2, ordinal=2)
Double getDirectionChangeInDegrees();
@Statistic(messageKey="AbsoluteDirectionChange", resultDecimals=2, ordinal=2)
Double getAbsoluteDirectionChangeInDegrees();
@Dimension(messageKey="ToSide")
NauticalSide getToSide();
@Statistic(messageKey="ManeuverLoss", resultDecimals=0, ordinal=3)
Distance getManeuverLoss();
@@ -4,18 +4,14 @@ import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.tracking.MarkPassingManeuver;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
public interface HasMarkPassingContext {
public interface HasMarkPassingContext extends HasWindOnTrackedLeg, HasManeuver, HasTrackedLegOfCompetitor {
@Connector(scanForStatistics=false)
HasTrackedLegOfCompetitorContext getTrackedLegOfCompetitorContext();
MarkPassingManeuver getManeuver();
//TODO Clean-Up:
// Move Dimensions and Statistics to Maneuver/MarkPassingManeuver and connect to it
// Find a way to implement HasManeuverContext and HasMarkPassingManeuver with a base class
@@ -16,6 +16,7 @@ public interface HasRaceOfCompetitorContext {
public HasTrackedRaceContext getTrackedRaceContext();
@Connector(messageKey="Competitor")
@Statistic(messageKey="")
public Competitor getCompetitor();
@Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible
@@ -0,0 +1,5 @@
package com.sap.sailing.datamining.data;
public interface HasTrackedLegOfCompetitor {
HasTrackedLegOfCompetitorContext getTrackedLegOfCompetitorContext();
}
@@ -8,8 +8,7 @@ import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
public interface HasTrackedLegOfCompetitorContext {
public interface HasTrackedLegOfCompetitorContext extends HasWindOnTrackedLeg {
@Connector(scanForStatistics=false)
public HasTrackedLegContext getTrackedLegContext();
@@ -0,0 +1,23 @@
package com.sap.sailing.datamining.data;
import java.util.Locale;
import com.sap.sailing.datamining.Activator;
import com.sap.sailing.domain.common.Positioned;
import com.sap.sailing.domain.common.Wind;
import com.sap.sse.common.Timed;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.data.Cluster;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
import com.sap.sse.i18n.ResourceBundleStringMessages;
public interface HasWind extends Positioned, Timed {
Wind getWind();
@Dimension(messageKey="WindStrengthInBeaufort", ordinal=11)
default ClusterDTO getWindStrengthAsBeaufortCluster(Locale locale, ResourceBundleStringMessages stringMessages) {
Wind wind = getWind();
Cluster<?> cluster = Activator.getClusterGroups().getWindStrengthInBeaufortClusterGroup().getClusterFor(wind);
return new ClusterDTO(cluster.asLocalizedString(locale, stringMessages));
}
}
@@ -0,0 +1,35 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Wind;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
public interface HasWindFixContext extends HasWind {
@Connector(scanForStatistics=false)
public HasTrackedRaceContext getTrackedRaceContext();
@Statistic(messageKey="")
public Wind getWind();
@Statistic(messageKey="windFrom", resultDecimals=1)
double getWindFromDegrees();
@Statistic(messageKey="windSpeedKnots", resultDecimals=1)
double getWindSpeedInKnots();
@Override
default TimePoint getTimePoint() {
return getWind().getTimePoint();
}
@Override
default Position getPosition() {
return getWind().getPosition();
}
@Dimension(messageKey="WindSourceType")
String getWindSourceType();
}
@@ -0,0 +1,17 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.common.Wind;
public interface HasWindOnTrackedLeg extends HasTrackedLegOfCompetitor, HasWind {
default Wind getWind() {
if (getWindInternal() == null) {
setWindInternal(getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext().getTrackedRace()
.getWind(getPosition(), getTimePoint()));
}
return getWindInternal();
}
Wind getWindInternal();
void setWindInternal(Wind wind);
}
@@ -0,0 +1,18 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
public interface HasWindTrackContext {
@Connector(scanForStatistics=false)
public HasTrackedRaceContext getTrackedRaceContext();
@Dimension(messageKey="WindSourceType")
String getWindSourceType();
@Dimension(messageKey="WindSourceName")
String getWindSourceName();
WindTrack getWindTrack();
}
@@ -0,0 +1,44 @@
package com.sap.sailing.datamining.impl.components;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.datamining.data.HasWindFixContext;
import com.sap.sailing.datamining.data.HasWindTrackContext;
import com.sap.sailing.datamining.impl.data.WindFixWithContext;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
/**
* Retrieves all wind fixes from a {@link TrackedRace} that are provided by wind sources that are not currently
* {@link TrackedRace#getWindSourcesToExclude() excluded}.
*
* @author Axel Uhl (d043530)
*
*/
public class WindFixRetrievalProcessor extends AbstractRetrievalProcessor<HasWindTrackContext, HasWindFixContext> {
public WindFixRetrievalProcessor(ExecutorService executor, Collection<Processor<HasWindFixContext, ?>> resultReceivers, int retrievalLevel) {
super(HasWindTrackContext.class, HasWindFixContext.class, executor, resultReceivers, retrievalLevel);
}
@Override
protected Iterable<HasWindFixContext> retrieveData(HasWindTrackContext element) {
Collection<HasWindFixContext> windFixesWithContext = new ArrayList<>();
final WindTrack windTrack = element.getWindTrack();
windTrack.lockForRead();
try {
for (final Wind wind : windTrack.getFixes()) {
windFixesWithContext.add(new WindFixWithContext(element.getTrackedRaceContext(), wind, element.getWindSourceType()));
}
} finally {
windTrack.unlockAfterRead();
}
return windFixesWithContext;
}
}
@@ -0,0 +1,42 @@
package com.sap.sailing.datamining.impl.components;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
import com.sap.sailing.datamining.data.HasWindTrackContext;
import com.sap.sailing.datamining.impl.data.WindTrackWithContext;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
/**
* Retrieves all wind fixes from a {@link TrackedRace} that are provided by wind sources that are not currently
* {@link TrackedRace#getWindSourcesToExclude() excluded}.
*
* @author Axel Uhl (d043530)
*
*/
public class WindTrackRetrievalProcessor extends AbstractRetrievalProcessor<HasTrackedRaceContext, HasWindTrackContext> {
public WindTrackRetrievalProcessor(ExecutorService executor, Collection<Processor<HasWindTrackContext, ?>> resultReceivers, int retrievalLevel) {
super(HasTrackedRaceContext.class, HasWindTrackContext.class, executor, resultReceivers, retrievalLevel);
}
@Override
protected Iterable<HasWindTrackContext> retrieveData(HasTrackedRaceContext element) {
Collection<HasWindTrackContext> windTracksWithContext = new ArrayList<>();
final TrackedRace trackedRace = element.getTrackedRace();
for (final WindSource windSource : trackedRace.getWindSources()) {
if (!trackedRace.getWindSourcesToExclude().contains(windSource)) {
final WindTrack windTrack = trackedRace.getOrCreateWindTrack(windSource);
windTracksWithContext.add(new WindTrackWithContext(element, windTrack, windSource));
}
}
return windTracksWithContext;
}
}
@@ -0,0 +1,56 @@
package com.sap.sailing.datamining.impl.components.aggregators;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.BearingCluster;
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
import com.sap.sse.datamining.impl.components.SimpleAggregationProcessorDefinition;
import com.sap.sse.datamining.impl.components.aggregators.AbstractParallelGroupedDataStoringAggregationProcessor;
import com.sap.sse.datamining.shared.GroupKey;
public class ParallelBearingAverageDegreesAggregationProcessor
extends AbstractParallelGroupedDataStoringAggregationProcessor<Bearing, Double> {
private static final AggregationProcessorDefinition<Bearing, Double> DEFINITION =
new SimpleAggregationProcessorDefinition<>(Bearing.class, Double.class, "Average", ParallelBearingAverageDegreesAggregationProcessor.class);
private final Map<GroupKey, BearingCluster> results;
public static AggregationProcessorDefinition<Bearing, Double> getDefinition() {
return DEFINITION;
}
public ParallelBearingAverageDegreesAggregationProcessor(ExecutorService executor,
Collection<Processor<Map<GroupKey, Double>, ?>> resultReceivers) {
super(executor, resultReceivers, "Average");
results = new HashMap<>();
}
@Override
protected void storeElement(GroupedDataEntry<Bearing> element) {
BearingCluster cluster = results.get(element.getKey());
if (cluster == null) {
cluster = new BearingCluster();
results.put(element.getKey(), cluster);
}
cluster.add(element.getDataEntry());
}
@Override
protected Map<GroupKey, Double> aggregateResult() {
Map<GroupKey, Double> result = new HashMap<>();
for (Entry<GroupKey, BearingCluster> clusterEntry : results.entrySet()) {
GroupKey key = clusterEntry.getKey();
result.put(key, clusterEntry.getValue().getAverage().getDegrees());
}
return result;
}
}
@@ -7,7 +7,6 @@ import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.impl.MeterDistance;
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
@@ -56,7 +55,7 @@ public class ParallelDistanceAverageAggregationProcessor
Map<GroupKey, Distance> sumAggregation = sumAggregationProcessor.getResult();
for (Entry<GroupKey, Distance> sumAggregationEntry : sumAggregation.entrySet()) {
GroupKey key = sumAggregationEntry.getKey();
result.put(key, new MeterDistance(sumAggregationEntry.getValue().getMeters() / elementAmountPerKey.get(key).doubleValue()));
result.put(key, sumAggregationEntry.getValue().scale(1. / elementAmountPerKey.get(key).doubleValue()));
}
return result;
}
@@ -44,5 +44,4 @@ public class ParallelDistanceSumAggregationProcessor extends
protected Map<GroupKey, Distance> getResult() {
return results;
}
}
@@ -1,18 +1,13 @@
package com.sap.sailing.datamining.impl.data;
import java.util.Locale;
import com.sap.sailing.datamining.Activator;
import com.sap.sailing.datamining.data.HasGPSFixContext;
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sse.datamining.data.Cluster;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
import com.sap.sse.i18n.ResourceBundleStringMessages;
public class GPSFixWithContext implements HasGPSFixContext {
private static final long serialVersionUID = -4537126043228674949L;
private final HasTrackedLegOfCompetitorContext trackedLegOfCompetitorContext;
private final GPSFixMoving gpsFix;
@@ -32,20 +27,14 @@ public class GPSFixWithContext implements HasGPSFixContext {
public GPSFixMoving getGPSFix() {
return gpsFix;
}
@Override
public ClusterDTO getWindStrengthAsBeaufortCluster(Locale locale, ResourceBundleStringMessages stringMessages) {
Wind wind = getWind();
Cluster<?> cluster = Activator.getClusterGroups().getWindStrengthInBeaufortClusterGroup().getClusterFor(wind);
return new ClusterDTO(cluster.asLocalizedString(locale, stringMessages));
}
private Wind getWind() {
if (wind == null) {
wind = getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext().getTrackedRace()
.getWind(gpsFix.getPosition(), gpsFix.getTimePoint());
}
@Override
public Wind getWindInternal() {
return wind;
}
@Override
public void setWindInternal(Wind wind) {
this.wind = wind;
}
}
@@ -4,14 +4,17 @@ import com.sap.sailing.datamining.data.HasManeuverContext;
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.tracking.Maneuver;
public class ManeuverWithContext implements HasManeuverContext {
private static final long serialVersionUID = 7717196485074392156L;
private final HasTrackedLegOfCompetitorContext trackedLegOfCompetitor;
private final Maneuver maneuver;
private Wind wind;
public ManeuverWithContext(HasTrackedLegOfCompetitorContext trackedLegOfCompetitor, Maneuver maneuver) {
this.trackedLegOfCompetitor = trackedLegOfCompetitor;
@@ -53,9 +56,28 @@ public class ManeuverWithContext implements HasManeuverContext {
return getManeuver().getDirectionChangeInDegrees();
}
@Override
public Double getAbsoluteDirectionChangeInDegrees() {
return Math.abs(getManeuver().getDirectionChangeInDegrees());
}
@Override
public NauticalSide getToSide() {
return getManeuver().getDirectionChangeInDegrees() >= 0 ? NauticalSide.STARBOARD : NauticalSide.PORT;
}
@Override
public Distance getManeuverLoss() {
return getManeuver().getManeuverLoss();
}
@Override
public Wind getWindInternal() {
return wind;
}
@Override
public void setWindInternal(Wind wind) {
this.wind = wind;
}
}
@@ -7,18 +7,20 @@ import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.tracking.MarkPassingManeuver;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.Util;
public class MarkPassingWithContext implements HasMarkPassingContext {
private static final long serialVersionUID = -337042113749307686L;
private final HasTrackedLegOfCompetitorContext trackedLegOfCompetitor;
private final MarkPassingManeuver maneuver;
private Double absoluteRank;
private boolean rankHasBeenInitialized;
private Wind wind;
public MarkPassingWithContext(HasTrackedLegOfCompetitorContext trackedLegOfCompetitor, MarkPassingManeuver maneuver) {
this.trackedLegOfCompetitor = trackedLegOfCompetitor;
@@ -84,4 +86,13 @@ public class MarkPassingWithContext implements HasMarkPassingContext {
return absoluteRank;
}
@Override
public Wind getWindInternal() {
return wind;
}
@Override
public void setWindInternal(Wind wind) {
this.wind = wind;
}
}
@@ -6,7 +6,10 @@ import com.sap.sailing.datamining.data.HasTrackedLegContext;
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.TimePoint;
@@ -15,6 +18,7 @@ import com.sap.sse.datamining.data.Cluster;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompetitorContext {
private static final long serialVersionUID = 5944904146286262768L;
private final HasTrackedLegContext trackedLegContext;
@@ -25,6 +29,7 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
private boolean isRankAtStartInitialized;
private Double rankAtFinish;
private boolean isRankAtFinishInitialized;
private Wind wind;
public TrackedLegOfCompetitorWithContext(HasTrackedLegContext trackedLegContext, TrackedLegOfCompetitor trackedLegOfCompetitor) {
this.trackedLegContext = trackedLegContext;
@@ -120,5 +125,52 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti
return (finishTime.asMillis() - startTime.asMillis()) / 1000;
}
@Override
public Wind getWindInternal() {
return wind;
}
@Override
public void setWindInternal(Wind wind) {
this.wind = wind;
}
@Override
public Position getPosition() {
final TrackedLeg trackedLeg = getTrackedLegContext().getTrackedLeg();
final TrackedRace trackedRace = trackedLeg.getTrackedRace();
final TimePoint timepoint = getTimePointBetweenLegStartAndLegFinish(trackedRace);
final Position result;
if (timepoint == null) {
result = null;
} else {
result = trackedLeg.getMiddleOfLeg(timepoint);
}
return result;
}
private TimePoint getTimePointBetweenLegStartAndLegFinish(final TrackedRace trackedRace) {
final TimePoint competitorLegStartTime = getTrackedLegOfCompetitor().getStartTime();
final TimePoint competitorLegEndTime = getTrackedLegOfCompetitor().getFinishTime();
final TimePoint startTime = competitorLegStartTime != null ? competitorLegStartTime :
trackedRace.getStartOfRace() != null ? trackedRace.getStartOfRace() : trackedRace.getStartOfTracking();
final TimePoint endTime = competitorLegEndTime != null ? competitorLegEndTime :
trackedRace.getEndOfRace() != null ? trackedRace.getEndOfRace() : trackedRace.getEndOfTracking();
final TimePoint timepoint = endTime == null ? startTime : startTime == null ? null : startTime.plus(startTime.until(endTime).divide(2));
return timepoint;
}
@Override
public TimePoint getTimePoint() {
final TrackedLeg trackedLeg = getTrackedLegContext().getTrackedLeg();
final TrackedRace trackedRace = trackedLeg.getTrackedRace();
return getTimePointBetweenLegStartAndLegFinish(trackedRace);
}
@Override
public HasTrackedLegOfCompetitorContext getTrackedLegOfCompetitorContext() {
return this;
}
}
@@ -0,0 +1,52 @@
package com.sap.sailing.datamining.impl.data;
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
import com.sap.sailing.datamining.data.HasWindFixContext;
import com.sap.sailing.domain.common.Wind;
public class WindFixWithContext implements HasWindFixContext {
private static final long serialVersionUID = -4537126043228674949L;
private final HasTrackedRaceContext trackedRaceContext;
private final String windSourceType;
private final Wind wind;
public WindFixWithContext(HasTrackedRaceContext trackedRaceContext, Wind wind, String windSourceType) {
this.trackedRaceContext = trackedRaceContext;
this.wind = wind;
this.windSourceType = windSourceType;
}
@Override
public HasTrackedRaceContext getTrackedRaceContext() {
return trackedRaceContext;
}
@Override
public Wind getWind() {
return wind;
}
@Override
public double getWindFromDegrees() {
return getWind().getFrom().getDegrees();
}
@Override
public double getWindSpeedInKnots() {
return getWind().getKnots();
}
@Override
public String getWindSourceType() {
return windSourceType;
}
@Override
public String toString() {
return "WindFixWithContext [trackedRaceContext=" + trackedRaceContext + ", windSourceType=" + windSourceType
+ ", wind=" + wind + "]";
}
}
@@ -0,0 +1,51 @@
package com.sap.sailing.datamining.impl.data;
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
import com.sap.sailing.datamining.data.HasWindTrackContext;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.tracking.WindTrack;
public class WindTrackWithContext implements HasWindTrackContext {
private final HasTrackedRaceContext trackedRaceContext;
private final String windSourceType;
private final String windSourceName;
private final WindTrack windTrack;
public WindTrackWithContext(HasTrackedRaceContext trackedRaceContext, WindTrack windTrack, WindSource windSource) {
this.trackedRaceContext = trackedRaceContext;
this.windTrack = windTrack;
this.windSourceType = windSource.getType().name();
this.windSourceName = windSource.getType().name()+(windSource.getId()==null?"":" ("+windSource.getId()+")");
}
@Override
public HasTrackedRaceContext getTrackedRaceContext() {
return trackedRaceContext;
}
@Override
public String getWindSourceType() {
return windSourceType;
}
@Override
public String toString() {
return "WindTrackWithContext [trackedRaceContext=" + trackedRaceContext + ", windSourceType=" + windSourceType
+ ", windSourceName=" + windSourceName + "]";
}
@Override
public String getWindSourceName() {
return windSourceName;
}
@Override
public WindTrack getWindTrack() {
return windTrack;
}
}
@@ -6,7 +6,7 @@ Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Fragment-Host: com.sap.sailing.declination
Require-Bundle: org.junit4;bundle-version="4.8.2"
Require-Bundle: org.junit;bundle-version="4.8.2"
Import-Package: com.sap.sailing.domain.common,
com.sap.sailing.domain.common.impl,
com.sap.sailing.domain.common.quadtree
@@ -16,7 +16,7 @@ public enum BoatClassMasterdata {
_49ER ("49er", true, 4.88, 1.93, BoatHullType.MONOHULL, true),
_49ERFX ("49erFX", true, 4.88, 1.93, BoatHullType.MONOHULL, true, "49FX"),
_420 ("420", true, 4.20, 1.65, BoatHullType.MONOHULL, true, "420er", "420M", "420W"),
_470 ("470", true, 4.70, 1.68, BoatHullType.MONOHULL, true, "470er", "470M", "470W"),
_470 ("470", true, 4.70, 1.68, BoatHullType.MONOHULL, true, "470er", "470M", "470W", "470 - M", "470 - W"),
_5O5 ("5O5", true, 5.03, 1.88, BoatHullType.MONOHULL, true, "505", "5o5", "505er", "5o5er"),
_5_5MR ("5.5mR", true, 9.50, 1.92, BoatHullType.MONOHULL, true, "5.5 Meter", "5.5 Metre", "5.5", "5.5M", "5.5-metre", "5.5 metre"),
A_CAT ("A-Catamaran", true, 5.49, 2.30, BoatHullType.CATAMARAN, false, "A-Cat", "ACat", "A-Class Catamaran"),
@@ -85,7 +85,7 @@ public enum BoatClassMasterdata {
RS500 ("RS 500", true, 4.34, 1.58, BoatHullType.MONOHULL, true, "RS500", "RS_500"),
RS800 ("RS 800", true, 4.80, 1.88, BoatHullType.MONOHULL, true, "RS800", "RS_800"),
RS_AERO ("RS Aero", true, 4.00, 1.40, BoatHullType.MONOHULL, false, "RSAERO", "RS_Aero"),
RS_X ("RS:X", true, 2.86, 0.93, BoatHullType.SURFERBOARD, false, "RS-X", "RSX", "RS:X"),
RS_X ("RS:X", true, 2.86, 0.93, BoatHullType.SURFERBOARD, false, "RS-X", "RSX", "RS:X", "RS:X Men", "RS:X Woman"),
RS_FEVA ("RS Feva", true, 3.64, 1.42, BoatHullType.MONOHULL, true, "RSFeva"),
SONAR ("Sonar", true, 7.01, 2.39, BoatHullType.MONOHULL, true),
SOLING ("Soling", true, 8.15, 1.91, BoatHullType.MONOHULL, true),
@@ -100,6 +100,7 @@ public enum BoatClassMasterdata {
TORNADO ("Tornado Catamaran", true, 6.10, 3.02, BoatHullType.CATAMARAN, true, "Tornado", "Tornado Cat"),
TRIAS ("Trias", true, 9.20, 2.12, BoatHullType.MONOHULL, true),
VIPER_640 ("Viper 640", true, 6.43, 2.49, BoatHullType.MONOHULL, true),
VO60 ("VO60", true, 19.5, 5.25, BoatHullType.MONOHULL, true, "Volvo Ocean 60", "VolvoOcean60", "W60", "Whitbread60", "Whitbread 60"),
VX_ONE ("VX ONE", true, 5.79, 2.19, BoatHullType.MONOHULL, true, "VX-ONE"),
X_99 ("X-99", true, 9.96, 2.95, BoatHullType.MONOHULL, true, "X99"),
@@ -58,6 +58,12 @@ public enum DataImportSubProgress {
return messages.importWindTracks();
}
},
IMPORT_SENSOR_FIXES {
@Override
public String getMessage(CommonStringMessages messages) {
return messages.importSensorFixes();
}
},
UPDATE_EVENT_LEADERBOARD_GROUP_LINKS {
@Override
public String getMessage(CommonStringMessages messages) {
@@ -1,3 +1,6 @@
package com.sap.sailing.domain.common;
public enum LegType { UPWIND, DOWNWIND, REACHING }
public enum LegType { UPWIND, DOWNWIND, REACHING;
public static double UPWIND_DOWNWIND_TOLERANCE_IN_DEG=45.; // TracTrac does 22.5, Marcus Baur suggest 40; Nils Schröder suggests 60
}
@@ -3,6 +3,6 @@ package com.sap.sailing.domain.common;
import com.sap.sse.datamining.annotations.Connector;
public interface Moving {
@Connector(messageKey="Speed")
@Connector(messageKey="")
SpeedWithBearing getSpeed();
}
@@ -67,7 +67,7 @@ public interface Speed extends Comparable<Speed>, Serializable {
}
};
@Statistic(messageKey="", resultDecimals=2)
@Statistic(messageKey="speedInKnots", resultDecimals=2)
double getKnots();
double getMetersPerSecond();
@@ -1,10 +1,12 @@
package com.sap.sailing.domain.common;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.annotations.Statistic;
public interface SpeedWithBearing extends Speed {
@Statistic(messageKey="bearing", resultDecimals=1)
Bearing getBearing();
/**
@@ -0,0 +1,92 @@
package com.sap.sailing.domain.common;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
/**
* Information about the time competitors of a race are expected to need for the legs of a race. This is based on a
* {@link TrackedRace} with {@link TrackedLeg}s and
* {@link TrackedRace#getWind(com.sap.sailing.domain.common.Position, com.sap.sse.common.TimePoint) wind information}.
* Furthermore, a valid {@link PolarDataService} instance must be bound to the {@link TrackedRace} to make predictions
* possible.
* <p>
*
* In order to give a rationale for the response, in addition to the total expected duration the expected durations for
* each leg are specified, together with the {@link Wind} data used for the leg, leg distance, the true wind angle for
* the leg's direction and the leg type that this leads to.
*
* @author Axel Uhl (d043530)
*
*/
public interface TargetTimeInfo {
public interface LegTargetTimeInfo {
/**
* The distance between the waypoints delimiting the leg, at the {@link #getExpectedStartTimePoint() expected
* time point} at which the competitor starts the leg.
*/
Distance getDistance();
/**
* True wind at the position in the middle between the two positions at which the waypoints delimiting
* the leg are at {@link #getExpectedStartTimePoint()}.
*/
Wind getWind();
/**
* The bearing from the leg's start waypoint to the leg's end waypoint at {@link #getExpectedStartTimePoint()}/
*/
Bearing getLegBearing();
/**
* The angle between the wind direction (from) and the bearing from the leg's start waypoint position at
* {@link #getExpectedStartTimePoint()} and the leg's end waypoint position at
* {@link #getExpectedStartTimePoint()}. For example, if a windward mark is a few meters off to the left,
* viewed from the leeward start line, then the wind comes a little more from the starboard side compared
* to the course middle line, therefore would have a true wind angle to the leg of, say 5deg.
*/
Bearing getTrueWindAngleToLeg();
/**
* The time a competitor is expected to need to sail the leg in the {@link #getWind() wind conditions expected}.
*/
Duration getExpectedDuration();
/**
* The time point when the competitor is expected to enter this leg. For the race's first leg
* this equals the {@link TargetTimeInfo#getExpectedStartTimePoint()} result.
*/
TimePoint getExpectedStartTimePoint();
/**
* The type of the leg at {@link #getExpectedStartTimePoint()}, given the {@link #getWind() wind conditions}
* and the {@link #getLegBearing() leg bearing} at that point in time.
*/
LegType getLegType();
}
/**
* The time point when a competitor whose hypothetical race is described
* by this object starts. This time is the basis for determining wind angles
* as input for the polar / VPP calculations. Wind is taken on each leg
* during the expected time at which the competitor starts that leg.
*/
TimePoint getExpectedStartTimePoint();
/**
* The expected total duration; equals the sum of the {@link LegTargetTimeInfo#getExpectedDuration() leg durations}
* as aggregated across {@link #getLegTargetTimes()}.
*/
Duration getExpectedDuration();
/**
* The per-leg information about the expected hypothetical sail around the course. The element
* order matches that of the {@link Course#getLegs() legs in the race course}.
*/
Iterable<LegTargetTimeInfo> getLegTargetTimes();
/**
* The {@link Duration#plus(Duration) sum} of {@link LegTargetTimeInfo#getExpectedDuration() expected leg durations}
* across all legs of type {@code spentInLegsOfType}.
*/
Duration getExpectedDuration(LegType spentInLegsOfType);
}
@@ -17,4 +17,29 @@ public class TimePointSpecificationFoundInLogImpl implements TimePointSpecificat
public TimePoint getTimePoint() {
return timePoint;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((timePoint == null) ? 0 : timePoint.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TimePointSpecificationFoundInLogImpl other = (TimePointSpecificationFoundInLogImpl) obj;
if (timePoint == null) {
if (other.timePoint != null)
return false;
} else if (!timePoint.equals(other.timePoint))
return false;
return true;
}
}
@@ -14,24 +14,28 @@ public class BoatClassDTO extends NamedDTO implements Serializable, Comparable<B
public static final String DEFAULT_NAME = "Default";
private Distance hullLength;
private Distance hullBeam;
private String displayName;
BoatClassDTO() {}
public BoatClassDTO(String name, String displayName, Distance hullLength) {
public BoatClassDTO(String name, String displayName, Distance hullLength, Distance hullBeam) {
super(name);
this.hullLength = hullLength;
this.hullBeam = hullBeam;
}
public BoatClassDTO(String name, Distance hullLength) {
super(name);
this.hullLength = hullLength;
this.displayName = null;
public BoatClassDTO(String name, Distance hullLength, Distance hullBeam) {
this(name, /* display name */ null, hullLength, hullBeam);
}
public Distance getHullLength() {
return hullLength;
}
public Distance getHullBeam() {
return hullBeam;
}
public String getDisplayName() {
return displayName;
@@ -12,6 +12,7 @@ public interface CommonStringMessages {
String importWait();
String importLeaderboardGroups();
String importWindTracks();
String importSensorFixes();
String updateEventLeaderboardGroupLinks();
}
@@ -0,0 +1,116 @@
package com.sap.sailing.domain.common.impl;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.TargetTimeInfo;
import com.sap.sailing.domain.common.Wind;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
public class TargetTimeInfoImpl implements TargetTimeInfo {
private final Iterable<TargetTimeInfo.LegTargetTimeInfo> legInfos;
public static class LegTargetTimeInfoImpl implements LegTargetTimeInfo {
private final Distance distance;
private final Wind wind;
private final Bearing legBearing;
private final Duration expectedDuration;
private final TimePoint expectedStartTimePoint;
private final LegType legType;
public LegTargetTimeInfoImpl(Distance distance, Wind wind, Bearing legBearing, Duration expectedDuration,
TimePoint expectedStartTimePoint, LegType legType) {
super();
this.distance = distance;
this.wind = wind;
this.legBearing = legBearing;
this.expectedDuration = expectedDuration;
this.expectedStartTimePoint = expectedStartTimePoint;
this.legType = legType;
}
@Override
public Distance getDistance() {
return distance;
}
@Override
public Wind getWind() {
return wind;
}
@Override
public Bearing getLegBearing() {
return legBearing;
}
@Override
public Bearing getTrueWindAngleToLeg() {
return getLegBearing().getDifferenceTo(getWind().getBearing().reverse());
}
@Override
public Duration getExpectedDuration() {
return expectedDuration;
}
@Override
public TimePoint getExpectedStartTimePoint() {
return expectedStartTimePoint;
}
@Override
public LegType getLegType() {
return legType;
}
@Override
public String toString() {
return "LegTargetTimeInfoImpl [distance=" + distance + ", wind=" + wind + ", legBearing=" + legBearing
+ ", expectedDuration=" + expectedDuration + ", expectedStartTimePoint=" + expectedStartTimePoint
+ ", legType=" + legType + "]";
}
}
public TargetTimeInfoImpl(Iterable<LegTargetTimeInfo> legInfos) {
super();
this.legInfos = legInfos;
}
@Override
public TimePoint getExpectedStartTimePoint() {
return Util.isEmpty(legInfos) ? null : legInfos.iterator().next().getExpectedStartTimePoint();
}
@Override
public Duration getExpectedDuration() {
Duration result = Duration.NULL;
for (final LegTargetTimeInfo legInfo : legInfos) {
result = result.plus(legInfo.getExpectedDuration());
}
return result;
}
@Override
public Iterable<LegTargetTimeInfo> getLegTargetTimes() {
return legInfos;
}
@Override
public Duration getExpectedDuration(final LegType spentInLegsOfType) {
Duration result = Duration.NULL;
for (final LegTargetTimeInfo legInfo : legInfos) {
if (legInfo.getLegType() == spentInLegsOfType) {
result = result.plus(legInfo.getExpectedDuration());
}
}
return result;
}
@Override
public String toString() {
return "TargetTimeInfoImpl [legInfos=" + legInfos + "]";
}
}
@@ -37,6 +37,7 @@ public enum Permission implements com.sap.sse.security.shared.Permission {
LEADERBOARD,
LEADERBOARD_GROUP,
TRACKED_RACE,
DATA_MINING,
;
// TODO once we can use Java8 here, move this up into a "default" method on the Permission interface
@@ -6,4 +6,4 @@ Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Fragment-Host: com.sap.sailing.domain.deckmanadapter
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.junit4
Require-Bundle: org.junit;bundle-version="4.8.2"
@@ -6,7 +6,7 @@ Bundle-SymbolicName: com.sap.sailing.domain.igtimiadapter.test
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.junit4;bundle-version="4.8.2",
Require-Bundle: org.junit;bundle-version="4.8.2",
com.sap.sailing.domain.common,
com.sap.sse.mongodb,
com.sap.sse.common
@@ -23,7 +23,7 @@ public class WebSocketServerListTest {
@Test
public void testWebSocketServerList() throws IllegalStateException, ClientProtocolException, IOException, ParseException, URISyntaxException {
final ClientImpl testAppClient = new ClientImpl("7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6",
"aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a", "http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback");
"aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a", "http", "127.0.0.1", "8888", "/igtimi/oauth/v1/authorizationcallback");
MongoDBConfiguration mongoTestConfig = MongoDBConfiguration.getDefaultTestConfiguration();
MongoDBService mongoTestService = mongoTestConfig.getService();
final IgtimiConnectionFactoryImpl igtimiConnectionFactory = new IgtimiConnectionFactoryImpl(testAppClient, PersistenceFactory.INSTANCE.getDomainObjectFactory(mongoTestService),
@@ -37,7 +37,7 @@ public class SignInTest {
IllegalAccessException, ClassCastException, ParseException {
// use the credentials of "Another Test App"
final Client testAppClient = new ClientImpl("7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6",
"aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a", "http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback");
"aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a", "http", "127.0.0.1", "8888", "/igtimi/oauth/v1/authorizationcallback");
MongoDBConfiguration mongoTestConfig = MongoDBConfiguration.getDefaultTestConfiguration();
MongoDBService mongoTestService = mongoTestConfig.getService();
final IgtimiConnectionFactoryImpl igtimiConnectionFactory = new IgtimiConnectionFactoryImpl(testAppClient, PersistenceFactory.INSTANCE.getDomainObjectFactory(mongoTestService),
@@ -55,7 +55,7 @@ public class SignInTest {
InstantiationException, IllegalAccessException, ClassCastException {
// use the credentials of "Another Test App"
final Client testAppClient = new ClientImpl("a4cecd8593e12d43a03433a6db0eea243a411749f93c278dce6a26d4804eebd2",
"4d66022d1ec3e2991f8053514495b61cc076ff02d664f0dc8f3df9150c3864ef", "http://1.2.3.4");
"4d66022d1ec3e2991f8053514495b61cc076ff02d664f0dc8f3df9150c3864ef", "http", "1.2.3.4", null, "/");
MongoDBConfiguration mongoTestConfig = MongoDBConfiguration.getDefaultTestConfiguration();
MongoDBService mongoTestService = mongoTestConfig.getService();
final IgtimiConnectionFactoryImpl igtimiConnectionFactory = new IgtimiConnectionFactoryImpl(testAppClient, PersistenceFactory.INSTANCE.getDomainObjectFactory(mongoTestService),
@@ -71,7 +71,7 @@ public class SignInTest {
InstantiationException, IllegalAccessException, ClassCastException, ParseException {
// use the credentials of "Another Test App"
final Client testAppClient = new ClientImpl("a4cecd8593e12d43a03433a6db0eea243a411749f93c278dce6a26d4804eebd2",
"4d66022d1ec3e2991f8053514495b61cc076ff02d664f0dc8f3df9150c3864ef", "http://1.2.3.4");
"4d66022d1ec3e2991f8053514495b61cc076ff02d664f0dc8f3df9150c3864ef", "http", "1.2.3.4", null, "/");
MongoDBConfiguration mongoTestConfig = MongoDBConfiguration.getDefaultTestConfiguration();
MongoDBService mongoTestService = mongoTestConfig.getService();
final IgtimiConnectionFactory igtimiConnectionFactory = new IgtimiConnectionFactoryImpl(testAppClient, PersistenceFactory.INSTANCE.getDomainObjectFactory(mongoTestService),
@@ -155,7 +155,7 @@ public class WebSocketTest {
public void testWebSocketConnect() throws Exception {
final List<Fix> allFixesReceived = new ArrayList<>();
final Client client = new ClientImpl("7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6",
"aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a", "http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback");
"aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a", "http", "127.0.0.1", "8888", "/igtimi/oauth/v1/authorizationcallback");
MongoDBConfiguration mongoTestConfig = MongoDBConfiguration.getDefaultTestConfiguration();
MongoDBService mongoTestService = mongoTestConfig.getService();
final IgtimiConnectionFactory igtimiConnectionFactory = new IgtimiConnectionFactoryImpl(client, PersistenceFactory.INSTANCE.getDomainObjectFactory(mongoTestService),
@@ -8,8 +8,8 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.json.simple;bundle-version="1.1.0",
com.sun.jersey;bundle-version="1.17.0",
org.objectweb.asm;bundle-version="3.3.1",
org.apache.httpcomponents.httpclient;bundle-version="4.2.5",
org.apache.httpcomponents.httpcore;bundle-version="4.0.0",
org.apache.httpcomponents.httpclient;bundle-version="[4.2.5,4.3.0)",
org.apache.httpcomponents.httpcore;bundle-version="[4.0.0,4.3.0)",
com.sap.sailing.domain.common,
com.sap.sailing.domain.igtimiadapter.persistence,
com.sap.sailing.domain.shared.android,
@@ -18,5 +18,7 @@ public interface Client {
String getSecret();
String getRedirectUri();
String getDefaultRedirectUri();
String getRedirectUri(String redirectProtocol, String redirectHost, String redirectPort);
}
@@ -32,8 +32,11 @@ public interface IgtimiConnectionFactory {
* Obtains a URL that a user agent (e.g., a web browser) can be sent to in order to allow that user to authenticate
* and then authorize this factory's {@link Client} for accessing the user's Igtimi data. The URL is chosen such that
* it redirects to the {@link AuthorizationCallback} with the <code>code</code> response type.
* @param redirectProtocol TODO
* @param redirectHost TODO
* @param redirectPort TODO
*/
String getAuthorizationUrl();
String getAuthorizationUrl(String redirectProtocol, String redirectHost, String redirectPort);
/**
* Using the "account" service, retrieves the {@link Account} information for this access token and stores the token
@@ -38,10 +38,9 @@ public class Activator implements BundleActivator {
private static final String DEFAULT_CLIENT_ID = "d29eae61621af3057db0e638232a027e96b1d2291b1b89a1481dfcac075b0bf4";
private static final String DEFAULT_CLIENT_SECRET = "537dbd14a84fcb470c91d85e8c4f8f7a356ac5ffc8727594d1bfe900ee5942ef";
private static final String DEFAULT_CLIENT_REDIRECT_URI = "http://sapsailing.com/igtimi/oauth/v1/authorizationcallback";
private static final String CLIENT_REDIRECT_PATH = "/igtimi/oauth/v1/authorizationcallback";
private static final String CLIENT_ID_PROPERTY_NAME = "igtimi.client.id";
private static final String CLIENT_SECRET_PROPERTY_NAME = "igtimi.client.secret";
private static final String CLIENT_REDIRECT_URI_PROPERTY_NAME = "igtimi.client.redirecturi";
private final Future<IgtimiConnectionFactoryImpl> connectionFactory;
private final Future<IgtimiWindTrackerFactory> windTrackerFactory;
private final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactoryWithPriority(Thread.NORM_PRIORITY, /* daemon */ true));
@@ -50,8 +49,7 @@ public class Activator implements BundleActivator {
logger.info(getClass().getName()+" constructor");
final String clientId = System.getProperty(CLIENT_ID_PROPERTY_NAME, DEFAULT_CLIENT_ID);
final String clientSecret = System.getProperty(CLIENT_SECRET_PROPERTY_NAME, DEFAULT_CLIENT_SECRET);
final String clientRedirectUri = System.getProperty(CLIENT_REDIRECT_URI_PROPERTY_NAME, DEFAULT_CLIENT_REDIRECT_URI);
final Client client = new ClientImpl(clientId, clientSecret, clientRedirectUri);
final Client client = new ClientImpl(clientId, clientSecret, "https", "www.sapsailing.com", /* port==null means default */ null, CLIENT_REDIRECT_PATH);
final DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory();
final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory();
connectionFactory = executor.submit(new Callable<IgtimiConnectionFactoryImpl>() {
@@ -5,13 +5,19 @@ import com.sap.sailing.domain.igtimiadapter.Client;
public class ClientImpl implements Client {
private final String id;
private final String secret;
private final String redirectUri;
private final String defaultRedirectProtocol;
private final String defaultRedirectHostname;
private final String defaultRedirectPort;
private final String redirectUriPath;
public ClientImpl(String id, String secret, String redirectUri) {
public ClientImpl(String id, String secret, String defaultRedirectProtocol, String defaultRedirectHostname, String defaultRedirectPort, String redirectUriPath) {
super();
this.id = id;
this.secret = secret;
this.redirectUri = redirectUri;
this.defaultRedirectProtocol = defaultRedirectProtocol;
this.defaultRedirectHostname = defaultRedirectHostname;
this.defaultRedirectPort = defaultRedirectPort;
this.redirectUriPath = redirectUriPath;
}
@Override
@@ -25,7 +31,13 @@ public class ClientImpl implements Client {
}
@Override
public String getRedirectUri() {
return redirectUri;
public String getDefaultRedirectUri() {
return getRedirectUri(defaultRedirectProtocol, defaultRedirectHostname, defaultRedirectPort);
}
@Override
public String getRedirectUri(String redirectProtocol, String redirectHost, String redirectPort) {
return redirectProtocol+"://"+redirectHost+(redirectPort==null||redirectPort.isEmpty()?"":(":"+redirectPort))+
(redirectUriPath.startsWith("/")?redirectUriPath:"/"+redirectUriPath);
}
}
@@ -112,7 +112,7 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
}
private String getOauthAuthorizeUrl() throws UnsupportedEncodingException {
return getBaseUrl()+"/oauth/authorize?response_type=code&client_id="+getClient().getId()+"&redirect_uri="+URLEncoder.encode(getClient().getRedirectUri(), "UTF-8");
return getBaseUrl()+"/oauth/authorize?response_type=code&client_id="+getClient().getId()+"&redirect_uri="+URLEncoder.encode(getClient().getDefaultRedirectUri(), "UTF-8");
}
/**
@@ -320,8 +320,9 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
}
@Override
public String getAuthorizationUrl() {
return getBaseUrl()+"/oauth/authorize?response_type=code&client_id="+getClient().getId()+"&redirect_uri="+client.getRedirectUri();
public String getAuthorizationUrl(String redirectProtocol, String redirectHost, String redirectPort) {
return getBaseUrl()+"/oauth/authorize?response_type=code&client_id="+getClient().getId()+
"&redirect_uri="+client.getRedirectUri(redirectProtocol, redirectHost, redirectPort);
}
private Client getClient() {
@@ -344,7 +345,7 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
urlParameters.add(new BasicNameValuePair("client_id", getClient().getId()));
urlParameters.add(new BasicNameValuePair("client_secret", getClient().getSecret()));
urlParameters.add(new BasicNameValuePair("code", code));
urlParameters.add(new BasicNameValuePair("redirect_uri", getClient().getRedirectUri()));
urlParameters.add(new BasicNameValuePair("redirect_uri", getClient().getDefaultRedirectUri()));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
HttpResponse response = client.execute(post);
JSONObject accessTokenJson = ConnectivityUtils.getJsonFromResponse(response);
@@ -170,9 +170,7 @@ public class WebSocketConnectionManager implements LiveDataConnection {
@Override
public void onWebSocketText(String message) {
if (logger.isLoggable(Level.FINEST)) {
logger.finest("Received "+message+" in "+this);
}
logger.finest(()->"Received "+message+" in "+this);
if (message.equals("1")) {
logger.fine("Received server heartbeat for "+this);
receivedServerHeartbeatInInterval = true;
@@ -193,9 +191,7 @@ public class WebSocketConnectionManager implements LiveDataConnection {
}
}
}
if (logger.isLoggable(Level.FINEST)) {
logger.finest("Received fixes"+fixes+" for "+this);
}
logger.finest(()->"Received fixes"+fixes+" for "+this);
notifyListeners(fixes);
} catch (ParseException e) {
logger.log(Level.SEVERE, "Error trying to parse a web socket data package coming from Igtimi "+this, e);
@@ -1,10 +1,13 @@
package com.sap.sailing.domain.persistence;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Consumer;
import com.mongodb.DBObject;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
@@ -28,8 +31,14 @@ import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver;
import com.sap.sailing.domain.leaderboard.LeaderboardRegistry;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.tracking.RaceHandle;
import com.sap.sailing.domain.tracking.RaceTracker;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.Util.Pair;
/**
@@ -135,4 +144,33 @@ public interface DomainObjectFactory {
Iterable<Entry<DeviceConfigurationMatcher, DeviceConfiguration>> loadAllDeviceConfigurations();
Map<String, Set<URL>> loadResultUrls();
/**
* Loads all {@link RaceTrackingConnectivityParameters} objects from the database telling how to re-load those races
* that were {@link MongoObjectFactory#addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)
* marked as to be restored} before the server got re-started. Callers that would like to use the result to
* re-connect to those races should take care not to flood servers with requests. Instead, ideally, callers would
* monitor the loading {@link TrackedRace#getStatus() status} or the resulting {@link TrackedRace}s (see
* {@link RaceTracker#getRaceHandle()}, {@link RaceHandle#getRace(long)}, {@link RaceHandle#getTrackedRegatta()} and
* {@link TrackedRegatta#getTrackedRace(RaceDefinition)}.
*
* @param callback
* invoked for each connectivity params object successfully resolved; this pattern is preferred over a
* non-{@code void} return type because resolving the connectivity parameters objects itself happens
* through a callback pattern that may be triggered asynchronously by the services for handling the
* respective parameter types becoming available only later. For example, during the OSGi startup phase,
* when the {@code RacingEventService} is launched, not all persistence bundles will have run their
* activators; some may even depend on the {@code RacingEventService} and therefore won't start their
* activators before the activator of {@code RacingEventService} has completed. This would either result
* in a {@link NoCorrespondingServiceRegisteredException} or would have to be handled by not treating
* those connectivity parameter objects which defeats the whole purpose of this method.
* @return the number of connectivity parameter objects found in the database; callers may use this to understand
* the progress with the {@code callback} invocations of which eventually there should be this many, at
* least if all handlers have ultimately become available.
*
* @see MongoObjectFactory#addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)
* @see MongoObjectFactory#removeConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)
*/
int loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameters> callback)
throws MalformedURLException, URISyntaxException;
}
@@ -19,6 +19,7 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
@@ -149,4 +150,31 @@ public interface MongoObjectFactory {
void removeResultUrl(String resultProviderName, URL url);
/**
* Updates the database such that the next call to
* {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameter>)} won't return an object equivalent to
* {@code params} anymore; in other words, the race whose connectivity parameters are described by {@code params}
* will no longer be considered as to be restored.
*
* @see #addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)
*/
void removeConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters params);
/**
* Updates the database such that the next call to
* {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameter>)} will return an object equivalent to
* {@code params}; in other words, the race whose connectivity parameters are described by {@code params} will be
* considered as to be restored.
*
* @see #removeConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)
*/
void addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters params);
/**
* Removes all {@link RaceTrackingConnectivityParameters} objects from those to restore; short for calling
* {@link #removeConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters)} for all parameter
* objects obtained through {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameter>)}.
*/
void removeAllConnectivityParametersForRacesToRestore();
}
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.persistence.impl;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
/**
* Defines literals providing the names for MongoDB collections. The literal documentation described the semantics
@@ -100,4 +101,10 @@ public enum CollectionNames {
* URLs providing race results
*/
RESULT_URLS,
/**
* DB representations of {@link RaceTrackingConnectivityParameters} objects, serialized in a type-specific
* way by corresponding implementations of the RaceTrackingConnectivityParametersMongoHandler} interface.
*/
CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED,
}
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.persistence.impl;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
@@ -14,6 +15,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -199,6 +201,8 @@ import com.sap.sailing.domain.ranking.RankingMetricConstructor;
import com.sap.sailing.domain.ranking.RankingMetricsFactory;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
@@ -235,8 +239,9 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
private final DB database;
private final DomainFactory baseDomainFactory;
private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder;
private final TypeBasedServiceFinderFactory serviceFinderFactory;
private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder;
private final TypeBasedServiceFinder<RaceTrackingConnectivityParametersHandler> raceTrackingConnectivityParamsServiceFinder;
/**
* Uses <code>null</code> as the {@link TypeBasedServiceFinder}, meaning that no {@link DeviceIdentifier}s can be loaded
@@ -252,8 +257,10 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
if (serviceFinderFactory != null) {
this.deviceIdentifierServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class);
this.deviceIdentifierServiceFinder.setFallbackService(new PlaceHolderDeviceIdentifierMongoHandler());
this.raceTrackingConnectivityParamsServiceFinder = serviceFinderFactory.createServiceFinder(RaceTrackingConnectivityParametersHandler.class);
} else {
this.deviceIdentifierServiceFinder = null;
this.raceTrackingConnectivityParamsServiceFinder = null;
}
this.baseDomainFactory = baseDomainFactory;
this.competitorDeserializer = CompetitorJsonDeserializer.create(baseDomainFactory);
@@ -2276,4 +2283,29 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
return modified;
}
@Override
public int loadConnectivityParametersForRacesToRestore(Consumer<RaceTrackingConnectivityParameters> callback) throws MalformedURLException, URISyntaxException {
final DBCollection collection = database.getCollection(CollectionNames.CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED.name());
int count = 0;
for (final DBObject o : collection.find()) {
count++;
final String type = (String) o.get(TypeBasedServiceFinder.TYPE);
raceTrackingConnectivityParamsServiceFinder.applyServiceWhenAvailable(type, connectivityParamsPersistenceService -> {
final Map<String, Object> map = new HashMap<>();
for (final String key : o.keySet()) {
if (!key.equals(TypeBasedServiceFinder.TYPE)) {
map.put(key, o.get(key));
}
}
try {
callback.accept(connectivityParamsPersistenceService.mapTo(map));
} catch (Exception e) {
logger.log(Level.SEVERE, "Exception trying to load race restore connectivity parameters "
+ o + " with handler " + connectivityParamsPersistenceService, e);
}
});
}
return count;
}
}
@@ -105,6 +105,8 @@ import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDevic
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.WindTrack;
@@ -129,6 +131,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
private final DB database;
private final CompetitorJsonSerializer competitorSerializer = CompetitorJsonSerializer.create();
private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder;
private final TypeBasedServiceFinder<RaceTrackingConnectivityParametersHandler> raceTrackingConnectivityParamsServiceFinder;
/**
* Uses <code>null</code> for the device type service finder and hence will be unable to store device identifiers.
@@ -144,8 +147,10 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
if (serviceFinderFactory != null) {
this.deviceIdentifierServiceFinder = serviceFinderFactory.createServiceFinder(DeviceIdentifierMongoHandler.class);
this.deviceIdentifierServiceFinder.setFallbackService(new PlaceHolderDeviceIdentifierMongoHandler());
this.raceTrackingConnectivityParamsServiceFinder = serviceFinderFactory.createServiceFinder(RaceTrackingConnectivityParametersHandler.class);
} else {
this.deviceIdentifierServiceFinder = null;
this.raceTrackingConnectivityParamsServiceFinder = null;
}
}
@@ -1516,4 +1521,50 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
result.put(FieldNames.SAILORS_INFO_LOCALE.name(), locale != null ? locale.toLanguageTag() : null);
return result;
}
@Override
public void removeConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters params) {
if (raceTrackingConnectivityParamsServiceFinder != null) {
final String typeIdentifier = params.getTypeIdentifier();
final RaceTrackingConnectivityParametersHandler paramsPersistenceService = raceTrackingConnectivityParamsServiceFinder.findService(typeIdentifier);
if (paramsPersistenceService != null) {
final DBCollection collection = database.getCollection(CollectionNames.CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED.name());
DBObject key = new BasicDBObject();
key.putAll(paramsPersistenceService.getKey(params));
collection.remove(key, WriteConcern.SAFE);
} else {
logger.warning("Couldn't find a persistence service for connectivity parameters of type "+typeIdentifier);
}
} else {
logger.warning("No connectivity parameters service finder set; unable to remove connectivity parameters from persistent store for "
+ params + " of type " + params.getTypeIdentifier());
}
}
@Override
public void addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters params) {
final String typeIdentifier = params.getTypeIdentifier();
if (raceTrackingConnectivityParamsServiceFinder == null) {
logger.warning("No service finder has been configured to find connectivity parameter persistence services. Can't add connectivity parameters to DB for restore.");
} else {
try {
final RaceTrackingConnectivityParametersHandler paramsPersistenceService = raceTrackingConnectivityParamsServiceFinder.findService(typeIdentifier);
final DBCollection collection = database.getCollection(CollectionNames.CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED.name());
DBObject key = new BasicDBObject();
key.putAll(paramsPersistenceService.getKey(params));
DBObject dbObject = new BasicDBObject();
dbObject.putAll(paramsPersistenceService.mapFrom(params));
collection.update(key, dbObject, /* upsert */ true, /* multi */ false, WriteConcern.SAFE);
} catch (NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Couldn't find a persistence service for connectivity parameters of type "+typeIdentifier+
". Couldn't store race "+params.getTrackerID()+" for restoring.", e);
}
}
}
@Override
public void removeAllConnectivityParametersForRacesToRestore() {
database.getCollection(CollectionNames.CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED.name()).drop();
}
}
@@ -6,7 +6,7 @@ Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Fragment-Host: com.sap.sailing.domain.racelogtrackingadapter
Require-Bundle: org.junit4;bundle-version="4.8.2",
Require-Bundle: org.junit;bundle-version="4.8.2",
com.sap.sailing.domain.racelogtrackingadapter.testsupport,
org.mockito.mockito-core;bundle-version="1.9.5",
org.objenesis;bundle-version="1.3.0",
@@ -78,7 +78,7 @@ public class CreateAndTrackWithRaceLogTest {
@Before
public void setup() {
service = new RacingEventServiceImpl(true, new MockSmartphoneImeiServiceFinderFactory());
service = new RacingEventServiceImpl(/* clearPersistentCompetitorStore */ true, new MockSmartphoneImeiServiceFinderFactory(), /* restoreTrackedRaces */ false);
sensorFixStore = service.getSensorFixStore();
service.getMongoObjectFactory().getDatabase().dropDatabase();
author = service.getServerAuthor();
@@ -113,7 +113,7 @@ public class CreateAndTrackWithRaceLogTest {
Exception {
RaceColumn column = leaderboard.getRaceColumnByName(columnName);
exception.expect(NotDenotedForRaceLogTrackingException.class);
adapter.startTracking(service, leaderboard, column, fleet);
adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
}
private void testSize(Track<?> track, int expected) {
@@ -184,7 +184,7 @@ public class CreateAndTrackWithRaceLogTest {
raceLog.add(new RaceLogRegisterCompetitorEventImpl(t(), author, 0, comp1));
raceLog.add(new RaceLogStartOfTrackingEventImpl(t(0), author, /* passId */ 0));
// start tracking
adapter.startTracking(service, leaderboard, column, fleet);
adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
// now there is a tracked race
@@ -226,7 +226,7 @@ public class CreateAndTrackWithRaceLogTest {
raceLog.add(new RaceLogStartOfTrackingEventImpl(t(0), author, /* passId */ 0));
// start tracking
adapter.startTracking(service, leaderboard, column, fleet);
adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
// now there is a trackedrace
TrackedRace race = column.getTrackedRace(fleet);
@@ -15,7 +15,7 @@ Require-Bundle: com.sap.sailing.domain.shared.android,
org.json.simple;bundle-version="1.1.0",
org.mockito.mockito-core;bundle-version="1.9.5",
org.hamcrest;bundle-version="1.1.0",
org.junit4;bundle-version="4.8.2",
org.junit;bundle-version="4.8.2",
com.sap.sse.common,
com.sap.sailing.server.gateway.serialization.shared.android
Export-Package: com.sap.sailing.domain.racelog.tracking.test.mock
@@ -0,0 +1,11 @@
package com.sap.sailing.domain.racelog.tracking.test.mock;
import com.sap.sse.common.TypeBasedServiceFinder;
public abstract class AbstractTypeBasedServiceFinder<ServiceT> implements TypeBasedServiceFinder<ServiceT> {
@Override
public void applyServiceWhenAvailable(String type, com.sap.sse.common.TypeBasedServiceFinder.Callback<ServiceT> callback) {
final ServiceT service = findService(type);
callback.withService(service);
}
}
@@ -4,9 +4,8 @@ import java.util.Collections;
import java.util.Set;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TypeBasedServiceFinder;
public class MockEmptyServiceFinder<ServiceType> implements TypeBasedServiceFinder<ServiceType> {
public class MockEmptyServiceFinder<ServiceType> extends AbstractTypeBasedServiceFinder<ServiceType> {
private ServiceType fallback;
@Override
@@ -15,9 +15,8 @@ import com.sap.sailing.domain.persistence.racelog.tracking.FixMongoHandler;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.DoubleVectorFixMongoHandlerImpl;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMongoHandlerImpl;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMovingMongoHandlerImpl;
import com.sap.sse.common.TypeBasedServiceFinder;
public class MockGPSFixMongoServiceFinder implements TypeBasedServiceFinder<FixMongoHandler<?>> {
public class MockGPSFixMongoServiceFinder extends AbstractTypeBasedServiceFinder<FixMongoHandler<?>> {
private final MongoObjectFactoryImpl mof = new MongoObjectFactoryImpl(null);
private final DomainObjectFactoryImpl dof = new DomainObjectFactoryImpl(null, null);
private final FixMongoHandler<?> movingHandler = new GPSFixMovingMongoHandlerImpl(mof, dof);
@@ -3,9 +3,7 @@ package com.sap.sailing.domain.racelog.tracking.test.mock;
import java.util.Collections;
import java.util.Set;
import com.sap.sse.common.TypeBasedServiceFinder;
public class MockServiceFinder<T> implements TypeBasedServiceFinder<T> {
public class MockServiceFinder<T> extends AbstractTypeBasedServiceFinder<T> {
private final T handler;
private T fallback;
@@ -32,5 +32,5 @@ Import-Package: com.google.zxing;version="3.1.0",
org.osgi.framework;version="1.6.0",
org.osgi.util.tracker;version="1.5.1"
Export-Package: com.sap.sailing.domain.racelogtracking,
com.sap.sailing.domain.racelogtracking.impl;x-friends:="com.sap.sailing.domain.racelogtrackingadapter.testsupport,com.sap.sailing.gwt.ui.test"
com.sap.sailing.domain.racelogtracking.impl;x-friends:="com.sap.sailing.domain.racelogtrackingadapter.testsupport,com.sap.sailing.gwt.ui.test,com.sap.sailing.mongodb.test"
Bundle-Activator: com.sap.sailing.domain.racelogtracking.impl.Activator
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<file datatype="javapropertyresourcebundle" date="2016-12-21T15:30:12Z" original="/usr/sap/ljs/app/Converter_7335190261158680380/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en" target-language="ja">
<file datatype="javapropertyresourcebundle" date="2017-01-12T14:31:21Z" original="/usr/sap/ljs/app/Converter_7335190261158680380/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en" target-language="ja">
<header>
<skl>
<internal-file crc="064477f4b22ea4cc8cbdaab36795b9a4" form="base64">H4sIAAAAAAAAAF1RQU7DQAy85xW+cakQ50o5FCSkSEBLk8J5m7iN1c16tXZbIsTf2U1SWnHzzjjjmYkGUx/I7Qt3IjVK7J455NWEwhWGHYdMauPe10/c4DJ8kJBugq14jXsSxbCQ/NUcEOQYEHo+QmtOCNoifD/8wMJ7ICdqrMXmHqoWHSS9YWHH1vI5XRzlgQPUlurDwFpyBzhKoqNsAOlMUN+yi+oMYToPRrIz2po7rDj/HKe4kNGy3AgGyUuN30F8JjOZcU1gam6pxQiNtI2aLmY/oe2HsFVL8hKt5MVuiGdizICmSb40ctAZssBjogZPVCOcSdvhneIbm9b7aw0zEOq87aesW4wlpEiS3Myz7ZH7Cl2DIU8j6DBnxvtSOWAxylT4pRdLDbs7vfaejvaoM/AWjeDl8DxJFCz5pHCtxPupgj/qtpJkYhXTxl/t/ZvpMC8XKyhj6lTBY7I40plErHAl7Vv9vwoTnv0Cs+RzW3sCAAA=</internal-file>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<file datatype="javapropertyresourcebundle" date="2016-12-21T15:30:11Z" original="/usr/sap/ljs/app/Converter_7335190261158680380/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en" target-language="ru">
<file datatype="javapropertyresourcebundle" date="2017-01-12T14:33:19Z" original="/usr/sap/ljs/app/Converter_7335190261158680380/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en" target-language="ru">
<header>
<skl>
<internal-file crc="064477f4b22ea4cc8cbdaab36795b9a4" form="base64">H4sIAAAAAAAAAF1RQU7DQAy85xW+cakQ50o5FCSkSEBLk8J5m7iN1c16tXZbIsTf2U1SWnHzzjjjmYkGUx/I7Qt3IjVK7J455NWEwhWGHYdMauPe10/c4DJ8kJBugq14jXsSxbCQ/NUcEOQYEHo+QmtOCNoifD/8wMJ7ICdqrMXmHqoWHSS9YWHH1vI5XRzlgQPUlurDwFpyBzhKoqNsAOlMUN+yi+oMYToPRrIz2po7rDj/HKe4kNGy3AgGyUuN30F8JjOZcU1gam6pxQiNtI2aLmY/oe2HsFVL8hKt5MVuiGdizICmSb40ctAZssBjogZPVCOcSdvhneIbm9b7aw0zEOq87aesW4wlpEiS3Myz7ZH7Cl2DIU8j6DBnxvtSOWAxylT4pRdLDbs7vfaejvaoM/AWjeDl8DxJFCz5pHCtxPupgj/qtpJkYhXTxl/t/ZvpMC8XKyhj6lTBY7I40plErHAl7Vv9vwoTnv0Cs+RzW3sCAAA=</internal-file>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<file datatype="javapropertyresourcebundle" date="2016-12-21T15:30:12Z" original="/usr/sap/ljs/app/Converter_7335190261158680380/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en" target-language="zh-CN">
<file datatype="javapropertyresourcebundle" date="2017-01-12T14:35:06Z" original="/usr/sap/ljs/app/Converter_7335190261158680380/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en" target-language="zh-CN">
<header>
<skl>
<internal-file crc="064477f4b22ea4cc8cbdaab36795b9a4" form="base64">H4sIAAAAAAAAAF1RQU7DQAy85xW+cakQ50o5FCSkSEBLk8J5m7iN1c16tXZbIsTf2U1SWnHzzjjjmYkGUx/I7Qt3IjVK7J455NWEwhWGHYdMauPe10/c4DJ8kJBugq14jXsSxbCQ/NUcEOQYEHo+QmtOCNoifD/8wMJ7ICdqrMXmHqoWHSS9YWHH1vI5XRzlgQPUlurDwFpyBzhKoqNsAOlMUN+yi+oMYToPRrIz2po7rDj/HKe4kNGy3AgGyUuN30F8JjOZcU1gam6pxQiNtI2aLmY/oe2HsFVL8hKt5MVuiGdizICmSb40ctAZssBjogZPVCOcSdvhneIbm9b7aw0zEOq87aesW4wlpEiS3Myz7ZH7Cl2DIU8j6DBnxvtSOWAxylT4pRdLDbs7vfaejvaoM/AWjeDl8DxJFCz5pHCtxPupgj/qtpJkYhXTxl/t/ZvpMC8XKyhj6lTBY7I40plErHAl7Vv9vwoTnv0Cs+RzW3sCAAA=</internal-file>
@@ -39,8 +39,10 @@ public interface RaceLogTrackingAdapter {
* <li>Is a {@link RaceLogRaceTracker} already listening for this racelog? If not, add one.</li>
* <li>Is a {@link RaceLogStartTrackingEvent} present in the racelog? If not, add one</li>
* </ul>
* @param trackWind TODO
* @param correctWindDirectionByMagneticDeclination TODO
*/
RaceHandle startTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet)
RaceHandle startTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, boolean trackWind, boolean correctWindDirectionByMagneticDeclination)
throws NotDenotedForRaceLogTrackingException, Exception;
RaceLogTrackingState getRaceLogTrackingState(RacingEventService service, RaceColumn raceColumn, Fleet fleet);
@@ -22,6 +22,7 @@ import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory;
import com.sap.sailing.domain.racelogtracking.SmartphoneUUIDIdentifier;
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RegattaLogFixTrackerRegattaListener;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler;
import com.sap.sailing.domain.tracking.TrackedRegattaListener;
import com.sap.sailing.server.MasterDataImportClassLoaderService;
import com.sap.sailing.server.RacingEventService;
@@ -97,7 +98,14 @@ public class Activator implements BundleActivator {
regattaLogSensorDataTrackerTrackedRegattaListener, null));
registrations.add(context.registerService(Replicable.class,
regattaLogSensorDataTrackerTrackedRegattaListener, null));
new Thread(()->{
try {
registrations.add(context.registerService(RaceTrackingConnectivityParametersHandler.class,
new RaceLogConnectivityParamsHandler(racingEventServiceTracker.waitForService(0)), getDict(RaceLogConnectivityParams.TYPE)));
} catch (Exception e) {
logger.log(Level.SEVERE, "Exception trying to register race log tracking connectivity params persistence handler", e);
}
}, "RaceLog tracking activator registering connectivity params persistence handler").start();
logger.log(Level.INFO, "Started "+context.getBundle().getSymbolicName());
}
@@ -22,12 +22,17 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.regattalike.HasRegattaLike;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.RaceTracker;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.impl.AbstractRaceTrackingConnectivityParameters;
import com.sap.sailing.server.RacingEventService;
public class RaceLogConnectivityParams implements RaceTrackingConnectivityParameters {
public class RaceLogConnectivityParams extends AbstractRaceTrackingConnectivityParameters {
/**
* A type identifier that needs to be unique for the
*/
public static final String TYPE = "RACE_LOG_TRACKING";
private final RacingEventService service;
private final RaceColumn raceColumn;
private final Fleet fleet;
@@ -37,7 +42,9 @@ public class RaceLogConnectivityParams implements RaceTrackingConnectivityParame
private final DomainFactory domainFactory;
public RaceLogConnectivityParams(RacingEventService service, Regatta regatta, RaceColumn raceColumn, Fleet fleet,
Leaderboard leaderboard, long delayToLiveInMillis, DomainFactory domainFactory) throws RaceNotCreatedException {
Leaderboard leaderboard, long delayToLiveInMillis, DomainFactory domainFactory, boolean trackWind,
boolean correctWindDirectionByMagneticDeclination) throws RaceNotCreatedException {
super(trackWind, correctWindDirectionByMagneticDeclination);
this.service = service;
this.regatta = regatta;
this.raceColumn = raceColumn;
@@ -45,12 +52,16 @@ public class RaceLogConnectivityParams implements RaceTrackingConnectivityParame
this.leaderboard = leaderboard;
this.delayToLiveInMillis = delayToLiveInMillis;
this.domainFactory = domainFactory;
if (!new RaceLogTrackingStateAnalyzer(getRaceLog()).analyze().isForTracking()) {
throw new RaceNotCreatedException(String.format("Racelog (%s) is not denoted for tracking", getRaceLog()));
}
}
@Override
public String getTypeIdentifier() {
return TYPE;
}
@Override
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
RaceLogResolver raceLogResolver) {
@@ -70,7 +81,7 @@ public class RaceLogConnectivityParams implements RaceTrackingConnectivityParame
throw new RaceNotCreatedException("No regatta for race-log tracked race");
}
DynamicTrackedRegatta trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta);
return new RaceLogRaceTracker(trackedRegatta, this, windStore, raceLogResolver);
return new RaceLogRaceTracker(trackedRegatta, this, windStore, raceLogResolver, this);
}
@Override
@@ -0,0 +1,71 @@
package com.sap.sailing.domain.racelogtracking.impl;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.impl.AbstractRaceTrackingConnectivityParametersHandler;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.common.TypeBasedServiceFinder;
/**
* Handles mapping TracTrac connectivity parameters from and to a map with {@link String} keys. The
* "param URL" is considered the {@link #getKey(RaceTrackingConnectivityParameters) key} for these objects.<p>
*
* Lives in the same package as {@link RaceTrackingConnectivityParameters} for package-private access to
* its members.
*
* @author Axel Uhl (d043530)
*
*/
public class RaceLogConnectivityParamsHandler extends AbstractRaceTrackingConnectivityParametersHandler {
private static final String FLEET_NAME = "fleetName";
private static final String RACE_COLUMN_NAME = "raceColumnName";
private static final String LEADERBOARD_NAME = "leaderboardName";
private static final String DELAY_TO_LIVE_IN_MILLIS = "delayToLiveInMillis";
private final DomainFactory domainFactory;
private final RacingEventService racingEventService;
public RaceLogConnectivityParamsHandler(RacingEventService racingEventService) {
super();
this.racingEventService = racingEventService;
this.domainFactory = racingEventService.getBaseDomainFactory();
}
@Override
public Map<String, Object> mapFrom(RaceTrackingConnectivityParameters params) {
assert params instanceof RaceLogConnectivityParams;
final RaceLogConnectivityParams rlParams = (RaceLogConnectivityParams) params;
final Map<String, Object> result = getKey(params);
result.put(DELAY_TO_LIVE_IN_MILLIS, rlParams.getDelayToLiveInMillis());
addWindTrackingParameters(rlParams, result);
return result;
}
@Override
public RaceTrackingConnectivityParameters mapTo(Map<String, Object> map) throws MalformedURLException, URISyntaxException {
final RegattaLeaderboard leaderboard = (RegattaLeaderboard) racingEventService.getLeaderboardByName((String) map.get(LEADERBOARD_NAME));
final RaceColumn raceColumn = leaderboard.getRaceColumnByName((String) map.get(RACE_COLUMN_NAME));
return new RaceLogConnectivityParams(racingEventService, leaderboard.getRegatta(), raceColumn,
raceColumn.getFleetByName((String) map.get(FLEET_NAME)), leaderboard,
((Number) map.get(DELAY_TO_LIVE_IN_MILLIS)).longValue(), domainFactory, isTrackWind(map),
isCorrectWindDirectionByMagneticDeclination(map));
}
@Override
public Map<String, Object> getKey(RaceTrackingConnectivityParameters params) {
assert params instanceof RaceLogConnectivityParams;
final RaceLogConnectivityParams rlParams = (RaceLogConnectivityParams) params;
final Map<String, Object> result = new HashMap<>();
result.put(TypeBasedServiceFinder.TYPE, params.getTypeIdentifier());
result.put(LEADERBOARD_NAME, rlParams.getLeaderboard().getName());
result.put(RACE_COLUMN_NAME, rlParams.getRaceColumn().getName());
result.put(FLEET_NAME, rlParams.getFleet().getName());
return result;
}
}
@@ -7,7 +7,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -98,7 +97,8 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl {
private EndOfTrackingController endOfTrackingController;
public RaceLogRaceTracker(DynamicTrackedRegatta regatta, RaceLogConnectivityParams params, WindStore windStore,
RaceLogResolver raceLogResolver) {
RaceLogResolver raceLogResolver, RaceLogConnectivityParams connectivityParams) {
super(connectivityParams);
this.params = params;
this.windStore = windStore;
this.trackedRegatta = regatta;
@@ -194,17 +194,17 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl {
}
@Override
public Set<RaceDefinition> getRaces() {
return trackedRace == null ? null : Collections.singleton(trackedRace.getRace());
public RaceDefinition getRace() {
return trackedRace == null ? null : trackedRace.getRace();
}
@Override
public Set<RegattaAndRaceIdentifier> getRaceIdentifiers() {
return trackedRace == null ? null : Collections.singleton(trackedRace.getRaceIdentifier());
public RegattaAndRaceIdentifier getRaceIdentifier() {
return trackedRace == null ? null : trackedRace.getRaceIdentifier();
}
@Override
public RaceHandle getRacesHandle() {
public RaceHandle getRaceHandle() {
return new RaceLogRacesHandle(this);
}
@@ -312,6 +312,7 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl {
trackedRace.addStartTimeChangedListener(startOfTrackingController);
endOfTrackingController = new EndOfTrackingController(trackedRace, raceLog, raceLogEventAuthor);
trackedRace.addListener(endOfTrackingController);
notifyRaceCreationListeners();
logger.info(String.format("Started tracking race-log race (%s)", raceLog));
// this wakes up all waiting race handles
synchronized (this) {
@@ -1,7 +1,5 @@
package com.sap.sailing.domain.racelogtracking.impl;
import java.util.Set;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
@@ -28,12 +26,7 @@ public class RaceLogRacesHandle implements RaceHandle {
@Override
public RaceDefinition getRace(long timeoutInMilliseconds) {
long start = System.currentTimeMillis();
Set<RaceDefinition> raceDefs = tracker.getRaces();
RaceDefinition result = null;
if (raceDefs != null && !raceDefs.isEmpty()) {
result = tracker.getRaces().iterator().next();
}
RaceDefinition result = tracker.getRace();
boolean interrupted = false;
synchronized (tracker) {
while ((timeoutInMilliseconds == -1 || System.currentTimeMillis() - start < timeoutInMilliseconds)
@@ -47,13 +40,13 @@ public class RaceLogRacesHandle implements RaceHandle {
tracker.wait(timeToWait);
}
}
result = tracker.getRaces().isEmpty() ? null : tracker.getRaces().iterator().next();
result = tracker.getRace();
} catch (InterruptedException e) {
interrupted = true;
}
}
}
return result == null ? null : result;
return result;
}
@Override
@@ -96,7 +96,8 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
@Override
public RaceHandle startTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn,
Fleet fleet) throws NotDenotedForRaceLogTrackingException, Exception {
Fleet fleet, boolean trackWind, boolean correctWindDirectionByMagneticDeclination)
throws NotDenotedForRaceLogTrackingException, Exception {
RaceLog raceLog = raceColumn.getRaceLog(fleet);
RaceLogTrackingState raceLogTrackingState = new RaceLogTrackingStateAnalyzer(raceLog).analyze();
if (!raceLogTrackingState.isForTracking()) {
@@ -110,7 +111,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
}
final RaceHandle result;
if (!isRaceLogRaceTrackerAttached(service, raceLog)) {
result = addTracker(service, regatta, leaderboard, raceColumn, fleet, -1);
result = addTracker(service, regatta, leaderboard, raceColumn, fleet, -1, trackWind, correctWindDirectionByMagneticDeclination);
} else {
result = null;
}
@@ -123,16 +124,15 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
* 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, boolean trackWind,
boolean correctWindDirectionByMagneticDeclination) throws RaceLogRaceTrackerExistsException, Exception {
RaceLog raceLog = raceColumn.getRaceLog(fleet);
assert !isRaceLogRaceTrackerAttached(service, raceLog) : new RaceLogRaceTrackerExistsException(
leaderboard.getName() + " - " + raceColumn.getName() + " - " + fleet.getName());
Regatta regatta = regattaToAddTo == null ? null : service.getRegatta(regattaToAddTo);
RaceLogConnectivityParams params = new RaceLogConnectivityParams(service, regatta, raceColumn, fleet,
leaderboard, delayToLiveInMillis, domainFactory);
leaderboard, delayToLiveInMillis, domainFactory, trackWind, correctWindDirectionByMagneticDeclination);
return service.addRace(regattaToAddTo, params, timeoutInMilliseconds);
}
@@ -8,7 +8,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: com.sap.sailing.domain.common;bundle-version="1.0.0",
com.sap.sailing.domain.shared.android;bundle-version="1.0.0",
org.hamcrest;bundle-version="1.1.0",
org.junit4;bundle-version="4.8.2",
org.junit;bundle-version="4.8.2",
org.objenesis;bundle-version="1.3.0",
org.mockito.mockito-core;bundle-version="1.9.5",
com.sap.sailing.domain.test,
@@ -413,7 +413,7 @@ public class CurrentRaceFilterImplTest {
for (int i=0; i < numberOfRaces; i++) {
_505RaceCells.add(new RaceCellImpl(raceColumnNamePrefix+(i+firstRaceColumnNumber),
/* race log */ null, /* factor */ firstRaceColumnNumber, /* explicitFactor */ null,
/* zeroBasedIndexInFleet */ i));
/* zeroBasedIndexInFleet */ i, /* targetTime */ null));
}
final RaceRowImpl _505RaceRow = new RaceRowImpl(new FleetImpl(fleetName), _505RaceCells);
return _505RaceRow;
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.abstractlog.race;
import com.sap.sailing.domain.abstractlog.Revokable;
public interface RaceLogEndOfTrackingEvent extends RaceLogEvent {
public interface RaceLogEndOfTrackingEvent extends RaceLogEvent, Revokable {
}
@@ -1,5 +1,7 @@
package com.sap.sailing.domain.abstractlog.race;
public interface RaceLogStartOfTrackingEvent extends RaceLogEvent {
import com.sap.sailing.domain.abstractlog.Revokable;
public interface RaceLogStartOfTrackingEvent extends RaceLogEvent, Revokable {
}
@@ -13,12 +13,30 @@ public class ConfirmedFinishPositioningListFinder extends RaceLogAnalyzer<Compet
@Override
protected CompetitorResults performAnalysis() {
return performAnalysis(/* eventToIgnore */ null);
}
private CompetitorResults performAnalysis(RaceLogFinishPositioningConfirmedEvent eventToIgnore) {
for (RaceLogEvent event : getPassEventsDescending()) {
if (event instanceof RaceLogFinishPositioningConfirmedEvent) {
if (event != eventToIgnore && event instanceof RaceLogFinishPositioningConfirmedEvent) {
RaceLogFinishPositioningConfirmedEvent finishPositioningEvent = (RaceLogFinishPositioningConfirmedEvent) event;
return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
}
}
return null;
}
/**
* Same as {@link #analyze()}, only that if {@code event} is found in the log then it is ignored for this
* analysis. This way, the method returns a result as it would have been without {@code event} in the
* {@link RaceLog}. This can be useful, e.g., to determine the result prior to the last update.
*/
public CompetitorResults analyzeIgnoring(RaceLogFinishPositioningConfirmedEvent event) {
log.lockForRead();
try {
return performAnalysis(event);
} finally {
log.unlockAfterRead();
}
}
}
@@ -0,0 +1,45 @@
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
public class TrackingTimesEventFinder extends RaceLogAnalyzer<Util.Pair<RaceLogStartOfTrackingEvent, RaceLogEndOfTrackingEvent>> {
public TrackingTimesEventFinder(RaceLog raceLog) {
super(raceLog);
}
@Override
protected Util.Pair<RaceLogStartOfTrackingEvent, RaceLogEndOfTrackingEvent> performAnalysis() {
boolean startOfTrackingFound = false;
boolean endOfTrackingFound = false;
RaceLogStartOfTrackingEvent start = null;
RaceLogEndOfTrackingEvent end = null;
final RaceLog raceLog = getLog();
for (RaceLogEvent event : raceLog.getUnrevokedEventsDescending()) {
if (!startOfTrackingFound && event instanceof RaceLogStartOfTrackingEvent) {
start = (RaceLogStartOfTrackingEvent) event;
startOfTrackingFound = true;
}
if (!endOfTrackingFound && event instanceof RaceLogEndOfTrackingEvent) {
end = (RaceLogEndOfTrackingEvent) event;
endOfTrackingFound = true;
}
if (startOfTrackingFound && endOfTrackingFound) {
break;
}
}
final Pair<RaceLogStartOfTrackingEvent, RaceLogEndOfTrackingEvent> result;
if (startOfTrackingFound || endOfTrackingFound) {
result = new Util.Pair<>(start, end);
} else {
result = null;
}
return result;
}
}
@@ -2,7 +2,6 @@ package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
import com.sap.sailing.domain.common.abstractlog.TimePointSpecificationFoundInLog;
import com.sap.sailing.domain.common.abstractlog.TimePointSpecificationFoundInLogImpl;
@@ -10,38 +9,19 @@ import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
public class TrackingTimesFinder extends RaceLogAnalyzer<Util.Pair<TimePointSpecificationFoundInLog, TimePointSpecificationFoundInLog>> {
private final TrackingTimesEventFinder trackingTimesEventFinder;
public TrackingTimesFinder(RaceLog raceLog) {
super(raceLog);
this.trackingTimesEventFinder = new TrackingTimesEventFinder(raceLog);
}
@Override
protected Util.Pair<TimePointSpecificationFoundInLog, TimePointSpecificationFoundInLog> performAnalysis() {
boolean startOfTrackingFound = false;
boolean endOfTrackingFound = false;
TimePointSpecificationFoundInLog start = null;
TimePointSpecificationFoundInLog end = null;
final RaceLog raceLog = getLog();
for (RaceLogEvent event : raceLog.getUnrevokedEventsDescending()) {
if (!startOfTrackingFound && event instanceof RaceLogStartOfTrackingEvent) {
start = new TimePointSpecificationFoundInLogImpl(event.getLogicalTimePoint());
startOfTrackingFound = true;
}
if (!endOfTrackingFound && event instanceof RaceLogEndOfTrackingEvent) {
end = new TimePointSpecificationFoundInLogImpl(event.getLogicalTimePoint());
endOfTrackingFound = true;
}
if (startOfTrackingFound && endOfTrackingFound) {
break;
}
}
final Pair<TimePointSpecificationFoundInLog, TimePointSpecificationFoundInLog> result;
if (startOfTrackingFound || endOfTrackingFound) {
result = new Util.Pair<>(start, end);
} else {
result = null;
}
return result;
Pair<RaceLogStartOfTrackingEvent, RaceLogEndOfTrackingEvent> preResult = trackingTimesEventFinder.performAnalysis();
return preResult == null ? null :
new Util.Pair<TimePointSpecificationFoundInLog, TimePointSpecificationFoundInLog>(
preResult.getA()==null?null:new TimePointSpecificationFoundInLogImpl(preResult.getA().getLogicalTimePoint()),
preResult.getB()==null?null:new TimePointSpecificationFoundInLogImpl(preResult.getB().getLogicalTimePoint()));
}
}
@@ -1,6 +1,5 @@
package com.sap.sailing.domain.abstractlog.race.state;
public interface RaceStateChangedListener {
void onRacingProcedureChanged(ReadonlyRaceState state);
@@ -110,4 +110,6 @@ public interface SharedDomainFactory extends CompetitorFactory {
ControlPointWithTwoMarks getOrCreateControlPointWithTwoMarks(String id, String name, Mark left, Mark right);
RaceLogResolver getRaceLogResolver();
Mark getOrCreateMark(String name, MarkType markType);
}
Loaded 100 of 734 files, more files were not shown because too many files have changed in this diff. Show more