mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-21 21:25:38 +00:00
implemented RaceCreationListener callback pattern on RaceTracker as prerequisite for linking connectivity parameters to Race/TrackedRace
Change-Id: Ib74b2a1c1defe7c89f9a3584cbb230fe73358a13
This commit is contained in:
+15
-11
@@ -1539,17 +1539,21 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
@Override
|
||||
public void addConnectivityParametersForRaceToRestore(RaceTrackingConnectivityParameters params) {
|
||||
final String typeIdentifier = params.getTypeIdentifier();
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -312,6 +312,7 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl {
|
||||
trackedRace.addStartTimeChangedListener(startOfTrackingController);
|
||||
endOfTrackingController = new EndOfTrackingController(trackedRace, raceLog, raceLogEventAuthor);
|
||||
trackedRace.addListener(endOfTrackingController);
|
||||
notifyRaceCreationListeners();
|
||||
logger.info(String.format("Started tracking race-log race (%s)", raceLog));
|
||||
// this wakes up all waiting race handles
|
||||
synchronized (this) {
|
||||
|
||||
+1
@@ -485,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());
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -183,7 +183,7 @@ public class SwissTimingReplayAdapterServiceTest {
|
||||
public void testRaceData_SAW010955_20120802_WithDomainAdapter() throws Exception {
|
||||
SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, /* raceName */ "SAW005906",
|
||||
"SAW005906", /* boatClass */ null, DomainFactory.INSTANCE, new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false,
|
||||
mock(RaceLogResolver.class), EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE);
|
||||
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));
|
||||
@@ -198,7 +198,7 @@ public class SwissTimingReplayAdapterServiceTest {
|
||||
public void testStartPerformanceDetection() throws Exception {
|
||||
SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, /* raceName */ "SAW005905",
|
||||
"SAW005905", /* boatClass */ null, DomainFactory.INSTANCE, new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false,
|
||||
mock(RaceLogResolver.class), EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE);
|
||||
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();
|
||||
|
||||
+12
-6
@@ -29,11 +29,12 @@ public class SwissTimingReplayConnectivityParameters implements RaceTrackingConn
|
||||
private final String link;
|
||||
private final SwissTimingReplayService replayService;
|
||||
|
||||
private class SwissTimingReplayRaceTracker extends AbstractRaceTrackerImpl {
|
||||
class SwissTimingReplayRaceTracker extends AbstractRaceTrackerImpl {
|
||||
private final WindStore windStore;
|
||||
private SwissTimingReplayToDomainAdapter listener;
|
||||
|
||||
private SwissTimingReplayRaceTracker(WindStore windStore, SwissTimingReplayToDomainAdapter listener, SwissTimingReplayConnectivityParameters connectivityParams) {
|
||||
public SwissTimingReplayRaceTracker(WindStore windStore, SwissTimingReplayToDomainAdapter listener,
|
||||
SwissTimingReplayConnectivityParameters connectivityParams) {
|
||||
super(connectivityParams);
|
||||
this.windStore = windStore;
|
||||
this.listener = listener;
|
||||
@@ -43,6 +44,11 @@ public class SwissTimingReplayConnectivityParameters implements RaceTrackingConn
|
||||
public Regatta getRegatta() {
|
||||
return listener.getRegatta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRaceCreationListeners() {
|
||||
super.notifyRaceCreationListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceDefinition getRace() {
|
||||
@@ -129,9 +135,9 @@ public class SwissTimingReplayConnectivityParameters implements RaceTrackingConn
|
||||
SwissTimingReplayToDomainAdapter listener = new SwissTimingReplayToDomainAdapter(/* regatta */ null, raceName,
|
||||
raceID, domainFactory.getBaseDomainFactory().getOrCreateBoatClass(boatClassName), domainFactory,
|
||||
trackedRegattaRegistry, useInternalMarkPassingAlgorithm, raceLogResolver, raceLogStore,
|
||||
regattaLogStore);
|
||||
regattaLogStore, l->new SwissTimingReplayRaceTracker(windStore, l, this));
|
||||
replayService.loadRaceData(link, listener);
|
||||
return new SwissTimingReplayRaceTracker(windStore, listener, this);
|
||||
return listener.getTracker();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -140,9 +146,9 @@ public class SwissTimingReplayConnectivityParameters implements RaceTrackingConn
|
||||
SwissTimingReplayToDomainAdapter listener = new SwissTimingReplayToDomainAdapter(regatta, raceName,
|
||||
raceID, domainFactory.getBaseDomainFactory().getOrCreateBoatClass(boatClassName),
|
||||
domainFactory, trackedRegattaRegistry, useInternalMarkPassingAlgorithm, raceLogResolver,
|
||||
raceLogStore, regattaLogStore);
|
||||
raceLogStore, regattaLogStore, l->new SwissTimingReplayRaceTracker(windStore, l, this));
|
||||
replayService.loadRaceData(link, listener);
|
||||
return new SwissTimingReplayRaceTracker(windStore, listener, this);
|
||||
return listener.getTracker();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+33
-2
@@ -44,9 +44,12 @@ 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;
|
||||
@@ -149,17 +152,38 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
|
||||
|
||||
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, String raceName, String raceIdForRaceDefinition,
|
||||
BoatClass boatClass, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver,
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore) {
|
||||
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, TrackerConstructor trackerConstructor) {
|
||||
this.tracker = trackerConstructor == null ? null : trackerConstructor.createTracker(this);
|
||||
this.raceLogResolver = raceLogResolver;
|
||||
// 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;
|
||||
@@ -188,6 +212,10 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
|
||||
this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
|
||||
}
|
||||
|
||||
public RaceTracker getTracker() {
|
||||
return tracker;
|
||||
}
|
||||
|
||||
public Regatta getRegatta() {
|
||||
return regatta;
|
||||
}
|
||||
@@ -379,6 +407,9 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
|
||||
trackedRace.setStartTimeReceived(bestStartTimeKnownSoFar);
|
||||
}
|
||||
trackedRacePerRaceID.put(currentRaceID, trackedRace);
|
||||
if (dynamicRaceDefinitionSet != null) {
|
||||
dynamicRaceDefinitionSet.addRaceDefinition(race, trackedRace);
|
||||
}
|
||||
}
|
||||
|
||||
public DynamicTrackedRegatta getTrackedRegatta() {
|
||||
|
||||
+1
@@ -656,6 +656,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl
|
||||
public void addRaceDefinition(final RaceDefinition race, final DynamicTrackedRace trackedRace) {
|
||||
this.race = race;
|
||||
updateStatusOfTrackedRace(trackedRace);
|
||||
notifyRaceCreationListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+24
@@ -2,12 +2,17 @@ package com.sap.sailing.domain.tracking;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
|
||||
/**
|
||||
* Base class for all {@link RaceTracker}s that must implement listener notifications
|
||||
*/
|
||||
public abstract class AbstractRaceTrackerBaseImpl implements RaceTracker {
|
||||
private final RaceTrackerListeners listeners = new RaceTrackerListeners();
|
||||
private final ConcurrentHashMap<RaceTracker.RaceCreationListener, Void> raceCreationListeners = new ConcurrentHashMap<>();
|
||||
|
||||
private final RaceTrackingConnectivityParameters connectivityParams;
|
||||
|
||||
public AbstractRaceTrackerBaseImpl(RaceTrackingConnectivityParameters connectivityParams) {
|
||||
@@ -48,6 +53,25 @@ public abstract class AbstractRaceTrackerBaseImpl implements RaceTracker {
|
||||
listeners.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(RaceCreationListener listener) {
|
||||
raceCreationListeners.put(listener, null);
|
||||
final RaceDefinition race = getRace();
|
||||
if (race != null) {
|
||||
listener.onRaceCreated(this);
|
||||
remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(RaceCreationListener listener) {
|
||||
raceCreationListeners.remove(listener);
|
||||
}
|
||||
|
||||
protected void notifyRaceCreationListeners() {
|
||||
raceCreationListeners.keySet().forEach(l->l.onRaceCreated(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTrackingConnectivityParameters getConnectivityParams() {
|
||||
return connectivityParams;
|
||||
|
||||
+1
@@ -15,6 +15,7 @@ import com.sap.sailing.domain.base.RaceDefinition;
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface DynamicRaceDefinitionSet {
|
||||
void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace);
|
||||
}
|
||||
|
||||
@@ -87,11 +87,26 @@ public interface RaceTracker {
|
||||
*/
|
||||
void onTrackerWillStop(boolean preemptive);
|
||||
}
|
||||
|
||||
interface RaceCreationListener {
|
||||
/**
|
||||
* Tracker has received its {@link RaceDefinition}, so that now {@link RaceTracker#getRace} no longer returns
|
||||
* {@code null} but a valid {@link RaceDefinition}
|
||||
*
|
||||
* @param tracker
|
||||
* this tracker is passed to the listener which can then obtain the {@link RaceTracker#getRace()
|
||||
* race} and the {@link RaceTracker#getConnectivityParams() connectivity parameters}, etc. If the
|
||||
* {@link RaceTracker} already has created its race, this method is called immediately upon
|
||||
* {@link RaceTracker#add(Listener) adding} this listener so that the listener will always receive
|
||||
* the call for a valid race if the race is created at any point in time, regardless the point in
|
||||
* time of the listener registration. This helps avoid race conditions.
|
||||
*/
|
||||
void onRaceCreated(RaceTracker tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new RaceTracker.Listener for this race tracker.
|
||||
*
|
||||
* @param newListener
|
||||
* @return true if listener has been added
|
||||
*/
|
||||
boolean add(RaceTracker.Listener newListener);
|
||||
@@ -99,10 +114,14 @@ public interface RaceTracker {
|
||||
/**
|
||||
* Remove listener from race tracker
|
||||
*
|
||||
* @param newListener
|
||||
* @param listener
|
||||
* @return the listener registration for listener removal
|
||||
*/
|
||||
void remove(RaceTracker.Listener newListener);
|
||||
void remove(RaceTracker.Listener listener);
|
||||
|
||||
void add(RaceTracker.RaceCreationListener listener);
|
||||
|
||||
void remove(RaceTracker.RaceCreationListener listener);
|
||||
|
||||
/**
|
||||
* The connectivity parameters used to create this tracker. Can be used, e.g., to add or remove those parameters to
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<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.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dfile.encoding=cp1252 -Dexpedition.udp.port=2010 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -Dpersistentcompetitors.clear=false -XX:+UseMembar -Digtimi.client.id=7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6 -Digtimi.client.secret=aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a -Digtimi.client.redirecturi=http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback -Dpolardata.source.url=https://dev.sapsailing.com"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Declipse.ignoreApp=true -Dosgi.noShutdown=true -Dfile.encoding=cp1252 -Dexpedition.udp.port=2010 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -Dkiwo.results=${project_loc:com.sap.sailing.kiworesultimport.test}/resources -Dpersistentcompetitors.clear=false -XX:+UseMembar -Digtimi.client.id=7fcdd217e0aa16090edb4ad55b09ec43b2021090e209541fc9b7003c2a2b70c6 -Digtimi.client.secret=aa569cf4909bdc7b0e04b11873f3c4ea20687421e010fcc25b771cca9e6f3f9a -Digtimi.client.redirecturi=http://127.0.0.1:8888/igtimi/oauth/v1/authorizationcallback -Dpolardata.source.url=https://dev.sapsailing.com -Drestore.tracked.races=true"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
|
||||
<stringAttribute key="pde.version" value="3.3"/>
|
||||
<stringAttribute key="profilingTraceType-ALLOCATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%INCREASE_COUNT%CTX_KEY%8192%CTX_ENTRY%KEY_MIN_SIZE%CTX_KEY%32%CTX_ENTRY%KEY_MAX_SIZE%CTX_KEY%65536%CTX_ENTRY%KEY_INC_LINE_NRS%CTX_KEY%true%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%CLASS_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ADAPTIVE%CTX_KEY%false%CTX_ENTRY%"/>
|
||||
|
||||
Reference in New Issue
Block a user