mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-30 17:36:40 +00:00
Merge branch 'master' of ssh://195.227.10.246/home/trac/git
This commit is contained in:
commit
193aa9d04a
7 files changed
+127
-38
No files matched your search
+5
@@ -25,4 +25,9 @@ public interface RaceHandle {
|
||||
|
||||
DynamicTrackedEvent getTrackedEvent();
|
||||
|
||||
/**
|
||||
* The tracker managing the tracking of the race to which this is a handle.
|
||||
*/
|
||||
RaceTracker getRaceTracker();
|
||||
|
||||
}
|
||||
+14
@@ -2,12 +2,22 @@ package com.sap.sailing.domain.tractracadapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedEvent;
|
||||
import com.sap.sailing.domain.tracking.TrackedEvent;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
import com.sap.sailing.util.Util.Triple;
|
||||
|
||||
public interface RaceTracker {
|
||||
|
||||
/**
|
||||
* Stops tracking the race and removes the {@link TrackedRace} object one gets from calling
|
||||
* {@link #getTrackedEvent()}.{@link TrackedEvent#getTrackedRace(RaceDefinition) getTrackedRace(}{@link #getRace() getRace())}
|
||||
* from the {@link #getTrackedEvent() tracked event}.
|
||||
*/
|
||||
void stop() throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
com.sap.sailing.domain.base.Event getEvent();
|
||||
@@ -22,5 +32,9 @@ public interface RaceTracker {
|
||||
RaceHandle getRaceHandle();
|
||||
|
||||
DynamicTrackedEvent getTrackedEvent();
|
||||
|
||||
WindStore getWindStore();
|
||||
|
||||
Triple<URL, URI, URI> getURLs();
|
||||
|
||||
}
|
||||
+9
-1
@@ -4,17 +4,20 @@ import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedEvent;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.RaceHandle;
|
||||
import com.sap.sailing.domain.tractracadapter.RaceTracker;
|
||||
import com.tractrac.clientmodule.Event;
|
||||
|
||||
public class RaceHandleImpl implements RaceHandle {
|
||||
private final Event tractracEvent;
|
||||
private final DomainFactory domainFactory;
|
||||
private final DynamicTrackedEvent trackedEvent;
|
||||
private final RaceTracker raceTracker;
|
||||
|
||||
public RaceHandleImpl(DomainFactory domainFactory, Event tractracEvent, DynamicTrackedEvent trackedEvent) {
|
||||
public RaceHandleImpl(DomainFactory domainFactory, Event tractracEvent, DynamicTrackedEvent trackedEvent, RaceTracker raceTracker) {
|
||||
this.domainFactory = domainFactory;
|
||||
this.tractracEvent = tractracEvent;
|
||||
this.trackedEvent = trackedEvent;
|
||||
this.raceTracker = raceTracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -32,5 +35,10 @@ public class RaceHandleImpl implements RaceHandle {
|
||||
public DynamicTrackedEvent getTrackedEvent() {
|
||||
return trackedEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker getRaceTracker() {
|
||||
return raceTracker;
|
||||
}
|
||||
|
||||
}
|
||||
+16
-1
@@ -22,6 +22,7 @@ import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.RaceHandle;
|
||||
import com.sap.sailing.domain.tractracadapter.RaceTracker;
|
||||
import com.sap.sailing.domain.tractracadapter.Receiver;
|
||||
import com.sap.sailing.util.Util.Triple;
|
||||
import com.tractrac.clientmodule.Event;
|
||||
import com.tractrac.clientmodule.data.DataController;
|
||||
import com.tractrac.clientmodule.data.DataController.Listener;
|
||||
@@ -35,6 +36,8 @@ public class RaceTrackerImpl implements Listener, RaceTracker {
|
||||
private final Set<Receiver> receivers;
|
||||
private final DomainFactory domainFactory;
|
||||
private final DynamicTrackedEvent trackedEvent;
|
||||
private final WindStore windStore;
|
||||
private final Triple<URL, URI, URI> urls;
|
||||
|
||||
/**
|
||||
* Creates a race tracked for the specified URL/URIs and starts receiving all available existing and future push
|
||||
@@ -60,6 +63,8 @@ public class RaceTrackerImpl implements Listener, RaceTracker {
|
||||
*/
|
||||
protected RaceTrackerImpl(DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI, WindStore windStore)
|
||||
throws URISyntaxException, MalformedURLException, FileNotFoundException {
|
||||
urls = new Triple<URL, URI, URI>(paramURL, liveURI, storedURI);
|
||||
this.windStore = windStore;
|
||||
this.domainFactory = domainFactory;
|
||||
// Read event data from configuration file
|
||||
tractracEvent = KeyValue.setup(paramURL);
|
||||
@@ -87,6 +92,16 @@ public class RaceTrackerImpl implements Listener, RaceTracker {
|
||||
addListenersForStoredDataAndStartController(typeControllers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Triple<URL, URI, URI> getURLs() {
|
||||
return urls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindStore getWindStore() {
|
||||
return windStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicTrackedEvent getTrackedEvent() {
|
||||
return trackedEvent;
|
||||
@@ -94,7 +109,7 @@ public class RaceTrackerImpl implements Listener, RaceTracker {
|
||||
|
||||
@Override
|
||||
public RaceHandle getRaceHandle() {
|
||||
return new RaceHandleImpl(domainFactory, tractracEvent, getTrackedEvent());
|
||||
return new RaceHandleImpl(domainFactory, tractracEvent, getTrackedEvent(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+18
-1
@@ -2,6 +2,7 @@ package com.sap.sailing.server.test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
@@ -83,7 +84,7 @@ public class RaceTrackerTest {
|
||||
@Test
|
||||
public void testStopTracking() throws MalformedURLException, IOException, InterruptedException, URISyntaxException {
|
||||
TrackedEvent oldTrackedEvent = raceHandle.getTrackedEvent();
|
||||
TrackedRace oldTrackedRace = oldTrackedEvent.getTrackedRaces().iterator().next();
|
||||
TrackedRace oldTrackedRace = getTrackedRace(oldTrackedEvent);
|
||||
service.stopTracking(raceHandle.getEvent());
|
||||
RaceHandle myRaceHandle = service.addRace(paramUrl, liveUri, storedUri, EmptyWindStore.INSTANCE);
|
||||
TrackedEvent newTrackedEvent = myRaceHandle.getTrackedEvent();
|
||||
@@ -91,4 +92,20 @@ public class RaceTrackerTest {
|
||||
// expecting a new tracked race to be created when starting over with tracking
|
||||
assertNotSame(oldTrackedRace, newTrackedRace);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test asserts that tracking the same race twice doesn't create another tracker and in particular no
|
||||
* new tracked event / tracked race.
|
||||
*/
|
||||
@Test
|
||||
public void testTrackingSameRaceWithoutStopping() throws MalformedURLException, IOException, InterruptedException, URISyntaxException {
|
||||
TrackedEvent oldTrackedEvent = raceHandle.getTrackedEvent();
|
||||
TrackedRace oldTrackedRace = getTrackedRace(oldTrackedEvent);
|
||||
RaceHandle myRaceHandle = service.addRace(paramUrl, liveUri, storedUri, EmptyWindStore.INSTANCE);
|
||||
TrackedEvent newTrackedEvent = myRaceHandle.getTrackedEvent();
|
||||
TrackedRace newTrackedRace = getTrackedRace(newTrackedEvent);
|
||||
// expecting a new tracked race to be created when starting over with tracking
|
||||
assertSame(oldTrackedRace, newTrackedRace);
|
||||
assertSame(raceHandle.getRaceTracker(), myRaceHandle.getRaceTracker());
|
||||
}
|
||||
}
|
||||
@@ -46,10 +46,11 @@ public interface RacingEventService {
|
||||
DomainFactory getDomainFactory();
|
||||
|
||||
/**
|
||||
* Defines the event and for each race listed in the JSON document creates a {@link RaceTracker} that starts
|
||||
* tracking the respective race. The {@link RaceDefinition}s obtained this way are all grouped into the single
|
||||
* {@link Event} produced for the event listed in the JSON response. Note that the many race trackers will have
|
||||
* their TracTrac <code>Event</code> each, all with the same name, meaning the same event but being distinct.
|
||||
* Defines the event and for each race listed in the JSON document that is not already being tracked by this service
|
||||
* creates a {@link RaceTracker} that starts tracking the respective race. The {@link RaceDefinition}s obtained this
|
||||
* way are all grouped into the single {@link Event} produced for the event listed in the JSON response. Note that
|
||||
* the many race trackers will have their TracTrac <code>Event</code> each, all with the same name, meaning the same
|
||||
* event but being distinct.
|
||||
*
|
||||
* @param jsonURL
|
||||
* URL of a JSON response that contains an "event" object telling the event's name and ID, as well as a
|
||||
@@ -60,22 +61,31 @@ public interface RacingEventService {
|
||||
URISyntaxException, IOException, ParseException, org.json.simple.parser.ParseException;
|
||||
|
||||
/**
|
||||
* Adds a single race tracker and starts tracking the race, using the race's parameter URL which delivers the single
|
||||
* configuration text file for that race. While the result of passing this URL to the TracTrac
|
||||
* <code>KeyValue.setup</code> is a TracTrac <code>Event</code>, those events only manage a single race. In our
|
||||
* domain model, we group those races into a single instance of our {@link Event} class.
|
||||
* If not already tracking the URL/URI/URI combination, adds a single race tracker and starts tracking the race,
|
||||
* using the race's parameter URL which delivers the single configuration text file for that race. While the result
|
||||
* of passing this URL to the TracTrac <code>KeyValue.setup</code> is a TracTrac <code>Event</code>, those events
|
||||
* only manage a single race. In our domain model, we group those races into a single instance of our {@link Event}
|
||||
* class.
|
||||
* <p>
|
||||
*
|
||||
* If this is the first race of an event, the {@link Event} is created as well. If the {@link RaceDefinition} for
|
||||
* the race already exists, it isn't created again. Also, if a {@link RaceTracker} for the given race already
|
||||
* exists, it is not added again.
|
||||
* exists, it is not added again.<p>
|
||||
*
|
||||
* Note that when the race identified by <code>paramURL</code>, <code>liveURI</code> and <code>storedURI</code> is
|
||||
* already being tracked, then regardless of the <code>windStore</code> selection the existing tracker will be used
|
||||
* and its race handle will be returned. A log message will indicate a potential wind store mismatch (based on
|
||||
* {@link WindStore#equals(Object)}).
|
||||
*/
|
||||
RaceHandle addRace(URL paramURL, URI liveURI, URI storedURI, WindStore windStore) throws MalformedURLException, FileNotFoundException,
|
||||
URISyntaxException;
|
||||
|
||||
/**
|
||||
* Stops tracking all races of the event specified. This will also stop tracking wind for all races of this event.
|
||||
* See {@link #stopTrackingWind(Event, RaceDefinition)}.
|
||||
* See {@link #stopTrackingWind(Event, RaceDefinition)}. If there were multiple calls to
|
||||
* {@link #addRace(URL, URI, URI, WindStore)} with an equal combination of URLs/URIs, the {@link RaceTracker}
|
||||
* already tracking the race was re-used. The trackers will be stopped by this call regardless of how many calls
|
||||
* were made that ensured they were tracking.
|
||||
*/
|
||||
void stopTracking(Event event) throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
|
||||
+45
-25
@@ -16,6 +16,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.declination.DeclinationService;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
@@ -34,11 +35,13 @@ import com.sap.sailing.util.Util.Pair;
|
||||
import com.sap.sailing.util.Util.Triple;
|
||||
|
||||
public class RacingEventServiceImpl implements RacingEventService {
|
||||
private static final Logger logger = Logger.getLogger(RacingEventServiceImpl.class.getName());
|
||||
|
||||
private final DomainFactory domainFactory;
|
||||
|
||||
private final Map<String, Event> eventsByName;
|
||||
|
||||
private final Map<Event, Set<RaceTracker>> raceTrackers;
|
||||
private final Map<Event, Set<RaceTracker>> raceTrackersByEvent;
|
||||
|
||||
/**
|
||||
* Remembers the wind tracker and the port on which the UDP receiver with which the wind tracker is
|
||||
@@ -46,13 +49,19 @@ public class RacingEventServiceImpl implements RacingEventService {
|
||||
*/
|
||||
private final Map<RaceDefinition, Pair<WindTracker, Integer>> windTrackers;
|
||||
|
||||
/**
|
||||
* Remembers the trackers by paramURL/liveURI/storedURI to avoid duplication
|
||||
*/
|
||||
private final Map<Triple<URL, URI, URI>, RaceTracker> raceTrackersByURLs;
|
||||
|
||||
private final Map<Integer, UDPExpeditionReceiver> windReceivers;
|
||||
|
||||
public RacingEventServiceImpl() {
|
||||
domainFactory = DomainFactory.INSTANCE;
|
||||
eventsByName = new HashMap<String, Event>();
|
||||
raceTrackers = new HashMap<Event, Set<RaceTracker>>();
|
||||
raceTrackersByEvent = new HashMap<Event, Set<RaceTracker>>();
|
||||
windTrackers = new HashMap<RaceDefinition, Pair<WindTracker, Integer>>();
|
||||
raceTrackersByURLs = new HashMap<Triple<URL, URI, URI>, RaceTracker>();
|
||||
windReceivers = new HashMap<Integer, UDPExpeditionReceiver>();
|
||||
}
|
||||
|
||||
@@ -85,33 +94,44 @@ public class RacingEventServiceImpl implements RacingEventService {
|
||||
@Override
|
||||
public RaceHandle addRace(URL paramURL, URI liveURI, URI storedURI, WindStore windStore) throws MalformedURLException, FileNotFoundException,
|
||||
URISyntaxException {
|
||||
// FIXME check if a tracker for this parameter combination already exists and if so, return its race handle
|
||||
RaceTracker tracker = getDomainFactory().createRaceTracker(paramURL, liveURI, storedURI, windStore);
|
||||
Set<RaceTracker> trackers = raceTrackers.get(tracker.getEvent());
|
||||
if (trackers == null) {
|
||||
trackers = new HashSet<RaceTracker>();
|
||||
raceTrackers.put(tracker.getEvent(), trackers);
|
||||
}
|
||||
trackers.add(tracker);
|
||||
String eventName = tracker.getEvent().getName();
|
||||
Event eventWithName = eventsByName.get(eventName);
|
||||
if (eventWithName != null) {
|
||||
if (eventWithName != tracker.getEvent()) {
|
||||
throw new RuntimeException("Internal error. Two Event objects with equal name "+eventName);
|
||||
Triple<URL, URI, URI> key = new Triple<URL, URI, URI>(paramURL, liveURI, storedURI);
|
||||
RaceTracker tracker = raceTrackersByURLs.get(key);
|
||||
if (tracker == null) {
|
||||
tracker = getDomainFactory().createRaceTracker(paramURL, liveURI, storedURI, windStore);
|
||||
raceTrackersByURLs.put(key, tracker);
|
||||
Set<RaceTracker> trackers = raceTrackersByEvent.get(tracker.getEvent());
|
||||
if (trackers == null) {
|
||||
trackers = new HashSet<RaceTracker>();
|
||||
raceTrackersByEvent.put(tracker.getEvent(), trackers);
|
||||
}
|
||||
trackers.add(tracker);
|
||||
String eventName = tracker.getEvent().getName();
|
||||
Event eventWithName = eventsByName.get(eventName);
|
||||
if (eventWithName != null) {
|
||||
if (eventWithName != tracker.getEvent()) {
|
||||
throw new RuntimeException("Internal error. Two Event objects with equal name "+eventName);
|
||||
}
|
||||
} else {
|
||||
eventsByName.put(eventName, tracker.getEvent());
|
||||
}
|
||||
} else {
|
||||
eventsByName.put(eventName, tracker.getEvent());
|
||||
WindStore existingTrackersWindStore = tracker.getWindStore();
|
||||
if (!existingTrackersWindStore.equals(windStore)) {
|
||||
logger.warning("Wind store mismatch. Requested wind store: "+windStore+
|
||||
". Wind store in use by existing tracker: "+existingTrackersWindStore);
|
||||
}
|
||||
}
|
||||
return tracker.getRaceHandle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopTracking(Event event) throws MalformedURLException, IOException, InterruptedException {
|
||||
if (raceTrackers.containsKey(event)) {
|
||||
for (RaceTracker raceTracker : raceTrackers.get(event)) {
|
||||
raceTracker.stop();
|
||||
if (raceTrackersByEvent.containsKey(event)) {
|
||||
for (RaceTracker raceTracker : raceTrackersByEvent.get(event)) {
|
||||
raceTracker.stop(); // this also removes the TrackedRace from trackedEvent
|
||||
raceTrackersByURLs.remove(raceTracker.getURLs());
|
||||
}
|
||||
raceTrackers.remove(event);
|
||||
raceTrackersByEvent.remove(event);
|
||||
}
|
||||
if (event != null && event.getName() != null) {
|
||||
eventsByName.remove(event.getName());
|
||||
@@ -123,19 +143,19 @@ public class RacingEventServiceImpl implements RacingEventService {
|
||||
|
||||
@Override
|
||||
public void stopTracking(Event event, RaceDefinition race) throws MalformedURLException, IOException, InterruptedException {
|
||||
if (raceTrackers.containsKey(event)) {
|
||||
Iterator<RaceTracker> trackerIter = raceTrackers.get(event).iterator();
|
||||
if (raceTrackersByEvent.containsKey(event)) {
|
||||
Iterator<RaceTracker> trackerIter = raceTrackersByEvent.get(event).iterator();
|
||||
while (trackerIter.hasNext()) {
|
||||
RaceTracker raceTracker = trackerIter.next();
|
||||
if (raceTracker.getRace() == race) {
|
||||
raceTracker.stop();
|
||||
raceTracker.stop(); // this also removes the TrackedRace from trackedEvent
|
||||
trackerIter.remove();
|
||||
raceTrackersByURLs.remove(raceTracker.getURLs());
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME remove TrackedRace from TrackedEvent
|
||||
// if the last tracked race was removed, remove the entire event
|
||||
if (raceTrackers.get(event).isEmpty()) {
|
||||
if (raceTrackersByEvent.get(event).isEmpty()) {
|
||||
stopTracking(event);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user