mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-19 12:15:28 +00:00
Merge branch 'master' into bug2447
Conflicts: java/com.sap.sailing.feature/feature.xml java/pom.xml
This commit is contained in:
+18
-3
File diff suppressed because one or more lines are too long
+26
-6
File diff suppressed because one or more lines are too long
+24
-4
File diff suppressed because one or more lines are too long
+23
-3
File diff suppressed because one or more lines are too long
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
# Counts the lines per committer currently in the tree, for all files with type
|
||||
# .java, .MF, .properties, .swift and .xml
|
||||
git ls-tree -r --name-only HEAD -- | grep "\(\.java$\)\|\(\.MF$\)\|\(\.properties$\)\|\(\.swift$\)\|\(\.xml$\)" | sed -e 's/^/"/' -e 's/$/"/' | xargs -n1 git blame HEAD | recode ISO-8859-1..UTF-8 | sed -e 's/^.* (\(.*\) [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [+-][0-9][0-9][0-9][0-9] *[0-9][0-9]*).*$/\1/' | sed -e 's/ *$//' | sort | uniq -c | sort -rn | awk 'BEGIN {s=0;} /.*/ {s=s+$1; print $0;} END { print "\n Sum: " s; }'
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
git log --shortstat --pretty="%cE" | sed 's/\(.*\)@.*/\1/' | grep -v "^$" | awk 'BEGIN { line=""; } !/^ / { if (line=="" || !match(line, $0)) {line = $0 "," line }} /^ / { print line " # " $0; line=""}' | tr '[:upper:]' '[:lower:]' | sort | sed -E 's/# //;s/ files? changed,//;s/([0-9]+) ([0-9]+ deletion)/\1 0 insertions\(+\), \2/;s/\(\+\)$/\(\+\), 0 deletions\(-\)/;s/insertions?\(\+\), //;s/ deletions?\(-\)//' | awk 'BEGIN {name=""; files=0; insertions=0; deletions=0;} {if ($1 != name && name != "") { print insertions " " name ":" files " files changed, " insertions " insertions(+), " deletions " deletions(-), " insertions-deletions " net"; files=0; insertions=0; deletions=0; name=$1; } name=$1; files+=$2; insertions+=$3; deletions+=$4} END {print name ": " files " files changed, " insertions " insertions(+), " deletions " deletions(-), " insertions-deletions " net";}' | grep -v "^[^,:]*,.*,: " | sort -n
|
||||
@@ -1 +0,0 @@
|
||||
bin
|
||||
@@ -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,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;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<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>
|
||||
Executable → Regular
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.sap.sailing.autoload</name>
|
||||
<name>com.sap.sailing.competitorimport</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
-5
@@ -1,12 +1,7 @@
|
||||
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
|
||||
Executable → Regular
-1
@@ -1,4 +1,3 @@
|
||||
#Mon Aug 29 13:20:38 CEST 2011
|
||||
eclipse.preferences.version=1
|
||||
pluginProject.extensions=false
|
||||
resolve.requirebundle=false
|
||||
@@ -0,0 +1,11 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Competitorimport
|
||||
Bundle-SymbolicName: com.sap.sailing.competitorimport
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Export-Package: com.sap.sailing.competitorimport
|
||||
Require-Bundle: com.sap.sse.common,
|
||||
com.sap.sailing.domain.shared.android,
|
||||
com.sap.sailing.domain.common
|
||||
Executable → Regular
+1
-1
@@ -7,6 +7,6 @@
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sailing.autoload</artifactId>
|
||||
<artifactId>com.sap.sailing.competitorimport</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.sap.sailing.competitorimport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
import com.sap.sailing.domain.common.CompetitorDescriptor;
|
||||
import com.sap.sse.common.Named;
|
||||
|
||||
/**
|
||||
* Competitor data may come from various sources, such as external regatta management systems (RMS),
|
||||
* CSV files, Excel spreadsheets and the like. When creating a regatta that uses "RaceLog Tracking"
|
||||
* (also known as Smartphone Tracking)---and be it only in order to manage results for the regatta
|
||||
* with the race committee app---it is tedious having to enter all competitor data manually when
|
||||
* that data is already available in electronic form.<p>
|
||||
*
|
||||
* In its simplest form, a provider will just produce an otherwise unstructured list of competitor
|
||||
* entries with no hint as to the event, regatta or race that the competitor pertains to. More
|
||||
* sophisticated providers may structure competitor data into events, regattas or even individual
|
||||
* races so that importing these competitors into a single fleet of one race column becomes possible.
|
||||
* This will be particularly useful for split-fleet racing.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface CompetitorProvider extends Named {
|
||||
/**
|
||||
* @return keys are event names, values are the names of the regatta in the event for which the connector has
|
||||
* competitor names. Should the value for a key be <code>null</code>, competitors for the event may still
|
||||
* be available, only they may not be keyed per regatta in that case.
|
||||
*/
|
||||
Map<String, Set<String>> getHasCompetitorsForRegattasInEvent() throws IOException;
|
||||
|
||||
/**
|
||||
* Obtains competitor records from the source of import
|
||||
*
|
||||
* @param eventName
|
||||
* an event name as obtained as a key in {@link #getHasCompetitorsForRegattasInEvent()}'s result
|
||||
* @param regattaName
|
||||
* <code>null</code> to get the competitors for all regattas in the event specified by
|
||||
* <code>eventName</code>, or a regatta name as provided in the value set for the key
|
||||
* <code>eventName</code> as returned by {@link #getHasCompetitorsForRegattasInEvent()}.
|
||||
*/
|
||||
Iterable<CompetitorDescriptor> getCompetitorDescriptors(String eventName, String regattaName) throws JAXBException, IOException;
|
||||
}
|
||||
@@ -40,7 +40,7 @@
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-incremental -war "${project_loc:com.sap.sailing.dashboards.gwt}" -startupUrl /dashboards/RibDashboard.html -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9874 com.sap.sailing.dashboards.gwt.RibDashboard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -war "${project_loc:com.sap.sailing.dashboards.gwt}" -startupUrl /dashboards/RibDashboard.html -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9874 com.sap.sailing.dashboards.gwt.RibDashboard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.dashboards.gwt"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -Dgwt.watchFileChanges=false"/>
|
||||
</launchConfiguration>
|
||||
|
||||
+1
-1
@@ -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-11-23T14:54:05Z" 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="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">
|
||||
<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
-1
@@ -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-11-23T14:54:05Z" 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="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">
|
||||
<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
-1
@@ -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-11-23T14:54:06Z" 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="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">
|
||||
<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>
|
||||
|
||||
+3
-2
@@ -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"),
|
||||
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.dto.PersonDTO;
|
||||
import com.sap.sse.common.CountryCode;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Named;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.NamedImpl;
|
||||
|
||||
|
||||
public class CompetitorDescriptor extends NamedImpl implements Named {
|
||||
private static final long serialVersionUID = -6645726854552711646L;
|
||||
|
||||
private final String eventName;
|
||||
private final String regattaName;
|
||||
private final String boatClassName;
|
||||
private final String boatName;
|
||||
private final String teamName;
|
||||
private final String raceName;
|
||||
private final String fleetName;
|
||||
private final String sailNumber;
|
||||
private final String name;
|
||||
private final CountryCode countryCode;
|
||||
private final List<PersonDTO> persons;
|
||||
private final Double timeOnTimeFactor;
|
||||
private final Duration timeOnDistanceAllowancePerNauticalMile;
|
||||
|
||||
public CompetitorDescriptor(String eventName, String regattaName, String boatClassName, String raceName,
|
||||
String fleetName, String sailNumber, String name, String teamName, String boatName, CountryCode countryCode,
|
||||
Iterable<PersonDTO> persons, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile) {
|
||||
super(name);
|
||||
this.eventName = eventName;
|
||||
this.regattaName = regattaName;
|
||||
this.boatClassName = boatClassName;
|
||||
this.boatName = boatName;
|
||||
this.raceName = raceName;
|
||||
this.fleetName = fleetName;
|
||||
this.sailNumber = sailNumber;
|
||||
this.name = name;
|
||||
this.teamName = teamName;
|
||||
this.countryCode = countryCode;
|
||||
this.persons = new ArrayList<>();
|
||||
Util.addAll(persons, this.persons);
|
||||
this.timeOnTimeFactor = timeOnTimeFactor;
|
||||
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
|
||||
}
|
||||
|
||||
public String getEventName() {
|
||||
return eventName;
|
||||
}
|
||||
|
||||
public String getRegattaName() {
|
||||
return regattaName;
|
||||
}
|
||||
|
||||
public String getBoatClassName() {
|
||||
return boatClassName;
|
||||
}
|
||||
|
||||
public String getRaceName() {
|
||||
return raceName;
|
||||
}
|
||||
|
||||
public String getFleetName() {
|
||||
return fleetName;
|
||||
}
|
||||
|
||||
public String getSailNumber() {
|
||||
return sailNumber;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public CountryCode getCountryCode() {
|
||||
return countryCode;
|
||||
}
|
||||
|
||||
public Iterable<PersonDTO> getPersons() {
|
||||
return persons;
|
||||
}
|
||||
|
||||
public Double getTimeOnTimeFactor() {
|
||||
return timeOnTimeFactor;
|
||||
}
|
||||
|
||||
public String getBoatName() {
|
||||
return boatName;
|
||||
}
|
||||
|
||||
public String getTeamName() {
|
||||
return teamName;
|
||||
}
|
||||
|
||||
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
|
||||
return timeOnDistanceAllowancePerNauticalMile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CompetitorDescriptor [eventName=" + eventName + ", regattaName=" + regattaName + ", boatClassName="
|
||||
+ boatClassName + ", boatName=" + boatName + ", teamName=" + teamName + ", raceName=" + raceName
|
||||
+ ", fleetName=" + fleetName + ", sailNumber=" + sailNumber + ", name=" + name + ", countryCode="
|
||||
+ countryCode + ", persons=" + persons + ", timeOnTimeFactor=" + timeOnTimeFactor
|
||||
+ ", timeOnDistanceAllowancePerNauticalMile=" + timeOnDistanceAllowancePerNauticalMile + "]";
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,10 @@ public interface Position extends Serializable {
|
||||
Distance getDistance(Position p);
|
||||
|
||||
/**
|
||||
* The bearing from this position towards <code>p</code> on a great circle
|
||||
* The bearing from this position towards <code>p</code> on a great circle.
|
||||
*
|
||||
* @return {@code null} if {@code p} is {@code null}, otherwise the bearing from {@code this} {@link Position} to
|
||||
* {@code p} along a great circle
|
||||
*/
|
||||
Bearing getBearingGreatCircle(Position p);
|
||||
|
||||
|
||||
+92
@@ -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);
|
||||
}
|
||||
+9
-5
@@ -14,25 +14,29 @@ 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;
|
||||
}
|
||||
|
||||
+5
@@ -20,6 +20,11 @@ public interface CompetitorDTO extends Serializable, MappableToDevice {
|
||||
|
||||
String getSearchTag();
|
||||
|
||||
/**
|
||||
* If the {@code searchTag} is not contained in {@link #getSearchTag()}, appends it to the search tag, separated by a space character
|
||||
*/
|
||||
void addToSearchTag(String searchTag);
|
||||
|
||||
BoatDTO getBoat();
|
||||
|
||||
BoatClassDTO getBoatClass();
|
||||
|
||||
+11
-3
@@ -181,19 +181,27 @@ public class CompetitorDTOImpl extends NamedDTO implements CompetitorDTO, Serial
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSearchTag() {
|
||||
return searchTag;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
@Override
|
||||
public void addToSearchTag(String searchTag) {
|
||||
if (this.searchTag == null) {
|
||||
this.searchTag = searchTag;
|
||||
} else if (!this.searchTag.contains(searchTag)) {
|
||||
this.searchTag += " "+searchTag;
|
||||
}
|
||||
}
|
||||
|
||||
public String email(){
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
public class PersonDTO extends NamedDTO {
|
||||
private static final long serialVersionUID = 7248019801310303654L;
|
||||
private Date dateOfBirth;
|
||||
private String description;
|
||||
private String nationalityThreeLetterIOCAcronym;
|
||||
|
||||
PersonDTO() {} // for GWT de-serialization only
|
||||
|
||||
public PersonDTO(String name, Date dateOfBirth, String description, String nationalityThreeLetterIOCAcronym) {
|
||||
super(name);
|
||||
this.dateOfBirth = dateOfBirth;
|
||||
this.description = description;
|
||||
this.nationalityThreeLetterIOCAcronym = nationalityThreeLetterIOCAcronym;
|
||||
}
|
||||
|
||||
public Date getDateOfBirth() {
|
||||
return dateOfBirth;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getNationalityThreeLetterIOCAcronym() {
|
||||
return nationalityThreeLetterIOCAcronym;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + Objects.hash(dateOfBirth, description, nationalityThreeLetterIOCAcronym);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
PersonDTO other = (PersonDTO) obj;
|
||||
return Objects.equals(dateOfBirth, other.dateOfBirth) && Objects.equals(description, other.description)
|
||||
&& Objects.equals(nationalityThreeLetterIOCAcronym, other.nationalityThreeLetterIOCAcronym);
|
||||
}
|
||||
}
|
||||
+6
@@ -112,6 +112,12 @@ public class PreviousCompetitorDTOImpl implements CompetitorDTO {
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToSearchTag(String searchTag) {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageURL() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
|
||||
Executable
+116
@@ -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 + "]";
|
||||
}
|
||||
}
|
||||
+2
-6
@@ -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);
|
||||
|
||||
+38
@@ -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;
|
||||
}
|
||||
|
||||
+34
@@ -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;
|
||||
|
||||
@@ -125,6 +126,12 @@ public interface MongoObjectFactory {
|
||||
*/
|
||||
void storeCompetitor(Competitor competitor);
|
||||
|
||||
/**
|
||||
* Like {@link #storeCompetitor(Competitor)}, but for a collection of competitors that are all
|
||||
* expected to be new, having a unique {@link Competitor#getId() ID}.
|
||||
*/
|
||||
void storeCompetitors(Iterable<Competitor> competitors);
|
||||
|
||||
void removeAllCompetitors();
|
||||
|
||||
void removeCompetitor(Competitor competitor);
|
||||
@@ -143,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();
|
||||
}
|
||||
|
||||
+7
@@ -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,
|
||||
}
|
||||
|
||||
+33
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+67
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.persistence.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -104,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;
|
||||
@@ -118,6 +121,7 @@ import com.sap.sse.common.TimeRange;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.TypeBasedServiceFinder;
|
||||
import com.sap.sse.common.TypeBasedServiceFinderFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.shared.media.ImageDescriptor;
|
||||
import com.sap.sse.shared.media.VideoDescriptor;
|
||||
@@ -127,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.
|
||||
@@ -142,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1245,6 +1252,20 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeCompetitors(Iterable<Competitor> competitors) {
|
||||
if (competitors != null && !Util.isEmpty(competitors)) {
|
||||
DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
|
||||
List<DBObject> competitorsDB = new ArrayList<>();
|
||||
for (Competitor competitor : competitors) {
|
||||
JSONObject json = competitorSerializer.serialize(competitor);
|
||||
DBObject entry = (DBObject) JSON.parse(json.toString());
|
||||
competitorsDB.add(entry);
|
||||
}
|
||||
collection.insert(competitorsDB);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllCompetitors() {
|
||||
logger.info("Removing all persistent competitor info");
|
||||
@@ -1500,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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+42
-5
@@ -2,7 +2,9 @@ package com.sap.sailing.domain.racelogtracking.test;
|
||||
|
||||
import static com.sap.sse.common.Util.size;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -11,14 +13,20 @@ import org.junit.Before;
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Sideline;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
@@ -26,12 +34,19 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.impl.MongoSensorFixStoreImpl;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockDeviceAndSessionIdentifierWithGPSFixesDeserializer;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.Track;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.DeviceAndSessionIdentifierWithGPSFixesDeserializer;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
@@ -61,13 +76,17 @@ public class AbstractGPSFixStoreTest {
|
||||
service = new RacingEventServiceImpl(null, null, serviceFinderFactory);
|
||||
raceLog = new RaceLogImpl("racelog");
|
||||
regattaLog = new RegattaLogImpl("regattalog");
|
||||
|
||||
dropPersistedData();
|
||||
store = new MongoSensorFixStoreImpl(service.getMongoObjectFactory(), service.getDomainObjectFactory(),
|
||||
serviceFinderFactory);
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
dropPersistedData();
|
||||
}
|
||||
|
||||
private void dropPersistedData() {
|
||||
MongoObjectFactoryImpl mongoOF = (MongoObjectFactoryImpl) service.getMongoObjectFactory();
|
||||
mongoOF.getGPSFixCollection().drop();
|
||||
mongoOF.getGPSFixMetadataCollection().drop();
|
||||
@@ -76,8 +95,9 @@ public class AbstractGPSFixStoreTest {
|
||||
}
|
||||
|
||||
protected void map(RegattaLog regattaLog, Competitor comp, DeviceIdentifier device, long from, long to) {
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
|
||||
comp, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(MillisecondsTimePoint.now(),
|
||||
MillisecondsTimePoint.now(), author, UUID.randomUUID(), comp, device, new MillisecondsTimePoint(from),
|
||||
new MillisecondsTimePoint(to)));
|
||||
}
|
||||
|
||||
protected void map(Competitor comp, DeviceIdentifier device, long from, long to) {
|
||||
@@ -85,8 +105,25 @@ public class AbstractGPSFixStoreTest {
|
||||
}
|
||||
|
||||
protected void map(Mark mark, DeviceIdentifier device, long from, long to) {
|
||||
regattaLog.add(new RegattaLogDeviceMarkMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
|
||||
mark, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
|
||||
regattaLog.add(new RegattaLogDeviceMarkMappingEventImpl(MillisecondsTimePoint.now(),
|
||||
MillisecondsTimePoint.now(), author, UUID.randomUUID(), mark, device, new MillisecondsTimePoint(from),
|
||||
new MillisecondsTimePoint(to)));
|
||||
}
|
||||
|
||||
protected void defineMarksOnRegattaLog(Mark... marks) {
|
||||
for (int i = 0; i < marks.length; i++) {
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(i + 1), author,
|
||||
new MillisecondsTimePoint(1), 0, marks[i]));
|
||||
}
|
||||
}
|
||||
|
||||
protected DynamicTrackedRaceImpl createDynamicTrackedRace(BoatClass boatClass, RaceDefinition raceDefinition) {
|
||||
DynamicTrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
|
||||
/* startDate */ null, /* endDate */null, null, null, "a", null));
|
||||
return new DynamicTrackedRaceImpl(regatta, raceDefinition, Collections.<Sideline> emptyList(),
|
||||
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
|
||||
mock(RaceLogResolver.class));
|
||||
}
|
||||
|
||||
protected void testNumberOfRawFixes(Track<?> track, long expected) {
|
||||
|
||||
+4
-4
@@ -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);
|
||||
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
package com.sap.sailing.domain.racelogtracking.test.impl;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.ConcurrentModificationException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Sideline;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.persistence.PersistenceFactory;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.impl.MongoSensorFixStoreImpl;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.EmptySensorFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.SensorFixMapper;
|
||||
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogsensortracking.SensorFixMapperFactory;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RaceLogFixTrackerManager;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class RaceLogFixTrackerManagerTest {
|
||||
protected final MockSmartphoneImeiServiceFinderFactory serviceFinderFactory = new MockSmartphoneImeiServiceFinderFactory();
|
||||
protected final DeviceIdentifier device = new SmartphoneImeiIdentifier("a");
|
||||
protected final DeviceIdentifier deviceTest = new SmartphoneImeiIdentifier("b");
|
||||
protected RaceLog raceLog;
|
||||
protected RaceLog raceLog2;
|
||||
protected RegattaLog regattaLog;
|
||||
protected SensorFixStore store;
|
||||
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null,
|
||||
null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
|
||||
protected final Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
|
||||
protected final Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
|
||||
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
|
||||
|
||||
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
|
||||
private DynamicTrackedRace trackedRace;
|
||||
|
||||
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
|
||||
return new GPSFixMovingImpl(new DegreePosition(lat, lng), new MillisecondsTimePoint(millis),
|
||||
new KnotSpeedWithBearingImpl(knots, new DegreeBearingImpl(degrees)));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws UnknownHostException, MongoException {
|
||||
raceLog = new RaceLogImpl("racelog");
|
||||
raceLog2 = new RaceLogImpl("racelog2");
|
||||
|
||||
regattaLog = new RegattaLogImpl("regattalog");
|
||||
|
||||
store = new MongoSensorFixStoreImpl(PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(),
|
||||
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory(), serviceFinderFactory);
|
||||
|
||||
Course course = new CourseImpl("course",
|
||||
Arrays.asList(new Waypoint[] { new WaypointImpl(mark), new WaypointImpl(mark2) }));
|
||||
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(comp));
|
||||
DynamicTrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
|
||||
/* startDate */ null, /* endDate */null, null, null, "a", null));
|
||||
trackedRace = new DynamicTrackedRaceImpl(regatta, race, Collections.<Sideline> emptyList(),
|
||||
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
|
||||
mock(RaceLogResolver.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 4001: A {@link ConcurrentModificationException} was thrown when stopping tracking for a race with multiple
|
||||
* attached RaceLogs.
|
||||
*/
|
||||
@Test
|
||||
public void testThatNoExceptionIsThrownWhenStoppingTrackingForRaceWithMultipleRaceLogs_bug4001() {
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRaceLog(raceLog2);
|
||||
|
||||
RaceLogFixTrackerManager raceLogFixTrackerManager = new RaceLogFixTrackerManager(trackedRace,
|
||||
EmptySensorFixStore.INSTANCE, new SensorFixMapperFactory() {
|
||||
@Override
|
||||
public <FixT extends Timed, TrackT extends DynamicTrack<FixT>> SensorFixMapper<FixT, TrackT, Competitor> createCompetitorMapper(
|
||||
Class<? extends RegattaLogDeviceMappingEvent<?>> eventType) {
|
||||
throw new IllegalArgumentException("Unknown event type");
|
||||
}
|
||||
});
|
||||
raceLogFixTrackerManager.stop(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 4001: A {@link ConcurrentModificationException} was thrown when stopping tracking for a race with multiple
|
||||
* attached RaceLogs.
|
||||
*/
|
||||
@Test
|
||||
public void testThatNoExceptionIsThrownWhenStoppingTrackingWhenAddingSecondRaceLogWhileAlreadyTracking_bug4001() {
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
|
||||
RaceLogFixTrackerManager raceLogFixTrackerManager = new RaceLogFixTrackerManager(trackedRace,
|
||||
EmptySensorFixStore.INSTANCE, new SensorFixMapperFactory() {
|
||||
@Override
|
||||
public <FixT extends Timed, TrackT extends DynamicTrack<FixT>> SensorFixMapper<FixT, TrackT, Competitor> createCompetitorMapper(
|
||||
Class<? extends RegattaLogDeviceMappingEvent<?>> eventType) {
|
||||
throw new IllegalArgumentException("Unknown event type");
|
||||
}
|
||||
});
|
||||
trackedRace.attachRaceLog(raceLog2);
|
||||
raceLogFixTrackerManager.stop(false);
|
||||
}
|
||||
}
|
||||
+230
-44
@@ -1,66 +1,59 @@
|
||||
package com.sap.sailing.domain.racelogtracking.test.impl;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.Timeout;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEndOfTrackingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartOfTrackingEventImpl;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Sideline;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.FixLoaderAndTracker;
|
||||
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.common.impl.TimeRangeImpl;
|
||||
|
||||
public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
|
||||
private static final Logger logger = Logger.getLogger(TrackedRaceLoadsFixesTest.class.getName());
|
||||
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
|
||||
|
||||
private final Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
|
||||
private final Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null,
|
||||
null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
private final Course course = new CourseImpl("course", Arrays.asList(new WaypointImpl(mark), new WaypointImpl(mark2)));
|
||||
private final RaceDefinition raceDefinition = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(comp, comp2));
|
||||
|
||||
@Rule
|
||||
public Timeout TrackedRaceLoadsFixesTestTimeout = new Timeout(3 * 60 * 1000);
|
||||
|
||||
@Test
|
||||
public void doesRaceLoadOnlyBetweenStartAndEndOfTracking() throws TransformationException,
|
||||
NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
|
||||
DeviceIdentifier markDevice = new SmartphoneImeiIdentifier("imei2");
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
|
||||
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
|
||||
new WaypointImpl(mark2) }));
|
||||
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
|
||||
defineMarksOnRegattaLog(mark, mark2);
|
||||
map(comp, device, 0, 10000);
|
||||
map(mark, markDevice, 0, 10000);
|
||||
|
||||
@@ -71,13 +64,7 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
|
||||
store.storeFix(markDevice, createFix(1100, 10, 20, 30, 40));
|
||||
store.storeFix(markDevice, createFix(2100, 10, 20, 30, 40));
|
||||
|
||||
DynamicTrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
|
||||
null, /* endDate */null, null, null, "a", null));
|
||||
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
|
||||
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
|
||||
/* useMarkPassingCalculator */ false,
|
||||
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
|
||||
final DynamicTrackedRaceImpl trackedRace = createDynamicTrackedRace(boatClass, raceDefinition);
|
||||
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(1000));
|
||||
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2000));
|
||||
new FixLoaderAndTracker(trackedRace, store, null);
|
||||
@@ -100,16 +87,9 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
|
||||
@Test
|
||||
public void areFixesStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException,
|
||||
InterruptedException {
|
||||
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
|
||||
defineMarksOnRegattaLog(mark, mark2);
|
||||
DeviceIdentifier device2 = new SmartphoneImeiIdentifier("imei2");
|
||||
DeviceIdentifier device3 = new SmartphoneImeiIdentifier("imei3");
|
||||
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
|
||||
new WaypointImpl(mark2) }));
|
||||
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(comp, comp2));
|
||||
|
||||
map(comp, device, 0, 20000);
|
||||
map(comp2, device2, 0, 600);
|
||||
@@ -127,12 +107,7 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
|
||||
store.storeFix(device, createFix(i + 1000, 10, 20, 30, 40));
|
||||
}
|
||||
|
||||
DynamicTrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
|
||||
/* startDate */ null, /* endDate */null, null, null, "a", null));
|
||||
DynamicTrackedRace trackedRace = new DynamicTrackedRaceImpl(regatta, race,
|
||||
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
|
||||
/*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, mock(RaceLogResolver.class));
|
||||
DynamicTrackedRace trackedRace = createDynamicTrackedRace(boatClass, raceDefinition);
|
||||
|
||||
new FixLoaderAndTracker(trackedRace, store, null);
|
||||
|
||||
@@ -146,16 +121,227 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark2), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixesForCompetitorsAreNotLoadedIfMappingDoesNotIntersectWithTrackingInterval()
|
||||
throws InterruptedException {
|
||||
testFixes(/* start of tracking */ 200, /* end of tracking */ 300, /* mappings and fixes */ () -> {
|
||||
map(comp, device, 0, 100);
|
||||
store.storeFix(device, createFix(10, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(20, 10, 20, 30, 40));
|
||||
}, /* tests and expectations */ trackedRace -> testNumberOfRawFixes(trackedRace.getTrack(comp), 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixesForCompetitorsAreLoadedIfMappingDoesIntersectWithTrackingIntervalFixesWithinIntersectionOnly()
|
||||
throws InterruptedException {
|
||||
testFixes(/* start of tracking */ 100, /* end of tracking */ 300, /* mappings and fixes */ () -> {
|
||||
map(comp, device, 0, 200);
|
||||
store.storeFix(device, createFix(50, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(150, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(250, 10, 20, 30, 40));
|
||||
map(comp, device, 350, 500);
|
||||
store.storeFix(device, createFix(400, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(450, 10, 20, 30, 40));
|
||||
}, /* tests and expectations */ trackedRace -> testNumberOfRawFixes(trackedRace.getTrack(comp), 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddingMappingLoadsFixesPreviouslyNotCovered() throws InterruptedException {
|
||||
testFixes(/* start of tracking */ 10, /* end of tracking */ 500, /* mappings and fixes */ () -> {
|
||||
map(comp, device, 0, 200);
|
||||
map(comp, device, 300, 400);
|
||||
store.storeFix(device, createFix(50, 10, 20, 30, 40)); // in first mapping
|
||||
store.storeFix(device, createFix(150, 10, 20, 30, 40)); // in first mapping
|
||||
store.storeFix(device, createFix(250, 10, 20, 30, 40)); // outside both mappings
|
||||
store.storeFix(device, createFix(350, 10, 20, 30, 40)); // in second mapping
|
||||
}, /* tests and expectations */ trackedRace -> {
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 3);
|
||||
map(comp, device, 0, 500); // covers fix at 250ms; assert that only that fix is loaded
|
||||
try {
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Exception waiting for loading to finish", e);
|
||||
}
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 4);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddingMappingDoesNotLoadFixesAlreadyCoveredByExistingMapping() throws InterruptedException {
|
||||
testFixes(/* start of tracking */ 10, /* end of tracking */ 500, /* mappings and fixes */ () -> {
|
||||
map(comp, device, 0, 200);
|
||||
map(comp, device, 300, 400);
|
||||
store.storeFix(device, createFix(50, 10, 20, 30, 40)); // in first mapping
|
||||
store.storeFix(device, createFix(150, 10, 20, 30, 40)); // in first mapping
|
||||
store.storeFix(device, createFix(250, 10, 20, 30, 40)); // outside both mappings
|
||||
store.storeFix(device, createFix(350, 10, 20, 30, 40)); // in second mapping
|
||||
}, /* tests and expectations */ trackedRace -> {
|
||||
map(comp, device, 0, 500); // covers fix at 250ms
|
||||
try {
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Exception waiting for loading to finish", e);
|
||||
}
|
||||
store.storeFix(device, createFix(400, 10, 20, 30, 40)); // in third mapping
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 5);
|
||||
});
|
||||
}
|
||||
|
||||
/** Regression test for bug 4008 - https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4008 */
|
||||
@Test
|
||||
public void testFixesForMarkAreLoadedIfMappingDoesNotIntersectWithTrackingInterval() throws InterruptedException {
|
||||
testFixes(/* start of tracking */ 200, /* end of tracking */ 300, /* mappings and fixes */ () -> {
|
||||
map(mark, device, 0, 100);
|
||||
store.storeFix(device, createFix(10, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(20, 10, 20, 30, 40));
|
||||
}, /* tests and expectations */ trackedRace -> testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 2));
|
||||
}
|
||||
|
||||
/** Regression test for bug 4008 - https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4008 */
|
||||
@Test
|
||||
public void testFixesForTwoMarksAreLoadedIfMappingsDoNotIntersectWithTrackingInterval()
|
||||
throws InterruptedException {
|
||||
testFixes(/* start of tracking */ 400, /* end of tracking */ 500, /* mappings and fixes */ () -> {
|
||||
map(mark, device, 0, 100);
|
||||
store.storeFix(device, createFix(50, 10, 20, 30, 40));
|
||||
map(mark2, device, 200, 300);
|
||||
store.storeFix(device, createFix(250, 10, 20, 30, 40));
|
||||
}, /* tests and expectations */ trackedRace -> {
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark2), 1);
|
||||
});
|
||||
}
|
||||
|
||||
/** Regression test for bug 4008 - https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4008 */
|
||||
@Test
|
||||
public void testFixesForMarkAreLoadedIfMappingDoesIntersectWithTrackingIntervalFixesWithinIntersectionOnly()
|
||||
throws InterruptedException {
|
||||
testFixes(/* start of tracking */ 100, /* end of tracking */ 300, /* mappings and fixes */ () -> {
|
||||
map(mark, device, 0, 200);
|
||||
store.storeFix(device, createFix(50, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(150, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(250, 10, 20, 30, 40));
|
||||
|
||||
map(mark, device, 350, 500);
|
||||
store.storeFix(device, createFix(400, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(450, 10, 20, 30, 40));
|
||||
}, /* tests and expectations */ trackedRace -> {
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
});
|
||||
}
|
||||
|
||||
/** Regression test for bug 4008 - https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4008 */
|
||||
@Test
|
||||
public void testFixesForMarkAreLoadedIfMappingDoesIntersectWithTrackingIntervalAllFixesBecauseOfNoFixesWithIntersection()
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
testFixes(/* start of tracking */ 100, /* end of tracking */ 300, /* mappings and fixes */ () -> {
|
||||
map(mark, device, 0, 200);
|
||||
store.storeFix(device, createFix(50, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(250, 10, 20, 30, 40));
|
||||
map(mark, device, 350, 500);
|
||||
store.storeFix(device, createFix(400, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(450, 10, 20, 30, 40));
|
||||
}, /* tests and expectations */ trackedRace -> {
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 3);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixForMarkIsAddedIfBeforeTrackingIntervalAndNoOtherFixExists()
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
testFixes(/* start of tracking */ 100, /* end of tracking */ 300, /* mappings */ () -> map(mark, device, 0, 200),
|
||||
/* fixes and tests/expectations */ trackedRace -> {
|
||||
store.storeFix(device, createFix(50, 10, 20, 30, 40));
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixForMarkIsAddedIfAfterTrackingIntervalAndNoOtherFixExists()
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
testFixes(/* start of tracking */ 100, /* end of tracking */ 300, /* mappings */ () -> map(mark, device, 0, 400), /* fixes and tests/expectations */ trackedRace -> {
|
||||
store.storeFix(device, createFix(350, 10, 20, 30, 40));
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixForMarkIsAddedIfBeforeTrackingIntervalAndBetterThanAnExistingOne()
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
testFixes(/* start of tracking */ 100, /* end of tracking */ 300, /* mappings */ () -> map(mark, device, 0, 400),
|
||||
/* fixes and tests/expectations */ trackedRace -> {
|
||||
store.storeFix(device, createFix(50, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(75, 10, 20, 30, 40));
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 2);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixForMarkIsNotAddedIfBeforeTrackingIntervalAndWorseThanAnExistingOne()
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
testFixes(/* start of tracking */ 100, /* end of tracking */ 300, /* mappings */ () -> map(mark, device, 0, 400),
|
||||
/* fixes and tests/expectations */ trackedRace -> {
|
||||
store.storeFix(device, createFix(75, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(50, 10, 20, 30, 40));
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixForMarkIsAddedIfAfterTrackingIntervalAndBetterThanAnExistingOne()
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
testFixes(/* start of tracking */ 100, /* end of tracking */ 300, /* mappings */ () -> map(mark, device, 0, 400),
|
||||
/* fixes and tests/expectations */ trackedRace -> {
|
||||
store.storeFix(device, createFix(375, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(350, 10, 20, 30, 40));
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 2);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixForMarkIsNotAddedIfAfterTrackingIntervalAndWorseThanAnExistingOne()
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
testFixes(/* start of tracking */ 100, /* end of tracking */ 300, /* mappings */ () -> map(mark, device, 0, 400),
|
||||
/* fixes and tests/expectations */ trackedRace -> {
|
||||
store.storeFix(device, createFix(350, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(375, 10, 20, 30, 40));
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixForMarkIsNotAddedIfNotWithinTrackingIntervalAndFixWithinTrackingIntervalExists()
|
||||
throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
testFixes(/* start of tracking */ 100, /* end of tracking */ 300, /* mappings */ () -> map(mark, device, 0, 400),
|
||||
/* fixes and tests/expectations */ trackedRace -> {
|
||||
store.storeFix(device, createFix(200, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(50, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(350, 10, 20, 30, 40));
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
});
|
||||
}
|
||||
|
||||
private void testFixes(long startOfTracking, long endOfTracking, Runnable beforeTrackingStarted,
|
||||
Consumer<DynamicTrackedRace> afterTrackingStarted) throws InterruptedException {
|
||||
defineMarksOnRegattaLog(mark, mark2);
|
||||
raceLog.add(new RaceLogStartOfTrackingEventImpl(new MillisecondsTimePoint(startOfTracking), author, 0));
|
||||
raceLog.add(new RaceLogEndOfTrackingEventImpl(new MillisecondsTimePoint(endOfTracking), author, 0));
|
||||
beforeTrackingStarted.run();
|
||||
DynamicTrackedRace trackedRace = createDynamicTrackedRace(boatClass, raceDefinition);
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
new FixLoaderAndTracker(trackedRace, store, null);
|
||||
trackedRace.waitForLoadingToFinish();
|
||||
afterTrackingStarted.accept(trackedRace);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metadataStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
assertEquals(0, store.getNumberOfFixes(device));
|
||||
assertEquals(null, store.getTimeRangeCoveredByFixes(device));
|
||||
|
||||
map(comp, device, 0, 600);
|
||||
|
||||
store.storeFix(device, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(200, 10, 20, 30, 40));
|
||||
|
||||
assertEquals(2, store.getNumberOfFixes(device));
|
||||
assertEquals(TimeRangeImpl.create(100, 200), store.getTimeRangeCoveredByFixes(device));
|
||||
}
|
||||
|
||||
+11
@@ -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);
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -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
|
||||
|
||||
+1
-2
@@ -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);
|
||||
|
||||
+1
-3
@@ -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
-1
@@ -5,7 +5,7 @@ iOSUsers=启动 iOS 应用
|
||||
androidUsers=启动 Android 应用
|
||||
alternativelyVisitThisLink=如果在已安装该应用的设备中读取邮件,只需点击以下链接即可启动:
|
||||
buoyTender=浮标供应船
|
||||
appStoreInstallText=如果尚无该应用,请安装:
|
||||
appStoreInstallText=如果您尚无该应用,请安装:
|
||||
appIos=安装 iOS 应用
|
||||
appAndroid=安装 Android 应用
|
||||
buoyPingerAppName=SAP Sailing Buoy Pinger
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ iOSUsers=启动 iOS 应用
|
||||
androidUsers=启动 Android 应用
|
||||
alternativelyVisitThisLink=如果在已安装该应用的设备中读取邮件,只需点击以下链接即可启动:
|
||||
buoyTender=浮标供应船
|
||||
appStoreInstallText=如果尚无该应用,请安装:
|
||||
appStoreInstallText=如果您尚无该应用,请安装:
|
||||
appIos=安装 iOS 应用
|
||||
appAndroid=安装 Android 应用
|
||||
buoyPingerAppName=SAP Sailing Buoy Pinger
|
||||
|
||||
+4
-4
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file datatype="javapropertyresourcebundle" original="/usr/sap/ljs/app/Converter_2566045106627533633/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en">
|
||||
<file datatype="javapropertyresourcebundle" original="/usr/sap/ljs/app/Converter_7335190261158680380/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en">
|
||||
<header>
|
||||
<skl>
|
||||
<internal-file crc="cdbdcb19e10086d34f715e2a7da26eef" form="base64">H4sIAAAAAAAAAF2RTU/DMAyG7/0VvnGZEGekHgYSUiVgY+3gnLXeajWNo9jbqBD/naQtbOLm+PXH+zgaTN2ROxTuRGqU2D1xyKs5C5c07DlkUhv3tnnkBlfhnYR0G2zFGzyQKIal5C+mQ5BjQBj4CK05IWiL8HX3DUvvgZyosRabW6hadJDmjQV7tpbPaeM0HjhAbanuRtWS6+AoSY5jA0hvgvqWXZzOEOb1YCQ7o625x4rzjymKBRmtyq1gkLzU2AfxmcxkxjWBqbmWllNqkm2c6SL7Ce0wwlYtyXO0khf7Ec9EzICmSb40atAbssATUYMnqhHOpO34TvjGpvLhcoYFCPXeDjPrDuMREpIkN/fZ7shDha7BkKcQdIwz432pHLCYxlT4qclSw+5GLzdPCwfUBXiLRvB36X1qL1jyuftyDu9n/D/p+hzJwDqSxm/2/tX0mJfLNZSROOE/JHuTnEnMFa6kQ6v/S2HOZz95rIJYdwIAAA==</internal-file>
|
||||
<internal-file crc="064477f4b22ea4cc8cbdaab36795b9a4" form="base64">H4sIAAAAAAAAAF1RQU7DQAy85xW+cakQ50o5FCSkSEBLk8J5m7iN1c16tXZbIsTf2U1SWnHzzjjjmYkGUx/I7Qt3IjVK7J455NWEwhWGHYdMauPe10/c4DJ8kJBugq14jXsSxbCQ/NUcEOQYEHo+QmtOCNoifD/8wMJ7ICdqrMXmHqoWHSS9YWHH1vI5XRzlgQPUlurDwFpyBzhKoqNsAOlMUN+yi+oMYToPRrIz2po7rDj/HKe4kNGy3AgGyUuN30F8JjOZcU1gam6pxQiNtI2aLmY/oe2HsFVL8hKt5MVuiGdizICmSb40ctAZssBjogZPVCOcSdvhneIbm9b7aw0zEOq87aesW4wlpEiS3Myz7ZH7Cl2DIU8j6DBnxvtSOWAxylT4pRdLDbs7vfaejvaoM/AWjeDl8DxJFCz5pHCtxPupgj/qtpJkYhXTxl/t/ZvpMC8XKyhj6lTBY7I40plErHAl7Vv9vwoTnv0Cs+RzW3sCAAA=</internal-file>
|
||||
</skl>
|
||||
<phase-group>
|
||||
<phase company-name="SAP AG" date="2016-11-04T21:01:36Z" phase-name="file-creation" process-name="file-creation" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter"/>
|
||||
<phase company-name="SAP AG" date="2016-12-16T08:45:26Z" phase-name="file-creation" process-name="file-creation" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter"/>
|
||||
</phase-group>
|
||||
<tool tool-company="SAP AG" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter" tool-name="TEW: Javascript .properties Flexible File Converter" tool-version="1.1.0"/>
|
||||
</header>
|
||||
@@ -33,7 +33,7 @@
|
||||
<source>buoy tender</source>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="appStoreInstallText" resname="appStoreInstallText">
|
||||
<source>If don't have the App yet, please install:</source>
|
||||
<source>If you don't have the App yet, please install:</source>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="appIos" resname="appIos">
|
||||
<source>Install iOS App</source>
|
||||
|
||||
+6
-6
@@ -1,12 +1,12 @@
|
||||
<?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-11-23T14:56:08Z" original="/usr/sap/ljs/app/Converter_2566045106627533633/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en" target-language="ja">
|
||||
<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">
|
||||
<header>
|
||||
<skl>
|
||||
<internal-file crc="cdbdcb19e10086d34f715e2a7da26eef" form="base64">H4sIAAAAAAAAAF2RTU/DMAyG7/0VvnGZEGekHgYSUiVgY+3gnLXeajWNo9jbqBD/naQtbOLm+PXH+zgaTN2ROxTuRGqU2D1xyKs5C5c07DlkUhv3tnnkBlfhnYR0G2zFGzyQKIal5C+mQ5BjQBj4CK05IWiL8HX3DUvvgZyosRabW6hadJDmjQV7tpbPaeM0HjhAbanuRtWS6+AoSY5jA0hvgvqWXZzOEOb1YCQ7o625x4rzjymKBRmtyq1gkLzU2AfxmcxkxjWBqbmWllNqkm2c6SL7Ce0wwlYtyXO0khf7Ec9EzICmSb40atAbssATUYMnqhHOpO34TvjGpvLhcoYFCPXeDjPrDuMREpIkN/fZ7shDha7BkKcQdIwz432pHLCYxlT4qclSw+5GLzdPCwfUBXiLRvB36X1qL1jyuftyDu9n/D/p+hzJwDqSxm/2/tX0mJfLNZSROOE/JHuTnEnMFa6kQ6v/S2HOZz95rIJYdwIAAA==</internal-file>
|
||||
<internal-file crc="064477f4b22ea4cc8cbdaab36795b9a4" form="base64">H4sIAAAAAAAAAF1RQU7DQAy85xW+cakQ50o5FCSkSEBLk8J5m7iN1c16tXZbIsTf2U1SWnHzzjjjmYkGUx/I7Qt3IjVK7J455NWEwhWGHYdMauPe10/c4DJ8kJBugq14jXsSxbCQ/NUcEOQYEHo+QmtOCNoifD/8wMJ7ICdqrMXmHqoWHSS9YWHH1vI5XRzlgQPUlurDwFpyBzhKoqNsAOlMUN+yi+oMYToPRrIz2po7rDj/HKe4kNGy3AgGyUuN30F8JjOZcU1gam6pxQiNtI2aLmY/oe2HsFVL8hKt5MVuiGdizICmSb40ctAZssBjogZPVCOcSdvhneIbm9b7aw0zEOq87aesW4wlpEiS3Myz7ZH7Cl2DIU8j6DBnxvtSOWAxylT4pRdLDbs7vfaejvaoM/AWjeDl8DxJFCz5pHCtxPupgj/qtpJkYhXTxl/t/ZvpMC8XKyhj6lTBY7I40plErHAl7Vv9vwoTnv0Cs+RzW3sCAAA=</internal-file>
|
||||
</skl>
|
||||
<phase-group>
|
||||
<phase company-name="SAP AG" date="2016-11-04T21:01:36Z" phase-name="file-creation" process-name="file-creation" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter"/>
|
||||
<phase company-name="SAP AG" date="2016-12-16T08:45:26Z" phase-name="file-creation" process-name="file-creation" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter"/>
|
||||
</phase-group>
|
||||
<tool tool-company="SAP AG" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter" tool-name="TEW: Javascript .properties Flexible File Converter" tool-version="1.1.0"/>
|
||||
</header>
|
||||
@@ -17,7 +17,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="scanQRCodeOrVisitUrlToRegisterAs" resname="scanQRCodeOrVisitUrlToRegisterAs">
|
||||
<source>Make sure you have the <ph id="1">{0}</ph> App installed. Then scan the following QRCode or click the link using your smartphone to register as</source>
|
||||
<target state="translated"><ph id="1">{0}</ph> アプリがインストールされていることを確認してください。その上で、以下の QR コードをスキャンするか、スマートフォンを使用してリンクをクリックして登録します:</target>
|
||||
<target state="signed-off"><ph id="1">{0}</ph> アプリがインストールされていることを確認してください。その上で、以下の QR コードをスキャンするか、スマートフォンを使用してリンクをクリックして登録します:</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="welcomeTo" resname="welcomeTo">
|
||||
<source>Welcome to</source>
|
||||
@@ -40,8 +40,8 @@
|
||||
<target state="signed-off">設標船</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="appStoreInstallText" resname="appStoreInstallText">
|
||||
<source>If don't have the App yet, please install:</source>
|
||||
<target state="signed-off">まだアプリがない場合は、インストールしてください:</target>
|
||||
<source>If you don't have the App yet, please install:</source>
|
||||
<target state="translated">まだアプリがない場合は、インストールしてください:</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="appIos" resname="appIos">
|
||||
<source>Install iOS App</source>
|
||||
|
||||
+5
-5
@@ -1,12 +1,12 @@
|
||||
<?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-11-23T14:56:08Z" original="/usr/sap/ljs/app/Converter_2566045106627533633/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en" target-language="ru">
|
||||
<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">
|
||||
<header>
|
||||
<skl>
|
||||
<internal-file crc="cdbdcb19e10086d34f715e2a7da26eef" form="base64">H4sIAAAAAAAAAF2RTU/DMAyG7/0VvnGZEGekHgYSUiVgY+3gnLXeajWNo9jbqBD/naQtbOLm+PXH+zgaTN2ROxTuRGqU2D1xyKs5C5c07DlkUhv3tnnkBlfhnYR0G2zFGzyQKIal5C+mQ5BjQBj4CK05IWiL8HX3DUvvgZyosRabW6hadJDmjQV7tpbPaeM0HjhAbanuRtWS6+AoSY5jA0hvgvqWXZzOEOb1YCQ7o625x4rzjymKBRmtyq1gkLzU2AfxmcxkxjWBqbmWllNqkm2c6SL7Ce0wwlYtyXO0khf7Ec9EzICmSb40atAbssATUYMnqhHOpO34TvjGpvLhcoYFCPXeDjPrDuMREpIkN/fZ7shDha7BkKcQdIwz432pHLCYxlT4qclSw+5GLzdPCwfUBXiLRvB36X1qL1jyuftyDu9n/D/p+hzJwDqSxm/2/tX0mJfLNZSROOE/JHuTnEnMFa6kQ6v/S2HOZz95rIJYdwIAAA==</internal-file>
|
||||
<internal-file crc="064477f4b22ea4cc8cbdaab36795b9a4" form="base64">H4sIAAAAAAAAAF1RQU7DQAy85xW+cakQ50o5FCSkSEBLk8J5m7iN1c16tXZbIsTf2U1SWnHzzjjjmYkGUx/I7Qt3IjVK7J455NWEwhWGHYdMauPe10/c4DJ8kJBugq14jXsSxbCQ/NUcEOQYEHo+QmtOCNoifD/8wMJ7ICdqrMXmHqoWHSS9YWHH1vI5XRzlgQPUlurDwFpyBzhKoqNsAOlMUN+yi+oMYToPRrIz2po7rDj/HKe4kNGy3AgGyUuN30F8JjOZcU1gam6pxQiNtI2aLmY/oe2HsFVL8hKt5MVuiGdizICmSb40ctAZssBjogZPVCOcSdvhneIbm9b7aw0zEOq87aesW4wlpEiS3Myz7ZH7Cl2DIU8j6DBnxvtSOWAxylT4pRdLDbs7vfaejvaoM/AWjeDl8DxJFCz5pHCtxPupgj/qtpJkYhXTxl/t/ZvpMC8XKyhj6lTBY7I40plErHAl7Vv9vwoTnv0Cs+RzW3sCAAA=</internal-file>
|
||||
</skl>
|
||||
<phase-group>
|
||||
<phase company-name="SAP AG" date="2016-11-04T21:01:36Z" phase-name="file-creation" process-name="file-creation" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter"/>
|
||||
<phase company-name="SAP AG" date="2016-12-16T08:45:26Z" phase-name="file-creation" process-name="file-creation" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter"/>
|
||||
</phase-group>
|
||||
<tool tool-company="SAP AG" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter" tool-name="TEW: Javascript .properties Flexible File Converter" tool-version="1.1.0"/>
|
||||
</header>
|
||||
@@ -40,8 +40,8 @@
|
||||
<target state="signed-off">лоцмейстерское судно</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="appStoreInstallText" resname="appStoreInstallText">
|
||||
<source>If don't have the App yet, please install:</source>
|
||||
<target state="signed-off">Если у вас еще нет приложения, установите его:</target>
|
||||
<source>If you don't have the App yet, please install:</source>
|
||||
<target state="translated">Если у вас еще нет приложения, установите его:</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="appIos" resname="appIos">
|
||||
<source>Install iOS App</source>
|
||||
|
||||
+16
-16
@@ -1,63 +1,63 @@
|
||||
<?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-11-23T14:56:08Z" original="/usr/sap/ljs/app/Converter_2566045106627533633/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages.properties" source-language="en" target-language="zh-CN">
|
||||
<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">
|
||||
<header>
|
||||
<skl>
|
||||
<internal-file crc="cdbdcb19e10086d34f715e2a7da26eef" form="base64">H4sIAAAAAAAAAF2RTU/DMAyG7/0VvnGZEGekHgYSUiVgY+3gnLXeajWNo9jbqBD/naQtbOLm+PXH+zgaTN2ROxTuRGqU2D1xyKs5C5c07DlkUhv3tnnkBlfhnYR0G2zFGzyQKIal5C+mQ5BjQBj4CK05IWiL8HX3DUvvgZyosRabW6hadJDmjQV7tpbPaeM0HjhAbanuRtWS6+AoSY5jA0hvgvqWXZzOEOb1YCQ7o625x4rzjymKBRmtyq1gkLzU2AfxmcxkxjWBqbmWllNqkm2c6SL7Ce0wwlYtyXO0khf7Ec9EzICmSb40atAbssATUYMnqhHOpO34TvjGpvLhcoYFCPXeDjPrDuMREpIkN/fZ7shDha7BkKcQdIwz432pHLCYxlT4qclSw+5GLzdPCwfUBXiLRvB36X1qL1jyuftyDu9n/D/p+hzJwDqSxm/2/tX0mJfLNZSROOE/JHuTnEnMFa6kQ6v/S2HOZz95rIJYdwIAAA==</internal-file>
|
||||
<internal-file crc="064477f4b22ea4cc8cbdaab36795b9a4" form="base64">H4sIAAAAAAAAAF1RQU7DQAy85xW+cakQ50o5FCSkSEBLk8J5m7iN1c16tXZbIsTf2U1SWnHzzjjjmYkGUx/I7Qt3IjVK7J455NWEwhWGHYdMauPe10/c4DJ8kJBugq14jXsSxbCQ/NUcEOQYEHo+QmtOCNoifD/8wMJ7ICdqrMXmHqoWHSS9YWHH1vI5XRzlgQPUlurDwFpyBzhKoqNsAOlMUN+yi+oMYToPRrIz2po7rDj/HKe4kNGy3AgGyUuN30F8JjOZcU1gam6pxQiNtI2aLmY/oe2HsFVL8hKt5MVuiGdizICmSb40ctAZssBjogZPVCOcSdvhneIbm9b7aw0zEOq87aesW4wlpEiS3Myz7ZH7Cl2DIU8j6DBnxvtSOWAxylT4pRdLDbs7vfaejvaoM/AWjeDl8DxJFCz5pHCtxPupgj/qtpJkYhXTxl/t/ZvpMC8XKyhj6lTBY7I40plErHAl7Vv9vwoTnv0Cs+RzW3sCAAA=</internal-file>
|
||||
</skl>
|
||||
<phase-group>
|
||||
<phase company-name="SAP AG" date="2016-11-04T21:01:36Z" phase-name="file-creation" process-name="file-creation" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter"/>
|
||||
<phase company-name="SAP AG" date="2016-12-16T08:45:26Z" phase-name="file-creation" process-name="file-creation" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter"/>
|
||||
</phase-group>
|
||||
<tool tool-company="SAP AG" tool-id="urn:x-sap:sls-mlt:java:properties-flexible-converter" tool-name="TEW: Javascript .properties Flexible File Converter" tool-version="1.1.0"/>
|
||||
</header>
|
||||
<body>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="trackingInvitationFor" resname="trackingInvitationFor">
|
||||
<source>Tracking Invitation for</source>
|
||||
<target>跟踪邀请 - </target>
|
||||
<target state="signed-off">跟踪邀请 - </target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="scanQRCodeOrVisitUrlToRegisterAs" resname="scanQRCodeOrVisitUrlToRegisterAs">
|
||||
<source>Make sure you have the <ph id="1">{0}</ph> App installed. Then scan the following QRCode or click the link using your smartphone to register as</source>
|
||||
<target>确保已安装 <ph id="1">{0}</ph> 应用。然后,使用智能手机扫描以下二维码或点击链接注册</target>
|
||||
<target state="signed-off">确保已安装 <ph id="1">{0}</ph> 应用。然后,使用智能手机扫描以下二维码或点击链接注册</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="welcomeTo" resname="welcomeTo">
|
||||
<source>Welcome to</source>
|
||||
<target>欢迎使用</target>
|
||||
<target state="signed-off">欢迎使用</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="iOSUsers" resname="iOSUsers">
|
||||
<source>Start iOS App</source>
|
||||
<target>启动 iOS 应用</target>
|
||||
<target state="signed-off">启动 iOS 应用</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="androidUsers" resname="androidUsers">
|
||||
<source>Start Android App</source>
|
||||
<target>启动 Android 应用</target>
|
||||
<target state="signed-off">启动 Android 应用</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="alternativelyVisitThisLink" resname="alternativelyVisitThisLink">
|
||||
<source>If you are reading this mail on the device with the App already installed, simply click below to start:</source>
|
||||
<target>如果在已安装该应用的设备中读取邮件,只需点击以下链接即可启动:</target>
|
||||
<target state="signed-off">如果在已安装该应用的设备中读取邮件,只需点击以下链接即可启动:</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="buoyTender" resname="buoyTender">
|
||||
<source>buoy tender</source>
|
||||
<target>浮标供应船</target>
|
||||
<target state="signed-off">浮标供应船</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="appStoreInstallText" resname="appStoreInstallText">
|
||||
<source>If don't have the App yet, please install:</source>
|
||||
<target>如果尚无该应用,请安装:</target>
|
||||
<source>If you don't have the App yet, please install:</source>
|
||||
<target state="translated">如果您尚无该应用,请安装:</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="appIos" resname="appIos">
|
||||
<source>Install iOS App</source>
|
||||
<target>安装 iOS 应用</target>
|
||||
<target state="signed-off">安装 iOS 应用</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="appAndroid" resname="appAndroid">
|
||||
<source>Install Android App</source>
|
||||
<target>安装 Android 应用</target>
|
||||
<target state="signed-off">安装 Android 应用</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="buoyPingerAppName" resname="buoyPingerAppName">
|
||||
<source>SAP Sailing Buoy Pinger</source>
|
||||
<target>SAP Sailing Buoy Pinger</target>
|
||||
<target state="signed-off">SAP Sailing Buoy Pinger</target>
|
||||
</trans-unit>
|
||||
<trans-unit datatype="x-urn:x-sap:sls-mlt:java:flexible-converter:messageformat" id="sailInSightAppName" resname="sailInSightAppName">
|
||||
<source>SAP Sail InSight</source>
|
||||
<target>SAP Sail InSight</target>
|
||||
<target state="signed-off">SAP Sail InSight</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
||||
+3
-1
@@ -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);
|
||||
|
||||
+9
-1
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
+16
-5
@@ -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
|
||||
|
||||
+71
@@ -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;
|
||||
}
|
||||
}
|
||||
+8
-7
@@ -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) {
|
||||
|
||||
+3
-10
@@ -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
|
||||
|
||||
+7
-7
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+123
-24
@@ -135,13 +135,56 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
|
||||
final DynamicGPSFixTrack<Mark, GPSFix> markTrack = trackedRace.getOrCreateTrack(mark);
|
||||
final GPSFix firstFixAtOrAfter;
|
||||
final boolean forceFix;
|
||||
markTrack.lockForRead();
|
||||
try {
|
||||
forceFix = Util.isEmpty(markTrack.getRawFixes())
|
||||
|| (firstFixAtOrAfter = markTrack.getFirstFixAtOrAfter(timePoint)) != null
|
||||
&& firstFixAtOrAfter.getTimePoint().equals(timePoint);
|
||||
} finally {
|
||||
markTrack.unlockAfterRead();
|
||||
if (trackedRace.isWithinStartAndEndOfTracking(fix.getTimePoint())) {
|
||||
forceFix = false;
|
||||
} else {
|
||||
markTrack.lockForRead();
|
||||
try {
|
||||
if (Util.isEmpty(markTrack.getRawFixes())
|
||||
|| (firstFixAtOrAfter = markTrack.getFirstFixAtOrAfter(timePoint)) != null
|
||||
&& firstFixAtOrAfter.getTimePoint().equals(timePoint)) {
|
||||
// either the first fix or overwriting an existing one
|
||||
forceFix = true;
|
||||
} else {
|
||||
// checking if the given fix is "better" than an existing one
|
||||
TimePoint startOfTracking = trackedRace.getStartOfTracking();
|
||||
TimePoint endOfTracking = trackedRace.getStartOfTracking();
|
||||
if (startOfTracking != null) {
|
||||
GPSFix fixAfterStartOfTracking = markTrack
|
||||
.getFirstFixAtOrAfter(startOfTracking);
|
||||
if (fixAfterStartOfTracking == null
|
||||
|| !trackedRace.isWithinStartAndEndOfTracking(
|
||||
fixAfterStartOfTracking.getTimePoint())) {
|
||||
// There is no fix in the tracking interval, so this fix could be "better"
|
||||
// than ones already available in the track
|
||||
// Better means closer before/after the beginning/end of the tracking
|
||||
// interval
|
||||
if (timePoint.before(startOfTracking)) {
|
||||
// check if it is closer to the beginning of the tracking interval
|
||||
GPSFix fixBeforeStartOfTracking = markTrack
|
||||
.getLastFixAtOrBefore(startOfTracking);
|
||||
forceFix = (fixBeforeStartOfTracking == null
|
||||
|| fixBeforeStartOfTracking.getTimePoint().before(timePoint));
|
||||
} else if (endOfTracking != null && timePoint.after(endOfTracking)) {
|
||||
// check if it is closer to the end of the tracking interval
|
||||
GPSFix fixAfterEndOfTracking = markTrack
|
||||
.getFirstFixAtOrAfter(endOfTracking);
|
||||
forceFix = (fixAfterEndOfTracking == null
|
||||
|| fixAfterEndOfTracking.getTimePoint().after(timePoint));
|
||||
} else {
|
||||
forceFix = false;
|
||||
}
|
||||
} else {
|
||||
// there is already a fix in the tracking interval
|
||||
forceFix = false;
|
||||
}
|
||||
} else {
|
||||
forceFix = false;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
markTrack.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
trackedRace.recordFix(mark, (GPSFix) fix, /* only when in tracking interval */ !forceFix);
|
||||
}
|
||||
@@ -160,6 +203,57 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
|
||||
startTracking();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loading fixes for {@link Mark}s needs special handling compared with {@link Competitor}s. If there are no fixes
|
||||
* available in the tracking interval, it is necessary to load other available fixes before/after the tracking
|
||||
* interval. this is due to the buoy pinger app can be used in the morning to ping some marks. The resulting fixes
|
||||
* need to also be available for races later on the day. This method ensures that if available, fixes are initially
|
||||
* loaded when starting tracking. In contrast to that, mappings for {@link Competitor}s have no special handling.
|
||||
*
|
||||
* @param mappings
|
||||
* the added mappings
|
||||
* @param item
|
||||
* the item the mappings belong to
|
||||
*/
|
||||
private void loadFixesForNewMappings(Iterable<DeviceMappingWithRegattaLogEvent<WithID>> mappings, WithID item) {
|
||||
TimeRange trackingTimeRange = getTrackingTimeRange();
|
||||
if (item instanceof Mark) {
|
||||
Mark mark = (Mark) item;
|
||||
if (containsMappingThatIntersectsTimeRange(mappings, trackingTimeRange)) {
|
||||
loadFixesInTimeRange(mappings, trackingTimeRange);
|
||||
}
|
||||
DynamicGPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
|
||||
// load all mapped fixes if there was no fix in the tracking TimeRange
|
||||
final boolean loadAllMappedFixes = (track.getFirstRawFix() == null);
|
||||
if (loadAllMappedFixes) {
|
||||
// either got an empty track of there is no mapping for the TimeRange of the race at all.
|
||||
// try again without constraining the mapping interval by start/end of tracking to at
|
||||
// least attempt to get fixes at all in case there were any within the device mapping interval specified
|
||||
mappings.forEach(mapping -> loadFixes(mapping.getTimeRange(), mapping));
|
||||
}
|
||||
} else {
|
||||
loadFixesInTimeRange(mappings, trackingTimeRange);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadFixesInTimeRange(Iterable<DeviceMappingWithRegattaLogEvent<WithID>> mappings, TimeRange trackingTimeRange) {
|
||||
mappings.forEach(mapping -> loadFixes(trackingTimeRange.intersection(mapping.getTimeRange()), mapping));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given callback for every known mapping of the given item.
|
||||
*
|
||||
* @param callback the callback to call for every known mapping
|
||||
*/
|
||||
public boolean containsMappingThatIntersectsTimeRange(Iterable<DeviceMappingWithRegattaLogEvent<WithID>> mappings, TimeRange timeRange) {
|
||||
for (DeviceMappingWithRegattaLogEvent<WithID> mapping : mappings) {
|
||||
if(timeRange.intersects(mapping.getTimeRange())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void loadFixes(TimeRange timeRangeToLoad, DeviceMappingWithRegattaLogEvent<? extends WithID> mapping) {
|
||||
if(timeRangeToLoad == null) {
|
||||
return;
|
||||
@@ -212,15 +306,6 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
|
||||
@SuppressWarnings("unchecked")
|
||||
DeviceMapping<Mark> markMapping = (DeviceMapping<Mark>) mapping;
|
||||
gpsFixStore.loadMarkTrack(track, markMapping, timeRangeToLoad.from(), timeRangeToLoad.to());
|
||||
if (track.getFirstRawFix() == null) {
|
||||
logger.fine("Loading mark positions from outside of start/end of tracking interval (" + timeRangeToLoad.from()
|
||||
+ ".." + timeRangeToLoad.to() + ") because no fixes were found in that interval");
|
||||
// got an empty track for the mark; try again without constraining the mapping interval
|
||||
// by start/end of tracking to at least attempt to get fixes at all in case there were any
|
||||
// within the device mapping interval specified
|
||||
gpsFixStore.loadMarkTrack(track, markMapping, /* startOfTimeWindowToLoad */ null,
|
||||
/* endOfTimeWindowToLoad */ null);
|
||||
}
|
||||
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
|
||||
logger.log(Level.WARNING, "Could not load mark track " + mapping.getMappedTo());
|
||||
}
|
||||
@@ -355,26 +440,40 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mappingAdded(DeviceMappingWithRegattaLogEvent<WithID> mapping) {
|
||||
// The listener is first added to not lose any fix after loading the initial fixes and adding the listener.
|
||||
sensorFixStore.addListener(listener, mapping.getDevice());
|
||||
loadFixes(getTrackingTimeRange().intersection(mapping.getTimeRange()), mapping);
|
||||
protected void mappingsAdded(Iterable<DeviceMappingWithRegattaLogEvent<WithID>> mappings, WithID item) {
|
||||
// The listener is first added. This causes that no fix is lost but potentially fixes are being processes twice.
|
||||
// There are the following cases:
|
||||
// 1. A fix is added before the mapping update started
|
||||
// -> the fix is dropped but during mapping update the whole mapping is being loaded including this fix.
|
||||
// 2. A fix is added while the write lock is being held for the mappings
|
||||
// -> The fix will be processed after the write lock is removed. In this state
|
||||
// the mappings are up-to-date and in a consequence the fix is loaded into the track.
|
||||
// In addition, the fix is loaded on mapping update, but both fix instances consistently have the same state.
|
||||
// 3. A fix is added after a successful mapping update
|
||||
// -> The fix is only added once, because the initial loading during mapping update is finished
|
||||
mappings.forEach(mapping -> sensorFixStore.addListener(listener, mapping.getDevice()));
|
||||
loadFixesForNewMappings(mappings, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link #loadFixes loads fixes} that are captured by {@code newMapping} but not by {@code oldMapping}. This
|
||||
* may require up to two {@link #loadFixes} calls: one for the fixes after and one for the fixes before the old
|
||||
* mapping.
|
||||
*/
|
||||
@Override
|
||||
protected void mappingChanged(DeviceMappingWithRegattaLogEvent<WithID> oldMapping,
|
||||
DeviceMappingWithRegattaLogEvent<WithID> newMapping) {
|
||||
final TimeRange newTimeRange = newMapping.getTimeRange();
|
||||
final TimeRange oldTimeRange = oldMapping.getTimeRange();
|
||||
if(newTimeRange.endsAfter(oldTimeRange)) {
|
||||
final TimePoint oldTo= oldTimeRange.to();
|
||||
if (newTimeRange.endsAfter(oldTimeRange)) {
|
||||
final TimePoint oldTo = oldTimeRange.to();
|
||||
final TimePoint newFrom = newTimeRange.from();
|
||||
final TimePoint from = oldTo.after(newFrom) ? oldTo : newFrom;
|
||||
final TimeRange rangeToLoad = new TimeRangeImpl(from, newTimeRange.to());
|
||||
loadFixes(rangeToLoad, newMapping);
|
||||
}
|
||||
if(newTimeRange.startsBefore(oldTimeRange)) {
|
||||
final TimePoint oldFrom= oldTimeRange.from();
|
||||
if (newTimeRange.startsBefore(oldTimeRange)) {
|
||||
final TimePoint oldFrom = oldTimeRange.from();
|
||||
final TimePoint newTo = newTimeRange.to();
|
||||
final TimePoint to = oldFrom.after(newTo) ? oldFrom : newTo;
|
||||
final TimeRange rangeToLoad = new TimeRangeImpl(newTimeRange.from(), to);
|
||||
|
||||
+2
-1
@@ -120,7 +120,8 @@ public class RaceLogFixTrackerManager implements TrackingDataLoader {
|
||||
stopTrackerIfStillRunning(preemptive);
|
||||
trackedRace.removeListener(raceChangeListener);
|
||||
synchronized (knownRaceLogs) {
|
||||
for (RaceLog raceLog : knownRaceLogs) {
|
||||
final Set<RaceLog> tempSet = new HashSet<>(knownRaceLogs);
|
||||
for (RaceLog raceLog : tempSet) {
|
||||
removeRaceLogUnlocked(raceLog);
|
||||
}
|
||||
}
|
||||
|
||||
+27
-19
@@ -242,7 +242,6 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
|
||||
LockUtil.lockForWrite(mappingsLock);
|
||||
try {
|
||||
oldMappings.putAll(mappings);
|
||||
|
||||
mappings.clear();
|
||||
mappings.putAll(newMappings);
|
||||
mappingsByDevice.clear();
|
||||
@@ -266,26 +265,27 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
|
||||
* Calculates <em>and applies</em> the mapping changes by removing listeners no longer needed for the mappings removed,
|
||||
* and by loading and adding the fixes for extended or added mappings.
|
||||
*/
|
||||
private void calculateDiff(Map<ItemT, List<DeviceMappingWithRegattaLogEvent<ItemT>>> previousMappings,
|
||||
Map<ItemT, List<DeviceMappingWithRegattaLogEvent<ItemT>>> newMappings) {
|
||||
private void calculateDiff(Map<ItemT, ? extends Iterable<DeviceMappingWithRegattaLogEvent<ItemT>>> previousMappings,
|
||||
Map<ItemT, ? extends Iterable<DeviceMappingWithRegattaLogEvent<ItemT>>> newMappings) {
|
||||
Set<ItemT> itemsToProcess = new HashSet<ItemT>(previousMappings.keySet());
|
||||
itemsToProcess.addAll(newMappings.keySet());
|
||||
for (ItemT item : itemsToProcess) {
|
||||
if (!newMappings.containsKey(item)) {
|
||||
previousMappings.get(item).forEach(this::mappingRemovedInternal);
|
||||
} else {
|
||||
final List<DeviceMappingWithRegattaLogEvent<ItemT>> oldMappings = previousMappings.containsKey(item)
|
||||
final Iterable<DeviceMappingWithRegattaLogEvent<ItemT>> oldMappings = previousMappings.containsKey(item)
|
||||
? previousMappings.get(item) : Collections.emptyList();
|
||||
|
||||
final List<DeviceMappingWithRegattaLogEvent<ItemT>> addedMappings = new ArrayList<>();
|
||||
for (DeviceMappingWithRegattaLogEvent<ItemT> newMapping : newMappings.get(item)) {
|
||||
DeviceMappingWithRegattaLogEvent<ItemT> oldMapping = findAndRemoveMapping(newMapping,
|
||||
oldMappings);
|
||||
DeviceMappingWithRegattaLogEvent<ItemT> oldMapping = findAndRemoveMapping(newMapping, oldMappings);
|
||||
if (oldMapping == null) {
|
||||
mappingAddedInternal(newMapping);
|
||||
addedMappings.add(newMapping);
|
||||
} else if (!newMapping.getTimeRange().equals(oldMapping.getTimeRange())) {
|
||||
mappingChangedInternal(oldMapping, newMapping);
|
||||
}
|
||||
}
|
||||
mappingsAddedInternal(addedMappings, item);
|
||||
// oldMappings now still contains those mappings that were not entirely substituted by the new mappings
|
||||
oldMappings.forEach(this::mappingRemovedInternal);
|
||||
}
|
||||
}
|
||||
@@ -309,21 +309,24 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
|
||||
/**
|
||||
* Called when a {@link DeviceMapping} was added.
|
||||
*
|
||||
* @param mapping the new mapping
|
||||
* @param mappings the new mapping
|
||||
*/
|
||||
protected abstract void mappingAdded(DeviceMappingWithRegattaLogEvent<ItemT> mapping);
|
||||
protected abstract void mappingsAdded(Iterable<DeviceMappingWithRegattaLogEvent<ItemT>> mappings, ItemT item);
|
||||
|
||||
private void mappingAddedInternal(DeviceMappingWithRegattaLogEvent<ItemT> mapping) {
|
||||
private void mappingsAddedInternal(Iterable<DeviceMappingWithRegattaLogEvent<ItemT>> mappings, ItemT item) {
|
||||
try {
|
||||
mappingAdded(mapping);
|
||||
mappingsAdded(mappings, item);
|
||||
} catch(Exception e) {
|
||||
logger.log(Level.SEVERE, "error while adding mapping " + mapping, e);
|
||||
logger.log(Level.SEVERE, "error while adding mapping " + mappings, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a {@link DeviceMapping} was changed regarding its mapped time range.
|
||||
* This can occur if an open ended mapping is being closed or a close event gets revoked.
|
||||
* This can occur if an open ended mapping is being closed or a close event gets revoked
|
||||
* or a new mapping is added that may partly overlap with an old mapping such that only
|
||||
* parts of the fixes covered by the new mapping need to be loaded (the ones not already
|
||||
* covered by the old mapping).
|
||||
*
|
||||
* @param oldMapping the old mapping
|
||||
* @param newMapping the new mapping
|
||||
@@ -342,11 +345,10 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
|
||||
|
||||
private DeviceMappingWithRegattaLogEvent<ItemT> findAndRemoveMapping(
|
||||
DeviceMappingWithRegattaLogEvent<ItemT> mappingToFind,
|
||||
List<DeviceMappingWithRegattaLogEvent<ItemT>> newItemsToProcess) {
|
||||
for (Iterator<DeviceMappingWithRegattaLogEvent<ItemT>> iterator = newItemsToProcess.iterator(); iterator
|
||||
.hasNext();) {
|
||||
Iterable<DeviceMappingWithRegattaLogEvent<ItemT>> newItemsToProcess) {
|
||||
for (Iterator<DeviceMappingWithRegattaLogEvent<ItemT>> iterator = newItemsToProcess.iterator(); iterator.hasNext();) {
|
||||
DeviceMappingWithRegattaLogEvent<ItemT> deviceMapping = iterator.next();
|
||||
if(isSame(mappingToFind, deviceMapping)) {
|
||||
if (isSame(mappingToFind, deviceMapping)) {
|
||||
iterator.remove();
|
||||
return deviceMapping;
|
||||
}
|
||||
@@ -354,9 +356,15 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two device mappings based on their device, the item mapped to and the race/regatta log event type
|
||||
* that usually corresponds with the type of item to which the device is mapped. Note that in particular the
|
||||
* mappings' time ranges are ignored for this comparison.
|
||||
*/
|
||||
private boolean isSame(DeviceMappingWithRegattaLogEvent<ItemT> mapping1,
|
||||
DeviceMappingWithRegattaLogEvent<ItemT> mapping2) {
|
||||
return mapping1.getDevice().equals(mapping2.getDevice()) && mapping1.getMappedTo().equals(mapping2.getMappedTo())
|
||||
&& mapping1.getEventType().equals(mapping2.getEventType());
|
||||
&& mapping1.getEventType().equals(mapping2.getEventType())
|
||||
&& mapping1.getRegattaLogEvent().getId().equals(mapping2.getRegattaLogEvent().getId());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+2
@@ -68,6 +68,8 @@ public interface CompetitorStore extends CompetitorFactory {
|
||||
String newSailId, Nationality newNationality, URI newTeamImageUri, URI newFlagImageUri,
|
||||
Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag);
|
||||
|
||||
void addCompetitors(Iterable<Competitor> competitors);
|
||||
|
||||
CompetitorDTO convertToCompetitorDTO(Competitor c);
|
||||
|
||||
/**
|
||||
|
||||
+2
@@ -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);
|
||||
}
|
||||
|
||||
+3
-1
@@ -48,7 +48,9 @@ public class BoatClassImpl extends NamedImpl implements BoatClass {
|
||||
|
||||
public BoatClassImpl(String name, boolean typicallyStartsUpwind) {
|
||||
this(name, typicallyStartsUpwind, /* displayName */ null,
|
||||
/* hull length */ new MeterDistance(5), /* hullBeam */ null, /* hullType */ null);
|
||||
// use the typical dinghy parameters as default
|
||||
/* hull length */ new MeterDistance(5), /* hullBeam */ new MeterDistance(1.8),
|
||||
/* hullType */ BoatHullType.MONOHULL);
|
||||
}
|
||||
|
||||
public BoatClassImpl(String name, BoatClassMasterdata masterData) {
|
||||
|
||||
+11
-2
@@ -154,14 +154,23 @@ public class SharedDomainFactoryImpl implements SharedDomainFactory {
|
||||
return getOrCreateMark(name, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mark getOrCreateMark(String name, MarkType markType) {
|
||||
return getOrCreateMark(name, name, markType);
|
||||
}
|
||||
|
||||
private Mark getOrCreateMark(Serializable id, String name, MarkType markType) {
|
||||
return getOrCreateMark(id, name, markType, /* color */ null, /* shape */ null, /* pattern */ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mark getOrCreateMark(Serializable id, String name) {
|
||||
return getOrCreateMark(id, name, null, null, null, null);
|
||||
return getOrCreateMark(id, name, /* type */ null, /* color */ null, /* shape */ null, /* pattern */ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mark getOrCreateMark(String toStringRepresentationOfID, String name) {
|
||||
return getOrCreateMark(toStringRepresentationOfID, name, null, null, null, null);
|
||||
return getOrCreateMark(toStringRepresentationOfID, name, /* type */ null, /* color */ null, /* shape */ null, /* pattern */ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+15
-1
@@ -250,7 +250,8 @@ public class TransientCompetitorStoreImpl implements CompetitorStore, Serializab
|
||||
c.getFlagImage() == null ? null : c.getFlagImage().toString(),
|
||||
new BoatDTO(c.getBoat().getName(), c.getBoat().getSailID(), c.getBoat().getColor()),
|
||||
new BoatClassDTO(c.getBoat().getBoatClass()
|
||||
.getName(), c.getBoat().getBoatClass().getDisplayName(), c.getBoat().getBoatClass().getHullLength()),
|
||||
.getName(), c.getBoat().getBoatClass().getDisplayName(), c.getBoat().getBoatClass().getHullLength(),
|
||||
c.getBoat().getBoatClass().getHullBeam()),
|
||||
c.getTimeOnTimeFactor(), c.getTimeOnDistanceAllowancePerNauticalMile(), c.getSearchTag());
|
||||
weakCompetitorDTOCache.put(c, competitorDTO);
|
||||
}
|
||||
@@ -274,4 +275,17 @@ public class TransientCompetitorStoreImpl implements CompetitorStore, Serializab
|
||||
LockUtil.unlockAfterWrite(lock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCompetitors(Iterable<Competitor> competitors) {
|
||||
LockUtil.lockForWrite(lock);
|
||||
try {
|
||||
for (Competitor competitor: competitors) {
|
||||
competitorCache.put(competitor.getId(), competitor);
|
||||
competitorsByIdAsString.put(competitor.getId().toString(), competitor);
|
||||
}
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.base.racegroup;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.common.TargetTimeInfo;
|
||||
import com.sap.sse.common.Named;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
@@ -33,4 +34,11 @@ public interface RaceCell extends Named {
|
||||
* index 0.
|
||||
*/
|
||||
int getZeroBasedIndexInFleet();
|
||||
|
||||
/**
|
||||
* If there is a tracked race for this race and we have sufficient information about wind and the boat class's
|
||||
* polar / VPP data this method will return an estimated duration for how long the race will take based on the
|
||||
* current course.
|
||||
*/
|
||||
TargetTimeInfo getTargetTime();
|
||||
}
|
||||
|
||||
+11
-2
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.base.racegroup.impl;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.base.racegroup.RaceCell;
|
||||
import com.sap.sailing.domain.common.TargetTimeInfo;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.NamedImpl;
|
||||
|
||||
@@ -22,6 +23,8 @@ public class RaceCellImpl extends NamedImpl implements RaceCell {
|
||||
|
||||
private final int zeroBasedIndexInFleet;
|
||||
|
||||
private final TargetTimeInfo targetTime;
|
||||
|
||||
/**
|
||||
* @param zeroBasedIndexInFleet
|
||||
* A Series offers a sequence of RaceColumns, each of them split according to the Fleets modeled for the
|
||||
@@ -34,12 +37,13 @@ public class RaceCellImpl extends NamedImpl implements RaceCell {
|
||||
* except in case the first race column is a "virtual" one that holds a non-discardable carry-forward
|
||||
* result. In this case, the second Race Column, which is the first "non-virtual" one, receives index 0.
|
||||
*/
|
||||
public RaceCellImpl(String raceColumnName, RaceLog raceLog, double factor, Double explicitFactor, int zeroBasedIndexInFleet) {
|
||||
public RaceCellImpl(String raceColumnName, RaceLog raceLog, double factor, Double explicitFactor, int zeroBasedIndexInFleet, TargetTimeInfo targetTime) {
|
||||
super(raceColumnName);
|
||||
this.raceLog = raceLog;
|
||||
this.factor = factor;
|
||||
this.explicitFactor = explicitFactor;
|
||||
this.zeroBasedIndexInFleet = zeroBasedIndexInFleet;
|
||||
this.targetTime = targetTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,9 +74,14 @@ public class RaceCellImpl extends NamedImpl implements RaceCell {
|
||||
return zeroBasedIndexInFleet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetTimeInfo getTargetTime() {
|
||||
return targetTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RaceCellImpl [factor=" + factor + ", explicitFactor=" + explicitFactor + ", zeroBasedIndexInFleet="
|
||||
+ zeroBasedIndexInFleet + ", getName()=" + getName() + "]";
|
||||
+ zeroBasedIndexInFleet + ", name=" + getName() + ", targetTime: " + getTargetTime() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,12 @@ Require-Bundle: com.sap.sailing.domain.swisstimingadapter,
|
||||
org.mongodb.mongo-java-driver;bundle-version="2.13.0",
|
||||
com.sap.sse.mongodb,
|
||||
com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.common
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sse.common,
|
||||
com.sap.sailing.domain.persistence,
|
||||
com.sap.sse
|
||||
Export-Package: com.sap.sailing.domain.swisstimingadapter.persistence,
|
||||
com.sap.sailing.domain.swisstimingadapter.persistence.impl; x-friends:="com.sap.sailing.domain.swisstimingadapter.test"
|
||||
Import-Package: org.osgi.framework
|
||||
com.sap.sailing.domain.swisstimingadapter.persistence.impl;x-friends:="com.sap.sailing.domain.swisstimingadapter.test,com.sap.sailing.mongodb.test"
|
||||
Import-Package: org.osgi.framework,
|
||||
org.osgi.util.tracker;version="1.5.1"
|
||||
Bundle-Activator: com.sap.sailing.domain.swisstimingadapter.persistence.impl.Activator
|
||||
|
||||
+36
@@ -1,16 +1,52 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter.persistence.impl;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
import java.util.logging.Level;
|
||||
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.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.SwissTimingAdapterFactoryImpl;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.SwissTimingTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler;
|
||||
import com.sap.sse.common.TypeBasedServiceFinder;
|
||||
import com.sap.sse.mongodb.MongoDBService;
|
||||
import com.sap.sse.util.ServiceTrackerFactory;
|
||||
|
||||
public class Activator implements BundleActivator {
|
||||
private static final Logger logger = Logger.getLogger(Activator.class.getName());
|
||||
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
for (CollectionNames name : CollectionNames.values()) {
|
||||
MongoDBService.INSTANCE.registerExclusively(CollectionNames.class, name.name());
|
||||
}
|
||||
new Thread(() -> {
|
||||
final ServiceTracker<MongoObjectFactory, MongoObjectFactory> mongoObjectFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, MongoObjectFactory.class);
|
||||
final ServiceTracker<DomainObjectFactory, DomainObjectFactory> domainObjectFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, DomainObjectFactory.class);
|
||||
try {
|
||||
final MongoObjectFactory mongoObjectFactory = mongoObjectFactoryServiceTracker.waitForService(0);
|
||||
final DomainObjectFactory domainObjectFactory = domainObjectFactoryServiceTracker.waitForService(0);
|
||||
final Dictionary<String, Object> properties = new Hashtable<String, Object>();
|
||||
final com.sap.sailing.domain.swisstimingadapter.DomainFactory domainFactory = new SwissTimingAdapterFactoryImpl().getOrCreateSwissTimingAdapter(
|
||||
domainObjectFactory.getBaseDomainFactory()).getSwissTimingDomainFactory();
|
||||
final SwissTimingConnectivityParamsHandler paramsHandler = new SwissTimingConnectivityParamsHandler(
|
||||
MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore(mongoObjectFactory, domainObjectFactory),
|
||||
MongoRegattaLogStoreFactory.INSTANCE.getMongoRegattaLogStore(mongoObjectFactory, domainObjectFactory),
|
||||
domainFactory);
|
||||
properties.put(TypeBasedServiceFinder.TYPE, SwissTimingTrackingConnectivityParameters.TYPE);
|
||||
context.registerService(RaceTrackingConnectivityParametersHandler.class, paramsHandler, properties);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Exception trying to register SwissTiming RaceTrackingConnectivityParametersHandler implementation", e);
|
||||
}
|
||||
}, getClass().getName() + " registering connectivity handler").start();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter.persistence.impl;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Competitor;
|
||||
import com.sap.sailing.domain.swisstimingadapter.CrewMember;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.StartList;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.CompetitorWithID;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.CompetitorWithoutID;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.CrewMemberImpl;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.StartListImpl;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.SwissTimingTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.impl.AbstractRaceTrackingConnectivityParametersHandler;
|
||||
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 SwissTimingConnectivityParamsHandler extends AbstractRaceTrackingConnectivityParametersHandler {
|
||||
private static final String CREW_MEMBER_POSITION = "crewMemberPosition";
|
||||
private static final String CREW_MEMBER_NATIONALITY = "crewMemberNationality";
|
||||
private static final String CREW_MEMBER_NAME = "crewMemberName";
|
||||
private static final String COMPETITOR_CREW = "competitorCrew";
|
||||
private static final String COMPETITOR_THREE_LETTER_IOC_CODE = "competitorThreeLetterIocCode";
|
||||
private static final String COMPETITOR_NAME = "competitorName";
|
||||
private static final String COMPETITOR_BOAT_ID = "competitorBoatId";
|
||||
private static final String COMPETITOR_ID = "competitorId";
|
||||
private static final String USE_INTERNAL_MARK_PASSING_ALGORITHM = "useInternalMarkPassingAlgorithm";
|
||||
private static final String DELAY_TO_LIVE_IN_MILLIS = "delayToLiveInMillis";
|
||||
private static final String START_LIST = "startList";
|
||||
private static final String RACE_NAME = "raceName";
|
||||
private static final String RACE_ID = "raceID";
|
||||
private static final String RACE_DESCRIPTION = "raceDescription";
|
||||
private static final String PORT = "port";
|
||||
private static final String BOAT_CLASS_NAME = "boatClassName";
|
||||
private static final String HOSTNAME = "hostname";
|
||||
private final RaceLogStore raceLogStore;
|
||||
private final RegattaLogStore regattaLogStore;
|
||||
private final DomainFactory domainFactory;
|
||||
private final SwissTimingFactory swissTimingFactory;
|
||||
|
||||
public SwissTimingConnectivityParamsHandler(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, DomainFactory domainFactory) {
|
||||
super();
|
||||
this.raceLogStore = raceLogStore;
|
||||
this.regattaLogStore = regattaLogStore;
|
||||
this.domainFactory = domainFactory;
|
||||
this.swissTimingFactory = SwissTimingFactory.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> mapFrom(RaceTrackingConnectivityParameters params) {
|
||||
assert params instanceof SwissTimingTrackingConnectivityParameters;
|
||||
final SwissTimingTrackingConnectivityParameters stParams = (SwissTimingTrackingConnectivityParameters) params;
|
||||
final Map<String, Object> result = getKey(params);
|
||||
result.put(BOAT_CLASS_NAME, stParams.getBoatClass()==null?null:stParams.getBoatClass().getName());
|
||||
result.put(RACE_DESCRIPTION, stParams.getRaceDescription());
|
||||
result.put(RACE_NAME, stParams.getRaceName());
|
||||
result.put(START_LIST, createStartListDBObject(stParams));
|
||||
result.put(DELAY_TO_LIVE_IN_MILLIS, stParams.getDelayToLiveInMillis());
|
||||
result.put(USE_INTERNAL_MARK_PASSING_ALGORITHM, stParams.isUseInternalMarkPassingAlgorithm());
|
||||
addWindTrackingParameters(stParams, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private BasicDBList createStartListDBObject(final SwissTimingTrackingConnectivityParameters stParams) {
|
||||
final BasicDBList startListDbObject;
|
||||
if (stParams.getStartList() != null) {
|
||||
startListDbObject = new BasicDBList();
|
||||
for (final Competitor competitor : stParams.getStartList().getCompetitors()) {
|
||||
DBObject competitorDBObject = createCompetitorDBObject(competitor);
|
||||
startListDbObject.add(competitorDBObject);
|
||||
}
|
||||
} else {
|
||||
startListDbObject = null;
|
||||
}
|
||||
return startListDbObject;
|
||||
}
|
||||
|
||||
private StartList createStartListFromDBObject(String raceId, BasicDBList startListDBObject) {
|
||||
List<Competitor> competitors = new ArrayList<>();
|
||||
for (final Object competitorObject : startListDBObject) {
|
||||
final DBObject competitorDBObject = (DBObject) competitorObject;
|
||||
competitors.add(createCompetitorFromDBObject(competitorDBObject));
|
||||
}
|
||||
return new StartListImpl(raceId, competitors);
|
||||
}
|
||||
|
||||
private DBObject createCompetitorDBObject(Competitor competitor) {
|
||||
final DBObject result = new BasicDBObject();
|
||||
result.put(COMPETITOR_ID, competitor.getID());
|
||||
result.put(COMPETITOR_BOAT_ID, competitor.getBoatID());
|
||||
result.put(COMPETITOR_NAME, competitor.getName());
|
||||
result.put(COMPETITOR_THREE_LETTER_IOC_CODE, competitor.getThreeLetterIOCCode());
|
||||
result.put(COMPETITOR_CREW, createCrewDbObject(competitor.getCrew()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private BasicDBList createCrewDbObject(List<CrewMember> crew) {
|
||||
final BasicDBList result;
|
||||
if (crew == null) {
|
||||
result = null;
|
||||
} else {
|
||||
result = new BasicDBList();
|
||||
for (final CrewMember crewMember : crew) {
|
||||
final DBObject crewMemberDBObject = new BasicDBObject();
|
||||
crewMemberDBObject.put(CREW_MEMBER_NAME, crewMember.getName());
|
||||
crewMemberDBObject.put(CREW_MEMBER_NATIONALITY, crewMember.getNationality());
|
||||
crewMemberDBObject.put(CREW_MEMBER_POSITION, crewMember.getPosition());
|
||||
result.add(crewMemberDBObject);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<CrewMember> createCrewFromDBObject(BasicDBList crewDBObject) {
|
||||
final List<CrewMember> result;
|
||||
if (crewDBObject == null) {
|
||||
result = null;
|
||||
} else {
|
||||
result = new ArrayList<>();
|
||||
for (final Object o : crewDBObject) {
|
||||
final DBObject crewMemberDBObject = (DBObject) o;
|
||||
result.add(new CrewMemberImpl((String) crewMemberDBObject.get(CREW_MEMBER_NAME),
|
||||
(String) crewMemberDBObject.get(CREW_MEMBER_NATIONALITY),
|
||||
(String) crewMemberDBObject.get(CREW_MEMBER_POSITION)));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Competitor createCompetitorFromDBObject(DBObject competitorDBObject) {
|
||||
final Competitor result;
|
||||
final String competitorId = (String) competitorDBObject.get(COMPETITOR_ID);
|
||||
final String boatID = (String) competitorDBObject.get(COMPETITOR_BOAT_ID);
|
||||
final String threeLetterIOCCode = (String) competitorDBObject.get(COMPETITOR_THREE_LETTER_IOC_CODE);
|
||||
final String name = (String) competitorDBObject.get(COMPETITOR_NAME);
|
||||
final BasicDBList crewDBObject = (BasicDBList) competitorDBObject.get(COMPETITOR_CREW);
|
||||
if (competitorId == null) {
|
||||
result = new CompetitorWithoutID(boatID, threeLetterIOCCode, name);
|
||||
} else {
|
||||
result = new CompetitorWithID(competitorId, boatID, threeLetterIOCCode, name, createCrewFromDBObject(crewDBObject));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTrackingConnectivityParameters mapTo(Map<String, Object> map) throws MalformedURLException, URISyntaxException {
|
||||
return new SwissTimingTrackingConnectivityParameters(
|
||||
(String) map.get(HOSTNAME),
|
||||
((Number) map.get(PORT)).intValue(),
|
||||
(String) map.get(RACE_ID),
|
||||
(String) map.get(RACE_NAME),
|
||||
(String) map.get(RACE_DESCRIPTION),
|
||||
domainFactory.getBaseDomainFactory().getOrCreateBoatClass((String) map.get(BOAT_CLASS_NAME)),
|
||||
map.get(START_LIST) == null ? null : createStartListFromDBObject((String) map.get(RACE_ID), (BasicDBList) map.get(START_LIST)),
|
||||
((Number) map.get(DELAY_TO_LIVE_IN_MILLIS)).longValue(),
|
||||
swissTimingFactory, domainFactory, raceLogStore, regattaLogStore,
|
||||
(boolean) map.get(USE_INTERNAL_MARK_PASSING_ALGORITHM), isTrackWind(map), isCorrectWindDirectionByMagneticDeclination(map));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getKey(RaceTrackingConnectivityParameters params) {
|
||||
assert params instanceof SwissTimingTrackingConnectivityParameters;
|
||||
final SwissTimingTrackingConnectivityParameters stParams = (SwissTimingTrackingConnectivityParameters) params;
|
||||
final Map<String, Object> result = new HashMap<>();
|
||||
result.put(TypeBasedServiceFinder.TYPE, params.getTypeIdentifier());
|
||||
result.put(HOSTNAME, stParams.getHostname());
|
||||
result.put(PORT, stParams.getPort());
|
||||
result.put(RACE_ID, stParams.getRaceID());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.xrr.schema,
|
||||
com.sap.sailing.domain.shared.android
|
||||
Export-Package: com.sap.sailing.domain.swisstimingadapter,
|
||||
com.sap.sailing.domain.swisstimingadapter.impl;x-friends:="com.sap.sailing.server.test"
|
||||
com.sap.sailing.domain.swisstimingadapter.impl;x-friends:="com.sap.sailing.server.test,com.sap.sailing.mongodb.test,com.sap.sailing.domain.swisstimingadapter.persistence"
|
||||
Import-Package: com.sap.sailing.xrr.schema,
|
||||
org.osgi.framework
|
||||
Bundle-Activator: com.sap.sailing.domain.swisstimingadapter.impl.Activator
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter;
|
||||
|
||||
public interface CrewMember {
|
||||
public String getName();
|
||||
public String getName();
|
||||
|
||||
public String getNationality();
|
||||
public String getNationality();
|
||||
|
||||
public String getPosition();
|
||||
public String getPosition();
|
||||
}
|
||||
|
||||
+8
-5
@@ -10,6 +10,7 @@ import com.sap.sailing.domain.base.Nationality;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.MarkType;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
@@ -31,6 +32,9 @@ public interface DomainFactory {
|
||||
|
||||
com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory();
|
||||
|
||||
/**
|
||||
* @param boatClass if {@code null}, the boat class will be inferred from the Race ID
|
||||
*/
|
||||
Regatta getOrCreateDefaultRegatta(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String raceID, BoatClass boatClass, TrackedRegattaRegistry trackedRegattaRegistry);
|
||||
|
||||
Nationality getOrCreateNationality(String threeLetterIOCCode);
|
||||
@@ -62,11 +66,10 @@ public interface DomainFactory {
|
||||
RaceTrackingConnectivityParameters createTrackingConnectivityParameters(String hostname, int port, String raceID,
|
||||
String raceName, String raceDescription, BoatClass boatClass, StartList startList,
|
||||
long delayToLiveInMillis, SwissTimingFactory swissTimingFactory, DomainFactory domainFactory,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm);
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination);
|
||||
|
||||
ControlPoint getOrCreateControlPoint(Iterable<String> devices);
|
||||
|
||||
RaceDefinition createRaceDefinition(Regatta regatta, String raceID, Iterable<Competitor> competitors,
|
||||
List<ControlPoint> courseDefinition);
|
||||
ControlPoint getOrCreateControlPoint(Iterable<String> devices, MarkType markType);
|
||||
|
||||
RaceDefinition createRaceDefinition(Regatta regatta, String swissTimingRaceID, Iterable<Competitor> competitors,
|
||||
List<ControlPoint> courseDefinition, String raceName, String raceIdForRaceDefinition);
|
||||
}
|
||||
|
||||
+3
-1
@@ -26,10 +26,12 @@ public interface SwissTimingAdapter {
|
||||
* is specified, a regatta lookup is performed with that identifier; if the regatta is found, it is used
|
||||
* to add the races to. Otherwise, a default regatta as described above will be created and used.
|
||||
* @param useInternalMarkPassingAlgorithm use our own instead of the SwissTiming-provided mark passing / split times
|
||||
* @param trackWind TODO
|
||||
* @param correctWindDirectionByMagneticDeclination TODO
|
||||
*/
|
||||
RaceHandle addSwissTimingRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, String raceID,
|
||||
String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
|
||||
StartList startList, RaceLogStore logStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm)
|
||||
StartList startList, RaceLogStore logStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination)
|
||||
throws InterruptedException, UnknownHostException, IOException, ParseException, Exception;
|
||||
|
||||
StartList readStartListForRace(String raceId, RegattaResults regattaResults);
|
||||
|
||||
+6
-4
@@ -10,6 +10,7 @@ import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.SwissTimingFactoryImpl;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.SwissTimingTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
@@ -54,14 +55,15 @@ public interface SwissTimingFactory {
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore,
|
||||
boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws InterruptedException, UnknownHostException,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, SwissTimingTrackingConnectivityParameters connectivityParams) throws InterruptedException, UnknownHostException,
|
||||
IOException, ParseException;
|
||||
|
||||
RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription,
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
|
||||
WindStore windStore, boolean useInternalMarkPassingAlgorithm,
|
||||
DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws UnknownHostException,
|
||||
InterruptedException, IOException, ParseException;
|
||||
WindStore windStore, boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
throws UnknownHostException, InterruptedException, IOException, ParseException;
|
||||
|
||||
Race createRace(String raceId, String raceName, String description, BoatClass boatClass);
|
||||
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter.impl;
|
||||
|
||||
import com.sap.sailing.domain.swisstimingadapter.Competitor;
|
||||
|
||||
public abstract class AbstractCompetitor implements Competitor {
|
||||
private final String boatID;
|
||||
private final String threeLetterIOCCode;
|
||||
private final String name;
|
||||
|
||||
public AbstractCompetitor(String boatID, String threeLetterIOCCode, String name) {
|
||||
super();
|
||||
this.boatID = boatID;
|
||||
this.threeLetterIOCCode = threeLetterIOCCode;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBoatID() {
|
||||
return boatID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThreeLetterIOCCode() {
|
||||
return threeLetterIOCCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((boatID == null) ? 0 : boatID.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((threeLetterIOCCode == null) ? 0 : threeLetterIOCCode.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;
|
||||
AbstractCompetitor other = (AbstractCompetitor) obj;
|
||||
if (boatID == null) {
|
||||
if (other.boatID != null)
|
||||
return false;
|
||||
} else if (!boatID.equals(other.boatID))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (threeLetterIOCCode == null) {
|
||||
if (other.threeLetterIOCCode != null)
|
||||
return false;
|
||||
} else if (!threeLetterIOCCode.equals(other.threeLetterIOCCode))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+38
-31
@@ -2,54 +2,61 @@ package com.sap.sailing.domain.swisstimingadapter.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.swisstimingadapter.Competitor;
|
||||
import com.sap.sailing.domain.swisstimingadapter.CrewMember;
|
||||
|
||||
public class CompetitorWithID implements Competitor {
|
||||
private final String boatID;
|
||||
private final String threeLetterIOCCode;
|
||||
private final String name;
|
||||
public class CompetitorWithID extends AbstractCompetitor {
|
||||
private final String id;
|
||||
|
||||
private List<CrewMember> crew;
|
||||
|
||||
public CompetitorWithID(String id, String boatID, String threeLetterIOCCode, String name, List<CrewMember> crew) {
|
||||
super();
|
||||
this.boatID = boatID;
|
||||
this.threeLetterIOCCode = threeLetterIOCCode;
|
||||
this.name = name;
|
||||
super(boatID, threeLetterIOCCode, name);
|
||||
this.id = id;
|
||||
this.crew = crew;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBoatID() {
|
||||
return boatID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThreeLetterIOCCode() {
|
||||
return threeLetterIOCCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CompetitorWithID [boatID=" + boatID + ", threeLetterIOCCode=" + threeLetterIOCCode + ", name=" + name
|
||||
+ ", id=" + id + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CrewMember> getCrew() {
|
||||
return crew;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((crew == null) ? 0 : crew.hashCode());
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
CompetitorWithID other = (CompetitorWithID) obj;
|
||||
if (crew == null) {
|
||||
if (other.crew != null)
|
||||
return false;
|
||||
} else if (!crew.equals(other.crew))
|
||||
return false;
|
||||
if (id == null) {
|
||||
if (other.id != null)
|
||||
return false;
|
||||
} else if (!id.equals(other.id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CompetitorWithID [boatID=" + getBoatID() + ", threeLetterIOCCode=" + getThreeLetterIOCCode() + ", name=" + getName()
|
||||
+ ", id=" + id + ", crew=" + getCrew() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
+10
-34
@@ -2,49 +2,25 @@ package com.sap.sailing.domain.swisstimingadapter.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.swisstimingadapter.Competitor;
|
||||
import com.sap.sailing.domain.swisstimingadapter.CrewMember;
|
||||
|
||||
public class CompetitorWithoutID implements Competitor {
|
||||
private final String boatID;
|
||||
private final String threeLetterIOCCode;
|
||||
private final String name;
|
||||
|
||||
public class CompetitorWithoutID extends AbstractCompetitor {
|
||||
public CompetitorWithoutID(String boatID, String threeLetterIOCCode, String name) {
|
||||
super();
|
||||
this.boatID = boatID;
|
||||
this.threeLetterIOCCode = threeLetterIOCCode;
|
||||
this.name = name;
|
||||
super(boatID, threeLetterIOCCode, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBoatID() {
|
||||
return boatID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThreeLetterIOCCode() {
|
||||
return threeLetterIOCCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CompetitorWithoutID [boatID=" + boatID + ", threeLetterIOCCode="
|
||||
+ threeLetterIOCCode + ", name=" + name + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CrewMember> getCrew() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public List<CrewMember> getCrew() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CompetitorWithoutID [boatID=" + getBoatID() + ", threeLetterIOCCode=" + getThreeLetterIOCCode() + ", name=" + getName() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
+61
-20
@@ -3,29 +3,70 @@ package com.sap.sailing.domain.swisstimingadapter.impl;
|
||||
import com.sap.sailing.domain.swisstimingadapter.CrewMember;
|
||||
|
||||
public class CrewMemberImpl implements CrewMember {
|
||||
private String name;
|
||||
private String nationality;
|
||||
private String position;
|
||||
private String name;
|
||||
private String nationality;
|
||||
private String position;
|
||||
|
||||
public CrewMemberImpl(String name, String nationality, String position) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.nationality = nationality;
|
||||
this.position = position;
|
||||
}
|
||||
public CrewMemberImpl(String name, String nationality, String position) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.nationality = nationality;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNationality() {
|
||||
return nationality;
|
||||
}
|
||||
@Override
|
||||
public String getNationality() {
|
||||
return nationality;
|
||||
}
|
||||
|
||||
public String getPosition() {
|
||||
return position;
|
||||
}
|
||||
public String getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((nationality == null) ? 0 : nationality.hashCode());
|
||||
result = prime * result + ((position == null) ? 0 : position.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;
|
||||
CrewMemberImpl other = (CrewMemberImpl) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (nationality == null) {
|
||||
if (other.nationality != null)
|
||||
return false;
|
||||
} else if (!nationality.equals(other.nationality))
|
||||
return false;
|
||||
if (position == null) {
|
||||
if (other.position != null)
|
||||
return false;
|
||||
} else if (!position.equals(other.position))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CrewMemberImpl [name=" + name + ", nationality=" + nationality + ", position=" + position + "]";
|
||||
}
|
||||
}
|
||||
|
||||
+30
-12
@@ -28,6 +28,7 @@ import com.sap.sailing.domain.base.impl.PersonImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.TeamImpl;
|
||||
import com.sap.sailing.domain.common.MarkType;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
@@ -176,17 +177,17 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceDefinition createRaceDefinition(Regatta regatta, String raceID, Iterable<Competitor> competitors,
|
||||
List<ControlPoint> courseDefinition) {
|
||||
public RaceDefinition createRaceDefinition(Regatta regatta, String swissTimingRaceID, Iterable<Competitor> competitors,
|
||||
List<ControlPoint> courseDefinition, String raceName, String raceIdForRaceDefinition) {
|
||||
List<Waypoint> waypoints = new ArrayList<>();
|
||||
for (ControlPoint controlPoint : courseDefinition) {
|
||||
Waypoint waypoint = baseDomainFactory.createWaypoint(controlPoint, /* passingInstruction */ PassingInstruction.None);
|
||||
waypoints.add(waypoint);
|
||||
}
|
||||
com.sap.sailing.domain.base.Course domainCourse = new CourseImpl("Course", waypoints);
|
||||
BoatClass boatClass = getRaceTypeFromRaceID(raceID).getBoatClass();
|
||||
logger.info("Creating RaceDefinitionImpl for race "+raceID);
|
||||
RaceDefinition result = new RaceDefinitionImpl(regatta.getId().toString()+"/"+raceID, domainCourse, boatClass, competitors);
|
||||
BoatClass boatClass = getRaceTypeFromRaceID(swissTimingRaceID).getBoatClass();
|
||||
logger.info("Creating RaceDefinitionImpl for race "+swissTimingRaceID);
|
||||
RaceDefinition result = new RaceDefinitionImpl(raceName, domainCourse, boatClass, competitors, raceIdForRaceDefinition);
|
||||
regatta.addRace(result);
|
||||
return result;
|
||||
}
|
||||
@@ -264,7 +265,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
private com.sap.sailing.domain.base.Course createCourse(String courseName, Course course) {
|
||||
List<Waypoint> waypoints = new ArrayList<Waypoint>();
|
||||
for (Mark mark : course.getMarks()) {
|
||||
ControlPoint controlPoint = getOrCreateControlPoint(mark.getDevices());
|
||||
ControlPoint controlPoint = getOrCreateControlPoint(mark.getDevices(), getMarkType(mark.getMarkType()));
|
||||
Waypoint waypoint = baseDomainFactory.createWaypoint(controlPoint, /* passingInstruction */ PassingInstruction.None);
|
||||
waypoints.add(waypoint);
|
||||
}
|
||||
@@ -272,15 +273,28 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a mark type as defined by SwissTiming into a {@link MarkType} as defined by the domain model
|
||||
*/
|
||||
private MarkType getMarkType(com.sap.sailing.domain.swisstimingadapter.Mark.MarkType markType) {
|
||||
final MarkType result;
|
||||
if (markType == null) {
|
||||
result = null;
|
||||
} else {
|
||||
result = MarkType.BUOY;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControlPoint getOrCreateControlPoint(Iterable<String> devices) {
|
||||
public ControlPoint getOrCreateControlPoint(Iterable<String> devices, MarkType markType) {
|
||||
ControlPoint result;
|
||||
synchronized (controlPointCache) {
|
||||
result = controlPointCache.get(devices);
|
||||
if (result == null) {
|
||||
switch (Util.size(devices)) {
|
||||
case 1:
|
||||
result = getOrCreateMark(devices.iterator().next());
|
||||
result = getOrCreateMark(devices.iterator().next(), markType);
|
||||
break;
|
||||
case 2:
|
||||
Iterator<String> markNameIter = devices.iterator();
|
||||
@@ -299,6 +313,10 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
private ControlPoint getOrCreateMark(String name, MarkType markType) {
|
||||
return baseDomainFactory.getOrCreateMark(name, markType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param trackerID
|
||||
* the "device name" and the "sail number" in case of an {@link MessageType#RPD RPD} message, used as the mark's
|
||||
@@ -321,7 +339,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
List<com.sap.sse.common.Util.Pair<com.sap.sailing.domain.base.ControlPoint, PassingInstruction>> newDomainControlPoints = new ArrayList<com.sap.sse.common.Util.Pair<com.sap.sailing.domain.base.ControlPoint, PassingInstruction>>();
|
||||
for (Mark mark : marks) {
|
||||
// TODO bug 1043: propagate the mark names to the waypoint names
|
||||
com.sap.sailing.domain.base.ControlPoint domainControlPoint = getOrCreateControlPoint(mark.getDevices());
|
||||
com.sap.sailing.domain.base.ControlPoint domainControlPoint = getOrCreateControlPoint(mark.getDevices(), getMarkType(mark.getMarkType()));
|
||||
newDomainControlPoints.add(new com.sap.sse.common.Util.Pair<>(domainControlPoint, PassingInstruction.None));
|
||||
}
|
||||
courseToUpdate.update(newDomainControlPoints, baseDomainFactory);
|
||||
@@ -359,10 +377,10 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
public RaceTrackingConnectivityParameters createTrackingConnectivityParameters(String hostname, int port,
|
||||
String raceID, String raceName, String raceDescription, BoatClass boatClass, StartList startList,
|
||||
long delayToLiveInMillis, SwissTimingFactory swissTimingFactory, DomainFactory domainFactory,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm) {
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm,
|
||||
boolean trackWind, boolean correctWindDirectionByMagneticDeclination) {
|
||||
return new SwissTimingTrackingConnectivityParameters(hostname, port, raceID, raceName, raceDescription,
|
||||
boatClass, startList, delayToLiveInMillis, swissTimingFactory, domainFactory, raceLogStore,
|
||||
regattaLogStore, useInternalMarkPassingAlgorithm);
|
||||
regattaLogStore, useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+56
-54
@@ -59,94 +59,96 @@ public class SwissTimingAdapterImpl implements SwissTimingAdapter {
|
||||
|
||||
@Override
|
||||
public List<com.sap.sailing.domain.swisstimingadapter.RaceRecord> getSwissTimingRaceRecords(String hostname,
|
||||
int port) throws InterruptedException, UnknownHostException, IOException,
|
||||
ParseException {
|
||||
int port) throws InterruptedException, UnknownHostException, IOException, ParseException {
|
||||
List<com.sap.sailing.domain.swisstimingadapter.RaceRecord> result = new ArrayList<com.sap.sailing.domain.swisstimingadapter.RaceRecord>();
|
||||
// TODO --> Frank: this needs to come from Manage2Sail and its JSON document somehow...
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceHandle addSwissTimingRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo,
|
||||
String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
|
||||
public RaceHandle addSwissTimingRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, String raceID,
|
||||
String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
|
||||
StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds,
|
||||
boolean useInternalMarkPassingAlgorithm)
|
||||
throws Exception {
|
||||
return trackerManager.addRace(regattaToAddTo, swissTimingDomainFactory.createTrackingConnectivityParameters(
|
||||
hostname, port, raceID, raceName, raceDescription, boatClass, startList,
|
||||
DEFAULT_SWISSTIMING_LIVE_DELAY_IN_MILLISECONDS, swissTimingFactory, swissTimingDomainFactory,
|
||||
raceLogStore, regattaLogStore, useInternalMarkPassingAlgorithm), timeoutInMilliseconds);
|
||||
boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) throws Exception {
|
||||
return trackerManager.addRace(regattaToAddTo,
|
||||
swissTimingDomainFactory.createTrackingConnectivityParameters(hostname, port, raceID, raceName,
|
||||
raceDescription, boatClass, startList, DEFAULT_SWISSTIMING_LIVE_DELAY_IN_MILLISECONDS,
|
||||
swissTimingFactory, swissTimingDomainFactory, raceLogStore, regattaLogStore,
|
||||
useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination),
|
||||
timeoutInMilliseconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StartList readStartListForRace(String raceId, RegattaResults regattaResults) {
|
||||
StartList result = null;
|
||||
StartList result = null;
|
||||
List<Competitor> competitors = new ArrayList<Competitor>();
|
||||
|
||||
Map<String, Person> persons = new HashMap<String, Person>();
|
||||
Map<String, Boat> boats = new HashMap<String, Boat>();
|
||||
Map<String, Team> teams = new HashMap<String, Team>();
|
||||
// collect boats, persons and teams
|
||||
Map<String, Person> persons = new HashMap<String, Person>();
|
||||
Map<String, Boat> boats = new HashMap<String, Boat>();
|
||||
Map<String, Team> teams = new HashMap<String, Team>();
|
||||
// collect boats, persons and teams
|
||||
for (Object o : regattaResults.getPersonOrBoatOrTeam()) {
|
||||
if(o instanceof Person) {
|
||||
Person p = (Person) o;
|
||||
persons.put(p.getPersonID(), p);
|
||||
} else if (o instanceof Boat) {
|
||||
Boat b = (Boat) o;
|
||||
boats.put(b.getBoatID(), b);
|
||||
} else if (o instanceof Team) {
|
||||
Team t = (Team) o;
|
||||
teams.put(t.getTeamID(), t);
|
||||
}
|
||||
if (o instanceof Person) {
|
||||
Person p = (Person) o;
|
||||
persons.put(p.getPersonID(), p);
|
||||
} else if (o instanceof Boat) {
|
||||
Boat b = (Boat) o;
|
||||
boats.put(b.getBoatID(), b);
|
||||
} else if (o instanceof Team) {
|
||||
Team t = (Team) o;
|
||||
teams.put(t.getTeamID(), t);
|
||||
}
|
||||
}
|
||||
|
||||
for (Object o : regattaResults.getPersonOrBoatOrTeam()) {
|
||||
if (o instanceof Event) {
|
||||
Event event = (Event) o;
|
||||
Event event = (Event) o;
|
||||
for (Object eventO : event.getRaceOrDivisionOrRegattaSeriesResult()) {
|
||||
if (eventO instanceof Division) {
|
||||
Division division = (Division) eventO;
|
||||
for(Object seriesResultOrRaceResultOrTRResult: division.getSeriesResultOrRaceResultOrTRResult()) {
|
||||
if(seriesResultOrRaceResultOrTRResult instanceof RaceResult) {
|
||||
RaceResult raceResult = (RaceResult) seriesResultOrRaceResultOrTRResult;
|
||||
if(raceResult.getRaceID().equals(raceId)) {
|
||||
Team team = teams.get(raceResult.getTeamID());
|
||||
if(team != null) {
|
||||
Boat boat = boats.get(team.getBoatID());
|
||||
if(boat != null) {
|
||||
List<CrewMember> crew = new ArrayList<CrewMember>();
|
||||
for(Crew crewMember: team.getCrew()) {
|
||||
Person person = persons.get(crewMember.getPersonID());
|
||||
crew.add(new CrewMemberImpl(person.getGivenName() + " " + person.getFamilyName(),
|
||||
person.getNOC().name(), crewMember.getPosition().name()));
|
||||
}
|
||||
Crew firstCrewMember = team.getCrew().get(0);
|
||||
Person person = persons.get(firstCrewMember.getPersonID());
|
||||
String nationality = person.getNOC().name();
|
||||
CompetitorWithID competitor = new CompetitorWithID(team.getTeamID(), boat.getSailNumber(), nationality, team.getTeamName(), crew);
|
||||
competitors.add(competitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Object seriesResultOrRaceResultOrTRResult : division.getSeriesResultOrRaceResultOrTRResult()) {
|
||||
if (seriesResultOrRaceResultOrTRResult instanceof RaceResult) {
|
||||
RaceResult raceResult = (RaceResult) seriesResultOrRaceResultOrTRResult;
|
||||
if (raceResult.getRaceID().equals(raceId)) {
|
||||
Team team = teams.get(raceResult.getTeamID());
|
||||
if (team != null) {
|
||||
Boat boat = boats.get(team.getBoatID());
|
||||
if (boat != null) {
|
||||
List<CrewMember> crew = new ArrayList<CrewMember>();
|
||||
for (Crew crewMember : team.getCrew()) {
|
||||
Person person = persons.get(crewMember.getPersonID());
|
||||
crew.add(new CrewMemberImpl(
|
||||
person.getGivenName() + " " + person.getFamilyName(),
|
||||
person.getNOC().name(), crewMember.getPosition().name()));
|
||||
}
|
||||
Crew firstCrewMember = team.getCrew().get(0);
|
||||
Person person = persons.get(firstCrewMember.getPersonID());
|
||||
String nationality = person.getNOC().name();
|
||||
CompetitorWithID competitor = new CompetitorWithID(team.getTeamID(),
|
||||
boat.getSailNumber(), nationality, team.getTeamName(), crew);
|
||||
competitors.add(competitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!competitors.isEmpty()) {
|
||||
result = new StartListImpl(raceId, competitors);
|
||||
if (!competitors.isEmpty()) {
|
||||
result = new StartListImpl(raceId, competitors);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaResults readRegattaEntryListFromXrrUrl(String xrrEntryListUrl) throws IOException, JAXBException {
|
||||
// try to read the entry list from manage2sail
|
||||
// try to read the entry list from manage2sail
|
||||
URL regattaEntryListUrl = new URL(xrrEntryListUrl);
|
||||
URLConnection regattaEntryListConn = regattaEntryListUrl.openConnection();
|
||||
RegattaResults regattaResults = ParserFactory.INSTANCE.createParser((InputStream) regattaEntryListConn.getContent(), xrrEntryListUrl).parse();
|
||||
RegattaResults regattaResults = ParserFactory.INSTANCE
|
||||
.createParser((InputStream) regattaEntryListConn.getContent(), xrrEntryListUrl).parse();
|
||||
return regattaResults;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -92,22 +92,23 @@ public class SwissTimingFactoryImpl implements SwissTimingFactory {
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore,
|
||||
boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
throws InterruptedException, UnknownHostException, IOException, ParseException {
|
||||
return new SwissTimingRaceTrackerImpl(raceID, raceName, raceDescription, boatClass, hostname, port, startList,
|
||||
raceLogStore, regattaLogStore, windStore, domainFactory, this,
|
||||
trackedRegattaRegistry, raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm);
|
||||
trackedRegattaRegistry, raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm, connectivityParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription,
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
|
||||
WindStore windStore, boolean useInternalMarkPassingAlgorithm,
|
||||
DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
|
||||
WindStore windStore, boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
throws UnknownHostException, InterruptedException, IOException, ParseException {
|
||||
return new SwissTimingRaceTrackerImpl(regatta, raceID, raceName, raceDescription, boatClass, hostname, port,
|
||||
startList, windStore, domainFactory, this, trackedRegattaRegistry, raceLogResolver, delayToLiveInMillis,
|
||||
useInternalMarkPassingAlgorithm);
|
||||
startList, windStore, domainFactory, this, trackedRegattaRegistry, raceLogStore, regattaLogStore,
|
||||
raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm, connectivityParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+26
-19
@@ -10,7 +10,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -112,25 +111,34 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
protected SwissTimingRaceTrackerImpl(String raceID, String raceName, String raceDescription, BoatClass boatClass,
|
||||
String hostname, int port, StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
WindStore windStore, DomainFactory domainFactory, SwissTimingFactory factory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm) throws InterruptedException,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, long delayToLiveInMillis,
|
||||
boolean useInternalMarkPassingAlgorithm, SwissTimingTrackingConnectivityParameters connectivityParams) throws InterruptedException,
|
||||
UnknownHostException, IOException, ParseException {
|
||||
this(domainFactory.getOrCreateDefaultRegatta(raceLogStore, regattaLogStore, raceID,
|
||||
boatClass, trackedRegattaRegistry), raceID, raceName,
|
||||
raceDescription, boatClass, hostname, port, startList, windStore, domainFactory, factory,
|
||||
trackedRegattaRegistry,
|
||||
raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm);
|
||||
this(/* regatta */ null, raceID, raceName, raceDescription, boatClass, hostname, port, startList, windStore,
|
||||
domainFactory, factory, trackedRegattaRegistry, raceLogStore, regattaLogStore, raceLogResolver,
|
||||
delayToLiveInMillis, useInternalMarkPassingAlgorithm, connectivityParams);
|
||||
}
|
||||
|
||||
protected SwissTimingRaceTrackerImpl(Regatta regatta, String raceID, String raceName, String raceDescription,
|
||||
BoatClass boatClass, String hostname, int port, StartList startList, WindStore windStore,
|
||||
DomainFactory domainFactory, SwissTimingFactory factory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver,
|
||||
long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm) throws InterruptedException, UnknownHostException, IOException,
|
||||
ParseException {
|
||||
super();
|
||||
DomainFactory domainFactory, SwissTimingFactory factory, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, RaceLogResolver raceLogResolver,
|
||||
long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm, SwissTimingTrackingConnectivityParameters connectivityParams)
|
||||
throws InterruptedException, UnknownHostException, IOException, ParseException {
|
||||
super(connectivityParams);
|
||||
this.raceLogResolver = raceLogResolver;
|
||||
this.tmdMessageQueue = new TMDMessageQueue(this);
|
||||
this.regatta = regatta;
|
||||
final Regatta effectiveRegatta;
|
||||
// Try to find a pre-associated event based on the Race ID
|
||||
if (regatta == null) {
|
||||
effectiveRegatta = trackedRegattaRegistry.getRememberedRegattaForRace(raceID);
|
||||
} else {
|
||||
effectiveRegatta = regatta;
|
||||
}
|
||||
// if regatta is still null, no previous assignment of any of the races in this TracTrac event to a Regatta was
|
||||
// found; in this case, create a default regatta based on the TracTrac event data
|
||||
this.regatta = effectiveRegatta == null ? domainFactory.getOrCreateDefaultRegatta(raceLogStore, regattaLogStore,
|
||||
raceID, boatClass, trackedRegattaRegistry) : effectiveRegatta;
|
||||
this.connector = factory.getOrCreateSailMasterConnector(hostname, port, raceID, raceName, raceDescription, boatClass);
|
||||
this.domainFactory = domainFactory;
|
||||
this.raceID = raceID;
|
||||
@@ -142,11 +150,10 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
this.windStore = windStore;
|
||||
this.id = createID(raceID, hostname, port);
|
||||
connector.addSailMasterListener(this);
|
||||
trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta);
|
||||
trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(this.regatta);
|
||||
this.delayToLiveInMillis = delayToLiveInMillis;
|
||||
this.competitorsByBoatId = new HashMap<String, Competitor>();
|
||||
this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -168,13 +175,12 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RaceDefinition> getRaces() {
|
||||
final Set<RaceDefinition> emptySet = Collections.emptySet();
|
||||
return race==null?emptySet:Collections.singleton(race);
|
||||
public RaceDefinition getRace() {
|
||||
return race;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceHandle getRacesHandle() {
|
||||
public RaceHandle getRaceHandle() {
|
||||
return new RaceHandle() {
|
||||
@Override
|
||||
public Regatta getRegatta() {
|
||||
@@ -479,6 +485,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
assert SwissTimingRaceTrackerImpl.this.race == race;
|
||||
}
|
||||
}, useInternalMarkPassingAlgorithm, raceLogResolver);
|
||||
notifyRaceCreationListeners();
|
||||
logger.info("Created SwissTiming RaceDefinition and TrackedRace for "+race.getName());
|
||||
}
|
||||
|
||||
|
||||
+45
-6
@@ -10,11 +10,13 @@ import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.StartList;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
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;
|
||||
|
||||
public class SwissTimingTrackingConnectivityParameters extends AbstractRaceTrackingConnectivityParameters {
|
||||
public static final String TYPE = "SWISS_TIMING";
|
||||
|
||||
public class SwissTimingTrackingConnectivityParameters implements RaceTrackingConnectivityParameters {
|
||||
private final String hostname;
|
||||
private final int port;
|
||||
private final String raceID;
|
||||
@@ -32,8 +34,8 @@ public class SwissTimingTrackingConnectivityParameters implements RaceTrackingCo
|
||||
public SwissTimingTrackingConnectivityParameters(String hostname, int port, String raceID, String raceName,
|
||||
String raceDescription, BoatClass boatClass, StartList startList, long delayToLiveInMillis,
|
||||
SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, RaceLogStore raceLogStore,
|
||||
RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm) {
|
||||
super();
|
||||
RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) {
|
||||
super(trackWind, correctWindDirectionByMagneticDeclination);
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
this.raceID = raceID;
|
||||
@@ -49,13 +51,18 @@ public class SwissTimingTrackingConnectivityParameters implements RaceTrackingCo
|
||||
this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeIdentifier() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
|
||||
RaceLogResolver raceLogResolver) throws Exception {
|
||||
return swissTimingFactory.createRaceTracker(raceID, raceName, raceDescription, boatClass, hostname, port,
|
||||
startList, delayToLiveInMillis, raceLogStore, regattaLogStore, windStore,
|
||||
useInternalMarkPassingAlgorithm,
|
||||
domainFactory, trackedRegattaRegistry, raceLogResolver);
|
||||
domainFactory, trackedRegattaRegistry, raceLogResolver, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,7 +70,7 @@ public class SwissTimingTrackingConnectivityParameters implements RaceTrackingCo
|
||||
WindStore windStore, RaceLogResolver raceLogResolver) throws Exception {
|
||||
return swissTimingFactory.createRaceTracker(regatta, raceID, raceName, raceDescription, boatClass, hostname,
|
||||
port, startList, delayToLiveInMillis, windStore, useInternalMarkPassingAlgorithm,
|
||||
domainFactory, trackedRegattaRegistry, raceLogResolver);
|
||||
domainFactory, trackedRegattaRegistry, raceLogResolver, raceLogStore, regattaLogStore, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,4 +82,36 @@ public class SwissTimingTrackingConnectivityParameters implements RaceTrackingCo
|
||||
public long getDelayToLiveInMillis() {
|
||||
return delayToLiveInMillis;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getRaceID() {
|
||||
return raceID;
|
||||
}
|
||||
|
||||
public String getRaceName() {
|
||||
return raceName;
|
||||
}
|
||||
|
||||
public String getRaceDescription() {
|
||||
return raceDescription;
|
||||
}
|
||||
|
||||
public BoatClass getBoatClass() {
|
||||
return boatClass;
|
||||
}
|
||||
|
||||
public StartList getStartList() {
|
||||
return startList;
|
||||
}
|
||||
|
||||
public boolean isUseInternalMarkPassingAlgorithm() {
|
||||
return useInternalMarkPassingAlgorithm;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-7
@@ -17,9 +17,6 @@ import java.util.Map;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayRace;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.impl.SwissTimingRaceConfig;
|
||||
@@ -33,13 +30,13 @@ public class SwissTimingRaceConfigurationTest {
|
||||
@Test
|
||||
public void testLoadConfigurations() throws IOException, ParseException, org.json.simple.parser.ParseException {
|
||||
InputStream inputStream = getClass().getResourceAsStream(JSON_URL);
|
||||
List<SwissTimingReplayRace> races = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class)).parseJSONObject(inputStream , JSON_URL);
|
||||
List<SwissTimingReplayRace> races = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE).parseJSONObject(inputStream , JSON_URL);
|
||||
Map<String, SwissTimingRaceConfig> configsById = new HashMap<String, SwissTimingRaceConfig>();
|
||||
for (SwissTimingReplayRace race : races) {
|
||||
URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, race.getRaceId()));
|
||||
URLConnection connection = configFileURL.openConnection();
|
||||
InputStream configDataStream = connection.getInputStream();
|
||||
SwissTimingRaceConfig raceConfig = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class)).loadRaceConfig(configDataStream);
|
||||
SwissTimingRaceConfig raceConfig = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE).loadRaceConfig(configDataStream);
|
||||
configsById.put(race.getRaceId(), raceConfig);
|
||||
}
|
||||
}
|
||||
@@ -49,7 +46,7 @@ public class SwissTimingRaceConfigurationTest {
|
||||
URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, "446483"));
|
||||
URLConnection connection = configFileURL.openConnection();
|
||||
InputStream configDataStream = connection.getInputStream();
|
||||
SwissTimingRaceConfig config_446483 = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class)).loadRaceConfig(configDataStream);
|
||||
SwissTimingRaceConfig config_446483 = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE).loadRaceConfig(configDataStream);
|
||||
assertNotNull(config_446483);
|
||||
assertEquals("GB", config_446483.country_code);
|
||||
assertNull(config_446483.event_name);
|
||||
@@ -66,7 +63,7 @@ public class SwissTimingRaceConfigurationTest {
|
||||
URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, "6260"));
|
||||
URLConnection connection = configFileURL.openConnection();
|
||||
InputStream configDataStream = connection.getInputStream();
|
||||
SwissTimingRaceConfig config_446483 = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class)).loadRaceConfig(configDataStream);
|
||||
SwissTimingRaceConfig config_446483 = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE).loadRaceConfig(configDataStream);
|
||||
assertNotNull(config_446483);
|
||||
assertEquals("GB", config_446483.country_code);
|
||||
assertEquals("London 2012 Olympic Games", config_446483.event_name);
|
||||
|
||||
+9
-5
@@ -20,6 +20,8 @@ import org.junit.Test;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayRace;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.impl.SwissTimingReplayParserImpl;
|
||||
@@ -35,7 +37,7 @@ public class SwissTimingReplayAdapterServiceTest {
|
||||
public void testLoadRaceJson() throws Exception {
|
||||
String swissTimingUrlText = "/2012_OSG.json";
|
||||
InputStream inputStream = getClass().getResourceAsStream(swissTimingUrlText);
|
||||
final SwissTimingReplayServiceImpl swissTimingReplayService = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class));
|
||||
final SwissTimingReplayServiceImpl swissTimingReplayService = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE);
|
||||
List<SwissTimingReplayRace> races = swissTimingReplayService.parseJSONObject(inputStream , swissTimingUrlText);
|
||||
assertEquals(201, races.size());
|
||||
assertEquals("446483", races.get(0).getRaceId());
|
||||
@@ -179,8 +181,9 @@ public class SwissTimingReplayAdapterServiceTest {
|
||||
|
||||
@Test
|
||||
public void testRaceData_SAW010955_20120802_WithDomainAdapter() throws Exception {
|
||||
SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, DomainFactory.INSTANCE,
|
||||
new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false, mock(RaceLogResolver.class));
|
||||
SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, /* raceName */ "SAW005906",
|
||||
"SAW005906", /* boatClass */ null, DomainFactory.INSTANCE, new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false,
|
||||
mock(RaceLogResolver.class), EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, /* tracker creator */ null);
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW005906.20120805.replay"), replayListener);
|
||||
Iterable<? extends TrackedRace> trackedRaces = replayListener.getTrackedRaces();
|
||||
assertFalse(Util.isEmpty(trackedRaces));
|
||||
@@ -193,8 +196,9 @@ public class SwissTimingReplayAdapterServiceTest {
|
||||
|
||||
@Test
|
||||
public void testStartPerformanceDetection() throws Exception {
|
||||
SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, DomainFactory.INSTANCE,
|
||||
new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false, mock(RaceLogResolver.class));
|
||||
SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, /* raceName */ "SAW005905",
|
||||
"SAW005905", /* boatClass */ null, DomainFactory.INSTANCE, new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false,
|
||||
mock(RaceLogResolver.class), EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, /* tracker creator */ null);
|
||||
new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW005905.20120805.replay"), replayListener);
|
||||
Iterable<? extends TrackedRace> trackedRaces = replayListener.getTrackedRaces();
|
||||
TrackedRace trackedRace = trackedRaces.iterator().next();
|
||||
|
||||
@@ -13,7 +13,10 @@ Require-Bundle: com.sap.sailing.domain.common,
|
||||
com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||
com.sap.sse,
|
||||
com.sap.sse.common,
|
||||
com.sap.sailing.domain.shared.android
|
||||
Export-Package: com.sap.sailing.domain.swisstimingreplayadapter
|
||||
Import-Package: org.osgi.framework;version="1.7.0"
|
||||
com.sap.sailing.domain.shared.android,
|
||||
com.sap.sailing.domain.persistence
|
||||
Export-Package: com.sap.sailing.domain.swisstimingreplayadapter,
|
||||
com.sap.sailing.domain.swisstimingreplayadapter.impl;x-friends:="com.sap.sailing.mongodb.test"
|
||||
Import-Package: org.osgi.framework;version="1.7.0",
|
||||
org.osgi.util.tracker;version="1.5.1"
|
||||
Bundle-Activator: com.sap.sailing.domain.swisstimingreplayadapter.impl.Activator
|
||||
|
||||
+32
-13
@@ -1,14 +1,20 @@
|
||||
package com.sap.sailing.domain.swisstimingreplayadapter;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.impl.SwissTimingRaceConfig;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.TrackerManager;
|
||||
|
||||
public interface SwissTimingReplayService {
|
||||
|
||||
@@ -22,6 +28,30 @@ public interface SwissTimingReplayService {
|
||||
|
||||
DateFormat getStartTimeFormat();
|
||||
|
||||
/**
|
||||
* @param regattaToAddTo
|
||||
* the regatta to which the race shall be added; if <code>null</code>, a default regatta will be
|
||||
* created/used based on the {@code regattaName} and {@code boatClassName} parameter values
|
||||
* @param link
|
||||
* the URL without the implicit "http://" prefix, as obtained, e.g., from
|
||||
* {@link SwissTimingReplayRace#getLink()}.
|
||||
* @param raceName TODO
|
||||
* @param raceID
|
||||
* the SwissTiming ID for the race
|
||||
* @param trackerManager TODO
|
||||
* @param useInternalMarkPassingAlgorithm
|
||||
* use our own instead of the SwissTiming-provided mark rounding / split times
|
||||
* @param raceLogStore TODO
|
||||
* @param regattaLogStore TODO
|
||||
* @param boatClassNameName
|
||||
* only required if {@code regattaToAddTo} is {@code null}; used for the retrieval/creation of a default
|
||||
* regatta
|
||||
*/
|
||||
void loadRaceData(RegattaIdentifier regattaToAddTo, String link, String raceName, String raceID,
|
||||
String boatClassName, TrackerManager trackerManager, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
|
||||
|
||||
/**
|
||||
* @param link
|
||||
* the URL without the implicit "http://" prefix, as obtained, e.g., from
|
||||
@@ -30,17 +60,6 @@ public interface SwissTimingReplayService {
|
||||
* @param replayListener
|
||||
* the listener to receive all persing events
|
||||
*/
|
||||
void loadRaceData(String link, SwissTimingReplayListener replayListener);
|
||||
|
||||
/**
|
||||
* @param link
|
||||
* the URL without the implicit "http://" prefix, as obtained, e.g., from
|
||||
* {@link SwissTimingReplayRace#getLink()}.
|
||||
* @param regatta
|
||||
* the regatta to which the race shall be added; if <code>null</code>, a default regatta will be
|
||||
* created/used
|
||||
* @param useInternalMarkPassingAlgorithm use our own instead of the SwissTiming-provided mark rounding / split times
|
||||
*/
|
||||
void loadRaceData(String link, Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm);
|
||||
void loadRaceData(String link, SwissTimingReplayListener listener);
|
||||
|
||||
}
|
||||
|
||||
+36
@@ -1,12 +1,24 @@
|
||||
package com.sap.sailing.domain.swisstimingreplayadapter.impl;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
import java.util.logging.Level;
|
||||
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.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingAdapterFactory;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayServiceFactory;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler;
|
||||
import com.sap.sse.common.TypeBasedServiceFinder;
|
||||
import com.sap.sse.util.ServiceTrackerFactory;
|
||||
|
||||
public class Activator implements BundleActivator {
|
||||
private static final Logger logger = Logger.getLogger(Activator.class.getName());
|
||||
@@ -21,6 +33,30 @@ public class Activator implements BundleActivator {
|
||||
public void start(BundleContext context) throws Exception {
|
||||
// register the racing service in the OSGi registry
|
||||
context.registerService(SwissTimingReplayServiceFactory.class.getName(), swissTimingReplayServiceFactory, null);
|
||||
new Thread(() -> {
|
||||
final ServiceTracker<MongoObjectFactory, MongoObjectFactory> mongoObjectFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, MongoObjectFactory.class);
|
||||
final ServiceTracker<DomainObjectFactory, DomainObjectFactory> domainObjectFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, DomainObjectFactory.class);
|
||||
final ServiceTracker<SwissTimingAdapterFactory, SwissTimingAdapterFactory> swissTimingAdapterFactoryServiceTracker = ServiceTrackerFactory.createAndOpen(context, SwissTimingAdapterFactory.class);
|
||||
final ServiceTracker<RaceLogResolver, RaceLogResolver> raceLogResolverServiceTracker = ServiceTrackerFactory.createAndOpen(context, RaceLogResolver.class);
|
||||
try {
|
||||
final MongoObjectFactory mongoObjectFactory = mongoObjectFactoryServiceTracker.waitForService(0);
|
||||
final DomainObjectFactory domainObjectFactory = domainObjectFactoryServiceTracker.waitForService(0);
|
||||
final SwissTimingAdapterFactory swissTimingAdapterFactory = swissTimingAdapterFactoryServiceTracker.waitForService(0);
|
||||
final RaceLogResolver raceLogResolver = raceLogResolverServiceTracker.waitForService(0);
|
||||
final Dictionary<String, Object> properties = new Hashtable<String, Object>();
|
||||
final com.sap.sailing.domain.swisstimingadapter.DomainFactory domainFactory = swissTimingAdapterFactory
|
||||
.getOrCreateSwissTimingAdapter(domainObjectFactory.getBaseDomainFactory())
|
||||
.getSwissTimingDomainFactory();
|
||||
final SwissTimingReplayConnectivityParamsHandler paramsHandler = new SwissTimingReplayConnectivityParamsHandler(
|
||||
MongoRaceLogStoreFactory.INSTANCE.getMongoRaceLogStore(mongoObjectFactory, domainObjectFactory),
|
||||
MongoRegattaLogStoreFactory.INSTANCE.getMongoRegattaLogStore(mongoObjectFactory, domainObjectFactory),
|
||||
domainFactory, swissTimingReplayServiceFactory.createSwissTimingReplayService(domainFactory, raceLogResolver));
|
||||
properties.put(TypeBasedServiceFinder.TYPE, SwissTimingReplayConnectivityParameters.TYPE);
|
||||
context.registerService(RaceTrackingConnectivityParametersHandler.class, paramsHandler, properties);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Exception trying to register SwissTiming Replay RaceTrackingConnectivityParametersHandler implementation", e);
|
||||
}
|
||||
}, getClass().getName() + " registering connectivity handler").start();
|
||||
logger.log(Level.INFO, "Started "+context.getBundle().getSymbolicName());
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package com.sap.sailing.domain.swisstimingreplayadapter.impl;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.CompetitorStatus;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayListener;
|
||||
|
||||
public class SwissTimingReplayAdapter implements SwissTimingReplayListener {
|
||||
public abstract class SwissTimingReplayAdapter implements SwissTimingReplayListener {
|
||||
|
||||
@Override
|
||||
public void keyFrameIndex(int keyFrameIndex) {}
|
||||
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
package com.sap.sailing.domain.swisstimingreplayadapter.impl;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayService;
|
||||
import com.sap.sailing.domain.tracking.AbstractRaceTrackerImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.RaceHandle;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
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.sse.common.Util;
|
||||
|
||||
public class SwissTimingReplayConnectivityParameters extends AbstractRaceTrackingConnectivityParameters {
|
||||
public static final String TYPE = "SWISS_TIMING_REPLAY";
|
||||
|
||||
private final boolean useInternalMarkPassingAlgorithm;
|
||||
private final DomainFactory domainFactory;
|
||||
private final String boatClassName;
|
||||
private final RaceLogStore raceLogStore;
|
||||
private final RegattaLogStore regattaLogStore;
|
||||
private final String raceName;
|
||||
private final String raceID;
|
||||
private final String link;
|
||||
private final SwissTimingReplayService replayService;
|
||||
|
||||
class SwissTimingReplayRaceTracker extends AbstractRaceTrackerImpl {
|
||||
private final WindStore windStore;
|
||||
private SwissTimingReplayToDomainAdapter listener;
|
||||
|
||||
public SwissTimingReplayRaceTracker(WindStore windStore, SwissTimingReplayToDomainAdapter listener,
|
||||
SwissTimingReplayConnectivityParameters connectivityParams) {
|
||||
super(connectivityParams);
|
||||
this.windStore = windStore;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Regatta getRegatta() {
|
||||
return listener.getRegatta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRaceCreationListeners() {
|
||||
super.notifyRaceCreationListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceDefinition getRace() {
|
||||
RaceDefinition race;
|
||||
try {
|
||||
race = listener.getRaceDefinition(raceID, 1 /* very short timeout */);
|
||||
return race;
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicTrackedRegatta getTrackedRegatta() {
|
||||
return listener.getTrackedRegatta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceHandle getRaceHandle() {
|
||||
return new RaceHandle() {
|
||||
@Override
|
||||
public Regatta getRegatta() {
|
||||
return listener.getRegatta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceDefinition getRace() {
|
||||
try {
|
||||
return listener.getRaceDefinition(raceID);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceDefinition getRace(long timeoutInMilliseconds) {
|
||||
try {
|
||||
return listener.getRaceDefinition(raceID, timeoutInMilliseconds);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicTrackedRegatta getTrackedRegatta() {
|
||||
return SwissTimingReplayRaceTracker.this.getTrackedRegatta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker getRaceTracker() {
|
||||
return SwissTimingReplayRaceTracker.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindStore getWindStore() {
|
||||
return windStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getID() {
|
||||
return getTrackerID();
|
||||
}
|
||||
}
|
||||
|
||||
public SwissTimingReplayConnectivityParameters(String link, String raceName, String raceID, String boatClassName,
|
||||
boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
|
||||
SwissTimingReplayService replayService, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore) {
|
||||
super(/* trackWind: never track live wind with a SwissTiming Replay race */ false, /* correctWindDirectionByMagneticDeclination */ false);
|
||||
this.link = link;
|
||||
this.raceName = raceName;
|
||||
this.raceID = raceID;
|
||||
this.boatClassName = boatClassName;
|
||||
this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
|
||||
this.domainFactory = domainFactory;
|
||||
this.replayService = replayService;
|
||||
this.raceLogStore = raceLogStore;
|
||||
this.regattaLogStore = regattaLogStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, final WindStore windStore,
|
||||
RaceLogResolver raceLogResolver) throws Exception {
|
||||
SwissTimingReplayToDomainAdapter listener = new SwissTimingReplayToDomainAdapter(/* regatta */ null, raceName,
|
||||
raceID, domainFactory.getBaseDomainFactory().getOrCreateBoatClass(boatClassName), domainFactory,
|
||||
trackedRegattaRegistry, useInternalMarkPassingAlgorithm, raceLogResolver, raceLogStore,
|
||||
regattaLogStore, l->new SwissTimingReplayRaceTracker(windStore, l, this));
|
||||
replayService.loadRaceData(link, listener);
|
||||
return listener.getTracker();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
WindStore windStore, RaceLogResolver raceLogResolver) throws Exception {
|
||||
SwissTimingReplayToDomainAdapter listener = new SwissTimingReplayToDomainAdapter(regatta, raceName,
|
||||
raceID, domainFactory.getBaseDomainFactory().getOrCreateBoatClass(boatClassName),
|
||||
domainFactory, trackedRegattaRegistry, useInternalMarkPassingAlgorithm, raceLogResolver,
|
||||
raceLogStore, regattaLogStore, l->new SwissTimingReplayRaceTracker(windStore, l, this));
|
||||
replayService.loadRaceData(link, listener);
|
||||
return listener.getTracker();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTrackerID() {
|
||||
return new Util.Pair<>(link, raceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no live tracking with this SwissTiming replay connector
|
||||
*/
|
||||
@Override
|
||||
public long getDelayToLiveInMillis() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeIdentifier() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public boolean isUseInternalMarkPassingAlgorithm() {
|
||||
return useInternalMarkPassingAlgorithm;
|
||||
}
|
||||
|
||||
public String getBoatClassName() {
|
||||
return boatClassName;
|
||||
}
|
||||
|
||||
public String getRaceName() {
|
||||
return raceName;
|
||||
}
|
||||
|
||||
public String getRaceID() {
|
||||
return raceID;
|
||||
}
|
||||
|
||||
public String getLink() {
|
||||
return link;
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package com.sap.sailing.domain.swisstimingreplayadapter.impl;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayService;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.impl.AbstractRaceTrackingConnectivityParametersHandler;
|
||||
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 SwissTimingReplayConnectivityParamsHandler extends AbstractRaceTrackingConnectivityParametersHandler {
|
||||
private static final String BOAT_CLASS_NAME = "boatClassName";
|
||||
private static final String RACE_ID = "raceId";
|
||||
private static final String RACE_NAME = "raceName";
|
||||
private static final String LINK = "link";
|
||||
private static final String USE_INTERNAL_MARK_PASSING_ALGORITHM = "useInternalMarkPassingAlgorithm";
|
||||
private static final String DELAY_TO_LIVE_IN_MILLIS = "delayToLiveInMillis";
|
||||
private final RaceLogStore raceLogStore;
|
||||
private final RegattaLogStore regattaLogStore;
|
||||
private final DomainFactory domainFactory;
|
||||
private final SwissTimingReplayService replayService;
|
||||
|
||||
public SwissTimingReplayConnectivityParamsHandler(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
DomainFactory domainFactory, SwissTimingReplayService replayService) {
|
||||
super();
|
||||
this.raceLogStore = raceLogStore;
|
||||
this.regattaLogStore = regattaLogStore;
|
||||
this.domainFactory = domainFactory;
|
||||
this.replayService = replayService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> mapFrom(RaceTrackingConnectivityParameters params) {
|
||||
assert params instanceof SwissTimingReplayConnectivityParameters;
|
||||
final SwissTimingReplayConnectivityParameters stParams = (SwissTimingReplayConnectivityParameters) params;
|
||||
final Map<String, Object> result = getKey(params);
|
||||
result.put(DELAY_TO_LIVE_IN_MILLIS, stParams.getDelayToLiveInMillis());
|
||||
result.put(USE_INTERNAL_MARK_PASSING_ALGORITHM, stParams.isUseInternalMarkPassingAlgorithm());
|
||||
result.put(RACE_NAME, stParams.getRaceName());
|
||||
result.put(RACE_ID, stParams.getRaceID());
|
||||
result.put(BOAT_CLASS_NAME, stParams.getBoatClassName());
|
||||
addWindTrackingParameters(stParams, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTrackingConnectivityParameters mapTo(Map<String, Object> map) throws MalformedURLException, URISyntaxException {
|
||||
return new SwissTimingReplayConnectivityParameters((String) map.get(LINK), (String) map.get(RACE_NAME),
|
||||
(String) map.get(RACE_ID), (String) map.get(BOAT_CLASS_NAME),
|
||||
(boolean) map.get(USE_INTERNAL_MARK_PASSING_ALGORITHM), domainFactory, replayService, raceLogStore,
|
||||
regattaLogStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getKey(RaceTrackingConnectivityParameters params) {
|
||||
assert params instanceof SwissTimingReplayConnectivityParameters;
|
||||
final SwissTimingReplayConnectivityParameters stParams = (SwissTimingReplayConnectivityParameters) params;
|
||||
final Map<String, Object> result = new HashMap<>();
|
||||
result.put(TypeBasedServiceFinder.TYPE, params.getTypeIdentifier());
|
||||
result.put(LINK, stParams.getLink());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
-1
@@ -15,7 +15,6 @@ public class SwissTimingReplayParserImpl implements SwissTimingReplayParser {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public UnknownMessageIdentificationCode(byte messageIdentificationCode, long position) {
|
||||
super("Unknown message identification code: " + messageIdentificationCode+" at position "+position);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ public class SwissTimingReplayServiceFactoryImpl implements SwissTimingReplaySer
|
||||
public SwissTimingReplayService createSwissTimingReplayService(DomainFactory domainFactory, RaceLogResolver raceLogResolver) {
|
||||
SwissTimingReplayService result = servicesForDomainFactories.get(domainFactory);
|
||||
if (result == null) {
|
||||
result = new SwissTimingReplayServiceImpl(domainFactory, raceLogResolver);
|
||||
result = new SwissTimingReplayServiceImpl(domainFactory);
|
||||
servicesForDomainFactories.put(domainFactory, result);
|
||||
}
|
||||
return result;
|
||||
|
||||
+14
-10
@@ -1,9 +1,12 @@
|
||||
package com.sap.sailing.domain.swisstimingreplayadapter.impl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.text.DateFormat;
|
||||
import java.text.MessageFormat;
|
||||
@@ -18,13 +21,15 @@ import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayListener;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayRace;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayService;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.TrackerManager;
|
||||
import com.sap.sse.util.ByteArrayOutputStreamWithVisibleBuffer;
|
||||
|
||||
public class SwissTimingReplayServiceImpl implements SwissTimingReplayService {
|
||||
@@ -35,11 +40,9 @@ public class SwissTimingReplayServiceImpl implements SwissTimingReplayService {
|
||||
private static final TimeZone DEFAULT_TIMEZONE = TimeZone.getTimeZone("GMT");
|
||||
|
||||
private final DomainFactory domainFactory;
|
||||
private final RaceLogResolver raceLogResolver;
|
||||
|
||||
public SwissTimingReplayServiceImpl(DomainFactory domainFactory, RaceLogResolver raceLogResolver) {
|
||||
public SwissTimingReplayServiceImpl(DomainFactory domainFactory) {
|
||||
this.domainFactory = domainFactory;
|
||||
this.raceLogResolver = raceLogResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,10 +149,11 @@ public class SwissTimingReplayServiceImpl implements SwissTimingReplayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadRaceData(String link, Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
boolean useInternalMarkPassingAlgorithm) {
|
||||
SwissTimingReplayListener listener = new SwissTimingReplayToDomainAdapter(regatta, domainFactory,
|
||||
trackedRegattaRegistry, useInternalMarkPassingAlgorithm, raceLogResolver);
|
||||
loadRaceData(link, listener);
|
||||
public void loadRaceData(RegattaIdentifier regattaToAddTo, String link, String raceName, String raceID,
|
||||
String boatClassName, TrackerManager trackerManager, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception {
|
||||
trackerManager.addRace(regattaToAddTo, new SwissTimingReplayConnectivityParameters(link, raceName, raceID,
|
||||
boatClassName, useInternalMarkPassingAlgorithm, domainFactory, this, raceLogStore, regattaLogStore), /* timeout */ 0);
|
||||
}
|
||||
}
|
||||
|
||||
+136
-18
@@ -16,6 +16,7 @@ import java.util.TimeZone;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.ControlPoint;
|
||||
import com.sap.sailing.domain.base.Course;
|
||||
@@ -37,14 +38,18 @@ import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.CompetitorStatus;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayListener;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayParser;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.impl.SwissTimingReplayConnectivityParameters.SwissTimingReplayRaceTracker;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
import com.sap.sailing.domain.tracking.TrackingDataLoader;
|
||||
@@ -77,11 +82,14 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
|
||||
|
||||
private final DomainFactory domainFactory;
|
||||
|
||||
private final Map<String, RaceDefinition> racePerRaceID;
|
||||
/**
|
||||
* Can be waited on; additions are {@link Object#notifyAll() notified}.
|
||||
*/
|
||||
private final Map<String, RaceDefinition> racePerRaceIdForRaceDefinition;
|
||||
private final Map<String, DynamicTrackedRace> trackedRacePerRaceID;
|
||||
|
||||
/**
|
||||
* The last race ID received from {@link #raceID(String)}. Used as key into {@link #racePerRaceID} and
|
||||
* The last race ID received from {@link #raceID(String)}. Used as key into {@link #racePerRaceIdForRaceDefinition} and
|
||||
* {@link #trackedRacePerRaceID} for storing data from subsequent messages.
|
||||
*/
|
||||
private String currentRaceID;
|
||||
@@ -140,18 +148,57 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
|
||||
|
||||
private final RaceLogResolver raceLogResolver;
|
||||
|
||||
private final String raceName;
|
||||
|
||||
private final String raceIdForRaceDefinition;
|
||||
|
||||
/**
|
||||
* Optional callback to which to announce the arrival of the {@link RaceDefinition}
|
||||
*/
|
||||
private final DynamicRaceDefinitionSet dynamicRaceDefinitionSet;
|
||||
|
||||
private final SwissTimingReplayRaceTracker tracker;
|
||||
|
||||
@FunctionalInterface
|
||||
public static interface TrackerConstructor {
|
||||
SwissTimingReplayRaceTracker createTracker(SwissTimingReplayToDomainAdapter adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param regatta
|
||||
* the regatta to associate the race(s) received by the listener with, or <code>null</code> to force the
|
||||
* use / creation of a default regatta per race
|
||||
* @param useInternalMarkPassingAlgorithm use our own instead of the SwissTiming-provided mark rounding / split times
|
||||
* @param useInternalMarkPassingAlgorithm
|
||||
* use our own instead of the SwissTiming-provided mark rounding / split times
|
||||
* @param trackerConstructor
|
||||
* if not {@code null} this object is used to construct the {@link SwissTimingReplayRaceTracker} that can
|
||||
* be obtained from {@link #getTracker()}. This tracker's {@link RaceTracker.RaceCreationListener}s will
|
||||
* be {@link SwissTimingReplayRaceTracker#notifyRaceCreationListeners() notified} when this adapter has
|
||||
* created the race.
|
||||
*/
|
||||
public SwissTimingReplayToDomainAdapter(Regatta regatta, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver) {
|
||||
public SwissTimingReplayToDomainAdapter(Regatta regatta, String raceName, String raceIdForRaceDefinition,
|
||||
BoatClass boatClass, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, TrackerConstructor trackerConstructor) {
|
||||
this.tracker = trackerConstructor == null ? null : trackerConstructor.createTracker(this);
|
||||
this.raceLogResolver = raceLogResolver;
|
||||
this.regatta = regatta;
|
||||
// when the race is created, notify the tracker's race creation listeners
|
||||
this.dynamicRaceDefinitionSet = trackerConstructor == null ? null : (race, trackedRace)->this.tracker.notifyRaceCreationListeners();
|
||||
this.raceName = raceName;
|
||||
this.raceIdForRaceDefinition = raceIdForRaceDefinition;
|
||||
final Regatta effectiveRegatta;
|
||||
// Try to find a pre-associated event based on the Race ID
|
||||
if (regatta == null) {
|
||||
effectiveRegatta = trackedRegattaRegistry.getRememberedRegattaForRace(raceIdForRaceDefinition);
|
||||
} else {
|
||||
effectiveRegatta = regatta;
|
||||
}
|
||||
// if regatta is still null, no previous assignment of any of the races in this TracTrac event to a Regatta was
|
||||
// found; in this case, create a default regatta based on the TracTrac event data
|
||||
this.regatta = effectiveRegatta == null ? domainFactory.getOrCreateDefaultRegatta(raceLogStore, regattaLogStore,
|
||||
raceIdForRaceDefinition, boatClass, trackedRegattaRegistry) : effectiveRegatta;
|
||||
this.trackedRegattaRegistry = trackedRegattaRegistry;
|
||||
racePerRaceID = new HashMap<>();
|
||||
racePerRaceIdForRaceDefinition = new HashMap<>();
|
||||
trackedRacePerRaceID = new HashMap<>();
|
||||
bestStartTimePerRaceID = new HashMap<>();
|
||||
raceTimePerRaceID = new HashMap<>();
|
||||
@@ -165,6 +212,14 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
|
||||
this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
|
||||
}
|
||||
|
||||
public RaceTracker getTracker() {
|
||||
return tracker;
|
||||
}
|
||||
|
||||
public Regatta getRegatta() {
|
||||
return regatta;
|
||||
}
|
||||
|
||||
public Iterable<DynamicTrackedRace> getTrackedRaces() {
|
||||
return trackedRacePerRaceID.values();
|
||||
}
|
||||
@@ -273,7 +328,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
|
||||
if (id2 != null && !id2.trim().isEmpty()) {
|
||||
markNames.add(id2.trim());
|
||||
}
|
||||
final ControlPoint controlPoint = domainFactory.getOrCreateControlPoint(markNames);
|
||||
final ControlPoint controlPoint = domainFactory.getOrCreateControlPoint(markNames, getMarkType(markType));
|
||||
if (index == 0) {
|
||||
currentCourseDefinition = new ArrayList<>();
|
||||
}
|
||||
@@ -290,9 +345,32 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a domain {@link com.sap.sailing.domain.common.MarkType} from a SwissTiming replay {@link MarkType mark type}.
|
||||
*/
|
||||
private com.sap.sailing.domain.common.MarkType getMarkType(MarkType markType) {
|
||||
final com.sap.sailing.domain.common.MarkType result;
|
||||
if (markType == null) {
|
||||
result = null;
|
||||
} else {
|
||||
if (markType.isBoat()) {
|
||||
if (markType.isStart()) {
|
||||
result = com.sap.sailing.domain.common.MarkType.STARTBOAT;
|
||||
} else if (markType.isFinish()) {
|
||||
result = com.sap.sailing.domain.common.MarkType.FINISHBOAT;
|
||||
} else {
|
||||
result = com.sap.sailing.domain.common.MarkType.BUOY;
|
||||
}
|
||||
} else {
|
||||
result = com.sap.sailing.domain.common.MarkType.BUOY;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trackersCount(short trackersCount) {
|
||||
RaceDefinition race = racePerRaceID.get(currentRaceID);
|
||||
RaceDefinition race = racePerRaceIdForRaceDefinition.get(raceIdForRaceDefinition);
|
||||
if (race == null) {
|
||||
createRace();
|
||||
} else {
|
||||
@@ -311,13 +389,13 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
|
||||
}
|
||||
|
||||
private void createRace() {
|
||||
final Regatta myRegatta = regatta != null ? regatta : domainFactory.getOrCreateDefaultRegatta(
|
||||
EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
|
||||
currentRaceID, domainFactory.getRaceTypeFromRaceID(currentRaceID).getBoatClass(), trackedRegattaRegistry);
|
||||
RaceDefinition race = domainFactory.createRaceDefinition(myRegatta,
|
||||
currentRaceID, competitorsPerRaceID.get(currentRaceID), currentCourseDefinition);
|
||||
racePerRaceID.put(currentRaceID, race);
|
||||
DynamicTrackedRace trackedRace = trackedRegattaRegistry.getOrCreateTrackedRegatta(myRegatta).
|
||||
RaceDefinition race = domainFactory.createRaceDefinition(regatta,
|
||||
currentRaceID, competitorsPerRaceID.get(currentRaceID), currentCourseDefinition, raceName, raceIdForRaceDefinition);
|
||||
synchronized (racePerRaceIdForRaceDefinition) {
|
||||
racePerRaceIdForRaceDefinition.put(raceIdForRaceDefinition, race);
|
||||
racePerRaceIdForRaceDefinition.notifyAll();
|
||||
}
|
||||
DynamicTrackedRace trackedRace = getTrackedRegatta().
|
||||
createTrackedRace(race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE,
|
||||
TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS,
|
||||
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND,
|
||||
@@ -329,6 +407,46 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
|
||||
trackedRace.setStartTimeReceived(bestStartTimeKnownSoFar);
|
||||
}
|
||||
trackedRacePerRaceID.put(currentRaceID, trackedRace);
|
||||
if (dynamicRaceDefinitionSet != null) {
|
||||
dynamicRaceDefinitionSet.addRaceDefinition(race, trackedRace);
|
||||
}
|
||||
}
|
||||
|
||||
public DynamicTrackedRegatta getTrackedRegatta() {
|
||||
return trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits synchronously until a race with ID {@code raceID} was added to {@link #racePerRaceIdForRaceDefinition}.
|
||||
*/
|
||||
public RaceDefinition getRaceDefinition(String raceID) throws InterruptedException {
|
||||
return getRaceDefinition(raceID, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits synchronously until a race with ID {@code raceID} was added to {@link #racePerRaceIdForRaceDefinition}
|
||||
*
|
||||
* @param timeoutInMillis
|
||||
* if 0, waits until a race for {@code raceID} was added to {@link #racePerRaceIdForRaceDefinition}; otherwise the call
|
||||
* returns after so many milliseconds at the latest, even if no race with that ID was added, in which
|
||||
* case the method returns {@code null}
|
||||
*/
|
||||
public RaceDefinition getRaceDefinition(String raceIdForRaceDefinition, long timeoutInMillis) throws InterruptedException {
|
||||
final RaceDefinition result;
|
||||
long targetTime = 0;
|
||||
if (timeoutInMillis != 0) {
|
||||
targetTime = System.currentTimeMillis() + timeoutInMillis;
|
||||
}
|
||||
synchronized (racePerRaceIdForRaceDefinition) {
|
||||
while (!racePerRaceIdForRaceDefinition.containsKey(raceIdForRaceDefinition)) {
|
||||
racePerRaceIdForRaceDefinition.wait(timeoutInMillis == 0 ? 0 : Math.max(1, targetTime-System.currentTimeMillis()));
|
||||
if (timeoutInMillis != 0 && System.currentTimeMillis() > targetTime) {
|
||||
break; // if a real timeout has been specified, don't wait again
|
||||
}
|
||||
}
|
||||
result = racePerRaceIdForRaceDefinition.get(raceIdForRaceDefinition);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user